/* mearone.com custom CSS. Built by tools/build.sh from _base.css + modules/.
   Do not hand-edit this file, edit the sources and rebuild. */

/* ==========================================================================
   01 - TOKENS
   See DESIGN-SPEC.md sections 1 to 5. Declared globally; applied only to surfaces we
   rebuild. Do NOT globally repaint the site from #000/#fff off the back of
   these. That is a separate, deliberate decision.
   ========================================================================== */

:root {
  /* surfaces */
  --mo-paper:      oklch(0.988 0.002 80);
  --mo-paper-sunk: oklch(0.964 0.003 80);

  /* ink */
  --mo-ink:        oklch(0.19  0.006 80);
  --mo-ink-2:      oklch(0.42  0.006 80);
  --mo-ink-3:      oklch(0.60  0.005 80);

  /* structure */
  --mo-rule:       oklch(0.88  0.003 80);
  --mo-rule-firm:  oklch(0.72  0.004 80);

  /* inverted band */
  --mo-void:       oklch(0.16  0.008 250);
  --mo-void-ink:   oklch(0.96  0.003 250);
  --mo-void-ink-2: oklch(0.74  0.006 250);
  --mo-void-rule:  oklch(0.34  0.010 250);

  /* single accent, under 10% of surface */
  --mo-accent:     oklch(0.62  0.150 235);
  --mo-accent-dim: oklch(0.62  0.150 235 / 0.14);

  /* type
     IMPORTANT: Salient sets `html { font-size: 20px }`, not the 16px browser
     default. Every rem below is therefore computed against a 20px root so the
     RENDERED pixel size matches the design spec's intent. Verified live
     2026-08-10. If Salient's root ever changes, this block is the only place
     that needs recalculating. */
  --mo-font-display: "space-age", "Roboto", sans-serif;
  --mo-font-body:    "Abel", "Helvetica Neue", Arial, sans-serif;
  --mo-font-sub:     "Roboto", "Helvetica Neue", Arial, sans-serif;

  --mo-display:  clamp(1.8rem, 7vw, 3.2rem);   /* 36px to 64px */
  --mo-h2:       clamp(1.2rem, 3.5vw, 1.8rem); /* 24px to 36px */
  --mo-quote-lg: clamp(1.1rem, 2.6vw, 1.5rem); /* 22px to 30px */
  --mo-measure:  28rem;   /* 560px: one shared text measure so every block on the page shares a left edge */
  --mo-body:     0.95rem;                      /* 19px */
  --mo-label:    0.6rem;                       /* 12px */
  --mo-meta:     0.65rem;                      /* 13px */

  --mo-lh-display: 1.05;
  --mo-lh-heading: 1.2;
  --mo-lh-quote:   1.4;
  --mo-lh-body:    1.65;

  --mo-track-display: 0.06em;
  --mo-track-label:   0.18em;

  /* spacing, 4px base, against the same 20px root */
  --mo-1: 0.2rem;   --mo-2: 0.4rem;  --mo-3: 0.6rem;  --mo-4: 0.8rem;   /*  4  8 12 16 */
  --mo-6: 1.2rem;   --mo-8: 1.6rem;  --mo-12: 2.4rem; --mo-16: 3.2rem;  /* 24 32 48 64 */
  --mo-24: 4.8rem;  --mo-32: 6.4rem; --mo-40: 8rem;                     /* 96 128 160 */

  /* motion */
  --mo-ease-out:  cubic-bezier(0.22, 1, 0.36, 1);
  --mo-ease-soft: cubic-bezier(0.25, 1, 0.5, 1);
  --mo-dur-micro: 150ms;
  --mo-dur-enter: 400ms;
  --mo-dur-exit:  260ms;
}

/* Focus is never removed. Applies everywhere, including Salient's own controls. */
a:focus-visible,
button:focus-visible,
input:focus-visible,
textarea:focus-visible,
select:focus-visible,
[tabindex]:focus-visible {
  outline: 2px solid var(--mo-accent);
  outline-offset: 2px;
}


/* ==========================================================================
   00 - MIGRATED FROM "ADDITIONAL CSS"
   Moved verbatim out of Appearance > Customize > Additional CSS on
   2026-08-10, minus the rules that were breaking the dropdown menu.

   DROPPED, and why:
     .sf-menu ul { margin-top: -15px }
        pulled the dropdown panel up underneath the header bar.
     .sf-menu > li ul { padding: 0 20px; background: none }
        `background:none` deleted Salient's white dropdown panel, and the
        20px side padding squeezed a 240px panel to 200px usable, which
        forced the longer gallery names to wrap and collide.
     ...#header-outer .sf-menu li ul (from the grouped rule below)
        a third source of `background-color: transparent` on the submenu.

   These three look like a "transparent header" snippet pasted wholesale
   from a support forum, with the submenu as collateral damage.
   Replacements live in module 02.
   ========================================================================== */

/* Mailchimp List Subscribe Form fields, built for a dark band.
   Superseded by module 05, kept here until that ships. */
#mce-FNAME,
#mce-EMAIL {
  border-bottom: 1px solid #fff;
}

/* Search overlay. Intentional, kept.
   NOTE: the submenu selectors that were grouped into this rule upstream
   have been removed. That grouping is what made the dropdown see-through. */
#search-outer .ui-widget-content,
#header-outer nav > ul > .megamenu > .sub-menu,
body #header-outer nav > ul > .megamenu > .sub-menu > li > a,
#header-outer .widget_shopping_cart .cart_list a,
#header-secondary-outer ul ul li a,
#header-outer .widget_shopping_cart .cart_list li,
.woocommerce .cart-notification,
#header-outer .widget_shopping_cart_content {
  background-color: transparent;
}

/* Fullscreen zoom portfolio slider. Intentional, kept. */
.nectar_fullscreen_zoom_recent_projects .project-slide .project-info p {
  font-size: 20px;
}

.nectar_fullscreen_zoom_recent_projects .project-slide .project-info .normal-container > a {
  border: 1px solid #fff;
  padding: 5px 20px;
}

/* CF7 submit. Superseded by module 04, kept until that ships. */
.wpcf7-form-control.wpcf7-submit.has-spinner {
  color: #000;
  background-color: #fff;
}


/* ==========================================================================
   02 - NAVIGATION
   Desktop dropdown panel (Salient "sf-menu"). See DESIGN-SPEC.md.
   Notes on the three removed "Additional CSS" rules that used to make this
   panel see-through live at the top of style.css.

   SCOPE NOTE (orchestrator, after review of the authored draft):
   the off-canvas mobile menu is deliberately almost untouched here. Its
   transparency was fixed at source by switching Salient's Overlay Opacity
   option from `dark` to `solid`, which is a cleaner fix than a CSS override
   and survives without any rule in this file. Verified in-browser: the panel
   is fully opaque, links render in Space Age, the Gallery submenu slides in
   correctly with a Back link, and touch targets are already generous. There
   is nothing left to fix there, so this module does not restyle it. The one
   exception is a focus ring, which is a genuine accessibility gap.
   ========================================================================== */


/* --------------------------------------------------------------------------
   Square corners on the dropdown
   Salient rounds the dropdown panel by default. The client asked for square
   corners here specifically, and it is the right call: the whole site is
   built from hard-edged full-bleed rectangles, so a rounded panel is the one
   soft shape in the entire interface.

   Deliberately NOT applied to `#slide-out-widget-area *`. That would also
   square the circular social icons in the mobile menu, which are meant to be
   round and are not what was asked for.

   SPECIFICITY: Salient sets the radius from an inline dynamic stylesheet with
     body:not([data-header-format="left-header"]) #header-outer .sf-menu li ul
   which scores (1,2,3) and loads after this file. A plain
   `#header-outer .sf-menu > li ul` is only (1,1,2) and silently loses. The
   leading `body` plus `.sub-menu` here takes this to (1,2,4) so it wins on
   specificity alone, with no !important needed.
   -------------------------------------------------------------------------- */
body #header-outer .sf-menu > li ul.sub-menu,
body #header-outer .sf-menu > li ul.sub-menu li,
body #header-outer .sf-menu > li ul.sub-menu li a {
  border-radius: 0;
}


/* --------------------------------------------------------------------------
   Off-canvas: focus ring only
   Salient's mobile nav has no visible keyboard focus state. Everything else
   about this panel is already correct after the source-level opacity fix.
   -------------------------------------------------------------------------- */
#slide-out-widget-area li.menu-item > a:focus-visible {
  outline: 2px solid var(--mo-accent);
  outline-offset: 2px;
}


/* ==========================================================================
   DESKTOP DROPDOWN
   Gated at 768px as a safe floor. Salient decides its own dropdown vs
   off-canvas switchover; starting the fixes at the tablet tier guarantees
   they are already active whenever the dropdown can appear.
   ========================================================================== */
