/* ===========================================================================
   LexHost public site — the whole stylesheet.
   ---------------------------------------------------------------------------
   This site used to be seven React pages rendered with MUI. It is now plain
   HTML, so the look MUI used to compute at runtime is written out here once:
   the design tokens, the typography scale, and the handful of components the
   marketing pages actually used (button, card, chip, avatar, table, accordion,
   text field).

   THE TOKENS ARE THE CONTRACT. Every value under :root is copied from
   apps/frontend/src/styles/tokens.ts, and the type scale below is MUI's own
   default scale with this project's weight overrides folded in. Change a colour
   in tokens.ts and it has to be changed here too, or the app and the marketing
   site drift apart — that is the price of not shipping a framework.

   Breakpoints are MUI's: sm 600, md 900, lg 1200.
   Spacing is MUI's: one unit = 8px, so `py: {xs: 6, md: 10}` is 48px / 80px.
   =========================================================================== */

:root {
  /* --- Colour (tokens.ts) ------------------------------------------------ */
  --primary: #138b3f;
  --primary-light: #3fbd6d;
  --primary-dark: #126d34;
  --primary-contrast: #ffffff;
  --secondary: #0f172a;

  --bg: #ffffff;
  --bg-paper: #ffffff;
  --bg-subtle: #f8fafc;

  --text: #0f172a;
  --text-secondary: #475569;
  --divider: #e2e8f0;
  --grey-200: #eeeeee;
  --grey-400: #bdbdbd;
  --grey-500: #9e9e9e;

  --tint-soft: rgba(19, 139, 63, 0.12);
  --tint-softer: rgba(19, 139, 63, 0.1);
  --primary-outline: rgba(19, 139, 63, 0.5);
  --primary-hover: rgba(19, 139, 63, 0.04);
  --action-hover: rgba(0, 0, 0, 0.04);
  --action-selected: rgba(0, 0, 0, 0.08);

  --footer-text: #cbd5e1;
  --footer-muted: #94a3b8;
  --footer-heading: #ffffff;
  --footer-border: rgba(255, 255, 255, 0.1);

  --error: #d32f2f;
  --error-bg: #fdeded;
  --success-bg: #edf7ed;
  --warning-bg: #fff4e5;
  --warning-text: #663c00;
  --success-text: #1e4620;
  --error-text: #5f2120;
  /* The set had no INFO pair, because nothing on the site had said anything
     merely informative until the SEO dialog's "where to make the change" note.
     MUI's own info palette, so it matches the same note in the dashboard. */
  --info-bg: #e5f6fd;
  --info-text: #014361;

  /* --- Shape & type ------------------------------------------------------ */
  --radius: 12px;
  --radius-card: 16px;
  --radius-btn: 10px;
  --font:
    "Roboto", "Helvetica Neue", Arial, -apple-system, BlinkMacSystemFont,
    sans-serif;

  /* MUI elevation 2 and 6 — the only two the marketing pages ever used. */
  --shadow-2:
    0 3px 1px -2px rgba(0, 0, 0, 0.2), 0 2px 2px 0 rgba(0, 0, 0, 0.14),
    0 1px 5px 0 rgba(0, 0, 0, 0.12);
  --shadow-6:
    0 3px 5px -1px rgba(0, 0, 0, 0.2), 0 6px 10px 0 rgba(0, 0, 0, 0.04),
    0 1px 18px 0 rgba(0, 0, 0, 0.02);

  --gradient-brand: linear-gradient(90deg, #138b3f, #3fbd6d);
  --gradient-hero-glow: radial-gradient(
    1200px 500px at 50% -10%,
    rgba(19, 139, 63, 0.1),
    rgba(255, 255, 255, 0)
  );

  /* Sticky header height, so anchored sections clear it. */
  --header-h: 64px;
}

/* --- Reset ---------------------------------------------------------------- */

*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
}

/* Someone who asked their OS not to animate should not be flung down a page. */
@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
  }
}

body {
  margin: 0;
  font-family: var(--font);
  font-size: 1rem;
  line-height: 1.5;
  color: var(--text);
  background: var(--bg);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  /* The footer is pinned to the bottom on a short page. */
  display: flex;
  flex-direction: column;
  min-height: 100vh;
}

main {
  flex: 1;
  /* A reveal that starts 40px to the side must not widen the page on a phone.
     `clip`, not `hidden`: it creates no scroll container, so the sticky and fixed
     photographs inside keep working, and no stacking context either. */
  overflow-x: clip;
}

img {
  max-width: 100%;
  border-style: none;
}

a {
  color: inherit;
}

h1,
h2,
h3,
h4,
h5,
h6,
p,
figure {
  margin: 0;
}

/* Titles are regular weight on every page — the browser's own bold on h1-h6
   included. */
h1,
h2,
h3,
h4,
h5,
h6 {
  font-weight: 400;
}

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

button {
  font: inherit;
  color: inherit;
}

/* Keyboard focus stays visible everywhere; a mouse click does not draw one. */
:focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: 2px;
}

/* `hidden` is how site.js hides things, and the browser's own rule for it is a
   plain `display: none` that ANY author `display` beats — `.card--fill` sets
   `display: flex`, so a filtered-out blog card stayed on screen. This is the
   one place !important is the right tool: it makes the attribute mean what it
   says everywhere. */
[hidden] {
  display: none !important;
}

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

/* --- Typography ----------------------------------------------------------
   MUI's default scale with this theme's weight and letter-spacing overrides.
   Class names match the `variant` they replace, so a page reads the same as
   the JSX it came from.                                                     */

.h2 {
  font-size: 3.75rem;
  font-weight: 400;
  line-height: 1.2;
  letter-spacing: -0.02em;
}

.h3 {
  font-size: 3rem;
  font-weight: 400;
  line-height: 1.167;
  letter-spacing: -0.01em;
}

.h4 {
  font-size: 2.125rem;
  font-weight: 400;
  line-height: 1.235;
}

.h5 {
  font-size: 1.5rem;
  font-weight: 400;
  line-height: 1.334;
}

.h6 {
  font-size: 1.25rem;
  font-weight: 400;
  line-height: 1.6;
}

.subtitle1 {
  font-size: 1rem;
  font-weight: 400;
  line-height: 1.75;
}

.subtitle2 {
  font-size: 0.875rem;
  font-weight: 500;
  line-height: 1.57;
}

.body1 {
  font-size: 1rem;
  font-weight: 400;
  line-height: 1.5;
}

.body2 {
  font-size: 0.875rem;
  font-weight: 400;
  line-height: 1.43;
}

.caption {
  font-size: 0.75rem;
  font-weight: 400;
  line-height: 1.66;
}

.overline {
  display: block;
  font-size: 0.75rem;
  font-weight: 700;
  line-height: 2.66;
  letter-spacing: 0.08333em;
  text-transform: uppercase;
}

/* The h2/h3 on a phone are set per page in the markup that needs it; these are
   the two the whole site shares, because a 60px headline does not fit 360px. */
@media (max-width: 899px) {
  .h2 {
    font-size: 2.25rem;
  }
  .h3 {
    font-size: 2rem;
  }
  .h4 {
    font-size: 1.75rem;
  }
}

.muted {
  color: var(--text-secondary);
}
.primary-text {
  color: var(--primary);
}
.bold {
  font-weight: 700;
}
.semibold {
  font-weight: 600;
}
.center {
  text-align: center;
}

/* --- Layout --------------------------------------------------------------- */

.container {
  width: 100%;
  max-width: 1200px;
  margin: 0 auto;
  padding-inline: 16px;
}

.container--md {
  max-width: 900px;
}

@media (min-width: 600px) {
  .container {
    padding-inline: 24px;
  }
}

/* py: {xs: 6, md: 10} — the section rhythm the whole site uses. */
.section {
  padding-block: 48px;
}

/* Extra air above a section — for copy that follows something full-screen and
   needs room to breathe before it starts. Sized against the viewport width, so
   the gap grows with the page rather than stepping at one breakpoint. */
.section--pad-top {
  padding-top: 10vw;
}

.section--tight {
  padding-block: 32px;
}

@media (min-width: 900px) {
  .section {
    padding-block: 80px;
  }
  .section--tight {
    padding-block: 48px;
  }
}

.band {
  background: var(--bg-subtle);
  border-top: 1px solid var(--divider);
}

.band--bottom {
  border-bottom: 1px solid var(--divider);
}

.band--plain {
  background: var(--bg);
}

/* An anchored section must clear the sticky header, or its heading lands
   underneath it. Same 80 the React pages used. */
[id] {
  scroll-margin-top: 80px;
}

.stack {
  display: flex;
  flex-direction: column;
}

.gap-1 {
  gap: 8px;
}
.gap-15 {
  gap: 12px;
}
.gap-2 {
  gap: 16px;
}
.gap-3 {
  gap: 24px;
}
.gap-4 {
  gap: 32px;
}

/* The centred eyebrow + heading + lede that opens most sections. */
.section-head {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
  text-align: center;
  margin-bottom: 40px;
}

.section-head .lede {
  max-width: 640px;
}

.section-head--left {
  align-items: flex-start;
  text-align: left;
}

/*
 * Every public page's hero is the same height: 80vh.
 *
 * `min-height`, not `height`, so a hero whose copy is taller than the viewport
 * — the products one on a short laptop, any of them at a large text size —
 * grows instead of spilling out of its own section. On the pages that carry
 * one, the parallax layer is absolutely positioned and sizes off the section,
 * so it follows this without anything further.
 *
 * Centring is what makes the extra height usable: the sections keep the padding
 * they had, which is now a minimum rather than the thing setting the height, and
 * the container sits in the middle of whatever is left. `.container` is already
 * `width: 100%` with `margin: 0 auto`, so it still centres horizontally as a
 * flex item.
 *
 * `vh` ignores the retracting toolbar on mobile browsers, so a phone hero is
 * about a tenth taller than the visible viewport on first paint; `dvh` is the
 * unit that tracks it, if that turns out to matter.
 */
.hero,
.product-hero,
.pricing-hero,
.blog-hero,
.sales-hero,
.contact-hero {
  min-height: 80vh;
  display: flex;
  align-items: center;
}

/* --- Grid ----------------------------------------------------------------
   `--cols` is the desktop column count; everything collapses to one column on
   a phone and (where asked) two on a tablet.                                */

.grid {
  display: grid;
  gap: 24px;
  grid-template-columns: 1fr;
}

.grid--tight {
  gap: 16px;
}

@media (min-width: 600px) {
  .grid--sm2 {
    grid-template-columns: repeat(2, 1fr);
  }
}

@media (min-width: 900px) {
  .grid--2 {
    grid-template-columns: repeat(2, 1fr);
  }
  .grid--3 {
    grid-template-columns: repeat(3, 1fr);
  }
  .grid--4 {
    grid-template-columns: repeat(4, 1fr);
  }
  .grid--5 {
    grid-template-columns: repeat(5, 1fr);
  }
  .grid--6 {
    grid-template-columns: repeat(6, 1fr);
  }
}

/* --- Icons ---------------------------------------------------------------
   Inline SVG, sized and coloured by CSS exactly as MUI's SvgIcon is.        */

.ico {
  width: 1em;
  height: 1em;
  font-size: 24px;
  fill: currentColor;
  flex-shrink: 0;
  display: inline-block;
  user-select: none;
}

.ico--sm {
  font-size: 18px;
}
.ico--xs {
  font-size: 14px;
}

/* --- Buttons -------------------------------------------------------------- */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  border: 1px solid transparent;
  border-radius: var(--radius-btn);
  padding: 8px 20px;
  font-family: inherit;
  font-size: 0.875rem;
  font-weight: 600;
  line-height: 1.75;
  text-decoration: none;
  text-transform: none;
  cursor: pointer;
  background: none;
  transition:
    background-color 0.2s,
    border-color 0.2s,
    box-shadow 0.2s,
    color 0.2s;
  white-space: nowrap;
}

.btn .ico {
  font-size: 20px;
}

.btn--lg {
  padding: 10px 22px;
  font-size: 0.9375rem;
}

.btn--sm {
  padding: 5px 14px;
  font-size: 0.8125rem;
}

/* A button whose label is a sentence rather than a word, for the few that are.
   `.btn` is `white-space: nowrap` because a button normally must not break, and
   an inline-flex box sizes to its content — so a long label keeps its own width
   and pushes out of a narrow screen instead of wrapping. This lets that one
   wrap: the text may break, the icons may fall onto their own line beside it,
   and `max-width` is what actually stops the box growing past its parent.
   `line-height` comes back down because a wrapped label sets several lines and
   the button's own 1.75 is spacing meant for exactly one. */
.btn--wrap {
  white-space: normal;
  flex-wrap: wrap;
  max-width: 100%;
  text-align: center;
  line-height: 1.4;
}

.btn--contained {
  background: var(--primary);
  color: var(--primary-contrast);
}

