/* ══════════════════════════════════════════════════════════════════════════
   assets/public-blocks.css
   Mark VII Car Wash Academy — PUBLIC content-block library.

   Loads AFTER assets/public-shell.css. The shell is the frame (tokens, type,
   header, hero, footer, buttons); this file is the set of blocks every page
   body is built from.

   Every block here is a port of a washtec.com block, taken from their own
   stylesheets (merged-c3158fb2…min.css, app.css, styles__ltr.css) and their
   rendered DOM. The `m-` prefix becomes `pub-`; the values do not change.
   Where a rule needed a raster icon we could not take, the icon is redrawn as
   an inline SVG data URI so the block stays self-contained — noted at each
   one. Nothing else is improvised.

   Block                     WashTec original
   ─────────────────────────────────────────────────────────────────────────
   .pub-intro                .m-intro              interior page header band
   .pub-content-block        .m-content-block      prose body
   .pub-headline-group       .m-headline-group     heading + subline
   .pub-text-image           .m-text-and-image-block
   .pub-offset               .m-image-and-container-block   (the offset one)
   .pub-teasers              .m-teaser-boxes
   .pub-cards                .m-link-preview
   .pub-numbers              .m-numbers
   .pub-quote                .m-quote
   .pub-downloads            .m-downloads
   .pub-accordion            .m-accordion
   .pub-form                 .m-form
   .space-*                  .space-top-* / .space-bottom-*
   ══════════════════════════════════════════════════════════════════════════ */

/* ── Section spacing modifiers — .space-top-* / .space-bottom-*, verbatim.
   These are how washtec.com varies rhythm between sections; without them
   every band sits on the same 2.5rem/3.125rem and the page reads flat. */
.mvii-public .space-top-sm     { margin-top: 20px !important; }
.mvii-public .space-top-md     { margin-top: 40px !important; }
.mvii-public .space-top-lg     { margin-top: 60px !important; }
.mvii-public .space-top-xlg    { margin-top: 120px !important; }
.mvii-public .space-top-none   { margin-top: 0 !important; }
.mvii-public .space-bottom-sm  { margin-bottom: 20px !important; }
.mvii-public .space-bottom-md  { margin-bottom: 40px !important; }
.mvii-public .space-bottom-lg  { margin-bottom: 60px !important; }
.mvii-public .space-bottom-xlg { margin-bottom: 120px !important; }
.mvii-public .space-bottom-none{ margin-bottom: 0 !important; }
.mvii-public .no-padding-before { padding-top: 0 !important; }
.mvii-public .no-padding-after  { padding-bottom: 0 !important; }
/* Headings carry `width: fit-content` (that is how the gradient text-fill is
   kept to the glyphs), so centring the text is not enough — the box has to be
   centred too. Buttons are deliberately NOT in this list: a `margin: 0 auto`
   on a flex item inside a row of actions does not centre it, it shoves it to
   the far end of the row, which is exactly what happened to the two buttons in
   the closing band. Rows of buttons centre themselves via their own flex
   container instead. */
.mvii-public .text-center { text-align: center; }
.mvii-public .text-center .pub-h2,
.mvii-public .text-center :where(h1, h2, h3, h4, h5, h6) { margin-left: auto; margin-right: auto; }
/* A single button standing alone in a content block does centre this way —
   their .m-content-block :where(.m-button) { margin: 0 auto }. */
.mvii-public .pub-content-block > .pub-btn { margin-left: auto; margin-right: auto; }
/* Row of actions under a block. */
.mvii-public .pub-actions { display: flex; gap: 1.25rem; flex-wrap: wrap; }
.mvii-public .text-center .pub-actions { justify-content: center; }

/* ══════════════════════════════════════════════════════════════════════════
   .pub-intro — .m-intro
   This is how washtec.com heads an interior page, and it is also how the page
   clears the fixed header: the container simply carries 16.1875rem of top
   padding at >=1200px (6.6875rem below), with the corporate gradient behind
   it. The shell used to reserve that space with `body { padding-top }`, which
   worked but put a blank white gap above the first band on every page. This
   is the real mechanism, and it is why their interior pages open on colour.
   ══════════════════════════════════════════════════════════════════════════ */
.mvii-public .pub-intro { color: var(--mv-white); }
.mvii-public .pub-intro__container {
  min-height: 18.1875rem;
  padding-top: 6.6875rem; padding-bottom: 2.5rem;
  background: var(--mv-gradient);
}
@media (max-width: 1200px) { .mvii-public .pub-intro__container { min-height: 11.9375rem; } }
@media (min-width: 1200px) {
  .mvii-public .pub-intro__container { min-height: unset; padding-top: 16.1875rem; padding-bottom: 3.75rem; }
}
.mvii-public .pub-intro__container.blue-dark { background: var(--mv-blue-dark); }
.mvii-public .pub-intro__inner {
  display: flex; flex-direction: row; align-items: center; gap: 1.5rem;
  width: 100%; max-width: var(--mv-container); margin: 0 auto;
  padding-left: var(--mv-container-pad); padding-right: var(--mv-container-pad);
}
.mvii-public .pub-intro__heading {
  max-width: 1280px; margin-bottom: 0;
  font-size: 2.125rem; font-weight: 800; line-height: 1.41;
  color: var(--mv-white);
}
@media (min-width: 1200px) {
  .mvii-public .pub-intro__heading { font-size: 4.875rem; line-height: 1.28; }
}
/* The gradient text-fill that default sections apply to headings must not
   reach in here — the band is already gradient, so the heading is solid white. */
