/*
 * Marketing surface — one stylesheet, both vertical apexes.
 *
 * This is not the admin app's aesthetic and must not become it. DESIGN.md §1 splits three
 * surfaces with opposite requirements: the admin SPA optimises for density because staff
 * live in it all day, tenant sites are branded as the *tenant*, and this surface is our own
 * front door — calm, credible, premium. Borrowing the admin palette wholesale would make
 * our shop window look like a settings screen; inventing a third palette, which an earlier
 * version of this file did, makes the logo clash with the page it sits on.
 *
 * **The palettes are the product's own, per apex.** MassageSuite is blue (hue 260) and
 * SpaSuite is green (hue 163), the same hues and lightnesses as
 * `web/src/theme/tokens.generated.css`, scoped the same way the app scopes them —
 * `:root[data-brand="spasuite"]` — so one stylesheet serves both apexes and the wordmark's
 * own colours belong to the page around it. Each page declares its brand on <html>.
 *
 * No webfonts, deliberately. DESIGN.md §6 forbids hotlinking Google Fonts (a third-party
 * request on every page, a Core Web Vitals cost on the very metric the site builder is sold
 * on, and a live GDPR question in the EU) and self-hosting needs font files nobody has
 * subset yet. A system old-style serif for headings against the system humanist sans is the
 * pairing that reads "spa" most reliably anyway. Zero layout shift as a side effect.
 *
 * Dark is marketing-only. The app has no dark token block yet, so there is nothing to match;
 * these values are derived by holding each brand's hue and inverting the lightness ramp.
 */

/* MassageSuite Blue — the default, matching tokens.generated.css :root. */
:root {
  --ground: oklch(0.982 0.006 260);
  --ground-raised: oklch(0.998 0.0009 260);
  --ink: oklch(0.255 0.006 260);
  --ink-soft: oklch(0.5 0.006 260);
  --rule: oklch(0.905 0.006 260);
  --accent: oklch(0.5 0.15 260);
  --accent-hover: oklch(0.41 0.155 260);
  --accent-wash: oklch(0.96 0.019 260);
  /*
   * Interactive boundaries are a separate token from decorative ones, and darker.
   * DESIGN.md §7 requires 3:1 for UI boundaries — a section separator is decoration and
   * exempt, but the edge of a button is what makes it read as a button, so it is not.
   * Measured, not guessed: `--rule` against the ground is 1.28:1, which is why reusing it
   * on the quiet button was a real failure against our own stated floor.
   */
  --edge: oklch(0.6 0.02 260);
  --focus: oklch(0.585 0.15 260);

  --measure: 34rem;
  --shell: 68rem;
}

/* SpaSuite Green. Lower chroma than the blue, exactly as the app's block has it. */
:root[data-brand='spasuite'] {
  --ground: oklch(0.982 0.007 163);
  --ground-raised: oklch(0.998 0.0029 163);
  --ink: oklch(0.255 0.007 163);
  --ink-soft: oklch(0.5 0.007 163);
  --rule: oklch(0.905 0.007 163);
  --accent: oklch(0.5 0.105 163);
  --accent-hover: oklch(0.41 0.11 163);
  --accent-wash: oklch(0.96 0.045 163);
  --edge: oklch(0.6 0.022 163);
  --focus: oklch(0.585 0.105 163);
}

/*
 * Declared after both light blocks on purpose. `:root[data-brand=...]` out-specifies
 * a bare `:root`, so a light brand block would otherwise beat the dark default and SpaSuite
 * would never go dark.
 */
@media (prefers-color-scheme: dark) {
  :root {
    --ground: oklch(0.19 0.012 260);
    --ground-raised: oklch(0.23 0.013 260);
    --ink: oklch(0.95 0.006 260);
    --ink-soft: oklch(0.74 0.01 260);
    --rule: oklch(0.32 0.012 260);
    --accent: oklch(0.78 0.11 260);
    --accent-hover: oklch(0.86 0.09 260);
    --accent-wash: oklch(0.26 0.03 260);
    --edge: oklch(0.66 0.026 260);
    --focus: oklch(0.8 0.12 260);
  }

  :root[data-brand='spasuite'] {
    --ground: oklch(0.19 0.012 163);
    --ground-raised: oklch(0.23 0.013 163);
    --ink: oklch(0.95 0.006 163);
    --ink-soft: oklch(0.74 0.01 163);
    --rule: oklch(0.32 0.012 163);
    --accent: oklch(0.78 0.08 163);
    --accent-hover: oklch(0.86 0.07 163);
    --accent-wash: oklch(0.26 0.025 163);
    --edge: oklch(0.66 0.026 163);
    --focus: oklch(0.8 0.09 163);
  }
}

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

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