@media (min-width: 768px) {

  /* Panel.
     Measured live at 240px wide. At 12px, "METAPHYSICAL SURREALISM" needs
     roughly 250px on one line, so four of the six items were wrapping, and
     with the old fixed 14px line-height the wrapped lines nearly touched.
     300px lets the long labels sit on one line; white-space stays normal on
     the items below so anything that still does not fit wraps rather than
     overflowing the panel edge.
     Salient's soft elevation shadow is left alone. The ban list targets
     rounded corners and decorative blur, not elevation. */
  body #header-outer .sf-menu > li ul.sub-menu {
    width: 300px;
    background-color: var(--mo-paper);
  }

  /* Items.
     `height: auto` on the li plus a ratio line-height on the link replaces
     the fixed 40px row, so a label that does wrap grows its own row instead
     of colliding with the row beneath it. That was the actual collision bug.

     Rows are deliberately contiguous (no margin between them): this is a
     mouse-driven dropdown, and gaps would make the hover tint read as
     detached floating blocks against the panel. The 44px min-height carries
     the touch-target requirement on its own. */
  body #header-outer .sf-menu li ul li {
    height: auto;
  }

  /* SPECIFICITY: two Salient rules set line-height and colour on these links,
       main-styles  #header-outer .sf-menu li ul li.menu-item a   (1,2,4)
       dynamic-css  #top .sf-menu li ul li.menu-item a            (1,2,4)
     Matching their `li.menu-item` and adding a leading `body` takes this to
     (1,2,5), which wins outright. Without it, `min-height` and `width` landed
     (nothing else sets those) while `line-height`, `color` and `padding`
     silently lost, which is a confusing half-applied state to debug.

     display: block is restated defensively. min-height does nothing on an
     inline element and this rule should not depend on Salient setting it. */
  body #header-outer .sf-menu li ul li.menu-item > a {
    display: block;
    font-size: var(--mo-label);
    line-height: 1.35;
    min-height: 44px;
    box-sizing: border-box;
    padding: var(--mo-3) var(--mo-4);
    white-space: normal;

    /* COLOUR IS DELIBERATELY NOT SET HERE.
       Salient ships `#top .sf-menu li ul li.menu-item a { color:#000 !important }`
       from its Customizer-driven dynamic stylesheet. Matching that with our own
       !important at higher specificity still did not win in practice, and the
       difference at stake is pure black versus a near-black that is
       imperceptible at 12px. Escalating the specificity war for an invisible
       change is not worth the maintenance cost, so Salient keeps this one.
       The spec's "no pure #000" rule is about deliberate design choices, not
       about fighting a theme default nobody can see. */
  }

  body #header-outer .sf-menu li ul li.menu-item > a:hover,
  body #header-outer .sf-menu li ul li.menu-item > a:active {
    background-color: var(--mo-accent-dim); /* tint only: no size, position or font change, so neighbours never shift */
  }

  /* Restated inside the dropdown scope because Salient's nav CSS resets
     outline on .sf-menu links, which can beat the sitewide token rule
     depending on stylesheet load order. */
  body #header-outer .sf-menu li ul li.menu-item > a:focus-visible {
    outline: 2px solid var(--mo-accent);
    outline-offset: 2px;
  }

  /* Keyboard reveal fallback. A no-op if Salient's show/hide is
     display-based, a real fix if it is opacity/visibility-based. Additive
     only, so it cannot make a working toggle worse. */
  body #header-outer .sf-menu > li:focus-within > ul.sub-menu {
    opacity: 1;
    visibility: visible;
  }

  @media (prefers-reduced-motion: no-preference) {
    body #header-outer .sf-menu li ul li.menu-item > a {
      transition: background-color var(--mo-dur-micro) var(--mo-ease-out);
    }
  }
}


/* ==========================================================================
   03 - BIO PAGE (/about)  -  CINEMATIC DIRECTION

   The artwork is the page. Near-black ground throughout, prose reversed out
   of it, full-bleed painting bands, and the opening lines set directly on the
   hero image. Chosen by the client over an editorial-catalogue and an
   archive-record alternative.

   ROW HOOKS: Salient silently drops `el_class` on [vc_row] but keeps it on
   [image_with_animation]. Rows are therefore targeted with :has() against
   classes that survive: .mo-hero-img / .mo-band-img land on the <img>, and
   .mo-hero-copy / .mo-body / .mo-q1 / .mo-q2 are in markup we author inside
   the text blocks.

   SPECIFICITY: Salient ships `.main-content img { height: auto }` at (0,1,1).
   Bare single-class selectors lose silently, which is how the first version
   of this file appeared to do nothing at all. Anything that has to beat a
   Salient default is scoped through the row to clear (0,2,2) or higher.
   ========================================================================== */


/* --------------------------------------------------------------------------
   PAGE GROUND
   The whole content area goes dark on this page only. The footer stays light,
   which reads as a deliberate close rather than an inconsistency.
   -------------------------------------------------------------------------- */
body.page-id-648 .container-wrap,
body.page-id-648 .main-content {
  background-color: var(--mo-void);
}


/* --------------------------------------------------------------------------
   HERO: cropped painting with the opening lines set on it

   The file is 812x1080 portrait. At its natural aspect, full width, it would
   run about 1900px tall on a 1440px screen and bury the whole page. So the
   band takes a viewport-relative height and the image is cropped into it from
   the top, where the composition's focal point sits.

   Height is viewport-relative rather than a fixed aspect ratio because the
   brief was "full width but do not push everything below the fold", which is
   a fact about the VIEWPORT, not about the image's proportions.
   -------------------------------------------------------------------------- */
.wpb_row:has(img.mo-hero-img) {
  position: relative;
  overflow: hidden;
}

.wpb_row:has(img.mo-hero-img) img.mo-hero-img {
  display: block;
  width: 100%;
  max-width: 100%;
  height: clamp(420px, 72vh, 760px);
  object-fit: cover;
  object-position: center top;
}

/* Scrim.
   NOT a ::after on the row. That was tried and silently never painted:
   Salient's .wpb_column is position:relative, and in this structure it wins
   the paint order over the row's pseudo-element, so the gradient rendered
   behind the artwork. Verified by injecting z-index on the pseudo-element and
   seeing no change at all.

   Putting the gradient on the copy block itself is both simpler and reliable,
   because that element already paints above the image. It also scopes the
   darkening to exactly where the text is instead of over the whole band, so
   the painting's focal point stays completely untouched.

   Space Age at label size has very thin strokes, so the eyebrow needs a real
   ground rather than merely a light colour: near-white at 12px was still
   illegible over the bright starfield without this. */
.mo-hero-copy {
  position: absolute;
  z-index: 2;
  left: 0;
  right: 0;
  bottom: 0;
  padding: var(--mo-16) var(--mo-6) var(--mo-12);
  background: linear-gradient(
    to bottom,
    oklch(0.16 0.008 250 / 0) 0%,
    oklch(0.16 0.008 250 / 0.55) 28%,
    oklch(0.16 0.008 250 / 0.86) 62%,
    oklch(0.16 0.008 250 / 0.94) 100%
  );
}

.mo-hero-copy > * {
  max-width: var(--mo-measure);
  margin-inline: auto;
}

@media (min-width: 768px) {
  .mo-hero-copy { padding: var(--mo-12) var(--mo-16) var(--mo-16); }

  .mo-hero-copy > * {
    max-width: var(--mo-measure);
    margin-inline: auto;
  }
}



.mo-eyebrow {
  font-family: var(--mo-font-display);
  font-size: var(--mo-label);
  line-height: 1;
  letter-spacing: var(--mo-track-label);
  text-transform: uppercase;
  color: var(--mo-void-ink);   /* full-strength: --mo-void-ink-2 vanished against the starfield */
  margin: 0 0 var(--mo-4);
}

.mo-lead {
  font-family: var(--mo-font-sub);
  font-weight: 300;
  font-size: var(--mo-quote-lg);
  line-height: var(--mo-lh-quote);
  color: var(--mo-void-ink);
  margin: 0;
  text-wrap: pretty;
}

/* Parallax, progressive enhancement only. Scroll-driven animations need no JS
   and no scroll listener, so there is nothing to clean up and no jank.
   Browsers without support get a static image, which is a fine result.
   Deliberately NOT background-attachment: fixed, which is broken on iOS.
   Scaled slightly so the drift can never expose an edge of the crop. */
@media (prefers-reduced-motion: no-preference) and (min-width: 768px) {
  @supports (animation-timeline: view()) {
    .wpb_row:has(img.mo-hero-img) img.mo-hero-img {
      animation: mo-drift linear both;
      animation-timeline: view();
      animation-range: entry 0% exit 100%;
      will-change: transform;
    }

    @keyframes mo-drift {
      from { transform: scale(1.08) translate3d(0, -2%, 0); }
      to   { transform: scale(1.08) translate3d(0,  2%, 0); }
    }
  }
}


/* --------------------------------------------------------------------------
   BODY COPY, reversed out
   The old page ran about 120 characters per line at 16px. 68ch is the target.
   -------------------------------------------------------------------------- */
.wpb_row:has(.mo-body) {
  padding-block: var(--mo-16);
}

/* Aligns to the SAME left edge as the hero copy above it. Previously the hero
   copy was flush left at the page inset while the body was centred, so the eye
   had nowhere to land at the start of paragraph two and the page lost its
   thread exactly there. Continuity of the left edge is what carries the flow. */
.wpb_row:has(.mo-body) .wpb_text_column {
  max-width: var(--mo-measure);
  margin-inline: auto;
}



.wpb_row:has(.mo-body) p {
  font-family: var(--mo-font-body);
  font-size: var(--mo-body);
  line-height: var(--mo-lh-body);
  color: var(--mo-void-ink-2);
}

.wpb_row:has(.mo-body) p + p {
  margin-top: var(--mo-6);
}

@media (min-width: 768px) {
  .wpb_row:has(.mo-body) { padding-block: var(--mo-24); }
}


/* --------------------------------------------------------------------------
   FULL-BLEED BAND (studio portrait)
   1944x1296 landscape, so this runs edge to edge with no upscaling below
   1944px of viewport.
   -------------------------------------------------------------------------- */
.wpb_row:has(img.mo-band-img) {
  overflow: hidden;
}

.wpb_row:has(img.mo-band-img) img.mo-band-img {
  display: block;
  width: 100%;
  max-width: 100%;
  height: auto;
}


/* --------------------------------------------------------------------------
   PULL QUOTES
   Both sit on the dark ground now, so they cannot be told apart by inversion
   the way they would on a light page. They are separated by SCALE and
   ALIGNMENT instead: the first is display-scale and centred, the second is
   reading-size, narrower, flush left, with a hairline above its attribution.

   NO accent border stripe on either. That is the reflex blockquote and it
   reads as generic.
   -------------------------------------------------------------------------- */
.mo-q1,
.mo-q2 {
  margin: 0;
  padding: 0;
  border: 0;              /* Salient ships a left border on blockquote */
  background: none;
  quotes: none;
}

.mo-q1 cite,
.mo-q2 cite {
  display: block;
  font-family: var(--mo-font-display);
  font-size: var(--mo-label);
  font-style: normal;
  letter-spacing: var(--mo-track-label);
  text-transform: uppercase;
  color: var(--mo-void-ink-2);
}

/* Both quotes now share one treatment. An earlier version set the first at
   display scale and the second at reading size, which read as two unrelated
   elements rather than a pair. They are separated by SPACE and a RULE, not by
   size: same face, same size, same measure, same alignment, with real air and
   a hairline between them. */
.wpb_row:has(.mo-q1) .wpb_text_column,
.wpb_row:has(.mo-q2) .wpb_text_column {
  max-width: var(--mo-measure);
  margin-inline: auto;
}

.wpb_row:has(.mo-q1) { padding-block: var(--mo-16) var(--mo-12); }
.wpb_row:has(.mo-q2) { padding-block: var(--mo-12) var(--mo-24); }