.mvii-public .pub-intro__heading .grad {
  background-image: none; -webkit-text-fill-color: var(--mv-white); color: var(--mv-white);
}
.mvii-public .pub-intro__lede {
  max-width: 60ch; margin-top: 1.5rem;
  font-size: 1.125rem; line-height: 1.33; color: rgb(255 255 255 / .92);
}
@media (min-width: 1200px) { .mvii-public .pub-intro__lede { font-size: 1.5rem; } }
.mvii-public .pub-intro__actions { display: flex; gap: 12px; flex-wrap: wrap; margin-top: 1.875rem; }
/* .m-intro__image — the optional full-bleed image directly beneath the band. */
.mvii-public .pub-intro__image {
  display: block; width: 100%; max-height: 45rem; height: auto;
  margin: 0 auto; object-fit: cover;
}

/* ── .pub-on-dark ─────────────────────────────────────────────────────────
   Any block that paints its own gradient or dark background but is NOT a
   .pub-section.gradient-1 needs the heading gradient-fill switched off, or
   its headings render as gradient-on-gradient and disappear. That is exactly
   what happened to the sign-in panel's headline on first render: it inherited
   `-webkit-text-fill-color: transparent` from the site-wide heading treatment
   and vanished into the panel behind it. Put this class on any such block. */
.mvii-public .pub-on-dark,
.mvii-public .pub-on-dark p { color: var(--mv-white); }
.mvii-public .pub-on-dark :where(h1, h2, h3, h4, h5, h6),
.mvii-public .pub-on-dark .grad {
  background-image: none; -webkit-text-fill-color: var(--mv-white); color: var(--mv-white);
}
/* Prose-anchor colouring is scoped to .pub-section p/li in the shell, at
   (0,2,1). A link inside a dark panel has to beat that, or it renders in the
   corporate blue on a navy ground and disappears. */
.mvii-public .pub-section .pub-on-dark a,
.mvii-public .pub-section .pub-on-dark p a { color: var(--mv-white); text-decoration: underline; }

/* ══════════════════════════════════════════════════════════════════════════
   .pub-content-block — .m-content-block
   Their body copy is 1.125rem below 1200px and 1.5rem above. Block children
   are spaced by `:where(:not(:last-child)) { margin-bottom: 1.5rem }` rather
   than by per-element margins, and unstyled lists get the round bullet drawn
   in currentColor at -1.5625rem. All verbatim.
   ══════════════════════════════════════════════════════════════════════════ */
.mvii-public .pub-content-block { font-size: 1.125rem; line-height: 1.33; }
@media (min-width: 1200px) { .mvii-public .pub-content-block { font-size: 1.5rem; } }
.mvii-public .pub-content-block :where(:not(:last-child)) { margin-bottom: 1.5rem; }
.mvii-public .pub-content-block :where(:is(ul, ol):not([class])) { margin-left: 1.5625rem; list-style: none; padding: 0; }
.mvii-public .pub-content-block :where(:is(ul, ol):not([class]) li) { position: relative; }
.mvii-public .pub-content-block :where(ul:not([class]) li)::before {
  content: ''; position: absolute; left: -1.5625rem; top: .4375rem;
  width: .625rem; height: .625rem; border-radius: 50%; background-color: currentColor;
}
@media (min-width: 1200px) { .mvii-public .pub-content-block :where(ul:not([class]) li)::before { top: .625rem; } }
.mvii-public .pub-content-block :where(ol:not([class])) { counter-reset: ordered-list; }
.mvii-public .pub-content-block :where(ol:not([class]) li)::before {
  counter-increment: ordered-list; content: counter(ordered-list) ".";
  position: absolute; left: -1.5625rem; top: .375rem; font: inherit; line-height: .625rem;
}
@media (min-width: 1200px) { .mvii-public .pub-content-block :where(ol:not([class]) li)::before { top: .625rem; } }
.mvii-public .pub-content-block :where(a:not([class])) { color: inherit; text-decoration: underline; }
.mvii-public .pub-content-block .blue { color: var(--mv-blue-dark); }
.mvii-public .pub-content-block .light-blue { color: var(--mv-blue-25); }
/* Their images inside a content block bleed to the container edge below 900px. */
.mvii-public .pub-content-block :where(img:not([class])) {
  max-width: calc(100% + 2.5rem); width: calc(100% + 2.5rem);
  margin-right: -1.25rem; margin-left: -1.25rem;
}
@media (min-width: 900px) {
  .mvii-public .pub-content-block :where(img:not([class])) { max-width: 100%; width: 100%; margin-right: 0; margin-left: 0; }
}
.mvii-public .pub-headline-group--has-icon { display: flex; flex-direction: row; align-items: flex-start; gap: .5em; }
.mvii-public .pub-headline-group__content { flex: 1 1 0%; min-width: 0; }
.mvii-public .pub-headline-group__icon { flex: 0 0 auto; width: 2.5rem; height: 2.5rem; }

/* ══════════════════════════════════════════════════════════════════════════
   .pub-text-image — .m-text-and-image-block
   Column below 900px, row above, with the image column fixed at 35.3125rem
   and a 119px gutter on the text side. The --right modifier reverses it and
   moves the gutter. The 119px is theirs; it is what gives their alternating
   rows the wide, unhurried gap ours never had.
   ══════════════════════════════════════════════════════════════════════════ */
