/* Theme base styles */

/* Adobe Fonts: All Round Gothic (Typekit project phm7gfs) */
@import url("https://use.typekit.net/phm7gfs.css");

/* Tools
Any animations, or functions used throughout the project.
Note: _macros.css needs to be imported into each stylesheet where macros are used and not included here
*/

/* Generic
This is where reset, normalize & box-sizing styles go.
*/

*, *:before, *:after {
  box-sizing: border-box;
}
/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */

/* Document
   ========================================================================== */

/**
 * 1. Correct the line height in all browsers.
 * 2. Prevent adjustments of font size after orientation changes in iOS.
 */

html {
  line-height: 1.15; /* 1 */
  -webkit-text-size-adjust: 100%; /* 2 */
}

/* Sections
   ========================================================================== */

/**
 * Remove the margin in all browsers.
 */

body {
  margin: 0;
}

/**
 * Correct the font size and margin on `h1` elements within `section` and
 * `article` contexts in Chrome, Firefox, and Safari.
 */

h1 {
  font-size: 2em;
  margin: 0.67em 0;
}

/* Grouping content
   ========================================================================== */

/**
 * Add the correct box sizing in Firefox.
 */

hr {
  box-sizing: content-box;
  height: 0;
}

/**
 * 1. Correct the inheritance and scaling of font size in all browsers.
 * 2. Correct the odd `em` font sizing in all browsers.
 */

pre {
  font-family: monospace, monospace; /* 1 */
  font-size: 1em; /* 2 */
}

/* Text-level semantics
   ========================================================================== */

/**
 * 1. Remove the bottom border in Chrome 57-
 * 2. Add the correct text decoration in Chrome, Edge, Opera, and Safari.
 */

abbr[title] {
  border-bottom: none; /* 1 */
  text-decoration: underline; /* 2 */
  text-decoration: underline dotted; /* 2 */
}

/**
 * Add the correct font weight in Chrome, Edge, and Safari.
 */

b,
strong {
  font-weight: bolder;
}

/**
 * 1. Correct the inheritance and scaling of font size in all browsers.
 * 2. Correct the odd `em` font sizing in all browsers.
 */

code,
kbd,
samp {
  font-family: monospace, monospace; /* 1 */
  font-size: 1em; /* 2 */
}

/**
 * Add the correct font size in all browsers.
 */

small {
  font-size: 80%;
}

/**
 * Prevent `sub` and `sup` elements from affecting the line height in
 * all browsers.
 */

sub,
sup {
  font-size: 75%;
  line-height: 0;
  position: relative;
  vertical-align: baseline;
}

sub {
  bottom: -0.25em;
}

sup {
  top: -0.5em;
}

/* Forms
   ========================================================================== */

/**
 * 1. Change the font styles in all browsers.
 * 2. Remove the margin in Firefox and Safari.
 */

button,
input,
optgroup,
select,
textarea {
  font-family: inherit; /* 1 */
  font-size: 100%; /* 1 */
  line-height: 1.15; /* 1 */
  margin: 0; /* 2 */
}

/**
 * Remove the inheritance of text transform in Edge and Firefox.
 * 1. Remove the inheritance of text transform in Firefox.
 */

button,
select { /* 1 */
  text-transform: none;
}

/**
 * Correct the inability to style clickable types in iOS and Safari.
 */

button,
[type="button"],
[type="reset"],
[type="submit"] {
  -webkit-appearance: button;
}

/**
 * Remove the inner border and padding in Firefox.
 */

button::-moz-focus-inner,
[type="button"]::-moz-focus-inner,
[type="reset"]::-moz-focus-inner,
[type="submit"]::-moz-focus-inner {
  border-style: none;
  padding: 0;
}

/**
 * Restore the focus styles unset by the previous rule.
 */

button:-moz-focusring,
[type="button"]:-moz-focusring,
[type="reset"]:-moz-focusring,
[type="submit"]:-moz-focusring {
  outline: 1px dotted ButtonText;
}

/**
 * Correct the padding in Firefox.
 */

fieldset {
  padding: 0.35em 0.75em 0.625em;
}

/**
 * Remove the padding so developers are not caught out when they zero out `fieldset` elements in all browsers.
 */

legend {
  padding: 0;
}

/**
 * Add the correct vertical alignment in Chrome, Firefox, and Opera.
 */

progress {
  vertical-align: baseline;
}

/**
 * Correct the cursor style of increment and decrement buttons in Chrome.
 */

[type="number"]::-webkit-inner-spin-button,
[type="number"]::-webkit-outer-spin-button {
  height: auto;
}

/**
 * 1. Correct the odd appearance in Chrome and Safari.
 * 2. Correct the outline style in Safari.
 */

[type="search"] {
  -webkit-appearance: textfield; /* 1 */
  outline-offset: -2px; /* 2 */
}

/**
 * Remove the inner padding in Chrome and Safari on macOS.
 */

[type="search"]::-webkit-search-decoration {
  -webkit-appearance: none;
}

/**
 * 1. Correct the inability to style clickable types in iOS and Safari.
 * 2. Change font properties to `inherit` in Safari.
 */

::-webkit-file-upload-button {
  -webkit-appearance: button; /* 1 */
  font: inherit; /* 2 */
}

/* Interactive
   ========================================================================== */

/*
 * Add the correct display in Edge and Firefox.
 */

details {
  display: block;
}

/*
 * Add the correct display in all browsers.
 */

summary {
  display: list-item;
}

/* Objects
Non-cosmetic design patterns including grid and layout classes)
*/



/* CSS variables */

:root {
  --column-gap: 2.13%;
  --column-width-multiplier: 8.333;
}

/* Mobile layout */

.row-fluid {
  display: flex;
  flex-wrap: wrap;
  width: 100%;
}


  .row-fluid .span1,
  .row-fluid .span2,
  .row-fluid .span3,
  .row-fluid .span4,
  .row-fluid .span5,
  .row-fluid .span6,
  .row-fluid .span7,
  .row-fluid .span8,
  .row-fluid .span9,
  .row-fluid .span10,
  .row-fluid .span11,
  .row-fluid .span12{
  min-height: 1px;
  width: 100%;
}

/* Desktop layout */

@media (min-width: 768px) {
  .row-fluid {
    flex-wrap: nowrap;
    justify-content: space-between;
  }

  
    .row-fluid .span1 {
      width: calc(var(--column-width-multiplier) * 1% * 1 - var(--column-gap) * (11 * var(--column-width-multiplier) / 100));
    }
  
    .row-fluid .span2 {
      width: calc(var(--column-width-multiplier) * 1% * 2 - var(--column-gap) * (10 * var(--column-width-multiplier) / 100));
    }
  
    .row-fluid .span3 {
      width: calc(var(--column-width-multiplier) * 1% * 3 - var(--column-gap) * (9 * var(--column-width-multiplier) / 100));
    }
  
    .row-fluid .span4 {
      width: calc(var(--column-width-multiplier) * 1% * 4 - var(--column-gap) * (8 * var(--column-width-multiplier) / 100));
    }
  
    .row-fluid .span5 {
      width: calc(var(--column-width-multiplier) * 1% * 5 - var(--column-gap) * (7 * var(--column-width-multiplier) / 100));
    }
  
    .row-fluid .span6 {
      width: calc(var(--column-width-multiplier) * 1% * 6 - var(--column-gap) * (6 * var(--column-width-multiplier) / 100));
    }
  
    .row-fluid .span7 {
      width: calc(var(--column-width-multiplier) * 1% * 7 - var(--column-gap) * (5 * var(--column-width-multiplier) / 100));
    }
  
    .row-fluid .span8 {
      width: calc(var(--column-width-multiplier) * 1% * 8 - var(--column-gap) * (4 * var(--column-width-multiplier) / 100));
    }
  
    .row-fluid .span9 {
      width: calc(var(--column-width-multiplier) * 1% * 9 - var(--column-gap) * (3 * var(--column-width-multiplier) / 100));
    }
  
    .row-fluid .span10 {
      width: calc(var(--column-width-multiplier) * 1% * 10 - var(--column-gap) * (2 * var(--column-width-multiplier) / 100));
    }
  
    .row-fluid .span11 {
      width: calc(var(--column-width-multiplier) * 1% * 11 - var(--column-gap) * (1 * var(--column-width-multiplier) / 100));
    }
  
}
/* Header/footer chrome wrapper — on the SAME rail as the dnd content, so the
   logo/CTA/footer line up with the module gutter (was full-width + 1rem, which
   ignored the rail). */
.content-wrapper {
  max-width: var(--os-max-width);
  margin-inline: auto;
  padding-inline: var(--os-section-pad-h);
}

/* ============================================================
   THE RAIL — Option 1 (ratified 2026-08-18). Layer 1, shared.

   SPEC-022: the gutter is a Layer-1 decision — ONE shared owner of the
   horizontal; no module invents its own. This file is that owner. Every native
   dnd section caps its CONTENT (.row-fluid) to the brand max-width and insets it
   by the brand gutter; columns contribute NO horizontal. A brand may ship a
   different --os-max-width / --os-section-pad-h (Layer-2 values) but never a
   different WAY of applying one.

   The section BAND (.dnd-section) still spans full width, so a full-width
   background or photo bleeds edge-to-edge while its content rails. A module whose
   CONTENT must bleed (cover / hero / statement bands) opts out with a 100vw
   break-out on its own outer — in the module CSS, not here.

   Gutter lives at EVERY width now (the old `@media (max-width:767px)` that zeroed
   the column gutter is gone — that was the mobile edge-touch bug). Vertical
   rhythm is untouched: padding-INLINE only, so --os-flow-gap stays the peer's. */
.dnd-section > .row-fluid {
  max-width: var(--os-max-width);
  margin-inline: auto;
  padding-inline: var(--os-section-pad-h);
}

.dnd-section .dnd-column {
  padding-inline: 0;
}

/* CURATED BACKGROUND OPTIONS (Layer 1, SPEC-022). One `.os-bg--<name>` class per
   named brand background the picker offers. Token-driven so the VALUE is Layer 2
   (a brand sets `--<prefix>-bg-<name>` in theme-overrides) and WHICH options a
   brand offers is Layer 3 (its `offers` block). A brand that does not define the
   token never lists the option, so the unused class is inert. Text defaults to the
   brand ink, overridable per background with `--os-on-<name>`. First entry: Rich
   Black (Tom, 2026-08-24). Add a sibling class here as the palette grows. */
.os-bg--rich-black {
  /* Fallbacks are load-bearing: a reference with NO fallback would register this as
     a REQUIRED skin role, and a brand that doesn't offer Rich Black would then be
     skipped by build_brand's role check. With the fallback it stays optional, and a
     brand without the token renders inert (transparent). NB: keys_pulled scans this
     file including comments and does not strip them, so this note deliberately does
     NOT spell out the bare no-fallback form — writing it here would re-register the
     role from the comment itself (measured 2026-08-24). */
  /* Set --os-surface so a BAND module (one that paints its own background) can read
     it as `background: var(--os-surface, <its default>)` and let the picker win —
     a plain background-color would be overridden by the module's own rule. Also
     paint background-color directly, for a plain container that reads neither. */
  --os-surface: var(--os-bg-rich-black, transparent);
  background-color: var(--os-surface, transparent);
  color: var(--os-on-rich-black, var(--os-ink));
}
/* _flow — VERTICAL RHYTHM. Layer 1, shared.

   THE OWNERSHIP DOCTRINE (ratified 2026-08-31, Tom). This file is to the
   vertical what `_containers-dnd.css` is to the horizontal: ONE shared owner.
   Two levels, one rule — the SECTION owns the space, the atoms own none.

     BAND   `.dnd-section`                        padding-top/bottom  --os-section-pad-v
     ROWS   stacked rows inside a section column  margin-top          --os-flow-gap

   A brand may ship different VALUES (--os-section-pad-v, --os-flow-gap are
   Layer 2, set in its theme-overrides :root) but never a different WAY of
   applying one. No module invents its own outer vertical; a module that needs
   more room inside itself uses its own padding, which is a different thing.

   WHY THE BAND RULE LIVES HERE and not in a new `_section-rhythm.css`: a new
   partial has to be added by hand to every brand's `main.css`, which is the one
   file the build does NOT propagate. Nothing gates an unreferenced CSS partial
   — the registry-table check covers modules and template partials, not these —
   so a brand missed at author time would silently ship with no section rhythm
   and the page would still render. `_flow.css` is already included by every
   brand, and the band padding is the same doctrine one level up, so it goes
   where the doctrine already lives. Split it out only if a gate exists first.

   WHY LONGHANDS, not `padding-block`: HubSpot writes editor-set section padding
   as a generated class carrying `padding-top`/`padding-bottom` with `!important`
   (see the cascade note on the band rule). Matching its physical longhands keeps
   that override a plain same-property `!important` win with no logical-to-
   physical mapping in between. `.rt-section` and `_footer.css` already write the
   token this way, so this also stays consistent with them. */


/* ── THE BAND ────────────────────────────────────────────────────────────────
   Native `.dnd-section` had NO vertical owner before this rule. `--os-section-pad-v`
   (theme field `section_padding_vertical`) reached only `.rt-section`, the footer
   and the system templates — every one of them a CODED surface. A marketer building
   in the editor got nothing, so their sections conjoined flatly. This closes that.

   THE EDITOR STILL WINS, and it is worth writing down HOW, because it is not the
   inline style you would expect. MEASURED on STG 2026-08-31, both directions, on a
   real published page: HubSpot emits a per-section generated CLASS into the page's
   own <style> block, carrying `!important` on the physical longhands —

     `.dnd_area-row-2-padding { padding-top: 40px !important;
                                padding-bottom: 40px !important; }`

   named `<dnd-area-name>-row-<n>-padding`, whether the number came from the editor
   sidebar or from a template declaring its own dnd_section padding parameter. A
   section nobody has touched carries NO such class at all — its `rowMetaData` is a
   bare `{"cssClass": "dnd-section"}`.

   (Written without literal HubL delimiters on purpose: `build-registry-tables.py`
   classifies any _base sheet containing them as "stamped", which would silently
   excuse this file from its brand-divergence check. See finding SP2.)

   So: untouched section takes this rule (verified: 96px, the token); touched section
   takes the marketer's number (verified: 40px on the same page, same load), because
   `!important` beats it. Nothing here needs to defend that, and nothing here should
   ever be given `!important` of its own — that would take the control away.

   Horizontal-neutral by design — the rail in `_containers-dnd.css` stays the peer's. */
.dnd-section {
  padding-top: var(--os-section-pad-v);
  padding-bottom: var(--os-section-pad-v);
}

/* MOBILE STEP (Tom, 2026-08-31, ruling on finding SP6). The token is a single
   number, so without this a 390px phone took the full desktop band — 96px at the
   brand default, top and bottom, on a 390px-wide column.

   0.6x at max-width 767px is NOT a new number: it is exactly what every brand's
   `theme-overrides.css` already does to `.os-section` (the coded-section root), in
   the same breakpoint, with the same multiplier. All three web brands agreed on it
   independently before this rule existed, which is what made it the precedent to
   match rather than a value to invent. Lifting it to Layer 1 for the dnd band keeps
   the two surfaces in step instead of letting a coded page and an editor-built page
   breathe differently on the same phone.

   Still no `!important`, and still the same specificity (0,1,0) as the rule above —
   so the editor's per-section number keeps winning here too, and the opt-outs below
   (0,2,0) keep winning regardless of source order. */