body {
  margin: 0;
  background: var(--ground);
  color: var(--ink);
  font-family: system-ui, -apple-system, 'Segoe UI', sans-serif;
  font-size: 1.0625rem;
  line-height: 1.65;
  text-rendering: optimizeLegibility;
}

h1,
h2,
h3 {
  font-family: 'Iowan Old Style', 'Palatino Linotype', Palatino, Georgia, serif;
  font-weight: 600;
  line-height: 1.18;
  letter-spacing: -0.012em;
  margin: 0;
  text-wrap: balance;
}

h1 {
  font-size: clamp(2.1rem, 5.2vw, 3.4rem);
}
h2 {
  font-size: clamp(1.5rem, 3vw, 2rem);
}
h3 {
  font-size: 1.1rem;
  font-family: system-ui, sans-serif;
  font-weight: 600;
  letter-spacing: 0;
}

p {
  margin: 0 0 1rem;
  max-width: var(--measure);
}

a {
  color: var(--accent);
  text-decoration-thickness: 1px;
  text-underline-offset: 0.18em;
}
a:hover {
  color: var(--accent-hover);
}

/* Visible on a light ground, and never removed — DESIGN.md §7. */
:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 3px;
  border-radius: 3px;
}

.shell {
  max-width: var(--shell);
  margin-inline: auto;
  padding-inline: clamp(1.25rem, 5vw, 2.5rem);
}

/* ---- Masthead ---------------------------------------------------------- */

.masthead {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding-block: 1.5rem;
  flex-wrap: wrap;
}

/*
 * The wordmark is the supplied artwork, not type set to look like it.
 *
 * Sized by height with width auto, because the two lockups have different aspect ratios —
 * MassageSuite is 5.1:1 and SpaSuite 3.3:1, since its badge is circular and its type sits
 * smaller inside the same box. Matching heights would make the blue one read much wider, so
 * each page sets its own and they are tuned to look like the same weight of mark, not the
 * same number of pixels.
 *
 * The files are cropped to their artwork. The originals carry 37–52% empty space below the
 * lockup, so an uncropped image at this height would render the mark at half its apparent
 * size and float it in a box of nothing.
 */
.wordmark {
  display: inline-flex;
  align-items: center;
  text-decoration: none;
}

.wordmark img {
  display: block;
  height: var(--wordmark-height, 2rem);
  width: auto;
}

/* Only one of the pair is ever shown; the other is display:none, so both are fetched but
   the swap needs no JavaScript and no flash. */
:root .wordmark .on-dark { display: none; }
:root .wordmark .on-light { display: block; }

@media (prefers-color-scheme: dark) {
  :root .wordmark .on-dark { display: block; }
  :root .wordmark .on-light { display: none; }
}

.masthead nav {
  display: flex;
  gap: 1.5rem;
  align-items: center;
  font-size: 0.95rem;
  flex-wrap: wrap;
}

/*
 * Staff sign-in: the way back in, and the last thing in the primary nav so it lands in the
 * top-right corner. That corner is a convention worth obeying rather than improving on — a
 * returning owner looks there first and does not read the page to find it.
 *
 * It is the *only* button in the masthead, on purpose. The acquisition CTA used to sit here
 * too, and two pills side by side present a returning user's errand and a stranger's errand
 * as alternatives to each other. The masthead is not sticky, so a CTA here was visible only
 * while the hero's larger primary button was also on screen — it was competing for the corner
 * and buying nothing.
 *
 * Reuses .btn-quiet's tokens unchanged, so the measured floors carry over: text --ink on
 * --ground is 14.97:1 light / 15.96:1 dark, and the --edge border that makes it read as a
 * control is 3.75:1 (MassageSuite) and 3.72:1 (SpaSuite) light, 5.94/5.99:1 dark — above the
 * DESIGN.md §7 floor of 3:1 for UI boundaries, which is why it borrows --edge and not --rule.
 */