.mo-q1,
.mo-q2 {
  font-family: var(--mo-font-sub);
  font-weight: 300;
  font-size: clamp(1.15rem, 2vw, 1.45rem);
  line-height: 1.45;
  color: var(--mo-void-ink);
  text-wrap: pretty;
}

.mo-q1 cite,
.mo-q2 cite {
  margin-top: var(--mo-6);
}

/* The division between the two, drawn once above the second quote so it reads
   as a separator rather than a border on either one. */
.wpb_row:has(.mo-q2) .wpb_text_column {
  border-top: 1px solid var(--mo-void-rule);
  padding-top: var(--mo-16);
}

@media (min-width: 768px) {
  .wpb_row:has(.mo-q1) { padding-block: var(--mo-24) var(--mo-16); }
  .wpb_row:has(.mo-q2) { padding-block: var(--mo-16) var(--mo-32); }
}


/* Hero lead shares the page measure and centring with everything below it.
   Stated explicitly at row scope because the earlier flush-left rule in the
   768px query kept winning and left this block at the padding edge while the
   body and both quotes centred at 440px. That mismatch was the visible break
   in flow at paragraph two. */
.wpb_row:has(img.mo-hero-img) .mo-hero-copy > * {
  max-width: var(--mo-measure);
  margin-inline: auto;
}


/* ==========================================================================
   04 - CONTACT FORM (/contact)  -  CONTACT FORM 7 ON A LIGHT GROUND

   This targets the CF7 form measured live on /contact: form.wpcf7-form,
   each field a <p> > label > (bare text node, then span.wpcf7-form-control-
   wrap > input/textarea), submit as input[type="submit"].wpcf7-submit, and
   CF7's own .wpcf7-response-output / .wpcf7-not-valid-tip / .wpcf7-spinner
   states, all currently unstyled defaults. reCAPTCHA v2 renders below submit
   as its own ~302x76 widget outside our control.

   The row that made this page dark (a hard-coded black WPBakery row bg) is
   being removed by the orchestrator. This module assumes --mo-paper, not
   --mo-void. If the page is still dark when this lands, that is a sequencing
   bug in the deploy, not a reason to reach for --mo-void tokens here.

   SPECIFICITY: Salient ships a "Form Styling" tab and applies its own rules
   to form fields; bare classes like `.wpcf7-form-control` lose silently the
   same way `.main-content img { height: auto }` beats bare hero-image
   classes on the bio page (see 03-bio.css). Every selector below is scoped
   through `.wpcf7-form` at minimum, and through `.wpcf7-form p` where a
   Salient input rule is being beaten, to clear real specificity rather than
   trusting source order.
   ========================================================================== */


/* --------------------------------------------------------------------------
   FORM WRAPPER
   Salient's default CF7 field is a barely-visible 14px underline input on
   whatever background it's dropped on. This resets the whole column to sit
   on --mo-paper deliberately (the contact row's own background is being
   normalised by the orchestrator, but the form should not depend on that
   timing to look correct).
   -------------------------------------------------------------------------- */
.wpcf7-form {
  max-width: 32rem;
  margin-inline: auto;
}

.wpcf7-form p {
  margin: 0 0 var(--mo-6);
}


/* --------------------------------------------------------------------------
   LABELS
   Structure is label > (bare text) + span.wpcf7-form-control-wrap > input.
   `display: block` on the label stacks the text above the wrap; the text
   node itself has no element to target for spacing, so the gap is built by
   giving the SPAN a top margin instead of trying to margin the bare text.
   -------------------------------------------------------------------------- */
.wpcf7-form p label {
  display: block;
  font-family: var(--mo-font-display);
  font-size: var(--mo-label);
  line-height: 1.3;
  letter-spacing: var(--mo-track-label);
  text-transform: uppercase;
  color: var(--mo-ink-2);
}

.wpcf7-form p label span.wpcf7-form-control-wrap {
  display: block;
  margin-top: var(--mo-2);
}


/* --------------------------------------------------------------------------
   FIELD BOXES
   16px is the floor (iOS zooms the page on focus below that). Salient's own
   `.wpcf7-form-control` rule sets a small underline-only border directly on
   the input, so this has to win on border, padding, height and font-size at
   once rather than patch one property; scoping through `.wpcf7-form p` gets
   there without !important.
   -------------------------------------------------------------------------- */
.wpcf7-form p input[type="text"],
.wpcf7-form p input[type="email"],
.wpcf7-form p textarea {
  display: block;
  width: 100%;
  box-sizing: border-box;
  min-height: 44px;
  padding: var(--mo-3) var(--mo-4);
  font-family: var(--mo-font-body);
  font-size: var(--mo-body);   /* 19px rendered against Salient's 20px root, well clear of the 16px iOS-zoom floor */
  line-height: 1.4;
  color: var(--mo-ink);
  background-color: var(--mo-paper);
  border: 1px solid var(--mo-rule-firm);
  border-radius: 0;         /* square corners, client-mandated, no exceptions */
  transition: border-color var(--mo-dur-micro) var(--mo-ease-out);
}

.wpcf7-form p textarea {
  min-height: 8.8rem;       /* ~4 lines at this line-height, no resize-driven layout jump */
  resize: vertical;
}

.wpcf7-form p input[type="text"]::placeholder,
.wpcf7-form p input[type="email"]::placeholder,
.wpcf7-form p textarea::placeholder {
  color: var(--mo-ink-3);
}

/* Hover: a hint that the field is interactive, before focus commits to it. */
.wpcf7-form p input[type="text"]:hover,
.wpcf7-form p input[type="email"]:hover,
.wpcf7-form p textarea:hover {
  border-color: var(--mo-ink-3);
}

/* Focus: per spec section 6, never removed, never left to the browser
   default. Salient does not set its own focus ring on these inputs, so no
   !important is needed here; this is additive, not a fight. */
.wpcf7-form p input[type="text"]:focus-visible,
.wpcf7-form p input[type="email"]:focus-visible,
.wpcf7-form p textarea:focus-visible {
  outline: 2px solid var(--mo-accent);
  outline-offset: 2px;
  border-color: var(--mo-accent);
}


/* --------------------------------------------------------------------------
   PER-FIELD ERROR TIP
   CF7 injects `.wpcf7-not-valid-tip` as a sibling straight after the input,
   inside the same label/wrap. Unstyled it is small red browser-default text
   with no spacing, easy to miss right under a field the same width.
   -------------------------------------------------------------------------- */
.wpcf7-form p .wpcf7-not-valid-tip {
  display: block;
  margin-top: var(--mo-2);
  font-family: var(--mo-font-body);
  font-size: var(--mo-meta);
  line-height: 1.4;
  color: oklch(0.5 0.18 25);   /* warm red, legible on --mo-paper, not in the OKLCH token list because it is a semantic error colour, not a brand surface */
}

/* Once a field is flagged invalid, give the box itself a visible edge too,
   not just the tip text below it. Salient adds `.wpcf7-not-valid` to the
   input. */
.wpcf7-form p input.wpcf7-not-valid,
.wpcf7-form p textarea.wpcf7-not-valid {
  border-color: oklch(0.5 0.18 25);
}


/* --------------------------------------------------------------------------
   SUBMIT
   Measured live at 87px wide, off-centre from the field column, 15px/22px
   padding on a white fill. Widened to the full field column, square corners,
   ink fill so it reads as the one committed action on the page (the accent
   is reserved for focus/links per spec, under 10% of surface).
   -------------------------------------------------------------------------- */
.wpcf7-form input[type="submit"].wpcf7-submit {
  display: block;
  width: 100%;
  box-sizing: border-box;
  margin-top: var(--mo-4);
  padding: var(--mo-3) var(--mo-6);
  font-family: var(--mo-font-display);
  font-size: var(--mo-label);
  letter-spacing: var(--mo-track-label);
  text-transform: uppercase;
  color: var(--mo-paper);
  background-color: var(--mo-ink);
  border: 1px solid var(--mo-ink);
  border-radius: 0;
  cursor: pointer;
  transition: background-color var(--mo-dur-micro) var(--mo-ease-out),
              color var(--mo-dur-micro) var(--mo-ease-out);
}

.wpcf7-form input[type="submit"].wpcf7-submit:hover {
  color: var(--mo-ink);
  background-color: var(--mo-paper);
}

.wpcf7-form input[type="submit"].wpcf7-submit:active {
  background-color: var(--mo-ink-2);
  border-color: var(--mo-ink-2);
  color: var(--mo-paper);
}

.wpcf7-form input[type="submit"].wpcf7-submit:focus-visible {
  outline: 2px solid var(--mo-accent);
  outline-offset: 2px;
}

.wpcf7-form input[type="submit"].wpcf7-submit:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}


/* --------------------------------------------------------------------------
   SUBMITTING STATE
   CF7 shows `.wpcf7-spinner` (an <img>, animated GIF by default) next to the
   submit button while the request is in flight. The stock GIF is a circular
   throbber, which reads as foreign against a hard-edged site, so it is
   hidden and replaced with a small square that pulses. Square corners
   preserved, transform/opacity only per spec section 5.
   -------------------------------------------------------------------------- */
/* BUGFIX 2026-08-11: this rule previously forced `visibility: visible`, which
   overrode CF7's own default of hidden and left a grey square parked on the
   page at all times, below and to the right of the Submit button. CF7 toggles
   a `.submitting` class on the FORM for the in-flight state; the spinner has to
   stay hidden until then. It also sits inline beside the button now instead of
   centring itself on its own line. */
.wpcf7-form .wpcf7-spinner {
  display: inline-block;
  vertical-align: middle;
  width: var(--mo-3);
  height: var(--mo-3);
  margin: 0 0 0 var(--mo-4);
  visibility: hidden;
  opacity: 1;
  background-color: var(--mo-ink);
  border-radius: 0;
}

.wpcf7-form.submitting .wpcf7-spinner {
  visibility: visible;
}

/* Reduced-motion users still get the square: CF7 toggles its visibility
   itself when the request starts/ends, which alone communicates state
   change without an infinite animation running. */
@media (prefers-reduced-motion: no-preference) {
  .wpcf7-form.submitting .wpcf7-spinner {
    animation: mo-pulse 900ms var(--mo-ease-soft) infinite;
  }
}