@media (max-width: 767px) {
  .dnd-section {
    padding-top: calc(var(--os-section-pad-v) * 0.6);
    padding-bottom: calc(var(--os-section-pad-v) * 0.6);
  }
}


/* ── EXCEPTION 1: CHROME ─────────────────────────────────────────────────────
   The header's drag-and-drop areas are `.dnd-section`s too. `header-cta` declares
   `padding={"top":0,"bottom":0}` in the template and is therefore already immune
   (it gets HubSpot's `!important` zero), but `header-top` and `header-bottom` ship
   with no declared padding — a marketer dropping a module into either would collect
   96px of body rhythm inside the header. Scoped to the chrome ancestor, so it holds
   for both header partials and for any brand that inlines its own.

   The FOOTER needs no rule: `templates/partials/footer.html` is fixed markup, not a
   dnd_area, and it already applies --os-section-pad-v itself (`_footer.css`). */
.header .dnd-section {
  padding-top: 0;
  padding-bottom: 0;
}


/* ── EXCEPTION 2: MODULES THAT ARE THEIR OWN BAND ────────────────────────────
   A module that paints and pads a full-width band IS the section's vertical space.
   Give its section padding as well and you get the space twice — and for the cover
   you break it outright, because its bleed-behind-header pull-up
   (`margin-top: calc(-1 * --os-header-h)`, restored in 62a75faa after two stacked
   regressions) is measured against the section's top edge. Section padding would
   push the hero back down by exactly the amount the pull-up removes.

   The list, swept module by module against each root element's own vertical
   declarations rather than by eye:

     .os-cover-cta      100vw band · --pad-* padding-block · --outer-* margin-block
                        · the bleed pull-up above
     .os-split-cta      band · --pad-* padding-block IS the section space
     .os-band           100vw full-bleed band · own `padding` shorthand
     .os-framed-cta     not a band, but already spaces itself with
                        `margin-block: var(--os-section-pad-v)` — see its own note
     .os-section        `_stats-counters`' root. Brand-side (each theme-overrides
                        defines it) and it already writes --os-section-pad-v top and
                        bottom, plus a 0.6x mobile step. NB `.os-section-intro` is a
                        DIFFERENT class token and is NOT matched here.

   Specificity (0,2,0) beats the band rule (0,1,0) regardless of source order.

   KNOWN, ACCEPTED: a section mixing a self-banding module with ordinary modules
   loses its rhythm for all of them. That combination is not what these modules are
   for — each is built to be the whole section — and the marketer can still set the
   section's padding in the editor, which wins. Revisit only if it shows up in real
   use; do not pre-solve it by matching on the module wrapper instead, which would
   reintroduce the doubling for every mixed section.

   Add a class here when a new module paints its own band. Nothing else. */
.dnd-section:has(.os-cover-cta),
.dnd-section:has(.os-split-cta),
.dnd-section:has(.os-band),
.dnd-section:has(.os-framed-cta),
.dnd-section:has(.os-section) {
  padding-top: 0;
  padding-bottom: 0;
}


/* ── THE ROWS ────────────────────────────────────────────────────────────────
   Vertical rhythm between stacked rows inside a section column.

   The atoms ship margin:0 by design (an atom owns no outer spacing); the SECTION
   owns the gap between them. One shared contract (Layer 1), one brand value
   (--os-flow-gap, Layer 2 — defined in each brand's theme-overrides :root).

   Selector: consecutive dnd rows inside a dnd column. Validated against both
   horizontal-rail options (layer-3-busting spike, 2026-08-18) — neither renests
   the native dnd tree, so .row-fluid-wrapper adjacency is stable. Scoped to
   .dnd-section .dnd-column so header/footer rows and the section's own structural
   row wrapper are untouched. Horizontal-neutral: margin-top only, never inline. */
.dnd-section .dnd-column > .row-fluid-wrapper + .row-fluid-wrapper {
  margin-top: var(--os-flow-gap);
}

/* Elements
Base HTML elements are styled in this section (<body>, <h1>, <a>, <p>, <button> etc.)
*/

/* ============================================================
   Othership — Typography
   Base HTML element styles for type, links, lists, and text.
   Consumes --os-* custom properties from theme-overrides.css.
   ============================================================ */

/* The overflow-wrap is meant to prevent long/large words from breaking the mobile responsiveness of a page (e.g. horizontal scrolling). It is preferred to reduce font sizes on mobile to address this, with this CSS specifically helping with extreme scenarios where a reduction in font size is not possible. */

body {
  font-family: var(--os-font-body);
  font-size: var(--os-body-size);
  line-height: var(--os-body-lh);
  color: var(--os-color-light);
  overflow-wrap: break-word;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

/* Handles word breaking for a few specific languages which handle breaks in words differently. If your content is not translated into these languages, you can safely remove this. */

html[lang^="ja"] body,
html[lang^="zh"] body,
html[lang^="ko"] body {
  line-break: strict;
  overflow-wrap: normal;
  word-break: break-all;
}

/* Paragraphs */

p {
  font-size: 1rem;
  margin: 0 0 1em;
}

/* Anchors */

a {
  color: var(--os-color-blue);
  text-decoration: underline;
  cursor: pointer;
  transition: color 0.2s ease;
}

a:hover {
  color: var(--os-color-green);
}

/* Headings */

h1,
h2 {
  font-family: var(--os-font-headline);
  font-weight: 500;
  letter-spacing: -0.02em;
  line-height: 1.15;
  margin: 0 0 0.5em;
}

h3,
h4,
h5,
h6 {
  font-family: var(--os-font-body);
  margin: 0 0 0.5em;
}

h1 {
  font-size: var(--os-h1-size);
  line-height: 1.1;
}

h2 {
  font-size: var(--os-h2-size);
  line-height: 1.15;
  letter-spacing: -0.01em;
}

h3 {
  font-size: var(--os-h3-size);
  font-weight: 600;
  letter-spacing: 0;
  line-height: 1.3;
}

h4 {
  font-size: var(--os-h4-size);
  font-weight: 600;
  letter-spacing: 0;
  line-height: 1.35;
}

h5 {
  font-size: 1rem;
  font-weight: 700;
  line-height: 1.4;
}

h6 {
  font-size: 0.875rem;
  font-weight: 700;
  line-height: 1.4;
}

/* Lists */

ul,
ol {
  margin: 0 0 1em;
}

ul ul,
ol ul,
ul ol,
ol ol {
  margin: 0;
}

ul.no-list {
  list-style: none;
  margin: 0;
  padding-left: 0;
}

/* Code blocks */

pre {
  overflow: auto;
}

code {
  vertical-align: bottom;
}

/* Blockquotes */

blockquote {
  border-left: 3px solid var(--os-color-green);
  margin: 0 0 1em;
  padding-left: 1em;
  color: rgba(255, 255, 255, 0.6);
}

/* Horizontal rules */

hr {
  border: none;
  border-bottom: 1px solid var(--os-border-dark);
}

/* Image alt text */

img {
  max-width: 100%;
  height: auto;
  font-size: 0.583rem;
  word-break: normal;
}

/* Responsive type */

@media (max-width: 767px) {
  h1 { font-size: calc(var(--os-h1-size) * 0.67); }
  h2 { font-size: calc(var(--os-h2-size) * 0.78); }
  h3 { font-size: calc(var(--os-h3-size) * 0.83); }
}
/* ============================================================
   Othership — Buttons
   Base button styles and branded variants.
   Consumes --os-btn-* custom properties from theme-overrides.css.
   ============================================================ */

/* Base button */

button,
.button,
.hs-button {
  display: inline-block;
  padding: var(--os-btn-pad-v) var(--os-btn-pad-h);
  font-family: var(--os-font-body);
  font-size: var(--os-btn-font-size);
  font-weight: var(--os-btn-font-weight);
  line-height: 1;
  text-align: center;
  text-decoration: none;
  border: 2px solid transparent;
  border-radius: var(--os-btn-radius);
  cursor: pointer;
  transition: all 0.2s ease;
  white-space: normal;
}

button:disabled,
.button:disabled,
.hs-button:disabled {
  background-color: var(--os-bg-muted);
  border-color: var(--os-bg-muted);
  color: var(--os-text-muted);
  cursor: not-allowed;
  opacity: 0.6;
}

/* The .os-btn--primary/secondary/inverse/sm/lg modifiers lived here and were
   removed 2026-08-17: nothing emitted them. Grepped every module.html,
   template, section and self-hosted page across the repo — the only hits were
   inside generated out/ previews, which merely inline this sheet.
   Buttons are styled by components/_button.css via .button--colourway /
   .button--cw-<n>; a second, unreachable vocabulary for the same job is how
   the two-homes problem started. The base rules above (button/.button/
   .hs-button and :disabled) and the .no-button reset below are LIVE — .button
   is what every CTA carries, and _menu uses .no-button. */

/* No button — full reset */

.no-button,
.no-button:hover,
.no-button:focus,
.no-button:active {
  background: none;
  border: none;
  border-radius: 0;
  color: initial;
  font-family: inherit;
  font-size: inherit;
  font-style: inherit;
  font-weight: inherit;
  letter-spacing: inherit;
  line-height: inherit;
  margin-bottom: 0;
  padding: 0;
  text-align: left;
  text-decoration: none;
  transition: none;
}
/* ============================================================
   FORMS — the HubSpot-form shim, converged.

   Authored once here in --os-* only; the stamp rewrites the prefix per brand,
   so one source skins DeskFlex's navy/gold form and Othership's dark/green one
   with no brand literals anywhere (that's the contract GATE enforces).

   WHY THIS FILE REPLACED THREE PER-BRAND COPIES (2026-08-07)
   ---------------------------------------------------------
   `_forms.css` used to be three divergent brand-local files inherited from the
   HubSpot boilerplate. Measured problems in them:

     1. HARDCODED OTHERSHIP GREEN IN EVERY BRAND. Line 68 of all three carried
        the same literal rgba() focus ring — Othership's accent green — so
        DeskFlex and TillerStack inputs flashed a green ring. Now derived from
        --os-accent-1 via color-mix, the same way _button.module already
        derives its hover/active shades. (No literal colour is repeated here:
        GATE scans comments too, and rightly rejected the first draft of this
        very note for quoting the hex.)

     2. DARK-GROUND ASSUMPTION, LIGHT-GROUND PAGES. Inputs were filled with a
        translucent-white wash and text in the "light" colour —
        correct on a dark page, invisible on a light one. DF LP1's hero form
        card is white, so it rendered near-white text in near-white fields. The
        old file did ship a `.<brand>-section--light` override block, but it
        only applied under that class and LP1 (rt- and zt- classes) never has it.
        Fixed by driving ground/ink from --os-card-bg / --os-ink, which each
        brand already defines correctly for its own canvas — a dark brand stays
        dark because its tokens are dark, not because the CSS assumes it.

     3. ONLY LEGACY FORMS WERE COVERED. Those selectors (.hs-form-field,
        .hs-input, form input[type=text]) target HubSpot's LEGACY renderer.
        Forms built in the updated editor render the .hsfc-* renderer instead,
        which ignores them entirely and is styled through HubSpot's own
        --hsf-* custom properties. That half was simply missing, which is the
        real reason embedded forms "look nothing like ours". Both halves are
        covered below.

   Token names in §1 are HubSpot's, taken from the property catalogue in
   hubspot-cms/_self-hosted/poc-hs-form/_hsfc-base-style.reference.css and the
   docs' styling tables — not invented. Precedence, highest first:
     --hsf-{component}__{prop}  >  --hsf-global__{prop}  >  HubSpot's
     --hsf-default-{component}__{prop}
   ============================================================ */

/* ============================================================
   §1 — NEW FORM RENDERER (.hsfc-*), driven by HubSpot's own properties.
   Set on :root because that is what HubSpot's docs prescribe; the embed reads
   them from wherever they cascade to it.
   ============================================================ */

:root {

  /* ----- global: cascades to inputs, labels, buttons, rich text -----
     --os-on-card, not --os-ink: this whole form lives inside a card (see the
     §4 note below), and on-card is the token brands define specifically for
     text sitting on --os-card-bg. Using --os-ink here is the bug that made
     Othership's form white-on-white — its card is deliberately white while
     --os-ink is the dark-PAGE ink. Non-inverting brands define on-card ==
     ink, so this is a no-op for them and a real fix for the inverting one. */
  --hsf-global__font-family: var(--os-font-body);
  --hsf-global__font-size:   var(--os-body-size);
  --hsf-global__color:       var(--os-on-card);
  --hsf-global__error-color: var(--os-form-error);

  /* ----- the form's own container -----
     Stripped flat: our pages already wrap a form in a card (rt-formcard, a
     dnd column, a system-page panel), so HubSpot's own card styling would
     double the padding and border. */
  --hsf-background__padding:       0;
  --hsf-background__border-style:  none;
  --hsf-background__border-width:  0;
  --hsf-background__border-radius: 0;
  --hsf-background__border-color:  transparent;

  /* ----- layout rhythm ----- */
  --hsf-row__horizontal-spacing:  16px;
  --hsf-row__vertical-spacing:    20px;
  --hsf-module__vertical-spacing:  8px;

  /* ----- labels ----- */
  --hsf-field-label__font-family: var(--os-font-body);
  --hsf-field-label__font-size:   0.875rem;
  --hsf-field-label__color:       var(--os-on-card);
  --hsf-field-label-requiredindicator__color: var(--os-form-error);

  /* ----- text inputs ----- */
  --hsf-field-input__font-family:       var(--os-font-body);
  --hsf-field-input__font-size:         var(--os-body-size);
  --hsf-field-input__color:             var(--os-on-card);
  --hsf-field-input__background-color:  var(--os-card-bg);
  --hsf-field-input__placeholder-color:  var(--os-ink-muted);
  --hsf-field-input__border-color:      var(--os-border);
  --hsf-field-input__border-style:      solid;
  --hsf-field-input__border-width:      1px 1px 1px 1px;
  --hsf-field-input__border-radius:     8px;
  --hsf-field-input__padding:           12px 14px;

  /* ----- textarea: same treatment, declared explicitly because HubSpot keeps
           a separate component namespace for it ----- */
  --hsf-field-textarea__font-family:      var(--os-font-body);
  --hsf-field-textarea__font-size:        var(--os-body-size);
  --hsf-field-textarea__color:            var(--os-on-card);
  --hsf-field-textarea__background-color: var(--os-card-bg);
  --hsf-field-textarea__placeholder-color: var(--os-ink-muted);
  --hsf-field-textarea__border-color:     var(--os-border);
  --hsf-field-textarea__border-style:     solid;
  --hsf-field-textarea__border-width:     1px 1px 1px 1px;
  --hsf-field-textarea__border-radius:    8px;
  --hsf-field-textarea__padding:          12px 14px;

  /* ----- checkbox / radio: accent is the tick/dot ----- */
  --hsf-field-checkbox__background-color: var(--os-card-bg);
  --hsf-field-checkbox__color:            var(--os-accent-1);
  --hsf-field-checkbox__border-color:     var(--os-border);
  --hsf-field-checkbox__border-style:     solid;
  --hsf-field-checkbox__border-width:     1px 1px 1px 1px;
  --hsf-field-checkbox__padding:          8px;

  --hsf-field-radio__background-color:    var(--os-card-bg);
  --hsf-field-radio__color:               var(--os-accent-1);
  --hsf-field-radio__border-color:        var(--os-border);
  --hsf-field-radio__border-style:        solid;
  --hsf-field-radio__border-width:        1px 1px 1px 1px;
  --hsf-field-radio__padding:             8px;

  /* ----- helper + footer text ----- */
  --hsf-field-description__font-family: var(--os-font-body);
  --hsf-field-description__font-size:   0.75rem;
  --hsf-field-description__color:       var(--os-ink-muted);

  --hsf-field-footer__font-family: var(--os-font-body);
  --hsf-field-footer__font-size:   0.75rem;
  --hsf-field-footer__color:       var(--os-ink-muted);

  /* ----- headings + rich text inside the form ----- */
  --hsf-heading__font-family: var(--os-font-head);
  --hsf-heading__color:       var(--os-on-card);
  --hsf-heading__text-shadow: none;

  --hsf-richtext__font-family: var(--os-font-body);
  --hsf-richtext__font-size:   var(--os-body-size);
  --hsf-richtext__color:       var(--os-ink-muted);

  /* ----- submit button: the SAME role tokens _button.module's primary preset
           uses, so a form's submit and a page's CTA cannot drift apart ----- */
  --hsf-button__font-family:      var(--os-font-body);
  --hsf-button__font-size:        var(--os-btn-font-size);
  --hsf-button__font-weight:      var(--os-btn-font-weight);
  --hsf-button__color:            var(--os-btn-primary-text);
  --hsf-button__background-color: var(--os-btn-primary-bg);
  --hsf-button__background-image: none;
  --hsf-button__border-color:     var(--os-btn-primary-bg);
  --hsf-button__border-style:     solid;
  --hsf-button__border-width:     2px 2px 2px 2px;
  --hsf-button__border-radius:    var(--os-btn-radius);
  --hsf-button__padding:          var(--os-btn-pad-v) var(--os-btn-pad-h);
  --hsf-button__box-shadow:       none;

  /* ----- alerts ----- */
  --hsf-erroralert__font-family: var(--os-font-body);
  --hsf-erroralert__font-size:   0.875rem;
  --hsf-erroralert__color:       var(--os-form-error);

  --hsf-infoalert__font-family: var(--os-font-body);
  --hsf-infoalert__font-size:   0.875rem;
  --hsf-infoalert__color:       var(--os-ink-muted);

  /* ----- multi-step progress bar ----- */
  --hsf-progressbar-text__font-family:              var(--os-font-body);
  --hsf-progressbar-text__font-size:                0.875rem;
  --hsf-progressbar-text__color:                    var(--os-ink-muted);
  --hsf-progressbar-progressLine__background-color: var(--os-accent-1);
  --hsf-progressbar-progressLine__background-image: none;
  --hsf-progressbar-progressLine__border-color:     var(--os-accent-1);
  --hsf-progressbar-progressLine__border-style:     none;
  --hsf-progressbar-progressLine__border-width:     0;
  --hsf-progressbar-trackLine__background-color:    var(--os-border);

  /* ----- navigation row: where the submit / next / back buttons sit -----
     Left, to line up with the left-aligned labels and inputs above. */
  --hsf-navigationrow-buttons__justify-content:        flex-start;
  --hsf-navigationrow-buttons-single__justify-content: flex-start;
}

/* Focus ring — not a --hsf-* property, so it needs a real selector. Derived
   from the accent by mixing toward transparent, so every brand gets its own
   ring and no brand's hex is written here (this is what replaced the
   hardcoded Othership green). */
.hsfc-TextInput:focus,
.hsfc-TextArea:focus,
.hsfc-Select:focus,
.hsfc-DateInput:focus {
  border-color: var(--os-accent-1);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--os-accent-1) 25%, transparent);
  outline: none;
}