/*
 * Tighter horizontal padding than a hero button, because this is a nav-scale control. No
 * margin separating it from the anchors: the nav wraps at narrow widths and any inline start
 * margin puts the pill 4px out of alignment with the links above it on the wrapped line,
 * which is more visible than the extra breathing room was on desktop. A bordered pill beside
 * three plain text links is already unmistakably a different kind of thing.
 */
.nav-signin {
  padding-inline: 1rem;
}

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

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  /* 44px minimum touch target, per DESIGN.md §7. */
  min-height: 44px;
  padding: 0.6rem 1.35rem;
  border-radius: 7px;
  font: inherit;
  font-weight: 550;
  text-decoration: none;
  border: 1px solid transparent;
  cursor: pointer;
  transition: background-color 140ms ease, border-color 140ms ease;
}

@media (prefers-reduced-motion: reduce) {
  .btn {
    transition: none;
  }
}

.btn-primary {
  background: var(--accent);
  border-color: var(--accent);
  /* Against the accent's lightness, both themes need their own ink. */
  color: var(--ground-raised);
}
.btn-primary:hover {
  background: var(--accent-hover);
  border-color: var(--accent-hover);
  color: var(--ground-raised);
}

.btn-quiet {
  border-color: var(--edge);
  color: var(--ink);
  background: transparent;
}
.btn-quiet:hover {
  border-color: var(--accent);
  color: var(--accent);
}

/* ---- Sections ---------------------------------------------------------- */

.hero {
  padding-block: clamp(3rem, 9vw, 6rem) clamp(2.5rem, 7vw, 4.5rem);
}

.lede {
  font-size: clamp(1.1rem, 2.1vw, 1.3rem);
  color: var(--ink-soft);
  max-width: 40rem;
  margin-block: 1.25rem 2rem;
}

.actions {
  display: flex;
  gap: 0.75rem;
  flex-wrap: wrap;
}

section {
  padding-block: clamp(2.5rem, 6vw, 4rem);
  border-top: 1px solid var(--rule);
}

.section-lede {
  color: var(--ink-soft);
  margin-bottom: 2.25rem;
}

.grid {
  display: grid;
  gap: 1.5rem 2rem;
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
  margin: 0;
  padding: 0;
  list-style: none;
}

.grid h3 {
  margin-bottom: 0.35rem;
}

.grid p {
  color: var(--ink-soft);
  font-size: 0.98rem;
  margin: 0;
  max-width: none;
}

/* A single claim that deserves to stand alone. */
.claim {
  background: var(--accent-wash);
  border: 1px solid var(--rule);
  border-radius: 12px;
  padding: clamp(1.5rem, 4vw, 2.25rem);
}

.claim p:last-child {
  margin-bottom: 0;
}

/* ---- Pricing ------------------------------------------------------------ */

/*
 * Two cards, and only two — the layout is allowed to assume that, because
 * ARCHITECTURE.md §11.5 decided two tiers and rejected a per-seat ladder. `auto-fit` at a
 * 19rem floor puts them side by side from about 44rem and stacks them below it, which is the
 * only breakpoint this section needs.
 *
 * `align-items: start` matters: without it the shorter card stretches to the taller one and
 * its border ends in the middle of nothing, which reads as a rendering fault rather than as
 * a shorter list.
 */
.plans {
  display: grid;
  gap: 1.25rem;
  grid-template-columns: repeat(auto-fit, minmax(19rem, 1fr));
  align-items: start;
  margin: 0 0 2.5rem;
  padding: 0;
  list-style: none;
}

.plan {
  background: var(--ground-raised);
  border: 1px solid var(--rule);
  border-radius: 12px;
  padding: clamp(1.35rem, 3.5vw, 1.9rem);
}

/*
 * The plan this apex's own reader is most likely on — Basic on MassageSuite, Pro on SpaSuite,
 * because the apex is positioning (ARCHITECTURE.md §11.3) and the same two plans are being
 * shown to two different businesses.
 *
 * Marked with the accent wash and the interactive `--edge` border rather than a "Most
 * popular" ribbon: we have no popularity data, and inventing the claim on a pricing page is
 * exactly the kind of thing the rest of this site refuses to do. The wash is the same one the
 * single claim box uses, at the same weight — it points, it does not shout.
 */
.plan-lead {
  background: var(--accent-wash);
  border-color: var(--edge);
}

.plan h3 {
  font-family: 'Iowan Old Style', 'Palatino Linotype', Palatino, Georgia, serif;
  font-size: 1.35rem;
  letter-spacing: -0.01em;
}