@keyframes mo-pulse {
  0%, 100% { transform: scale(1);    opacity: 1; }
  50%      { transform: scale(1.6);  opacity: 0.4; }
}


/* --------------------------------------------------------------------------
   RESPONSE OUTPUT
   CF7 renders one .wpcf7-response-output element and toggles a class on the
   FORM itself: .sent (success), .invalid / .failed (error). Both currently
   fall through to the browser's unstyled default paragraph.
   -------------------------------------------------------------------------- */
.wpcf7-form .wpcf7-response-output {
  display: block;
  margin: var(--mo-6) 0 0;
  padding: var(--mo-4);
  font-family: var(--mo-font-body);
  font-size: var(--mo-meta);
  line-height: 1.5;
  border: 1px solid var(--mo-rule-firm);
  background-color: var(--mo-paper-sunk);
  color: var(--mo-ink-2);
}

.wpcf7-form.sent .wpcf7-response-output {
  border-color: oklch(0.55 0.13 150);   /* success green, same treatment as the error red: semantic state colour, not a surface token */
  color: var(--mo-ink);
}

.wpcf7-form.invalid .wpcf7-response-output,
.wpcf7-form.failed .wpcf7-response-output,
.wpcf7-form.aborted .wpcf7-response-output,
.wpcf7-form.spam .wpcf7-response-output,
.wpcf7-form.unaccepted .wpcf7-response-output {
  border-color: oklch(0.5 0.18 25);
  color: var(--mo-ink);
}


/* --------------------------------------------------------------------------
   RECAPTCHA + SUBMIT: one line

   MEASURED, correcting an authored guess that never matched anything. This
   install uses the third-party "Contact Form 7 Captcha" plugin, not CF7's own
   reCAPTCHA integration, and it emits:

     <p>       <input type="submit"> <span class="wpcf7-spinner"> <br>   </p>
     <center>  <div class="cf7sr-g-recaptcha"> ... </div> ...            </center>

   The previous rules here targeted `.g-recaptcha` and a
   `.wpcf7-form-control-wrap` wrapper. Neither exists on this install: the class
   is `cf7sr-g-recaptcha`, and the wrapper is a literal <center> tag. So the
   whole block was inert, which is why the widget sat centred and detached
   while the Submit button was left-aligned above it.

   The two are siblings with no shared parent, and CSS cannot introduce one, so
   they are set inline-block and share a line. Below 768 they stack: Google's v2
   widget is a fixed 304px and would crowd a narrow column next to a button.

   The widget itself is a Google-controlled iframe and cannot be restyled from
   here, only placed — so no attempt is made to skin it.
   -------------------------------------------------------------------------- */
.wpcf7-form center:has(.cf7sr-g-recaptcha) {
  text-align: left;
  margin: 0;
}

/* The <br> after the submit input would otherwise push the widget onto its own
   line even once both are inline-block. */
.wpcf7-form p:has(input[type="submit"].wpcf7-submit) br {
  display: none;
}

@media (min-width: 768px) {
  /* FLOATS, not inline-block. Two inline-block siblings are separated by the
     whitespace text node between them in the source, which adds an
     unpredictable ~4px and stops the right-hand column landing exactly on the
     form's right edge. Floats have no such gap, so both column edges measure
     true. */
  /* Submit floats RIGHT so the captcha reads first, left to right, even though
     CF7 emits the submit <p> BEFORE the captcha in the source. Reversing with
     floats avoids touching the form template. */
  /* ONE shared top margin on both columns, and the submit input's own
     margin-top zeroed. Without that the two stacked differently: the submit
     inherited 16px on its <p> PLUS 16px on the input itself, while the plugin
     gives its <center> a 50px top margin. Same height is not the same as
     aligned — the boxes have to START on the same line. */
  .wpcf7-form p:has(input[type="submit"].wpcf7-submit) {
    float: right;
    width: calc(100% - 304px - var(--mo-4));
    margin: var(--mo-12) 0 0;
  }

  .wpcf7-form p:has(input[type="submit"].wpcf7-submit) input[type="submit"].wpcf7-submit {
    margin-top: 0;
  }

  /* !important only on the margin: the plugin ships a 50px top margin on this
     <center>, and matching it exactly is what aligns the two boxes. */
  .wpcf7-form center:has(.cf7sr-g-recaptcha) {
    float: left;
    width: 304px;   /* Google's v2 widget is a fixed 304x78 iframe we cannot resize */
    margin: var(--mo-12) 0 0 !important;
  }

  /* Match the widget's height exactly, so the pair reads as one row of two
     equal blocks rather than a button parked next to something taller. 78px is
     measured off the live iframe, not guessed. */
  .wpcf7-form input[type="submit"].wpcf7-submit {
    width: 100%;
    min-width: 0;
    height: 78px;
  }

  /* Contain the floats, and keep everything after them on its own line. */
  .wpcf7-form::after {
    content: "";
    display: table;
    clear: both;
  }

  .wpcf7-form .wpcf7-response-output {
    clear: both;
  }
}


/* SUBMIT LABEL SCALE. The button is now a 78px-tall column rather than a
   compact pill, and 12px label type looked lost inside it. 0.8rem is 16px
   against Salient's 20px root. */
.wpcf7-form input[type="submit"].wpcf7-submit {
  font-size: 0.8rem;
}

/* MOBILE ORDER. Below 768 the two controls stack, and in source order CF7 puts
   the submit <p> BEFORE the captcha, so the desktop "captcha first" reading
   flipped on phones. Floats cannot reorder stacked blocks, so the form becomes
   a flex column here purely to expose `order`. Everything else keeps the
   default order: 0 and therefore its DOM position; only these two are moved.
   Scoped to max-width so it can never interact with the float layout above. */
@media (max-width: 767px) {
  .wpcf7-form {
    display: flex;
    flex-direction: column;
  }

  .wpcf7-form center:has(.cf7sr-g-recaptcha) { order: 1; }
  .wpcf7-form p:has(input[type="submit"].wpcf7-submit) { order: 2; }
  .wpcf7-form .wpcf7-response-output { order: 3; }

  /* Pin the height so the larger label does not grow the button. 16px type
     plus the existing 12px padding would otherwise push this from 44 to 48. */
  .wpcf7-form input[type="submit"].wpcf7-submit {
    height: 44px;
  }
}


/* --------------------------------------------------------------------------
   TABLET AND UP
   -------------------------------------------------------------------------- */
@media (min-width: 768px) {
  .wpcf7-form {
    max-width: 34rem;
  }

  .wpcf7-form p input[type="text"],
  .wpcf7-form p input[type="email"],
  .wpcf7-form p textarea {
    padding: var(--mo-4) var(--mo-4);
  }

  /* SUPERSEDED 2026-08-11. This used to shrink the submit to its content at
     tablet and up. It now shares a two-column row with the reCAPTCHA widget,
     so it fills its column instead — see the RECAPTCHA + SUBMIT section above,
     which sets width/height there. Left as a comment rather than deleted
     because it sits AFTER that section in source order, so re-adding a width
     here would silently win again. */
}


/* ORCHESTRATOR NOTE (2026-08-10): the authoring pass added !important to this
   button's background and colour pre-emptively, guessing that Salient's global
   .button class would override it. That guess was never tested. Speculative
   !important is exactly what the spec tells us not to ship, so it has been
   stripped. If the button renders unstyled once the shortcode is live, add it
   back WITH the specific Salient rule named in a comment.
   ==========================================================================
   05 - NEWSLETTER SIGNUP BAND (homepage, above the footer)

   Client's own words: "the mail chimp sign up box needs to be added above
   the footer on the bottom of the homepage. the plugin there, its just not
   implemented on the front end." Plugin is Mailchimp List Subscribe Form,
   shortcode [mailchimpsf_form], already connected to MASTER LIST.

   MARKUP CONTRACT this file assumes. The orchestrator wraps the whole band
   (not just the shortcode output) in one container:

     <div class="mo-signup">
       <p class="mo-eyebrow">EYEBROW TEXT</p>          <-- reuses the global
                                                             .mo-eyebrow class
                                                             already defined
                                                             in 03-bio.css.
                                                             Do not redeclare
                                                             it here.
       <h2 class="mo-signup-heading">Short heading.</h2>
       [mailchimpsf_form]
     </div>

   If .mo-eyebrow ever moves or 03-bio.css is dropped from the build, that
   class needs to land somewhere shared, or this band loses its label style.

   The plugin's own markup cannot be rendered ahead of time, so every rule
   below is written to survive more than one shape of output. Known variants
   are covered explicitly (see each section). Anywhere the exact wrapping
   element is unknowable, :has() targets the input or label directly instead
   of guessing a class name, the same technique 02-nav.css and 03-bio.css
   already rely on for this build.

   SUPERSEDES: the "#mce-FNAME, #mce-EMAIL { border-bottom: 1px solid #fff }"
   rule left in _base.css section 00 (migrated from Additional CSS). That
   rule used a pure #fff and did nothing about the first-name field, the
   header the plugin prints, states, or messages. Delete it from _base.css
   once this module is confirmed live; keeping both is harmless but redundant.
   ========================================================================== */


/* --------------------------------------------------------------------------
   BAND: full-bleed void ground

   Paint lives on the WPBakery row, not on .mo-signup, for the same reason
   the bio page's bands work this way: a row set to WPBakery's native
   full-width/stretch option already spans the true viewport width with no
   scrollbar-width side effects, whereas a CSS 100vw breakout trick can
   overflow by the scrollbar's own width and reintroduce the horizontal
   scroll the spec bans. .mo-signup also gets the same background-color as a
   fallback paint layer, in case it ever lands somewhere that isn't inside a
   .wpb_row (a raw text widget, for instance): harmless double-paint when a
   row is present, still correct when it is not.

   ORCHESTRATOR MUST VERIFY: the row wrapping .mo-signup is actually set to
   WPBakery full-width/stretch. If it is not, this rule alone will not make
   the band reach the viewport edges, because the row is still constrained
   by Salient's .container. That is a WPBakery row setting, not something
   CSS can fix from inside a child element.
   -------------------------------------------------------------------------- */
.wpb_row:has(.mo-signup) {
  background-color: var(--mo-void);
}

