/*-- Biomedis International design system -- production skeleton.
     Drop in at: public/common/templates/BMI/styles/style.css

     Source of truth: references/design/css-architecture.md (this file's section
     numbers are that document's section numbers) and the approved Claude Design
     canvas "Biomedis Website Refresh.dc.html" (1,144 lines, 100% inline styles,
     59 style-hover attributes, zero media queries, zero classes).

     Structure mirrors the reference build's style.css (2,448 lines / 180 prefixed classes):
       1-4   Design core      -- tokens, reset, layout+type roles, buttons
       5-11  Components       -- chrome, cards, editorial, catalogue, PDP,
                                 membership, services
       12-14 WebItems adapter -- forms + states, icons, inherited ABT classes
       15-16 Accessibility + responsive

     RULES
       - Tokens only. Every colour / radius / size / shadow is a var(--bmi-*).
         A literal outside :root carries a "literal because" comment.
       - Zero inline style="" in markup. Zero JS-applied CSS. JS toggles
         classes (.is-open, .is-busy, .is-on) and nothing else.
       - Hover is a promise of interactivity: only on <a>, <button>, or a card
         whose whole surface is one link. Static info cards get none.
       - ASCII only. Glyphs are CSS escapes (\2192) or Font Awesome icons.
       - Bump ?v= in template.master on every edit to this file.  --*/


/*-- =====================================================================
     1. TOKENS
     ===================================================================== */
:root {
	/*-- brand: purple --------------------------------------------------*/
	--bmi-purple:            #6B2168;   /* links, primary button, cart button, active accents */
	--bmi-purple-hover:      #4E1350;   /* the ONE purple hover. dc:66's #54134F is normalised away */
	--bmi-purple-glow:       rgba(107,33,104,.05);

	/*-- brand: aubergine / ink -----------------------------------------*/
	--bmi-aubergine:         #2B0B2E;   /* utility bar, Home B hero panel, membership hero */
	--bmi-ink:               #22132A;   /* headings on light, footer, dark bands, dark button */
	--bmi-ink-body:          #1C1620;   /* body default; text on lime surfaces */
	--bmi-scrim:             rgba(34,19,42,.42);
	--bmi-badge-dark:        rgba(34,19,42,.85);

	/*-- brand: lime -----------------------------------------------------*/
	--bmi-lime:              #A6CE39;   /* nav underline, lime CTA, cart pill, active rails */
	--bmi-lime-light:        #B8DC4A;   /* selection, on-dark accents, lime hover */
	--bmi-lime-pill-bg:      rgba(184,220,74,.14);
	--bmi-lime-glow:         rgba(166,206,57,.16);
	--bmi-lime-tint:         #EEF5DA;   /* Add button resting fill; doubles as --bmi-success-tint */
	--bmi-lime-ink:          #4A6112;   /* Add button resting label; doubles as --bmi-success */
	--bmi-olive:             #5F7A19;   /* eyebrow on lime, "Free, all countries", tier eyebrow */

	/*-- text on light ---------------------------------------------------*/
	--bmi-text:              #1C1620;
	--bmi-text-strong:       #22132A;
	--bmi-text-mid:          #3A3040;   /* 12.52:1 on white */
	--bmi-text-muted:        #5C5164;   /* 7.46:1  -- THE paragraph colour */
	--bmi-text-caption:      #6E6272;   /* 5.75:1  -- captions, qty glyphs, meta */
	--bmi-quote:             #5A4C5E;   /* testimonial quote, Newsreader italic */

	/*-- text on light: the WCAG repairs (see css-architecture.md 5.6) ----
	   The canvas' #8E7E92 (3.78:1), #9A8C9C (3.18:1) and #A08FA2 (3.02:1)
	   all fail AA on small text. Pushed to 4.5:1 on white they land at
	   #827186 / #817184 / #857087 -- within 0.04 CR of each other, i.e. one
	   colour. So they collapse to ONE value under three names, and the three
	   roles are separated by weight / size / tracking instead of lightness.
	   #796A7B = 5.05 white, 4.79 #FBF8FB, 4.51 #F5F1F5, 4.77 #F7FAEE.       */
	--bmi-text-eyebrow-aa:   #796A7B;
	--bmi-text-meta-aa:      #796A7B;
	--bmi-text-faint-aa:     #796A7B;
	--bmi-text-disabled:     #796A7B;   /* 4.51:1 on the #F5F1F5 disabled ground */
	--bmi-numeral-aa:        #9E7BA1;   /* was #C9B4CB at 1.93:1; now 3.62:1, clears the large-text bar */
	--bmi-olive-muted-aa:    #5F7A19;   /* was #7A8A5C at 3.74:1; reuses the existing olive at 4.90:1 */

	/*-- text on dark ----------------------------------------------------*/
	--bmi-on-dark:           #FFFFFF;
	--bmi-on-dark-body:      #CDBFCF;   /* 10.00:1 on --bmi-ink */
	--bmi-on-dark-list:      #E4DAE5;   /* 12.94:1 */
	--bmi-on-dark-muted:     #B4A3B6;   /*  7.41:1 */
	--bmi-on-dark-util:      #D9C9DB;   /* 11.16:1 on --bmi-aubergine */
	--bmi-on-dark-faint-aa:  #8E7B90;   /* was #8E7A90 at 4.47:1; now 4.51 on ink, 4.53 on aubergine */

	/*-- surfaces --------------------------------------------------------*/
	--bmi-bg:                #FFFFFF;
	--bmi-wash:              #FBF8FB;   /* the purple wash band */
	--bmi-surface-2:         #F5F1F5;   /* image wells, newsletter band, sort track */
	--bmi-wash-lime:         #F7FAEE;   /* callout, benefits band, secondary hover, founder plate */
	--bmi-wash-lime-2:       #FAFCF4;   /* category-tile hover, premium column, recommended card */
	--bmi-header-bg:         rgba(255,255,255,.94);
	/* the canvas' #FDFBFD (testimonial placeholder ground) is deliberately absent:
	   the dashed placeholder frame and its note label do not ship (dc:436-437) */

	/*-- borders and rules -----------------------------------------------*/
	--bmi-border-card:       #EDE5ED;   /* canonical 1px card border */
	--bmi-rule:              #EFE8EF;   /* canonical 1px hairline */
	--bmi-rule-band:         #F0E9F0;   /* rules on the #FBF8FB bands; compare-table rows */
	--bmi-rule-faint:        #F3EDF3;   /* cart-line divider, services price divider */
	--bmi-border-header:     #EBE3EB;
	--bmi-border-chip:       #E4DBE4;   /* non-interactive labels */
	--bmi-border-strong:     #DCCFDC;   /* decorative heavy hairline. NOT for control
	                                       boundaries -- 1.50:1 on white fails SC 1.4.11.
	                                       Kept because dc:735 uses it as the (dropped)
	                                       services-row hover; see section 11.          */
	--bmi-border-lime:       #E4EDCB;
	--bmi-border-lime-2:     #E9F0D4;
	--bmi-rule-quote:        #E0D4E1;   /* 2px left rule on testimonial quotes */
	--bmi-border-util:       #5A3A5C;   /* utility-bar social chips, on aubergine */
	--bmi-border-footer:     #4A2F4C;   /* footer social chips */
	--bmi-border-footer-rule:#3B2440;
	--bmi-border-ondark:     rgba(255,255,255,.28);  /* ghost button */
	--bmi-border-ondark-2:   rgba(255,255,255,.18);  /* compare-table header divider */
	--bmi-border-ondark-3:   rgba(255,255,255,.14);  /* stat-bar top rule */

	/*-- THE control border (WCAG 2.2 SC 1.4.11, 3:1 non-text) ------------
	   The canvas' control borders sit at 1.30-1.50:1 against white
	   (#E7DFE7 1.30, #E4DBE4 1.35, #DDD1DE 1.47, #DCCFDC 1.50). Where the
	   border is the ONLY thing identifying an interactive control that
	   fails. #9E7FA1 clears 3:1 on all five light grounds
	   (3.50 / 3.32 / 3.13 / 3.31 / 3.38). Applied ONLY to .bmi-input,
	   .bmi-btn-secondary, .bmi-qty, .bmi-variants-chip, .bmi-pager-cell,
	   .bmi-header-iconbtn, .bmi-gallery-thumb-empty. The decorative
	   hairlines above stay light -- 1.4.11 exempts them, and darkening
	   every rule would turn a soft mauve system into a wireframe.          */
	--bmi-border-control-aa: #9E7FA1;

	/*-- functional state colours (none exist in the canvas) --------------*/
	--bmi-error:             #A32218;   /* 7.50:1 on white, 6.45:1 on its tint */
	--bmi-error-tint:        #FBEAE9;
	--bmi-success:           #4A6112;   /* 6.98:1 -- the SAME value as --bmi-lime-ink, on purpose */
	--bmi-success-tint:      #EEF5DA;
	--bmi-warn:              #8A5A12;   /* 5.91:1 */
	--bmi-warn-tint:         #FBF1DD;
	--bmi-info:              #6B2168;   /* 10.28:1 -- the brand purple */
	--bmi-info-tint:         #F3E9F3;

	/*-- focus -----------------------------------------------------------*/
	--bmi-focus-ring:        #6B2168;   /* 10.28:1 on white, 9.20:1 on #F5F1F5 */
	--bmi-focus-halo:        rgba(107,33,104,.18);
	--bmi-focus-ring-dark:   #B8DC4A;   /* 11.20:1 on ink, 11.24:1 on aubergine */
	--bmi-focus-halo-dark:   rgba(184,220,74,.28);

	/*-- elevation -------------------------------------------------------
	   Every card shadow uses a LARGE NEGATIVE SPREAD (-22 to -24px) so the
	   blur hugs the element and reads as a lift, not a halo. Preserve it.
	   The base is rgba(43,11,46) = the aubergine, NOT the ink.             */
	--bmi-shadow-card:       0 16px 40px -22px rgba(43,11,46,.4);
	--bmi-shadow-card-lg:    0 18px 44px -24px rgba(43,11,46,.45);
	--bmi-shadow-pill:       0 1px 3px rgba(43,11,46,.16);
	--bmi-shadow-drawer:     -24px 0 60px -30px rgba(34,19,42,.5);

	/*-- typography ------------------------------------------------------
	   Loaded in template.master:
	   family=Archivo:wght@400;500;600;700
	   &family=Newsreader:ital,opsz,wght@0,6..72,300;0,6..72,400;1,6..72,300
	   Newsreader 500 is dropped -- loaded by the canvas, used nowhere.
	   Newsreader italic 300 is the ONLY italic loaded, which is why
	   .bmi-quote-text pins font-weight:300.                                */
	--bmi-serif: Newsreader, Georgia, 'Times New Roman', serif;
	--bmi-sans:  Archivo, system-ui, -apple-system, 'Segoe UI', sans-serif;

	/*-- display scale. Clamps land EXACTLY on the canvas value at 1240px. */
	--bmi-fs-d1:  clamp(34px, 6.30vw, 78px);   /* hero A H1            */
	--bmi-fs-d2:  clamp(30px, 5.20vw, 64px);   /* hero B H1            */
	--bmi-fs-d3:  clamp(30px, 4.90vw, 60px);   /* membership hero H1   */
	--bmi-fs-d4:  clamp(28px, 4.40vw, 54px);   /* page H1              */
	--bmi-fs-d5:  clamp(26px, 3.90vw, 48px);   /* largest section H2   */
	--bmi-fs-d6:  clamp(26px, 3.75vw, 46px);   /* default section H2   */
	--bmi-fs-d7:  clamp(25px, 3.60vw, 44px);
	--bmi-fs-d8:  clamp(24px, 3.25vw, 40px);
	--bmi-fs-d9:  clamp(24px, 3.10vw, 38px);
	--bmi-fs-d10: clamp(23px, 2.95vw, 36px);

	/*-- UI scale. Half-pixel values are the canvas' own and are KEPT --
	   rounding them to a modular scale changes the rhythm of every page. */
	--bmi-fs-lead:    18.5px;
	--bmi-fs-lead-dk: 17.5px;
	--bmi-fs-lg:      16.5px;
	--bmi-fs-base:    16px;
	--bmi-fs-sm:      15.5px;
	--bmi-fs-xs:      15px;
	--bmi-fs-ui:      14.5px;
	--bmi-fs-ui-sm:   13.5px;
	--bmi-fs-meta:    13px;
	--bmi-fs-cap:     12.5px;
	--bmi-fs-eyebrow: 12px;
	--bmi-fs-label:   11.5px;
	--bmi-fs-badge:   11px;

	/*-- spacing ---------------------------------------------------------*/
	--bmi-maxw:        1240px;
	--bmi-maxw-narrow: 1040px;
	--bmi-gutter:      clamp(16px, 4vw, 40px);
	/*-- From the edge of a box that spans the page to where the page's content column starts
	     (the .bmi-wrap / .panel-table content edge). THE CONTAINER MATH LIVES HERE, once: a
	     full-bleed module that lines its copy up with the page reads this and never repeats
	     it. 100cqw is the width of the nearest size container, so the box reading it makes
	     itself one (container-type: inline-size). --*/
	--bmi-page-inset:  max(var(--bmi-gutter), calc((100cqw - var(--bmi-maxw)) / 2 + var(--bmi-gutter)));
	--bmi-section-pad: 96px;

	/*-- chrome. THE load-bearing variable: the canvas hard-codes
	   position:sticky;top:120px in three places against a chrome of
	   38 + 84 = 122px. Redefined at 1080 (utility bar hides) and 620.     */
	--bmi-utilbar-h:   38px;
	--bmi-header-h:    84px;
	--bmi-chrome-h:    122px;
	--bmi-sticky-top:  calc(var(--bmi-chrome-h) - 2px);

	/*-- radii. 6px is the control default (36 uses), 10px the card
	   default (14), 12px the large card (14).                             */
	--bmi-radius-ctl:  6px;
	--bmi-radius-card: 10px;
	--bmi-radius-lg:   12px;
	--bmi-radius-xl:   14px;
	--bmi-radius-pill: 20px;

	/*-- motion ----------------------------------------------------------*/
	--bmi-dur-hover:  .16s;
	--bmi-dur-fast:   .16s;
	--bmi-dur-card:   .18s;
	--bmi-dur-panel:  .22s;
	--bmi-dur-scrim:  .20s;
	--bmi-dur-drawer: .26s;
	--bmi-ease:       ease;
	--bmi-ease-out:   cubic-bezier(.22,1,.36,1);   /* dc:874, the drawer easing */

	/*-- accessibility ---------------------------------------------------*/
	--bmi-touch-min: 44px;

	/*-- form controls. ONE height for every text input, select, file field
	     and the buttons that sit on a form row with them, so a form never
	     steps up and down as the eye travels it. 52px is the canvas' own
	     control height; --bmi-touch-min stays the accessibility FLOOR that
	     this must never drop below, not the value to build to. --*/
	--bmi-input-h:   52px;
	--bmi-input-px:  18px;
}


/*-- =====================================================================
     2. RESET + BASE   (ports dc:14-23, the canvas' only real stylesheet)
     ===================================================================== */
*, *::before, *::after { box-sizing: border-box; }                       /* dc:15 */

html { -webkit-text-size-adjust: 100%; overflow-x: hidden; }
/* Anchored page content must remain below the sticky header at every breakpoint. */
:target { scroll-margin-top: calc(var(--bmi-chrome-h) + 24px); }

/* The parked off-canvas drawer (.bmi-mobilenav, translateX(102%)) lays out beyond the
   viewport and inflates the document, horizontally scrolling every page on a phone.
   html{overflow-x:hidden} only masks the scrollbar -- scrollWidth stays inflated and some
   mobile browsers still rubber-band. overflow-x:clip on the non-fixed layout wrapper is
   what actually clips it; clip (not hidden) keeps the vertical axis visible, so it adds no
   scroll container and cannot break a sticky header. Carried verbatim from ABT. */
#wrapper { overflow-x: clip; }

body {
	margin: 0;
	background: var(--bmi-bg);
	font-family: var(--bmi-sans);
	font-size: var(--bmi-fs-base);
	line-height: 1.6;
	color: var(--bmi-text);
	-webkit-font-smoothing: antialiased;
	text-rendering: optimizeLegibility;
}                                                                        /* dc:16 */

img { display: block; max-width: 100%; height: auto; }                   /* dc:17 */
a   { color: var(--bmi-purple); text-decoration: none; }                 /* dc:18 */
a:where([href]) { transition: color var(--bmi-dur-fast) var(--bmi-ease); }
a:where([href]):hover { color: var(--bmi-purple-hover); }                              /* dc:19  HOVER 60/60 */

/* The canvas re-declares font-family:Archivo on all 27 <button> elements and the one
   <input> because form controls do not inherit. These two rules replace all 28. */
button, input, select, textarea { font-family: inherit; font-size: inherit; }
button { cursor: pointer; background: none; border: none; padding: 0; color: inherit; }

/* [hidden] MUST WIN. The browser's own [hidden]{display:none} is a UA-stylesheet rule,
   so ANY class selector that sets display beats it -- and this sheet sets display on
   .bmi-mobilenav (flex), .bmi-scrim, .bmi-drawer and .bmi-sheet. Without this line the
   mobile drawer and its scrim render on a 1440px desktop with the attribute set, which
   is exactly what happened when the chrome was first wired. The overlays mount and
   unmount rather than transition, so [hidden] is the mechanism that closes them, and it
   has to outrank the component rule that opens them. */
[hidden] { display: none !important; }

h1, h2, h3 {
	margin: 0;
	font-family: var(--bmi-serif);
	font-weight: 300;
	color: var(--bmi-text-strong);
}
h4, h5, h6 { margin: 0; font-family: var(--bmi-sans); font-weight: 600; color: var(--bmi-text-strong); }
p { margin: 0 0 1em; }

::selection { background: var(--bmi-lime-light); color: var(--bmi-ink-body); }   /* dc:20 */

/* dc:21-22, renamed. bmFade was defined and never applied in the canvas; here it drives
   the scrim, which the canvas mounts with no fade at all. */
@keyframes bmiDrawer    { from { transform: translateX(102%); } to { transform: translateX(0); } }
@keyframes bmiDrawerOut { from { transform: translateX(0); }    to { transform: translateX(102%); } }
@keyframes bmiSheet     { from { transform: translateY(102%); } to { transform: translateY(0); } }
@keyframes bmiFade      { from { opacity: 0; }                  to { opacity: 1; } }
@keyframes bmiSpin      { to   { transform: rotate(360deg); } }
@keyframes bmiShimmer   { 100% { transform: translateX(100%); } }