/* ============================================================
   §2 — LEGACY FORM RENDERER (.hs-form / .hs-input).
   Same roles, so a legacy and a new form on the same page match.
   ============================================================ */

.hs-form-field {
  margin-bottom: 1.25rem;
}

form label {
  display: block;
  font-family: var(--os-font-body);
  font-size: 0.875rem;
  font-weight: 500;
  color: var(--os-on-card);
  margin-bottom: 0.35rem;
}

.form-title {
  margin-bottom: 0;
}

form legend {
  font-family: var(--os-font-body);
  font-size: 0.875rem;
  color: var(--os-ink-muted);
}

form input[type=text],
form input[type=search],
form input[type=email],
form input[type=password],
form input[type=tel],
form input[type=number],
form input[type=file],
form select,
form textarea {
  display: inline-block;
  width: 100%;
  padding: 12px 14px;
  font-family: var(--os-font-body);
  font-size: var(--os-body-size);
  color: var(--os-on-card);
  background-color: var(--os-card-bg);
  border: 1px solid var(--os-border);
  border-radius: 8px;
  transition: border-color 0.2s ease, box-shadow 0.2s ease;
}

form input[type=text]:focus,
form input[type=search]:focus,
form input[type=email]:focus,
form input[type=password]:focus,
form input[type=tel]:focus,
form input[type=number]:focus,
form select:focus,
form textarea:focus {
  border-color: var(--os-accent-1);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--os-accent-1) 25%, transparent);
  outline: none;
}

form input::placeholder,
form textarea::placeholder {
  color: var(--os-ink-muted);
}

form textarea {
  resize: vertical;
}

form fieldset {
  max-width: 100% !important;
}

/* checkbox / radio */

form .inputs-list {
  margin: 0;
  padding: 0;
  list-style: none;
}

form .inputs-list > li {
  display: block;
  margin: 0.5rem 0;
}

form .inputs-list input,
form .inputs-list span {
  vertical-align: middle;
}

form input[type=checkbox],
form input[type=radio] {
  -webkit-appearance: none;
  appearance: none;
  width: 20px;
  height: 20px;
  min-width: 20px;
  border: 2px solid var(--os-border);
  background: var(--os-card-bg);
  cursor: pointer;
  margin: 0 0.45rem 0 0;
  position: relative;
  vertical-align: middle;
  transition: background 0.15s, border-color 0.15s, box-shadow 0.15s;
}

form input[type=checkbox] {
  border-radius: 5px;
}

form input[type=radio] {
  border-radius: 50%;
}

form input[type=checkbox]:checked,
form input[type=radio]:checked {
  background: var(--os-accent-1);
  border-color: var(--os-accent-1);
}

form input[type=checkbox]:checked::after {
  content: "";
  position: absolute;
  left: 5px;
  top: 1px;
  width: 6px;
  height: 11px;
  border: solid var(--os-on-accent);
  border-width: 0 2.5px 2.5px 0;
  transform: rotate(40deg);
}

form input[type=radio]:checked::after {
  content: "";
  position: absolute;
  left: 4px;
  top: 4px;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--os-on-accent);
}

form input[type=checkbox]:focus-visible,
form input[type=radio]:focus-visible {
  outline: none;
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--os-accent-1) 25%, transparent);
}

form input[type=checkbox]:hover:not(:checked),
form input[type=radio]:hover:not(:checked) {
  border-color: var(--os-accent-1);
}

/* date picker */

.hs-dateinput {
  position: relative;
}

.hs-dateinput:before {
  content: '\01F4C5';
  position: absolute;
  right: 10%;
  top: 50%;
  transform: translateY(-50%);
}

.fn-date-picker .pika-table thead th {
  color: var(--os-on-card);
  background-color: var(--os-card-bg);
}

.fn-date-picker td.is-selected .pika-button {
  background-color: var(--os-accent-1);
  color: var(--os-on-accent);
  border-radius: 0;
  box-shadow: none;
}

.fn-date-picker td .pika-button:hover,
.fn-date-picker td .pika-button:focus {
  background-color: var(--os-accent-1);
  color: var(--os-on-accent);
  border-radius: 0 !important;
}

/* file picker — no field chrome, it renders its own control */

form input[type=file] {
  background-color: transparent;
  border: initial;
  padding: initial;
}

/* rich text inside a form */

form .hs-richtext,
form .hs-richtext p {
  font-size: 0.875rem;
  color: var(--os-ink-muted);
  margin: 0 0 1.25rem;
}

form .hs-richtext img {
  max-width: 100% !important;
}

/* GDPR / legal consent */

.legal-consent-container .hs-form-booleancheckbox-display > span,
.legal-consent-container .hs-form-booleancheckbox-display > span p {
  margin-left: 1rem !important;
}

.legal-consent-container,
.legal-consent-container p {
  font-size: 0.75rem;
  color: var(--os-ink-muted);
}

/* validation */

.hs-form-required {
  color: var(--os-form-error);
}

.hs-input.invalid.error {
  border-color: var(--os-form-error);
}

.hs-error-msg {
  color: var(--os-form-error);
  margin-top: 0.35rem;
  font-size: 0.8125rem;
}

/* submit — same role tokens as _button.module's primary preset */

form input[type=submit],
form .hs-button {
  display: inline-block;
  padding: var(--os-btn-pad-v) var(--os-btn-pad-h);
  font-family: var(--os-font-body);
  font-size: var(--os-btn-font-size);
  font-weight: var(--os-btn-font-weight);
  line-height: 1;
  text-align: center;
  text-decoration: none;
  background-color: var(--os-btn-primary-bg);
  color: var(--os-btn-primary-text);
  border: 2px solid var(--os-btn-primary-bg);
  border-radius: var(--os-btn-radius);
  cursor: pointer;
  transition: all 0.2s ease;
  white-space: normal;
}

form input[type=submit]:hover,
form .hs-button:hover {
  background-color: var(--os-btn-primary-hover);
  border-color: var(--os-btn-primary-hover);
}

/* captcha */

.grecaptcha-badge {
  margin: 0 auto;
}

/* ============================================================
   §3 — LOAD-ORDER BACKSTOP.

   HubSpot injects its own form stylesheet, and it competes by LOAD ORDER, not
   specificity: when it lands after the theme's CSS it wins on equal-specificity
   rules no matter how well-scoped §2 is. `.hs-form-html` is the wrapper the
   embed renders into, so scoping to it plus !important is the one lever that
   reliably beats the injected sheet — the same technique the Othership
   scheduler LP used to make an embedded form match its page.

   Deliberately narrow: only the properties where being overridden is VISIBLE
   and where HubSpot's default is actively wrong for us. !important is a blunt
   instrument, so it is spent on the field chrome and the submit button, not
   sprayed across the whole shim.
   ============================================================ */

.hs-form-html input[type=text],
.hs-form-html input[type=email],
.hs-form-html input[type=tel],
.hs-form-html input[type=number],
.hs-form-html input[type=password],
.hs-form-html select,
.hs-form-html textarea {
  font-family: var(--os-font-body) !important;
  color: var(--os-on-card) !important;
  background-color: var(--os-card-bg) !important;
  border: 1px solid var(--os-border) !important;
  border-radius: 8px !important;
}

.hs-form-html input:focus,
.hs-form-html select:focus,
.hs-form-html textarea:focus {
  outline: none !important;
  border-color: var(--os-accent-1) !important;
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--os-accent-1) 25%, transparent) !important;
}

.hs-form-html .hs-button {
  font-family: var(--os-font-body) !important;
  font-size: var(--os-btn-font-size) !important;
  font-weight: var(--os-btn-font-weight) !important;
  color: var(--os-btn-primary-text) !important;
  background-color: var(--os-btn-primary-bg) !important;
  border: 2px solid var(--os-btn-primary-bg) !important;
  border-radius: var(--os-btn-radius) !important;
  padding: var(--os-btn-pad-v) var(--os-btn-pad-h) !important;
}

/* ============================================================
   §4 — ZERO OUTER PADDING. Non-negotiable default.

   HubSpot ships `--hsf-default-background__padding: 40px`, so an embedded form
   arrives inside a 40px box it drew itself. On our pages the form is ALWAYS
   already inside a container that owns its own padding (rt-formcard, a dnd
   column, a system-page panel), so HubSpot's box is pure double padding.

   §1 already sets --hsf-background__padding: 0, and that is the correct first
   move — but it is not sufficient on its own. Custom properties resolve by
   INHERITANCE, not by a cascade contest: a value declared closer to the form
   element (which is how HubSpot writes a per-form Layout setting) beats our
   `:root` declaration no matter how specific or !important the `:root` one is.
   Fixing that per form in HubSpot's own layout settings is exactly the manual
   step this shim exists to abolish.

   So the padding is also killed on the real containers, with !important on the
   actual `padding` property — that DOES win, because it is a normal property in
   a normal cascade rather than a custom-property lookup.

   Scope note: only the OUTER box is zeroed. Row and field spacing
   (--hsf-row__*, --hsf-module__vertical-spacing in §1) is deliberately kept —
   this removes the frame, it does not collapse the form's internal rhythm.
   ============================================================ */

/* new renderer: wrapper → form → step → step content */
.hsfc-FormWrapper,
.hsfc-Form,
.hsfc-Step,
.hsfc-Step__Content,
.hsfc-Renderer {
  padding: 0 !important;
  margin: 0 !important;
  background-color: transparent !important;
  border: 0 !important;
  box-shadow: none !important;
}

/* legacy renderer + the CMS module wrapper HubSpot puts around either one */
.hs-form-html,
form.hs-form,
.hs_cos_wrapper_type_form {
  padding: 0 !important;
  margin: 0 !important;
  background-color: transparent !important;
  border: 0 !important;
  box-shadow: none !important;
}

/* Last field / submit row must not leave a trailing gap under the form either —
   the container below it owns that space. */
.hsfc-NavigationRow,
.hs-form-html .hs_submit,
form.hs-form .hs_submit {
  margin-bottom: 0 !important;
  padding-bottom: 0 !important;
}

/* ============================================================
   §5 — SUBMIT BUTTON, FORCED.

   Same failure mode as the padding, one level down, and measured live on DF LP1
   2026-08-07: §1 sets --hsf-button__background-color to the brand's primary
   button role, but a per-form button style set in HubSpot's form editor declares
   that property closer to the form element, and custom properties resolve by
   inheritance, so our :root value loses. The button rendered HubSpot's colour.

   Second bug in the same place: the earlier !important button rule was scoped to
   `.hs-form-html`, which is the wrapper the DEVELOPER-MODE embed renders (§2a of
   hubspot-cms/AGENTS.md). A form placed with the @hubspot/form CMS module is
   wrapped in `.hs_cos_wrapper_type_form` instead, so that rule never matched the
   case that actually matters on a theme page.

   Fixed the way the padding was: force the real properties, on BOTH renderers'
   button elements, unscoped from any one wrapper. Same role tokens as
   _button.module's primary preset, so a form's submit and a page CTA cannot
   drift apart.
   ============================================================ */