.mo-signup {
  background-color: var(--mo-void); /* fallback paint, see comment above */
  text-align: center; /* deliberate: this band is a single closing CTA, not
                          flowing prose, so it follows the mo-q1 precedent
                          (centred display moment) rather than the body
                          copy's left-aligned norm */

  /* var(--mo-measure) is not declared yet anywhere in this build (checked
     _base.css and the deployed mearone.css, neither has it, despite
     DESIGN-SPEC section 2 and the bio page notes both referencing it). The
     28rem fallback in this var() call is that same value, so this rule is
     already correct today and will keep working unchanged once the token
     is added to _base.css's :root. Flagging this for the orchestrator
     rather than adding the token myself, since 01-tokens/_base.css is not
     this module's file to own. */
  max-width: var(--mo-measure, 28rem);
  margin-inline: auto;

  padding: var(--mo-16) var(--mo-6);
}

@media (min-width: 768px) {
  .mo-signup {
    /* only the vertical figure changes per DESIGN-SPEC's explicit mobile/
       desktop pair for full-bleed band padding; horizontal stays put since
       the measure cap plus centring already produces generous side space
       once the viewport is wider than 560px */
    padding: var(--mo-32) var(--mo-6);
  }
}


/* --------------------------------------------------------------------------
   HEADING
   Roboto 200/300, matching the sub-heading role in DESIGN-SPEC section 2.
   No class for this exists yet elsewhere in the build (mo-q1/mo-q2 are
   quote-specific, wrong semantics and wrong scale for a short CTA line), so
   it is purpose-built here.
   -------------------------------------------------------------------------- */
.mo-signup-heading {
  font-family: var(--mo-font-sub);
  font-weight: 300;
  font-size: var(--mo-h2);
  line-height: var(--mo-lh-heading);
  color: var(--mo-void-ink);
  margin: 0 0 var(--mo-8);
  text-wrap: balance;
}


/* --------------------------------------------------------------------------
   PLUGIN HEADER: hide it
   The plugin prints its own "Sign up for MASTER LIST" line via
   .mc_custom_border_hdr. Our heading replaces it; the plugin's own header
   is redundant copy the client did not write and should never see live.
   -------------------------------------------------------------------------- */
.mo-signup .mc_custom_border_hdr {
  display: none;
}


/* --------------------------------------------------------------------------
   FORM ROW: stacked on mobile, inline at >=768px

   Targets #mc_signup_form and .mc_form_inside together since which one is
   the actual flex parent is not knowable ahead of render; applying the same
   layout to both is harmless if only one of them is real.

   The email field's own wrapper element (div, p, whatever the plugin
   emits) is selected by :has() against the input it contains rather than
   by guessing its class, so it can be told to grow and the submit wrapper
   told not to, without knowing either class name.
   -------------------------------------------------------------------------- */
.mo-signup #mc_signup_form,
.mo-signup .mc_form_inside {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: var(--mo-4); /* stacked fields, comfortably over the 8px tap-target
                        separation floor */
}

/* Reset default browser margins on whatever element the plugin uses to wrap
   each field. Left alone, a bare <p> or <div> with its UA margin breaks the
   flex gap above into uneven, doubled-up spacing. */
.mo-signup #mc_signup_form p,
.mo-signup #mc_signup_form div {
  margin: 0;
}

/* The email field's wrapper grows to fill the row; the submit wrapper does
   not. mc_signup_submit is the one wrapper class the brief actually names,
   so it is targeted directly as well as through :has() for the submit
   input, in case the class is present without number-matching markup. */
.mo-signup #mc_signup_form > *:has(input#mce-EMAIL),
.mo-signup #mc_signup_form > *:has(input[name="mc_mv_EMAIL"]),
.mo-signup .mc_form_inside > *:has(input#mce-EMAIL),
.mo-signup .mc_form_inside > *:has(input[name="mc_mv_EMAIL"]) {
  flex: 1 1 auto;
}

.mo-signup .mc_signup_submit,
.mo-signup #mc_signup_form > *:has(input#mc_signup_submit) {
  flex: 0 0 auto;
}

@media (min-width: 768px) {
  .mo-signup #mc_signup_form,
  .mo-signup .mc_form_inside {
    flex-direction: row;
    align-items: flex-start;
    gap: var(--mo-3);
  }
}


/* --------------------------------------------------------------------------
   FIRST NAME: hidden, not just visually

   Two layers on purpose. The :has() rule hides the field's wrapping element
   so its row of vertical space collapses too, which is what actually keeps
   the band down to "email only" instead of leaving a gap where FNAME used
   to be. The direct rule on the input and label is a fallback for the case
   where the plugin emits no wrapper at all and they are bare siblings.

   display:none rather than visibility:hidden is required here, not just
   preferred: a hidden-but-required field excluded from layout by
   display:none is also excluded from HTML's constraint validation set, so
   the browser will not block submission over it. A visibility:hidden field
   stays in that set and can throw "not focusable" on submit if the plugin
   marks it required. This is the exact failure mode requirement 4 in the
   brief warns about.
   -------------------------------------------------------------------------- */
.mo-signup input#mce-FNAME,
.mo-signup label[for="mce-FNAME"] {
  display: none;
}

.mo-signup :is(div, p, li, span):has(> input#mce-FNAME),
.mo-signup :is(div, p, li, span):has(> label[for="mce-FNAME"]) {
  display: none;
}


/* --------------------------------------------------------------------------
   LABELS: visually hidden, kept for screen readers
   .mc_var_label covers whichever label the plugin actually renders (EMAIL,
   and FNAME if the hide above ever misses it). The placeholder plus the
   heading above already communicate the field's purpose visually, so a
   second visible "Email Address" caption would be redundant and would fight
   the single-line layout at 768px. Clipped off-screen instead of
   display:none because this is a genuinely optional label on a non-required
   field, not the constraint-validation case above.
   -------------------------------------------------------------------------- */
.mo-signup .mc_var_label,
.mo-signup label[for="mc_mv_EMAIL"] {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}


/* --------------------------------------------------------------------------
   EMAIL INPUT
   -------------------------------------------------------------------------- */
.mo-signup input#mce-EMAIL,
.mo-signup input[name="mc_mv_EMAIL"] {
  /* appearance reset: iOS Safari draws text inputs with a rounded corner
     and an inset shadow regardless of border-radius, which would quietly
     break the square-corners requirement on the one platform most likely
     to view this band */
  -webkit-appearance: none;
  appearance: none;

  display: block;
  width: 100%;
  box-sizing: border-box;
  min-height: 44px;

  /* --mo-body is 0.95rem against Salient's 20px root, i.e. 19px rendered,
     picked specifically because it clears the 16px floor below which iOS
     zooms the page on focus (see DESIGN-SPEC section 9 on the 20px root:
     a bare 1rem or a smaller label-scale token would still be legal CSS
     but would risk landing under 16px real pixels depending on inheritance) */
  font-family: var(--mo-font-body);
  font-size: var(--mo-body);
  color: var(--mo-void-ink);

  background-color: transparent;
  border: 1px solid var(--mo-void-rule);
  border-radius: 0;
  padding: var(--mo-3) var(--mo-4);
}

.mo-signup input#mce-EMAIL::placeholder,
.mo-signup input[name="mc_mv_EMAIL"]::placeholder {
  /* reuses --mo-void-ink-2, already the trusted 4.5:1-on-void colour for
     body copy on the bio page, so this placeholder clears the same floor
     without inventing a new value */
  color: var(--mo-void-ink-2);
  /* Firefox renders placeholder text at reduced opacity by default, which
     would pull it back under the contrast floor this rule just set */
  opacity: 1;
}

.mo-signup input#mce-EMAIL:hover,
.mo-signup input[name="mc_mv_EMAIL"]:hover {
  border-color: var(--mo-void-ink-2); /* colour tint only, no size or
                                          position change, per section 6 */
}

.mo-signup input#mce-EMAIL:disabled,
.mo-signup input[name="mc_mv_EMAIL"]:disabled {
  opacity: 0.5;
}

/* Restated in this scope on top of the sitewide rule in _base.css.
   02-nav.css already documents Salient resetting outline on its own form
   and nav elements depending on load order; doing the same restatement
   here costs nothing and removes that risk. */
.mo-signup input#mce-EMAIL:focus-visible,
.mo-signup input[name="mc_mv_EMAIL"]:focus-visible {
  outline: 2px solid var(--mo-accent);
  outline-offset: 2px;
  border-color: var(--mo-accent);
}


/* --------------------------------------------------------------------------
   SUBMIT BUTTON

   Filled with the single accent, which is legal against the "under 10% of
   surface" budget in DESIGN-SPEC section 1: this is one small control in a
   band that is otherwise flat void, and it is the one interactive moment
   the client explicitly wants attention on ("the one thing we are asking
   of you"). Text sits in --mo-void rather than white-on-accent so nothing
   here is a pure #fff, per the ban list.
   -------------------------------------------------------------------------- */
.mo-signup input#mc_signup_submit,
.mo-signup input[type="submit"].button {
  -webkit-appearance: none; /* iOS/Safari draw native submit-button chrome,
                                rounded, with its own gradient, otherwise */
  appearance: none;

  display: inline-block;
  min-height: 44px;
  box-sizing: border-box;
  padding: var(--mo-3) var(--mo-8);
  border: 1px solid var(--mo-accent);
  border-radius: 0;

  font-family: var(--mo-font-display);
  font-size: var(--mo-label);
  letter-spacing: var(--mo-track-label);
  text-transform: uppercase;

  background-color: var(--mo-accent);
  color: var(--mo-void);
  cursor: pointer;

  /* !important on the two paint properties only, not on layout. This
     module cannot render live to confirm whether it is needed, but
     02-nav.css already documents Salient shipping a colour !important on
     one of its own core interactive elements
     (#top .sf-menu li ul li.menu-item a with an important colour), and
     Salient's global .button class is exactly the kind of sitewide
     colour-scheme hook that pattern tends to show up on. Unlike the nav
     case, the colour here is not an invisible difference: an unstyled
     default button would visibly break the one CTA this band exists for,
     so pre-empting the risk is worth it. ORCHESTRATOR: remove these two
     !important flags if the button already renders correctly without them. */
  background-color: var(--mo-accent);
  color: var(--mo-void);
}

.mo-signup input#mc_signup_submit:hover,
.mo-signup input[type="submit"].button:hover {
  background-color: color-mix(in oklch, var(--mo-accent) 88%, var(--mo-void) 12%);
  border-color: color-mix(in oklch, var(--mo-accent) 88%, var(--mo-void) 12%);
}

.mo-signup input#mc_signup_submit:active,
.mo-signup input[type="submit"].button:active {
  /* subtle, immediate, colour only, meets the "<100ms perceived" bar in
     section 6 without a timed transition */
  background-color: color-mix(in oklch, var(--mo-accent) 76%, var(--mo-void) 24%);
}

.mo-signup input#mc_signup_submit:disabled,
.mo-signup input[type="submit"].button:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

.mo-signup input#mc_signup_submit:focus-visible,
.mo-signup input[type="submit"].button:focus-visible {
  outline: 2px solid var(--mo-accent);
  outline-offset: 2px;
}

@media (prefers-reduced-motion: no-preference) {
  .mo-signup input#mc_signup_submit,
  .mo-signup input[type="submit"].button,
  .mo-signup input#mce-EMAIL,
  .mo-signup input[name="mc_mv_EMAIL"] {
    /* transform/opacity are the only properties this spec allows animating,
       but a plain colour tint on hover reads as instant without needing
       either, so it transitions background-color and border-color directly,
       same pattern 02-nav.css uses for its dropdown hover state */
    transition:
      background-color var(--mo-dur-micro) var(--mo-ease-out),
      border-color var(--mo-dur-micro) var(--mo-ease-out);
  }
}


/* --------------------------------------------------------------------------
   MESSAGES: success and error

   No error/success colour exists in DESIGN-SPEC's token set (section 1 is
   surfaces, ink, structure and one accent only), so these two are declared
   locally rather than invented into the shared file this module does not
   own. Lightness is matched to --mo-void-ink-2 (0.74), the value already
   established elsewhere in this build as legible at body scale on
   --mo-void, only the hue changes for semantic meaning. This is a
   reasonable starting point, not a verified contrast pass; see the report
   for what still needs checking live.
   -------------------------------------------------------------------------- */
.mo-signup {
  --mo-signup-success: oklch(0.78 0.12 150);
  --mo-signup-error:   oklch(0.75 0.14 25);
}

.mo-signup #mc_message {
  margin-top: var(--mo-4);
  font-family: var(--mo-font-body);
  font-size: var(--mo-body);
  line-height: var(--mo-lh-body);
}