.btn--contained:hover {
  background: var(--primary-dark);
}

.btn--outlined {
  border-color: var(--primary-outline);
  color: var(--primary);
}

.btn--outlined:hover {
  border-color: var(--primary);
  background: var(--primary-hover);
}

/*
 * The one button on this site that is not brand green.
 *
 * It marks the free SEO check in the header, where every other item is either
 * plain text or the green "Get Started". Green would put it in the same sentence
 * as the sign-up and it is not one — it is a tool anybody can use without an
 * account — so it is the site's amber instead: outlined, so it stays quieter
 * than the filled call to action beside it while still not reading as another
 * nav link.
 *
 * The amber is the same #ed6c02 the SEO report uses for "needs work", which is
 * the only other place this colour appears.
 */
.btn--accent {
  border-color: #ed6c02;
  color: #b45309;
}

.btn--accent:hover {
  border-color: #b45309;
  background: rgba(237, 108, 2, 0.08);
}

.btn--text {
  color: var(--primary);
}

.btn--text:hover {
  background: var(--primary-hover);
}

/* Inherit-coloured text button — the header's "Log in", the blog's "Back". */
.btn--plain {
  color: var(--text);
}

.btn--plain:hover {
  background: var(--action-hover);
}

/* On a green or photographic band, the button inverts. */
.btn--onDark {
  background: #fff;
  color: var(--primary);
}

.btn--onDark:hover {
  background: rgba(255, 255, 255, 0.9);
}

.btn--onDarkOutlined {
  color: #fff;
  border-color: rgba(255, 255, 255, 0.6);
}

.btn--onDarkOutlined:hover {
  border-color: #fff;
  background: rgba(255, 255, 255, 0.08);
}

.btn[disabled],
.btn[aria-disabled="true"] {
  opacity: 0.5;
  pointer-events: none;
}

.btn-row {
  display: flex;
  flex-wrap: wrap;
  gap: 16px;
}

.btn-row--center {
  justify-content: center;
}

@media (max-width: 599px) {
  .btn-row--stack {
    flex-direction: column;
    align-items: stretch;
  }
}

/* --- Chips ---------------------------------------------------------------- */

.chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: 32px;
  padding-inline: 12px;
  border-radius: 16px;
  border: 1px solid transparent;
  font-size: 0.8125rem;
  font-weight: 600;
  line-height: 1;
  white-space: nowrap;
  background: var(--action-selected);
  color: var(--text);
  text-decoration: none;
}

.chip--sm {
  height: 24px;
  padding-inline: 8px;
  border-radius: 12px;
  font-size: 0.75rem;
}

.chip--outlined {
  background: transparent;
  border-color: var(--divider);
  color: var(--text);
}

.chip--primary {
  background: var(--primary);
  color: var(--primary-contrast);
}

.chip--primary-outlined {
  background: transparent;
  border-color: var(--primary-outline);
  color: var(--primary);
}

.chip--onDark {
  background: rgba(255, 255, 255, 0.16);
  color: #fff;
}

button.chip {
  cursor: pointer;
  font-family: inherit;
  transition:
    background-color 0.2s,
    border-color 0.2s,
    color 0.2s;
}

button.chip.chip--outlined:hover {
  background: var(--action-hover);
}

/* --- Cards ---------------------------------------------------------------- */

.card {
  background: var(--bg-paper);
  border: 1px solid var(--divider);
  border-radius: var(--radius-card);
  overflow: hidden;
}

.card--lift {
  transition:
    box-shadow 0.2s,
    transform 0.2s;
}

.card--lift:hover {
  box-shadow: var(--shadow-6);
  transform: translateY(-4px);
}

.card--fill {
  height: 100%;
  display: flex;
  flex-direction: column;
}

.card-body {
  padding: 24px;
}

.card-body--lg {
  padding: 24px;
}

@media (min-width: 900px) {
  .card-body--lg {
    padding: 32px;
  }
}

/* A whole card that is one link. MUI's CardActionArea, without the ripple. */
.card-link {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  height: 100%;
  color: inherit;
  text-decoration: none;
}

/* --- Avatars -------------------------------------------------------------- */

.avatar {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  background: var(--grey-400);
  color: #fff;
  font-size: 1.25rem;
  font-weight: 700;
  flex-shrink: 0;
  overflow: hidden;
}

.avatar--rounded {
  border-radius: var(--radius);
}

.avatar--tint {
  background: var(--tint-soft);
  color: var(--primary);
}

.avatar--primary {
  background: var(--primary);
  color: #fff;
}

.avatar--52 {
  width: 52px;
  height: 52px;
}
.avatar--48 {
  width: 48px;
  height: 48px;
}

/* --- Feature / check lists ------------------------------------------------ */

.checklist {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.check-row {
  display: flex;
  align-items: flex-start;
  gap: 8px;
}

.check-row .ico {
  color: var(--primary);
  margin-top: 2px;
}

/* --- Tables --------------------------------------------------------------- */

.table-wrap {
  background: var(--bg-paper);
  border: 1px solid var(--divider);
  border-radius: 4px;
  margin-inline: auto;
  overflow-x: auto;
}

.table-wrap--720 {
  max-width: 720px;
}
.table-wrap--860 {
  max-width: 860px;
}

table.tbl {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.875rem;
}

.tbl th,
.tbl td {
  padding: 16px;
  text-align: left;
  border-bottom: 1px solid var(--divider);
  vertical-align: middle;
}

.tbl th {
  font-weight: 500;
  line-height: 1.5rem;
}

.tbl thead th {
  font-weight: 700;
}

.tbl tbody tr:last-child td {
  border-bottom: none;
}

.tbl tbody tr:hover {
  background: var(--action-hover);
}

.tbl .num {
  text-align: right;
}

.tbl .tint-head th {
  background: var(--tint-soft);
}

/* The search box above the resource price list. */
.table-search {
  padding: 16px 16px 8px;
}

.table-empty td {
  color: var(--text-secondary);
  text-align: center;
  padding-block: 32px;
}

/* --- Accordion (the FAQ) --------------------------------------------------
   <details>/<summary>, so a question is open without JavaScript and the very
   first one is open on load exactly as MUI's `defaultExpanded` had it.      */

/* No border, and half the usual hover shadow — the same treatment as the home
   page's soft cards (`.card--soft`). */
.accordion {
  background: var(--bg);
  border: none;
  border-radius: 8px;
  margin-bottom: 12px;
  overflow: hidden;
  transition:
    box-shadow 0.2s,
    transform 0.2s;
}

.accordion:hover {
  box-shadow:
    0 3px 5px -1px rgba(0, 0, 0, 0.1), 0 6px 10px 0 rgba(0, 0, 0, 0.02),
    0 1px 18px 0 rgba(0, 0, 0, 0.01);
  transform: translateY(-2px);
}

.accordion > summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 12px 16px;
  min-height: 48px;
  cursor: pointer;
  list-style: none;
  font-size: 1rem;
  font-weight: 700;
  line-height: 1.75;
}

.accordion > summary::-webkit-details-marker {
  display: none;
}

.accordion > summary .ico {
  transition: transform 0.2s;
  color: var(--text-secondary);
}

.accordion[open] > summary .ico {
  transform: rotate(180deg);
}

.accordion-body {
  padding: 8px 16px 16px;
  color: var(--text-secondary);
}

/* --- Form fields ----------------------------------------------------------
   MUI's outlined TextField: a floating label is more machinery than this site
   needs, so the label sits above the box. Everything else — the radius, the
   focus ring, the helper line — matches.                                    */

.field {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.field > label {
  font-size: 0.875rem;
  font-weight: 600;
  color: var(--text);
}

.field .req {
  color: var(--error);
}

.field input,
.field select,
.field textarea {
  width: 100%;
  font-family: inherit;
  font-size: 1rem;
  line-height: 1.4375em;
  color: var(--text);
  background: var(--bg-paper);
  padding: 14px;
  border: 1px solid var(--divider);
  border-radius: 4px;
  transition:
    border-color 0.2s,
    box-shadow 0.2s;
}

.field textarea {
  resize: vertical;
}

.field select {
  appearance: none;
  -webkit-appearance: none;
  cursor: pointer;
  background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%23475569'%3E%3Cpath d='M7 10l5 5 5-5z'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 10px center;
  background-size: 24px;
  padding-right: 40px;
}

/* Fields inside a glass card are glass too — the same 70% white over a 5px
   blur as the card, so a form on a photograph does not read as white boxes
   cut out of the pane. */
.card--glass .field input,
.card--glass .field select,
.card--glass .field textarea {
  /* `background-color`, NOT the `background` shorthand: the shorthand resets
     `background-image`, and the select's chevron lives there. */
  background-color: rgba(255, 255, 255, 0.7);
  backdrop-filter: blur(5px);
  -webkit-backdrop-filter: blur(5px);
}

.field input:hover,
.field select:hover,
.field textarea:hover {
  border-color: var(--text);
}

.field input:focus,
.field select:focus,
.field textarea:focus {
  outline: none;
  border-color: var(--primary);
  box-shadow: inset 0 0 0 1px var(--primary);
}

.field .helper {
  font-size: 0.75rem;
  line-height: 1.66;
  color: var(--text-secondary);
  /* Reserved even when empty, so a row of fields does not jump when one of
     them starts showing an error. */
  min-height: 1.25em;
}

.field.is-invalid input,
.field.is-invalid select,
.field.is-invalid textarea {
  border-color: var(--error);
}

.field.is-invalid input:focus,
.field.is-invalid textarea:focus {
  box-shadow: inset 0 0 0 1px var(--error);
}

.field.is-invalid .helper {
  color: var(--error);
}

/* An input with a leading icon (the email boxes). */
.field .adorned {
  position: relative;
  display: flex;
  align-items: center;
}

.field .adorned .ico {
  position: absolute;
  left: 12px;
  font-size: 20px;
  color: var(--text-secondary);
  pointer-events: none;
}

.field .adorned input {
  padding-left: 42px;
}

.field--sm input,
.field--sm select,
.field--sm textarea {
  padding: 9px 12px;
  font-size: 0.875rem;
}

fieldset.radio-group {
  border: 0;
  margin: 0;
  padding: 0;
}

.radio-row {
  display: flex;
  flex-wrap: wrap;
  gap: 16px;
}

.radio-row label {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: 1rem;
  cursor: pointer;
}

.radio-row input[type="radio"] {
  accent-color: var(--primary);
  width: 20px;
  height: 20px;
  margin: 0;
}

/* The feature chips are checkboxes wearing a chip. */
.chip-check {
  position: relative;
  display: inline-flex;
}

.chip-check input {
  position: absolute;
  opacity: 0;
  width: 100%;
  height: 100%;
  margin: 0;
  cursor: pointer;
}

.chip-check span {
  display: inline-flex;
  align-items: center;
  height: 32px;
  padding-inline: 12px;
  border-radius: 16px;
  border: 1px solid var(--divider);
  font-size: 0.8125rem;
  font-weight: 600;
  transition:
    background-color 0.2s,
    border-color 0.2s,
    color 0.2s;
}

.chip-check input:checked + span {
  background: var(--primary);
  border-color: var(--primary);
  color: #fff;
}

.chip-check input:focus-visible + span {
  outline: 2px solid var(--primary);
  outline-offset: 2px;
}

/* --- Alerts --------------------------------------------------------------- */

.alert {
  display: flex;
  gap: 12px;
  padding: 6px 16px;
  border-radius: 4px;
  font-size: 0.875rem;
  line-height: 1.43;
  align-items: center;
  min-height: 48px;
}

.alert--success {
  background: var(--success-bg);
  color: var(--success-text);
}

.alert--error {
  background: var(--error-bg);
  color: var(--error-text);
}

.alert--warning {
  background: var(--warning-bg);
  color: var(--warning-text);
}

/* --- Divider -------------------------------------------------------------- */

.divider {
  border: 0;
  border-top: 1px solid var(--divider);
  margin: 0;
}

/* ===========================================================================
   Header
   =========================================================================== */

.header {
  position: sticky;
  top: 0;
  z-index: 1100;
  background: rgba(255, 255, 255, 0.7);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--divider);
}

.header .container {
  display: flex;
  align-items: center;
  gap: 16px;
  min-height: var(--header-h);
}

.logo {
  display: flex;
  align-items: center;
  gap: 8px;
  text-decoration: none;
  margin-right: auto;
}

.logo img {
  width: 34px;
  height: 34px;
  border-radius: 10px;
  display: block;
}

.logo span {
  font-size: 1.25rem;
  font-weight: 800;
  letter-spacing: -0.02em;
  color: var(--text);
}

.logo em {
  font-style: normal;
  color: var(--primary);
}

.logo--light span {
  color: #fff;
}

.nav {
  display: none;
  align-items: center;
  gap: 8px;
}

@media (min-width: 900px) {
  .nav {
    display: flex;
  }
}