.hsfc-Button,
.hs-button,
input[type=submit].hs-button,
.hs_cos_wrapper_type_form .hs-button {
  font-family: var(--os-font-body) !important;
  font-size: var(--os-btn-font-size) !important;
  font-weight: var(--os-btn-font-weight) !important;
  color: var(--os-btn-primary-text) !important;
  background-color: var(--os-btn-primary-bg) !important;
  background-image: none !important;
  border: 2px solid var(--os-btn-primary-bg) !important;
  border-radius: var(--os-btn-radius) !important;
  padding: var(--os-btn-pad-v) var(--os-btn-pad-h) !important;
  box-shadow: none !important;
  cursor: pointer;
}

.hsfc-Button:hover,
.hsfc-Button:focus,
.hs-button:hover,
.hs-button:focus,
.hs_cos_wrapper_type_form .hs-button:hover,
.hs_cos_wrapper_type_form .hs-button:focus {
  color: var(--os-btn-primary-text) !important;
  background-color: var(--os-btn-primary-hover) !important;
  border-color: var(--os-btn-primary-hover) !important;
}

/* ============================================================
   §6 — FIELDS, FORCED. The same fix as §5, for the inputs.

   §3 backstops the fields only under `.hs-form-html`, the developer-mode embed
   wrapper. A form placed with the @hubspot/form CMS module is wrapped in
   `.hs_cos_wrapper_type_form`, so on a THEME page that backstop never fires and
   the fields fall back to §2's unscoped rules, which carry no !important and so
   lose to HubSpot's injected stylesheet on load order. Identical class of bug to
   the submit button; found by asking whether the shim really covers all four
   surfaces (form, module, fields, button) rather than assuming it.

   Forced unscoped, on both renderers' input elements, so the shim does not
   depend on WHICH wrapper HubSpot happened to render.
   ============================================================ */

.hsfc-TextInput,
.hsfc-TextareaInput,
.hsfc-DropdownInput,
.hsfc-DateInput,
.hsfc-PhoneInput,
.hs-input,
.hs_cos_wrapper_type_form input[type=text],
.hs_cos_wrapper_type_form input[type=email],
.hs_cos_wrapper_type_form input[type=tel],
.hs_cos_wrapper_type_form select,
.hs_cos_wrapper_type_form textarea {
  font-family: var(--os-font-body) !important;
  font-size: var(--os-body-size) !important;
  color: var(--os-on-card) !important;
  background-color: var(--os-card-bg) !important;
  border: 1px solid var(--os-border) !important;
  border-radius: 8px !important;
}

.hsfc-TextInput:focus,
.hsfc-TextareaInput:focus,
.hsfc-DropdownInput:focus,
.hsfc-DateInput:focus,
.hsfc-PhoneInput:focus,
.hs-input:focus,
.hs_cos_wrapper_type_form input:focus,
.hs_cos_wrapper_type_form select:focus,
.hs_cos_wrapper_type_form textarea:focus {
  outline: none !important;
  border-color: var(--os-accent-1) !important;
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--os-accent-1) 25%, transparent) !important;
}

/* Labels and validation text: the module wrapper case, matching §2's roles. */
.hs_cos_wrapper_type_form label,
.hsfc-FieldLabel {
  font-family: var(--os-font-body) !important;
  color: var(--os-on-card) !important;
}

.hs_cos_wrapper_type_form .hs-error-msg,
.hsfc-ErrorAlert {
  color: var(--os-form-error) !important;
}
/* ============================================================
   Othership — Tables
   Branded table styles using --os-* design tokens.
   ============================================================ */

/* Table */

table {
  border-collapse: collapse;
  margin-bottom: 1.25rem;
  overflow-wrap: break-word;
  width: 100%;
}

/* Table cells */

td,
th {
  vertical-align: top;
  padding: 0.75rem 1rem;
  border-bottom: 1px solid var(--os-border-dark);
  text-align: left;
}

/* Table header */

thead th {
  vertical-align: bottom;
  font-family: var(--os-font-body);
  font-weight: 600;
  font-size: 0.8125rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.6);
  border-bottom: 2px solid var(--os-border-dark);
}

/* Striped rows */

tbody tr:nth-child(even) {
  background-color: rgba(255, 255, 255, 0.05);
}

/* Light section tables */

.os-section--light table td,
.os-section--light table th {
  border-color: var(--os-border-light);
}

.os-section--light thead th {
  color: var(--os-text-muted);
  border-bottom-color: var(--os-border-light);
}

.os-section--light tbody tr:nth-child(even) {
  background-color: var(--os-bg-muted);
}

/* Components
Specific pieces of UI that are stylized. Typically used for global partial styling
*/

/* Button colourways — shared. Any module may emit
   class="button button--colourway button--cw-<n> [button--mode-<mode>]".
   Layer 1 (capability); count baked per brand; modes set --mode-* from the
   brand's own theme CSS. See SPEC-022. */


.button--cw-1 {
  --fill: var(--os-cw-1);
  --ink: var(--os-on-cw-1);
}

.button--cw-2 {
  --fill: var(--os-cw-2);
  --ink: var(--os-on-cw-2);
}

.button--cw-3 {
  --fill: var(--os-cw-3);
  --ink: var(--os-on-cw-3);
}

.button--cw-4 {
  --fill: var(--os-cw-4);
  --ink: var(--os-on-cw-4);
}

.button--cw-5 {
  --fill: var(--os-cw-5);
  --ink: var(--os-on-cw-5);
}


/* Appearance. Reads --mode-* (a brand's optional mode) with a FILLED fallback,
   which itself falls back to the accent role so a button is never unstyled. */
.button--colourway {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-family: var(--os-font-body);
  font-size: var(--os-btn-font-size);
  font-weight: var(--os-btn-font-weight);
  line-height: 1;
  text-align: center;
  text-decoration: none;
  cursor: pointer;
  white-space: normal;
  padding: var(--os-btn-pad-v) var(--os-btn-pad-h);
  border-radius: var(--os-btn-radius);
  background: var(--mode-bg, var(--fill, var(--os-accent-1)));
  color: var(--mode-fg, var(--ink, var(--os-on-accent)));
  border: 2px solid var(--mode-border, var(--fill, var(--os-accent-1)));
  transition: background-color 0.2s ease, color 0.2s ease, border-color 0.2s ease;
}

.button--colourway:hover,
.button--colourway:focus {
  background: var(--mode-bg-hover,
              color-mix(in srgb, var(--fill, var(--os-accent-1)) 86%,
                                 var(--ink, var(--os-on-accent))));
  border-color: var(--mode-border, var(--fill, var(--os-accent-1)));
  /* `color` MUST be repeated here, identical to the base rule. A button is an
     <a>, and the theme's generic link style sets `a:hover { color: <accent> }`.
     That selector (0-1-1) outranks `.button--colourway` (0-1-0), so leaving
     colour out of the hover state handed the text to the link rule — every
     colourway's label turned the brand accent on hover, whatever fill it had.
     Measured 2026-08-17: cw-4 (blue) went black -> the accent on hover. */
  color: var(--mode-fg, var(--ink, var(--os-on-accent)));
}

.button--colourway:focus-visible {
  outline: 2px solid var(--fill, var(--os-accent-1));
  outline-offset: 2px;
}
/* ============================================================
   Header — dark navigation bar using --os-* design tokens.
   ============================================================ */

/* The header bar itself — background + sticky. Ported from a dead,
   brand-prefixed nav class that was never wired to this real selector, so
   --os-nav-bg went unused here: harmless on a brand whose page is already
   dark (Othership), but it left --os-nav-text unreadable on a light page
   (DeskFlex, TillerStack) since the header carried no background of its own. */
/* NOT sticky by default. This rule used to declare `position: sticky` outright, which
   meant EVERY header on EVERY page was pinned regardless of the "Sticky header" theme
   field — the field re-declared sticky when on and did nothing when off, because this
   had already done it. So the control was decorative (Tom, 2026-08-23: noticed only
   because frosted made the pinning visible — a transparent header sliding over content
   is obvious where an opaque one is not).

   Stickiness now comes from ONE place: `theme.header.sticky`, applied per template. The
   frosted variant inherits it rather than forcing it.

   z-index stays: the header must still layer above the page when something deliberately
   slides under it (see _cover-cta's bleed-behind-header), sticky or not. */
.header {
  background-color: var(--os-nav-bg);
  color: var(--os-nav-text);
  position: relative;
  z-index: 1000;
}

/* The generic page-wide link colour (elements/_typography.css) is tuned for
   links on the page body, not inside a header that now has its own
   background — a direct rule on `a` always wins over an ancestor's inherited
   colour, so without this override, any link in the header (nav menu, etc.)
   would fall back to the page link colour and can go invisible against a
   brand whose nav background happens to match that colour (DeskFlex: both
   are the same navy). Also ported from the same dead nav class as above. */
.header a {
  color: var(--os-nav-text);
  text-decoration: none;
}
.header a:hover {
  color: var(--os-accent-1);
}

/* Header DND sections */

.header .dnd-section {
  padding: 0;
}

/* No-navigation variant — coded landing pages (header-no-navigation.html).
   No menu, no dark nav bar: it reads as the top edge of the page canvas, so
   it takes --os-bg/--os-ink (each brand's own canvas) instead of the dark
   --os-nav-bg used by the full site header. Verified against DF LP1 Figma
   node 25593:853: white ground, hairline shadow, 72px-tall bar, 122px logo
   at 1440 width (the live render carried the dark nav bg — this class was
   applied in markup but had no CSS at all — and a 200px logo, both wrong). */
.header--no-navigation {
  background-color: var(--os-bg);
  color: var(--os-ink);
  box-shadow: var(--os-shadow-sm);
}

.header--no-navigation .header__container {
  padding-block: 1.45rem;

  /* ⚠️ SUPERSEDED 2026-08-23 — the measurement below is kept because the numbers are
     still the record of how this was diagnosed, but its CONCLUSION ("drop the max-width")
     no longer holds and must not be re-applied. It was correct only while the BODY was
     full-bleed. The body now rides the centred max-width rail
     (`objects/_containers-dnd.css`), so the fix inverted: the header is railed too. See
     the note directly above the `max-width` declaration for the current reasoning.
     Read both before changing either — this rule has now been flipped in both
     directions, once for each state of the body.

     Align the header's content with the BODY's content, measured rather than
     guessed (DF LP1 at 1440px, 2026-08-07): body content began at 56px, header
     content at 153px, a 97px mismatch that read as the logo floating inboard of
     the h1 below it.

     Where each number comes from:
       body   = 16px  (`.dnd-section .dnd-column` padding, 1rem)
              + 40px  (--os-section-pad-h on the module's own wrap)
              = 56px, measured from the VIEWPORT edge, because the theme's dnd
                sections are full-bleed: the hero row spans the viewport and is
                not centred inside a max-width band.
       header = 113px (max-width 1200 centred in 1440 → (1440-1200)/2)
              + 40px  (--os-section-pad-h)
              = 153px.

     So the mismatch is the centring, not the padding. Dropping the max-width
     and adding the dnd column's 1rem to the gutter makes the two derive the
     same inset from the same token at every width, instead of one being centred
     while the other is full-bleed. */
  /* Ride the SAME centred rail as the body and the full nav header: cap to
     --os-max-width, centre it, inset by --os-section-pad-h. An earlier version set
     max-width:none (full-bleed) to match a then-full-bleed body; the body is now on
     the max-width rail (objects/_containers-dnd.css), so full-bleed made the header
     span the whole viewport and drift off the body on any screen wider than the rail
     — the logo/CTA hugged the 2K edges while the body sat in the centred column
     (Tom, 2026-08-23). Railing it aligns header, body and footer at every width. */
  max-width: var(--os-max-width);
  margin-inline: auto;
  padding-inline: var(--os-section-pad-h);
}

.header--no-navigation .header__logo {
  max-width: 122px;
}

/* Mobile + tablet: the generic .header__container rule below switches to
   flex-direction:column and centers the logo (width:100%; margin:0 auto).
   That exists for the FULL nav header, which needs separate rows for its
   menu / search / language-switcher items. This header has at most a logo
   and one CTA, so stacking just dropped the button onto its own line,
   left-aligned under a centered logo. Keep it a single row instead —
   logo left, CTA right, same as desktop. Two classes beats the one-class
   generic rule on specificity, so this wins regardless of source order. */
@media (max-width: 767px) {
  .header--no-navigation .header__container {
    flex-direction: row;
    align-items: center;
    /* `.dnd-section .dnd-column` drops its 1rem at this same breakpoint
       (objects/_containers-dnd.css), so the body gutter becomes
       --os-section-pad-h alone. Drop the 1rem here too or the header would sit
       16px inboard of the body on mobile. */
    padding-inline: var(--os-section-pad-h);
  }

  .header--no-navigation .header__logo {
    margin: 0 auto 0 0;
    width: auto;
  }
}

/* Header container */

.header__container {
  display: flex;
  justify-content: space-between;
  /* Header content must align with BODY content. This rule previously set no
     max-width and no horizontal padding, so the logo sat flush against the
     viewport edge while every body section was inset by --os-section-pad-h —
     the header looked detached from the page (spotted on DF LP1, 2026-08-07).
     Same two tokens the body containers use (root-templates .rt-container,
     the module wrappers), so header and body share one measure by construction
     rather than by coincidence.
     Applies to BOTH header partials — header.html and
     header-no-navigation.html both use .header__container — and to every
     brand, since this file is _base-converged. */
  max-width: var(--os-max-width);
  margin-inline: auto;
  padding-inline: var(--os-section-pad-h);
  width: 100%;
}

.header__row-1 {
  padding-top: 1rem;
}

.header__row-1,
.header__row-2 {
  align-items: center;
  display: flex;
  justify-content: flex-end;
  width: 100%;
}

@media (max-width: 1150px) and (min-width: 767px) {
  .header__column {
    width: 100%;
  }
}

@media (max-width: 767px) {
  .header__container {
    flex-direction: column;
    /* keep the horizontal gutter: the shorthand `padding: 1rem 0 0` used here
       previously reset padding-inline to 0, cancelling the gutter on exactly
       the widths where flush-to-edge reads worst */
    padding: 1rem var(--os-section-pad-h) 0;
  }

  .header__column {
    position: relative;
  }

  .header__row-1 {
    padding-top: 0;
  }

  .header__row-2 {
    justify-content: center;
    padding: 1.05rem;
  }
}

/* Navigation skipper */

.header__skip {
  height: 1px;
  left: -1000px;
  overflow: hidden;
  position: absolute;
  text-align: left;
  top: -1000px;
  width: 1px;
}

.header__skip:hover,
.header__skip:focus,
.header__skip:active {
  height: auto;
  left: 0;
  overflow: visible;
  top: 0;
  width: auto;
}

/* Logo */