.mo-signup #mc_message:empty {
  display: none; /* no reserved empty box before the form has been submitted */
}

.mo-signup .mc_success_msg,
.mo-signup #mc_message.mc_success_msg {
  color: var(--mo-signup-success);
}

.mo-signup .mc_error_msg,
.mo-signup #mc_message.mc_error_msg {
  color: var(--mo-signup-error);
}


/* --------------------------------------------------------------------------
   CONTACT PAGE HEAD AND FORM ALIGNMENT

   The WPBakery column sets a centred text-align that the form inherits, so
   labels sat centred above left-aligned fields. Forms read as broken when the
   label does not start where its input starts.

   The h1 and intro are new: the page previously had NO h1 at all, and its
   heading was an <h3> buried inside four nested leftover Squarespace divs
   (sqs-block html-block, block-yui_3_17_2_1_...), which have been removed.
   -------------------------------------------------------------------------- */
body.page-id-647 .wpcf7-form,
body.page-id-647 .wpcf7-form p,
body.page-id-647 .wpcf7-form p label {
  text-align: left;
}

body.page-id-647 .mo-contact-title {
  font-family: var(--mo-font-display);
  font-size: var(--mo-h2);
  line-height: var(--mo-lh-heading);
  letter-spacing: var(--mo-track-display);
  text-transform: uppercase;
  color: var(--mo-ink);
  margin: 0 0 var(--mo-3);
}

body.page-id-647 .mo-contact-intro {
  font-family: var(--mo-font-body);
  font-size: var(--mo-body);
  line-height: var(--mo-lh-body);
  color: var(--mo-ink-2);
  margin: 0 0 var(--mo-12);
}


/* --------------------------------------------------------------------------
   NEWSLETTER: ACTUAL PLUGIN MARKUP  -  ID-FREE

   REWRITTEN 2026-08-11, and the reason matters more than the rules.

   The Mailchimp List Subscribe Form update installed in this session added
   support for more than one form per page. To do that it now SUFFIXES every
   id it emits:

     mc_signup_form    ->  mc_signup_form_cbadb47224_1
     mc_mv_EMAIL       ->  mc_mv_EMAIL_2
     mc_mv_FNAME       ->  mc_mv_FNAME_3
     mc_mv_LNAME       ->  mc_mv_LNAME_4
     mc_signup_submit  ->  mc_signup_submit_cbadb47224_1

   Every rule in the previous version of this block keyed on those ids, so the
   whole fix layer went dead in a single plugin update and the band fell back
   to raw plugin output: three stub inputs, a stray "* = required field" and an
   unstyled button. The suffix is derived from the form instance, so it will
   change again on the next one.

   NOTHING BELOW USES AN ID. Classes and name attributes are stable across
   instances; ids on this plugin are not.

   Also new in that update: the plugin now renders FNAME and LNAME. It did not
   before, which is why an earlier note in this file claimed there was no
   first-name field on this install. There is now, and there are two.

   MARKUP, verified live 2026-08-11:
     form[id^=mc_signup_form] > .mc_form_inside
       div.mc_merge_var  > label.mc_var_label + input.mc_input[name=mc_mv_EMAIL]
       div.mc_merge_var  > label + input[name=mc_mv_FNAME]
       div.mc_merge_var  > label + input[name=mc_mv_LNAME]
       div.mc-indicates-required           "* = required field"
       div[style=display:none]             "Alternative Email:" + input[name=mailchimp_sf_alt_email]
       div.mc_signup_submit > input.mc_signup_submit_button
   -------------------------------------------------------------------------- */

/* Layout container. .mc_form_inside is the real flex parent; the <form> holds
   the volatile id and is matched by prefix only, never by exact id. */
.mo-signup form[id^="mc_signup_form"],
.mo-signup .mc_form_inside {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: var(--mo-4);
}

.mo-signup .mc_form_inside > * {
  margin: 0;
}

/* EMAIL ONLY.
   Name fields, the required-field note and the plugin's honeypot are all
   removed from layout.

   The honeypot is restated here rather than trusted: the plugin ships it as
   style="display: none; !important" and that !important is in an invalid
   position, after the semicolon, so it parses as a dropped declaration. The
   display:none before it does still apply in Chrome, but a honeypot whose
   only defence is a malformed inline style is one parser quirk away from
   printing "Alternative Email:" to real visitors, where it reads as a
   challenge question on a newsletter signup. Not a risk worth carrying. */
.mo-signup .mc_merge_var:has(input[name="mc_mv_FNAME"]),
.mo-signup .mc_merge_var:has(input[name="mc_mv_LNAME"]),
.mo-signup .mc-indicates-required,
.mo-signup :is(div, p):has(> input[name="mailchimp_sf_alt_email"]) {
  display: none !important;
}

.mo-signup .mc_merge_var:has(input[name="mc_mv_EMAIL"]) {
  flex: 1 1 auto;
  min-width: 0;
}

.mo-signup input.mc_input[name="mc_mv_EMAIL"] {
  -webkit-appearance: none;
  appearance: none;
  display: block;
  width: 100%;
  box-sizing: border-box;
  min-height: 44px;
  padding: var(--mo-3) var(--mo-4);
  font-family: var(--mo-font-body);
  font-size: var(--mo-body);   /* 19px against Salient's 20px root, clear of the 16px iOS-zoom floor */
  color: var(--mo-void-ink);
  background-color: transparent;
  border: 1px solid var(--mo-void-rule);
  border-radius: 0;
}

.mo-signup input.mc_input[name="mc_mv_EMAIL"]::placeholder {
  color: var(--mo-void-ink-2);
  opacity: 1;              /* Firefox dims placeholders by default, back under the contrast floor */
}

.mo-signup input.mc_input[name="mc_mv_EMAIL"]:hover {
  border-color: var(--mo-void-ink-2);
}

.mo-signup input.mc_input[name="mc_mv_EMAIL"]:focus-visible {
  outline: 2px solid var(--mo-accent);
  outline-offset: 2px;
  border-color: var(--mo-accent);
}

/* SUBMIT.
   Targeted by .mc_signup_submit_button, NOT by .button. The plugin prints two
   class attributes on this one element:
     class="mc_signup_submit_button" ... class="button"
   and HTML parsing keeps the first and discards the second, so .button never
   matches anything here. That is why the button rendered unstyled. */
.mo-signup .mc_signup_submit {
  flex: 0 0 auto;
}

/* SPECIFICITY: Salient ships body[data-form-submit="regular"] input[type="submit"]
   at (0,2,2) from its dynamic stylesheet. The obvious
   `.mo-signup input.mc_signup_submit_button` is only (0,2,1) and loses, which
   is why this button rendered as a plain black box. Adding the wrapper class
   and the type attribute takes it to (0,4,1) and wins with no !important. */
.mo-signup .mc_signup_submit input.mc_signup_submit_button[type="submit"] {
  -webkit-appearance: none;
  appearance: none;
  display: inline-block;
  width: 100%;
  box-sizing: border-box;
  min-height: 44px;
  padding: var(--mo-3) var(--mo-8);
  font-family: var(--mo-font-display);
  font-size: var(--mo-label);
  letter-spacing: var(--mo-track-label);
  text-transform: uppercase;
  color: var(--mo-void);
  background-color: var(--mo-accent);
  border: 1px solid var(--mo-accent);
  border-radius: 0;
  cursor: pointer;
}

.mo-signup .mc_signup_submit input.mc_signup_submit_button[type="submit"]:hover {
  background-color: color-mix(in oklch, var(--mo-accent) 88%, var(--mo-void) 12%);
  border-color: color-mix(in oklch, var(--mo-accent) 88%, var(--mo-void) 12%);
}

.mo-signup .mc_signup_submit input.mc_signup_submit_button[type="submit"]:focus-visible {
  outline: 2px solid var(--mo-accent);
  outline-offset: 2px;
}

/* Messages. Prefix match for the same reason as the form. */
.mo-signup [id^="mc_message"] {
  margin-top: var(--mo-4);
  font-family: var(--mo-font-body);
  font-size: var(--mo-body);
  line-height: var(--mo-lh-body);
}

.mo-signup [id^="mc_message"]:empty {
  display: none;
}