.nav a.btn.is-active {
  font-weight: 700;
  color: var(--primary);
}

.nav-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  border: 0;
  border-radius: 50%;
  background: none;
  cursor: pointer;
  color: var(--text);
  margin-left: auto;
}

.nav-toggle:hover {
  background: var(--action-hover);
}

@media (min-width: 900px) {
  .nav-toggle {
    display: none;
  }
}

/* The mobile drawer. Hidden from assistive tech and from the tab order until
   it is opened — `inert` is set alongside `hidden` in site.js. */
.drawer-scrim {
  position: fixed;
  inset: 0;
  z-index: 1200;
  background: rgba(0, 0, 0, 0.5);
  opacity: 0;
  transition: opacity 0.2s;
}

.drawer-scrim.is-open {
  opacity: 1;
}

.drawer {
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  width: 260px;
  max-width: 85vw;
  background: var(--bg-paper);
  box-shadow: var(--shadow-6);
  transform: translateX(100%);
  transition: transform 0.2s;
  display: flex;
  flex-direction: column;
  overflow-y: auto;
}

.drawer-scrim.is-open .drawer {
  transform: translateX(0);
}

.drawer-head {
  padding: 16px;
}

.drawer-list a {
  display: block;
  padding: 12px 16px;
  text-decoration: none;
  font-size: 1rem;
}

.drawer-list a:hover {
  background: var(--action-hover);
}

.drawer-list a.is-active {
  background: var(--action-selected);
  font-weight: 700;
}