.mvii-public .pub-text-image { display: flex; flex-direction: column; align-items: center; gap: 2.5rem; }
@media (min-width: 900px) {
  .mvii-public .pub-text-image { flex-direction: row; gap: 1.875rem; }
  .mvii-public .pub-text-image--right { flex-direction: row-reverse; }
  .mvii-public .pub-text-image__image-wrapper { flex: 0 1 35.3125rem; }
  .mvii-public .pub-text-image__content-wrapper { flex: 1 1 35.3125rem; padding-left: 119px; padding-right: 0; }
  .mvii-public .pub-text-image--right .pub-text-image__content-wrapper { padding-left: 0; padding-right: 119px; }
}
.mvii-public .pub-text-image__image { display: block; width: 100%; height: auto; }

/* ══════════════════════════════════════════════════════════════════════════
   .pub-offset — .m-image-and-container-block
   THE offset column. The image wrapper pulls itself out of the section's own
   vertical padding with matching negative margins (-2.5rem, -3.125rem at
   >=900px), so the picture bleeds past the band top and bottom while the text
   stays on the grid. Image capped at min(34.1875rem, 50%); text flexes
   1 1 65.8125rem. Use inside a .pub-section with a .wide container.
   ══════════════════════════════════════════════════════════════════════════ */
@media (min-width: 600px) { .mvii-public .pub-offset { display: flex; align-items: center; flex-direction: row; } }
.mvii-public .pub-offset--right { flex-direction: row-reverse; }
.mvii-public .pub-offset .pub-content-block { width: 100%; }
.mvii-public .pub-offset__image-wrapper { align-self: stretch; margin-top: -2.5rem; margin-bottom: 2.5rem; }
@media (min-width: 600px) {
  .mvii-public .pub-offset__image-wrapper { flex: 0 1 auto; max-width: min(34.1875rem, 50%); margin-top: -2.5rem; margin-bottom: -2.5rem; }
}
@media (min-width: 900px) {
  .mvii-public .pub-offset__image-wrapper { margin-top: -3.125rem; margin-bottom: -3.125rem; }
}
.mvii-public .pub-offset__image { display: block; width: 100%; height: 100%; object-fit: cover; }
@media (min-width: 600px) { .mvii-public .pub-offset__text-wrapper { flex: 1 1 65.8125rem; } }

/* ══════════════════════════════════════════════════════════════════════════
   .pub-teasers — .m-teaser-boxes
   Flat grey boxes, 30px gap, two up. No radius, no shadow, no lift: the only
   motion is the image scaling to 107% on hover over .6s. The button inside is
   their gradient-filled pill that INVERTS to gradient-on-white text with a
   1px inset ring — that inversion is the detail that makes it theirs.
   ══════════════════════════════════════════════════════════════════════════ */
/* One deliberate deviation, and it is a correction rather than a restyle.
   Theirs reads `.m-teaser-boxes { gap:30px; margin:0 -14px }` with
   `.m-teaser-boxes--item { flex:1 0 calc(50% - 15px); margin:0 14px }`. Those
   numbers only resolve on washtec.com because the boxes sit inside a slick
   slider that sets an explicit track width on every slide; as a plain flex row
   the 50%-15px basis plus 28px of margin exceeds 50%, so exactly one box fits
   per line — which is what ours did on first render. The gutter here is the
   same 30px, expressed as a real `gap` with a basis that leaves room for it. */
.mvii-public .pub-teasers { display: flex; flex-wrap: wrap; flex-direction: row; gap: 30px; }
.mvii-public .pub-teaser {
  flex: 1 1 calc(50% - 15px); min-width: 0;
  background-color: var(--mv-grey-bg); display: flex; flex-direction: column;
}
@media (max-width: 800px) { .mvii-public .pub-teaser { flex: 1 1 100%; } }
.mvii-public .pub-teasers--three .pub-teaser { flex: 1 1 calc(33.333% - 20px); }
@media (max-width: 1200px) { .mvii-public .pub-teasers--three .pub-teaser { flex: 1 1 calc(50% - 15px); } }
@media (max-width: 800px)  { .mvii-public .pub-teasers--three .pub-teaser { flex: 1 1 100%; } }
.mvii-public .pub-teaser__image { overflow: hidden; }
.mvii-public .pub-teaser__image img {
  display: block; width: 100%; height: auto;
  transition: transform .6s cubic-bezier(.35, 0, 0, 1);
}
.mvii-public .pub-teaser__image img:hover { transform: scale(107%); }
.mvii-public .pub-teaser__wrapper { padding: 40px 20px; display: flex; flex-direction: column; flex: 1; }
.mvii-public .pub-teaser__headline {
  padding-bottom: 20px; width: fit-content;
  background-image: var(--mv-gradient);
  -webkit-background-clip: text; background-clip: text; -webkit-text-fill-color: #fff0;
}
.mvii-public .pub-teaser__description { padding-bottom: 20px; color: var(--mv-black); font-size: 1.125rem; line-height: 1.33; }
@media (min-width: 1200px) { .mvii-public .pub-teaser__description { font-size: 1.5rem; } }
.mvii-public .pub-teaser__link { margin-top: auto; }
.mvii-public .pub-teaser__link a,
.mvii-public .pub-grad-btn {
  display: flex; justify-content: center; align-items: center;
  min-width: min(11.375rem, 100%); width: fit-content;
  padding: .4375rem 1.25rem; border: none; border-radius: 1.25rem;
  font-family: var(--mv-font); font-size: 1.125rem; font-weight: 700; line-height: 1.625rem;
  text-decoration: none; color: var(--mv-white);
  background-image: var(--mv-gradient);
}
.mvii-public .pub-teaser__link a:hover,
.mvii-public .pub-grad-btn:hover {
  text-decoration: none;
  background-image: var(--mv-gradient);
  -webkit-background-clip: text; background-clip: text; -webkit-text-fill-color: #fff0;
  box-shadow: inset 0 0 0 1px var(--mv-blue-dark);
}
/* In a gradient or dark band their teasers go white instead of grey. */
.mvii-public .pub-section.gradient-1 .pub-teaser,
.mvii-public .pub-section.blue-dark  .pub-teaser { background-color: var(--mv-white); }