/*-- =====================================================================
     3. LAYOUT + TYPE ROLES   (utilities: one or two properties, no anatomy)
     ===================================================================== */

/*-- 3a. Container. 27 canvas occurrences of max-width:1240px;padding:0 40px --*/
.bmi-wrap        { width: 100%; max-width: var(--bmi-maxw); margin: 0 auto; padding: 0 var(--bmi-gutter); }


/*-- 3c. Bands -----------------------------------------------------------*/
.bmi-band-wash    { background: var(--bmi-wash);
                    border-top: 1px solid var(--bmi-rule-band);
                    border-bottom: 1px solid var(--bmi-rule-band); }
.bmi-band-lime    { background: var(--bmi-wash-lime);
                    border-top: 1px solid var(--bmi-border-lime-2);
                    border-bottom: 1px solid var(--bmi-border-lime-2); }
.bmi-band-dark    { background: var(--bmi-ink); color: var(--bmi-on-dark); }
.bmi-band-deep    { background: var(--bmi-aubergine); color: var(--bmi-on-dark); }
.bmi-band-surface { background: var(--bmi-surface-2); }
.bmi-band-dark h1, .bmi-band-dark h2, .bmi-band-dark h3,
.bmi-band-deep h1, .bmi-band-deep h2, .bmi-band-deep h3 { color: var(--bmi-on-dark); }

/*-- 3d. Eyebrow. 12 canvas occurrences of letter-spacing:.18em -- the single
     most repeated micro-pattern in the design. ------------------------- */
.bmi-eyebrow       { font-size: var(--bmi-fs-eyebrow); font-weight: 600; letter-spacing: .18em;
                     text-transform: uppercase; color: var(--bmi-text-eyebrow-aa); }
.bmi-eyebrow-dark  { color: var(--bmi-lime-light); }

.bmi-h-item { font-family: var(--bmi-serif); font-weight: 400; font-size: 28px; letter-spacing: -.015em; }

/*-- 3g. Body scale (Archivo) -------------------------------------------*/
.bmi-lead      { font-size: var(--bmi-fs-lead);    line-height: 1.62; color: var(--bmi-text-muted); text-wrap: pretty; }


/*-- 3i. Grids ----------------------------------------------------------*/
.bmi-grid  { display: grid; }
.bmi-g-4   { grid-template-columns: repeat(4, 1fr); }
.bmi-gap-22 { gap: 22px; }

/*-- 3j. Section head: heading left, "View all" link right ---------------*/
.bmi-viewall  { font-size: var(--bmi-fs-ui); font-weight: 600; white-space: nowrap;
                color: var(--bmi-purple); border-bottom: 2px solid var(--bmi-lime);
                padding-bottom: 3px;
                transition: color var(--bmi-dur-fast) var(--bmi-ease),
                            border-color var(--bmi-dur-fast) var(--bmi-ease); }
/* ADDED -- the canvas declares no hover on an element that is plainly a link */
.bmi-viewall:hover { color: var(--bmi-purple-hover); border-bottom-color: var(--bmi-lime-light); }


/*-- 3l. Visually hidden, still announced. --*/
.bmi-sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
               overflow: hidden; clip: rect(0,0,0,0); white-space: nowrap; border: 0; }


/*-- =====================================================================
     4. BUTTONS
     The canvas has 27 <button> elements, every one re-declaring
     font-family:Archivo and cursor:pointer, and NONE declaring a
     transition -- it relies on the style-hover directive, which is not CSS.
     One base class replaces all 27 re-declarations and supplies the
     transition production needs.
     ===================================================================== */
.bmi-btn {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: 9px;
	border: none;
	border-radius: var(--bmi-radius-ctl);
	font-family: var(--bmi-sans);
	font-weight: 600;
	text-decoration: none;
	white-space: nowrap;
	cursor: pointer;
	transition: background var(--bmi-dur-fast) var(--bmi-ease),
	            border-color var(--bmi-dur-fast) var(--bmi-ease),
	            color var(--bmi-dur-fast) var(--bmi-ease);
}

/*-- 4a. Colour variants. Every :hover below is one of the 59 style-hover
     attributes, resolved. Canvas lines are cited on each. --------------- */