.drawer-actions {
  padding: 16px;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.drawer-actions .btn {
  width: 100%;
}

/* ===========================================================================
   Footer
   =========================================================================== */

.footer {
  background: var(--secondary);
  color: var(--footer-text);
  margin-top: 64px;
}

/* A page whose last section is a full-bleed photograph (the home page's areas)
   runs it straight into the footer, with no white gap between. */
.footer--flush {
  margin-top: 0;
}

.footer .container {
  padding-block: 48px;
}

.footer-grid {
  display: grid;
  gap: 32px;
  grid-template-columns: 1fr;
}

@media (min-width: 600px) {
  .footer-grid {
    grid-template-columns: repeat(2, 1fr);
  }
}

@media (min-width: 900px) {
  .footer-grid {
    /* md={4} md={2} md={2} md={4} of MUI's 12 columns. */
    grid-template-columns: 4fr 2fr 2fr 4fr;
  }
}

.footer h2,
.footer .footer-heading {
  color: var(--footer-heading);
  font-size: 0.875rem;
  font-weight: 400;
  line-height: 1.57;
  margin-bottom: 12px;
}

.footer p,
.footer .footer-muted {
  color: var(--footer-muted);
}

.footer-links {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.footer-links a {
  color: var(--footer-text);
  text-decoration: none;
  font-size: 0.875rem;
  line-height: 1.43;
  width: fit-content;
}

.footer-links a:hover {
  color: var(--footer-heading);
  text-decoration: underline;
}

.footer-social {
  display: flex;
  gap: 8px;
  margin-top: 16px;
}

.footer-social a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  border-radius: 50%;
  color: var(--footer-text);
}

.footer-social a:hover {
  color: var(--footer-heading);
  background: rgba(255, 255, 255, 0.08);
}

.footer-social .ico {
  font-size: 20px;
}

.footer-bottom {
  margin-top: 40px;
  padding-top: 24px;
  border-top: 1px solid var(--footer-border);
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  justify-content: space-between;
  color: var(--footer-muted);
  font-size: 0.75rem;
  line-height: 1.66;
}

/* ===========================================================================
   Home
   =========================================================================== */

.hero {
  position: relative;
  overflow: hidden;
  isolation: isolate;
  /* The copy, then the stats under it — a column, centred in the full screen. */
  flex-direction: column;
  justify-content: center;
  align-items: stretch;
}

/*
 * A PARALLAX LAYER, AND THE SLACK THE MOVEMENT SPENDS.
 *
 * The products, pricing and blog heroes use this (the home hero sits on a fixed
 * backdrop instead). The selector is `[data-parallax]` — the same marker
 * site.js looks for — so any later section that wants a drifting picture gets
 * the mechanics for free. One hook for both
 * halves means a layer can never be positioned here and skipped there.
 *
 * Overhanging its section by 20% top and bottom, which is the whole budget for
 * the movement: site.js translates the layer and clamps itself to the overhang
 * it measures off the live element, so changing the 20% changes how far the
 * picture can travel and nothing else. A layer that exactly filled its section
 * would uncover an edge the moment it moved.
 *
 * `background-size: cover` on a box 40% taller than the section crops the image
 * tighter than it would at the section's own height — that is the trade for the
 * slack, and on the hero shot it reads as a slightly closer view.
 *
 * A section holding one of these needs `position: relative`, `overflow: hidden`
 * and a `position: relative; z-index: 1` container, or the layer paints over
 * the copy.
 */
[data-parallax] {
  position: absolute;
  inset: -20% 0;
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
}

/* The products hero. Its copy is left-aligned on a pane of frosted glass over
   the page's fixed backdrop, which is anchored left — the empty white down the
   left of that picture is what the copy sits on. */
.product-hero {
  position: relative;
  overflow: hidden;
  isolation: isolate;
}

/*
 * Everything above "One platform for websites, apps and cloud servers" scrolls
 * over the page's fixed photograph: the hero, the product shortcuts and the six
 * product sections. They carry no background of their own, and their copy —
 * headings, intros, body text, the eyebrows and the feature lists — is white on
 * the scrim. The sections from the cut down keep their own backgrounds and their
 * own dark text.
 */
.product-band {
  position: relative;
  z-index: 1;
  color: #fff;
}

.product-band .product-detail .intro,
.product-band .product-detail .muted,
.product-band .body2,
.product-band h2,
.product-hero .product-hero-panel,
.product-hero .product-hero-panel .muted {
  color: #fff;
}

.product-band .product-detail .muted,
.product-hero .product-hero-panel .muted {
  opacity: 0.92;
}

/* The green that carries meaning steps up to the lighter brand green, which
   holds on the scrim: the eyebrows, the ticks and the headline's accent. */
.product-band .primary-text,
.product-band .check-row .ico,
.product-hero .primary-text {
  color: var(--primary-light);
}

/* The "Our products" chip on the scrim: a pane of its own — 20% white over a
   5px blur — so it reads as a tag rather than an outline on the photograph. */
.product-hero .chip {
  background: rgba(255, 255, 255, 0.2);
  backdrop-filter: blur(5px);
  -webkit-backdrop-filter: blur(5px);
  border-color: rgba(255, 255, 255, 0.4);
  color: #fff;
}

/* The shortcuts under the hero: outlined on the photograph rather than filled. */
.product-nav .product-nav-card {
  background: transparent;
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  border: 1px solid rgba(255, 255, 255, 0.5);
  color: #fff;
}

.product-nav .product-nav-card:hover {
  background: rgba(255, 255, 255, 0.12);
  border-color: #fff;
}

.product-hero .container {
  position: relative;
  z-index: 1;
  padding-top: 64px;
  padding-bottom: 48px;
}


/*
 * The product shortcuts, pulled up so they overlap the hero by 30%.
 *
 * The 30% is of the cards' own height, which is why that height is stated here
 * rather than left to the labels: a fixed height is what makes the fraction
 * mean anything, and `calc(var(--nav-card-h) * -0.3)` keeps the two numbers
 * tied together, so changing the height keeps the overlap at 30%.
 *
 * `position: relative` with a z-index lifts the row over the hero's parallax
 * layer, exactly as `.stats` does on the home page — the row is a sibling of
 * the hero, not a child, so the hero's `overflow: hidden` does not clip it.
 *
 * Six across is a desktop layout only. The generic grid falls back to one
 * column, which would be a six-card stack on a phone, so the small sizes get
 * their own progression: two up, then three, then all six.
 */
.product-nav {
  --nav-card-h: 88px;
  position: relative;
  z-index: 1;
  margin-top: calc(var(--nav-card-h) * -0.3);
  padding-bottom: 32px;
}

.product-nav .grid {
  grid-template-columns: repeat(2, 1fr);
}

@media (min-width: 600px) {
  .product-nav .grid {
    grid-template-columns: repeat(3, 1fr);
  }
}

@media (min-width: 900px) {
  .product-nav .grid {
    grid-template-columns: repeat(6, 1fr);
  }
}

/* The same glass as the stat cards, and grey for the same reason: below the
   hero the page is white, and a white pane on it would only read as a card
   across the part still standing on the photograph. */
.product-nav-card {
  height: var(--nav-card-h);
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: 12px;
  border: none;
  background: rgba(226, 232, 240, 0.7);
  color: var(--text);
  font-size: 0.875rem;
  font-weight: 600;
  line-height: 1.3;
  text-decoration: none;
  transition: background-color 0.2s;
}

.product-nav-card:hover {
  background: rgba(226, 232, 240, 0.95);
}

/* Same pane as the contact hero: 40% white over a 5px blur, sized to the copy
   it holds. `.section-head` centres its contents and carries a 40px bottom
   margin meant for a heading above a grid; neither applies to a hero panel, so
   the left modifier goes on in the markup and the margin comes off here. */
/* No pane: the copy sits straight on the darkened backdrop, in white. Only the
   width and padding remain, so nothing shifts. */
.product-hero-panel {
  max-width: 880px;
  margin-bottom: 0;
  padding: 32px 24px;
}

@media (min-width: 900px) {
  .product-hero-panel {
    padding: 40px;
  }
}

.hero .container:not(.stats) {
  position: relative;
  z-index: 1;
  padding-top: 80px;
  padding-bottom: 40px;
  display: flex;
}

@media (min-width: 900px) {
  .hero .container:not(.stats) {
    padding-top: 128px;
    padding-bottom: 56px;
    /* Desktop puts the copy on the left. The panel's own max-width is what
       leaves the right of the photograph showing. */
    justify-content: flex-start;
  }
}

/*
 * The copy sits straight on the darkened backdrop, in white — no pane, no blur.
 * The scrim is what the words read against. The panel keeps only its layout.
 */
/* The blur is the part both heroes share; the tint is not. Kept as one rule so
   the two panes cannot end up blurring by different amounts. */
.product-nav-card,
.card--glass {
  border-radius: var(--radius-card);
  backdrop-filter: blur(5px);
  -webkit-backdrop-filter: blur(5px);
}

.hero-panel {
  color: #fff;
}

.hero-panel {
  width: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 24px;
  text-align: center;
  padding: 32px 24px;
}

@media (min-width: 900px) {
  .hero-panel {
    max-width: 680px;
    align-items: flex-start;
    text-align: left;
    padding: 40px;
  }

  .hero-panel .btn-row {
    justify-content: flex-start;
  }
}

.hero h1 {
  font-size: 2.25rem;
  font-weight: 400;
  line-height: 1.2;
  letter-spacing: -0.02em;
}

/* Nothing in the hero panel is bold — the badge and the buttons included,
   which are 600 everywhere else on the site. */
.hero-panel .chip,
.hero-panel .btn {
  font-weight: 400;
}

@media (min-width: 900px) {
  .hero h1 {
    font-size: 3rem;
  }
}

/* "your business" — the one green phrase in the headline, in the lighter brand
   green, which holds against the scrim where the base green goes muddy. */
.hero h1 .accent {
  color: var(--primary-light);
}

.hero .lede {
  font-size: 1.25rem;
  font-weight: 400;
  line-height: 1.6;
  color: #fff;
  opacity: 0.92;
}

.hero-panel .caption.muted {
  color: #fff;
  opacity: 0.85;
}

/* Stats — the bottom of the hero, under the copy. */
.stats {
  position: relative;
  z-index: 1;
  padding-bottom: 48px;
}

@media (min-width: 900px) {
  .stats {
    padding-bottom: 80px;
  }
}

.stats .grid {
  grid-template-columns: repeat(2, 1fr);
}

/* Desktop: a row under the copy, 80% of the width it used to span, starting where
   the copy starts — the hero panel's own 40px inset. */
@media (min-width: 900px) {
  .stats .grid {
    grid-template-columns: repeat(4, 1fr);
    max-width: 80%;
    margin-inline-start: 40px;
  }
}

/* Outlined, not filled: no background and no blur, a 1px white edge, straight on
   the darkened hero photograph — the figure white and its label in the lighter
   brand green.

   `border` here rather than a narrower `.card` selector because these are the
   only cards with a white edge; the rest of the app's cards keep their grey one. */
.stat {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  /* 20% smaller than the 168px card these were, type included. */
  min-height: 134px;
  padding-inline: 13px;
  border: 1px solid #fff;
  background: transparent;
}

.stat .muted {
  color: var(--primary-light);
  font-size: 0.7rem;
}

/* Glass cards — the home page's service, product and testimonial cards: 70%
   white over the same 5px blur as the panels above, so the section behind each
   one shows through. */
.card--glass {
  background: rgba(255, 255, 255, 0.7);
}

/* Soft cards — no border, and a hover lift that casts half the shadow the other
   lifting cards do: the same three layers as --shadow-6, every alpha halved. A
   card without a border reads heavy under the full shadow. The glass cards are
   soft too; the home page's blog cards are soft without being glass. */
.card--glass,
.card--soft {
  border: none;
}

.card--glass.card--lift:hover,
.card--soft.card--lift:hover {
  box-shadow:
    0 3px 5px -1px rgba(0, 0, 0, 0.1), 0 6px 10px 0 rgba(0, 0, 0, 0.02),
    0 1px 18px 0 rgba(0, 0, 0, 0.01);
}

/* "What we do" on the home page — transparent over the home backdrop, the same
   photograph and scrim as the hero, so its heading is white. Its cards are glass
   and keep their dark text. */
/* Cards over a darkened photograph — the home page's "What we do", "Why LexHost"
   and sales-partner cards, and the partners page's "How it works" and partner
   stories: outlined, not
   glass — no background and no blur, a 1px white edge, and white copy. Scoped to
   those sections; the product and testimonial cards keep their glass. */
.services-band .card--glass,
.why-band .card--glass,
.sales-cta-band .card--glass,
.partners-how .card--glass,
.partners-stories .card--glass,
.pricing-credits .card--glass {
  background: transparent;
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  border: 1px solid #fff;
  color: #fff;
}

.services-band .card--glass .muted,
.why-band .card--glass .muted,
.sales-cta-band .card--glass .muted,
.partners-how .card--glass .muted,
.partners-stories .card--glass .muted,
.pricing-credits .card--glass .muted {
  color: #fff;
  opacity: 0.85;
}

/* The line between a story and its author, faint white on the scrim. */
.partners-stories .card--glass .divider {
  border-color: rgba(255, 255, 255, 0.3);
}

/* The ticks in the lighter green, which holds on the scrim. */
.services-band .card--glass .check-row .ico,
.sales-cta-band .card--glass .check-row .ico,
.partners-how .card--glass .check-row .ico {
  color: var(--primary-light);
}

/* Sales partners on the home page — two full screens, the invitation and then
   "How it works" with its three outlined cards, over ONE photograph that holds
   still while both scroll past.

   The photograph is sticky, not fixed: a `100vh` layer at `top: 0`, with the
   first part pulled up over it by `-100vh`. It holds still while the invitation
   scrolls away, and lets go the moment the second part fills the screen — from
   there the photograph and "How it works" scroll on together. (A `-100vh`
   margin on the photograph instead would shrink its margin box and keep it
   pinned a whole screen past the section, under the testimonials.) Pure CSS —
   the page's one scripted backdrop is the hero's. That is why the section has
   NO `overflow: hidden`: an ancestor that clips becomes the sticky element's
   scroller and it would never stick. */
/* The same sticky photograph under "Areas we serve", with cities in it. */
.sales-cta-band,
.areas-band {
  position: relative;
  isolation: isolate;
  color: #fff;
}

.sales-cta-bg,
.areas-bg {
  position: sticky;
  top: 0;
  height: 100vh;
  background: center / cover no-repeat;
}

.sales-cta-bg {
  background-image: url("/assets/img/sales_home.webp");
}

.areas-bg {
  background-image: url("/assets/img/cities.webp");
}

.sales-cta-part,
.areas-band > .container {
  position: relative;
  z-index: 1;
}

.sales-cta-bg + .sales-cta-part,
.areas-bg + .container {
  margin-top: -100vh;
}

/* Areas we serve, in white on the scrim: the states full white, the cities a
   step back so each state still heads its list. */
.areas-band .section-head,
.areas-band .section-head .primary-text,
.areas-band .section-head .muted {
  color: #fff;
}

.areas-band .section-head .muted {
  opacity: 0.92;
}

.areas-band .areas .city {
  color: rgba(255, 255, 255, 0.75);
}

.sales-cta-copy {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 16px;
  max-width: 680px;
  text-align: center;
}

@media (min-width: 900px) {
  .sales-cta-copy {
    align-items: flex-start;
    text-align: left;
  }
}

.sales-cta-copy p {
  opacity: 0.92;
}

.sales-cta-band .section-head,
.sales-cta-band .section-head .primary-text,
.sales-cta-band .section-head .muted {
  color: #fff;
}

.sales-cta-band .section-head .muted {
  opacity: 0.92;
}

/* "Why LexHost" — its own photograph under the shared scrim, a full screen tall,
   the heading and the four outlined cards centred in it. The home backdrop has
   faded out by here, so this is a plain section background, not a fixed layer. */
.why-band {
  position: relative;
  overflow: hidden;
  isolation: isolate;
  background: url("/assets/img/home_hero_1.webp") center / cover no-repeat;
}

.why-band .container {
  position: relative;
  z-index: 1;
}

.why-band .section-head,
.why-band .section-head .primary-text {
  color: #fff;
}

/* Each reason: its icon beside its copy, inside the card's padding. */
.why-item {
  display: flex;
  gap: 16px;
  padding: 24px;
}

/* An icon in a white circle, the whole disc at 80% opacity over a 5px blur of
   the photograph — the "What we do", "Why LexHost" and sales-partner cards. The icons' own
   white backgrounds disappear into the disc. */
.icon-disc {
  flex: 0 0 56px;
  width: 56px;
  height: 56px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: #fff;
  opacity: 0.8;
  backdrop-filter: blur(5px);
  -webkit-backdrop-filter: blur(5px);
}

.icon-disc img {
  display: block;
  width: 60%;
  height: 60%;
  object-fit: contain;
}

/* In "What we do" and on the SEO Check page the icon heads the card, centred
   above its title. */
.services-band .icon-disc,
/* 60% larger than the 56px disc the other pages use — these six sit alone above
   their titles, with nothing else in the card to hold the eye. */
.seo-what .icon-disc {
  flex-basis: 90px;
  width: 90px;
  height: 90px;
  margin: 0 auto 16px;
}

/* In the pricing credit cards it heads the card, centred on its own line above
   the chip, with the spacing the square frame it replaced carried. */
.pricing-credits .icon-disc {
  margin: 0 auto 20px;
}

/* In the sales-partner cards (home and partners pages) it is a flex child of the
   card's stack. */
.sales-cta-band .icon-disc,
.partners-how .icon-disc {
  align-self: center;
}

/* A full screen tall, its heading and cards centred in it. */
.services-band {
  display: flex;
  flex-direction: column;
}

.services-band > .container {
  margin-block: auto;
}

.services-band .section-head,
.services-band .section-head .primary-text,
.services-band .section-head .muted {
  color: #fff;
}

.services-band .section-head .muted {
  opacity: 0.92;
}

.stat .value {
  color: #fff;
  font-size: 1.7rem;
  font-weight: 400;
}

/* The flipped opening quote. `align-self` matters: in a stretched flex column
   the span would be full width, and mirroring a full-width box throws the glyph
   over to the right-hand edge. */
.quote-mark {
  display: flex;
  align-self: flex-start;
  color: var(--primary);
  opacity: 0.3;
  transform: scaleX(-1);
}

.quote-mark .ico {
  font-size: 40px;
}

.rating {
  display: flex;
  gap: 2px;
  color: #faaf00;
  margin-bottom: 12px;
}

.rating .ico {
  font-size: 18px;
}

.testimonial-quote {
  margin-bottom: 24px;
  flex: 1;
  font-style: italic;
}

.person {
  display: flex;
  align-items: center;
  gap: 16px;
}

/* The long keyword-rich SEO block every page carries. */
.prose {
  max-width: 820px;
  margin-inline: auto;
  display: flex;
  flex-direction: column;
  gap: 20px;
}

.prose--wide {
  max-width: 860px;
}

.prose p {
  color: var(--text-secondary);
}

/* The home page's hosting copy with the free SEO checker beside it: one column on
   a phone, the card under the copy; the card in a 360px right-hand column from
   the desktop breakpoint, top-aligned with the copy. */
.seo-copy {
  display: grid;
  gap: 40px;
  grid-template-columns: minmax(0, 1fr);
}

@media (min-width: 900px) {
  .seo-copy {
    grid-template-columns: minmax(0, 1fr) 360px;
    align-items: start;
    gap: 56px;
  }
}

/* The copy fills its column rather than centring itself in the page. */
.seo-copy .prose {
  max-width: none;
  margin-inline: 0;
}

/* The banner card: the site-map picture over a brand-green panel with the way
   into /seo-check. */
/* Half the screen tall overall: the green panel keeps the height its copy needs
   and the picture takes whatever is left above it, cropped to fit. */
.seo-side-banner {
  display: flex;
  flex-direction: column;
  height: 50vh;
  border-radius: var(--radius-card);
  overflow: hidden;
  background: var(--primary);
  color: #fff;
}

.seo-side-banner img {
  display: block;
  flex: 1;
  min-height: 0;
  width: 100%;
  object-fit: cover;
}

.seo-side-banner-body {
  flex-shrink: 0;
}

.seo-side-banner-body {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 12px;
  padding: 24px;
}

.seo-side-banner-body p {
  opacity: 0.9;
}

/* "Areas we serve" — a masonry of state headings. */
.areas {
  column-count: 2;
  column-gap: 32px;
}

@media (min-width: 600px) {
  .areas {
    column-count: 3;
  }
}

@media (min-width: 900px) {
  .areas {
    column-count: 4;
  }
}

@media (min-width: 1200px) {
  .areas {
    column-count: 5;
  }
}

.areas > div {
  /* Keeps a state's cities in the same column as its heading — without it a
     column break orphans them under the wrong state name. */
  break-inside: avoid;
  margin-bottom: 20px;
}

.areas .state {
  font-weight: 600;
  font-size: 0.875rem;
  line-height: 1.43;
}

.areas .city {
  font-size: 0.875rem;
  line-height: 1.43;
  color: var(--grey-500);
}

/* ===========================================================================
   Blog
   =========================================================================== */

.blog-card {
  position: relative;
}

.blog-card .cover {
  position: relative;
}

.blog-card .cover img {
  display: block;
  width: 100%;
  height: 220px;
  object-fit: cover;
}

.blog-card .cover .placeholder {
  height: 220px;
  background: var(--grey-200);
  color: var(--grey-400);
  display: flex;
  align-items: center;
  justify-content: center;
}

.blog-card .cover .placeholder .ico {
  font-size: 56px;
}

.blog-card .cover .chip {
  position: absolute;
  top: 12px;
  left: 12px;
  font-weight: 700;
}

/* Green accent line between the image and the card body. */
.blog-card .accent {
  height: 5px;
  background: var(--primary);
}

.blog-card .card-body {
  display: flex;
  flex-direction: column;
  flex-grow: 1;
}

.blog-card h3 {
  font-size: 1.25rem;
  font-weight: 400;
  line-height: 1.3;
  margin-bottom: 8px;
}

.blog-card .excerpt {
  color: var(--text-secondary);
  margin-bottom: 16px;
  flex: 1;
}

.blog-meta {
  display: flex;
  align-items: center;
  gap: 16px;
  color: var(--text-secondary);
  font-size: 0.75rem;
  line-height: 1.66;
}

.blog-meta .with-icon {
  display: inline-flex;
  align-items: center;
  gap: 4px;
}

.blog-filters {
  display: flex;
  flex-direction: column;
  gap: 16px;
  margin-bottom: 32px;
}

@media (min-width: 900px) {
  .blog-filters {
    flex-direction: row;
    align-items: center;
    justify-content: space-between;
  }
}

.blog-filters .chips {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.blog-search {
  position: relative;
  display: flex;
  align-items: center;
  width: 100%;
}

@media (min-width: 900px) {
  .blog-search {
    min-width: 280px;
    width: 280px;
  }
}

.blog-search .ico {
  position: absolute;
  left: 12px;
  font-size: 20px;
  color: var(--text-secondary);
  pointer-events: none;
}

.blog-search input {
  width: 100%;
  font-family: inherit;
  font-size: 0.875rem;
  padding: 9px 12px 9px 40px;
  border: 1px solid var(--divider);
  border-radius: 4px;
  background: var(--bg-paper);
}

.blog-search input:focus {
  outline: none;
  border-color: var(--primary);
  box-shadow: inset 0 0 0 1px var(--primary);
}

.blog-empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 16px;
  padding-block: 64px;
}

/* --- One article ---------------------------------------------------------- */

.article-head .h3 {
  font-size: 1.875rem;
  margin-bottom: 16px;
}

@media (min-width: 900px) {
  .article-head .h3 {
    font-size: 2.625rem;
  }
}

.article-byline {
  display: flex;
  align-items: center;
  gap: 16px;
  margin-bottom: 32px;
}

.article-cover {
  width: 100%;
  max-height: 420px;
  object-fit: cover;
  border-radius: var(--radius-card);
  margin-bottom: 32px;
  display: block;
}

.article-rule {
  height: 6px;
  border-radius: var(--radius-card);
  margin-bottom: 32px;
  background: var(--gradient-brand);
}

.article-body p {
  margin-bottom: 20px;
  line-height: 1.8;
  font-size: 18px;
}

.article-body h2 {
  font-size: 1.5rem;
  font-weight: 400;
  line-height: 1.334;
  margin-top: 32px;
  margin-bottom: 16px;
}

.article-cta {
  background: var(--bg-subtle);
  margin-top: 32px;
}

.article-cta .card-body {
  display: flex;
  flex-wrap: wrap;
  gap: 16px;
  align-items: center;
  justify-content: space-between;
}

.related-card .card-link {
  flex-direction: row;
  align-items: stretch;
}

.related-card .cover {
  width: 110px;
  flex-shrink: 0;
  object-fit: cover;
  display: block;
}

@media (min-width: 600px) {
  .related-card .cover {
    width: 150px;
  }
}

.related-card .placeholder {
  width: 110px;
  flex-shrink: 0;
  background: var(--grey-200);
  color: var(--grey-400);
  display: flex;
  align-items: center;
  justify-content: center;
}

@media (min-width: 600px) {
  .related-card .placeholder {
    width: 150px;
  }
}

.related-card .card-body {
  padding: 20px;
}

/* ===========================================================================
   Products
   =========================================================================== */

.product-row {
  display: grid;
  gap: 32px;
  align-items: center;
  grid-template-columns: 1fr;
}

@media (min-width: 900px) {
  .product-row {
    grid-template-columns: repeat(2, 1fr);
    gap: 64px;
  }
}

.product-row img {
  width: 100%;
  height: 240px;
  object-fit: cover;
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-6);
  display: block;
}