/* ══════════════════════════════════════════════════════════════════════════
   .pub-cards — .m-link-preview
   Their three-up card: 3:2 image, gradient headline, clamped description,
   gradient button pinned to the bottom. Breakpoints are 800px (two up) and
   1366px (three up) — not the 980/640 our old grid used, which is why our
   rows broke at different widths from theirs.
   ══════════════════════════════════════════════════════════════════════════ */
.mvii-public .pub-cards { display: grid; grid-template-columns: 1fr; gap: 30px; }
@media (min-width: 800px)  { .mvii-public .pub-cards { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1366px) { .mvii-public .pub-cards { grid-template-columns: repeat(3, 1fr); } }
.mvii-public .pub-cards--two { grid-template-columns: 1fr; }
@media (min-width: 800px) { .mvii-public .pub-cards--two { grid-template-columns: repeat(2, 1fr); } }
.mvii-public .pub-cardp { background-color: var(--mv-grey-bg); display: flex; flex-direction: column; }
.mvii-public .pub-cardp__image { overflow: hidden; aspect-ratio: 3 / 2; }
.mvii-public .pub-cardp__image img {
  display: block; width: 100%; height: 100%; object-fit: cover;
  transition: transform .6s cubic-bezier(.35, 0, 0, 1);
}
.mvii-public .pub-cardp__image img:hover { transform: scale(107%); }
.mvii-public .pub-cardp__wrapper { padding: 10px 20px 30px; flex: 1; display: flex; flex-direction: column; }
.mvii-public .pub-cardp__date { min-height: 1.4em; margin-bottom: 6px; font-size: 1rem; line-height: 1.4; color: var(--mv-black); opacity: .7; }
.mvii-public .pub-cardp__headline {
  padding-bottom: 20px; line-height: 1.3; font-size: 1.8rem; font-weight: 700; width: fit-content;
  background-image: var(--mv-gradient);
  -webkit-background-clip: text; background-clip: text; -webkit-text-fill-color: #fff0;
}
.mvii-public .pub-cardp__description { padding-bottom: 20px; color: var(--mv-black); flex: 1; font-size: 1.5rem; line-height: 1.2; }
.mvii-public .pub-cardp__description p { display: -webkit-box; -webkit-line-clamp: 4; -webkit-box-orient: vertical; overflow: hidden; margin: 0; }
.mvii-public .pub-cardp__link { margin-top: auto; display: flex; justify-content: center; align-items: center; }

/* ══════════════════════════════════════════════════════════════════════════
   .pub-numbers — .m-numbers
   Gradient stat tiles, 10px radius, one/two/three up. The counter steps
   3.125 → 3.3125 → 4.875rem across their three breakpoints.
   ══════════════════════════════════════════════════════════════════════════ */
.mvii-public .pub-numbers {
  display: grid; grid-template-columns: repeat(1, minmax(0, 1fr)); gap: 1.875rem;
  justify-items: center; margin-left: 0; padding: 0; list-style: none;
  color: var(--mv-white); text-align: center;
}
@media (min-width: 900px)  { .mvii-public .pub-numbers { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 1200px) { .mvii-public .pub-numbers--three { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
.mvii-public .pub-numbers__item {
  display: flex; flex-direction: column; align-items: center; gap: .625rem;
  max-width: 21.875rem; width: 100%; padding: 2.5rem 1.25rem 3.125rem;
  background: var(--mv-gradient) center center no-repeat; border-radius: 10px;
}
@media (min-width: 900px) { .mvii-public .pub-numbers__item { max-width: unset; } }
.mvii-public .pub-numbers__item.blue-dark { background: var(--mv-blue-dark) center center no-repeat; }
.mvii-public .pub-numbers__counter { margin: 0; font-size: 3.125rem; font-weight: 800; line-height: 1.12; color: var(--mv-white); }
@media (min-width: 900px)  { .mvii-public .pub-numbers__counter { font-size: 3.3125rem; line-height: 1.16; } }
@media (min-width: 1200px) { .mvii-public .pub-numbers__counter { font-size: 4.875rem;  line-height: 1.16; } }
.mvii-public .pub-numbers__title { margin: 0; font-size: 2.125rem; font-weight: 800; line-height: 1.12; color: var(--mv-white); }
@media (min-width: 900px) { .mvii-public .pub-numbers__title { font-size: 3.3125rem; line-height: 1.16; } }
.mvii-public .pub-numbers__text { margin: 0; font-size: 1.125rem; font-weight: 700; line-height: 1.33; }
@media (min-width: 900px) { .mvii-public .pub-numbers__text { font-size: 1.75rem; line-height: 1.39; } }

/* ══════════════════════════════════════════════════════════════════════════
   .pub-quote — .m-quote
   Italic 1.25rem body (1.75rem at >=900px) sitting under a large quotation
   mark, with an extrabold caption. Theirs uses a quote.svg we do not have, so
   the mark is drawn with the typeface itself at the same 9.625rem / 11.5rem
   footprint — same shape, no missing asset.
   ══════════════════════════════════════════════════════════════════════════ */
/* `figure` and `blockquote` both ship with a browser margin (40px on the
   blockquote), which pushed the body away from the mark on first render. The
   block resets both — the spacing here is the block's own, not the UA's. */
.mvii-public .pub-quote { display: flex; flex-direction: column; align-items: start; font-size: 1.25rem; text-align: left; margin: 0; }
@media (min-width: 900px) { .mvii-public .pub-quote { font-size: 1.75rem; } }
.mvii-public .pub-quote__mark {
  display: block; font-family: var(--mv-font); font-weight: 800;
  font-size: 9.625rem; line-height: .55; height: 3.4rem; overflow: hidden;
  color: var(--mv-grey-bg); margin: 0 0 1rem; user-select: none;
}
@media (min-width: 900px) { .mvii-public .pub-quote__mark { font-size: 11.5rem; height: 4.0625rem; } }
.mvii-public .pub-section.gradient-1 .pub-quote__mark,
.mvii-public .pub-section.blue-dark  .pub-quote__mark { color: rgb(255 255 255 / .25); }
.mvii-public .pub-quote__body {
  max-width: 57.6875rem; padding-bottom: 1.875rem; margin: 0;
  font-weight: 500; font-style: italic; line-height: 1.4; quotes: '\201C' '\201D';
}
@media (min-width: 900px) { .mvii-public .pub-quote__body { padding-bottom: 2.5rem; line-height: 1.29; } }
.mvii-public .pub-quote__body::before { content: open-quote; }
.mvii-public .pub-quote__body::after  { content: close-quote; }
.mvii-public .pub-quote__caption { max-width: 57.6875rem; font-weight: 800; font-style: italic; line-height: 1; }
@media (min-width: 900px) { .mvii-public .pub-quote__caption { font-style: normal; line-height: 1.29; } }

/* ══════════════════════════════════════════════════════════════════════════
   .pub-downloads — .m-downloads
   The document list. This is the block the Standards & Conduct Agreement and
   the Initial Assessment belong in. Their PDF sheet icon is an asset we do
   not have, so it is redrawn as an inline SVG data URI at the same 2.875 x
   3.375rem (4.5625 x 5.3125rem at >=900px) footprint — one for dark type on
   light bands, one for light type on gradient bands.
   ══════════════════════════════════════════════════════════════════════════ */
.mvii-public .pub-downloads { list-style: none; margin: 0; padding: 0; }
.mvii-public .pub-downloads__item { display: flex; align-items: center; gap: .875rem; }
@media (min-width: 900px) { .mvii-public .pub-downloads__item { gap: 1rem; } }
.mvii-public .pub-downloads__item:not(:last-child) { margin-bottom: 1.875rem; }
.mvii-public .pub-downloads__item::before {
  content: ''; flex: 0 0 auto; display: block;
  width: 2.875rem; height: 3.375rem; background-size: 2.875rem 3.375rem;
  background-repeat: no-repeat; background-position: center center;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 46 54' fill='none' stroke='%23123253' stroke-width='2.5'%3E%3Cpath d='M28 2H8a4 4 0 0 0-4 4v42a4 4 0 0 0 4 4h30a4 4 0 0 0 4-4V16z'/%3E%3Cpath d='M28 2v14h14'/%3E%3Cpath d='M13 33h20M13 41h14'/%3E%3C/svg%3E");
}
@media (min-width: 900px) {
  .mvii-public .pub-downloads__item::before { width: 4.5625rem; height: 5.3125rem; background-size: 4.5625rem 5.3125rem; }
}
.mvii-public .pub-section.gradient-1 .pub-downloads__item::before,
.mvii-public .pub-section.blue-dark  .pub-downloads__item::before {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 46 54' fill='none' stroke='%23ffffff' stroke-width='2.5'%3E%3Cpath d='M28 2H8a4 4 0 0 0-4 4v42a4 4 0 0 0 4 4h30a4 4 0 0 0 4-4V16z'/%3E%3Cpath d='M28 2v14h14'/%3E%3Cpath d='M13 33h20M13 41h14'/%3E%3C/svg%3E");
}
.mvii-public .pub-downloads__link { font-size: 1.125rem; line-height: 1.33; color: var(--mv-black); text-decoration: none; }
@media (min-width: 900px) { .mvii-public .pub-downloads__link { font-size: 1.5rem; } }
.mvii-public .pub-downloads__link:hover { text-decoration: underline; }
.mvii-public .pub-section.gradient-1 .pub-downloads__link,
.mvii-public .pub-section.blue-dark  .pub-downloads__link { color: var(--mv-white); }
.mvii-public .pub-downloads__size { display: block; font-size: .875rem; opacity: .7; }

/* ══════════════════════════════════════════════════════════════════════════
   .pub-accordion — .m-accordion
   Light-grey title bars, 80px minimum, 22px type (2rem at >=1200px), with a
   49px chevron that rotates 180deg when open. Closed panels are moved off
   canvas rather than display:none so their height can animate — kept, because
   it is also what keeps the content in the accessibility tree and findable by
   in-page search.
   ══════════════════════════════════════════════════════════════════════════ */
.mvii-public .pub-accordion__item { margin-bottom: 10px; }
.mvii-public .pub-accordion__item:last-child { margin-bottom: 0; }
.mvii-public .pub-accordion__title {
  position: relative; width: 100%; text-align: left;
  background-color: var(--mv-grey-light); min-height: 80px;
  padding: 17px 99px 17px 20px; cursor: pointer; border: 0;
  font-family: var(--mv-font); font-size: 22px; font-weight: 400; color: var(--mv-black);
  display: flex; align-items: center;
}
@media (min-width: 1200px) { .mvii-public .pub-accordion__title { font-size: 2rem; } }
.mvii-public .pub-accordion__title:hover { background-color: var(--mv-grey-bg, #e6e6e6); }
.mvii-public .pub-accordion__title::after {
  position: absolute; right: 20px; top: 17px; content: '';
  width: 49px; height: 49px; display: block;
  transition: transform .3s ease-out;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 49 49' fill='none' stroke='%23123253' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='14 20 24.5 31 35 20'/%3E%3C/svg%3E") center center no-repeat;
}
.mvii-public .pub-accordion__item.open .pub-accordion__title::after { transform: rotate(180deg); }
.mvii-public .pub-accordion__content { padding: 0; overflow: hidden; position: absolute; left: -1000000px; }
.mvii-public .pub-accordion__item.open .pub-accordion__content { padding: 40px 99px 40px 17px; position: static; }

/* ══════════════════════════════════════════════════════════════════════════
   .pub-form — .m-form
   A two-column grid at >=900px with a 1.25rem/1.875rem gutter. Their inputs
   are square: 1px warm-grey border, an inset shadow, 2.5rem tall, NO radius.
   Ours had 10px radius and a focus ring — a different language entirely.
   The submit centres itself (margin: 0 auto), which is why their forms read
   symmetrical.
   ══════════════════════════════════════════════════════════════════════════ */
.mvii-public .pub-form { display: grid; grid-template-columns: minmax(0, 1fr); gap: .9375rem 1.875rem; }
@media (min-width: 900px) { .mvii-public .pub-form { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 1.25rem 1.875rem; } }
.mvii-public .pub-form__field { display: flex; flex-wrap: wrap; flex-direction: column; }
@media (min-width: 900px) { .mvii-public .pub-form__field { gap: .3125rem; } }
/* SESSION-20 AUDIT: --span-1 was used on contact.html and feedback.html but
   had no rule anywhere. washtec's is `.m-form__field--span-1{grid-column:span 1}`
   unconditionally (their only override is scoped to the newsletter overlay). */
.mvii-public .pub-form__field--span-1 { grid-column: span 1; }
.mvii-public .pub-form__field--span-2 { grid-column: span 1; }
@media (min-width: 900px) { .mvii-public .pub-form__field--span-2 { grid-column: span 2; } }
.mvii-public .pub-form__field--checkbox { flex-direction: row; flex-wrap: nowrap; align-items: center; gap: .9375rem; }
.mvii-public .pub-form__field--submit { grid-column: span 1; }
@media (min-width: 900px) { .mvii-public .pub-form__field--submit { grid-column: span 2; } }
.mvii-public .pub-form__label { font-size: 1.125rem; line-height: 1.33; color: var(--mv-blue-dark); cursor: pointer; }
.mvii-public .pub-form__required { font-size: .875rem; line-height: 1.8; color: var(--mv-black); }
.mvii-public .pub-form__input,
.mvii-public .pub-form__textarea,
.mvii-public .pub-form__select {
  width: 100%; padding: 0 .5rem;
  border: .0625rem solid #8e8e8e66; border-radius: 0;
  box-shadow: inset 0 .125rem .375rem 0 rgb(0 0 0 / .2);
  font: inherit; font-family: var(--mv-font); color: var(--mv-black); background-color: var(--mv-white);
}
.mvii-public .pub-form__input,
.mvii-public .pub-form__select { height: 2.5rem; }
.mvii-public .pub-form__textarea { resize: none; padding: .5rem; }
.mvii-public .pub-form__input:focus,
.mvii-public .pub-form__textarea:focus,
.mvii-public .pub-form__select:focus { outline: 2px solid var(--mv-nice-blue); outline-offset: 1px; }
.mvii-public .pub-form__checkbox {
  flex: 0 0 auto; appearance: none; display: flex; justify-content: center; align-items: center;
  width: 2.5rem; height: 2.5rem; border: .0625rem solid #8e8e8e66;
  background-color: var(--mv-grey-bg, #e6e6e6); box-shadow: inset 0 .1875rem .1875rem 0 rgb(0 0 0 / .3);
  overflow: hidden; cursor: pointer;
}
.mvii-public .pub-form__checkbox:checked {
  background-image: linear-gradient(var(--mv-nice-blue), var(--mv-nice-blue));
  background-position: center center; background-repeat: no-repeat; background-size: 1.625rem 1.625rem;
}
.mvii-public .pub-form__submit { margin: 0 auto; cursor: pointer; }

/* ── Headings inside an accordion panel ───────────────────────────────────
   A panel is already a subsection, so a heading inside it must not render at
   the section scale — an <h2> at 4.875rem inside a 22px accordion title reads
   as a mistake. These step the whole run down to the subline sizes. */
.mvii-public .pub-accordion__content :where(h1, h2, h3) { font-size: 1.5625rem; font-weight: 700; line-height: 1.28; }
@media (min-width: 1200px) { .mvii-public .pub-accordion__content :where(h1, h2, h3) { font-size: 2rem; } }
.mvii-public .pub-accordion__content :where(h4, h5, h6) { font-size: 1.25rem; font-weight: 700; line-height: 1.28; }
@media (min-width: 1200px) { .mvii-public .pub-accordion__content :where(h4, h5, h6) { font-size: 1.5rem; } }

/* ══════════════════════════════════════════════════════════════════════════
   PART TWO — added after Daniel supplied outerHTML captures of 25 washtec.com
   pages (session 19). Indexing those revealed a page skeleton every interior
   page shares, and a handful of blocks and wrapper conventions the first pass
   could not see from the homepage alone:

     <hr class="reset-gaps">     a real element BETWEEN every section
     m-intro--has-media          intro band followed by a full-bleed image
     m-headline / m-subline      wrappers that carry the heading + subheading
     text-media-bodytext         wrapper around the body copy
     text-media-ctas             wrapper around the buttons, centred, 20px gap
     m-button--section           button that takes its colours from the band
     <h2><div class="h3">…       element stays h2, class sets the SIZE
     m-section--gradient-2/3     NOT gradients — flat grey (#e6e6e6) bands
     m-slider-block              text beside a card-over-image carousel
     m-testimonials-block        a quote in a grey band

   That last size trick matters: it is how they keep heading semantics while
   stepping the scale down inside a block, and it is why my headings kept
   coming out a size too large in the first pass.
   ══════════════════════════════════════════════════════════════════════════ */

/* The separator between sections. Invisible, zero-height — it exists so the
   section margins collapse predictably. Copied rather than dropped because
   removing it changes the vertical rhythm everywhere. */
.mvii-public .reset-gaps { padding: 0; margin: 0; opacity: 0; border: 0; }

/* ── Section variants ─────────────────────────────────────────────────────
   Their naming is misleading and worth stating plainly: --gradient-2 and
   --gradient-3 are NOT gradients. Both are flat grey (--color-grey-bg,
   #e6e6e6) with black text. gradient-2 is the band their testimonials sit in.
   Only --gradient-1 carries the corporate gradient. */
.mvii-public .pub-section.gradient-2,
.mvii-public .pub-section.gradient-3,
.mvii-public .pub-section.grey-dark-blue { background-color: var(--mv-grey-bg); color: var(--mv-black); }
.mvii-public .pub-section.all-white { background-color: var(--mv-white); color: var(--mv-black); }

/* .m-button--section: takes its colours from the band it is in, which is why
   their pages can drop the same button into a white, grey, gradient or dark
   section without a per-page override. */
.mvii-public .pub-btn-section { border-color: var(--mv-blue-dark); color: var(--mv-blue-dark); background-color: transparent; }
.mvii-public .pub-btn-section:hover { border-color: var(--mv-white); background-color: var(--mv-blue-dark); color: var(--mv-white); }
.mvii-public .pub-section.gradient-1 .pub-btn-section,
.mvii-public .pub-section.gradient-2 .pub-btn-section { border-color: var(--mv-blue-dark); color: var(--mv-blue-dark); }
.mvii-public .pub-section.blue-dark .pub-btn-section { border-color: var(--mv-white); color: var(--mv-white); }
.mvii-public .pub-section.blue-dark .pub-btn-section:hover { border-color: var(--mv-white); background-color: var(--mv-white); color: var(--mv-blue-dark); }

/* ── Content wrappers ─────────────────────────────────────────────────────
   These carry no visual weight of their own on washtec.com either — they are
   the hooks the section modifiers reach through to colour headings, sublines
   and body copy. Ported so our markup can be shaped exactly like theirs. */
.mvii-public .pub-headline { display: block; }
.mvii-public .pub-subline { display: block; margin-top: .625rem; }
.mvii-public .pub-bodytext { display: block; }
.mvii-public .pub-ctas { display: flex; justify-content: center; gap: 20px; flex-wrap: wrap; }
.mvii-public .pub-ctas a { margin: 0; }
/* Blocks that align their text left align their buttons with it. */
.mvii-public .text-left .pub-ctas,
.mvii-public .pub-text-image__content-wrapper .pub-ctas,
.mvii-public .pub-offset__text-wrapper .pub-ctas { justify-content: flex-start; }

/* ── Intro with media ─────────────────────────────────────────────────────
   .m-intro--has-media: the band is followed immediately by a full-bleed
   image, and the pair gets 60px of clearance beneath. This is how every
   overview page on their site opens. */
.mvii-public .pub-intro--has-media { margin-bottom: 60px; }
.mvii-public .pub-intro__image--no-height-limit { max-height: inherit; }
/* Their rule is `width:100%; height:auto; max-height:45rem; object-fit:cover`,
   so the band's depth comes entirely from the SOURCE image's shape: their
   overview pages ship a 1080x720, their contact page a 1080x241 letterbox
   strip. Feeding a 16:9 frame into it gives a band a full screen deep, which
   is what a stand-in photo did to the contact page. This modifier pins the
   letterbox ratio so a placeholder cannot dominate the page; supply a real
   1080x241 crop and it can come off. */
.mvii-public .pub-intro__image--band { aspect-ratio: 1080 / 241; height: auto; max-height: 22rem; object-fit: cover; }

/* ── Numbers: the icon ────────────────────────────────────────────────────
   Ported with the block in part one; only the icon sizing was missing. */
.mvii-public .pub-numbers__image { width: 6.5625rem; height: 6.5625rem; margin: 0; color: var(--mv-white); }  /* ours are inline SVG stroke icons in the palette, where theirs are raster illustrations */
@media (min-width: 900px) { .mvii-public .pub-numbers__image { width: 10.625rem; height: 10.625rem; } }

/* ══════════════════════════════════════════════════════════════════════════
   .pub-slider — .m-slider-block + .m-content-block-slider

   Text block beside a carousel whose slides are an image with a white card
   pulled up over its lower edge. Their carousel is Shoelace's <sl-carousel>
   custom element, styled through ::part(). We cannot ship that — it is an
   external script and a heavy dependency for one component — so the same
   visual is rebuilt here on CSS scroll-snap with the identical measurements:

     slider wrapper   max-width 42.6875rem, full-bleed below 1200px
     content wrapper  flex 0 1 34.125rem beside it at >=1200px
     card             max-width 27.9375rem, margin-top -6.875rem,
                      padding 1.875rem 1.25rem 2.5rem, radius 10px,
                      shadow 0 2px 20px rgb(0 0 0 / .25)
     heading          1.125rem / 700 / centred
     text             .875rem / 1.5
     pagination dot   .9375rem, blue-dark when active

   Scroll-snap also means it degrades to a plain swipeable row with no JS,
   which the web-component version does not.
   ══════════════════════════════════════════════════════════════════════════ */
.mvii-public .pub-slider {
  display: flex; flex-direction: column; justify-content: space-between;
  align-items: center; gap: 2.5rem;
}
@media (min-width: 1200px) {
  .mvii-public .pub-slider { flex-direction: row; gap: 1.875rem; }
  .mvii-public .pub-slider--left { flex-direction: row-reverse; }
  .mvii-public .pub-slider__content-wrapper { flex: 0 1 34.125rem; }
  .mvii-public .pub-slider__wrapper { flex: 0 1 42.6875rem; width: 100%; margin: 0; }
}
.mvii-public .pub-slider__wrapper {
  display: flex; flex-direction: column; align-items: center;
  max-width: 42.6875rem;
  width: calc(100% + var(--mv-container-pad) * 2);
  margin-right: calc(-1 * var(--mv-container-pad));
  margin-left: calc(-1 * var(--mv-container-pad));
  min-width: 0;
}
.mvii-public .pub-slider__track {
  display: flex; width: 100%;
  overflow-x: auto; scroll-snap-type: x mandatory;
  scrollbar-width: none; -ms-overflow-style: none;
  /* Positioned so a slide's offsetParent is the track. The script measures
     with getBoundingClientRect either way, but leaving the track static is
     what made offsetLeft resolve to <body> in the first place, and nothing
     else here depends on it being static. */
  position: relative;
}
.mvii-public .pub-slider__track::-webkit-scrollbar { display: none; }
.mvii-public .pub-slide {
  flex: 0 0 100%; scroll-snap-align: center;
  display: flex; flex-direction: column; align-items: center;
  margin-bottom: 24px;
}
.mvii-public .pub-slide__image { display: block; height: auto; width: 100%; max-width: 42.6875rem; aspect-ratio: 1366 / 912; object-fit: cover; }  /* their slides are 1366x912; the stand-in is 16:9, so the box holds the shape */
.mvii-public .pub-slide__card {
  max-width: 27.9375rem; width: calc(100% - var(--mv-container-pad) * 2);
  padding: 1.875rem 1.25rem 2.5rem;
  background-color: var(--mv-white); color: var(--mv-black);
  margin-top: -6.875rem; border-radius: 10px;
  box-shadow: 0 2px 20px 0 rgb(0 0 0 / .25);
  position: relative; z-index: 1;
}
.mvii-public .pub-slide__card--no-image { margin-top: 0; }
.mvii-public .pub-slide__heading {
  margin-bottom: 1.0625rem; color: var(--mv-blue-dark);
  font-size: 1.125rem; font-weight: 700; line-height: 1.33; text-align: center;
  background-image: none; -webkit-text-fill-color: var(--mv-blue-dark); width: auto;
}
.mvii-public .pub-slide__text { margin-bottom: 1.5rem; font-size: .875rem; line-height: 1.5; }
.mvii-public .pub-slide__button { margin: 0 auto; }
.mvii-public .pub-slider__nav { display: flex; align-items: center; gap: 1.25rem; margin-top: 1.25rem; }
.mvii-public .pub-slider__dots { display: flex; gap: .625rem; }
.mvii-public .pub-slider__dot {
  width: .9375rem; height: .9375rem; border-radius: 50%; border: 0; padding: 0; cursor: pointer;
  background-color: var(--mv-grey-bg); transition: background-color var(--mv-transition);
}
.mvii-public .pub-slider__dot[aria-current="true"] { background-color: var(--mv-blue-dark); }
.mvii-public .pub-slider__arrow {
  width: 35px; height: 18px; border: 0; padding: 0; cursor: pointer; background: none;
  color: var(--mv-blue-dark); display: flex; align-items: center; justify-content: center;
}
.mvii-public .pub-slider__arrow svg { width: 35px; height: 18px; stroke: currentColor; fill: none; stroke-width: 2; }
.mvii-public .pub-section.gradient-1 .pub-slider__arrow,
.mvii-public .pub-section.blue-dark .pub-slider__arrow { color: var(--mv-white); }
.mvii-public .pub-section.gradient-1 .pub-slider__dot[aria-current="true"],
.mvii-public .pub-section.blue-dark .pub-slider__dot[aria-current="true"] { background-color: var(--mv-white); }

/* ── .pub-testimonials — .m-testimonials-block ────────────────────────────
   Their plain (non-video) variant is simply a quote laid out in a band; the
   band is --gradient-2, which is flat grey. The elaborate version with the
   video, the success-story seal and the rotated gradient tab is a separate
   --video modifier we have no content for. */
.mvii-public .pub-testimonials { display: flex; flex-direction: column; gap: 1.875rem; }
@media (min-width: 900px) { .mvii-public .pub-testimonials { display: grid; } }

/* The IP notice's short form (ip-notice.html, 10 Sep): the line a one-page
   document prints in its footer, shown as it prints - small, grey, one block. */
.mvii-public .pub-short-form { font-size: .8125rem; line-height: 1.5; color: var(--mv-grey-dark); background: var(--mv-grey-light); border-left: 3px solid var(--mv-blue-dark); padding: .75rem 1rem; margin: 0 0 1.5rem; }