.header__logo {
  align-items: center;
  display: flex;
  height: auto;
  margin-right: auto;
  max-width: 200px;
  overflow: hidden;
}

@media (max-width: 767px) {
  .header__logo {
    margin: 0 auto;
    width: 100%;
  }
}

.header__logo img {
  max-width: 100%;
  /* AN EXPLICIT HEIGHT, because an SVG wordmark has no intrinsic size.
     Thirteen of sixteen brands bake a .svg header logo whose root carries only
     a viewBox — no width, no height (HubSpot's File Manager reports their
     dimensions as null too). Inside this flex container with height:auto that
     resolves to 0x0, so the logo was invisible on every one of those brands.
     Measured 2026-09-04 with the real assets and these exact rules:
       Jadian  (.svg)  0x0     -> 122x41
       Othership (.png) 122x41 -> 121x41   (unchanged, so the PNG brands are safe)
     Only the three PNG brands ever rendered, which is why Othership looked
     correct and Jadian did not.
     Height rather than width so the aspect ratio comes from the asset; a brand
     with a differently proportioned mark overrides the token. */
  height: var(--os-header-logo-h, 41px);
  width: auto;
}

.header__logo .logo-company-name {
  font-size: 1.167rem;
  margin-top: 0.7rem;
  color: var(--os-nav-text);
}

.header__logo--main {
  padding-top: 1rem;
}

/* Animated logo (theme.header.logo_animated), generic box — not pixel-tuned
   to any one brand's SVG. `.header__logo` clips (overflow:hidden) by design
   for the static case; the reveal's own empty canvas margin needs the clip
   OFF or the animation bleeds against the box edge instead of the page. */
.header__logo--animated {
  overflow: visible;
}

.header__logo--animated object {
  height: 100%;
  width: auto;
}

/* Search bar */

.header__search {
  padding: 0 1rem;
  width: auto;
}



  .hs-search-field__form {
    position: relative;
  }

  .header__search .hs-search-field__label {
    flex-basis: auto;
  }



.header__search .hs-search-field__input {
  
  height: 45px;
  padding: 0 0.7rem;
  background-color: rgba(255, 255, 255, 0.1);
  border: 1px solid var(--os-border-strong);
  border-radius: 8px;
  color: var(--os-nav-text);
}

.header__search .hs-search-field__input::placeholder {
  color: rgba(255, 255, 255, 0.5);
}


  .header__search .hs-search-field__button {
    padding: 0;
    fill: var(--os-nav-text);
    background-color: transparent;
    border: none;
    padding: 10px;
    position: absolute;
    top: 0;
    right: 0;
  }

  .header__search .hs-search-field__button svg {
    height: 25px;
    fill: var(--os-nav-text);
  }


.header__search .hs-search-field--open .hs-search-field__input {
  border-bottom: none;
  border-radius: 8px 8px 0 0;
  max-width: 100%;
}

.header__search .hs-search-field--open .hs-search-field__suggestions {
  background-color: var(--os-bg);
  border: 1px solid var(--os-border-strong);
  border-radius: 0 0 8px 8px;
  border-top-width: 1px;
  position: absolute;
  width: 100%;
  z-index: 10;
}

.header__search .hs-search-field__suggestions li {
  border-top: 1px solid var(--os-border-strong);
  font-size: 0.875rem;
}

.header__search .hs-search-field__suggestions li a {
  color: var(--os-nav-text);
  padding: 0.35rem 0.7rem;
  text-decoration: none;
  transition: background-color 0.3s;
}

.header__search .hs-search-field__suggestions li a:hover {
  background-color: rgba(255, 255, 255, 0.1);
}

.header__search .hs-search-field__suggestions #results-for {
  display: none;
}

@media (min-width: 767px) {
  .header__search form {
    align-items: center;
    display: flex;
    flex-direction: row;
  }

  .header__search label {
    margin: 0 1rem 0 0;
    color: var(--os-nav-text);
  }

  .header__search .hs-search-field__input {
    width: auto;
  }
}

@media (max-width: 767px) {
  .header__search {
    border-top: 1px solid var(--os-border-strong);
    order: 1;
    padding: 1.05rem;
  }
}

/* Language switcher */

.header__language-switcher {
  cursor: pointer;
  padding-right: 1.4rem;
}

.header__language-switcher .lang_switcher_class {
  position: static;
}

.header__language-switcher .lang_list_class {
  border: 1px solid var(--os-border-strong);
  border-radius: 8px;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
  display: block;
  left: calc(100% - 24px);
  opacity: 0;
  min-width: 100px;
  padding-top: 0;
  text-align: left;
  top: 100%;
  transition: opacity 0.3s;
  visibility: hidden;
  background-color: var(--os-bg);
}

.header__language-switcher:hover .lang_list_class,
.header__language-switcher:focus .lang_list_class {
  opacity: 1;
  transition: opacity 0.3s;
  visibility: visible;
}

.header__language-switcher .lang_list_class:before {
  left: 70%;
  top: -25px;
}

.header__language-switcher .lang_list_class:after {
  left: 70%;
  top: -22px;
}

.header__language-switcher .lang_list_class.first-active::after {
  top: -22px;
  transition: 0.3s;
}

.header__language-switcher .lang_list_class li {
  border: none;
  font-size: 18px;
  padding: 0.35rem 0.7rem;
  color: var(--os-nav-text);
}

.header__language-switcher .lang_list_class li:first-child {
  border-radius: 8px 8px 0 0;
  border-top: none;
}

.header__language-switcher .lang_list_class li:last-child {
  border-bottom: none;
  border-radius: 0 0 8px 8px;
}

.header__language-switcher .lang_list_class li:hover {
  background-color: rgba(255, 255, 255, 0.1);
  transition: background-color 0.3s;
}

.header__language-switcher--label {
  display: flex;
  position: relative;
}

.header__language-switcher--label-current {
  align-items: center;
  display: flex;
  font-size: 0.75rem;
  margin-bottom: 0.175rem;
  margin-left: 0.7rem;
  color: var(--os-nav-text);
}

.header__language-switcher--label-current:after {
  border-left: 4px solid transparent;
  border-right: 4px solid transparent;
  border-top: 6px solid var(--os-nav-text);
  content: "";
  display: block;
  height: 0px;
  margin-left: 0.7rem;
  margin-top: 0.175rem;
  width: 0px;
}

@media (max-width: 767px) {
  .header__language-switcher {
    border-top: 1px solid var(--os-border-strong);
    padding-left: 1.05rem;
    padding-right: 0;
  }

  .header__language-switcher .lang_list_class {
    border: none;
    box-shadow: unset;
    display: block;
    left: 30px;
    opacity: 1;
    padding: 0 1.05rem;
    top: 0;
    visibility: visible;
  }

  .header__language-switcher .lang_list_class li {
    background-color: inherit;
    font-size: 0.917rem;
  }

  .header__language-switcher--label-current {
    display: none;
  }

  .header__language-switcher .globe_class {
    background-image: none;
  }

  .header__language-switcher .lang_list_class li:hover{
    background-color: inherit;
  }

  .header__language-switcher .lang_list_class:before,
  .header__language-switcher .lang_list_class:after {
    content: none;
  }
    .header__language-switcher .hs-language-switcher__menu {
        display: block;
        box-shadow:none!important;
        background: transparent;
    }
    .header__language-switcher .hs-language-switcher__menu a {
        font-size: 20px!important;
        color: var(--os-nav-text);
    }
    .header__language-switcher .hs-language-switcher__button {
        display: none;
    }
  }

/* Navigation */

#nav-toggle {
  display: none;
}

/* Mobile toggles */

@media (max-width: 767px) {
  .header__navigation,
  .header__search,
  .header__language-switcher {
    display: none;
    width: 100%;
  }

  .header__navigation.open,
  .header__search.open,
  .header__language-switcher.open {
    background-color: var(--os-bg);
    display: block;
    left: 0;
    min-height: calc(100vh - 115px);
    position: absolute;
    right: 0;
    top: 75px;
    z-index: 2;
  }

  .header__navigation--toggle,
  .header__search--toggle,
  .header__language-switcher--toggle,
  .header__close--toggle {
    cursor: pointer;
    margin: 0 5vw;
    position: relative;
  }

  .header__navigation--toggle.hide,
  .header__search--toggle.hide,
  .header__language-switcher--toggle.hide {
    display: none;
  }

  .header__navigation--toggle.open,
  .header__search--toggle.open,
  .header__language-switcher--toggle.open {
    display: block;
    margin-left: 0;
    margin-right: auto;
  }

  .header__navigation--toggle:after,
  .header__search--toggle:after,
  .header__language-switcher--toggle:after {
    display: none;
    font-size: 1.083rem;
    font-weight: 600;
    position: absolute;
    left: 40px;
    text-transform: uppercase;
    top: -10px;
    color: var(--os-nav-text);
  }

  .header__navigation--toggle.open:after,
  .header__search--toggle.open:after,
  .header__language-switcher--toggle.open:after {
    display: block;
    word-break: normal;
  }

  /* Hamburger icon — uses CSS filter to invert to white for dark nav */
  .header__navigation--toggle {
    background-image: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48c3ZnIHdpZHRoPSIyNHB4IiBoZWlnaHQ9IjI0cHgiIHZpZXdCb3g9IjAgMCAyNCAxOSIgdmVyc2lvbj0iMS4xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIj4gICAgICAgIDx0aXRsZT5oYW1idXJnZXI8L3RpdGxlPiAgICA8ZGVzYz5DcmVhdGVkIHdpdGggU2tldGNoLjwvZGVzYz4gICAgPGcgaWQ9ImhhbWJ1cmdlciIgc3Ryb2tlPSJub25lIiBzdHJva2Utd2lkdGg9IjEiIGZpbGw9Im5vbmUiIGZpbGwtcnVsZT0iZXZlbm9kZCI+ICAgICAgICA8ZyBpZD0iR3JvdXAiIHN0cm9rZT0iIzQ5NEE1MiIgc3Ryb2tlLXdpZHRoPSIzIj4gICAgICAgICAgICA8cmVjdCBpZD0iUmVjdGFuZ2xlIiB4PSIxLjUiIHk9IjEuNSIgd2lkdGg9IjIxIiBoZWlnaHQ9IjEiIHJ4PSIwLjUiPjwvcmVjdD4gICAgICAgICAgICA8cmVjdCBpZD0iUmVjdGFuZ2xlLUNvcHktNCIgeD0iMS41IiB5PSI5LjUiIHdpZHRoPSIyMSIgaGVpZ2h0PSIxIiByeD0iMC41Ij48L3JlY3Q+ICAgICAgICAgICAgPHJlY3QgaWQ9IlJlY3RhbmdsZS1Db3B5LTUiIHg9IjEuNSIgeT0iMTcuNSIgd2lkdGg9IjIxIiBoZWlnaHQ9IjEiIHJ4PSIwLjUiPjwvcmVjdD4gICAgICAgIDwvZz4gICAgPC9nPjwvc3ZnPg==);
    background-size: cover;
    height: 25px;
    width: 25px;
    filter: brightness(0) invert(1);
  }

  .header__navigation--toggle:after {
    content: "Menu";
  }

  .header__language-switcher--toggle {
    background-image: url(//static.hsappstatic.net/cos-LanguageSwitcher/static-1.1/img/globe.png);
    background-size: cover;
    height: 25px;
    width: 25px;
    filter: brightness(0) invert(1);
  }

  .header__language-switcher--toggle:after {
    content: "Language";
  }

  .header__search--toggle {
    background-image: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48c3ZnIHdpZHRoPSIyNHB4IiBoZWlnaHQ9IjI0cHgiIHZpZXdCb3g9IjAgMCAyNCAyNCIgdmVyc2lvbj0iMS4xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIj4gICAgICAgIDx0aXRsZT5TZWFyY2g8L3RpdGxlPiAgICA8ZGVzYz5DcmVhdGVkIHdpdGggU2tldGNoLjwvZGVzYz4gICAgPGRlZnM+ICAgICAgICA8cGF0aCBkPSJNOS4xMzg2MTUzNCwxNS44OTI1Njg1IEM1LjQxMzk1NzQyLDE1Ljg5MjU2ODUgMi4zODM4ODUyNywxMi44NjM0NDc1IDIuMzgzODg1MjcsOS4xMzkwMDM3NiBDMi4zODM4ODUyNyw1LjQxNDU2MDA1IDUuNDEzOTU3NDIsMi4zODM4ODUyNyA5LjEzODYxNTM0LDIuMzgzODg1MjcgQzEyLjg2MzI3MzMsMi4zODM4ODUyNyAxNS44OTI1Njg1LDUuNDE0NTYwMDUgMTUuODkyNTY4NSw5LjEzOTAwMzc2IEMxNS44OTI1Njg1LDEyLjg2MzQ0NzUgMTIuODYzMjczMywxNS44OTI1Njg1IDkuMTM4NjE1MzQsMTUuODkyNTY4NSBNOS4xMzg3NTI0NSwyLjQzMzYwODg3ZS0xMyBDMTQuMTc3OTk1NSwyLjQzMzYwODg3ZS0xMyAxOC4yNzY0NTM3LDQuMTAwMzI0NzEgMTguMjc2NDUzNyw5LjEzOTI3Nzk2IEMxOC4yNzY0NTM3LDExLjIyOTgyMTEgMTcuNTcxMDE2OSwxMy4xNTg0NDM0IDE2LjM4NTYzMTMsMTQuNjk5NjY5NiBMMjMuNjUwODg4MSwyMS45NjUyMjY2IEMyNC4xMTYzNzA2LDIyLjQzMDcwOTIgMjQuMTE2MzcwNiwyMy4xODU0MDU1IDIzLjY1MDg4ODEsMjMuNjUwODg4MSBDMjMuMTg1NDA1NSwyNC4xMTYzNzA2IDIyLjQzMDcwOTIsMjQuMTE2MzcwNiAyMS45NjUyMjY2LDIzLjY1MDg4ODEgTDE0LjY5OTgxMzMsMTYuMzg1NDcxMyBDMTMuMTU4NDQwNSwxNy41NzA5NTA5IDExLjIyOTU3MzgsMTguMjc2NDUzNyA5LjEzODc1MjQ1LDE4LjI3NjQ1MzcgQzQuMDk5NTA5MzgsMTguMjc2NDUzNyAtMy43MzAzNDkzNmUtMTQsMTQuMTc4MjMxMiAtMy43MzAzNDkzNmUtMTQsOS4xMzkyNzc5NiBDLTMuNzMwMzQ5MzZlLTE0LDQuMTAwMzI0NzEgNC4wOTk1MDkzOCwyLjQzMzYwODg3ZS0xMyA5LjEzODc1MjQ1LDIuNDMzNjA4ODdlLTEzIFoiIGlkPSJwYXRoLTEiPjwvcGF0aD4gICAgPC9kZWZzPiAgICA8ZyBpZD0iU2VhcmNoIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMSIgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIj4gICAgICAgIDxtYXNrIGlkPSJtYXNrLTIiIGZpbGw9IndoaXRlIj4gICAgICAgICAgICA8dXNlIHhsaW5rOmhyZWY9IiNwYXRoLTEiPjwvdXNlPiAgICAgICAgPC9tYXNrPiAgICAgICAgPHVzZSBpZD0iSWNvbnMvQWN0aW9ucy9TZWFyY2giIGZpbGw9IiM0OTRBNTIiIHhsaW5rOmhyZWY9IiNwYXRoLTEiPjwvdXNlPiAgICA8L2c+PC9zdmc+);
    background-size: cover;
    height: 25px;
    width: 25px;
    filter: brightness(0) invert(1);
  }

  .header__search--toggle:after {
    content: "Search";
  }

  .header__close--toggle {
    background-image: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48c3ZnIHdpZHRoPSIyNHB4IiBoZWlnaHQ9IjE5cHgiIHZpZXdCb3g9IjAgMCAyNCAxOSIgdmVyc2lvbj0iMS4xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIj4gICAgICAgIDx0aXRsZT5jbG9zZTwvdGl0bGU+ICAgIDxkZXNjPkNyZWF0ZWQgd2l0aCBTa2V0Y2guPC9kZXNjPiAgICA8ZyBpZD0iY2xvc2UiIHN0cm9rZT0ibm9uZSIgc3Ryb2tlLXdpZHRoPSIxIiBmaWxsPSJub25lIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiPiAgICAgICAgPGcgaWQ9Ikdyb3VwIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgyLjAwMDAwMCwgLTEuMDAwMDAwKSIgc3Ryb2tlPSIjNDk0QTUyIiBzdHJva2Utd2lkdGg9IjMiPiAgICAgICAgICAgIDxyZWN0IGlkPSJSZWN0YW5nbGUiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDEwLjAwMDAwMCwgMTAuNTAwMDAwKSByb3RhdGUoLTQ1LjAwMDAwMCkgdHJhbnNsYXRlKC0xMC4wMDAwMDAsIC0xMC41MDAwMDApICIgeD0iLTAuNSIgeT0iMTAuNSIgd2lkdGg9IjIxIiBoZWlnaHQ9IjEiIHJ4PSIwLjUiPjwvcmVjdD4gICAgICAgICAgICA8cmVjdCBpZD0iUmVjdGFuZ2xlLUNvcHktNSIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMTAuMDAwMDAwLCAxMC41MDAwMDApIHJvdGF0ZSg0NS4wMDAwMDApIHRyYW5zbGF0ZSgtMTAuMDAwMDAwLCAtMTAuNTAwMDAwKSAiIHg9Ii0wLjUiIHk9IjEwLjUiIHdpZHRoPSIyMSIgaGVpZ2h0PSIxIiByeD0iMC41Ij48L3JlY3Q+ICAgICAgICA8L2c+ICAgIDwvZz48L3N2Zz4=);
    background-repeat: no-repeat;
    background-size: 110%;
    display: none;
    height: 25px;
    margin-right: 0;
    width: 25px;
    filter: brightness(0) invert(1);
  }

  .header__close--toggle.show {
    display: block;
  }
}