@media (min-width: 900px) {
  .product-row img {
    height: 380px;
  }
}

/* Odd sections put the picture on the right. On a phone both stack with the
   picture last, which is what MUI's `column-reverse` did. */
@media (min-width: 900px) {
  .product-row--flip .product-media {
    order: 2;
  }
}

@media (max-width: 899px) {
  .product-row .product-media {
    order: 2;
  }
}

.product-detail {
  display: flex;
  flex-direction: column;
  gap: 16px;
}

.product-detail .h3 {
  font-size: 1.75rem;
}

@media (min-width: 900px) {
  .product-detail .h3 {
    font-size: 2.25rem;
  }
}

.product-detail .intro {
  font-size: 1.25rem;
  font-weight: 500;
  line-height: 1.6;
}

.product-features {
  display: grid;
  gap: 8px;
  grid-template-columns: 1fr;
}

@media (min-width: 600px) {
  .product-features {
    grid-template-columns: repeat(2, 1fr);
  }
}

.product-eyebrow {
  display: flex;
  align-items: center;
  gap: 12px;
}

.product-solo {
  max-width: 820px;
  margin-inline: auto;
}

/* ===========================================================================
   Pricing
   =========================================================================== */

/* The pricing hero. It has no photograph of its own: it is transparent over the
   page's fixed backdrop, a full screen tall, its copy white on the scrim.
   `--gradient-hero-glow`, the radial glow this section used to paint, is
   unused. */
.pricing-hero {
  position: relative;
  overflow: hidden;
  isolation: isolate;
}

/* The contact hero. Its copy is a left-aligned stack, and the left of this
   photograph is the empty sunlit wall — the woman at the desk sits to the right
   of where the heading ends. */
.contact-hero,
.blog-hero {
  position: relative;
  overflow: hidden;
  isolation: isolate;
}

.contact-hero .container,
.blog-hero .container {
  position: relative;
  z-index: 1;
  padding-block: 48px;
}

/*
 * The contact page's backdrop — a fixed, full-screen layer the top of the page
 * scrolls over, holding two photographs stacked.
 *
 * Fixed rather than `background-attachment: fixed`, which iOS ignores and which
 * repaints on every scroll frame. `z-index: -1` puts it under everything in the
 * body and above the canvas the body's white is painted on, so it shows through
 * exactly the sections that have no background of their own: the hero, the
 * contact form and the website application.
 *
 * The second photograph starts invisible; site.js raises its opacity as the form
 * scrolls away, and lowers the whole layer's as "Talk to a real hosting expert"
 * comes up. Both are opacity only — no movement — so nothing here needs a
 * reduced-motion exception.
 *
 * Anchored right at every width: the people are on the right of both pictures
 * and the empty room on the left, so a narrow viewport crops the room.
 */
.contact-backdrop,
.partners-backdrop,
.home-backdrop,
.pricing-backdrop,
.products-backdrop {
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
}

.contact-backdrop-img,
.partners-backdrop-img,
.home-backdrop-img,
.pricing-backdrop-img,
.products-backdrop-img {
  position: absolute;
  inset: 0;
  background-size: cover;
  background-position: right center;
  background-repeat: no-repeat;
}

.contact-backdrop-img--1 {
  background-image: url("/assets/img/contact_hero_1.webp");
}

.contact-backdrop-img--2 {
  background-image: url("/assets/img/contact_hero_2.webp");
  opacity: 0;
}

/* The partners page: the office, with its subject in the middle of the frame,
   then the woman at the desk beside the world map, who sits on the right. */
.partners-backdrop-img--1 {
  background-image: url("/assets/img/sales_hero_bg.webp");
  background-position: center;
}

.partners-backdrop-img--2 {
  background-image: url("/assets/img/sales_home.webp");
  opacity: 0;
}

/* Products: its own photograph, anchored left — the empty white down its left
   is what the copy sits on. */
.products-backdrop-img--1 {
  background-image: url("/assets/img/product_hero_1.webp");
  background-position: left center;
}

/* Pricing: the products photograph, anchored left — the empty white down its
   left is what the centred copy sits on. */
.pricing-backdrop-img--1 {
  background-image: url("/assets/img/product_hero_1.webp");
  background-position: left center;
}

/* The home page: one photograph — the two at the desk in the middle, the rack on
   the right — held a little right of centre so a narrow viewport keeps both. */
.home-backdrop-img--1 {
  background-image: url("/assets/img/home_hero2.webp");
  background-position: 70% center;
}

/* Copy set straight on the darkened backdrop is white, the same as every other
   copy on the scrim: the hero panel's overline, heading and lede, and the
   website application's heading. The form cards keep their dark text on glass. */
.contact-hero-panel,
.contact-hero-panel .primary-text,
.contact-hero-panel .muted,
.contact-application-head,
.contact-application-head .primary-text,
.contact-application-head .muted {
  color: #fff;
}

.contact-hero-panel .muted,
.contact-application-head .muted {
  opacity: 0.92;
}

/* Full-screen sections: the home hero and "What we do", the contact hero and
   form, the free SEO check's hero, and on the partners page the hero, "How it
   works", the earnings table and the partner stories. */
.blog-hero,
.contact-hero,
.contact-form-section,
.hero,
.pricing-hero,
.pricing-credits,
.pricing-journey,
.services-band,
.why-band,
.sales-cta-part,
.sales-hero,
.partners-how,
.partners-earnings,
.partners-stories,
.seo-hero {
  min-height: 100vh;
}

.contact-form-section,
.pricing-credits,
.pricing-journey,
.why-band,
.sales-cta-part,
.partners-how,
.partners-earnings,
.partners-stories {
  display: flex;
  flex-direction: column;
  justify-content: center;
}

/* The blog's photograph: a white office, the desk and laptop down the right.
   Anchored right for the same reason as the contact hero's — a narrow viewport
   crops the empty floor on the left and keeps the desk. */
.blog-hero-bg {
  background-image: url("/assets/img/blog_hero.webp");
  background-position: right center;
}

/* The copy sits on the same frosted glass the home hero uses. The left of this
   photograph is a sunlit wall, so dark text on it is legible but weak; the pane
   gives the words a background of their own without hiding the room. Sized and
   padded here rather than on .hero-panel because this copy is a left-aligned
   .stack, not that panel's centred flex column. */
/* A lighter tint than the home hero's 70% — enough to lift the words off the
   picture without turning the pane into a white card, so the room still reads
   through it. Where `backdrop-filter` is unsupported this degrades to the 40%
   alone: thinner cover than the home hero's, and it holds because the copy sits
   over the sunlit wall on the left of this photograph rather than the subject
   further right. */
.contact-hero-panel,
.blog-hero-panel {
  max-width: 720px;
  padding: 32px 24px;
}

/* The blog hero: a full screen of the photograph under the shared scrim, its
   copy white and straight on it — no pane. */
.blog-hero-panel,
.blog-hero-panel .primary-text,
.blog-hero-panel .muted {
  color: #fff;
}

.blog-hero-panel .muted {
  opacity: 0.92;
}

@media (min-width: 900px) {
  .contact-hero-panel,
  .blog-hero-panel {
    padding: 40px;
  }
}

.pricing-hero .container {
  position: relative;
  z-index: 1;
  padding-block: 48px;
  text-align: center;
}

@media (min-width: 900px) {
  .pricing-hero .container {
    padding-block: 72px;
  }
}

.pricing-hero .lede {
  max-width: 720px;
  margin-inline: auto;
  font-size: 1.25rem;
  font-weight: 400;
  line-height: 1.6;
  color: #fff;
  opacity: 0.92;
}

/* The hero and "How credits work" sit on the darkened backdrop: their copy is
   white, and the green that carries meaning — the overlines, the chips, the
   journey numbers, the ticks — steps up to the lighter brand green, which holds
   on it. */
.pricing-hero .container,
.pricing-credits,
.pricing-journey {
  position: relative;
  z-index: 1;
  color: #fff;
}

.pricing-hero .primary-text,
.pricing-credits .primary-text,
.pricing-credits .muted,
.pricing-journey .muted {
  color: #fff;
}

.pricing-credits .muted,
.pricing-journey .muted {
  opacity: 0.92;
}

.pricing-hero .chip--primary-outlined,
.pricing-credits .chip--primary-outlined,
.seo-hero .chip--primary-outlined {
  color: var(--primary-light);
  border-color: var(--primary-light);
}

/* The plain outlined chips under the hero buttons carry dark text on a slate
   border, neither of which survives the scrim: white on a white edge instead. */
.pricing-hero .chip--outlined {
  color: #fff;
  border-color: rgba(255, 255, 255, 0.5);
}

.pricing-journey .journey-num,
.pricing-credits .check-row .ico {
  color: var(--primary-light);
}

.pricing-journey .journey-num {
  border-color: var(--primary-light);
}

.credit-type {
  position: relative;
  overflow: hidden;
  height: 100%;
}

/* An oversized ghost of the same icon, bled off the corner — decoration only,
   so it is hidden from assistive tech. */
.credit-type .ghost {
  position: absolute;
  top: -28px;
  right: -28px;
  color: var(--primary);
  opacity: 0.06;
  pointer-events: none;
}

.credit-type .ghost .ico {
  font-size: 180px;
}

.credit-type .card-body {
  position: relative;
}

/* The five-step "life of a credit" thread. */
.journey {
  position: relative;
}

/* The thread the steps hang off. Behind them, at the vertical centre of the
   96px circles, and only where the steps are actually in a row — stacked on a
   phone, a horizontal rule would run through nothing. */
.journey::before {
  content: "";
  display: none;
  position: absolute;
  top: 48px;
  left: 10%;
  right: 10%;
  border-top: 2px dashed var(--divider);
  z-index: 0;
}

@media (min-width: 900px) {
  .journey::before {
    display: block;
  }
}

.journey-grid {
  position: relative;
  z-index: 1;
  display: grid;
  gap: 32px;
  grid-template-columns: 1fr;
}

@media (min-width: 600px) {
  .journey-grid {
    grid-template-columns: repeat(2, 1fr);
  }
}

@media (min-width: 900px) {
  .journey-grid {
    grid-template-columns: repeat(5, 1fr);
    gap: 16px;
  }
}

.journey-step {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
  text-align: center;
  padding-inline: 8px;
}

.journey-badge {
  position: relative;
}

/* The same white disc as the home page's card icons (`.icon-disc`), at this
   section's larger size: no border, 80% white over a 5px blur of the
   photograph. The icons' own white backgrounds disappear into it. */
.journey-circle {
  width: 96px;
  height: 96px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  background: #fff;
  opacity: 0.8;
  backdrop-filter: blur(5px);
  -webkit-backdrop-filter: blur(5px);
}

.journey-circle img {
  display: block;
  width: 60%;
  height: 60%;
  object-fit: contain;
}

.journey-num {
  position: absolute;
  top: -6px;
  right: -6px;
  width: 28px;
  height: 28px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  background: transparent;
  border: 1px solid var(--primary);
  color: var(--primary);
  font-size: 13px;
  font-weight: 700;
}