.price {
  display: flex;
  align-items: baseline;
  gap: 0.45rem;
  flex-wrap: wrap;
  margin: 0.5rem 0 0.4rem;
  max-width: none;
}

.price b {
  font-family: 'Iowan Old Style', 'Palatino Linotype', Palatino, Georgia, serif;
  font-size: clamp(2.1rem, 5vw, 2.6rem);
  font-weight: 600;
  line-height: 1.05;
  letter-spacing: -0.02em;
}

.price span {
  color: var(--ink-soft);
  font-size: 0.95rem;
}

.plan-for {
  color: var(--ink-soft);
  font-size: 0.96rem;
  max-width: none;
  margin-bottom: 1.2rem;
}

/* Same dash-and-text shape as `.scope`, because it is the same kind of list and a second
   bullet convention on one page is one more thing for a reader to decode. */
.plan-lines {
  display: grid;
  gap: 0.65rem;
  margin: 0;
  padding: 0;
  list-style: none;
  font-size: 0.98rem;
}

.plan-lines li {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 0.65rem;
  align-items: baseline;
  color: var(--ink-soft);
}

.plan-lines b {
  color: var(--ink);
  font-weight: 600;
}

.plan-lines span[aria-hidden] {
  color: var(--accent);
  font-weight: 600;
}

/* The one sentence a plan owes that is not a feature — separated by a rule so it does not
   read as another line item. */
.plan-note {
  margin: 1.2rem 0 0;
  padding-top: 1rem;
  border-top: 1px solid var(--rule);
  color: var(--ink-soft);
  font-size: 0.92rem;
  max-width: none;
}

.pricing-notes {
  max-width: 44rem;
}

.pricing-notes p {
  color: var(--ink-soft);
  max-width: none;
}

.pricing-notes b {
  color: var(--ink);
  font-weight: 600;
}

/* A URL read as one thing. Wrapping `massagesuite.app/spa/your-practice` mid-path turns an
   example address into two fragments the reader has to reassemble. */
.nowrap {
  white-space: nowrap;
}

/* ---- Fit ---------------------------------------------------------------- */

/*
 * The covered-entity statement. A panel rather than plain prose, because it is the one
 * passage on the page a reader may need to find again and send to somebody else — and
 * deliberately *not* `.claim`, whose accent wash is spent on the exclusion constraint. Two
 * accent boxes on one page would make neither of them the one thing worth stopping at.
 */
.fit {
  background: var(--ground-raised);
  border: 1px solid var(--rule);
  border-inline-start: 3px solid var(--edge);
  border-radius: 12px;
  padding: clamp(1.4rem, 3.5vw, 2rem);
}

.fit p {
  max-width: 46rem;
}

.fit p:last-child {
  margin-bottom: 0;
}

.scope {
  display: grid;
  gap: 0.9rem;
  margin: 0;
  padding: 0;
  list-style: none;
  max-width: 44rem;
}

.scope li {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 0.65rem;
  align-items: baseline;
  color: var(--ink-soft);
}

.scope b {
  color: var(--ink);
  font-weight: 600;
}

.scope span[aria-hidden] {
  color: var(--accent);
  font-weight: 600;
}

footer {
  border-top: 1px solid var(--rule);
  padding-block: 2.5rem 3.5rem;
  color: var(--ink-soft);
  font-size: 0.92rem;
}

footer p {
  max-width: none;
}

/*
 * The footer is where a reader who got to the bottom looks for the two things the page owes
 * them: the way in and the way to reach a person. Both are repeated here rather than assumed
 * remembered from the masthead 3,000 pixels up.
 *
 * The cross-apex link is *not* duplicated into this row. It already exists one line below, in
 * the sentence that explains which of the two brands the reader wants — a bare "MassageSuite"
 * in a link row says less than the sentence does, and two anchors to one href in one footer is
 * a link a screen reader announces twice for no gain.
 *
 * Links here inherit --accent: 5.81:1 (MassageSuite) / 5.41:1 (SpaSuite) light, 9.20 / 9.52:1
 * dark, against the DESIGN.md §7 text floor of 4.5:1. No border between the row and the
 * sentence — the accent-versus-ink-soft colour difference already separates them, and the
 * footer already carries a rule at its top.
 */
.footer-nav {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 1.75rem;
  margin-bottom: 1.25rem;
}