@media (min-width: 768px) {
  .mo-signup form[id^="mc_signup_form"],
  .mo-signup .mc_form_inside {
    flex-direction: row;
    align-items: flex-start;
    gap: var(--mo-3);
  }

  /* SPECIFICITY: Salient ships body[data-form-submit="regular"] input[type="submit"]
   at (0,2,2) from its dynamic stylesheet. The obvious
   `.mo-signup input.mc_signup_submit_button` is only (0,2,1) and loses, which
   is why this button rendered as a plain black box. Adding the wrapper class
   and the type attribute takes it to (0,4,1) and wins with no !important. */
.mo-signup .mc_signup_submit input.mc_signup_submit_button[type="submit"] {
    width: auto;
    min-width: 11rem;
  }
}


/* Salient runs data-form-style="minimal", which strips text inputs to a single
   bottom rule via body[data-form-style="minimal"] ... input[type="text"], reaching
   (0,3,3). Our (0,3,1) rule above loses to it, so the field rendered as a bare
   floating white underline: on a dark band that reads as a stray line, not a
   form. Putting the body attribute in our own selector takes this to (0,4,2)
   and settles it without !important. */
body[data-form-style="minimal"] .mo-signup input.mc_input[name="mc_mv_EMAIL"] {
  /* !important, deliberately, and this is the one place in the build that earns
     it. Salient sets this field from at least three directions at once:
     style.css `input[type="text"] {border-style:none}`, salient-dynamic-styles
     `body[data-form-style="minimal"] input[type="text"]` and ascend.css
     `.ascend .container-wrap .span_12.light input[type="text"]`. A (0,4,2)
     selector was measured losing to that stack anyway, and the next escalation
     is a longer selector that the next theme update can invalidate just as
     easily. The site-wide alternative is flipping Salient Options > Form
     Styling off "minimal", but that would restyle the contact form too, which
     is already correct. So: one field, four declarations, documented. */
  border: 1px solid var(--mo-void-rule) !important;
  border-radius: 0 !important;
  padding: var(--mo-3) var(--mo-4) !important;
  background-color: transparent !important;
}

body[data-form-style="minimal"] .mo-signup input.mc_input[name="mc_mv_EMAIL"]:hover {
  border-color: var(--mo-void-ink-2) !important;
}

body[data-form-style="minimal"] .mo-signup input.mc_input[name="mc_mv_EMAIL"]:focus,
body[data-form-style="minimal"] .mo-signup input.mc_input[name="mc_mv_EMAIL"]:focus-visible {
  border-color: var(--mo-accent) !important;
  outline: 2px solid var(--mo-accent);
  outline-offset: 2px;
}

/* The accent-filled button was legal under the spec's 10% accent budget but
   wrong for this site: a saturated blue CTA on a black-and-white artist's
   homepage reads as a stray piece of someone else's UI. Paper fill on the void
   band carries the same "one committed action" weight in the site's own
   palette, and matches the 404 button and the contact submit, so the site has
   one button language instead of three. */
.mo-signup .mc_signup_submit input.mc_signup_submit_button[type="submit"] {
  background-color: var(--mo-paper);
  border-color: var(--mo-paper);
  color: var(--mo-ink);
}

.mo-signup .mc_signup_submit input.mc_signup_submit_button[type="submit"]:hover {
  background-color: transparent;
  border-color: var(--mo-paper);
  color: var(--mo-paper);
}


/* The email label is un-hidden and shown above the field.
   The plugin emits placeholder="" so there is no placeholder to fall back on,
   which left a completely unlabelled box sitting next to a Subscribe button.
   A visible label is also what the contact form already does, so this keeps one
   form language across the site rather than two. It has to out-specify the
   visually-hidden .mc_var_label rule earlier in this file, hence the wrapper
   class in the selector. */
.mo-signup .mc_merge_var label.mc_var_label {
  position: static;
  width: auto;
  height: auto;
  margin: 0 0 var(--mo-2);
  padding: 0;
  overflow: visible;
  clip: auto;
  white-space: normal;
  display: block;
  text-align: left;
  font-family: var(--mo-font-display);
  font-size: var(--mo-label);
  line-height: 1.3;
  letter-spacing: var(--mo-track-label);
  text-transform: uppercase;
  color: var(--mo-void-ink-2);
}

.mo-signup .mc_merge_var label.mc_var_label .mc_required {
  color: var(--mo-void-ink-2);
}

@media (min-width: 768px) {
  /* the label adds height above the input only, so the row aligns on its
     baseline edge instead of its top, or the button floats up beside the
     label rather than beside the field */
  .mo-signup form[id^="mc_signup_form"],
  .mo-signup .mc_form_inside {
    align-items: flex-end;
  }
}


/* STACKED, client direction 2026-08-11: the email field sits ABOVE the button
   at every width, rather than sharing a row from 768px up.

   Stated last on purpose. Two earlier rules in this file set
   flex-direction: row inside the same 768px query (the original module's, and
   one added earlier today). All three selectors resolve to the same
   specificity, so source order decides and this one wins. Overriding rather
   than deleting keeps the earlier blocks readable as the history of what the
   markup actually turned out to be. */
@media (min-width: 768px) {
  .mo-signup form[id^="mc_signup_form"],
  .mo-signup .mc_form_inside {
    flex-direction: column;
    align-items: stretch;
    gap: var(--mo-4);
  }

  /* full width so the two controls read as one stacked pair rather than a
     field with an unrelated button parked under it */
  .mo-signup .mc_signup_submit input.mc_signup_submit_button[type="submit"] {
    width: 100%;
    min-width: 0;
  }
}


/* ==========================================================================
   06 - 404 PAGE
   Salient styles the numeral from its inline dynamic stylesheet with
       body #ajax-content-wrap #error-404 h1     -> (2,0,2)   TWO IDs.
   The previous attempt here used
       body.error404 .container.main-content h1  -> (0,3,2)   zero IDs,
   which matches the element but can never win: one ID beats any number of
   classes. Everything below is scoped through
       body.error404 #ajax-content-wrap #error-404   -> (2,1,2)
   which clears it outright, with no !important anywhere.
   Salient's other rule, body #error-404 h1 (1,0,2), is what puts Open Sans on
   this page; it is displaced by the same scoping rather than fought separately.
   CSS ONLY: real exits (Gallery / Bio / Shop) need a 404.php in the child
   theme, and the Theme File Editor cannot create files. See NOTES.md.
   ========================================================================== */

body.error404 #ajax-content-wrap .container-wrap,
body.error404 #ajax-content-wrap #error-404 {
  background-color: var(--mo-void);
}

body.error404 #ajax-content-wrap #error-404 {
  padding-block: var(--mo-24) var(--mo-32);
  padding-inline: var(--mo-6);
  text-align: center;
}

/* The numeral is deliberately the QUIETEST thing here despite being the
   biggest: it carries no information the visitor needs, so it takes the rule
   colour and the sentence below it does the talking. Floor of 3.5rem against
   Salient's 20px root = 70px, so it still reads as display scale at 390px
   without 18vw forcing a horizontal scrollbar. */
body.error404 #ajax-content-wrap #error-404 h1 {
  margin: 0;
  font-family: var(--mo-font-display);
  font-size: clamp(3.5rem, 18vw, 10rem);
  font-weight: 400;
  line-height: 0.9;
  letter-spacing: var(--mo-track-display);
  color: var(--mo-void-rule);
}

body.error404 #ajax-content-wrap #error-404 h2 {
  margin: var(--mo-6) 0 0;
  font-family: var(--mo-font-sub);
  font-weight: 300;
  font-size: var(--mo-quote-lg);
  line-height: var(--mo-lh-quote);
  letter-spacing: 0;
  color: var(--mo-void-ink);
  text-transform: none;
  text-wrap: balance;
}

/* Salient's .nectar-button is a rounded accent pill. Squared and hollowed,
   with the same fill-inverts hover as the contact form submit so the site has
   one button language rather than two. */
body.error404 #ajax-content-wrap #error-404 a.nectar-button {
  display: inline-block;
  box-sizing: border-box;
  min-height: 44px;
  margin-top: var(--mo-12);
  padding: var(--mo-3) var(--mo-8);
  font-family: var(--mo-font-display);
  font-size: var(--mo-label);
  line-height: 1.8;
  letter-spacing: var(--mo-track-label);
  text-transform: uppercase;
  color: var(--mo-void-ink);
  /* Salient ships .nectar-button[data-color-override="false"].regular-button
     { background-color:#000 !important } from its dynamic stylesheet. !important
     beats non-important at ANY specificity, so this is the one place on the
     page where matching it is the only option, not a shortcut. A pure #000
     pill on the tinted near-black ground reads as a stray rectangle, which is
     why it cannot just be left alone. */
  background-color: transparent !important;
  border: 1px solid var(--mo-void-rule);
  border-radius: 0;
  box-shadow: none;
  transition: background-color var(--mo-dur-micro) var(--mo-ease-out),
              border-color     var(--mo-dur-micro) var(--mo-ease-out),
              color            var(--mo-dur-micro) var(--mo-ease-out);
}

body.error404 #ajax-content-wrap #error-404 a.nectar-button span {
  color: inherit;
  font-family: inherit;
  font-size: inherit;
  letter-spacing: inherit;
}

body.error404 #ajax-content-wrap #error-404 a.nectar-button:hover,
body.error404 #ajax-content-wrap #error-404 a.nectar-button:focus-visible {
  color: var(--mo-ink);
  background-color: var(--mo-paper) !important;
  border-color: var(--mo-paper);
}

/* One-word button; the sliding arrow just pushes the label off centre. */
body.error404 #ajax-content-wrap #error-404 a.nectar-button i.icon-button-arrow {
  display: none;
}

@media (min-width: 768px) {
  body.error404 #ajax-content-wrap #error-404 {
    padding-block: var(--mo-32) var(--mo-40);
  }
}


/* ==========================================================================
   07 - FOOTER SEAL

   Client direction 2026-08-11: shrink the Metaphysical Surrealism seal by 25%
   and tighten it up against the social icons.

   The seal is a core/image block inside a footer widget, so the block editor
   writes width and height ATTRIBUTES onto the <img> (its figure carries
   `is-resized`). A CSS width beats an HTML width attribute, so no !important is
   needed, but `height: auto` has to go with it or the height attribute stays
   put and the image squashes.

   The gap under the seal measured 45px and was TWO separate things stacked,
   which is why changing either alone barely moves it:

     15px   figure margin-bottom   (block editor default)
     30px   #copyright padding-top (Salient)

   This is a footer widget, so it applies on every page that renders the footer.
   ========================================================================== */