.example-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding-block: 4px;
  font-size: 0.875rem;
  color: var(--text-secondary);
}

.example-row--total {
  color: var(--text);
  font-weight: 700;
}

/* ===========================================================================
   Contact
   =========================================================================== */

/* `minmax(0, …)`, not a bare `fr`. A bare `1fr` track cannot shrink below its
   content's min-content width, and the email address in "Email us" is one
   unbreakable word — on a phone it held the column, the form beside it and
   the whole page wider than the screen. */
.contact-grid {
  display: grid;
  gap: 32px;
  grid-template-columns: minmax(0, 1fr);
}

@media (min-width: 900px) {
  .contact-grid {
    /* md={4} / md={8} of MUI's 12 columns. */
    grid-template-columns: minmax(0, 1fr) minmax(0, 2fr);
  }
}

/* An address or a number may break anywhere rather than run out of its card. */
.channel a,
.channel .value {
  overflow-wrap: anywhere;
}

.channel .card-body {
  display: flex;
  gap: 16px;
  align-items: center;
}

.channel .ico {
  color: var(--primary);
}

.channel a,
.channel .value {
  font-weight: 600;
  color: inherit;
  text-decoration: none;
}

.channel a:hover {
  text-decoration: underline;
}

.card--primary {
  background: var(--primary);
  color: var(--primary-contrast);
  border: none;
}

.card--primary p {
  opacity: 0.9;
}

.form-grid {
  display: grid;
  gap: 20px;
  grid-template-columns: 1fr;
}

@media (min-width: 600px) {
  .form-grid--2 {
    grid-template-columns: repeat(2, 1fr);
  }
}

.form-grid .span-2 {
  grid-column: 1 / -1;
}

.form-section {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.form-section > h3 {
  font-size: 1rem;
  font-weight: 400;
  line-height: 1.75;
}

.form-sections {
  display: flex;
  flex-direction: column;
  gap: 32px;
}

.form-sections > * + * {
  border-top: 1px solid var(--divider);
  padding-top: 32px;
}

.link-list {
  display: flex;
  flex-direction: column;
  gap: 12px;
  width: 100%;
}

.link-row {
  display: flex;
  flex-direction: column;
  gap: 12px;
  align-items: flex-start;
}

@media (min-width: 600px) {
  .link-row {
    flex-direction: row;
  }
}

.link-row .field {
  flex: 1;
  width: 100%;
}

/*
 * One-box rows — "cities you serve". A city is one word, and a box the width of
 * the whole card invites a paragraph. So it stops exactly where the first box of
 * a two-box row does: the full width less the two 12px gaps and the 34px remove
 * button, halved.
 */
@media (min-width: 600px) {
  .link-list[data-single] .link-row .field {
    flex: 0 1 calc((100% - 58px) / 2);
  }
}

.icon-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  border: 0;
  border-radius: 50%;
  background: none;
  cursor: pointer;
  color: var(--text-secondary);
  flex-shrink: 0;
}

.icon-btn:hover {
  background: var(--action-hover);
}

.icon-btn[disabled] {
  opacity: 0.4;
  pointer-events: none;
}

.logo-picker {
  display: flex;
  gap: 16px;
  align-items: center;
}

.logo-picker img {
  width: 96px;
  height: 96px;
  object-fit: contain;
  border-radius: 4px;
  border: 1px solid var(--divider);
  background: var(--bg-paper);
  padding: 8px;
}

/* ===========================================================================
   Sales partners
   =========================================================================== */

/*
 * The hero has no photograph of its own any more: it is transparent over the
 * partners page's fixed backdrop (`.partners-backdrop`), a full screen tall.
 * What it keeps is the dark scrim — its own ::before — so the white copy stays
 * legible over a bright office. `isolation` keeps the scrim and the copy in
 * their own stacking context; the backdrop, fixed at `z-index: -1` outside the
 * section, is unaffected by it.
 */
.sales-hero,
.partners-how,
.partners-stories {
  position: relative;
  overflow: hidden;
  isolation: isolate;
}

/* Dark scrim so the white copy stays readable over the photo — the hero's,
   "How it works" on the same photograph, the partner stories on the second, the
   contact page's whole backdrop, where it lies over both photographs and fades
   out with them, and the free SEO check's hero, which is an illustration rather
   than a photograph and joined this list so the page stops being the one hero
   that looks like a different site. */
.sales-hero::before,
.partners-how::before,
.partners-stories::before,
.why-band::before,
.sales-cta-bg::after,
.areas-bg::after,
.contact-backdrop::after,
.home-backdrop::after,
.pricing-backdrop::after,
.products-backdrop::after,
.blog-hero-bg::after,
.faq-bg::after,
.seo-hero::before {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(
    180deg,
    rgba(15, 23, 42, 0.63),
    rgba(15, 23, 42, 0.75)
  );
}

.sales-hero .container {
  position: relative;
  z-index: 1;
  padding-block: 80px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 24px;
  text-align: center;
  color: #fff;
}

@media (min-width: 900px) {
  .sales-hero .container {
    padding-block: 128px;
  }
}

/* "How it works" and the partner stories on the scrim: the container sits above
   the ::before, and the heading turns white like the hero's. The cards are
   glass and keep their own dark text. */
.partners-how .container,
.partners-stories .container {
  position: relative;
  z-index: 1;
}

.partners-how .section-head,
.partners-how .section-head .primary-text,
.partners-how .section-head .muted,
.partners-stories .section-head,
.partners-stories .section-head .primary-text {
  color: #fff;
}

.partners-how .section-head .muted {
  opacity: 0.92;
}

.sales-hero h1 {
  font-size: 2.125rem;
  font-weight: 400;
  line-height: 1.2;
  letter-spacing: -0.02em;
  max-width: 880px;
  text-shadow: 0 2px 14px rgba(0, 0, 0, 0.45);
}

@media (min-width: 900px) {
  .sales-hero h1 {
    font-size: 3.25rem;
  }
}

.sales-hero .lede {
  max-width: 680px;
  font-size: 1.25rem;
  font-weight: 400;
  line-height: 1.6;
  opacity: 0.92;
  text-shadow: 0 2px 14px rgba(0, 0, 0, 0.45);
}

.earnings-cell .amount {
  font-weight: 700;
  color: var(--primary);
}

.earnings-cell .per {
  display: block;
  font-size: 0.75rem;
  color: var(--text-secondary);
}

.list-head {
  display: flex;
  flex-direction: column;
  gap: 16px;
  margin-bottom: 40px;
}

@media (min-width: 600px) {
  .list-head {
    flex-direction: row;
    justify-content: space-between;
    align-items: flex-end;
  }
}

/* --- Print ---------------------------------------------------------------
   Somebody printing a blog post wants the article, not the furniture.      */

@media print {
  .header,
  .footer,
  .drawer-scrim,
  .article-cta,
  .blog-filters {
    display: none !important;
  }

  body {
    color: #000;
  }
}

/* ===========================================================================
   The free SEO Compliance Check — /seo-check
   ---------------------------------------------------------------------------
   A port of the dashboard's SEO widget to this site, in plain CSS. It is the
   one screen here with real state in it, so it carries more rules than the rest
   of the marketing pages put together.

   Everything below reuses the tokens at the top of this file. Nothing here
   invents a colour: the four verdicts map onto the palette the alerts already
   use, so a "fail" row and an error banner are the same red.
   =========================================================================== */

/* --- The hero ------------------------------------------------------------- */

/*
 * A full screen tall, like every other hero here — the height comes from the
 * shared `min-height: 100vh` list further up this file rather than from a rule
 * of its own, so the day that number changes it changes everywhere at once.
 *
 * `min-height` and not `height`: the copy, the form and the note together are
 * taller than the viewport on a phone in landscape, and a fixed height there
 * would crop the button off the bottom.
 *
 * ── ON THE SAME SCRIM AS EVERY OTHER HERO ───────────────────────────────────
 *
 * This block used to be the one hero on the site with no scrim over it, and the
 * argument was that the artwork is an illustration drawn for it — near-white,
 * subjects held to the left and right, middle third left empty for exactly
 * these words — so a pane would cover nothing but the white it was drawn to
 * leave. That reasoning was about this page alone, and the page does not exist
 * alone: arriving here from the banner on any other page meant arriving at the
 * one hero that looked like a different site.
 *
 * So it joins the shared `::before` above, and the copy turns white with it —
 * which is why `.seo-hero-inner` sets a colour at all, and why the accent and
 * the chip step up to `--primary-light` the way they do on the home and pricing
 * heroes (the base green goes muddy on the scrim).
 *
 * `isolation` keeps the scrim and the copy in their own stacking context, as it
 * does on `.sales-hero`. `background-color` stays as the ground beneath: it is
 * what shows while a 700 KB image is still arriving, and what remains if it
 * never does.
 */
.seo-hero {
  position: relative;
  overflow: hidden;
  isolation: isolate;
  display: flex;
  align-items: center;
  background-color: var(--bg-subtle);
  background-image: url("/assets/img/seo_check_hero.webp");
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
  border-bottom: 1px solid var(--divider);
}

/*
 * Above the scrim.
 *
 * This replaces a white veil that used to apply below 900px only, where `cover`
 * crops the illustration's sides in and walks its subjects under the heading.
 * The dark scrim covers that case at every width, so the narrow-viewport rule
 * has nothing left to do.
 */
.seo-hero > .container {
  position: relative;
  z-index: 1;
}

.seo-hero-inner {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 20px;
  text-align: center;
  padding-block: 56px;
  max-width: 720px;
  margin-inline: auto;
  /* Everything in the block, including the three social icons — `.hero-social a`
     is `color: inherit`, so they come white from here rather than from a rule of
     their own. The address box is not affected: it sets its own dark text on a
     white ground, which is what makes it read as a box on the scrim. */
  color: #fff;
}

.seo-hero h1 {
  font-size: 2.25rem;
  font-weight: 400;
  line-height: 1.2;
  letter-spacing: -0.02em;
  margin: 0;
  /* The same shadow the other heroes' headings carry: the scrim is a gradient
     and the illustration under it is not evenly light, so the words need to
     hold over the brightest part of it too. */
  text-shadow: 0 2px 14px rgba(0, 0, 0, 0.45);
}

@media (min-width: 900px) {
  .seo-hero h1 {
    font-size: 3rem;
  }
}

.seo-hero h1 .accent {
  color: var(--primary-light);
}

.seo-hero .lede {
  font-size: 1.125rem;
  line-height: 1.6;
  /* `--text-secondary` is a grey for a light ground and disappears on the
     scrim. White held back a little is how every other hero says the same
     thing. */
  color: inherit;
  opacity: 0.92;
  text-shadow: 0 2px 14px rgba(0, 0, 0, 0.45);
  margin: 0;
}

.seo-hero-note {
  color: inherit;
  opacity: 0.86;
}

/* The address box and its button, side by side once there is room for both. */
.seo-form {
  display: flex;
  flex-direction: column;
  gap: 12px;
  width: 100%;
  max-width: 560px;
}

@media (min-width: 600px) {
  .seo-form {
    flex-direction: row;
  }
}

.seo-form input {
  flex: 1;
  width: 100%;
  padding: 14px 16px;
  font-family: inherit;
  font-size: 1rem;
  color: var(--text);
  background: var(--bg-paper);
  border: 1px solid var(--divider);
  border-radius: var(--radius-btn);
}

.seo-form input:focus {
  outline: none;
  border-color: var(--primary);
  box-shadow: 0 0 0 3px var(--tint-softer);
}

.seo-form .btn {
  flex-shrink: 0;
}

/* --- The score ring ------------------------------------------------------- */

/*
 * The score gauge — a port of the dashboard's ScoreGauge, which is what sits at
 * the top of this same report there.
 *
 * The number and its BAND WORD are HTML layered over the SVG rather than SVG
 * text, so they inherit the page's font and need no counter-rotation trick to
 * stay upright.
 */
.seo-gauge {
  position: relative;
  flex-shrink: 0;
}

.seo-gauge svg {
  display: block;
}

.seo-gauge-track {
  fill: none;
  stroke: var(--divider);
}

.seo-gauge-value {
  fill: none;
  transition: stroke-dashoffset 0.6s ease-out;
}

/* The three bands api/seoCompliance.ts scores against: 90+, 60+, below. */
.seo-gauge--pass .seo-gauge-value {
  stroke: var(--primary);
}
.seo-gauge--warn .seo-gauge-value {
  stroke: #ed6c02;
}
.seo-gauge--fail .seo-gauge-value {
  stroke: var(--error);
}
.seo-gauge--unknown .seo-gauge-value {
  stroke: var(--grey-500);
}

.seo-gauge-face {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  text-align: center;
}

.seo-gauge-number {
  font-weight: 800;
  line-height: 1;
}