.bmi-btn-primary        { background: var(--bmi-purple); color: #fff; }
.bmi-btn-primary:hover  { background: var(--bmi-purple-hover); color: #fff; }
   /* HOVER dc:87, 262, 427, 603, 710, 744, 770, 870 (8 buttons) */

.bmi-btn-lime           { background: var(--bmi-lime); color: var(--bmi-ink-body); font-weight: 700; }
.bmi-btn-lime:hover     { background: var(--bmi-lime-light); color: var(--bmi-ink-body); }


.bmi-btn-secondary      { background: #fff; color: var(--bmi-text-strong);
                          border: 1.5px solid var(--bmi-border-control-aa); }
.bmi-btn-secondary:hover{ border-color: var(--bmi-lime); background: var(--bmi-wash-lime); color: var(--bmi-text-strong); }
   /* HOVER dc:88, 204, 368, 404 (4) */

.bmi-btn-ghost          { background: transparent; color: #fff;
                          border: 1.5px solid var(--bmi-border-ondark); }
.bmi-btn-ghost:hover    { border-color: var(--bmi-lime-light); color: var(--bmi-lime-light); }


/*-- 4b. Sizes. --bmi-btn-px is read back by .is-busy to reserve spinner room. --*/
.bmi-btn-xl         { --bmi-btn-px: 34px; height: 54px; padding: 0 var(--bmi-btn-px); font-size: var(--bmi-fs-xs); letter-spacing: .01em; }
.bmi-btn-lg         { --bmi-btn-px: 32px; height: 52px; padding: 0 var(--bmi-btn-px); font-size: var(--bmi-fs-xs); }
.bmi-btn-md         { --bmi-btn-px: 30px; height: 50px; padding: 0 var(--bmi-btn-px); font-size: var(--bmi-fs-ui); }
.bmi-btn-sm         { --bmi-btn-px: 28px; height: 48px; padding: 0 var(--bmi-btn-px); font-size: var(--bmi-fs-ui); }
.bmi-btn-block      { width: 100%; }


/*-- =====================================================================
     5. GLOBAL CHROME   (utility bar, header, newsletter, footer, overlays)
     ===================================================================== */

/*-- 5a. Utility bar -- dc:28-50, present on all six artboards ----------*/
.bmi-utilbar        { background: var(--bmi-aubergine); color: var(--bmi-on-dark-util);
                      font-size: var(--bmi-fs-cap); letter-spacing: .01em; }
.bmi-utilbar-inner  { height: var(--bmi-utilbar-h); display: flex; align-items: center;
                      justify-content: space-between; gap: 24px; }
.bmi-utilbar-info   { display: flex; align-items: center; gap: 22px; }
.bmi-utilbar-info > * + * { border-left: 1px solid var(--bmi-border-util); padding-left: 22px; }
/*-- The standing claims are the "TopBar" core menu. A row with no link is a span, and each row
     after the first takes the same divider the phone link gives the block. The design lights the
     final claim in lime; which claim that is stays the client's, by the order of the rows. --*/
.bmi-utilbar-notes .nav-ul.t0 { display: flex; align-items: center; gap: 22px; }
.bmi-utilbar-notes .nav-li.t0 + .nav-li.t0 { border-left: 1px solid var(--bmi-border-util); padding-left: 22px; }
.bmi-utilbar-notes .nav-item  { color: var(--bmi-on-dark-muted);
                                transition: color var(--bmi-dur-fast) var(--bmi-ease); }
.bmi-utilbar-notes .nav-li.t0:last-child:not(:first-child) > .nav-item { color: var(--bmi-lime-light); font-weight: 600; }
.bmi-utilbar-notes .nav-item[href]:hover { color: #fff; }
.bmi-utilbar-notes .nav-ul.t1 { display: none; }
.bmi-utilbar-links  { display: flex; align-items: center; gap: 20px; }
.bmi-utilbar-link   { color: var(--bmi-on-dark-util);
                      transition: color var(--bmi-dur-fast) var(--bmi-ease); }
.bmi-utilbar-link:hover { color: var(--bmi-lime-light); }
   /* HOVER dc:39, 40, 41, 42 (4) */
.bmi-utilbar-social { display: flex; gap: 10px; padding-left: 6px; }
.bmi-utilbar-chip   { width: 22px; height: 22px; border-radius: 50%;
                      border: 1px solid var(--bmi-border-util);
                      display: grid; place-items: center; color: inherit;
                      transition: border-color var(--bmi-dur-fast) var(--bmi-ease),
                                  color var(--bmi-dur-fast) var(--bmi-ease); }
.bmi-utilbar-chip:hover { border-color: var(--bmi-lime); color: var(--bmi-lime-light); }
   /* ADDED -- the chips are links; the canvas gives them no hover */

/*-- 5b. Sticky header -- dc:52-72 --------------------------------------*/
.bmi-header        { position: sticky; top: 0; z-index: 40;
                     background: var(--bmi-header-bg); backdrop-filter: blur(10px);
                     -webkit-backdrop-filter: blur(10px);
                     border-bottom: 1px solid var(--bmi-border-header); }
.bmi-header-inner  { height: var(--bmi-header-h); display: flex; align-items: center;
                     justify-content: space-between; gap: 40px; }
.bmi-header-logo   { display: block; flex: 0 0 auto; }
.bmi-header-logo img { height: 52px; width: auto; }
.bmi-header-nav    { display: flex; align-items: center; gap: 34px;
                     font-size: var(--bmi-fs-ui); font-weight: 500; }

.bmi-header-actions { display: flex; align-items: center; gap: 14px; flex: 0 0 auto; }

/*-- 5b-ii. THE HEADER ACTION MENU IS DATA, so these rules dress whatever the administrator
     put in the "HeaderActions" core menu rather than four anchors a template hardcoded.

     The module already classifies every row and has since the ABT port: a row whose name is
     only an icon glyph gets `nav-icononly`, a row with words gets `nav-haslabel`. So the two
     shapes the design needs are the two classes already on the page, and adding a fifth row
     in the back office needs no CSS here at all. `nav-count` is the badge the module wraps a
     trailing count in, which is how the basket total rides on an ordinary menu row.

     Written against the module's OWN vocabulary. The previous rules were written against
     `.bmi-header-iconbtn` / `.bmi-header-cart` / `.bmi-header-cartpill`, which only ever
     existed on hand-written markup -- the module's classes had no styling at all, so the
     one emitted vocabulary and the one styled vocabulary never met. --*/
/*-- The language menu (bmi.js renderLanguageMenu). A first-party select until a visitor picks a
     language; the same header-control ring as the icon buttons beside it, so it reads as one row. --*/
.gtranslate_wrapper { display: flex; align-items: center; }
.gtranslate_wrapper .bmi-language { height: var(--bmi-touch-min); padding: 0 30px 0 14px; border-radius: 999px;
                      border: 1px solid var(--bmi-border-control-aa); background-color: transparent;
                      color: var(--bmi-text-caption); font: inherit; font-size: 14px; cursor: pointer;
                      transition: border-color var(--bmi-dur-fast) var(--bmi-ease), color var(--bmi-dur-fast) var(--bmi-ease); }
.gtranslate_wrapper .bmi-language:hover,
.gtranslate_wrapper .bmi-language:focus-visible { border-color: var(--bmi-purple); color: var(--bmi-purple); }
@media (max-width: 700px) { .gtranslate_wrapper .bmi-language { padding: 0 24px 0 10px; font-size: 13px; } }
.bmi-header-actionnav .nav-ul.t0 { display: flex; align-items: center; gap: 14px;
                      list-style: none; margin: 0; padding: 0; }
.bmi-header-actionnav .nav-li.t0 { margin: 0; padding: 0; }
.bmi-header-actionnav .nav-ul .nav-item { display: flex; align-items: center; text-decoration: none;
                      white-space: nowrap; gap: 0; }
.bmi-header-actionnav .nav-ul .nav-item .fa { font-size: 17px; line-height: 1; margin: 0; }

   /* An icon row IS the circle. Same geometry as .bmi-header-iconbtn below, which still
      dresses the drawer's close button and the privacy panel. */
.bmi-header-actionnav .nav-item.nav-icononly { width: var(--bmi-touch-min); height: var(--bmi-touch-min);
                      border-radius: 50%; justify-content: center;
                      border: 1px solid var(--bmi-border-control-aa); background: transparent;
                      color: var(--bmi-text-caption);
                      transition: border-color var(--bmi-dur-fast) var(--bmi-ease),
                                  color var(--bmi-dur-fast) var(--bmi-ease); }
.bmi-header-actionnav .nav-item.nav-icononly:hover,
.bmi-header-actionnav .nav-item.nav-icononly:focus-visible { border-color: var(--bmi-purple); color: var(--bmi-purple); }
   /* The module gives every icon row a text label taken from its URL, so the icon has an
      accessible name and the mobile drawer can read "[icon] Account" off the SAME row.
      Hidden from sight here, never from the accessibility tree: display:none would take
      the name away with it. */
.bmi-header-actionnav .nav-item.nav-icononly .nav-iconlabel { position: absolute; width: 1px; height: 1px;
                      margin: -1px; padding: 0; overflow: hidden; white-space: nowrap;
                      clip: rect(0 0 0 0); clip-path: inset(50%); border: 0; }

   /* A row with words IS the filled chip -- the basket, and anything else the client labels. */
.bmi-header-actionnav .nav-item.nav-haslabel { position: relative; height: var(--bmi-touch-min);
                      padding: 0 16px; border-radius: 19px;
                      background: var(--bmi-purple); color: #fff;
                      font-size: var(--bmi-fs-meta); font-weight: 600;
                      transition: background-color var(--bmi-dur-fast) var(--bmi-ease),
                                  color var(--bmi-dur-fast) var(--bmi-ease); }
.bmi-header-actionnav .nav-item.nav-haslabel:hover,
.bmi-header-actionnav .nav-item.nav-haslabel:focus-visible { background: var(--bmi-purple-hover); color: #fff; }
   /* HOVER dc:66 -- the canvas says #54134F here and #4E1350 on the other eight
      purple buttons. NORMALISED to one value; #54134F is dropped from the palette. */
.bmi-header-actionnav .nav-item.nav-haslabel .fa { margin-right: 9px; }
.bmi-header-actionnav .nav-item .nav-count { min-width: 20px; height: 20px; padding: 0 6px; margin-left: 9px;
                      border-radius: 10px; background: var(--bmi-lime); color: var(--bmi-ink-body);
                      font-size: var(--bmi-fs-label); font-weight: 700;
                      display: grid; place-items: center; }

.bmi-header-iconbtn { width: var(--bmi-touch-min); height: var(--bmi-touch-min); border-radius: 50%;
                      border: 1px solid var(--bmi-border-control-aa); background: transparent;
                      display: grid; place-items: center; color: var(--bmi-text-caption);
                      transition: border-color var(--bmi-dur-fast) var(--bmi-ease),
                                  color var(--bmi-dur-fast) var(--bmi-ease); }
.bmi-header-iconbtn:hover { border-color: var(--bmi-purple); color: var(--bmi-purple); }
.bmi-header-burger  { display: none; width: var(--bmi-touch-min); height: var(--bmi-touch-min); place-items: center;
                      color: var(--bmi-text); border: 0; background: transparent; cursor: pointer; }


/*-- 5d. Footer -- dc:775-836 -------------------------------------------
     No bottom padding: .bmi-footer-legal's own padding:26px 0 closes it. */
.bmi-footer          { background: var(--bmi-ink); color: var(--bmi-on-dark-body); padding: 72px 0 0; }
.bmi-footer-grid     { display: grid; grid-template-columns: 1.4fr 1fr 1fr 1fr 1fr; gap: 48px; }
/*-- bmi-logo-white.png is the reversed master, not the colour one recoloured. The colour master
     is ink on white: the letter counters, circuit traces and leaf veins are OPAQUE WHITE fills.
     brightness(0) invert(1) painted those the same white as the strokes, so every counter filled
     in and BIOMEDIS read as solid blobs on the plum. The reversed asset knocks the white out to
     transparent instead, so the footer ink shows through the counters the way the page shows
     through them in the header. No filter: the asset is already the right colour. --*/
.bmi-footer-logo     { height: 56px; width: auto; opacity: .92; }
/*-- The sentence and the contact link under the logo are the "FooterIntro" core menu: a row
     with no link is the sentence, a row with one is the lime link. The module's own nowrap on
     top-level items is lifted, or the sentence runs out of its column in one line. --*/
.bmi-footer-intro .nav-ul.t0 { display: flex; flex-direction: column; align-items: flex-start;
                       gap: 16px; margin-top: 20px; }
.bmi-footer-intro .nav-item,
.module-site_navigation.bmi-footer-intro .nav-ul.t0 .nav-li.t0 .nav-item.t0 { display: block; white-space: normal;
                       font-size: var(--bmi-fs-ui); line-height: 1.7; color: var(--bmi-on-dark-muted); }
.bmi-footer-intro .nav-item[href],
.module-site_navigation.bmi-footer-intro .nav-ul.t0 .nav-li.t0 .nav-item.t0[href] { line-height: 1.4; color: var(--bmi-lime-light);
                       transition: color var(--bmi-dur-fast) var(--bmi-ease); }
.module-site_navigation.bmi-footer-intro .nav-ul.t0 .nav-li.t0 .nav-item.t0[href]:hover { color: #fff; }
.bmi-footer-intro .nav-ul.t1 { display: none; }
.bmi-footer-social   { display: flex; gap: 10px; margin-top: 22px; }
/*-- The chip names its own colour. It used to inherit the site's purple link colour, which on
     the aubergine footer is about 1.5:1 -- three icons nobody could see. --*/
.bmi-footer-chip     { width: 34px; height: 34px; border-radius: 50%; color: var(--bmi-on-dark-body);
                       border: 1px solid var(--bmi-on-dark-muted);
                       display: grid; place-items: center;
                       transition: border-color var(--bmi-dur-fast) var(--bmi-ease),
                                   color var(--bmi-dur-fast) var(--bmi-ease); }
.bmi-footer-chip:hover { border-color: var(--bmi-lime); color: var(--bmi-lime-light); }  /* ADDED */
.bmi-footer-link     { color: var(--bmi-on-dark-muted);
                       transition: color var(--bmi-dur-fast) var(--bmi-ease); }
.bmi-footer-link:hover { color: var(--bmi-lime-light); }
   /* HOVER dc:792-797, 803-807, 813-817, 823-827 -- 20 identical attributes, one rule */
.bmi-footer-legal    { margin-top: 60px; padding: 26px 0;
                       border-top: 1px solid var(--bmi-border-footer-rule);
                       display: flex; align-items: center; justify-content: space-between;
                       gap: 24px; font-size: var(--bmi-fs-meta);
                       color: var(--bmi-on-dark-faint-aa); }

/*-- 5e. Overlays: scrim, cart drawer, mobile nav, filter sheet.
     ONE overlay system, three uses. dc:838-875. ------------------------ */
.bmi-scrim        { position: fixed; inset: 0; background: var(--bmi-scrim); z-index: 90;
                    animation: bmiFade var(--bmi-dur-scrim) var(--bmi-ease-out); }
body.has-drawer   { overflow: hidden; }   /* JS toggles the CLASS, never an inline style */

.bmi-drawer       { position: fixed; top: 0; right: 0; bottom: 0; width: 430px; z-index: 91;
                    background: #fff; display: flex; flex-direction: column;
                    box-shadow: var(--bmi-shadow-drawer);
                    animation: bmiDrawer var(--bmi-dur-drawer) var(--bmi-ease-out); }
/* The canvas has no exit animation -- it unmounts. Production mirrors the entry. */
.bmi-drawer.is-closing { animation: bmiDrawerOut var(--bmi-dur-panel) var(--bmi-ease-out) forwards; }


/*-- Mobile nav drawer. NET NEW -- the canvas is desktop-only. Reuses the
     cart drawer's geometry, scrim and keyframe rather than inventing a
     second overlay language. The 2.5px lime nav underline cannot survive a
     vertical stack, so the active marker becomes a 3px lime LEFT RAIL --
     the pattern .bmi-sidebar-rail already uses. Same vocabulary. -------- */
.bmi-mobilenav      { position: fixed; top: 0; right: 0; bottom: 0; z-index: 91;
                      width: min(86vw, 360px); background: var(--bmi-aubergine);
                      color: var(--bmi-on-dark); display: flex; flex-direction: column;
                      box-shadow: var(--bmi-shadow-drawer);
                      animation: bmiDrawer var(--bmi-dur-drawer) var(--bmi-ease-out); }
.bmi-mobilenav-head { display: flex; align-items: center; justify-content: space-between;
                      padding: 22px 24px; }
/*-- The drawer head reuses .bmi-header-logo, which the ladder shrinks to 44px at 1080 and 38px
     at 620 -- correct for the STICKY BAR, where vertical space is the whole constraint, and
     wrong here, where the panel is full height and has room. Inherited, the logo rendered 71x38
     in the drawer and its wordmark was illegible. Held at the desktop size instead; the selector
     is more specific than the ladder's, so it wins wherever it lands in the file. --*/
.bmi-mobilenav-head .bmi-header-logo img { height: 52px; }
.bmi-mobilenav-head .bmi-header-iconbtn { color: var(--bmi-on-dark); border-color: var(--bmi-on-dark-muted); }
.bmi-mobilenav-head .bmi-header-iconbtn:hover { color: var(--bmi-lime); border-color: var(--bmi-lime); }
.bmi-mobilenav-list { display: flex; flex-direction: column; overflow: auto; flex: 1; }
.bmi-mobilenav-util { padding: 18px 24px; font-size: var(--bmi-fs-ui);
                      color: var(--bmi-on-dark-util); display: flex; flex-direction: column; gap: 14px; }
/*-- The drawer's copy of the language menu (template.master). Shown only on a phone, where the
     header row gives its room to the burger; the 17i step switches the two over. The select wears
     the header control's ring, recoloured for the aubergine panel. --*/
.bmi-mobilenav .bmi-mobilenav-language { display: none; padding: 6px 24px 18px; }
.bmi-mobilenav-language .bmi-language { width: 100%; color: var(--bmi-on-dark);
                      border-color: var(--bmi-on-dark-muted); background-color: transparent; }
.bmi-mobilenav-language .bmi-language option { color: var(--bmi-ink-body); }
.bmi-mobilenav-language .bmi-language:hover,
.bmi-mobilenav-language .bmi-language:focus-visible { color: var(--bmi-lime-light); border-color: var(--bmi-lime); }


/*-- =====================================================================
     6. CARDS + THE PRODUCT SYSTEM
     One shell, five instances. dc:92, 174, 346, 526, 642.
     ===================================================================== */
.bmi-card        { background: #fff; border: 1px solid var(--bmi-border-card);
                   border-radius: var(--bmi-radius-card); overflow: hidden;
                   display: flex; flex-direction: column; }
/* Hover movement belongs only to the element that handles the action. */
.bmi-card-lift:where([href], [onclick]) { transition: box-shadow var(--bmi-dur-card) var(--bmi-ease),
                               transform var(--bmi-dur-card) var(--bmi-ease); }
.bmi-card-lift:where([href], [onclick]):hover,
.bmi-card-lift:where([href], [onclick]):focus-visible { box-shadow: var(--bmi-shadow-card); transform: translateY(-3px); }


/*-- =====================================================================
     7. EDITORIAL BLOCKS
     ===================================================================== */


/*-- =====================================================================
     8. CATALOGUE   (shop layout, sidebar, toolbar, pager, breadcrumb)
     ===================================================================== */


/*-- 8d. Pagination. .bmi-pager-step is the prev/next pill pager inherited from ABT, for
       account and admin record lists of unknown length. --*/
.bmi-pager      { display: flex; justify-content: center; align-items: center;
                  gap: 8px; margin-top: 52px; }
.bmi-pager-at   { font-size: 14px; color: var(--bmi-text-caption);
                  font-variant-numeric: tabular-nums; }
.bmi-pager-step { background: #fff; border: 1px solid var(--bmi-border-control-aa);
                  border-radius: 100px; padding: 8px 18px; font: inherit; font-size: 14px;
                  font-weight: 600; color: var(--bmi-text-strong); cursor: pointer;
                  transition: background var(--bmi-dur-fast) var(--bmi-ease),
                              border-color var(--bmi-dur-fast) var(--bmi-ease); }
.bmi-pager-step:hover:not([disabled]) { background: var(--bmi-surface-2);
                                        border-color: var(--bmi-purple); }
.bmi-pager-step[disabled] { color: var(--bmi-text-disabled); border-color: var(--bmi-border-card);
                            opacity: .55; cursor: default; }


/*-- 10b. Tier cards -- dc:698-709. .bmi-tier-rec compensates its extra 1px
     border with padding so the two cards stay the same height. The canvas
     does not, and the recommended card ends up 2px taller. -------------- */
.bmi-tier      { border: 1px solid var(--bmi-border-card);
                 border-radius: var(--bmi-radius-lg); padding: 34px 32px; }
.bmi-tier-eyebrow { font-size: var(--bmi-fs-eyebrow); font-weight: 700; letter-spacing: .14em;
                    text-transform: uppercase; color: var(--bmi-olive); }
.bmi-tier-fig  { font-family: var(--bmi-serif); font-size: 40px; line-height: 1;
                 margin-top: 14px; color: var(--bmi-text-strong); }
.bmi-tier-unit { font-family: var(--bmi-sans); font-size: var(--bmi-fs-base); font-weight: 500;
                 color: var(--bmi-text-caption); }
.bmi-tier-body { font-size: var(--bmi-fs-xs); line-height: 1.6;
                 color: var(--bmi-text-muted); margin-top: 14px; }


/*-- =====================================================================
     11. SERVICES
     ===================================================================== */
.bmi-service-row   { display: grid; grid-template-columns: 280px 1fr 220px; gap: 36px;
                     background: #fff; border: 1px solid var(--bmi-border-card);
                     border-radius: var(--bmi-radius-lg); overflow: hidden; }
/* dc:735 declares style-hover="border-color:#DCCFDC" on this ROW. The row is not a
   link -- its "Buy now" button is -- so under the house hover rule (hover is a promise
   of interactivity) the row hover is illegal unless the whole row becomes one link.
   DECISION: dropped. Kept here, commented, so the next reviewer sees a decision
   rather than an omission. Re-enable ONLY if the row is wrapped in a single <a>.
*/
.bmi-service-media { position: relative; background: var(--bmi-surface-2); overflow: hidden; min-height: 240px; }
.bmi-service-media img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.bmi-service-mid   { padding: 32px 0; }
.bmi-service-tag   { font-size: var(--bmi-fs-label); font-weight: 700; letter-spacing: .14em;
                     text-transform: uppercase; color: var(--bmi-text-meta-aa); }
.bmi-service-title { font-family: var(--bmi-serif); font-weight: 400; font-size: 28px;
                     letter-spacing: -.015em; margin: 10px 0 0; color: var(--bmi-text-strong); }
.bmi-service-body  { font-size: var(--bmi-fs-sm); line-height: 1.66; color: var(--bmi-text-muted);
                     margin-top: 12px; }
/* dc:743 has a redundant padding-left:32px after the shorthand; effective value is
   32px on all four sides. Written once here. */
.bmi-service-rail  { padding: 32px; border-left: 1px solid var(--bmi-rule-faint);
                     display: flex; flex-direction: column; justify-content: center;
                     align-items: flex-start; gap: 14px; }
.bmi-service-price { font-size: 24px; font-weight: 600; letter-spacing: -.015em;
                     color: var(--bmi-text-strong); }
.catalog-category-intro { margin-bottom: 28px; }


/*-- =====================================================================
     12. FORMS + STATES
     The canvas has ZERO :focus rules, one bare outline:none (dc:768), no
     disabled state, no error state, no loading state, and exactly ONE empty
     state (the empty cart). Everything here is net-new and specified as
     values, not intentions.
     ===================================================================== */

/*-- 12a. Inputs.

     ONE input control, and it is `.textbox`.

     This block used to specify `.bmi-input`, `.bmi-field-label`, `.bmi-help`
     and `.bmi-error-text`. NOTHING IN THE SITE EMITS ANY OF THEM -- 13 rules
     for `.bmi-input` and not one element carrying the class, while the input
     that every form actually renders, `.textbox` (92 files), got seven rules
     and no focus ring, no error state and no disabled state. That is the whole
     reason the five public forms looked like five different products: the
     design system was written against names the modules do not use, so each
     form ended up wearing whatever the module layer happened to set.

     So the specification moved onto the emitted names, and the `bmi-` names
     are kept as aliases on the same rules -- they are the documented design
     system vocabulary and hand-written markup may still reach for them.
     Anything added here must list BOTH.

     `--bmi-input-h` / `--bmi-input-px` hold the metrics so a select, a file
     field, a textarea and the button on a form row cannot drift apart. --*/
.textbox { box-sizing: border-box;
                   height: var(--bmi-input-h); padding: 0 var(--bmi-input-px);
                   background: #fff;
                   border: 1px solid var(--bmi-border-control-aa);
                   border-radius: var(--bmi-radius-ctl);
                   font-family: var(--bmi-sans); font-size: var(--bmi-fs-xs);
                   color: var(--bmi-text);
                   transition: border-color var(--bmi-dur-fast) var(--bmi-ease),
                               box-shadow var(--bmi-dur-fast) var(--bmi-ease); }
/*-- A form field fills the column it is in. The TEMPLATE decides how wide that
     column is; the field never decides for itself, and there is no max-width
     here or anywhere below. `.bmi-input` kept a 300px fixed width, which is the
     same mistake in the other direction. --*/
.textbox { width: 100%; }
.textbox::placeholder { color: var(--bmi-text-meta-aa); }
textarea.textbox { height: auto; min-height: 140px;
                     padding: 14px var(--bmi-input-px); line-height: 1.6; }
/*-- Selects and file fields are inputs and must not look like a third thing.
     A native select ignores `height` in some engines unless line-height comes
     with it, which is why the admin dropdowns sat 2px short of their siblings. --*/
select.textbox { line-height: var(--bmi-input-h); }
/* THE replacement for the canvas' bare outline:none at dc:768. Both :focus and
   :focus-visible -- a text field should ring on mouse focus too. */
.textbox:focus,
.textbox:focus-visible {
	outline: none;
	border-color: var(--bmi-purple);
	box-shadow: 0 0 0 3px var(--bmi-focus-halo);
}
/*-- The one-line note under a field. `.field-note` is what members renders and
     `.bmi-help` is the design system's name for it; both had to become the same
     thing, because `.field-note` had NO rule at all and so inherited 16px body
     copy in full body colour. On Create Account that made "Optional. Tell us
     where you work" and "At least 10 characters." typographically identical to
     the form's own prose, which is what flattened that page: every string on it
     carried the same weight, so none of them carried any. --*/
.field-note { display: block; margin-top: 6px; font-size: var(--bmi-fs-meta);
            line-height: 1.45; color: var(--bmi-text-caption); }

/*-- 12b. Error -- validate ON BLUR AND ON SUBMIT, never on keystroke. An
     error that fires on the third character of an email address is an
     accusation, not help.

     `.form-validator` and `.cvalidation` are what the module layer actually
     emits (setupValidator sets CssClass = "form-validator" and its comment
     says the colour "comes from the shared template class" -- which did not
     exist, so every validation message on the site rendered as ASP.NET's
     inline red). `.field-validators` is the wrapper and must stay empty-safe:
     it is rendered on every field whether or not it holds a message, so it
     may not carry margin of its own. ---------------------------------------- */
.form-group.has-error .textbox,
.field-group.has-error .textbox { border-color: var(--bmi-error);
                                  box-shadow: 0 0 0 3px rgba(163,34,24,.14); }
.field-validators:empty { display: none; }
.form-validator,
.cvalidation { display: flex; align-items: flex-start; gap: 6px; margin-top: 6px;
                  font-size: var(--bmi-fs-meta); line-height: 1.4; color: var(--bmi-error); }
/*-- ASP.NET BaseValidator writes ForeColor="Red" as an INLINE style, which no
     class selector can beat. The modules set CssClass and leave ForeColor at
     its default, so the palette has to be reasserted at the same specificity
     the inline style occupies. --*/
span.form-validator, span.cvalidation { color: var(--bmi-error) !important; }

/*-- 12c. Page-level messages.
     The class names form-message / msg-success / error-msg / msg-error /
     msg-info are CMS-CORE VOCABULARY, not ABT vocabulary, and are NOT
     renamed on the fork: FormMessage.cs writes them (line 39 picks the
     variant, line 41 writes "form-message " + variant), webitems.content.js
     writes them, and ~20 module admin pages write them -- 158 occurrences
     tree-wide. Only the COLOURS are re-pointed. The rule requires BOTH
     classes on the same element, which is exactly why FormMessage.cs exists.
     The 3px left accent marks a message with one
     notice language, not two. ------------------------------------------ */
.form-message { display: block; margin: 0 0 16px; }
.form-message.error-msg, .error-msg.form-message, .form-message.msg-error {
	padding: 12px 14px; border-radius: var(--bmi-radius-ctl);
	background: var(--bmi-error-tint); border-left: 3px solid var(--bmi-error);
	color: var(--bmi-error); font-size: 14px; line-height: 1.4;
}
.form-message.msg-success, .msg-success.form-message {
	padding: 12px 14px; border-radius: var(--bmi-radius-ctl);
	background: var(--bmi-success-tint); border-left: 3px solid var(--bmi-success);
	color: var(--bmi-success); font-size: 14px; line-height: 1.4;
}
.form-message.msg-info, .msg-info.form-message {
	padding: 14px 16px; border-radius: var(--bmi-radius-ctl);
	background: var(--bmi-info-tint); border-left: 3px solid var(--bmi-info);
	color: var(--bmi-text-strong); font-size: 14px; line-height: 1.45;
}
.form-message.msg-warn, .msg-warn.form-message {
	padding: 12px 14px; border-radius: var(--bmi-radius-ctl);
	background: var(--bmi-warn-tint); border-left: 3px solid var(--bmi-warn);
	color: var(--bmi-warn); font-size: 14px; line-height: 1.4;
}
.error-msg   { color: var(--bmi-error); }
.msg-success, .success-msg { color: var(--bmi-success); }

/*-- 12d. Disabled. --bmi-text-disabled is a real value (4.51:1 on the
     #F5F1F5 disabled ground), NOT opacity:.5 -- which would drag it to
     ~2.4:1. A disabled control still has to be identifiable.
     pointer-events:none on the button but NOT the input, because a disabled
     input still needs to accept a hover title explaining why. ---------- */
.bmi-btn[disabled], .bmi-btn.is-disabled {
	background: var(--bmi-surface-2); color: var(--bmi-text-disabled);
	border-color: var(--bmi-border-card); box-shadow: none;
	cursor: not-allowed; pointer-events: none;
}

/*-- 12e. Loading. TWO primitives, no global page spinner.
     .is-busy is the class bmiGuardOnce sets (the reference build named it differently; its script lines 131 and 135)
     already adds and removes on the double-submit guard -- only the visual
     is new. The label stays put so the button never changes width mid-click. */
.bmi-btn.is-busy { opacity: .62; pointer-events: none; position: relative;
                   padding-right: calc(var(--bmi-btn-px, 24px) + 22px); }
.bmi-btn.is-busy::after {
	content: ""; position: absolute; right: 12px; top: 50%; margin-top: -7px;
	width: 14px; height: 14px; border-radius: 50%;
	border: 2px solid currentColor; border-right-color: transparent;
	animation: bmiSpin .7s linear infinite;
}


/*-- 13. Icons use the Font Awesome library shipped with WebItems. --*/
/*-- ONE ICON LIBRARY, AND IT IS THE FRAMEWORK'S.

     This used to be an SVG sprite: nineteen hand-drawn symbols, twelve of them ever used, sitting
     beside the Font Awesome the framework already ships and every module config, back-office
     screen and error box already uses. Two systems doing one job, and because the public template
     never loaded FA, the `fa fa-*` glyphs modules DO emit into public pages rendered as nothing
     at all. Loading the framework's library fixes both at once.

     `.bmi-ico` is now a SIZE hint on an `<i>`, not an icon system. Font Awesome sizes by
     font-size, so that is what these set. --*/
.bmi-ico      { display: inline-block; vertical-align: middle; flex: 0 0 auto;
                font-size: 17px; line-height: 1; text-align: center; }
.bmi-utilbar-chip .bmi-ico { font-size: 11px; }
.bmi-footer-chip .bmi-ico  { font-size: 13px; }


/*-- =====================================================================
     14. INHERITED ABT COMPONENTS   (account + admin surfaces)
     Renamed from the reference build's prefix, restyled to BMI tokens, geometry kept verbatim --
     the account area is the same product, so its proportions do not change.
     The rename is TREE-WIDE: 4,169 abt[-_] occurrences across 114 files in
     public/. See css-architecture.md section 3 for what must move with each.
     ===================================================================== */

/*-- 14a. Account nav (was account-nav, reference style.css:1261-1273).
     NOTE: an account-card class does NOT exist in the reference build despite what its
     SKILL.md line 55 claims -- grep over the whole public/ tree returns
     zero hits. Do not carry a phantom. Account cards use .bmi-card. ---- */
.bmi-account-nav        { display: flex; flex-direction: column; }
.bmi-account-nav-link   { display: flex; align-items: center; gap: 10px; padding: 10px 13px;
                          font-size: var(--bmi-fs-ui); font-weight: 500;
                          color: var(--bmi-text-muted); text-decoration: none;
                          border-radius: var(--bmi-radius-ctl);
                          transition: background var(--bmi-dur-fast) var(--bmi-ease),
                                      color var(--bmi-dur-fast) var(--bmi-ease); }
.bmi-account-nav-link:hover  { background: var(--bmi-surface-2); color: var(--bmi-text-strong); }
.bmi-account-nav-link.is-active { background: var(--bmi-purple); color: #fff; font-weight: 600; }
.bmi-account-nav-link .fa-solid { width: 18px; text-align: center; flex: 0 0 18px; }
.bmi-account-sidebar    { position: sticky; top: var(--bmi-sticky-top); }
/* The nav card: the member's name and email above the links (reference style.css:1258-1274).
   The links are DIRECT children of .bmi-account-nav, which is what lets 17f wrap them into a row
   of chips on a phone. */
.bmi-account-navcard    { padding: 14px 8px 8px; }
.bmi-account-ident      { padding: 4px 13px 13px; margin-bottom: 8px; border-bottom: 1px solid var(--bmi-rule); }
.bmi-account-name       { font-family: var(--bmi-serif); font-weight: 400; font-size: 19px;
                          color: var(--bmi-text-strong); overflow-wrap: anywhere; }
.bmi-account-handle     { font-size: var(--bmi-fs-meta); color: var(--bmi-text-caption); overflow-wrap: anywhere; }
.bmi-sidebar-label      { font-size: var(--bmi-fs-label); font-weight: 700; letter-spacing: .14em;
                          text-transform: uppercase; color: var(--bmi-text-eyebrow-aa);
                          padding: 14px 13px 6px; }

/*-- 14a-2. Account CONTENT (reference style.css:1397-1398, 1506-1509, 1632, 1639,
     2283-2286, renamed abt- to bmi- and retokenised).

     These twelve classes were being EMITTED by the members module with no rule
     anywhere under public/. The module's own comments say they come "from the
     template system" -- they never did, so the whole signed-in account area
     rendered as unstyled stacked divs. That is the broken-looking account form,
     and it is the same defect as the back office styling itself with front-end
     classes: markup and stylesheet describing different vocabularies.

     TWO key/value conventions are in the tree and both are covered below rather
     than rewritten, because both render correctly once the CSS exists:
       .bmi-kv-row > .bmi-kv-k / .bmi-kv-v   (option.ascx.cs KeyValue helper)
       .bmi-kv-row > .k / .v                 (membership.ascx.cs)
     Normalising the markup is a separate change and not worth touching working
     output for. ---------------------------------------------------------- */

/* Page greeting, one per account page. The size lives on the container, so the heading inside it
   has to inherit or the user-agent default wins: it rendered at 92px as an h1 and 69px as an h2
   against the 46px this sets. Declared for both tags because the tag is a document-structure
   decision, not a styling one, and it has already changed once. */
/* ONE SERIF, NEVER BOLD. Newsreader is loaded at 300 and 400 only, so every 600 here was a
   bold the browser faked by smearing the regular face: "Hello, Vera", the sub-section heads, the
   name card and the referral figures read as a different, heavier typeface from the page title
   above them. Each now uses a weight that exists. */
.bmi-dashboard-welcome  { font-family: var(--bmi-serif); font-size: var(--bmi-fs-d6);
                          font-weight: 300; color: var(--bmi-text-strong); margin: 0 0 20px; }
.bmi-dashboard-welcome h1,
.bmi-dashboard-welcome h2 { font: inherit; color: inherit; margin: 0; }

/* Generic grouping block. Spacing only, so it composes with .bmi-card. */
.bmi-dashboard-section  { margin-bottom: 24px; }
.bmi-dashboard-section:last-child { margin-bottom: 0; }

/* In-page section heading: the ONE vocabulary for account sub-sections. */
.bmi-subhead            { font-family: var(--bmi-serif); font-size: 22px;
                          font-weight: 400; color: var(--bmi-text-strong); margin: 0 0 14px;
                          padding-bottom: 10px; border-bottom: 1px solid var(--bmi-rule); }
.bmi-subhead-count      { color: var(--bmi-text-meta-aa); font-weight: 400; font-size: .9em; }

/* Quiet definition rows: label left, value right, hairline between. */
.bmi-kv-row             { display: flex; justify-content: space-between; gap: 18px;
                          padding: 10px 0; border-bottom: 1px solid var(--bmi-rule); }
.bmi-kv-row:last-child  { border-bottom: 0; }
.bmi-kv-row .bmi-kv-k,
.bmi-kv-row .k          { color: var(--bmi-text-meta-aa); font-size: var(--bmi-fs-ui);
                          flex: 0 0 auto; }
.bmi-kv-row .bmi-kv-v,
.bmi-kv-row .v          { font-weight: 600; color: var(--bmi-text-strong); text-align: right;
                          min-width: 0; overflow-wrap: anywhere; }

/* Listing rows (orders, downloads, referrals). Same hairline rhythm as kv. */
.bmi-list-row           { display: flex; justify-content: space-between; align-items: center;
                          gap: 16px; padding: 12px 0; border-bottom: 1px solid var(--bmi-rule); }
.bmi-list-row:last-child { border-bottom: 0; }
.bmi-list-row h3        { font-size: var(--bmi-fs-ui); margin: 0; }

/* Saved address card. Boxed, because several sit side by side and the flat
   hairline rhythm above cannot show where one address ends and the next starts. */
.bmi-address-card       { background: #fff; border: 1px solid var(--bmi-border-card);
                          border-radius: var(--bmi-radius-card); padding: 16px 18px;
                          margin-bottom: 12px; }
.bmi-address-card:last-child { margin-bottom: 0; }
.bmi-address-label      { font-size: var(--bmi-fs-eyebrow); font-weight: 700;
                          letter-spacing: .08em; text-transform: uppercase;
                          color: var(--bmi-text-eyebrow-aa); margin-bottom: 6px; }
.bmi-address-body       { color: var(--bmi-text); line-height: 1.5; }
.bmi-address-flags      { margin-top: 10px; display: flex; flex-wrap: wrap; gap: 6px;
                          font-size: var(--bmi-fs-meta); color: var(--bmi-text-meta-aa); }

/* Quick-link card body: the page name over one line of what it holds. Block, and allowed to
   wrap: the row-flex and nowrap this used to carry put the name and the line side by side and
   cut the name off. */
.bmi-ql-body            { display: block; min-width: 0; }
.bmi-ql-name            { display: block; font-weight: 600; color: var(--bmi-text-strong); }


/*-- 14d. Badges (was badge-*, reference style.css:1663-1691). That build's pill
     GEOMETRY is kept verbatim; only the hues move. ABT's teal "good" /
     gold "in-flight" / red "ended" become BMI olive / purple / error. --- */
.bmi-badge-unread {
	display: inline-block; padding: 3px 10px; border-radius: 100px;
	font-size: var(--bmi-fs-eyebrow); font-weight: 600;
}
.bmi-badge-unread   { background: var(--bmi-error);    color: #fff; font-weight: 700; }
a.bmi-badge-unread { text-decoration: none; color: #fff;
                                                           transition: background var(--bmi-dur-fast) var(--bmi-ease),
                                                                       color var(--bmi-dur-fast) var(--bmi-ease); }
a.bmi-badge-unread:hover {
	background: var(--bmi-ink); color: #fff; text-decoration: underline;
}

/*-- 14g. ONE ACCOUNT VOCABULARY (2026-09-27), ported from the reference build's account area
     (style.css 176-215, 1516, 1526-1559, 1633-1638, 1663-1689) and retokenised. The account pages
     are drawn by two modules, members and store, which is what puts these here rather than in
     either one.

     Buttons: the .btn family (16g) is the only one on account pages. .btn-danger is a destructive
     action, never beside Save; .is-busy is what bmiGuardOnce sets while a submit is in flight.
     Messages: .form-message with .msg-success / .error-msg / .msg-info / .msg-warn (12c).
     Empty states: .no-results (16d), a box that says what to do next. --*/
.btn-danger             { background: var(--bmi-error); border-color: var(--bmi-error); color: #fff; }
/* literal because: the error red has no hover token; this is it one step darker (8.9:1 on white). */
.btn-danger:hover       { background: #7F1A12; border-color: #7F1A12; color: #fff; }
.btn.is-busy, .button.is-busy { opacity: .62; pointer-events: none; cursor: progress; position: relative; }
button.btn.is-busy, a.btn.is-busy { padding-right: 44px; }
button.btn.is-busy::after, a.btn.is-busy::after {
	content: ""; position: absolute; right: 14px; top: 50%; margin-top: -7px;
	width: 14px; height: 14px; border-radius: 50%;
	border: 2px solid currentColor; border-right-color: transparent;
	animation: bmiSpin .7s linear infinite;
}
.no-results > p { margin: 0 0 14px; }
.no-results > p:last-child { margin-bottom: 0; }

/* Status pills: olive = done or good, purple = waiting on something, red = ended or refused,
   grey = neither, and asks nothing of the reader. */
.bmi-badge              { display: inline-block; padding: 3px 10px; border-radius: 100px;
                          font-size: var(--bmi-fs-eyebrow); font-weight: 600; line-height: 1.4;
                          white-space: nowrap; vertical-align: middle; color: #fff; }
.bmi-badge-open         { background: var(--bmi-success); }
.bmi-badge-pending      { background: var(--bmi-purple); }
.bmi-badge-closed       { background: var(--bmi-error); }
.bmi-badge-muted        { background: var(--bmi-text-caption); }

/* One figure a reader compares (money, a count): never broken across two lines. */
.bmi-money              { white-space: nowrap; font-variant-numeric: tabular-nums; }

/* Data table: quiet caps header, hairline rows, sideways scroll on a narrow screen. Amount and
   action columns are .right so their digits line up. */
.bmi-table-wrap         { overflow-x: auto; }
.bmi-table              { width: 100%; border-collapse: collapse; font-size: var(--bmi-fs-ui); }
.bmi-table th           { text-align: left; font-size: var(--bmi-fs-label); font-weight: 700;
                          letter-spacing: .08em; text-transform: uppercase; color: var(--bmi-text-eyebrow-aa);
                          padding: 8px 12px 8px 0; border-bottom: 1px solid var(--bmi-border-control-aa);
                          white-space: nowrap; }
.bmi-table td           { padding: 12px 12px 12px 0; border-bottom: 1px solid var(--bmi-rule); vertical-align: top; }
.bmi-table tr:last-child td { border-bottom: 0; }
.bmi-table th:last-child, .bmi-table td:last-child { padding-right: 0; }
.bmi-table th.right, .bmi-table td.right { text-align: right; }
.bmi-table td.nowrap    { white-space: nowrap; }
.bmi-table-sub          { display: block; margin-top: 2px; font-size: var(--bmi-fs-meta);
                          color: var(--bmi-text-caption); line-height: 1.35; }

/* Figure tiles: a row of headline numbers above the detail they summarise. */
.bmi-stats              { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
                          gap: 14px; margin: 0 0 32px; }
.bmi-stat               { display: flex; flex-direction: column; padding: 16px 18px; background: #fff;
                          border: 1px solid var(--bmi-border-card); border-radius: var(--bmi-radius-card); }
.bmi-stat-count         { font-family: var(--bmi-serif); font-size: var(--bmi-fs-d10); font-weight: 400;
                          line-height: 1.1; color: var(--bmi-purple); overflow-wrap: anywhere; }
.bmi-stat-label         { margin-top: 6px; font-size: var(--bmi-fs-ui-sm); font-weight: 600; color: var(--bmi-text-strong); }
.bmi-stat-note          { margin-top: 2px; font-size: var(--bmi-fs-meta); color: var(--bmi-text-caption); }


/*-- 14e. Upload zone (was upload-zone, reference style.css:1732-1733,
     emitted by App_Code/SiteShell/UploadWidget.cs). All three sides move
     together: the CSS here, the C# emitter (lines 36-38 and 57-68), and
     the JS auto-attach pass. The fa-camera / fa-trash glyphs at
     UploadWidget.cs:61 and :63 become .bmi-ico SVGs in the same commit. -- */
.bmi-upload-zone          { display: flex; gap: 18px; align-items: flex-start; padding: 16px;
                            background: #fff; border: 1px dashed var(--bmi-border-control-aa);
                            border-radius: var(--bmi-radius-card);
                            transition: border-color var(--bmi-dur-panel) var(--bmi-ease),
                                        background var(--bmi-dur-panel) var(--bmi-ease); }
.bmi-upload-zone.dragover { border-color: var(--bmi-lime); background: var(--bmi-wash-lime); }
.bmi-upload-preview       { width: 88px; height: 88px; border-radius: 50%; overflow: hidden;
                            background: var(--bmi-surface-2); display: grid; place-items: center;
                            color: var(--bmi-text-meta-aa); flex: 0 0 auto; }
.bmi-upload-preview-cover { width: 220px; height: 124px; border-radius: var(--bmi-radius-ctl); }
.bmi-upload-preview-card  { width: 220px; height: 140px; border-radius: var(--bmi-radius-ctl); }
.bmi-upload-preview img   { width: 100%; height: 100%; object-fit: cover; }
.bmi-upload-controls      { display: flex; flex-direction: column; gap: 8px; min-width: 0; }
.bmi-upload-buttons       { display: flex; flex-wrap: wrap; gap: 8px; }
.bmi-upload-hint          { font-size: var(--bmi-fs-meta); color: var(--bmi-text-caption); }
.bmi-upload-status        { font-size: var(--bmi-fs-meta); color: var(--bmi-text-muted); }

/*-- 14f. Print (was ABT style.css:1716-1731). Orders and invoices get
     printed; this block is carried and its selector names updated. ----- */
@media print {
	.bmi-utilbar, .bmi-header, .bmi-footer, .bmi-newsletter,
	.bmi-scrim, .bmi-drawer, .bmi-mobilenav, .bmi-pager,
	.bmi-account-sidebar, .bmi-account-navcard,
	.dont-print { display: none !important; }   /* .dont-print is the MODULE layer's marker -- see 16 */
	body { background: #fff; color: #000; font-size: 12pt; }
	a[href]::after { content: ""; }
	.bmi-card { break-inside: avoid; }
}


/*-- =====================================================================
     15. ACCESSIBILITY
     The canvas has zero :focus rules and one bare outline:none (dc:768).
     ===================================================================== */

/*-- 15a. Skip link. The design has none. ------------------------------*/
.bmi-skip { position: absolute; left: -9999px; top: 0; z-index: 100;
            background: var(--bmi-ink); color: #fff; padding: 12px 20px;
            font-size: var(--bmi-fs-ui); font-weight: 600;
            border-radius: 0 0 var(--bmi-radius-ctl) 0; }
.bmi-skip:focus { left: 0; }
#bmi-main:focus { outline: none; box-shadow: none; }

/*-- 15b. THE focus ring. One shape, three grounds. A doubled box-shadow
     (inner halo + outer solid) rather than an outline, because an outline
     with offset clips inside the many overflow:hidden card shells. ----- */
:focus-visible {
	outline: none;
	box-shadow: 0 0 0 3px var(--bmi-focus-halo), 0 0 0 5px var(--bmi-focus-ring);
	border-radius: var(--bmi-radius-ctl);
}
.bmi-band-dark :focus-visible,
.bmi-band-deep :focus-visible,
.bmi-footer :focus-visible,
.bmi-utilbar :focus-visible,
.bmi-mobilenav :focus-visible {
	box-shadow: 0 0 0 3px var(--bmi-focus-halo-dark), 0 0 0 5px var(--bmi-focus-ring-dark);
}
@media (forced-colors: active) {
	:focus-visible { outline: 2px solid Highlight; outline-offset: 2px; }
}


/*-- 15d. Reduced motion. Zeroes the drawer, the scrim fade, the card lift,
     the accordion height transition, the spinner and the shimmer. ------ */
@media (prefers-reduced-motion: reduce) {
	html { scroll-behavior: auto; }
	*, *::before, *::after {
		animation-duration: .01ms !important;
		animation-iteration-count: 1 !important;
		transition-duration: .01ms !important;
	}
	.bmi-card-lift:where([href], [onclick]):hover, .bmi-card-lift:where([href], [onclick]):focus-visible { transform: none; }
}


/*-- =====================================================================
     16. THE MODULE LAYER   (PageManager's page grid + the shared module vocabulary)

     WHAT THIS IS AND WHY IT IS A SEPARATE SECTION. Everything above is the
     `bmi-` design system: classes this build authors and puts in the template
     by hand. Everything here is markup the CMS EMITS -- PageManager writes the
     page grid, and each module writes its list, card and form markup through a
     shared class vocabulary that predates this build. The names are not ours
     and cannot be renamed: they are compiled into PageManager.cs and into
     eleven modules' code-behind. So they are styled here, against the same
     tokens, rather than renamed into the `bmi-` namespace.

     WHY IT DID NOT EXIST. D3 replaced the inherited stylesheet with the design
     system, and the design system was authored from the six page artboards --
     which are template chrome. The module layer was never on an artboard, so it
     was never written. Measured on the E1 verification page before this
     section existed: 101 distinct classes emitted by the seven installed
     modules had no rule anywhere, and `.row` / `.cell` -- PageManager's own
     column grid -- were among them, which meant multi-column pages could not
     lay out at all. E1d.

     THE ONE LAW still holds. A class here earns its place by being shared
     across modules, or by belonging to PageManager itself. Anything only one
     module emits stays in that module's own registered style block.
     ===================================================================== */

/*-- 16a. PageManager's page grid.

     THE COLUMN WIDTHS ARE INLINE, NOT HERE. PageManager.cs:1252 writes
     `flex-basis` on every `.cell` -- plus `flex-shrink:0; flex-grow:0` when the
     column has a fixed width, and `justify-content` from the column's vertical
     alignment. So the only thing CSS has to supply is `display:flex` on `.row`.
     Without it every column stacks, the inline `flex-basis` is inert, and the
     page silently renders as one long single column. That is how this build
     shipped until E1d.

     `.cell` gets `min-width:0` because a flex item defaults to `min-width:auto`
     and will not shrink below its content -- one long word in a narrow sidebar
     is enough to push the whole row wider than the page. --*/
.PageManagerContent { width: 100%; }

.panel                  { position: relative; width: 100%; }
.panel-background,
.panel-background-layer { position: absolute; top: 0; left: 0; right: 0; bottom: 0; z-index: 0; }
.panel-background       { background-position: center; background-size: cover; background-repeat: no-repeat; }
.panel > .panel-title,
.panel > .panel-table   { position: relative; z-index: 1; }

.panel-title { width: 100%; max-width: var(--bmi-maxw); margin: 0 auto;
               padding: var(--bmi-section-pad) var(--bmi-gutter) 0; }
.panel-title .title-tag { margin: 0; }
.panel-title h2.title-tag { font-size: var(--bmi-fs-d6); line-height: 1.12; font-weight: 300; }
/* A page's own H1, when Page Manager or a module prints it as a section title (Shop, Devices,
   Services, Cart), is the page heading and takes the page H1 size. It inherited the browser's
   32px and sat smaller than the H2 under it. */
.panel-title h1.title-tag,
h1.module-title-tag { font-size: var(--bmi-fs-d4); line-height: 1.10; font-weight: 300; letter-spacing: -.015em; }
/* A picture floated beside rich text squeezes the words into a one-word column on a phone
   (the About page). Below tablet width it stands above the text instead. !important because
   the editor writes the float as an inline style. */
@media (max-width: 640px) {
	.content-data img { float: none !important; display: block; margin: 0 auto 16px !important; max-width: 100%; height: auto; }
}
.panel-title + .panel-table { padding-top: 28px; }

/*-- Panel rhythm modifiers.

     `.panel-title` and `.panel-table` ALREADY carry --bmi-section-pad, so putting one of
     the section-rhythm utilities (section 3b) on the PANEL adds a second 96px and opens a
     192px hole above the heading. That is what the first build of the rebuilt pages did,
     on every page. These retune the children instead of stacking on top of them. --*/
.panel.bmi-pad-66 > .panel-title,
.panel.bmi-pad-66 > .panel-table { padding-top: 66px; }
.panel.bmi-pad-66 > .panel-table { padding-bottom: 66px; }
.panel.bmi-pad-66 > .panel-title + .panel-table { padding-top: 22px; }
.panel.bmi-pad-76 > .panel-title,
.panel.bmi-pad-76 > .panel-table { padding-top: 76px; }
.panel.bmi-pad-76 > .panel-table { padding-bottom: 76px; }
.panel.bmi-pad-76 > .panel-title + .panel-table { padding-top: 24px; }
.panel.bmi-pad-88 > .panel-title,
.panel.bmi-pad-88 > .panel-table { padding-top: 88px; }
.panel.bmi-pad-88 > .panel-table { padding-bottom: 88px; }
.panel.bmi-pad-88 > .panel-title + .panel-table { padding-top: 26px; }

/*-- Full-bleed band. The module inside paints its own background edge to edge and owns its
     own padding, so the panel must not box it into the 1240px column. Every presentation
     hero and call-to-action band uses this. --*/
.panel.bmi-bleed > .panel-table { max-width: none; padding: 0; }

.panel-table { width: 100%; max-width: var(--bmi-maxw); margin: 0 auto;
               padding: var(--bmi-section-pad) var(--bmi-gutter); }
/* Consecutive sections on the same surface share one interval. */
.panel.no-bgcolor:not([class*="bmi-band-"]):not(.bmi-bleed) + .panel.no-bgcolor:not([class*="bmi-band-"]):not(.bmi-bleed) > .panel-title,
.panel.no-bgcolor:not([class*="bmi-band-"]):not(.bmi-bleed) + .panel.no-bgcolor:not([class*="bmi-band-"]):not(.bmi-bleed) > .panel-table { padding-top: 0; }
.panel.no-bgcolor:not([class*="bmi-band-"]):not(.bmi-bleed) + .panel.no-bgcolor:not([class*="bmi-band-"]):not(.bmi-bleed) > .panel-title + .panel-table { padding-top: 28px; }
.panel.bmi-page-intro > .panel-table { padding-top: 56px; padding-bottom: 40px; }
.panel.bmi-trust-section > .panel-table { padding-top: 32px; padding-bottom: 32px; }
.bmi-trust-section .card-style > ul > li { border: 0; border-radius: 0; background: transparent; }
.bmi-trust-section .item-data { padding: 8px 0; }
.panel-table.screen-height              { min-height: 99vh; display: flex; flex-direction: column; justify-content: center; }
.panel-table.screen-height.fixed-screen { min-height: 100vh; }

/* the row is the flex container the inline flex-basis values need */
.row  { display: flex; flex-wrap: wrap; align-items: stretch;
        width: calc(100% + var(--bmi-gutter));
        margin-left: calc(var(--bmi-gutter) / -2); margin-right: calc(var(--bmi-gutter) / -2); }
.panel-table.center > .row { justify-content: center; }
/* the pre/post rows and cells are structural spacers the CMS always emits */
.row-pre, .row-post { display: none; }

.cell         { display: flex; flex-direction: column; min-width: 0; flex-basis: auto;
                padding-left: calc(var(--bmi-gutter) / 2); padding-right: calc(var(--bmi-gutter) / 2); }
.panel.bmi-bleed .row { width: 100%; margin: 0; }
.panel.bmi-bleed .cell { padding-left: 0; padding-right: 0; }
/*-- AFTER .cell, and it has to be. Both selectors are one class, so the later one wins, and
     with the hide written first every .cell-pre and .cell-post came back as display:flex.
     They are zero-wide so nothing showed it until a cell was given a definite flex-basis:
     three items at 100% then wrap onto three lines and the row's 40px gap opens twice, which
     is a 40px white stripe above and below every full-bleed band. --*/
.cell-pre, .cell-post { display: none; }
.cell-wrapper { width: 100%; }
.cell-content { width: 100%; }
/* two modules in one column are two blocks, not one run-on */
.cell-content + .cell-content { margin-top: 56px; }

/* a narrow column is a sidebar: everything inside it steps down a size */
.cell.is-condensed .content-title { font-size: var(--bmi-fs-lg); }
.cell.is-condensed .item-data     { padding: 14px 16px 16px; }


/*-- 16b. Module heading and body.

     Every module that shows a title renders `.content-title`, and every module
     that shows editorial body copy renders `.content-data`. They are the module
     layer's equivalent of the design system's section head. --*/
.content-title { font-family: var(--bmi-serif); font-weight: 300;
                 font-size: var(--bmi-fs-d6); line-height: 1.12; letter-spacing: -.015em;
                 color: var(--bmi-text-strong); margin: 0 0 20px; }
.content-title.no-content { margin-bottom: 28px; }
/*-- overflow-wrap: an authored body can carry a run with no break in it -- a pasted address, a
     long link, or words glued by non-breaking spaces. The founder's credentials on /about end in
     "(massageandmeditation.com)&nbsp;and&nbsp;<em>Biomedis International</em>", one 300px-wide
     unbreakable run that went past the right edge of a 390px phone. break-word wraps such a run
     at the column edge and changes nothing where an ordinary space is available. --*/
.content-data,
.content-info  { font-size: var(--bmi-fs-base); line-height: 1.7; color: var(--bmi-text-muted);
                 overflow-wrap: break-word; }
.content-data > p:first-child,
.content-info > p:first-child { margin-top: 0; }
.content-data > p:last-child,
.content-info > p:last-child  { margin-bottom: 0; }
.content-data + .list-wrapper,
.content-data + ul            { margin-top: 28px; }

/*-- Prose INSIDE an editorial body. Until the page rebuild there was nothing in a
     `.content-data` but paragraphs, so a heading, a list or a table in one fell back
     to browser defaults: no rhythm, a 40px marker indent, and a heading the same
     colour as the body it heads. The page bodies are the whole of /legal, /privacy
     and every hero, and they carry their own h1 -- the panel heading cannot hold it
     without printing it twice (see tasks/bmi-build-pages.ps1). --*/
.content-data h1, .content-data h2,
.content-data h3, .content-data h4 { color: var(--bmi-text-strong); margin: 1.7em 0 .6em; }
.content-data h1 { font-size: var(--bmi-fs-d4); line-height: 1.10; letter-spacing: -.015em; }
.content-data h2 { font-size: var(--bmi-fs-d6); line-height: 1.14; letter-spacing: -.012em; }
.content-data h3 { font-size: var(--bmi-fs-d10); }
.content-data h4 { font-family: var(--bmi-sans); font-size: var(--bmi-fs-lead); font-weight: 600; }
.bmi-band-dark .content-data, .bmi-band-dark .bmi-lead,
.bmi-band-deep .content-data, .bmi-band-deep .bmi-lead { color: var(--bmi-on-dark-body); }
.bmi-band-dark .content-data h1, .bmi-band-dark .content-data h2,
.bmi-band-dark .content-data h3 { color: var(--bmi-on-dark); }
.bmi-band-dark .bmi-eyebrow { color: var(--bmi-lime-light); }

/*-- 16b-ii. THE PAGE MANAGER'S OWN COLOUR CONTROL.

     Picking a Background Color on a panel (or a column) in Page Manager is written by
     PageManager.BuildPanel / BuildPanelBox as three things: `has-bgcolor` on the panel, a
     `.panel-background-layer` painted with the rgba colour and opacity, and `dark-background`
     on the panel or the cell whenever that colour is dark. 16a already stretches the layer
     across the whole panel, so a picked colour IS a full-bleed band and keeps the band's own
     section padding (the shared-interval rule only collapses two panels with no colour). What
     the template never had was the other half of the reference build's adapter: text that
     reads on a dark pick. These are those rules on this template's tokens.

     EVERY SELECTOR IS WRAPPED IN :where(), so each one weighs exactly what the plain rule it
     answers weighs, and this block wins only by coming after it. That is deliberate: a white
     card, a callout or a table sitting inside a dark band pins its own ink with an ordinary
     class selector, and a heavier inversion rule would paint white text onto that white card.
     A dark hand-typed band (`bmi-band-dark`, `bmi-band-deep`) and a dark picked colour share
     the link colour below; the rest of the band rules sit with the rules they answer. --*/
:where(.panel.dark-background, .cell.dark-background) { color: var(--bmi-on-dark); }
:where(.panel.dark-background, .cell.dark-background) :is(h1, h2, h3, h4, h5, h6),
:where(.panel.dark-background, .cell.dark-background) .content-title { color: var(--bmi-on-dark); }
:where(.panel.dark-background, .cell.dark-background) .content-data,
:where(.panel.dark-background, .cell.dark-background) .content-info,
:where(.panel.dark-background, .cell.dark-background) .form-description,
:where(.panel.dark-background, .cell.dark-background) .bmi-lead { color: var(--bmi-on-dark-body); }
:where(.panel.dark-background, .cell.dark-background) .content-data :is(h1, h2, h3, h4) { color: var(--bmi-on-dark); }
:where(.panel.dark-background, .cell.dark-background) .bmi-eyebrow { color: var(--bmi-lime-light); }
:where(.panel.dark-background, .cell.dark-background) .label { color: var(--bmi-on-dark-list); }
:where(.panel.dark-background, .cell.dark-background, .bmi-band-dark, .bmi-band-deep) .content-data a[href]:not([class*="btn"]):not(.button) { color: var(--bmi-lime-light); }
:where(.panel.dark-background, .cell.dark-background, .bmi-band-dark, .bmi-band-deep) .content-data a[href]:not([class*="btn"]):not(.button):hover { color: #fff; }
:where(.panel.dark-background, .cell.dark-background) :focus-visible {
	box-shadow: 0 0 0 3px var(--bmi-focus-halo-dark), 0 0 0 5px var(--bmi-focus-ring-dark); }

/*-- A coloured COLUMN paints only its content box, so the gutter between two columns stays
     open instead of the colours butting together, and its content gets the inset a band
     gives it rather than running into the colour's edge. --*/
.cell.has-bgcolor { background-clip: content-box; }
.cell.has-bgcolor > .cell-wrapper { padding: clamp(24px, 4vw, 48px); }

/*-- "Screen Width" (the panel's Centered switch off) is the framework's full-bleed control:
     PageManager marks the table `center-no`. It gets the geometry `bmi-bleed` was typed in
     for, so a hero or a band that paints itself edge to edge needs no class name. No panel on
     either database is uncentred today, so this changes no existing page. --*/
.panel-table.center-no { max-width: none; padding: 0; }
.panel-table.center-no > .row { width: 100%; margin: 0; }
.panel-table.center-no > .row > .cell { padding-left: 0; padding-right: 0; }
.content-data > :first-child       { margin-top: 0; }
.content-data > :last-child        { margin-bottom: 0; }
/*-- THE TEMPLATE OWNS WIDTH. CONTENT NEVER SIZES ITSELF.

     This is where that rule was broken worst. `.content-data > p/ul/ol` carried
     `max-width: min(66ch, 100%)`, so every CMS body on the site rendered about 600px wide
     inside a 1240px shell. Because a panel is centred or start-aligned depending on the
     record, the result staggered down the page: a 600px column on the right, then one on the
     left, then one on the right, with the rest of the page empty either side. On the product
     page it produced a tall narrow description beside the gallery and then flipped sides for
     the shipping band underneath.

     A reading measure is still content sizing itself. If a body should read narrower, the
     TEMPLATE says so on the container that holds it, and every body inside that container
     follows. That is what `.panel-table` and `.bmi-wrap` are for. Do not put it back. --*/
.content-data ul, .content-data ol { margin: 0 0 1em; padding-left: 20px; }
.content-data ol { padding-left: 2em; }
.content-data li                   { margin: 0 0 .4em; }
.content-data li:last-child        { margin-bottom: 0; }
.content-data li::marker           { color: var(--bmi-lime-ink); }
.content-data strong               { color: var(--bmi-text-strong); font-weight: 600; }


/*-- 16c. The shared card / list system.

     `staff`, `info_cards`, `blog` and `testimonials` all render through this.
     The wrapper carries the behaviour classes and the `ul` is always its direct
     child, whatever the wrapper is called -- `.category-wrapper`,
     `.categories-wrapper`, `.list-wrapper`, `.info_card-wrapper`. `display-card`
     says "lay the items out as a grid of cards", `card-style` says "paint them",
     and `columns-N` says how many across. The `item-*` and `card-*` names are
     doubled on the same element by the modules; both are styled so neither can
     be the one that was forgotten. --*/
.blog-wrapper, .list-wrapper, .category-wrapper,
.categories-wrapper, .info_card-wrapper { width: 100%; }

.display-card > ul { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
                     gap: 24px; list-style: none; margin: 0; padding: 0; }
.media-grid > ul, .testimonial-grid {
    display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 24px;
    list-style: none; margin: 0; padding: 0; align-items: start; }
.media-grid > ul > li, .testimonial-grid > * { min-width: 0; margin: 0; }
.testimonial-grid > :only-child { grid-column: 1 / -1; }
.media-grid .img-wrap { position: relative; aspect-ratio: 16 / 9; overflow: hidden; }
.media-grid .img-wrap img { display: block; width: 100%; height: 100%; object-fit: cover; object-position: center; }
.site-search-form { display: flex; flex-wrap: wrap; align-items: end; gap: 12px; margin-bottom: 32px; }
.site-search-form label { flex-basis: 100%; font-weight: 600; }
.site-search-query { flex: 1; min-width: 0; }
.site-search-results { list-style: none; margin: 0; padding: 0; }
.site-search-result { border-top: 1px solid var(--bmi-rule); padding: 24px 0; }
.site-search-result h2 { margin: 4px 0 8px; font-size: var(--bmi-fs-lead); font-family: var(--bmi-sans); }
.site-search-kind { font-size: var(--bmi-fs-meta); color: var(--bmi-text-muted); }
.site-search-snippet { margin: 0; color: var(--bmi-text-muted); }
.site-search-pagination { display: flex; gap: 20px; margin-top: 24px; }
.display-images > ul, .display-steps > ul {
    display: grid; grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: 24px; list-style: none; margin: 0; padding: 0; }
.categories-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 24px; }
.display-card.columns-2 > ul { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.display-card.columns-3 > ul { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.display-card.columns-4 > ul { grid-template-columns: repeat(4, minmax(0, 1fr)); }
.catalog-wrapper.display-card > ul { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.catalog-wrapper.catalog-rail.display-card > ul { grid-template-columns: repeat(4, minmax(0, 1fr)); }
.display-card.compact     > ul { grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 18px; }
.display-card.compact-alt > ul { gap: 20px; }

.card-style > ul > li { display: flex; flex-direction: column; overflow: hidden;
                        background: #fff; border: 1px solid var(--bmi-border-card);
                        border-radius: var(--bmi-radius-card); }
.card-style.theme-gray > ul > li { background: var(--bmi-wash); }

/* the whole card is one link. `color-none` is the module layer's "inherit, do not paint". */
.cell-content a.color-none { display: flex; flex-direction: column; height: 100%;
                             color: inherit; text-decoration: none; }

/*-- media. `-img` holds a real <img>, `-bg` paints a background-image on the box
     itself; a module picks one and emits both the `item-` and `card-` name. --*/
.item-image, .card-image { position: relative; overflow: hidden; background: var(--bmi-surface-2); }
.card-image              { aspect-ratio: 4 / 3; }
.item-image > img        { display: block; width: 100%; height: 100%; object-fit: cover;
                           transition: transform var(--bmi-dur-card) var(--bmi-ease); }
.item-image-bg, .card-image-bg { background-position: center; background-size: cover;
                                 background-repeat: no-repeat; }
.item-image.nopad        { padding: 0; }
/*-- `no-image` is the module layer's placeholder state, and the placeholder is a
     small mark, not a photograph. Left on the `cover` sizing every other image
     gets, it is blown up until it fills the well and reads as a BROKEN image
     rather than an absent one. Both variants need constraining: `-img` holds a
     real <img> (object-fit), `-bg` paints it as a background (background-size). --*/
.item-image.no-image, .card-image.no-image {
                           background-color: var(--bmi-surface-2);
                           background-size: 72px auto; background-position: center;
                           background-repeat: no-repeat; }
.item-image.no-image > img { object-fit: contain; padding: 26%; opacity: .5; }
/* HOVER: only under a.color-none, because only that is clickable. `.nozoom` opts out. */
a.color-none:hover .item-image:not(.nozoom) > img,
a.color-none:focus-visible .item-image:not(.nozoom) > img { transform: scale(1.04); }

/*-- text --*/
.item-data, .card-data { display: flex; flex-direction: column; gap: 7px;
                         flex: 1 1 auto; padding: 18px 20px 22px; }
.item-title, .card-title       { font-family: var(--bmi-sans); font-size: var(--bmi-fs-sm);
                                 font-weight: 600; line-height: 1.3; letter-spacing: -.005em;
                                 color: var(--bmi-text-strong); }
.item-subtitle, .card-subtitle { font-size: var(--bmi-fs-meta); color: var(--bmi-text-mid); }
.item-timestamp, .card-timestamp { font-size: var(--bmi-fs-meta); letter-spacing: .04em;
                                   color: var(--bmi-text-meta-aa); }
.item-description, .card-description { font-size: var(--bmi-fs-sm); line-height: 1.6;
                                       color: var(--bmi-text-muted); }
.item-description > p:first-child { margin-top: 0; }
.item-description > p:last-child  { margin-bottom: 0; }

/* a card with no description should not leave a gap where one would have been */
.card-style > ul > li.no-description .item-data { gap: 4px; }
.display-card.hide-description .item-description { display: none; }

/* the bg-image variant carries its own picture, so the box needs a height */
.card-style > ul > li.with-bgimage .item-image-bg { aspect-ratio: 3 / 2; }


/*-- 16d. The shared form system.

     `survey` and `feedback_forms` render through this, and `members` will.
     `.textbox` is the module layer's input; the design system's own
     `.bmi-input` is a different, hand-authored control and the two are
     deliberately not merged -- one is emitted, one is written. --*/
.form-wrapper { width: 100%; }

/*-- BAND LAYOUT. The approved newsletter: the copy on one side of the row, the field and its
     button on the other, filling the page. The module sets `.form-band` from a per-placement
     setting, so one form record serves both shapes.

     `auto` on the second column, not a width: the fields decide how much they need and the copy
     takes the rest. Nothing here declares how wide the band is; the panel does. --*/
/*-- .form-main has THREE children, not two: the title, the description and the fields. A plain
     two-column grid therefore put the title left, the description right and pushed the fields onto
     a second row. The copy stacks in column one and the fields take column two across both rows. --*/
/*-- `auto` on the fields column let the FIELDS decide the split, and they took
     903px of 1160px -- leaving the newsletter's heading and its one-line
     description a 197px column to live in. That is the "four words per line"
     copy column: "News, events, offers and / the occasional discount." set as a
     narrow ragged stack beside a row of fields that then did not fill the space
     they had taken. Proportional columns instead, so the copy gets a third of
     the band and the fields get the rest, and neither can starve the other. --*/
.module-feedback_forms.form-band .form-main { display: grid;
                grid-template-columns: minmax(0, 1fr) minmax(0, 2fr);
                gap: 8px 60px; align-items: center; }
.module-feedback_forms.form-band .content-title    { grid-column: 1; grid-row: 1; margin: 0; }
.module-feedback_forms.form-band .form-description { grid-column: 1; grid-row: 2; margin-bottom: 0; }
.module-feedback_forms.form-band .form-fields      { grid-column: 2; grid-row: 1 / span 2;
                align-self: center; }
/*-- The band's field row. Every `li` is a field except the last, which holds
     the submit button, and any agreement field, which holds a sentence.

     Before: `min-width: 260px` on the input and nothing telling the items to
     grow, so the two fields sat at exactly 260px each inside a 903px row with
     383px of nothing after them, and the consent sentence and the Subscribe
     button shared the next line -- a long label on the left, a button pushed
     out to the right, and no relationship between them. That is the "thrown
     together" row.

     Now: the text fields SHARE the row and grow into it, the button keeps its
     own width at the end of that row, and an agreement sentence takes a full
     row of its own underneath (`order: 2` puts it after the button's line
     without the module having to reorder its fields). --*/
.module-feedback_forms.form-band .form-fields > ul { flex-flow: row wrap;
                align-items: flex-end; gap: 16px; }
/*-- The short single-value fields share the top row and GROW into it. Named by
     type rather than "every li", because the list also carries rows that are
     not fields: an agreement sentence, a captcha, and the HumanShield row,
     which is zero height and holds only hidden inputs. As a generic flex item
     that invisible row claimed a 234px column of the field row and pushed the
     Subscribe button onto a line of its own -- the exact "thrown together"
     stagger, produced by an element with nothing in it. --*/
.module-feedback_forms.form-band .form-fields > ul > li.field-text,
.module-feedback_forms.form-band .form-fields > ul > li.field-email,
.module-feedback_forms.form-band .form-fields > ul > li.field-phone,
.module-feedback_forms.form-band .form-fields > ul > li.field-number,
.module-feedback_forms.form-band .form-fields > ul > li.field-date,
.module-feedback_forms.form-band .form-fields > ul > li.field-option { flex: 1 1 180px; min-width: 0; order: 0; }
/*-- The submit closes that row. --*/
.module-feedback_forms.form-band .form-fields > ul > li.field-submit { flex: 0 0 auto; order: 1; }
/*-- Everything else takes a full row of its own beneath it: a consent sentence
     is a sentence and needs the width, and a security row is invisible so the
     row it sits on costs nothing. --*/
.module-feedback_forms.form-band .form-fields > ul > li { flex: 1 1 100%; min-width: 0; order: 2; }
/*-- The submit sits on the field row, so its empty label must not push it down. --*/
.module-feedback_forms.form-band .form-fields > ul > li.field-submit .label-empty { display: none; }
.module-feedback_forms.form-band .form-buttons { margin-top: 0; }
@media (max-width: 860px) {
	.media-grid > ul, .testimonial-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
	.module-feedback_forms.form-band .form-main { grid-template-columns: minmax(0, 1fr); gap: 14px; }
	.module-feedback_forms.form-band .content-title,
	.module-feedback_forms.form-band .form-description,
	.module-feedback_forms.form-band .form-fields { grid-column: 1; grid-row: auto; }
	.module-feedback_forms.form-band .form-fields > ul { flex-flow: column nowrap; align-items: stretch; }
	/*-- Stacked, every item is full width and the order flags stop applying,
	     or the submit would jump above the consent it is meant to follow. --*/
	/*-- li[class] matches the typed field rows too. Without it the desktop row's
	     `li.field-text { flex: 1 1 180px }` outranked this and, in a column, a
	     180px flex-basis is a HEIGHT: each field sat in a 180px box and the phone
	     newsletter showed ~130px of blank between First name and Email. --*/
	.module-feedback_forms.form-band .form-fields > ul > li,
	.module-feedback_forms.form-band .form-fields > ul > li[class],
	.module-feedback_forms.form-band .form-fields > ul > li.field-submit,
	.module-feedback_forms.form-band .form-fields > ul > li.field-agreement { flex: 0 0 auto; order: 0; }
}
/*-- No max-width. A form is content; the panel it sits in decides how wide it is. This used to
     be 720px, which is why the newsletter band on the home page and the contact form both sat
     at about seventy per cent of the page with dead space beside them. --*/
.form-main    { width: 100%; }
/*-- `.member-join-split` moved to 16d-3, beside `.member-join`. It used to
     carry the auth card's only spacing rule (margin-top: 20px) while
     `.member-join` itself had none, so Sign In got a gap under its button and
     Create Account did not. Spacing belongs to the shared class. --*/
.form-description { font-size: var(--bmi-fs-base); line-height: 1.7;
                    color: var(--bmi-text-muted); margin-bottom: 28px; }

.form-fields ul { list-style: none; margin: 0; padding: 0; display: flex;
                  flex-direction: column; gap: 18px; }
.field-group    { display: flex; flex-direction: column; gap: 7px; }
.form-group { margin-bottom: 18px; }
.form-group > .label { display: block; margin-bottom: 7px; }
.field          { position: relative; }
/*-- A field icon sits at the TRAILING edge, never the leading one: a glyph in front of
     the caret pushes the value off the field's own left rule and breaks the vertical line
     every other input in the form keeps. Right is also where the framework already puts
     the select chevron and the captcha reload, so one edge owns all input affordances. --*/
.field > .icon-overlay { position: absolute; top: 0; right: 16px;
                         height: var(--bmi-input-h); display: flex; align-items: center;
                         color: var(--bmi-text-caption); pointer-events: none; }
.field > .textbox.input-overlay { padding-right: 44px; }
.field-group > .label,
.label          { font-size: var(--bmi-fs-label); font-weight: 600; letter-spacing: .04em;
                  text-transform: uppercase; color: var(--bmi-text-mid); }
.label-empty    { display: none; }

/*-- `.textbox` IS SPECIFIED IN 12a, with `.bmi-input` on the same rules. The
     second, weaker copy that used to live here is gone.

     It is why Sign In had square corners and Contact had round ones. The radius
     was on `.textbox.rounded`, not on `.textbox`, and `.rounded` is appended by
     the MODULE: feedback_forms' createTextBox writes "textbox rounded", members'
     markup writes "textbox". Same class, same form system, two shapes, and
     nothing on either page to say which was intended. The radius now belongs to
     the control, so no module can opt out of it by forgetting a utility class.

     `.rounded` stays a live utility (16e) for non-input surfaces; on an input it
     is now a no-op rather than a switch, and the module markup keeps working
     whether it carries the class or not. --*/

/*-- The file field is the one input the browser will not let us size from the
     outside: its button is a shadow-DOM child with its own metrics. Give it the
     control's box and let the button sit inside it. --*/
.textbox-upload { height: auto; min-height: var(--bmi-input-h);
                  padding: 13px var(--bmi-input-px); line-height: 1.5; }

/* the required marker is an icon element with no glyph behind it: give it one */
.required { color: var(--bmi-error); }
.required::before { content: "*"; font-style: normal; }

/*-- `.button` is the module layer's button, emitted by survey, feedback_forms,
     staff, site_navigation and members (21 call sites). It is a DIFFERENT class
     from the design system's `.bmi-btn` and it is not going to be renamed,
     because it is written into those modules' code-behind. So it gets the same
     shape and the same palette here.

     It was missed on the first pass of 16 and the survey's submit control
     shipped as a 120x23 grey browser default. The measurement that was supposed
     to catch it counted `.button` as styled, because the PRESENTATION module's
     own block defines `.button.inserted-button` and a name match cannot tell
     the difference between that and a rule that applies. A class-name sweep
     finds what is missing; only looking at the rendered page finds what is
     wrong. --*/
.button {
	display: inline-flex; align-items: center; justify-content: center; gap: 9px;
	/*-- --bmi-input-h, not --bmi-touch-min: on the newsletter band this button
	     sits on the same row as two text fields, and at 44px against their 52px
	     it read as a smaller, lesser control sitting in a dent in the row. --*/
	height: var(--bmi-input-h); padding: 0 26px;
	background: var(--bmi-purple); color: #fff; border: none;
	border-radius: var(--bmi-radius-ctl);
	font-family: var(--bmi-sans); font-size: var(--bmi-fs-ui); font-weight: 600;
	line-height: 1; text-decoration: none; white-space: nowrap; cursor: pointer;
	transition: background var(--bmi-dur-fast) var(--bmi-ease),
	            border-color var(--bmi-dur-fast) var(--bmi-ease),
	            color var(--bmi-dur-fast) var(--bmi-ease); }
.button:hover        { background: var(--bmi-purple-hover); color: #fff; }
.button.btn-ltgray   { background: #fff; color: var(--bmi-text-strong);
                       border: 1px solid var(--bmi-border-control-aa); }
.button.btn-ltgray:hover { border-color: var(--bmi-lime); background: var(--bmi-wash-lime); color: var(--bmi-text-strong); }
/* input[type=submit] cannot hold flex children, so it centres its own label */
input.button { display: inline-block; text-align: center; }

.form-notice, .no-results { font-size: var(--bmi-fs-base); line-height: 1.6;
                            color: var(--bmi-text-muted); background: var(--bmi-wash);
                            border: 1px solid var(--bmi-border-card);
                            border-radius: var(--bmi-radius-card); padding: 20px 22px; }


/*-- 16d-2. THE TICK CONTROL.

     Three shapes reached the page and not one of them had a rule in this sheet.

     `.checkboxradio` is what feedback_forms puts on a CheckBox, a CheckBoxList
     and a RadioButtonList. It had NO rule at all, so the newsletter's consent
     row was a browser-default inline checkbox. `.bmi-optin` is what members
     uses, and it was declared TWICE, inside two module <style> blocks -- "two
     copies because the two controls are separate scopes, not because they
     should differ", says its own comment. Two copies is exactly how they came
     to differ from each other, and from the third one nobody wrote.

     Both module copies are now deleted and the rule lives here once. That is
     why the newsletter's tick and the Create Account tick were different sizes,
     different colours and aligned differently against their wording.

     ONE consent shape, `.field-consent` + `.bmi-optin`, and a separate shape
     for the multi-option lists, because a list of eight options is not the
     same object as one sentence with a tick against it. --*/

/*-- A hanging indent, not a flex row. Consent wording runs to two and three
     lines, and the trailing policy link has to flow INLINE after the last word
     rather than being pushed onto a line of its own -- which is what a flex row
     does to it. Absolute box + padding-left keeps wrapped lines aligned under
     each other and the tick against the first line's cap height. --*/
.field-consent,
.bmi-optin,
.bmi-join-agree { position: relative; display: block; margin: 0;
                  padding-left: 28px;
                  font-size: var(--bmi-fs-base); line-height: 1.55;
                  color: var(--bmi-text); cursor: pointer; }
.field-consent input[type="checkbox"],
.bmi-optin      input[type="checkbox"],
.bmi-join-agree input[type="checkbox"] {
                  position: absolute; left: 0; top: 3px; margin: 0;
                  width: 17px; height: 17px;
                  accent-color: var(--bmi-purple); cursor: pointer; }
.field-consent label,
.bmi-optin > span,
.bmi-join-agree > span { margin: 0; cursor: pointer; }

/*-- A LINK INSIDE CONSENT WORDING MUST LOOK LIKE ONE.

     The newsletter consent rendered as one flat run of link colour with no
     underline, and the ENTIRE sentence was the anchor -- so clicking the words
     never ticked the box, it always navigated to the privacy policy. Wording
     and link are separate elements now (see the agreement branch in
     feedback_forms' addField), and the link is underlined, so the half of the
     row that navigates is identifiable BEFORE it is clicked. Without the
     underline the two halves are indistinguishable and the control is a coin
     toss. --*/
.agreement-policy,
.field-consent a,
.bmi-optin a,
.bmi-join-agree a { text-decoration: underline; text-underline-offset: 2px; }

/*-- The multi-option lists. ASP.NET renders CheckBoxList and RadioButtonList as
     a <table>, one option per row, with the <input> and its <label> in the same
     cell and no spacing between them. --*/
.checkboxradio table { border-collapse: collapse; }
.checkboxradio td { padding: 3px 0; }
.checkboxradio input[type="checkbox"],
.checkboxradio input[type="radio"] { width: 17px; height: 17px; margin: 0 8px 0 0;
                                     vertical-align: -3px;
                                     accent-color: var(--bmi-purple); cursor: pointer; }
.checkboxradio label { font-size: var(--bmi-fs-base); line-height: 1.55;
                       color: var(--bmi-text); cursor: pointer; }


/*-- 16d-3. THE AUTH CARD -- Sign In, Create Account, Reset Password, Verify.

     Every class the members auth control emits was unstyled. `.member-join`,
     `.member-login-signup`, `.member-signup-wide`, `.form-row` and
     `.form-group-half` had ZERO rules between them, which is why the three
     screens differed from each other and from every other form on the site:
     `.form-row` never became a row (it computed `display: block`), so the
     two-column register layout its markup asks for never happened, and
     `.member-join` had no margin, so "Already have an account?" sat hard
     against the Create Account button while the identical block on Sign In
     had 20px from `.member-join-split`.

     The register markup is now a flat single-column list of `.form-group`,
     matching Edit Profile in the same module and matching feedback_forms, so
     `.form-row` / `.form-group-half` / `.bmi-aside-row` / `.bmi-field-aside`
     are no longer emitted at all. They are NOT given rules here. Styling
     markup that no longer exists is how this sheet got 13 rules for an input
     nothing renders. --*/

/*-- The gate cell fills its row.

     `Get_Task_Error` clears the page tree and drops the auth card into the
     page's own panel columns, tagging panel and cell `task-error`
     (PageManager.cs:1018). /account's main column is set to "Auto" in the back
     office because the signed-in dashboard wants a 260px sidebar beside it,
     and PageManager turns "Auto" into `flex-basis: auto` with no flex-grow
     (PageManager.cs:1269-1273) -- so the column SHRINK-WRAPS its content.

     That is the whole reason Create Account was wider than Sign In. Neither
     had a width; each collapsed onto whatever its own fields happened to
     measure, 264px for Sign In and 385px for Create Account. Not a style
     difference at all, and no amount of matching their CSS would have closed
     it.

     Grow the gate cell instead, so the card is the width of the container the
     template gave it -- the same container width Contact and Wholesale get.
     Scoped to `task-error`, so the signed-in dashboard's sidebar layout is
     untouched. The inline style sets flex-basis only, so flex-grow is free. --*/
.panel.task-error .cell.task-error { flex-grow: 1; }

/*-- The link row under the submit button. Sign In carries two links, Create
     Account and Reset carry one with a lead-in question; they now share one
     rule so the gap above them and the type are the same on all four screens. --*/
.member-join { margin-top: 26px; padding-top: 22px;
               border-top: 1px solid var(--bmi-rule);
               font-size: var(--bmi-fs-ui); color: var(--bmi-text-caption); }
.member-join a { font-weight: 600; }
/*-- Sign In's two links go to opposite edges. Side by side they read as one
     control and people click the wrong one (client report 2026-08-04). --*/
.member-join-split { display: flex; flex-wrap: wrap; justify-content: space-between;
                     gap: 12px 24px; }


/*-- 16d.1 O16. THE FORM SURFACES NOTHING HAS EVER RENDERED.

     Every class below is emitted by feedback_forms and defined by nothing, so each one is
     unstyled markup waiting for the day an administrator uses the feature that produces it.
     They were invisible to every sweep for the honest reason that no form on the site has an
     address field, a captcha, a spacer or a contact panel today -- and the moment the client
     adds one in the back office, which is a supported thing to do, the form renders wrong.

     Checked before writing: a control scan for `.field-group` returned 723 hits, so the search
     that returned zero for these really did mean zero. My first pass reported all twelve
     unstyled AND unemitted, which was a broken glob, not a finding. --*/

/*-- The composite address field, five panels in two rows. The module puts a plain block
     div.clear20 between Address2 and City to end the first row, and that div is also defined
     nowhere; it needs no rule, because an empty block between inline-blocks already breaks the
     line, and giving it a height would add a gap nobody asked for.

     inline-block rather than flex because the module emits the panels as siblings of whatever
     else the field holds, with no wrapper of its own to make a flex container out of. The
     gutters are padding, not margin, which works because box-sizing is border-box globally
     (line 236) so the percentages still add to 100. --*/
.field-inline           { display: inline-block; vertical-align: top; width: 100%; }
.field-inline .textbox  { width: 100%; }
.field-address1         { width: 62%; padding-right: 10px; }
.field-address2         { width: 38%; }
.field-address-city     { width: 50%; padding-right: 10px; }
.field-address-state    { width: 22%; padding-right: 10px; }
.field-address-zip      { width: 28%; }
@media (max-width: 560px) {
    /*-- State and Zip stay paired on a phone; a 2-character State box on its own row looks
         like a mistake. Address2 and City take the full width. --*/
    .field-address1, .field-address2, .field-address-city { width: 100%; padding-right: 0; }
    .field-address-state { width: 40%; padding-right: 10px; }
    .field-address-zip   { width: 60%; }
}

/*-- The captcha. The notice explains an image that sits BELOW it, so it reads as an
     instruction rather than a caption, and the reload control is a link the size of a target
     rather than a bare glyph. --*/
.captcha-notice  { margin: 8px 0 10px; font-size: var(--bmi-fs-meta);
                   color: var(--bmi-text-caption); }
.captcha-image   { display: flex; align-items: center; gap: 12px; }
.captcha-phrase  { display: block; border: 1px solid var(--bmi-rule);
                   border-radius: var(--bmi-radius-ctl); background: var(--bmi-surface-2); }
.captcha-reload  { display: inline-flex; align-items: center; justify-content: center;
                   width: 36px; height: 36px; border-radius: var(--bmi-radius-ctl);
                   color: var(--bmi-text-caption);
                   transition: background var(--bmi-dur-fast) var(--bmi-ease),
                               color var(--bmi-dur-fast) var(--bmi-ease); }
.captcha-reload:hover, .captcha-reload:focus-visible { background: var(--bmi-wash);
                   color: var(--bmi-purple); }

/*-- A deliberate blank row. The module fills it with a non-breaking space, so without a rule
     it is one line of text tall by accident rather than by design. --*/
.field-spacer    { height: 18px; line-height: 18px; font-size: 0; }

/*-- The contact details panel beside a form. The module ships it switched off
     (pnlFormContact Visible="False"), so it has never rendered here; it is an icon, a label
     and a value per row. --*/
.form-contact        { margin-bottom: 26px; }
.contact-field       { display: flex; align-items: flex-start; gap: 12px;
                       margin-bottom: 14px; }
.contact-field:last-child { margin-bottom: 0; }
.contact-field-icon  { flex: 0 0 auto; width: 20px; line-height: 1.6;
                       color: var(--bmi-text-caption); text-align: center; }
.contact-field-info  { flex: 1 1 auto; min-width: 0; font-size: var(--bmi-fs-ui);
                       line-height: 1.6; overflow-wrap: anywhere; }
.contact-field-info a { font-weight: 600; }

/*-- 16e. The module layer's utility classes.

     These are emitted inline by the modules and are the reason a paragraph
     inside a card does not double its margin against the card padding. Small
     and dull, and every one of them is load-bearing somewhere. --*/
.clear      { clear: both; }
/*-- `.center` means TWO different things and only one of them is text-align.
     A module puts it on a title or a slide's copy and means "centre this text".
     PageManager puts it on `.panel-table` from `SitePagePanels.IsCentered`
     (`PageManager.cs:1094`) and means "centre the COLUMN", which 16a handles with
     justify-content on the row. Left as one rule, the panel flag inherited down into every
     module on the page and centre-aligned FAQ answers, list bodies and rich text -- which
     reads as a design choice rather than a bug, so nothing flags it. Found in E3. --*/
.center     { text-align: center; }
.panel-table.center { text-align: start; }
/*-- The third place it appears. PageManager hardcodes `center` onto the panel heading
     literal, so a section heading that lives on the Section row centres while the identical
     heading written into a rich text body sits left. One page, two alignments, and no way to
     tell from the back office which you are going to get. The design is left-aligned
     throughout (7d, and the section head at 3j), so the panel heading follows it. --*/
.panel-title .title-tag.center { text-align: start; }
.small      { font-size: var(--bmi-fs-meta); }
.light      { color: var(--bmi-text-muted); }
.fwb        { font-weight: 600; }
.font-title { font-family: var(--bmi-serif); }
.rounded    { border-radius: var(--bmi-radius-ctl); }
.nopad      { padding: 0; }
.mr5        { margin-right: 5px; }
.mr8        { margin-right: 8px; }
.mbottom-0  { margin-bottom: 0; }
.mbottom-2  { margin-bottom: 12px; }
.m0-first-child > *:first-child { margin-top: 0; }
.m0-last-child  > *:last-child  { margin-bottom: 0; }
.m0-first-p     > p:first-child { margin-top: 0; }
.m10-last-p     > p:last-child  { margin-bottom: 10px; }
/* .dont-print is a hide-on-print marker the modules emit; its rule is in 14f. */


/*-- 16g. The shared card, button and link tokens.

     A SECOND vocabulary, separate from 16c's `.item-*` / `.card-*` list system. Several modules
     emit a bare `.card`, `.btn` or `.textlink` for one-off surfaces that are not list items --
     an FAQ category tile, a vote button, an inline "More" link. Counted as exact class tokens
     (not substrings; `\bcard\b` also matches `card-data`, which inflated the first count):
     `.card` in faqs / members / testimonials, `.btn` in blog / faqs / members / survey,
     `.textlink` and `.hover-lift` in faqs / members.

     Two or more modules is what puts a class here rather than in the module that emits it. The
     variants only ONE module uses stay with that module: `.btn-danger` and `.btn-brand-out` are
     members-only (E9), `.grid` is members-only, and `.acc-*` is faqs-only and lives in the faqs
     module's own style block.

     These are the module layer's twins of `.bmi-card` and `.bmi-btn` and are kept at the same
     geometry on purpose, so a module surface and a hand-written one do not read as two
     different products on the same page. --*/
.card { display: flex; flex-direction: column; overflow: hidden;
        background: #fff; border: 1px solid var(--bmi-border-card);
        border-radius: var(--bmi-radius-card); }
/* HOVER only where the card is itself a link -- faqs puts .card on an <a>. */
.hover-lift:where([href], [onclick]) { transition: box-shadow var(--bmi-dur-card) var(--bmi-ease),
                          transform var(--bmi-dur-card) var(--bmi-ease); }
a.hover-lift[href]:hover, .hover-lift:where([href], [onclick]):focus-visible {
	box-shadow: var(--bmi-shadow-card); transform: translateY(-3px); }

.textlink { display: inline-flex; align-items: center; gap: 6px;
            color: var(--bmi-purple); text-decoration: none; font-weight: 600;
            transition: color var(--bmi-dur-fast) var(--bmi-ease); }
.textlink:hover { color: var(--bmi-purple-hover); text-decoration: underline; }
.textlink .arr  { flex: 0 0 auto;
                  transition: transform var(--bmi-dur-fast) var(--bmi-ease); }
.textlink:hover .arr { transform: translateX(3px); }

.btn { display: inline-flex; align-items: center; justify-content: center; gap: 8px;
       height: var(--bmi-touch-min); padding: 0 24px;
       background: var(--bmi-purple); color: #fff; border: 1px solid transparent;
       border-radius: var(--bmi-radius-ctl);
       font-family: var(--bmi-sans); font-size: var(--bmi-fs-ui); font-weight: 600;
       line-height: 1; text-decoration: none; white-space: nowrap; cursor: pointer;
       transition: background var(--bmi-dur-fast) var(--bmi-ease),
                   border-color var(--bmi-dur-fast) var(--bmi-ease),
                   color var(--bmi-dur-fast) var(--bmi-ease); }
.btn:hover { background: var(--bmi-purple-hover); color: #fff; }
.btn-secondary { background: #fff; color: var(--bmi-text-strong);
                 border-color: var(--bmi-border-control-aa); }
.btn-secondary:hover { background: var(--bmi-wash-lime); border-color: var(--bmi-lime); color: var(--bmi-text-strong); }
.btn-ghost { background: transparent; color: var(--bmi-text-mid);
             border-color: var(--bmi-border-control-aa); }
.btn-ghost:hover { background: var(--bmi-wash); color: var(--bmi-purple);
                   border-color: var(--bmi-purple); }
/*-- .btn-small is NOT below the 44px touch minimum. It is smaller in padding and type, which is
     what the modules want it for (a vote button beside a paragraph), and still a 44px target. --*/
.btn-small { height: var(--bmi-touch-min); padding: 0 16px; font-size: var(--bmi-fs-meta); }

/*-- editorial helpers the modules put on their own intro copy --*/
.lead { font-size: var(--bmi-fs-lead); line-height: 1.6; color: var(--bmi-text-mid); }
.title-back { display: inline-flex; align-items: center; margin-right: 10px;
              color: var(--bmi-text-caption);
              transition: color var(--bmi-dur-fast) var(--bmi-ease); }
a.title-back:hover { color: var(--bmi-purple); }


/*-- 16f. Site navigation -- the five wrapper contexts.

     THE MODULE KEEPS ITS OWN CLASS NAMES. `site_navigation` emits one vocabulary --
     `.nav-ul` / `.nav-li` / `.nav-item`, tiered `t0` / `t1`, `.wc` on a parent that has
     children -- and it emits the SAME markup into all five places the template puts it. It has
     no way to know which one it is in, and hard-coding `bmi-` names into a module would couple
     the plugin to this one template, which is the opposite of THE ONE LAW.

     So the CONTEXT does the styling. `template.master` passes a different CssClass to each
     placement (`bmi-utilbar-nav`, `bmi-header-navlist`, `bmi-mobilenav-nav`, `bmi-footer-nav`,
     `bmi-footer-copyright`) and each rule below reaches through its wrapper to the module's own
     vocabulary. The anchor rules that already exist for hand-written links -- `.bmi-utilbar-link`,
     `.bmi-header-navlink`, `.bmi-mobilenav-link`, `.bmi-footer-link` -- are extended rather than
     duplicated, so the two kinds of link cannot drift apart.

     The roadmap asked for the renderer to emit those `bmi-` names instead. It is written this way
     because the module cannot tell its own context, and because the version of the module that
     shipped here is not the stock one the roadmap assumed -- see the E2 entry. --*/

.module-site_navigation .nav-ul  { list-style: none; margin: 0; padding: 0; }
.module-site_navigation .nav-li  { position: relative; }
.module-site_navigation .nav-item { display: inline-flex; align-items: center; gap: 6px;
                                    text-decoration: none; color: inherit; }

/*-- the chevron on a parent. The module emits an empty span; the glyph is ours. --*/
.module-site_navigation .nav-li.wc > .nav-item > .open-icon {
	width: 8px; height: 8px; flex: 0 0 auto; margin-left: 2px;
	border-right: 1.6px solid currentColor; border-bottom: 1.6px solid currentColor;
	transform: rotate(45deg) translate(-2px, -2px);
	transition: transform var(--bmi-dur-fast) var(--bmi-ease); }

/*-- 16f.1 Utility bar (aubergine, on dark) --*/
.bmi-utilbar-nav .nav-ul.t0 { display: flex; align-items: center; gap: 20px; }
.bmi-utilbar-nav .nav-item  { color: var(--bmi-on-dark-util);
                              transition: color var(--bmi-dur-fast) var(--bmi-ease); }
.bmi-utilbar-nav .nav-item[href]:hover { color: var(--bmi-lime-light); }
.bmi-utilbar-nav .nav-ul.t1 { display: none; }   /* the utility bar is one tier by design */

/*-- 16f.2 Header bar. Carries the signature lime baseline marker and the one-tier dropdown.

     The marker is drawn with ::after here rather than the hand-written `.bmi-header-navmark`
     span, because the module emits no such element and adding one would mean teaching it about
     this template. Same geometry: inside the 30px padding, 24px up, overhanging by 2px. --*/
.bmi-header-navlist .nav-ul.t0 { display: flex; align-items: center; gap: 34px;
                                 font-size: var(--bmi-fs-ui); font-weight: 500; }
.bmi-header-navlist .nav-item.t0 { position: relative; padding: 30px 0; color: var(--bmi-text);
                                   letter-spacing: .005em;
                                   transition: color var(--bmi-dur-fast) var(--bmi-ease); }
.bmi-header-navlist .nav-item.t0[href]:hover { color: var(--bmi-purple); }
.bmi-header-navlist .nav-item.t0::after { content: ""; position: absolute; left: -2px; right: -2px;
                                          bottom: 24px; height: 2.5px; border-radius: 2px;
                                          background: var(--bmi-lime);
                                          opacity: 0; transition: opacity var(--bmi-dur-fast) var(--bmi-ease); }
.bmi-header-navlist .nav-li.t0:hover > .nav-item.t0::after,
.bmi-header-navlist .nav-li.t0 > .nav-item.t0:focus-visible::after,
.bmi-header-navlist .nav-li.t0.is-active > .nav-item.t0::after { opacity: 1; }

/*-- the dropdown. :focus-within as well as :hover, so it is reachable by keyboard. --*/
.bmi-header-navlist .nav-ul.t1 {
	position: absolute; top: 100%; left: -18px; z-index: 40; min-width: 208px;
	padding: 10px 0; background: #fff; border: 1px solid var(--bmi-border-card);
	border-radius: var(--bmi-radius-card); box-shadow: var(--bmi-shadow-card-lg);
	opacity: 0; visibility: hidden; transform: translateY(-4px);
	transition: opacity var(--bmi-dur-fast) var(--bmi-ease),
	            visibility var(--bmi-dur-fast) var(--bmi-ease),
	            transform var(--bmi-dur-fast) var(--bmi-ease); }
.bmi-header-navlist .nav-li.t0:hover > .nav-ul.t1,
.bmi-header-navlist .nav-li.t0:focus-within > .nav-ul.t1 {
	opacity: 1; visibility: visible; transform: translateY(0); }
.bmi-header-navlist .nav-li.t0:hover > .nav-item.t0 > .open-icon,
.bmi-header-navlist .nav-li.t0:focus-within > .nav-item.t0 > .open-icon {
	transform: rotate(225deg) translate(-2px, -2px); }
.bmi-header-navlist .nav-item.t1 { display: block; padding: 9px 18px; width: 100%;
                                   font-size: var(--bmi-fs-sm); color: var(--bmi-text-muted);
                                   transition: background var(--bmi-dur-fast) var(--bmi-ease),
                                               color var(--bmi-dur-fast) var(--bmi-ease); }
.bmi-header-navlist .nav-item.t1[href]:hover { background: var(--bmi-wash); color: var(--bmi-purple); }

/*-- 16f.3 Mobile drawer. Vertical, on dark, and the second tier is an ACCORDION.

     THE ACCORDION IS A CLASS TOGGLE AND NEVER A HEIGHT WRITE. `bmi.js` adds `.is-open` to the
     `.nav-li.wc`; the height comes from `grid-template-rows` going 0fr -> 1fr, so it animates
     without any script measuring anything. A script that writes `style.maxHeight` has to guess
     the content height and is wrong the moment the content reflows -- a label wrapping to two
     lines, a font arriving late, the drawer opening at another width -- with nothing to
     re-measure it.

     THE GRID IS ON THE LI, NOT ON THE PANEL, and that is not a stylistic choice. The first
     version put `grid-template-rows: 0fr` on the `ul.t1`, which has three `li` children: 0fr
     sized only the FIRST row and the other two came back as implicit `auto` rows, so the panel
     measured 100px tall while closed. The `li.wc` has exactly two children -- the link and the
     panel -- so the rows are explicit and exact. The toggle is placed into row 1 by grid rather
     than positioned absolutely, so it stretches to whatever height that row turns out to be.

     THE MODULE EMITS NO CHEVRON HERE, AND THAT IS DELIBERATE. `site_navigation` picks its
     context by substring on the wrapper class (option.ascx.cs:67-73): `top-nav`, `header-nav`,
     `mobile-nav`. This wrapper is `bmi-mobilenav-nav`, which does NOT contain `mobile-nav` --
     there is no hyphen between `mobile` and `nav`. It looks like a typo and it must not be
     "fixed": the module's mobile-nav branch injects its own logo and close button, and
     `.bmi-mobilenav-head` above already provides both, so matching that branch would duplicate
     the drawer head and switch on a `locations` module this site does not install. The template
     supplies the one thing it actually wants -- the toggle -- from `bmi.js`. --*/
.bmi-mobilenav-nav .nav-ul.t0 { display: flex; flex-direction: column; }
/*-- The row, not the label. `.nav-item` is inline-flex by default (16f) because in the header
     it is one item in a flex row. In a vertical list that makes the link only as wide as its
     text, so the separator rule under it stops a third of the way across and the touch target
     is the word rather than the row. --*/
.bmi-mobilenav-nav .nav-item { display: flex; width: 100%; }
.bmi-mobilenav-nav .nav-item.t0 { position: relative; padding: 16px 24px;
                                  font-size: 18px; font-weight: 500; color: var(--bmi-on-dark);
                                  border-bottom: 1px solid rgba(255,255,255,.10); }
.bmi-mobilenav-nav .nav-li.t0.is-active > .nav-item.t0::before {
	content: ""; position: absolute; left: 0; top: 10px; bottom: 10px; width: 3px;
	background: var(--bmi-lime); border-radius: 2px; }

.bmi-mobilenav-nav .nav-li.wc { display: grid; grid-template-columns: 1fr auto;
                                grid-template-rows: auto 0fr;
                                transition: grid-template-rows var(--bmi-dur-panel) var(--bmi-ease); }
.bmi-mobilenav-nav .nav-li.wc.is-open { grid-template-rows: auto 1fr; }
.bmi-mobilenav-nav .nav-li.wc > .nav-item.t0 { grid-column: 1; grid-row: 1; }
.bmi-mobilenav-nav .nav-li.wc > .bmi-navtoggle { grid-column: 2; grid-row: 1; }
.bmi-mobilenav-nav .nav-li.wc > .nav-ul.t1 { grid-column: 1 / -1; grid-row: 2;
                                             overflow: hidden; min-height: 0;
                                             background: rgba(0,0,0,.18); }

/* the toggle bmi.js inserts. A real button, because it is a real control. */
.bmi-mobilenav-nav .bmi-navtoggle { display: grid; place-items: center;
	width: var(--bmi-touch-min); padding: 0; margin: 0; cursor: pointer;
	background: none; border: 0; border-bottom: 1px solid rgba(255,255,255,.10);
	color: var(--bmi-on-dark); }
.bmi-mobilenav-nav .bmi-navtoggle::before { content: ""; width: 8px; height: 8px;
	border-right: 1.6px solid currentColor; border-bottom: 1.6px solid currentColor;
	transform: rotate(45deg) translate(-2px, -2px);
	transition: transform var(--bmi-dur-fast) var(--bmi-ease); }
.bmi-mobilenav-nav .nav-li.wc.is-open > .bmi-navtoggle::before {
	transform: rotate(225deg) translate(-2px, -2px); }

.bmi-mobilenav-nav .nav-item.t1 { padding: 13px 24px 13px 40px; font-size: var(--bmi-fs-ui);
                                  color: var(--bmi-on-dark-muted);
                                  border-bottom: 1px solid rgba(255,255,255,.06); }

/*-- 16f.4 Footer columns. ONE "Footer" menu, the reference build's shape: each top-level row
     is a column heading and its children are the column's links.

     THE TOP-LEVEL LIST IS LAID ONTO THE FOOTER GRID'S OWN TRACKS. The module wraps its list in
     two divs (the placement and its update panel), so the placement spans the four link tracks
     as a subgrid, the update panel steps out of the box tree, and the list is a subgrid again:
     every heading lands in exactly the cell a hand-placed column used to, at every breakpoint the
     footer grid already has. The repeat(4) line is the fallback for a browser without subgrid. --*/
.bmi-footer-grid > .bmi-footer-nav { grid-column: 2 / -1; display: grid;
                                     grid-template-columns: repeat(4, minmax(0, 1fr));
                                     grid-template-columns: subgrid; }
.bmi-footer-nav > div { display: contents; }
.bmi-footer-nav .nav-ul.t0 { grid-column: 1 / -1; display: grid;
                             grid-template-columns: repeat(4, minmax(0, 1fr));
                             grid-template-columns: subgrid; row-gap: 32px; }
.bmi-footer-nav .nav-li.t0 { display: flex; flex-direction: column; min-width: 0; }
.bmi-footer-nav .nav-item.t0 { font-size: var(--bmi-fs-label); font-weight: 700; letter-spacing: .14em;
                               text-transform: uppercase; color: #fff;
                               transition: color var(--bmi-dur-fast) var(--bmi-ease); }
.bmi-footer-nav a.nav-item.t0:hover { color: var(--bmi-lime-light); }
.bmi-footer-nav .open-icon { display: none; }
.bmi-footer-nav .nav-ul.t1 { display: flex; flex-direction: column; gap: 12px; margin-top: 18px;
                             font-size: var(--bmi-fs-ui); }
.bmi-footer-nav .nav-item.t1 { color: var(--bmi-on-dark-muted);
                               transition: color var(--bmi-dur-fast) var(--bmi-ease); }
.bmi-footer-nav .nav-item.t1[href]:hover { color: var(--bmi-lime-light); }
.bmi-footer-nav .nav-ul.t2 { display: none; }   /* two tiers: heading and link */

/*-- 16f.5 Copyright row. Inline, separated by a middot drawn from CSS so the module does not
     have to carry a separator character it would then emit in every other context. The first
     row is the copyright line itself, plain text with the year from %SITE_CurrentYear%, and the
     module's nowrap is lifted so it can wrap on a phone. --*/
.bmi-footer-copyright .nav-ul.t0 { display: flex; flex-wrap: wrap; align-items: center; gap: 0; }
.module-site_navigation.bmi-footer-copyright .nav-ul.t0 .nav-li.t0 .nav-item.t0 { white-space: normal; }
.bmi-footer-copyright .nav-item  { color: var(--bmi-on-dark-muted);
                                   transition: color var(--bmi-dur-fast) var(--bmi-ease); }
.bmi-footer-copyright .nav-item[href]:hover { color: var(--bmi-lime-light); }
.bmi-footer-copyright .nav-li.t0 + .nav-li.t0::before {
	content: "\00b7"; margin: 0 10px; color: var(--bmi-on-dark-faint-aa); }
.bmi-footer-copyright .nav-ul.t1 { display: none; }


/*-- =====================================================================
     17. RESPONSIVE
     ONE ladder: ABT's eight max-width breakpoints adopted VERBATIM
     (1080 / 980 / 900 / 860 / 760 / 720 / 620 / 560, verified by grep over
     its 2,448 lines) plus exactly ONE new step at 1180px for the two grids
     BMI ships that are denser than anything in ABT -- the 6-across category
     rail and the 4-across product grid.

     The five-step 1320/1024/768/480 ladder proposed in design-system.md 7.2
     is REJECTED and must not appear in any BMI stylesheet: a parallel ladder
     would reflow the inherited account nav at 760 while the new shop grid
     reflows at 768, and two collapses eight pixels apart on one viewport is
     a bug nobody sees in a screenshot and everybody feels on a phone.

     The canvas is desktop-only -- <div style="min-width:1220px"> at dc:26,
     zero @media in 1,144 lines -- so every rule below is net-new.
     ===================================================================== */

/*-- 17a. 1180 -- BMI only. The dense grids break before the hamburger. --*/
@media (max-width: 1180px) {
	.display-card.compact > ul, .display-images > ul, .display-steps > ul {
		grid-template-columns: repeat(3, minmax(0, 1fr)); }
	.catalog-wrapper.catalog-rail.display-card > ul { grid-template-columns: repeat(3, minmax(0, 1fr)); }
	/*-- The shop grid follows the committed 3-up ladder, not .bmi-g-3's. The ladder in
	     references/design/css-architecture.md:1122-1131 was written against .bmi-g-3, but the
	     shop emits .catalog-wrapper.display-card, so none of it was ever reaching the catalogue.
	     Each step is restated on the class the shop actually renders. --*/
	.catalog-wrapper.display-card > ul { gap: 20px; }
	.bmi-g-4 { grid-template-columns: repeat(3, 1fr); gap: 20px; }
	.bmi-header-nav { gap: 24px; font-size: 14px; }
}

/*-- 17b. 1080 -- THE header switch. Mirrors ABT style.css:2320-2327. ---*/
@media (max-width: 1080px) {
	:root { --bmi-chrome-h: 84px; --bmi-header-h: 72px; }
	.bmi-utilbar     { display: none; }
	.bmi-header-nav  { display: none; }
	.bmi-header-burger { display: grid; }
	.bmi-header-logo img { height: 44px; }
}

/*-- 17c. 980 -- the splits stack; the sidebar becomes a sheet. ---------*/
@media (max-width: 980px) {
	/*-- THE MISSING STEP, and the one that mattered. Without it the shop held three columns
	     all the way down to 860, so 980-1080, a common tablet band, rendered three 184px
	     cards whose 4/3 media well is 138px tall: the photograph smaller than the title
	     under it. Measured before this rule: 183.875px x3. --*/
	.catalog-wrapper.display-card > ul { grid-template-columns: repeat(2, minmax(0, 1fr)); }
	.bmi-account-sidebar { position: static; }

	.bmi-service-row { grid-template-columns: 1fr; gap: 0; }
	.bmi-service-media { height: 200px; min-height: 0; }
	.bmi-service-mid { padding: 28px var(--bmi-gutter); }
	.bmi-service-rail{ padding: 0 var(--bmi-gutter) 28px;
	                   border-left: none; border-top: 1px solid var(--bmi-rule-faint);
	                   flex-direction: row; align-items: center; gap: 20px;
	                   padding-top: 20px; flex-wrap: wrap; }
	.bmi-service-rail .bmi-btn { width: auto; padding: 0 24px; }
}


/*-- 17e. 860 -- the 4-across strip goes 2x2; grids go 2-up; rhythm drops. */
@media (max-width: 860px) {
	.display-card > ul, .display-card.compact > ul,
	.display-images > ul, .display-steps > ul, .categories-grid {
		grid-template-columns: repeat(2, minmax(0, 1fr)); }
	.catalog-wrapper.display-card > ul,
	.catalog-wrapper.catalog-rail.display-card > ul { grid-template-columns: repeat(2, minmax(0, 1fr)); }
	/*-- MODULE LAYER (16). A placement's Columns setting (columns-N, from info_cards) halves to two
	     here, three and four alike: four becomes an even two-by-two rather than three and a stray. --*/
	.display-card.columns-3 > ul, .display-card.columns-4 > ul { grid-template-columns: repeat(2, minmax(0, 1fr)); }
	.display-card > ul             { gap: 18px; }
	/*-- Pinned to the spec's 16px. The generic .display-card > ul rule directly above matches
	     the same element with equal specificity, so the shop needs its own or it inherits 18. --*/
	.catalog-wrapper.display-card > ul { gap: 16px; }
	:root { --bmi-section-pad: 72px; }

	.bmi-g-4 { grid-template-columns: repeat(2, 1fr); gap: 16px; }

	.bmi-footer-grid { grid-template-columns: repeat(2, 1fr); gap: 32px 40px; }
	.bmi-footer-brand { grid-column: 1 / -1; }
	.bmi-footer-grid > .bmi-footer-nav { grid-column: 1 / -1; }
	.bmi-footer-nav .nav-ul.t0 { grid-template-columns: repeat(2, minmax(0, 1fr)); grid-template-columns: subgrid; }
	.bmi-lead { font-size: var(--bmi-fs-lg); }
}

/*-- 17f. 760 -- the compare table becomes cards; PDP gets an action bar. */
@media (max-width: 760px) {
	/*-- MODULE LAYER (16). The page grid stacks. The inline flex-basis PageManager
	     writes on each .cell is overridden here, not removed -- it is on the element,
	     so only a declaration of equal specificity in a later media query can win. --*/
	.row  { flex-direction: column; row-gap: var(--bmi-gutter); }
	.cell { flex-basis: auto !important; width: 100%; }
	.cell-content + .cell-content { margin-top: 40px; }


	.bmi-account-nav { flex-direction: row; flex-wrap: wrap; gap: 4px; }
	.bmi-account-nav-link { padding: 8px 11px; font-size: var(--bmi-fs-ui-sm); }
	/* a group label owns its own row so the groups still read as groups once the
	   nav becomes a wrapped chip row (inherited fix, ABT style.css:2379-2383) */
	.bmi-account-nav .bmi-sidebar-label { flex: 1 0 100%; padding: 12px 4px 2px; }
	.bmi-account-nav .bmi-sidebar-label:first-child { padding-top: 2px; }
	/* Compact on a phone: the chips are the whole card, and the name above them would push the
	   page below the fold; the header already carries the account. */
	.bmi-account-ident { display: none; }
	.bmi-account-navcard { padding: 8px; }


}


/*-- 17h. 620 -- single column; the header shrinks again. --------------*/
@media (max-width: 620px) {
	.media-grid > ul, .testimonial-grid { grid-template-columns: minmax(0, 1fr); }
	.panel.bmi-page-intro > .panel-table { padding-top: 36px; padding-bottom: 32px; }
	.display-card > ul, .display-card.compact > ul,
	.display-images > ul, .display-steps > ul, .categories-grid {
		grid-template-columns: minmax(0, 1fr); }
	/*-- 2-UP, NOT 1. The shop holds two columns one step longer than the home grid, and the
	     committed ladder says why: "a filtered catalogue is a scanning task and a 1-col list of
	     30 products is a long scroll" (css-architecture.md:1135). This dropped to a single
	     column here; the single-column step belongs at 560 and is now there. --*/
	.catalog-wrapper.display-card > ul { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
	.catalog-wrapper.catalog-rail.display-card > ul { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
	.catalog-rail .item-data { padding: 12px; }
	.catalog-rail .item-title { font-size: 14px; }
	/*-- MODULE LAYER (16). Two and three go to one column on a phone; four stays two-by-two, which is
	     what the home trust bar did when a template class forced it. --*/
	.display-card.columns-2 > ul, .display-card.columns-3 > ul { grid-template-columns: minmax(0, 1fr); }
	.item-data, .card-data { padding: 16px 16px 18px; }
	:root { --bmi-chrome-h: 64px; --bmi-header-h: 64px; --bmi-section-pad: 56px; }
	body { font-size: 15.5px; }

	.bmi-header-logo img { height: 38px; }
	.bmi-header-inner { gap: 16px; }
	.bmi-header-actions { gap: 8px; }
	.bmi-header-actionnav .nav-ul.t0 { gap: 8px; }
	/*-- The labelled chip collapses to its icon here. This used to be written `.is-compact`,
	     a class nothing added and nothing could add, so the rule was unreachable and the word
	     "Cart" would have pushed the header past the viewport on a phone. The breakpoint is
	     the condition; it does not need a class to say so as well.

	     font-size:0 rather than a rule hiding a label element, because the label is a bare
	     text node in a menu row an administrator typed -- there is no span to select, and
	     there should not have to be. The icon and the count set their own size back. --*/
	.bmi-header-actionnav .nav-item.nav-haslabel { width: var(--bmi-touch-min); padding: 0;
	                      border-radius: 50%; justify-content: center; font-size: 0; }
	.bmi-header-actionnav .nav-item.nav-haslabel .fa { margin-right: 0; }
	.bmi-header-actionnav .nav-item.nav-haslabel .nav-count { position: absolute; top: -4px; right: -4px;
	                      margin-left: 0; font-size: var(--bmi-fs-label); }

	.bmi-g-4 { grid-template-columns: 1fr; gap: 16px; }

	.bmi-eyebrow { letter-spacing: .14em; }

	.bmi-footer-grid  { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 30px 24px; }
	.bmi-footer-nav .nav-ul.t0 { row-gap: 30px; }
	.bmi-footer-legal { flex-direction: column; align-items: flex-start; gap: 8px; text-align: left; }

	/* the cart drawer goes full screen; the footer sticks so Checkout is always reachable */
	.bmi-drawer      { width: 100vw; left: 0; }
	.bmi-tier { padding: 26px 22px; }
}

/*-- 17i. 560 -- the last step. -------------------------------------------*/
@media (max-width: 560px) {
	/*-- The single-column step, moved here from 620 where it was arriving one breakpoint early. --*/
	.catalog-wrapper.display-card > ul { grid-template-columns: minmax(0, 1fr); }
	.bmi-mobilenav { width: 100vw; }
	/*-- THE BURGER MUST ALWAYS FIT. The logo, a 123px language menu, three 44px buttons and the
	     burger measured 450px against a 390px phone, and the burger -- last in the row -- sat at
	     x=390, past the edge, on every page: the main menu could not be opened at all. The language
	     menu moves into the drawer here (template.master), which leaves logo + four buttons, 305px
	     at the tightest gaps below, inside a 320px screen. --*/
	.bmi-header-actions > .gtranslate_wrapper { display: none; }
	.bmi-mobilenav .bmi-mobilenav-language { display: block; }
	.bmi-mobilenav .bmi-mobilenav-language:empty { display: none; }
}
@media (max-width: 380px) {
	.bmi-header-inner { gap: 10px; }
	.bmi-header-actions,
	.bmi-header-actionnav .nav-ul.t0 { gap: 6px; }
}

/* G3a: privacy preferences use the template's controls, colors and spacing. */
.bmi-privacy-link { appearance: none; background: none; border: 0; padding: 0; min-height: var(--bmi-touch-min); font: inherit; cursor: pointer; text-align: left; }
.bmi-privacy-banner[hidden], .bmi-privacy-overlay[hidden] { display: none; }
.bmi-privacy-banner { position: fixed; inset: auto 20px 20px; z-index: 1200; max-width: 860px; margin: auto; padding: 24px; background: #fff; color: var(--bmi-ink-body); border: 1px solid var(--bmi-purple); border-radius: var(--bmi-radius-ctl); box-shadow: 0 8px 40px rgb(0 0 0 / 18%); }
.bmi-privacy-banner p { margin: 0 0 16px; }
.bmi-privacy-actions { display: flex; flex-wrap: wrap; gap: 10px; }
.bmi-privacy-actions .bmi-btn { min-height: 44px; padding: 10px 16px; white-space: normal; }
.bmi-privacy-overlay { position: fixed; inset: 0; z-index: 1300; display: grid; place-items: center; padding: 20px; background: rgb(25 18 30 / 60%); }
.bmi-privacy-dialog { width: min(100%, 600px); max-height: calc(100dvh - 40px); overflow-y: auto; overscroll-behavior: contain; border-radius: var(--bmi-radius-ctl); background: #fff; color: var(--bmi-ink-body); padding: 28px; box-shadow: 0 16px 60px rgb(0 0 0 / 24%); }
.bmi-privacy-heading { display: flex; justify-content: space-between; align-items: start; gap: 16px; }
.bmi-privacy-heading h2 { margin: 0 0 14px; font-size: 30px; }
.bmi-privacy-heading .bmi-header-iconbtn { flex: 0 0 44px; }
.bmi-privacy-dialog p { font-size: 15px; line-height: 1.5; }
.bmi-privacy-choice { padding: 14px 0; border-top: 1px solid #ddd6df; }
.bmi-privacy-choice label { display: flex; gap: 10px; align-items: center; font-weight: 600; cursor: pointer; }
.bmi-privacy-choice input { width: 20px; height: 20px; accent-color: var(--bmi-purple); flex: 0 0 20px; }
.bmi-privacy-choice p { margin: 6px 0 0 30px; }
.bmi-privacy-open { overflow: hidden; }
@media (max-width: 560px) {
	.bmi-privacy-overlay { padding: 12px; }
	.bmi-privacy-dialog { padding: 20px; max-height: calc(100dvh - 24px); }
	.bmi-privacy-heading h2 { font-size: 25px; }
	.bmi-privacy-banner { inset: auto 12px 12px; padding: 18px; }
	.bmi-privacy-actions .bmi-btn { flex: 1 1 140px; }
}

/*-- END. Companion document: references/design/css-architecture.md
     Every class above is catalogued there with its canvas line reference,
     its element structure, and the decision behind any deviation. -------*/