/* HEADER HEIGHT, published as a token so a section can bleed up behind the header
   (see _cover-cta's "Bleed behind header"). MEASURED, not derived: the rendered
   no-nav header came to 99px on Othership at 1200px wide — padding-block 1.45rem
   twice, plus whichever of the logo box or the CTA button is taller. There is no
   CSS expression for "whichever is taller", so this is a pin, and it is wrong the
   moment the header's padding or the logo cap changes materially. Every consumer
   passes a fallback, so a brand that never sets it still renders sensibly. */
:root { --os-header-h: 6.1875rem; }

/* Header CTA slot (theme.header.cta_show) — converged button classes do the
   styling; this only places it in the nav row. */
.header__cta { margin-left: 20px; white-space: nowrap; }

/* When the CTA slot holds a dnd_area (a per-page, marketer-editable button
   rather than a theme field — see DF LP1), HubSpot wraps the dropped module in
   its own row/column divs, which default to width:100%. Shrink the whole chain to
   content so the slot hugs the rail and nothing stretches this flex child. Lives
   in _base so every brand's header CTA behaves the same, not just the page that
   hit it. */
.header__cta .dnd-section { padding: 0; }

/* The dnd CTA (LP / no-nav header) is ALWAYS RIGHT-ALIGNED and GROWS LEFTWARD
   (Tom, 2026-08-23): the header is logo-left / CTA-right, so the button's right
   edge stays on the rail while a longer label extends inward.

   Mechanism that survives HubSpot's dnd markup: the slot takes the space to the
   RIGHT of the logo (flex:1) and right-aligns its text; the injected row/column
   wrappers are forced FULL-WIDTH with text-align:right, so the alignment reaches
   the inline-block <a>, which lands at the right edge and widens inward. This
   overrides HubSpot's dnd-column centring (the _button module emits no alignment
   of its own unless a marketer sets one).

   An earlier attempt shrank the wrappers and used justify-content:flex-end; it
   stayed centred on the live page because a wrapper HubSpot forces to width:100%
   defeats flex-end. Embracing full-width + text-align:right is what actually bites.

   Scoped to .header--no-navigation (the LP / blank-canvas header that carries the
   dnd CTA) so the plain <a class="button header__cta"> in the full nav header is
   untouched. */
.header--no-navigation .header__cta { flex: 1 1 auto; text-align: right; }
.header--no-navigation .header__cta .dnd-section,
.header--no-navigation .header__cta .row-fluid-wrapper,
.header--no-navigation .header__cta .row-fluid,
.header--no-navigation .header__cta .dnd-column,
.header--no-navigation .header__cta .span12,
.header--no-navigation .header__cta .button-wrapper { width: 100%; text-align: right; }

/* THE CTA WAS OFF THE RAIL BY ONE GUTTER (Tom, 2026-08-24: "not fully right
   aligned", raised repeatedly — this is the cause). The CTA slot embeds a
   dnd_area, so HubSpot generates a nested `.dnd-section > .row-fluid` INSIDE the
   slot, and objects/_containers-dnd.css puts THE RAIL — max-width + centre +
   `padding-inline: --os-section-pad-h` — on EVERY `.dnd-section > .row-fluid`.
   The header container already rails the slot, so this inner one DOUBLE-applies:
   the button is inset one extra `--os-section-pad-h` on the right and never
   reaches the rail edge. The reset above zeroed `.dnd-section` padding but not
   this inner `.row-fluid`, which is where the gutter actually lives (see
   _containers-dnd.css:28-32). Kill the inner rail — the slot is already railed. */
.header__cta .dnd-section > .row-fluid {
  max-width: none;
  margin-inline: 0;
  padding-inline: 0;
}

/* ============================================================
   THEME.HEADER.* SETTINGS — the values, beside the rules they drive

   The RULES for .header--frosted and .header__logo--animated are further down
   this file. The VALUES they need used to live in blank-canvas.html's own
   inlined `the header block`, which meant every OTHER template got the
   classes with nothing driving them: the One-Off Shell showed no frost and no
   animation, and the whole Global-styles > Header panel looked dead
   (Tom, 2026-09-03).

   Moving them to the partial fixed the Shell but left blank-canvas holding a
   duplicate — two places to maintain one behaviour. They live HERE instead,
   because this file is where the rules are and every template loads it through
   main.css. Theme CSS is HubL-processed — theme-overrides.css already reads
   theme values, and this file already gates on get_asset_version — so the
   fields are readable at this layer.

   DO NOT WRITE HUBL DELIMITERS IN THESE COMMENTS. A CSS comment is not a HubL
   comment: the renderer parses tag delimiters inside it and fails the whole
   sheet. This exact block broke the build on 2026-09-03 by quoting them as
   examples, which is the same hazard the SP2 note records ("HubL delimiters in
   comments silently unlist a _base sheet"). Name the mechanism in prose
   instead.

   WHY NOT THE PARTIAL. blank-canvas CANNOT use the partial for its header, and
   that is deliberate, not an oversight: SPEC-021 BF-PLAT-02 — "a dnd_area
   inside a global_partial is GLOBAL content, one shared value across every page
   using that partial." Its header-cta must be PER PAGE (Tom's spec: a marketer
   sets the header CTA per page), so it inlines the markup, exactly as DF LP1
   does. Sharing the CSS is possible; sharing the markup is not.

   Authored --os-*; the build rewrites to the brand's own prefix.
   ============================================================ *//* Breathing room above the logo/CTA line (Tom) — top only. */
.header--no-navigation .header__container { padding-top: 1.75rem; }

/* Logo padding (theme.header.logo_padding). */
.header--no-navigation .header__logo { padding: 6px; }

/* Sticky (theme.header.sticky). Field-GATED, which is the distinction that
   matters: this file deliberately declares no position on .header itself
   because a HARDCODED sticky (pre-2026-08-23) pinned every header regardless of
   the field and made the control decorative. Gated on the field, it is the
   field. */

.header--no-navigation { position: sticky; top: 0; z-index: 999; }



/* Frost STRENGTH. The effect itself is .header--frosted::before below; this is
   only the blur it reads. Blur alone — a CSS noise overlay read as a grey wash
   rather than grain, so it was dropped. */
.header--frosted { --os-frost-blur: 18px; }



/* ANIMATED LOGO SIZING, so the reveal's WORDMARK matches the static logo
   exactly (Tom, 2026-08-22: the two were visibly different sizes). An earlier
   attempt set `max-width: none` and a flat object width, cancelling the logo cap
   and rendering the wordmark ~69% too large.

   The reveal SVG's canvas is mostly empty — it carries the animation's vertical
   overhead. Measured from othership-logo-reveal-*.svg, viewBox="-20 -95 576 305",
   wordmark bbox x 0..505.2, y 52.4..164.4:
     wordmark width  505.2/576 = 87.7% of canvas
     wordmark height 112/305   = 36.7%
     empty above     147.4/305 = 48.3%   <- the overhead to pull back
   So a 110px wordmark needs a 110 x (576/505.2) = 125.4px object, with its box
   pulled up so the WORDMARK centres rather than the box. Verified live
   2026-09-03: object 125x66, wordmark slot 110x24.

   The ratios are properties of THAT asset, so they are tokens with the measured
   values as fallbacks — a brand shipping a differently-proportioned reveal
   overrides them in its own theme-overrides.css and nothing here changes. A
   brand with NO reveal asset never reaches the animated markup at all:
   https://50629780.fs1.hubspotusercontent-na1.net/hubfs/50629780/saas/othership/images/othership-logo-reveal-v0-normal.svg bakes to "" for it, which is falsy. */
.header--no-navigation .header__logo--animated {
  --os-logo-w:     calc(var(--os-header-logo-max, 122px) - (2 * 6px));
  --os-anim-obj-w: calc(var(--os-logo-w) * var(--os-anim-w-ratio, 1.14006));
  --os-anim-obj-h: calc(var(--os-anim-obj-w) * var(--os-anim-canvas-ratio, 0.52951));
  --os-anim-wm-h:  calc(var(--os-logo-w) * var(--os-anim-wm-ratio, 0.22167));
  --os-anim-left:  calc(var(--os-logo-w) * var(--os-anim-left-ratio, -0.03958));
  overflow: visible;
}
.header--no-navigation .header__logo--animated > a {
  position: relative; display: block; overflow: visible;
  width: var(--os-logo-w); height: var(--os-anim-wm-h);
}
.header--no-navigation .header__logo--animated object {
  position: absolute; pointer-events: none;
  left: var(--os-anim-left);
  width: var(--os-anim-obj-w);
  aspect-ratio: var(--os-anim-aspect, 576 / 305);
  height: auto;
  /* wordmark centre sits 66.689% down the canvas; pull the box up by the
     difference between that and half the slot */
  top: calc((var(--os-anim-wm-h) / 2)
           - (var(--os-anim-obj-h) * var(--os-anim-centre, 0.66689)));
}


/* ============================================================
   FROSTED HEADER (optional, theme.header.frosted)

   The header frosts THE PAGE BEHIND IT, not itself. That distinction is the whole
   implementation: `backdrop-filter` blurs whatever is painted behind the element,
   so it does nothing useful while the header still paints its own opaque
   background — you get a blur of one flat colour, which is a no-op. The first
   version of this shipped that way (Tom, 2026-08-23: "the header frosts what's
   underneath, not itself").

   So `.header--frosted` REMOVES the background and the hairline shadow. The
   header becomes glass. Page content only passes UNDERNEATH it when the header is
   pinned, so the blur only has anything to act on when "Sticky header" is also on —
   frosted does not force that, by design. At scroll-top there
   is nothing behind yet, so the bar reads as the tint alone and the effect
   arrives as you scroll — which is how a frosted nav is supposed to behave.

   Three layers, painted under the content:
     1. backdrop-filter    blurs the page showing through the now-glass header
     2. a masked tint      keeps the logo and CTA legible over arbitrary content
     3. feTurbulence grain breaks up the banding a wide blur gives on flat colour

   THE TAPER is the mask, not the geometry: two elliptical gradients anchored to
   the TOP-LEFT and TOP-RIGHT corners, opaque at their corner and fading toward
   the centre and downward, so the frost is deepest under the logo and the button
   and rises to clear glass through the middle. `mask-composite: add` unions them;
   without it the second gradient replaces the first and the left end loses its
   frost.

   THE VERTICAL EXTENT IS THE WHOLE TRICK, and getting it wrong is what produced a
   hard bottom lip. The rule is not "keep the mask short" — it is that the mask must
   reach FULL transparency INSIDE the layer, wherever the layer ends. Break that and
   the blur is cut mid-strength and the cut is a visible line.

   The numbers, for a 99px header with the layer at height: 180% (= ~178px):
     ellipse vertical radius  125% of 178px  = ~222px
     opaque through            20% of that   = ~44px
     fully transparent by      72% of that   = ~160px   <- 18px inside the layer
   So the blur is still about half strength at the header's own bottom edge (99px),
   continues softly over the top of the next section, and is gone by 160px. Nothing
   gets clipped because the layer runs to 178px.

   History: `190%` with `inset: 0` finished the fade at ~135px against a 99px box —
   cut, visible lip. `100%` with `inset: 0` was clean but stopped short of the header
   edge, which read as too tight. Re-check all three numbers together if the header's
   height changes materially; they are a set, not independent.

   No brand values: the tint mixes the brand's own --os-bg, and the whole thing is
   opt-in, so a brand that never sets the field ships nothing extra.
   ============================================================ */

/* Frosted stays IN FLOW and does NOT set position — it inherits whatever "Sticky
   header" decided. When sticky IS on, that is exactly right for two reasons at once:

     - sticky keeps the header in flow, so it reserves its own height and the top of
       the page is never hidden underneath it — no manual offset needed (Tom,
       2026-08-23: "ensure there is vertical offset when the header is made sticky");
     - once you scroll, following content passes UNDERNEATH it, which is the only
       moment the blur has anything to act on — "an effect implicit when scrolling".

   An earlier version forced `position: fixed` here, on the wrong reading that a
   sticky header can never have content behind it. It can: at rest there is nothing
   behind, on scroll there is. Fixed bought nothing and pushed the first section up
   under the header. Do not reintroduce it, and do not set position here at all —
   that is the Sticky field's job.

   WITH STICKY OFF the blur has nothing to act on, because nothing ever passes behind
   the header. That combination is legal and simply does nothing; the field's help text
   says so rather than the CSS silently compensating.

   Glass, not paint: the opaque background is what blocked the blur (a
   backdrop-filter can only blur what is painted behind it, and the header was
   painting its own --os-bg over the whole area), and the hairline shadow would draw
   a hard line across the clear centre the taper exists to create. Same specificity
   as `.header--no-navigation`, later in the file, so both win on source order. */