.seo-gauge--pass .seo-gauge-number {
  color: var(--primary);
}
.seo-gauge--warn .seo-gauge-number {
  color: #ed6c02;
}
.seo-gauge--fail .seo-gauge-number {
  color: var(--error);
}
.seo-gauge--unknown .seo-gauge-number {
  color: var(--text-secondary);
}

/* The word is what carries the verdict; the colour only reinforces it. */
.seo-gauge-band {
  font-size: 0.75rem;
  color: var(--text-secondary);
}

/* --- The summary ---------------------------------------------------------- */

.seo-summary {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 24px;
  text-align: center;
  padding: 24px;
  background: var(--bg-subtle);
  border: 1px solid var(--divider);
  border-radius: var(--radius-card);
  margin-bottom: 32px;
}

@media (min-width: 600px) {
  .seo-summary {
    flex-direction: row;
    text-align: left;
    padding: 32px;
  }
}

.seo-summary-facts {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.seo-summary-head {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  gap: 8px;
}

@media (min-width: 600px) {
  .seo-summary-head {
    justify-content: flex-start;
  }
}

.seo-host {
  font-size: 0.9375rem;
  font-weight: 700;
  word-break: break-word;
}

.seo-chip-warn {
  border-color: #ed6c02;
  color: #b45309;
}

/*
 * The per-category tallies — "250/286" under each category's own icon.
 *
 * The icon is how a reader finds the group they want before reading a word, and
 * the tooltip names it, so the row stays a row instead of seven labelled boxes.
 */
.seo-cats {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 16px;
}

@media (min-width: 600px) {
  .seo-cats {
    justify-content: flex-start;
  }
}

.seo-cat-stat {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 0.8125rem;
  color: var(--text-secondary);
  cursor: help;
}

.seo-cat-stat b {
  font-weight: 700;
  color: var(--text);
}

.seo-checked-on {
  font-size: 0.8125rem;
  color: var(--text-secondary);
}

/* The progress and the button that ends it, side by side — the button is wanted
   precisely when the bar is taking too long, so it sits where the eye already
   is. It wraps under the bar on a narrow screen rather than squeezing it. */
.seo-running {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 12px;
}

.seo-running-bar {
  flex: 1;
  min-width: 220px;
}

.seo-stop {
  flex-shrink: 0;
}

/* The crawl's progress. Indeterminate only while nothing has been discovered
   yet — once there is a denominator, a real fraction is not a guess. */
.seo-progress {
  height: 6px;
  border-radius: 3px;
  background: var(--divider);
  overflow: hidden;
}

.seo-progress span {
  display: block;
  height: 100%;
  background: var(--primary);
  transition: width 0.4s ease;
}

.seo-progress--idle span {
  width: 40% !important;
  animation: seo-progress-slide 1.4s ease-in-out infinite;
}

@keyframes seo-progress-slide {
  0% {
    transform: translateX(-100%);
  }
  100% {
    transform: translateX(250%);
  }
}

.seo-progress-note {
  margin: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* --- The findings --------------------------------------------------------- */

.seo-section {
  margin-bottom: 40px;
}

.seo-section > .h6 {
  margin: 0 0 12px;
}

.seo-findings-head {
  margin-bottom: 20px;
}

.seo-findings-head .h6 {
  margin: 0 0 4px;
}

.seo-findings-head p {
  margin: 0;
  max-width: 70ch;
}

.seo-findings-url {
  display: block;
  margin-top: 4px;
  word-break: break-all;
}

/*
 * TWO COLUMNS on a wide screen, one on a narrow one — the dashboard's layout.
 * Seven categories stacked in a single column is a page nobody scrolls to the
 * end of; side by side the whole checklist is roughly one screen.
 *
 * `align-items: start` so a short category does not stretch to match the tall
 * one beside it, leaving a gap under its last row.
 */
.seo-findings {
  display: grid;
  grid-template-columns: 1fr;
  column-gap: 40px;
  row-gap: 28px;
  align-items: start;
}

@media (min-width: 900px) {
  .seo-findings {
    grid-template-columns: 1fr 1fr;
  }
}

.seo-cat-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding-bottom: 6px;
  border-bottom: 1px solid var(--divider);
}

.seo-cat-title {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 0;
  min-width: 0;
  font-size: 0.9375rem;
  font-weight: 400;
}

.seo-cat-icon {
  flex-shrink: 0;
  color: var(--text-secondary);
}

.seo-cat-count {
  flex-shrink: 0;
  font-size: 0.75rem;
  color: var(--text-secondary);
}

/* --- Check rows ----------------------------------------------------------- */

/*
 * What was checked on the left, what was found on the right, and the verdict in
 * a fixed column so the words line up down the page rather than ragging in and
 * out with the length of each value.
 */
.seo-row {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 7px 0;
  border-bottom: 1px solid var(--divider);
}

.seo-row[data-tip] {
  cursor: help;
}

.seo-row-main {
  flex: 1;
  min-width: 0;
  display: flex;
  align-items: baseline;
  gap: 8px;
}

.seo-row-label {
  font-size: 0.875rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* How far a rolled-up row reaches: "all 12 pages", "3 of 12 pages". */
.seo-row-scope {
  flex-shrink: 0;
  font-size: 0.75rem;
  color: var(--text-secondary);
}

.seo-row-value {
  flex-shrink: 0;
  max-width: 180px;
  font-size: 0.875rem;
  font-weight: 600;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* The verdict: the dot and the word, which always travel together. */
.seo-tag {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-width: 82px;
  font-size: 0.75rem;
  color: var(--text-secondary);
}

.seo-tag::before {
  content: "";
  width: 8px;
  height: 8px;
  border-radius: 50%;
  flex-shrink: 0;
}

.seo-tag--pass::before {
  background: var(--success-text);
}
.seo-tag--warn::before {
  background: #ed6c02;
}
.seo-tag--fail::before {
  background: var(--error);
}
.seo-tag--unknown::before {
  background: var(--grey-500);
}

/* Held in the layout even when empty, so the column of verdicts beside it does
   not shift from row to row. */
.seo-row-doc {
  flex-shrink: 0;
  display: flex;
  justify-content: flex-end;
  width: 28px;
}

.seo-doc {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  border: 0;
  border-radius: 50%;
  background: none;
  color: var(--text-secondary);
  cursor: pointer;
}

.seo-doc:hover {
  background: var(--action-hover);
  color: var(--primary);
}

/* --- The tooltip ---------------------------------------------------------- */

/*
 * The page's ONE tooltip, positioned by assets/js/seo-check.js.
 *
 * It replaces the browser's own — `<title>` on a hexagon and `title=` on a row —
 * which cannot be styled, waits out the OS delay, and truncates a long URL
 * wherever the platform feels like it.
 */
.seo-tip {
  position: absolute;
  z-index: 1400;
  max-width: 320px;
  padding: 8px 10px;
  border-radius: 6px;
  background: #303030;
  color: #fff;
  font-size: 0.75rem;
  line-height: 1.45;
  pointer-events: none;
  box-shadow: var(--shadow-2);
}

.seo-tip::after {
  content: "";
  position: absolute;
  left: 50%;
  margin-left: -5px;
  border: 5px solid transparent;
  border-top-color: #303030;
  top: 100%;
}

.seo-tip--below::after {
  top: auto;
  bottom: 100%;
  border-top-color: transparent;
  border-bottom-color: #303030;
}

.seo-tip-title,
.seo-tip-url,
.seo-tip-score,
.seo-tip-error {
  display: block;
}

.seo-tip-title {
  font-weight: 400;
}

/* A URL has no spaces to wrap at, so it must be allowed to break anywhere or it
   forces the tooltip as wide as the path is long. */
.seo-tip-url {
  opacity: 0.75;
  word-break: break-all;
}

.seo-tip-score {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-top: 4px;
  font-weight: 600;
}

.seo-tip-error {
  margin-top: 4px;
  opacity: 0.75;
}

.seo-tip-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  flex-shrink: 0;
}

.seo-tip-dot--pass {
  background: var(--primary);
}
.seo-tip-dot--warn {
  background: #ed6c02;
}
.seo-tip-dot--fail {
  background: var(--error);
}
.seo-tip-dot--unknown {
  background: var(--grey-500);
}

/* --- The structure graph -------------------------------------------------- */

/*
 * The radial site map. Ported from the dashboard's SiteStructureGraph so the two
 * draw the same picture — see assets/js/seo-check.js for the layout maths.
 *
 * The SVG SCALES TO FIT its box and never scrolls: a site map is a shape, and a
 * shape you have to drag around to see is not one. The cost is that a fifty-page
 * website draws smaller, which is why the labels give way above 26 nodes and the
 * score inside each hexagon is what always survives.
 */
.seo-graph {
  overflow: hidden;
  background: var(--bg-subtle);
  border: 1px solid var(--divider);
  border-radius: var(--radius-card);
}

.seo-edge {
  stroke: var(--divider);
  stroke-width: 2;
}

.seo-hex {
  cursor: pointer;
}

.seo-hex polygon {
  stroke: var(--bg-paper);
  stroke-width: 2;
  transition: filter 0.15s;
}

.seo-hex:hover polygon,
.seo-hex:focus-visible polygon {
  filter: brightness(1.08);
  stroke: var(--text);
}

.seo-hex.is-active polygon {
  stroke: var(--text);
  stroke-width: 3;
}

/* The three score bands. Never the only signal — every hexagon prints its
   number, because amber and red are one colour to a lot of readers. */
.seo-hex--pass polygon {
  fill: var(--primary);
}
.seo-hex--warn polygon {
  fill: #ed6c02;
}
.seo-hex--fail polygon {
  fill: var(--error);
}
.seo-hex--unknown polygon {
  fill: var(--grey-500);
}

.seo-hex-score {
  text-anchor: middle;
  dominant-baseline: middle;
  font-size: 13px;
  font-weight: 800;
  fill: #fff;
  pointer-events: none;
}

.seo-hex-label {
  text-anchor: middle;
  font-size: 12px;
  fill: var(--text-secondary);
  pointer-events: none;
}

.seo-legend {
  display: flex;
  flex-wrap: wrap;
  gap: 16px;
  margin-top: 12px;
  font-size: 0.8125rem;
  color: var(--text-secondary);
}

.seo-legend-item {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}

/* The swatch, so the legend says which colour it is naming. */
.seo-legend-item::before {
  content: "";
  width: 12px;
  height: 12px;
  border-radius: 3px;
}

.seo-legend--pass::before {
  background: var(--primary);
}
.seo-legend--warn::before {
  background: #ed6c02;
}
.seo-legend--fail::before {
  background: var(--error);
}

/* --- The advice dialog ---------------------------------------------------- */

.seo-dialog {
  position: fixed;
  inset: 0;
  z-index: 1300;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 16px;
  background: rgba(15, 23, 42, 0.5);
  overflow-y: auto;
}

/*
 * HEAD, SCROLLING BODY, ACTIONS — the dashboard dialog's three parts.
 *
 * The panel itself does not scroll; its body does. A fifty-line entry would
 * otherwise take its own title and its Close button off the top of the screen,
 * which on a phone leaves no way out of the dialog but the back gesture.
 */
.seo-dialog-panel {
  position: relative;
  display: flex;
  flex-direction: column;
  width: 100%;
  max-width: 640px;
  max-height: min(90vh, 820px);
  background: var(--bg-paper);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-6);
  overflow: hidden;
}

.seo-dialog-head {
  flex-shrink: 0;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 10px;
  /* Right padding clears the close button. */
  padding: 20px 56px 16px 24px;
}

.seo-dialog-heading {
  margin: 0;
  line-height: 1.3;
}

.seo-dialog-body {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  padding: 20px 24px;
  border-top: 1px solid var(--divider);
  border-bottom: 1px solid var(--divider);
}

.seo-dialog-actions {
  flex-shrink: 0;
  display: flex;
  justify-content: flex-end;
  padding: 12px 16px;
}

.seo-dialog-close {
  position: absolute;
  top: 12px;
  right: 12px;
}

/* 1. What the website says NOW — read before any of the advice below it. */
.seo-dialog-finding {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.seo-dialog-verdict {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 12px;
}

.seo-dialog-value {
  font-size: 0.875rem;
  font-weight: 600;
  word-break: break-word;
}

.seo-dialog-section {
  margin-top: 20px;
}

.seo-dialog-section h4 {
  margin: 0 0 6px;
}

.seo-dialog-blurb {
  display: block;
  margin-top: 8px;
}

.seo-dialog-nothing {
  margin-bottom: 6px;
}

.seo-dialog-panel p {
  margin: 0;
  line-height: 1.65;
}

.seo-dialog-panel code {
  padding: 1px 5px;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 0.86em;
  background: var(--grey-200);
  border-radius: 4px;
  /* A long attribute must be able to break, or it widens the dialog and every
     paragraph in it scrolls sideways. */
  word-break: break-word;
}

/*
 * The priority chip. Filled where the rule is urgent and outlined where it is
 * not, so the three levels are told apart by weight as well as by hue.
 */
.seo-priority--filled {
  border: 0;
  color: #fff;
}

.seo-priority--critical.seo-priority--filled {
  background: var(--error);
}
.seo-priority--important.seo-priority--filled {
  background: #ed6c02;
}
.seo-priority--optional {
  border-color: var(--divider);
  color: var(--text-secondary);
}

/* 5. Where to make the change — one note, the same for every row. */
.seo-note {
  display: flex;
  gap: 12px;
  margin-top: 24px;
  padding: 12px 14px;
  background: var(--info-bg);
  border-radius: var(--radius-card);
}

.seo-note .ico {
  flex-shrink: 0;
  margin-top: 2px;
  color: var(--info-text);
}

.seo-note p + p {
  margin-top: 2px;
}

.seo-steps {
  margin: 8px 0 0;
  padding-left: 20px;
  font-size: 0.875rem;
  line-height: 1.65;
  color: var(--text-secondary);
}

.seo-steps li {
  margin-bottom: 8px;
}

/* --- The banner on every other page --------------------------------------- */

/*
 * Advertises the checker from the rest of the site. A link, not a card with a
 * button in it: the whole strip is the target, which is what makes it work on a
 * phone where a 40px button inside a banner is a miss waiting to happen.
 */
.seo-banner {
  display: block;
  background: var(--tint-softer);
  border-top: 1px solid var(--divider);
  border-bottom: 1px solid var(--divider);
  text-decoration: none;
  color: inherit;
  transition: background-color 0.2s;
}

.seo-banner:hover {
  background: var(--tint-soft);
}

.seo-banner .container {
  display: flex;
  align-items: center;
  gap: 16px;
  padding-block: 20px;
}

.seo-banner-text {
  flex: 1;
  min-width: 0;
}

.seo-banner-text strong {
  display: block;
  font-size: 1rem;
}

.seo-banner-text span {
  font-size: 0.875rem;
  color: var(--text-secondary);
}

.seo-banner .ico {
  flex-shrink: 0;
  color: var(--primary);
}

/* ===========================================================================
   Scroll reveals
   ---------------------------------------------------------------------------
   Content that eases in as it scrolls into view — once, never again, never on
   a loop. Opacity and a short translate only: nothing scales, nothing bounces.

     data-reveal            fades in, rising 24px
     data-reveal="left"     fades in, travelling 40px in from the left
     data-reveal="right"    fades in, travelling 40px in from the right
     data-reveal-stagger    on a row of cards: each child rises in turn

   Hidden ONLY under `html.js`, which a one-line script in the page head sets,
   so without JavaScript nothing is ever hidden. site.js adds `.is-revealed`
   when the element enters the viewport, and when the transition has finished
   it removes both, handing the element back to its own styles — which is what
   keeps a card's hover lift working afterwards.
   =========================================================================== */

html.js [data-reveal] {
  opacity: 0;
  transform: translate3d(0, 24px, 0);
  transition:
    opacity 0.8s cubic-bezier(0.22, 1, 0.36, 1),
    transform 0.8s cubic-bezier(0.22, 1, 0.36, 1);
  transition-delay: var(--reveal-delay, 0ms);
}

html.js [data-reveal="left"] {
  transform: translate3d(-40px, 0, 0);
}

html.js [data-reveal="right"] {
  transform: translate3d(40px, 0, 0);
}

html.js [data-reveal].is-revealed {
  opacity: 1;
  transform: none;
}

/* Someone who asked their OS not to animate sees everything, still. */
@media (prefers-reduced-motion: reduce) {
  html.js [data-reveal] {
    opacity: 1;
    transform: none;
    transition: none;
  }
}

/* The same three links as the footer, at the top of a hero. A class of its own
   rather than `.footer-social`, whose colour is nailed to the footer's pale
   slate: here the links take the colour of the copy around them, so they read
   white on the dark heroes and dark on the light ones. */
.hero-social {
  display: flex;
  gap: 8px;
  margin-bottom: 4px;
}

.hero-social a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  border-radius: 50%;
  color: inherit;
  opacity: 0.85;
  transition: opacity 0.2s, background-color 0.2s;
}

.hero-social a:hover {
  opacity: 1;
  background: rgba(127, 127, 127, 0.16);
}

.hero-social .ico {
  font-size: 20px;
}

/* ===========================================================================
   We in social media
   ---------------------------------------------------------------------------
   Nine Instagram posts as cards, newest first. The card is a button: the
   picture, the date, four lines of the caption and nothing else — no likes,
   no comment counts. Clicking it opens the post dialog, where the picture
   takes 60% of the panel and the caption the remaining 40%.
   =========================================================================== */

.social-card-open {
  display: flex;
  flex-direction: column;
  width: 100%;
  height: 100%;
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  color: inherit;
  text-align: left;
  cursor: pointer;
}

.social-card-img {
  display: block;
  /* `height: auto` and `flex: none` are what actually hold the square: the
     element carries width/height attributes, and as a flex child it would
     otherwise take its height from the file (600px) rather than from its
     own width. */
  flex: none;
  width: 100%;
  height: auto;
  aspect-ratio: 1 / 1;
  object-fit: cover;
}

.social-card-body {
  display: flex;
  flex: 1;
  flex-direction: column;
  gap: 8px;
  padding: 16px;
}

/* Four lines, then an ellipsis — the rest is what the dialog is for. */
.social-card-text {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 4;
  line-clamp: 4;
  overflow: hidden;
  color: var(--text-secondary);
}

/* The hashtags, wherever they are shown. */
.social-tags {
  color: var(--primary);
  overflow-wrap: anywhere;
}

/* --- The post dialog ------------------------------------------------------
   The same scrim-and-panel as the SEO checker's advice dialog; only the split
   inside it is new.                                                         */

.social-dialog {
  position: fixed;
  inset: 0;
  z-index: 1300;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 16px;
  background: rgba(15, 23, 42, 0.5);
  overflow-y: auto;
}

.social-dialog-panel {
  display: flex;
  flex-direction: column;
  width: 100%;
  max-width: 1040px;
  max-height: min(90vh, 860px);
  background: var(--bg-paper);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-6);
  overflow: hidden;
}