/* !important on width ONLY, and it is unavoidable rather than lazy: the block
   editor writes style="width:200px" INLINE on this <img> (its figure carries
   `is-resized`). An inline style outranks every selector, so !important is the
   only mechanism CSS has. height stays un-flagged because only the HTML height
   ATTRIBUTE competes with it, and a plain declaration already beats that.
   Cleaner long-term fix, if anyone edits the footer widget: change the image
   block width to 150 there and drop the flag. */
#footer-outer #footer-widgets .widget_media_image img {
  width: 150px !important;   /* was 200px; native is 589x540, so still no upscale */
  height: auto;
}

#footer-outer #footer-widgets .widget_media_image figure {
  margin-bottom: 0;
}

/* Pulls the social row and the copyright line up together, so the seal and the
   icons read as one group rather than two stacked blocks. */
/* !important here is the ROBUST option, not the shortcut. Salient sets this
   from its dynamic stylesheet with
     body #footer-outer[data-cols="1"][data-disable-copyright="false"]
          [data-copyright-line="false"][data-matching-section-color="true"] #copyright
   which scores (2,4,1) against a plain #footer-outer #copyright at (2,0,1).
   Out-specifying it means reproducing all four attribute selectors, which then
   silently stops matching the moment anyone changes a footer option in the
   Salient panel. One flag on one declaration survives that; a 4-attribute
   selector does not. */
#footer-outer #copyright {
  padding-top: var(--mo-4) !important;   /* 16px, down from 30px */
}


/* ==========================================================================
   08 - REVISIONS 2026-08-11 (client review)
   ========================================================================== */

/* --------------------------------------------------------------------------
   BIO HERO: crop to the three faces

   Client supplied a reference crop: the three faces band, third eye centred.
   Measured against the 812x1080 source, that band is source rows 175 to 609 —
   434px tall, aspect 1.871.

   The old rule used height: clamp(420px, 72vh, 760px), which makes the crop a
   function of the VIEWPORT rather than of the painting. At 390x844 that box is
   taller than it is wide relative to the source, so cover scaled to fit the
   HEIGHT and cropped the sides instead — the whole painting showed and the
   faces were a small part of it. A fixed aspect-ratio keeps scaling
   width-driven at every width, which is what makes one object-position value
   correct everywhere: visible source height is then always 812/aspect = 434px.

   object-position 27% puts those 434 rows at 175..609:
     (1080 - 434) * 0.27 = 174.4
   -------------------------------------------------------------------------- */
.wpb_row:has(img.mo-hero-img) img.mo-hero-img {
  height: auto;
  aspect-ratio: 812 / 434;
  max-height: 88vh;
  object-fit: cover;
  object-position: center 34%;   /* client-approved framing, 2026-08-11 */
}

/* Below 768 the band is only ~208px tall at 390 wide, and the hero copy is
   ~263px, so it can no longer be overlaid on the image without spilling past
   it. It moves into normal flow underneath instead, on the solid void ground
   rather than the scrim gradient (which only exists to lift text off artwork).
   Keeping the faces full-width matters more than keeping the overlay: zooming
   in to buy height would crop off the two outer profiles, which is the exact
   thing being asked for. */
@media (max-width: 767px) {
  .mo-hero-copy {
    position: static;
    background: var(--mo-void);
    padding: var(--mo-8) var(--mo-6) var(--mo-12);
  }
}

/* --------------------------------------------------------------------------
   SECOND IMAGE (studio band): breathing room above and below
   It previously butted straight against the copy on both sides.
   -------------------------------------------------------------------------- */
/* Spacing goes on the COLUMN, and the selector needs the `html body` prefix.
   THREE things block the obvious targets here:
     - the ROW carries an inline style="padding-top:0;padding-bottom:0" written
       by WPBakery's row settings, and inline beats any selector;
     - a margin on the IMAGE loses its bottom half to Salient's
         .img-with-aniamtion-wrap .hover-wrap .hover-wrap-inner img.img-with-animation
         { margin-bottom: 0 }
       at (0,4,1), which outranks the (0,3,2) available here. That is why the
       first attempt produced 96px above the image and nothing below it.
   The column has no inline style, but WPBakery ships
         html body .full-width-content.vc_row-fluid .wpb_column { padding: 0 }
       at (0,3,2) in grid-system.css, and this row IS full-width-content, so a
       plain (0,3,1) column rule loses. `html body` takes ours to (0,3,3).
       The two quote rows are not full-width, which is why the identical rule
       worked there and silently did nothing here.
   (The typo in "aniamtion" is Salient's, and selectors have to match it.) */
html body .wpb_row:has(img.mo-band-img) .wpb_column {
  padding-block: var(--mo-16);   /* 64px */
}

@media (min-width: 768px) {
  html body .wpb_row:has(img.mo-band-img) .wpb_column {
    padding-block: var(--mo-24);  /* 96px */
  }
}

/* Tight fade to black, top and bottom. The page ground behind is --mo-void, so
   masking the image edges to transparent reads as the photograph dissolving
   into the page rather than sitting on it as a hard-edged rectangle.
   mask-image rather than a gradient overlay: there is no wrapper here that
   reliably paints ABOVE the image, which is the same paint-order trap already
   documented on the hero scrim. 7% is deliberately tight. */
.wpb_row:has(img.mo-band-img) img.mo-band-img {
  -webkit-mask-image: linear-gradient(to bottom, transparent 0%, #000 7%, #000 93%, transparent 100%);
          mask-image: linear-gradient(to bottom, transparent 0%, #000 7%, #000 93%, transparent 100%);
}

/* THE QUOTE BAND. Both quote rows were sitting flush against the copy above
   and the footer below. Same story as the band image: these rows also carry
   WPBakery's inline padding-top/bottom: 0, so the column is again the one
   target that lands without !important. */
.wpb_row:has(.mo-q1) .wpb_column,
.wpb_row:has(.mo-q2) .wpb_column {
  padding-block: var(--mo-16);   /* 64px */
}

/* Client asked for roughly 50px more black under the CLOSING quote in
   particular, since it is the last thing before the footer. Stated after the
   shared rule so it wins the tie. */
.wpb_row:has(.mo-q2) .wpb_column {
  padding-bottom: calc(var(--mo-16) + 50px);
}

@media (min-width: 768px) {
  .wpb_row:has(.mo-q1) .wpb_column,
  .wpb_row:has(.mo-q2) .wpb_column {
    padding-block: var(--mo-24);  /* 96px */
  }

  .wpb_row:has(.mo-q2) .wpb_column {
    padding-bottom: calc(var(--mo-24) + 50px);
  }
}

/* --------------------------------------------------------------------------
   BIO HERO: pointer parallax

   Client asked for the hero to feel less static. There are now two motions on
   this one element, and they are deliberately kept on SEPARATE CSS properties
   so they compose instead of overwriting each other:

     transform  -> the existing scroll-driven drift (animation-timeline: view())
     translate  -> pointer parallax, set from JS via --mo-px / --mo-py
     scale      -> a small base zoom

   `translate`, `rotate` and `scale` are independent properties that apply
   before `transform`, so all three stack. Writing the pointer offset into
   `transform` instead would have clobbered the scroll animation on every
   mousemove.

   The base zoom exists so the pointer drift can never expose an edge of the
   crop. It costs ~5% of the band, which the 27% object-position still keeps
   the three faces well inside.

   Gated on hover+fine pointer so touch devices get nothing to fight with, and
   on prefers-reduced-motion. Transition on translate only, never layout. */
/* The base zoom lives INSIDE the pointer query, not outside it. A global
   scale: 1.05 stacked on top of the scroll animation's scale(1.08) for a
   combined 1.13, which visibly tightened the crop and cut the central chin.
   Only the pointer drift needs edge slack, so only that context pays for it,
   and 1.02 is already ~15px of slack per side at desktop widths against a 12px
   maximum drift. */
@media (prefers-reduced-motion: no-preference) and (hover: hover) and (pointer: fine) {
  .wpb_row:has(img.mo-hero-img) img.mo-hero-img {
    scale: 1.02;
    translate: calc(var(--mo-px, 0) * -12px) calc(var(--mo-py, 0) * -8px);
    transition: translate 700ms var(--mo-ease-out);
    will-change: translate;
  }
}


/* --------------------------------------------------------------------------
   DROPDOWN HOVER, rebuilt 2026-08-11

   Client: "since we fixed the nav menu we dont really have a hover effect on
   the sub menu items". Correct, and the reason is specific: Salient's dynamic
   stylesheet ships

     #top .sf-menu li ul li.menu-item a:hover                  { background:#fff !important }
     #header-outer #top nav > ul > li:not(.megamenu) ul a:hover { background:#fff !important }

   and the dropdown panel is ALREADY white. So a hover state does fire, it just
   paints white on white. The earlier accent tint here carried no !important
   and lost outright.

   Two IDs are required to win: !important ties are broken by specificity, and
   Salient's winning selector has #header-outer AND #top. Matching both, plus
   the class chain, gets to (2,3,5) against their (2,1,5).

   Full inversion rather than a tint. The site's whole button language is
   invert-on-hover (404 exit, newsletter Subscribe, contact submit), so the nav
   using the same move keeps one interaction vocabulary. It also finally lets
   the link colour move: Salient pins these to #000 !important at (1,2,4), which
   this beats, so white text on ink is reachable where a tint alone was not.
   Tint only, no size or position change, so neighbouring rows never shift. */
/* MEASURED, not guessed: Salient's winning rule is
     #header-outer:not([data-format="left-header"]) #top nav > ul > li:not(.megamenu) ul a:hover
   which computes to (2,3,5) WITH !important. A first attempt here landed on
   exactly (2,3,5) too, and an !important tie is broken by source order —
   salient-dynamic-styles.css loads after mearone.css, so Salient still won and
   the hover stayed invisible. Adding `body` and `nav` takes this to (2,3,6),
   one element clear, with no duplicated-class tricks. */
body #header-outer #top nav .sf-menu li ul li.menu-item > a:hover,
body #header-outer #top nav .sf-menu li ul li.menu-item > a:focus-visible {
  background-color: var(--mo-ink) !important;
  color: var(--mo-paper) !important;
}