.header--frosted {
  background-color: transparent;
  box-shadow: none;
}

.header--frosted::before {
  content: "";
  position: absolute;
  /* EXTENDS BELOW THE HEADER, on purpose. Reaching the blur further down (Tom,
     2026-08-23) cannot be done by widening the mask alone: with `inset: 0` the layer
     stops at the header's own edge, so a mask that is still opaque there gets cut
     mid-strength and draws the hard lip we already removed once. Growing the box past
     the header lets the fade finish in open space instead.

     pointer-events: none matters more now — this overlaps the top of the first section,
     and must not eat its clicks. */
  top: 0;
  left: 0;
  right: 0;
  height: 180%;
  z-index: 0;
  pointer-events: none;

  /* `brightness()` DARKENS the frosted band, per brand, via --os-frost-dim
     (Tom, 2026-08-24: OS wants the glass with a touch more body). It multiplies
     the BACKDROP — the content showing through — so it dims a bright thing that
     scrolls under the header and is a no-op over flat colour. That is why it is
     brightness here and not a `background` veil: on a dark brand (OS `--os-bg` is
     #000) a veil is black-on-black and invisible, and a veil would also paint at
     rest, which this must not (see the "NOTHING IS PAINTED AT REST" note above).
     brightness paints nothing on its own — it only acts when there is a backdrop —
     so it keeps the at-rest-clear rule in every browser, fallback included, and
     rides the same scroll-gate opacity as the blur. Default 1 = unchanged; a brand
     opts in by setting its own `--<prefix>-frost-dim` below 1 in theme-overrides. */
  -webkit-backdrop-filter: blur(var(--os-frost-blur, 18px)) saturate(1.25) brightness(var(--os-frost-dim, 1));
  backdrop-filter: blur(var(--os-frost-blur, 18px)) saturate(1.25) brightness(var(--os-frost-dim, 1));

  /* VEIL — mixes --os-INK, deliberately, not --os-bg.
     Measured live 2026-08-23: on Othership --os-bg is #000 and the section behind
     the header is flat black (the framed CTA's glow sits at 50% 88%, near its own
     bottom). A --os-bg tint is therefore a black wash on black, and a blur of flat
     black is flat black — the whole effect computed correctly and was invisible.
     --os-ink is the brand's CONTRAST to --os-bg by definition, so this reads on a
     dark brand (light veil on black) and on a light one (dark veil on white)
     without either being hardcoded. Heaviest at the top where the logo and CTA are. */
  /* NOTHING IS PAINTED AT REST. No veil, no lip (Tom, 2026-08-23: "the gray sheen
     should also not be visible -- it's really just an effect implicit when
     scrolling"). Earlier versions carried a --os-ink veil and a feathered lip; both
     were visible on a still page, which is not what this is for. The ONLY thing this
     layer does now is blur, so the header reads as clear glass until something with
     detail scrolls under it — and the mask below is what shapes where that blur
     reaches. A veil is easy to add back if it turns out the glass needs body. */
  -webkit-mask-image:
    radial-gradient(115% 125% at 0% 0%,   #000 0%, #000 20%, transparent 72%),
    radial-gradient(115% 125% at 100% 0%, #000 0%, #000 20%, transparent 72%);
  mask-image:
    radial-gradient(115% 125% at 0% 0%,   #000 0%, #000 20%, transparent 72%),
    radial-gradient(115% 125% at 100% 0%, #000 0%, #000 20%, transparent 72%);
  -webkit-mask-composite: source-over;
  mask-composite: add;
}

/* NO GRAIN LAYER. There was one: a tiled feTurbulence data URI over the frosted area.
   It was removed 2026-08-23 (Tom: "seems to overlay grayishly when enabled ... leave it
   off altogether"), and the reason it could never be right is worth recording.

   What he wanted was the BLUR to be grainy. What a CSS layer can do is paint noise ON TOP
   of the blurred area, which on a dark ground reads as a grey wash no matter the blend
   mode — `overlay` is a no-op against pure black/white, `normal` is a haze, `soft-light`
   is a weaker haze.

   Actually graining the backdrop needs the backdrop itself run through an SVG filter
   chaining feGaussianBlur with feTurbulence — i.e. `backdrop-filter: url(#grain)`. CSS
   accepts that syntax; no current browser reliably implements url() filters for
   backdrop-filter (as opposed to plain `filter`, where it works). The alternative is
   sampling the backdrop into a canvas/WebGL pass and graining it there, which is a lot of
   machinery to hang off a page header.

   So: blur only. Do not re-add a noise overlay expecting it to look like grain. */

/* GATE THE BLUR ON SCROLL DEPTH (Tom, 2026-08-23: only after ~50% of the viewport).

   Done with a CSS scroll-driven animation, which is the performant answer: the
   `scroll()` timeline is evaluated by the compositor, so there is NO scroll listener, no
   JS, nothing on the main thread, and nothing to throttle. `animation-range: 50vh 60vh`
   means the keyframes run between those two scroll offsets; `both` fill holds the
   from-state below 50vh and the to-state above 60vh. So: no blur for the first half
   viewport, a short 10vh fade so it does not pop, then full blur.

   Opacity is what animates, not the blur radius. Opacity is a compositor property;
   interpolating `blur()` re-runs the filter every frame and is exactly the kind of thing
   that makes a header janky.

   PROGRESSIVE ENHANCEMENT, and the fallback is genuinely fine. Safari and Firefox do not
   support `animation-timeline` yet, so they skip this block and keep the ungated blur —
   which is already invisible at rest, because at scroll 0 there is nothing painted behind
   the header to blur. They lose the 0-50vh gating, not the effect.

   Reduced motion opts out entirely rather than snapping: someone who asked for less
   motion does not want a scroll-linked fade, and an ungated blur is the calmer result. */
@supports (animation-timeline: scroll()) {
  @media (prefers-reduced-motion: no-preference) {
    @keyframes zt-frost-in {
      from { opacity: 0; }
      to   { opacity: 1; }
    }
    .header--frosted::before {
      animation: zt-frost-in linear both;
      animation-timeline: scroll(root block);
      animation-range: 50vh 60vh;
    }
  }
}

/* Content above both layers. `isolation: isolate` is load-bearing, not tidiness:
   the animated logo is an <object> whose reveal animates opacity on several groups,
   each of which the browser promotes to its own composited layer. Over a
   backdrop-filter region those promoted layers made their tile boundaries VISIBLE as
   grey rectangles around the logo mid-animation (Tom's screenshot, 2026-08-23).
   Isolating the container gives the content its own compositing group so it stops
   sharing the backdrop layer with the glass underneath. */
.header--frosted .header__container {
  position: relative;
  z-index: 1;
  isolation: isolate;
}

/* Same reason, one level deeper: pin the animated logo to its own layer up front
   so the compositor is not creating and destroying one per animation step. */
.header--frosted .header__logo--animated,
.header--frosted .header__logo--animated object {
  transform: translateZ(0);
  backface-visibility: hidden;
}

/* No backdrop-filter: paint nothing rather than substitute a band. A visible
   stand-in would contradict the whole point — this effect is meant to be absent
   until something scrolls under it. */
@supports not (backdrop-filter: blur(1px)) {
  .header--frosted::before { background: none; }
}

/* Mobile: the bar is short and the two ends nearly touch, so a centre-clearing
   taper has no centre to clear. Flatten to one top-anchored fade. */
@media (max-width: 767px) {
  .header--frosted::before {
    -webkit-mask-image: linear-gradient(to bottom, #000 0%, #000 30%, transparent 78%);
    mask-image: linear-gradient(to bottom, #000 0%, #000 30%, transparent 78%);
  }
}
/* ============================================================
   Footer — shared brand chrome, using --os-* design tokens.

   Reads on a DARK footer band (e.g. Othership) AND a LIGHT one (DeskFlex,
   TillerStack): every colour derives from --os-footer-* or the brand accent
   (--os-accent-1), never a hardcoded ground. Two variants share this file:
     .footer            full site footer (brand + nav columns + meta + fleuron)
     .footer--minimal   slim single-row LP bar (overrides the block layout)
   Both inherit the accent shimmer seam (.footer::after) at the very page edge.
   ============================================================ */

.footer {
  position: relative;      /* anchors the bottom glow */
  background-color: var(--os-footer-bg);
  /* Optional per-brand footer background IMAGE over the bg colour — same treatment
     as the legacy OS emails (a pattern over a dark base). `, none` fallback keeps it
     out of the required-skin-roles set, so a brand that sets no image is unaffected.
     A brand opts in by setting `--<prefix>-footer-bg-image` in theme-overrides. */
  background-image: var(--os-footer-bg-image, none);
  background-position: center top;
  background-repeat: no-repeat;
  background-size: cover;
  color: var(--os-footer-text);
  font-family: var(--os-font-body);
}

/* Links: no default underline (nav reads as a list, not prose); accent on
   hover; a visible focus ring for keyboards on both light and dark grounds. */
.footer a {
  color: var(--os-footer-link);
  text-decoration: none;
  transition: color .15s ease;
}
.footer a:hover {
  color: var(--os-accent-1);
}
.footer a:focus-visible {
  outline: 2px solid var(--os-accent-1);
  outline-offset: 3px;
  border-radius: 2px;
}

/* GUTTER PARITY — the footer content rides the SAME rail as the header and the
   body dnd sections: --os-max-width capped, centred, inset by --os-section-pad-h.
   Declared explicitly here (not left to .content-wrapper alone) so parity holds
   by construction, exactly as .header__container does it. Vertical: full section
   pad on top; the bottom is intentionally large to hold the fleuron zone. */
.footer__container {
  position: relative;   /* lifts footer content above the bottom glow */
  z-index: 1;
  /* Ride the shared centred rail — the same --os-max-width + --os-section-pad-h as
     the header (both variants, now railed too) and the body dnd sections — so
     footer, header and body content share one centred column at every width,
     including screens wider than the rail (Tom, 2026-08-23). */
  max-width: var(--os-max-width);
  margin-inline: auto;
  padding-inline: var(--os-section-pad-h);
  padding-top: clamp(36px, 4.5vw, 56px);   /* the scheduler footer height, not the section rhythm (Tom, 2026-09-14) */
  padding-bottom: clamp(40px, 6vw, 76px);
}

/* --- Top region: brand block beside nav columns --- */
.footer__top {
  display: grid;
  grid-template-columns: minmax(220px, 1.3fr) 2fr;
  gap: clamp(32px, 5vw, 80px);
  align-items: start;
}

.footer__brand {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 16px;
}
.footer__logo img { display: block; max-width: 150px; height: auto; }
.footer__tagline {
  margin: 0;
  font-family: var(--os-font-head);
  font-size: 15px;
  font-weight: 600;
  color: var(--os-accent-1);
  max-width: 30ch;
}
.footer__social { display: flex; flex-wrap: wrap; gap: 22px; }
.footer__social a { display: inline-flex; width: 20px; height: 20px; opacity: .9; }
.footer__social a:hover { opacity: 1; }
.footer__social svg { width: 20px; height: 20px; display: block; }

/* Nav columns — flex so they always fill the rail and the last column's edge
   lines up with the flush-right meta row below, whatever the column count.
   Adding or removing a column just redistributes the row (scalable). */
.footer__nav {
  display: flex;
  flex-wrap: wrap;
  gap: clamp(24px, 3vw, 40px) clamp(32px, 4vw, 64px);
}
.footer__col { flex: 1 1 120px; min-width: 120px; }
/* Title + links both ride --os-footer-link (the brand's brighter footer colour,
   AA-legible where --os-footer-text is deliberately dim); the title is set apart
   by weight, tracking and case, not by a low opacity that would fail contrast. */
.footer__col-title {
  margin: 0 0 14px;
  font-family: var(--os-font-head);
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--os-footer-link);
}
.footer__links { margin: 0; padding: 0; list-style: none; }
.footer__links li { margin: 0 0 10px; }
.footer__links a { font-size: 14px; }

/* Hairline — mixed from the footer's own text colour so it reads on both a dark
   and a light band (page border tokens are tuned for light surfaces only). */
.footer__divider {
  width: 100%;
  height: 0;
  border-top: 1px solid color-mix(in srgb, var(--os-footer-text) 18%, transparent);
  margin: clamp(28px, 4vw, 44px) 0 clamp(18px, 2.5vw, 26px);
}

/* --- Meta row: legal + secondary links --- */
.footer__meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 12px 24px;
}
/* Address line (pin + street), stamped per brand from web_stamp.contact.address;
   absent for a brand that records none. Sits in the meta row beside the legal. */
.os-footer__address { margin: 0; font-size: 12px; color: var(--os-footer-text); opacity: 0.85;
  display: inline-flex; align-items: center; gap: 6px; }
/* Legal line reads at 0.85. At 0.65 it was too faint on a dark footer. */
.footer__legal {
  margin: 0;
  font-size: 12px;
  color: var(--os-footer-text);
  opacity: 0.85;
}
.footer__meta-links { display: flex; flex-wrap: wrap; gap: 20px; }
.footer__meta-links a { font-size: 12px; font-weight: 600; }

/* ============================================================
   BOTTOM GLOW (.footer::after) — the signature: a soft, globular brand-accent
   glow that emanates UP from the bottom edge of the page and dissolves into the
   footer ground. Not a line and not animated — a diffuse radial bleed, kept
   deliberately faint, offset slightly LEFT of centre.

   Sits BEHIND the footer content (the container is z-index:1), so the text reads
   over it. Uses --os-accent-1, so it's green on Othership and each brand's own
   accent elsewhere. There is no overflow:hidden on .footer, so on a slim footer
   the glow is free to rise past the top edge and feather out rather than being
   clipped into a hard band.
   ============================================================ */
.footer::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 0;
  height: clamp(140px, 17vw, 230px);
  pointer-events: none;
  background: radial-gradient(62% 120% at 40% 100%,
    color-mix(in srgb, var(--os-accent-1) 16%, transparent) 0%,
    color-mix(in srgb, var(--os-accent-1) 8%, transparent) 26%,
    color-mix(in srgb, var(--os-accent-1) 3%, transparent) 50%,
    transparent 76%);
}

/* --- Responsive --- */
@media (max-width: 767px) {
  .footer__top {
    grid-template-columns: 1fr;
    gap: clamp(28px, 8vw, 44px);
  }
  /* Columns go two-up and are allowed to shrink; without lowering the flex-basis
     and min-width here, three 120px columns force .footer__container wider than a
     phone viewport and .footer's overflow:hidden clips the last column. */
  .footer__nav { gap: 24px 20px; }
  .footer__col { flex: 1 1 40%; min-width: 40%; }
  /* Stack legal above the links, each on its own centred line, so a long legal
     string plus three links never overflow the clipped footer on a phone. */
  .footer__meta { flex-direction: column; justify-content: center; text-align: center; gap: 10px; }
  .footer__meta-links { justify-content: center; }
}

/* ------------------------------------------------------------
   Minimal LP footer (footer--minimal) — a slim single-row bar
   (logo - legal - links) for landing pages, overriding the
   block chrome above. Pairs with the no-nav header. Keeps the
   shimmer seam; drops the columns / fleuron (not in its markup).
   ------------------------------------------------------------ */
.footer--minimal .footer__container {
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: center;
  gap: 16px;
  text-align: left;
  padding-top: calc(var(--os-section-pad-v) * 0.5);
  padding-bottom: calc(var(--os-section-pad-v) * 0.5);
}
.footer--minimal .footer__logo img { max-width: 104px; }
.footer--minimal .footer__legal { margin: 0; }
.footer--minimal .footer__minimal-links { display: flex; gap: 20px; }
.footer--minimal .footer__minimal-links a { font-size: 12px; font-weight: 600; }
@media (max-width: 767px) {
  .footer--minimal .footer__container { flex-direction: column; text-align: center; gap: 10px; }
}
/* ============================================================
   Othership — Default Module Styles
   Menu, flyout, CTA, logo, and rich text defaults.
   Uses --os-* design tokens.
   ============================================================ */

/* Menu and simple menu */

.hs-menu-wrapper ul {
  display: flex;
  flex-wrap: wrap;
  list-style: none;
  margin: 0;
  padding-left: 0;
}

/* Horizontal menu */

.hs-menu-wrapper.hs-menu-flow-horizontal .hs-menu-children-wrapper {
  flex-direction: column;
}

@media (max-width: 767px) {
  .hs-menu-wrapper.hs-menu-flow-horizontal ul {
    flex-direction: column;
  }
}

/* Vertical menu */

.hs-menu-wrapper.hs-menu-flow-vertical ul {
  flex-direction: column;
}

/* Flyouts */

.hs-menu-wrapper.hs-menu-flow-vertical.flyouts ul {
  display: inline-flex;
}

@media (max-width: 767px) {
  .hs-menu-wrapper.hs-menu-flow-vertical ul {
    display: flex;
  }
}

.hs-menu-wrapper.flyouts .hs-item-has-children {
  position: relative;
}

.hs-menu-wrapper.flyouts .hs-menu-children-wrapper {
  left: -9999px;
  opacity: 0;
  position: absolute;
}

.hs-menu-wrapper.flyouts .hs-menu-children-wrapper a {
  display: block;
  white-space: nowrap;
}

.hs-menu-wrapper.hs-menu-flow-horizontal.flyouts .hs-item-has-children:hover > .hs-menu-children-wrapper {
  left: 0;
  opacity: 1;
  top: 100%;
}

.hs-menu-wrapper.hs-menu-flow-vertical.flyouts .hs-item-has-children:hover > .hs-menu-children-wrapper {
  left: 100%;
  opacity: 1;
  top: 0;
}

@media (max-width: 767px) {
  .hs-menu-wrapper.flyouts .hs-menu-children-wrapper,
  .hs-menu-wrapper.hs-menu-flow-horizontal.flyouts .hs-item-has-children:hover > .hs-menu-children-wrapper,
  .hs-menu-wrapper.hs-menu-flow-vertical.flyouts .hs-item-has-children:hover > .hs-menu-children-wrapper {
    left: 0;
    opacity: 1;
    position: relative;
    top: auto;
  }
}

/* CTA, logo, and rich text images */

.hs_cos_wrapper_type_cta img,
.hs_cos_wrapper_type_logo img,
.hs_cos_wrapper_type_rich_text img {
  height: auto;
  max-width: 100%;
}
/* ==========================================================================
   Section Heading — shared by all content block modules
   Used via: .os-section__heading > h2 + p
   Promoted to _base 2026-09-13 (Tom): the one brand-local sheet with a single
   variant across all sixteen web brands (ORCA-D-087, CL-19). The dark-ground
   muted colour was a grey hex literal in every brand copy; it is the ink-muted role.
   ========================================================================== */

.os-section__heading {
  text-align: center;
  margin-bottom: 48px;
}
.os-section__heading h2 {
  font-size: var(--os-h2-size);
  font-weight: 600;
  margin-bottom: 12px;
  line-height: 1.2;
}
.os-section__heading p {
  font-size: 18px;
  color: var(--os-text-muted);
  max-width: 560px;
  margin: 0 auto;
}
.os-section--dark .os-section__heading p { color: var(--os-ink-muted); }
/* ==========================================================================
   Stats / Counters
   Variants: dividers (default), cards, strip
   Preview: _docs/design-previews/stats-counters-design.html
   ========================================================================== */

.os-stats {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 32px;
  text-align: center;
}
.os-stats__item { flex: 1; }

.os-stats__number {
  font-size: 56px;
  font-weight: 800;
  line-height: 1.1;
  letter-spacing: -2px;
  margin-bottom: 8px;
}
.os-stats__label {
  font-size: 14px;
  text-transform: uppercase;
  letter-spacing: 2px;
  opacity: 0.6;
  font-weight: 500;
}
.os-stats__desc {
  font-size: 14px;
  color: var(--os-text-muted);
  margin-top: 8px;
  line-height: 1.5;
}
.os-section--dark .os-stats__desc { color: #777; }

/* Accent colors */
.os-stats__number--green { color: var(--os-color-green); }
.os-stats__number--blue  { color: var(--os-color-blue); }
.os-stats__number--pink  { color: var(--os-color-pink); }
.os-stats__number--light { color: var(--os-color-light); }
.os-stats__number--dark  { color: #000; }

/* --- Variant: Dividers --- */

.os-stats--dividers .os-stats__item + .os-stats__item {
  border-left: 1px solid var(--os-border-dark);
  padding-left: 32px;
}
.os-section--light .os-stats--dividers .os-stats__item + .os-stats__item,
.os-section--muted .os-stats--dividers .os-stats__item + .os-stats__item {
  border-left-color: var(--os-border-light);
}

/* --- Variant: Cards --- */

.os-stats--cards { gap: 16px; }
.os-stats--cards .os-stats__item {
  background: rgba(255,255,255,0.05);
  border-radius: var(--os-card-radius);
  padding: 40px 24px;
}
.os-section--light .os-stats--cards .os-stats__item,
.os-section--muted .os-stats--cards .os-stats__item {
  background: #fff;
  box-shadow: var(--os-shadow-sm);
}
.os-section--green .os-stats--cards .os-stats__item {
  background: rgba(0,0,0,0.08);
}

/* --- Variant: Compact Strip --- */

.os-stats--strip {
  justify-content: center;
  gap: 64px;
}
.os-stats--strip .os-stats__number {
  font-size: 40px;
  letter-spacing: -1px;
}
.os-stats--strip .os-stats__label { font-size: 12px; }

/* --- Strip: reduced section padding --- */
.os-section:has(.os-stats--strip) {
  padding-top: 56px;
  padding-bottom: 56px;
}

/* --- Responsive --- */

@media (max-width: 767px) {
  .os-stats {
    flex-wrap: wrap;
    gap: 24px;
  }
  .os-stats__item {
    flex: 1 1 calc(50% - 12px);
    min-width: 140px;
  }
  .os-stats__number { font-size: 40px; }
  .os-stats--dividers .os-stats__item + .os-stats__item {
    border-left: none;
    padding-left: 0;
  }
  .os-stats--strip { gap: 32px; }
  .os-stats--strip .os-stats__number { font-size: 32px; }
}

@media (max-width: 480px) {
  .os-stats__item { flex: 1 1 100%; }
}
/* ==========================================================================
   Blockquote / Pullquote
   Variants: centered (default), accent-border, card, statement, grid
   Preview: _docs/design-previews/blockquote-design.html
   ========================================================================== */

/* --- Base: Centered Large --- */

.os-blockquote {
  text-align: center;
  max-width: 680px;
  margin: 0 auto;
}
.os-blockquote__mark {
  font-size: 64px;
  line-height: 1;
  margin-bottom: 12px;
  color: var(--os-color-green);
}
.os-blockquote__text {
  font-size: 24px;
  font-weight: 500;
  font-style: italic;
  line-height: 1.5;
  margin-bottom: 24px;
}
.os-blockquote__attribution {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 16px;
  font-size: 14px;
}
.os-blockquote__avatar {
  width: 48px;
  height: 48px;
  border-radius: 50%;
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 18px;
  font-weight: 600;
  flex-shrink: 0;
  background: #333;
}
.os-blockquote__avatar img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.os-section--light .os-blockquote__avatar,
.os-section--muted .os-blockquote__avatar {
  background: #eee;
  color: #666;
}
.os-blockquote__cite { text-align: left; }
.os-blockquote__name {
  font-weight: 600;
  font-style: normal;
  display: block;
}
.os-section--light .os-blockquote__name,
.os-section--muted .os-blockquote__name {
  color: #000;
}
.os-blockquote__role {
  color: #999;
  font-style: normal;
  display: block;
  font-size: 13px;
}
.os-section--light .os-blockquote__role,
.os-section--muted .os-blockquote__role {
  color: var(--os-text-muted);
}

/* --- Variant: Accent Border --- */

.os-blockquote--border {
  text-align: left;
  max-width: 100%;
  padding-left: 32px;
  border-left: 4px solid var(--os-color-green);
}
.os-blockquote--border .os-blockquote__mark { display: none; }
.os-blockquote--border .os-blockquote__text { font-size: 22px; }
.os-blockquote--border .os-blockquote__attribution { justify-content: flex-start; }

/* --- Variant: Card --- */

.os-blockquote--card {
  max-width: 100%;
  background: rgba(255,255,255,0.04);
  border-radius: var(--os-card-radius);
  padding: 48px 40px;
}
.os-section--light .os-blockquote--card,
.os-section--muted .os-blockquote--card {
  background: #fff;
  box-shadow: var(--os-shadow-md);
}

/* --- Variant: Statement --- */

.os-blockquote--statement { max-width: 100%; }
.os-blockquote--statement .os-blockquote__mark {
  font-size: 80px;
  margin-bottom: 4px;
}
.os-blockquote--statement .os-blockquote__text {
  font-size: 32px;
  font-style: normal;
  font-weight: 700;
  line-height: 1.3;
  letter-spacing: -0.5px;
}
.os-blockquote--statement .os-blockquote__text em {
  font-style: normal;
  color: inherit;
  opacity: 0.5;
}
.os-section--dark .os-blockquote--statement .os-blockquote__text em {
  opacity: 0.5;
}
.os-section--green .os-blockquote--statement .os-blockquote__text em,
.os-section--blue .os-blockquote--statement .os-blockquote__text em,
.os-section--pink .os-blockquote--statement .os-blockquote__text em {
  color: rgba(0,0,0,0.5);
  opacity: 1;
}

/* --- Variant: Grid (side by side) --- */

.os-blockquotes-grid {
  display: grid;
  gap: 24px;
}
.os-blockquotes-grid--2 { grid-template-columns: repeat(2, 1fr); }
.os-blockquotes-grid--3 { grid-template-columns: repeat(3, 1fr); }
.os-blockquotes-grid--4 { grid-template-columns: repeat(4, 1fr); }

.os-blockquotes-grid .os-blockquote--card {
  text-align: left;
}
.os-blockquotes-grid .os-blockquote__text { font-size: 17px; }
.os-blockquotes-grid .os-blockquote__mark {
  font-size: 40px;
  margin-bottom: 8px;
  text-align: left;
}
.os-blockquotes-grid .os-blockquote__attribution {
  justify-content: flex-start;
}

/* --- Responsive --- */

@media (max-width: 767px) {
  .os-blockquotes-grid { grid-template-columns: 1fr !important; }
  .os-blockquote--statement .os-blockquote__text { font-size: 24px; }
  .os-blockquote--card { padding: 32px 24px; }
}

/* Utilities
Helper classes with ability to override anything that comes before it
*/

/* ============================================================
   Othership — Utility Classes
   Helper classes using --os-* design tokens.
   ============================================================ */

/* Screen reader only */

.show-for-sr {
  border: 0 !important;
  clip: rect(0, 0, 0, 0) !important;
  height: 1px !important;
  overflow: hidden !important;
  padding: 0 !important;
  position: absolute !important;
  white-space: nowrap !important;
  width: 1px !important;
}

@media (max-width: 767px) {
  .show-for-sr--mobile {
    border: 0 !important;
    clip: rect(0, 0, 0, 0) !important;
    height: 1px !important;
    overflow: hidden !important;
    padding: 0 !important;
    position: absolute !important;
    white-space: nowrap !important;
    width: 1px !important;
  }
}

/* Text colour utilities */

.os-text-dark   { color: var(--os-color-dark) !important; }
.os-text-light  { color: var(--os-color-light) !important; }
.os-text-muted  { color: var(--os-text-muted) !important; }
.os-text-green  { color: var(--os-color-green) !important; }
.os-text-blue   { color: var(--os-color-blue) !important; }
.os-text-pink   { color: var(--os-color-pink) !important; }

/* Background utilities */

.os-bg-dark     { background-color: var(--os-color-dark) !important; }
.os-bg-light    { background-color: var(--os-color-light) !important; }
.os-bg-muted    { background-color: var(--os-bg-muted) !important; }
.os-bg-green    { background-color: var(--os-color-green) !important; }
.os-bg-blue     { background-color: var(--os-color-blue) !important; }
.os-bg-pink     { background-color: var(--os-color-pink) !important; }

/* Text alignment */

.os-text-left   { text-align: left !important; }
.os-text-center { text-align: center !important; }
.os-text-right  { text-align: right !important; }

/* Spacing — margin-bottom */

.os-mb-0   { margin-bottom: 0 !important; }
.os-mb-xs  { margin-bottom: 4px !important; }
.os-mb-sm  { margin-bottom: 8px !important; }
.os-mb-md  { margin-bottom: 16px !important; }
.os-mb-lg  { margin-bottom: 24px !important; }
.os-mb-xl  { margin-bottom: 40px !important; }
.os-mb-2xl { margin-bottom: 64px !important; }

/* Spacing — margin-top */

.os-mt-0   { margin-top: 0 !important; }
.os-mt-xs  { margin-top: 4px !important; }
.os-mt-sm  { margin-top: 8px !important; }
.os-mt-md  { margin-top: 16px !important; }
.os-mt-lg  { margin-top: 24px !important; }
.os-mt-xl  { margin-top: 40px !important; }
.os-mt-2xl { margin-top: 64px !important; }

/* Spacing — padding */

.os-p-0    { padding: 0 !important; }
.os-p-sm   { padding: 8px !important; }
.os-p-md   { padding: 16px !important; }
.os-p-lg   { padding: 24px !important; }
.os-p-xl   { padding: 40px !important; }

/* Display */

.os-hidden { display: none !important; }