.social-dialog-img {
  display: block;
  flex: none;
  width: 100%;
  height: auto;
  aspect-ratio: 1 / 1;
  object-fit: cover;
  background: var(--grey-200);
}

.social-dialog-side {
  display: flex;
  flex: 1;
  min-height: 0;
  flex-direction: column;
}

.social-dialog-head {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 16px 12px 12px 20px;
}

.social-dialog-close {
  flex-shrink: 0;
  min-width: 0;
  padding: 6px 10px;
}

.social-dialog-body {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 16px;
  padding: 16px 20px;
  border-top: 1px solid var(--divider);
  border-bottom: 1px solid var(--divider);
}

.social-dialog-actions {
  flex-shrink: 0;
  display: flex;
  justify-content: flex-end;
  padding: 12px 16px;
}

/* Tablet and up: the picture on the left at 60%, the caption on the right at
   40%, with only the caption scrolling. */
@media (min-width: 900px) {
  .social-dialog-panel {
    flex-direction: row;
  }

  .social-dialog-img {
    width: 60%;
    /* Square, like the post itself — the panel is as tall as the picture, and
       the caption beside it scrolls if it is longer. */
    height: auto;
    aspect-ratio: 1 / 1;
    align-self: flex-start;
    object-fit: cover;
  }

  .social-dialog-side {
    width: 40%;
  }
}

/* ===========================================================================
   The FAQ, on its own photograph
   ---------------------------------------------------------------------------
   The same sticky photograph as the sales-partner and "Areas we serve" sections:
   a 100vh layer at `top: 0` with the questions pulled up over it by `-100vh`.
   The picture holds still while the page scrolls the questions past it, and
   lets go with the end of the section — the wheel is never captured, so
   scrolling over the questions scrolls the page.

   NO `overflow: hidden` on the section: a clipping ancestor becomes the sticky
   element's scroller and it would stop sticking.
   =========================================================================== */

.faq-band {
  position: relative;
  isolation: isolate;
  min-height: 100vh;
}

.faq-bg {
  position: sticky;
  top: 0;
  height: 100vh;
  background: url("/assets/img/faq_bg.webp") center / cover no-repeat;
}

.faq-bg + .container {
  position: relative;
  z-index: 1;
  margin-top: -100vh;
  padding-block: 48px;
}

/* White copy on the scrim, and the questions as glass rather than white bricks. */
.faq-band .section-head,
.faq-band .section-head .primary-text,
.faq-band .section-head .muted {
  color: #fff;
}

.faq-band .section-head .muted {
  opacity: 0.92;
}

.faq-band .accordion {
  background: rgba(255, 255, 255, 0.12);
  backdrop-filter: blur(5px);
  -webkit-backdrop-filter: blur(5px);
  color: #fff;
}

.faq-band .accordion:hover {
  background: rgba(255, 255, 255, 0.18);
}

.faq-band .accordion > summary .ico {
  color: #fff;
}

.faq-band .accordion-body {
  color: rgba(255, 255, 255, 0.88);
}

/* ===========================================================================
   The home page carries no bold
   ---------------------------------------------------------------------------
   Every weight on this page is regular — the eyebrows, buttons, chips, the FAQ
   questions, the logo, the nav's current page, the state names and the avatar
   initials included. Scoped to `.page-home` so the shared components keep their
   weights on every other page.
   =========================================================================== */

.page-home,
.page-home .overline,
.page-home .btn,
.page-home .chip,
.page-home .avatar,
.page-home .accordion > summary,
.page-home .field > label,
.page-home .logo span,
.page-home .nav a.btn.is-active,
.page-home .drawer-list a.is-active,
.page-home .blog-card .cover .chip,
.page-home .areas .state,
.page-home .subtitle1,
.page-home .subtitle2,
.page-home .stat .value,
.page-home h1,
.page-home h2,
.page-home h3,
.page-home h4,
.page-home h5,
.page-home h6,
.page-home strong,
.page-home b {
  font-weight: 400;
}

/* ===========================================================================
   A dropdown of our own
   ---------------------------------------------------------------------------
   A native <select> draws its option list in the operating system, where no
   stylesheet reaches it — on the contact form's glass card that list looked
   like it came from somewhere else entirely. This is a button and a list, so
   the open menu matches the page. The value still lives in a hidden input, so
   the form posts exactly what it always did.
   =========================================================================== */

.dropdown {
  position: relative;
}

.dropdown-toggle {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  width: 100%;
  /* The field's own metrics, so it lines up with the inputs beside it. */
  font-family: inherit;
  font-size: 1rem;
  line-height: 1.4375em;
  color: var(--text);
  background-color: var(--bg-paper);
  padding: 14px;
  border: 1px solid var(--divider);
  border-radius: 4px;
  cursor: pointer;
  text-align: left;
  transition:
    border-color 0.2s,
    box-shadow 0.2s;
}

.card--glass .dropdown-toggle {
  background-color: rgba(255, 255, 255, 0.7);
  backdrop-filter: blur(5px);
  -webkit-backdrop-filter: blur(5px);
}

.dropdown-toggle:hover {
  border-color: var(--text);
}

.dropdown-toggle:focus-visible,
.dropdown[data-open] .dropdown-toggle {
  border-color: var(--primary);
  box-shadow: inset 0 0 0 1px var(--primary);
  outline: none;
}

.dropdown-toggle .ico {
  flex-shrink: 0;
  color: var(--text-secondary);
  transition: transform 0.2s;
}

.dropdown[data-open] .dropdown-toggle .ico {
  transform: rotate(180deg);
}

.dropdown-menu {
  position: absolute;
  z-index: 20;
  top: calc(100% + 4px);
  left: 0;
  right: 0;
  margin: 0;
  padding: 6px;
  list-style: none;
  background: var(--bg-paper);
  border: 1px solid var(--divider);
  border-radius: 8px;
  box-shadow: var(--shadow-6);
  max-height: 280px;
  overflow-y: auto;
}

.dropdown-menu li {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 10px 12px;
  border-radius: 6px;
  cursor: pointer;
  font-size: 0.9375rem;
  line-height: 1.5;
}

.dropdown-menu li:hover,
.dropdown-menu li:focus-visible,
.dropdown-menu li[data-active] {
  background: var(--primary-hover);
  outline: none;
}

/* The chosen one keeps the brand green and a tick, so the list says which it is
   without relying on the highlight alone. */
.dropdown-menu li[aria-selected="true"] {
  color: var(--primary);
}

.dropdown-menu li[aria-selected="true"]::after {
  content: "";
  width: 16px;
  height: 16px;
  margin-left: auto;
  background: currentColor;
  -webkit-mask: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M9 16.17 4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z'/%3E%3C/svg%3E") no-repeat center / contain;
  mask: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M9 16.17 4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z'/%3E%3C/svg%3E") no-repeat center / contain;
}
