/* ===========================================================================
   Meetowt — landing page
   Aesthetic: "Civic Blueprint". Industrial/utilitarian dominant, editorial
   secondary. The product is infrastructure a company owns outright, so the
   page borrows from technical drawings and surveyors' plates: warm paper,
   hairline rules, monospace annotations, an oxide-red marking colour, and
   numbered specification rows instead of icon cards.

   Fonts are self-hosted on purpose. A page selling "nothing leaves your
   building" should not phone Google for its typefaces.
   =========================================================================== */

@font-face {
  font-family: "Bricolage";
  src: url("/fonts/bricolage.woff2") format("woff2");
  font-weight: 200 800;
  font-display: swap;
}
@font-face {
  font-family: "PlexSans";
  src: url("/fonts/plexsans.woff2") format("woff2");
  font-weight: 100 700;
  font-display: swap;
}
@font-face {
  font-family: "PlexMono";
  src: url("/fonts/plexmono.woff2") format("woff2");
  font-weight: 400 500;
  font-display: swap;
}

:root {
  --paper:      #f4f0e6;
  --paper-deep: #eae4d6;
  --ink:        #16140f;
  --ink-soft:   #4c463a;
  --ink-faint:  #6c6557;   /* darkened: #857d6c was 3.59:1 on paper, below AA */
  --rule:       #cec5ae;
  --rule-soft:  #ddd5c2;
  --accent:     #a83a17;   /* oxide red — a surveyor's marking, not a SaaS gradient */
  --accent-ink: #7d2a10;

  /* THE ACCENT DOES NOT WORK ON THE INK BAND, AND THIS IS THE PAIR THAT DOES.
     --accent measures 2.88:1 on --ink, well under AA, so the inverse section
     and the checked pay label cannot use it. This lighter oxide measures
     6.73:1 there. It was written as a raw hex in two rules and had no name,
     which is how a third use ends up being a fourth colour.

     IT IS FOR INK GROUNDS ONLY. On --paper it measures 2.40:1 — unreadable.
     Nothing outside .section--inverse and the checked pay label may use it. */
  --accent-on-ink: #e8814f;

  /* Depth, as two steps rather than as a value somebody picks each time. Both
     are the ink colour at low alpha — the same rgba already used by .plate —
     so this adds no colour to the palette, only a way to say "this sits above
     that". The flat 6px offset on .plate stays what it is: that one is a
     drawing convention, not an elevation. */
  --lift-1: 0 1px 2px rgba(22,20,15,.05), 0 2px 8px rgba(22,20,15,.05);
  --lift-2: 0 2px 4px rgba(22,20,15,.06), 0 10px 26px rgba(22,20,15,.08);

  --shell: 74rem;
  --step:  1.5rem;

  --display: "Bricolage", Georgia, serif;
  --body:    "PlexSans", "Segoe UI", sans-serif;
  --mono:    "PlexMono", ui-monospace, monospace;
}

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

html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  /* THE DELAYS GO TOO, NOT ONLY THE DURATIONS. Zeroing duration alone leaves
     any transition-delay standing — the pay panels hold `visibility 0s linear
     .16s` so a fading panel stays on screen for the length of its own fade,
     and with no fade there is nothing to wait for. A delay with no animation
     behind it is a pause a person did not ask for. */
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    animation-delay: 0s !important;
    transition-duration: .01ms !important;
    transition-delay: 0s !important;
    scroll-behavior: auto !important;
  }
}

/* EVERY JUMP TARGET CLEARS THE STICKY BAR, not just the ones in the legal
   pages. This used to be `.legal h2[id], .legal h3[id]` and nothing else, so
   "See pricing" in the hero scrolled #pricing's top edge to y=0 and the 4.25rem
   bar covered the first 12px of the heading's cap height — about 40% of it — on
   a phone. The same for #what, #compare and #questions, and for the one clause
   on the privacy page that is a <p> rather than a heading and so missed the
   narrower rule at every width.

   Written against [id] deliberately. scroll-margin costs nothing on an element
   nobody ever jumps to, and a rule listing the elements that are targets today
   is a rule that is wrong the first time somebody adds an anchor. */
[id] { scroll-margin-top: 5.5rem; }

/* The skip link has to move FOCUS, not only the scroll position, and that
   needs main to be focusable — see the tabindex="-1" on it in every page.
   Focusing a whole page region needs no ring: the visitor asked to be there. */
main[tabindex="-1"]:focus { outline: none; }

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font: 400 1.0625rem/1.65 var(--body);
  /* Faint plan-view grid. Sets the drawing-board mood without any images. */
  background-image:
    linear-gradient(to right, rgba(22,20,15,.032) 1px, transparent 1px),
    linear-gradient(to bottom, rgba(22,20,15,.032) 1px, transparent 1px);
  background-size: 2.5rem 2.5rem;
}

/* THE hidden ATTRIBUTE LOSES TO ANY CLASS THAT SETS display. The "Ask us"
   button is a .btn, and .btn sets display:inline-flex, which beats the browser's
   own [hidden] { display: none } — so ask.js hid the button and the button
   stayed on screen next to the form it had just opened. One line, everywhere,
   rather than remembering it at each call site. */
[hidden] { display: none !important; }

.shell { width: min(100% - 2.5rem, var(--shell)); margin-inline: auto; }

.skip {
  position: absolute; left: -9999px;
  background: var(--ink); color: var(--paper); padding: .75rem 1rem; z-index: 99;
}
.skip:focus { left: 1rem; top: 1rem; }

/* FIELDS AND ANYTHING GIVEN A tabindex ARE IN HERE TOO. The list used to be
   links and buttons, which left every text box on the site with nothing but the
   browser's default ring — and the pages that restyle their fields cancelled
   that without putting anything back. */
:where(a, button, input, textarea, select, summary, [tabindex]):focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
}

/* ── Type scale ─────────────────────────────────────────────────────────── */

h1, h2, h3 { font-family: var(--display); font-weight: 700; letter-spacing: -.022em; margin: 0; }
/* THE FLOOR CAME DOWN BECAUSE IT WAS WINNING ON EVERY PHONE. At 375px the old
   clamp resolved to its 2.6rem floor — 6.2vw is only 23px there — so the
   headline was set at 41.6px in a 335px measure. "Your company email," is about
   388px of advance at that size, so it broke again inside the line break the
   author had already chosen, and a three-line headline became six lines with
   half the breaks picked by the browser.
   The intercept keeps the large end where it was: at 1245px this still reaches
   the 4.5rem cap, and at 768px it lands within 2px of the old curve. */
h1 { font-size: clamp(2.15rem, 4.4vw + 1rem, 4.5rem); line-height: 1.04; text-wrap: balance; }
/* The line breaks the author chose, kept where they fit and dropped where they
   do not — see the note beside them in index.html. */
@media (max-width: 34rem) { .hero__break { display: none; } }
h2 { font-size: clamp(1.9rem, 3.6vw, 2.7rem); line-height: 1.12; }
h3 { font-size: 1.2rem; line-height: 1.3; }

h1 em {
  font-style: normal;
  color: var(--accent);
  /* Hand-underlined, like a drawing annotation */
  box-shadow: inset 0 -.14em 0 rgba(168,58,23,.18);
}

p { margin: 0 0 1rem; }

.tag, .plate__head, .plate__foot, .specs__num, .section__num, .tier__flag, .foot__note {
  font-family: var(--mono);
  font-size: .72rem;
  letter-spacing: .14em;
  text-transform: uppercase;
}

/* ── Top bar ────────────────────────────────────────────────────────────── */

/* OPAQUE, AND IT HAS TO BE. This was 88% paper over a page that is also paper,
   with a blur that had two identical tones to blur between — so the bar was
   invisible as a layer and headings and the background grid slid through it on
   the way past. The only edge was a hairline at 1.51:1.

   A solid ground plus a soft shadow is the whole fix: the bar is now a thing
   ABOVE the page rather than a tint on it, and the shadow is what says so.
   No script, so it reads the same on the first still frame as on the last. */
.topbar {
  border-bottom: 1px solid var(--rule);
  background: var(--paper);
  box-shadow: var(--lift-1);
  position: sticky; top: 0; z-index: 20;
}
.topbar__inner { display: flex; align-items: center; justify-content: space-between; gap: 1rem; height: 4.25rem; }

.wordmark {
  display: inline-flex; align-items: center; gap: .6rem;
  font-family: var(--display); font-weight: 800; font-size: 1.15rem;
  letter-spacing: -.02em; color: var(--ink); text-decoration: none;
}
.wordmark__mark {
  width: 1.35rem; height: 1.35rem;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 200 200'%3E%3Cpath d='M124 148 H144 A24 24 0 0 0 168 124 V76 A24 24 0 0 0 144 52 H56 A24 24 0 0 0 32 76 V124 A24 24 0 0 0 56 148' fill='none' stroke='%2316140f' stroke-width='30' stroke-linecap='round' stroke-linejoin='round'/%3E%3Ccircle cx='125' cy='92' r='21' fill='%23c2410c'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: center;
  background-size: contain;
}

.topbar nav { display: flex; align-items: center; gap: 1.6rem; }
.topbar nav a { color: var(--ink-soft); text-decoration: none; font-size: .95rem; }
.topbar nav a:hover { color: var(--ink); }
.nav-cta {
  color: var(--ink) !important;
  border-bottom: 2px solid var(--accent);
  padding-bottom: 1px;
}

/* ── Hero ───────────────────────────────────────────────────────────────── */

.hero { padding: clamp(3.5rem, 9vw, 7rem) 0 clamp(3rem, 7vw, 5.5rem); }
.hero__grid {
  display: grid;
  gap: clamp(2.5rem, 5vw, 4.5rem);
  /* Deliberately asymmetric: the plate is a sidebar annotation, not a twin column */
  grid-template-columns: minmax(0, 1.55fr) minmax(0, 1fr);
  align-items: start;
}

.tag { color: var(--accent); margin: 0 0 1.4rem; display: flex; align-items: center; gap: .7rem; }
.tag::after { content: ""; flex: 1; height: 1px; background: var(--rule); }

/* THE ONE OPENING MOMENT ON THE PAGE, AND IT MOVES NO WORDS.
   The rule beside the hero label draws itself from left to right, once, the way
   a line is drawn on a technical sheet. That is the whole of it: no section
   fading up on scroll, no number counting, nothing parked at opacity 0 waiting
   for an observer.

   The rule is decoration and carries no meaning, so the first still frame — the
   one a shared link, a thumbnail and a fast reader all get — is complete with it
   half drawn or not drawn at all. Nothing that says anything is allowed to
   animate in; the test for adding another of these is whether a reader who
   never sees it has lost a word.

   transform-only, so it costs no layout. It runs on the hero of every page,
   never below the fold, and never twice. */
@keyframes rule-drawn { from { transform: scaleX(0); } to { transform: scaleX(1); } }
.hero .tag::after {
  transform-origin: left center;
  animation: rule-drawn .65s cubic-bezier(.22,.61,.36,1) both;
}
@media (prefers-reduced-motion: reduce) {
  .hero .tag::after { animation: none; }
}

.lede {
  font-size: 1.18rem;
  color: var(--ink-soft);
  max-width: 34rem;
  margin-top: 1.6rem;
}

.cta-row { display: flex; flex-wrap: wrap; gap: .75rem; margin-top: 2.2rem; }

.btn {
  display: inline-flex; align-items: center; justify-content: center;
  font-family: var(--body); font-weight: 600; font-size: .97rem;
  padding: .8rem 1.5rem;
  text-decoration: none;
  border: 1.5px solid var(--ink);
  transition: transform .12s ease, background-color .12s ease,
              border-color .12s ease, color .12s ease, box-shadow .12s ease;
}

/* THE BUTTON PEOPLE ARE MEANT TO PRESS IS THE ACTION COLOUR NOW, rather than
   black that turns orange once a pointer is already on it. This is the change
   @DECISIONS.md recorded making in the product on 14 September and deliberately
   held back here — "worth doing, not worth doing silently in the same change as
   the product". It is being done here on purpose and by itself.

   The reason it was worth doing is the same reason: A TOUCHSCREEN HAS NO
   POINTER. On a phone the accent never touched Get started at all, so the one
   control the page exists to lead somebody to was the same colour as the
   furniture around it, and told apart from the ghost button beside it only by
   fill.

   Measured before it shipped, like every other colour on this page: --paper on
   --accent is 5.62:1, and on --accent-ink for the hover it is 8.35:1. */
.btn--solid {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--paper);
}
.btn--solid:hover {
  background: var(--accent-ink);
  border-color: var(--accent-ink);
  transform: translateY(-2px);
  box-shadow: var(--lift-1);
}
.btn--ghost { background: transparent; color: var(--ink); }
.btn--ghost:hover { background: var(--ink); color: var(--paper); transform: translateY(-2px); }

/* IT GOES BACK, AND IT GOES BACK UNDER A FINGER TOO. A hover lift with no
   pressed state leaves a touch device holding the raised position until
   something else is tapped, which reads as a button that stuck. */
.btn:active { transform: translateY(0); box-shadow: none; }
.btn--full { width: 100%; margin-top: auto; }
.btn--lg { padding: 1rem 2.2rem; font-size: 1.05rem; }

/* The spec plate — the thing you remember 24 hours later */
.plate {
  border: 1.5px solid var(--ink);
  background: var(--paper-deep);
  box-shadow: 6px 6px 0 rgba(22,20,15,.09);
}
.plate__head {
  display: flex; justify-content: space-between;
  padding: .6rem .85rem;
  border-bottom: 1.5px solid var(--ink);
  color: var(--ink);
  background: var(--paper);
}
.plate__rows { margin: 0; }
.plate__rows > div {
  display: flex; justify-content: space-between; align-items: baseline; gap: 1rem;
  padding: .7rem .85rem;
  border-bottom: 1px dashed var(--rule);
}
/* --ink-soft: the plate's ground is --paper-deep, where --ink-faint is
   4.56:1 on this .85rem text. Every label in the spec plate is this line. */
.plate__rows dt { color: var(--ink-soft); font-size: .85rem; }
.plate__rows dd {
  margin: 0; font-family: var(--mono); font-size: .85rem; text-align: right;
}
.plate__rows dd.mark { color: var(--accent); font-weight: 500; }
/* --ink-soft rather than --ink-faint, and the reason is the ground under it.
   --ink-faint measures 5.07:1 on --paper but only 4.56:1 on --paper-deep, which
   is what this sits on — legal, and with no headroom at all, on 11.5px mono
   tracked at .14em carrying the price. --ink-soft is 7.38:1 there. */
.plate__foot {
  display: flex; align-items: center; flex-wrap: wrap; gap: .3rem .55rem;
  padding: .7rem .85rem; color: var(--ink-soft);
}
/* The price and the words that qualify it break together or not at all. */
.plate__foot > span:not(.tick) { white-space: nowrap; }
.tick { width: .5rem; height: .5rem; background: var(--accent); display: inline-block; }

/* ── Sections ───────────────────────────────────────────────────────────── */

.section { padding: clamp(3.5rem, 8vw, 6rem) 0; border-top: 1px solid var(--rule); }

/* ONE TONE STEP, NOT A HAIRLINE, WHERE TWO LONG SECTIONS MEET.
   The homepage was six consecutive full-width bands of the same paper with one
   dark one at position five, and the only thing between any two of them was a
   1px rule measuring 1.51:1 against the ground it sits on. Three of those bands
   run 1,200 to 2,000 pixels; somebody scrolling fast could leave the pricing and
   arrive in the comparison table without a single signal that anything changed.

   So alternate sections sit on the deeper paper. It is the token the cards
   already use, it needs no new colour, and it is applied BY HAND rather than by
   :nth-child — a band changing ground because somebody inserted a section above
   it is exactly the kind of drift this file's comments exist to stop.

   IT IS ON #compare AND NOWHERE ELSE ON THE HOMEPAGE, which is the boundary the
   reader actually loses: pricing, the comparison and the questions run roughly
   1,500, 2,000 and 1,200 pixels back to back with only a hairline between them.
   One step in the middle of the three separates all three.

   CHECK WHAT IS INSIDE BEFORE PUTTING IT ON ANOTHER SECTION. .tier and
   .addon-band are --paper-deep themselves and would vanish on this ground —
   which is why #pricing stays on paper. .sums is handled below by flipping to
   the LIGHTER paper, so on this band it reads as raised rather than disappears.
   And --ink-faint drops from 5.07:1 to 4.56:1 here, so the small text that used
   it takes --ink-soft instead. */
.section--deep { background: var(--paper-deep); border-top-color: var(--rule); }
.section--deep .sums { background: var(--paper); }
.section--deep .fineprint,
.section--deep .cmp__early { color: var(--ink-soft); }

.section__title { display: flex; align-items: baseline; gap: 1rem; margin-bottom: 1rem; }
.section__num { color: var(--accent); font-size: .8rem; }
.section__lede { color: var(--ink-soft); max-width: 38rem; margin-bottom: 2.8rem; }

/* THE STANDFIRST AND THE ARGUMENT ARE NOT THE SAME THING, and on the three
   inner pages .section__lede had become the class for both — ten of them across
   five sections on one page, four consecutive ones inside a single section. Each
   carried 2.8rem of space beneath it, so the sentence introducing a section
   looked exactly like the fourth paragraph of it and the sections had no
   internal hierarchy at all: everything was the intro.

   .section__lede is the ONE sentence under a heading. Everything after it is
   .prose, set at ordinary paragraph rhythm. */
.prose { color: var(--ink-soft); max-width: 38rem; margin: 0 0 1.1rem; }
.prose:last-child { margin-bottom: 0; }

/* Numbered specification rows, not a grid of icon cards */
.specs { list-style: none; margin: 2.5rem 0 0; padding: 0; }
/* THE DIVIDER WAS BELOW THE POINT AT WHICH A HAIRLINE REGISTERS AS A LINE.
   --rule-soft measures 1.28:1 against the paper, and section 01 is the longest
   uninterrupted stretch on the homepage — nine rows of identical weight, colour
   and spacing, no imagery, and effectively no dividers either.

   A TINT OF --ink-faint RATHER THAN A FLAT TOKEN, and the reason is that these
   rows appear on two grounds. --rule is 1.51:1 on the paper and drops to 1.36:1
   on the deeper one, so a section that takes the tone step would have had its
   structure taken away again. Mixed with transparent the browser composites it
   over whatever is behind: 1.73:1 on paper and 1.68:1 on the deep ground —
   consistently visible on both, and no new colour, only an existing token at
   40%.

   The --rule line above it is the fallback for a browser with no color-mix. It
   is what these rows have today, so the worst case is no change. */
.specs li {
  display: grid;
  grid-template-columns: 4rem minmax(0, 1fr);
  gap: 0 1.5rem;
  padding: 1.6rem 0;
  border-top: 1px solid var(--rule);
  border-top-color: color-mix(in srgb, var(--ink-faint) 40%, transparent);
}
.specs li:last-child {
  border-bottom: 1px solid var(--rule);
  border-bottom-color: color-mix(in srgb, var(--ink-faint) 40%, transparent);
}
.specs__num { grid-column: 1; color: var(--accent); padding-top: .35rem; }
/* Both the heading and the body sit in the second column. Without this, grid
   auto-placement drops the paragraph back into the 4rem number column and it
   renders one word per line. */
.specs h3 { grid-column: 2; margin-bottom: .4rem; }
.specs p  { grid-column: 2; color: var(--ink-soft); max-width: 46rem; margin: 0; }
/* The date under a "recently shipped" entry. Quiet on purpose — it is the least
   interesting part of the line and should not compete with the heading.

   DECLARED HERE rather than at the end of the file, which is where it was
   first written. Down there it came after the max-width block below, so its
   grid-column: 2 beat the one-column mobile override at every width and the
   date rendered as a 134px-tall sliver down the edge of the phone. */
/* THE opacity WENT, AND IT WAS A CONTRAST FAILURE RATHER THAN A PREFERENCE.
   --ink-soft at 60% over the paper computes to #8f8a7f, which is 3.02:1 — below
   the 4.5:1 AA minimum, on 11.5px uppercase mono. An alpha is not a colour the
   palette was measured with; what it produces is. --ink-faint is the token for
   quiet text and is 5.07:1 here. */
.specs__when {
  grid-column: 2;
  display: block;
  margin-top: .5rem;
  font-family: var(--mono);
  font-size: .72rem;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

/* Inverted band — the one heavy block on the page */
.section--inverse {
  background: var(--ink);
  color: var(--paper);
  border-top-color: var(--ink);
}
.section--inverse .section__num { color: var(--accent-on-ink); }
.section--inverse h3 { margin-bottom: .5rem; }
.section--inverse p { color: rgba(244,240,230,.72); margin: 0; }
.why__grid {
  display: grid; gap: 2.2rem;
  grid-template-columns: repeat(auto-fit, minmax(min(15rem, 100%), 1fr));
  margin-top: 2.8rem;
}

/* ── Pricing ────────────────────────────────────────────────────────────── */

.tiers {
  display: grid; gap: 1.25rem;
  grid-template-columns: repeat(auto-fit, minmax(min(16.5rem, 100%), 1fr));
  align-items: stretch;
}

/* A single plan in a grid built for three stretches to the full width of the
   page and reads as a banner rather than a price. Capped and centred. */
.tiers--one {
  grid-template-columns: minmax(0, 26rem);
  justify-content: center;
}

.tier__small {
  margin: .9rem 0 0;
  text-align: center;
  font-size: .85rem;
  color: var(--ink-faint);
}

/* The paragraph about this not being free forever. Deliberately given room
   rather than shrunk into a footnote — it is the part people will hold us to. */
.pricing__honest {
  max-width: 46rem;
  margin: 2.2rem auto 0;
  padding: 1.1rem 1.3rem;
  border-left: 3px solid var(--rule);
  color: var(--ink-soft);
  font-size: .95rem;
  line-height: 1.65;
}
.pricing__honest strong { color: var(--ink); }
.tier {
  display: flex; flex-direction: column;
  border: 1.5px solid var(--rule);
  background: var(--paper-deep);
  padding: 1.6rem 1.5rem;
}
/* THE ONE CARD ON THE PAGE THAT IS GENUINELY ABOVE THE GROUND. The flat 6px
   offset stays — it is the drawing convention the spec plate uses and the two
   should read as the same family — with an ambient shadow behind it so the card
   sits on the page rather than being a rectangle with a line beside it. This is
   the object the whole section is for; it is allowed to be the thing that lifts.
   No hover, no scroll trigger: it is not a control and it does not move. */
.tier--pick {
  border-color: var(--ink);
  border-width: 2px;
  background: var(--paper);
  box-shadow: 6px 6px 0 rgba(22,20,15,.1), var(--lift-2);
}
.tier__flag {
  display: inline-block;
  background: var(--accent); color: var(--paper);
  padding: .25rem .6rem; margin: 0 0 .8rem;
}
.tier__for { color: var(--ink-faint); font-size: .9rem; margin: .3rem 0 0; }
.tier__price {
  font-family: var(--display); font-weight: 800;
  font-size: 2.9rem; line-height: 1; letter-spacing: -.03em;
  margin: 1.4rem 0 .2rem;
}
.tier__price--word { font-size: 2.1rem; }

/* THE PRICE THAT WILL APPLY, SHOWN STRUCK THROUGH BESIDE THE ONE THAT APPLIES
   TODAY. A free tier that quietly becomes a bill is how you lose the people who
   took a chance on you first, so the real number is on the page from the start
   rather than in a footnote. <s> carries that meaning to a screen reader too —
   "no longer accurate" — and .sr-only spells it out for one. */
.tier__was {
  display: block;
  font-size: 1.4rem;
  line-height: 1.3;
  color: var(--ink-faint);
  text-decoration: line-through;
  text-decoration-thickness: 2px;
  margin-bottom: .35rem;
}
/* THE CURRENCY MARK SITS ON THE BASELINE HERE, unlike the live price above it.
   .cur is superscripted and half-size for a big number; at this size that made
   "$1" read as "$" with a subscript, and the line ran straight into
   "/person/month". */
.tier__was .cur { font-size: 1em; vertical-align: baseline; margin-right: .06rem; }
.tier__was .per { font-size: .78rem; margin-left: .3rem; }
.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;
}
.cur { font-size: 1.3rem; vertical-align: super; margin-right: .1rem; }
.per { font-family: var(--body); font-size: .95rem; font-weight: 400; color: var(--ink-faint); }
.tier__seats { font-size: .95rem; color: var(--ink-soft); margin-bottom: 1.4rem; }

.tier__list { list-style: none; margin: 0 0 1.8rem; padding: 0; }
.tier__list li {
  position: relative;
  padding: .45rem 0 .45rem 1.4rem;
  font-size: .95rem;
  color: var(--ink-soft);
  border-bottom: 1px dashed var(--rule-soft);
}
.tier__list li::before {
  content: ""; position: absolute; left: 0; top: .95rem;
  width: .45rem; height: .45rem; background: var(--accent);
}

.fineprint { margin-top: 2rem; font-size: .87rem; color: var(--ink-faint); max-width: 42rem; }

/* ── Monthly or yearly ──────────────────────────────────────────────────── */

/* TWO RADIO BUTTONS AND A `:checked ~` RULE, NOT A SCRIPT, AND THAT IS THE
   WHOLE POINT OF IT. Everything else on this site degrades to "the page as it
   was published" when JavaScript does not arrive — the customer strip, the
   what's-new list, the price figures themselves. A switch cannot degrade that
   way: a switch that does not switch is a control that silently does nothing,
   which is the dead end window.confirm left in eleven buttons in the product.
   So both prices are in the markup and the browser does the swapping. */
.pay {
  /* A fieldset for the group name a screen reader reads out. Its own default
     border, padding and min-width are all in the way here. */
  border: 0;
  padding: 0;
  margin: 1.3rem 0 0;
  min-width: 0;
}

/* OFF SCREEN RATHER THAN display:none. A radio that is not displayed cannot be
   focused or reached with the arrow keys, and these two ARE the control — the
   labels beside them are only what it looks like. */
.pay__radio {
  position: absolute;
  width: 1px; height: 1px;
  opacity: 0;
  margin: 0; padding: 0;
  pointer-events: none;
}

.pay__choice {
  display: flex;
  flex-wrap: wrap;
  gap: .35rem;
  border: 1.5px solid var(--ink);
  padding: .3rem;
}

/* Each half takes what is left and wraps rather than squeezing, so the pair
   still reads on a narrow phone inside a card that is already padded. */
.pay__opt {
  flex: 1 1 8rem;
  display: flex;
  align-items: baseline;
  justify-content: center;
  gap: .4rem;
  padding: .55rem .7rem;
  font-size: .95rem;
  color: var(--ink-soft);
  text-align: center;
  cursor: pointer;
}
/* Under 200ms, and it goes back. The fill used to snap, which on a control
   whose whole job is to say "this is the one you picked" reads as a redraw
   rather than as an answer. */
.pay__opt {
  position: relative;
  transition: background-color .15s ease, color .15s ease;
}
.pay__opt:hover { color: var(--ink); }

/* THE SAVING IS A WORD AS WELL AS A COLOUR. Nobody reads a tint as "cheaper",
   and one man in twelve cannot separate this one from the ink around it. */
.pay__save {
  font-size: .78rem;
  color: var(--accent-ink);
  white-space: nowrap;
}
/* Empty when there is no discount to name — see pricing.js. Without this the
   gap in .pay__opt still holds a space open beside the word. */
.pay__save:empty { display: none; }

#pay-monthly:checked ~ .pay__choice label[for="pay-monthly"],
#pay-yearly:checked ~ .pay__choice label[for="pay-yearly"] {
  background: var(--ink);
  color: var(--paper);
}
/* The same orange .section--inverse uses on ink, rather than a new one: that
   pair is already on the page and already measured. --accent-ink is for the
   paper behind it and is far too dark here. */
#pay-monthly:checked ~ .pay__choice label[for="pay-monthly"] .pay__save,
#pay-yearly:checked ~ .pay__choice label[for="pay-yearly"] .pay__save {
  color: var(--accent-on-ink);
}

/* The focus ring has to be drawn on the label, because the thing actually
   focused is a radio nobody can see. */
#pay-monthly:focus-visible ~ .pay__choice label[for="pay-monthly"],
#pay-yearly:focus-visible ~ .pay__choice label[for="pay-yearly"] {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* SWITCHING IS A REAL STATE CHANGE AND IS THE ONE PLACE ON THIS PAGE THAT
   EARNS A TRANSITION. A price that swaps instantly reads as the page redrawing;
   the same price arriving over 160ms reads as an answer to what was just
   pressed. It is the only motion here that a person triggers.

   TRANSITIONS, NOT KEYFRAMES, AND THAT IS THE WHOLE TRICK. A transition does
   not run on first paint — it only runs on a CHANGE — so the monthly panel is
   at full opacity in the first still frame rather than being parked at nought
   waiting for something. An @keyframes with a from-state would have put the
   price invisible in the frame a shared link and a thumbnail get.

   THE TWO PANELS ARE STACKED IN ONE GRID CELL rather than one being display:
   none. display cannot transition, and stacking has a second benefit worth more
   than the fade: the card is the height of the taller panel either way, so
   switching no longer shoves the button and the feature list up or down.

   visibility rather than opacity alone, so the panel nobody chose is out of the
   accessibility tree instead of being read out invisibly. Its delay is what
   keeps it on screen for the length of its own fade out. */
.pay__panels { display: grid; align-items: start; }
.pay__panel {
  grid-area: 1 / 1;
  opacity: 0;
  visibility: hidden;
  transform: translateY(.3rem);
  transition: opacity .16s ease, transform .16s ease, visibility 0s linear .16s;
}
#pay-monthly:checked ~ .pay__panels .pay__panel[data-pay="monthly"],
#pay-yearly:checked  ~ .pay__panels .pay__panel[data-pay="yearly"] {
  opacity: 1;
  visibility: visible;
  transform: none;
  transition: opacity .16s ease, transform .16s ease, visibility 0s;
}

.pay__note {
  margin: .5rem 0 0;
  font-size: .9rem;
  line-height: 1.55;
  color: var(--ink-soft);
}

/* ── Close ──────────────────────────────────────────────────────────────── */

.section--close { text-align: center; }
.close h2 { margin-bottom: .8rem; }
.close p { color: var(--ink-soft); margin-bottom: 2rem; }

/* ── Footer ─────────────────────────────────────────────────────────────── */

/* A FOOTER THAT LOOKS LIKE A FOOTER. It was the same paper as the section above
   it, separated by a hairline at 1.51:1, directly under a closing section that
   is also paper, also centred and also ends in a button — so the wordmark and
   the five links read as one more line of the page rather than the end of it.
   A tone step and a real rule are the whole change. */
.foot {
  border-top: 1px solid var(--ink-faint);
  background: var(--paper-deep);
  padding: 2.4rem 0;
}
.foot__inner { display: flex; flex-wrap: wrap; gap: 1rem; justify-content: space-between; align-items: center; }
.foot__inner > span:first-child { font-family: var(--display); font-weight: 800; }
/* --ink-soft, not --ink-faint: this sits on --paper-deep now, where --ink-faint
   is 4.56:1 on text of .72rem. */
.foot__note { color: var(--ink-soft); }

/* ── Narrow screens ─────────────────────────────────────────────────────── */

@media (max-width: 56rem) {
  .hero__grid { grid-template-columns: 1fr; }
  .plate { max-width: 26rem; }
  .specs li { grid-template-columns: 1fr; gap: .4rem; }
  /* .specs__when belongs in this list for the same reason as the rest: the
     grid drops to ONE column here, so anything still asking for column 2 is
     asking for a track that does not exist and gets laid out in a sliver.
     The date rendered 134px tall down the side of the phone before this line. */
  .specs__num, .specs h3, .specs p, .specs__when { grid-column: 1; }
  .specs__num { padding-top: 0; }
}
@media (max-width: 34rem) {
  .topbar nav { gap: 1rem; }

  /* Only the in-page jump links go. They are shortcuts to sections the reader
     can reach by scrolling, so on a narrow screen they cost more room than
     they are worth.

     This used to be `a:not(.nav-cta)`, which hid everything that was not the
     one button — and that included "Sign in". On a phone there was then no
     way into the product at all for somebody who already had an account, on
     the page every visitor lands on.

     Naming what to hide rather than what to keep is the whole fix. A new link
     added to this nav is now visible by default, and the failure that leaves
     is a slightly crowded bar rather than a customer who cannot get in. */
  .topbar nav a.nav-jump { display: none; }

  /* Thumb-sized. What is left is a 45x25 link and a 77x28 one, both under
     Apple's 44pt and Android's 48dp minimum — small enough that missing them
     is normal rather than clumsy, on the one control a returning customer
     needs.

     Grown with a pseudo-element rather than padding. Padding would make the
     box 44px tall and drag the CTA's accent underline down to the bottom of
     it, away from the text it belongs to. This leaves every pixel of ink
     exactly where it is and only widens what a thumb can hit. The bar is
     4.25rem tall, so the larger area stays inside it. */
  .topbar nav a { position: relative; }
  .topbar nav a::after {
    content: "";
    position: absolute;
    inset: -.6rem -.35rem;
  }
}

/* --- Pricing add-on band ---------------------------------------------------
   WHAT IS STILL BEING BUILT, SAID BESIDE THE PRICE RATHER THAN MET IN WEEK ONE.
   It sits below the tiers because it applies to all of them.

   THIS COMMENT USED TO DESCRIBE A PAID EXTRA and was left behind when the copy
   above it changed - it argued that the band existed so nobody discovered a
   charge at checkout, over markup that now says the opposite: nothing on the
   roadmap is ever a second line on a bill. A stale comment arguing for the
   wrong thing is worse than none, because the next person writes the copy back
   towards it. The price element it justified (.addon-band__price) went with it;
   there is no price in this band and there must not be one.
   -------------------------------------------------------------------------- */

/* A SETTLED PROMISE, INKED. See the note above .sums for why the three boxes in
   this section no longer look alike. Constrained and centred with the rest of
   the pricing column — it used to run the full 74rem shell while the price it
   qualifies sat in a 26rem card, so the widest thing in the section was the
   caveat about the roadmap rather than the number. */
.addon-band {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  justify-content: space-between;
  gap: 1.5rem 2.5rem;
  max-width: 46rem;
  margin: 2.5rem auto 0;
  padding: 1.6rem 1.8rem;
  border: 1px solid var(--rule);
  border-left: 3px solid var(--ink);
  background: var(--paper-deep);
}

.addon-band__body { flex: 1 1 26rem; }

.addon-band__tag {
  font-family: var(--mono, ui-monospace, monospace);
  font-size: .7rem;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--accent);
  margin: 0 0 .4rem;
}

.addon-band__title { margin: 0 0 .6rem; font-size: 1.25rem; }

.addon-band__body p {
  margin: 0 0 .6rem;
  color: var(--ink-soft);
  max-width: 42rem;
}

/* --ink-soft rather than --ink-faint: this box is --paper-deep, where
   --ink-faint drops to 4.56:1 and this is .9rem text. */
.addon-band__note {
  font-size: .9rem;
  color: var(--ink-soft) !important;
  margin-bottom: 0 !important;
}

/* The pricing column, anchored once. The tier card, the honest paragraph, the
   add-on band and the two lines of fineprint used to sit at four different
   measures with three different alignments, so the eye was re-anchored four
   times inside one section. They share a measure now and the card stays the
   widest thing that carries a number. */
#pricing .fineprint { max-width: 46rem; margin-inline: auto; }

@media (max-width: 40rem) {
  .addon-band { flex-direction: column; }
}



/* Questions.
   Deliberately plain text rather than an accordion. A <details> would be
   tidier, but the answers here exist to be READ BY A MACHINE as much as by a
   person, and text that is open on the page is the version nothing can argue
   with. Two columns on a wide screen so ten questions do not become a scroll. */
/* minmax(min(20rem, 100%), 1fr), NOT minmax(20rem, 1fr), AND THE DIFFERENCE IS
   A SIDEWAYS-SCROLLING PAGE. A grid track cannot shrink below its own minimum,
   so on a 320px screen — an iPhone SE, or an Android in split view — a 20rem
   floor is 320px inside a 280px shell and the questions section pushed the
   whole document 40px wide. At 375px the shell is 335px and the margin is 15px,
   which is why it was invisible one step up.
   Every auto-fit track on this site carries the same guard now. */
.qa-list {
  display: grid;
  gap: 2.2rem 3rem;
  grid-template-columns: repeat(auto-fit, minmax(min(20rem, 100%), 1fr));
}
.qa__q {
  font-size: 1.05rem;
  line-height: 1.35;
  margin: 0 0 .5rem;
  text-wrap: balance;
}
.qa__q::before {
  content: "";
  display: block;
  width: 1.6rem;
  height: 2px;
  background: var(--accent);
  margin-bottom: .7rem;
}
.qa__a {
  margin: 0;
  color: var(--ink-soft);
  font-size: .95rem;
  line-height: 1.65;
  max-width: 34rem;
}


/* ── Inner pages ────────────────────────────────────────────────────────── */

/* The homepage hero is a two-column grid with the spec plate as its right-hand
   annotation. These pages have no plate, so without a measure the headline and
   lede would run the full width of the shell and become unreadable at the top
   of the one page a stranger landed on. Constrained rather than re-designed:
   same type, same spacing, just a line length somebody can follow. */
.hero--page > .shell > * { max-width: 44rem; }

/* .tag draws a rule to its right with flex:1, which on a full-width hero would
   stretch most of the viewport and read as a mistake. */
.hero--page .tag { max-width: 30rem; }

.foot__nav {
  display: flex;
  flex-wrap: wrap;
  gap: .3rem 1.4rem;
}
.foot__nav a {
  color: var(--ink-soft);
  text-underline-offset: 3px;
}
.foot__nav a:hover,
.foot__nav a:focus-visible { color: var(--accent); }

/* --------------------------------------------------------------------------
   Legal pages
   --------------------------------------------------------------------------
   Privacy and terms are read differently from the rest of the site: somebody
   is looking for one clause, not being persuaded. So the measure is narrower
   than a marketing section, the headings are numbered so a clause can be cited
   ("see 4.2"), and lists get the only list styling in this stylesheet — the
   rest of the site has no prose lists at all, which is why a bare <ul> here
   would have inherited browser defaults and looked like a different website.
   -------------------------------------------------------------------------- */
.legal { max-width: 42rem; }
.legal h2 { margin: 2.6rem 0 .8rem; }
.legal h3 { margin: 1.8rem 0 .6rem; font-size: 1.05rem; }
.legal p { color: var(--ink-soft); }
.legal ul { margin: 0 0 1rem; padding-left: 1.1rem; color: var(--ink-soft); }
.legal li { margin: 0 0 .45rem; }
.legal a { color: var(--accent-ink); }

/* The date a version of this document took effect. Kept beside the title
   rather than at the foot: "which version am I reading" is the first question
   anybody asks of a policy, and the last place they look is the bottom. */
.legal__stamp {
  font-family: var(--mono);
  font-size: .72rem;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--ink-faint);
  margin: 0 0 1.6rem;
}

/* A clause somebody will be pointed at by support. Given a target so a link
   like /privacy.html#keeping lands on it rather than near it. */
.legal h2[id], .legal h3[id] { scroll-margin-top: 5rem; }

/* --------------------------------------------------------------------------
   "Ask us"
   --------------------------------------------------------------------------
   The form behind the button on the privacy and terms pages. Its own classes
   rather than the sign-up form's: those live in signup.css, which these pages
   do not load, so borrowing them would have rendered browser defaults inside a
   carefully set page.
   -------------------------------------------------------------------------- */
/* A CONTROL THAT ONLY WORKS ONCE ITS SCRIPT HAS ARRIVED IS NOT ON THE PAGE
   UNTIL THEN. "Ask us" is a <button type="button"> with no behaviour of its
   own — ask.js builds the entire form behind it — so with scripts blocked it
   was a button that silently did nothing, which is the exact dead end that
   file's own header says it exists to remove. The plain-text mail address
   underneath it is the honest route and is already there.

   Done in the stylesheet rather than with a <noscript> in each page, because
   terms.html carries a placeholder and a deploy guard and is not ours to edit —
   and a fix that reaches one of the two pages carrying this button is not a
   fix. ask.js adds .is-live to every trigger it has actually wired up. */
[data-ask]:not(.is-live) { display: none !important; }

.ask { max-width: 34rem; margin: 1.2rem auto 0; text-align: left; }
.ask__field { display: block; margin: 0 0 .9rem; }
.ask__label {
  display: block;
  font-size: .85rem;
  font-weight: 600;
  color: var(--ink);
  margin: 0 0 .35rem;
}
/* THE EDGE OF A FORM CONTROL IS NOT DECORATION AND HAS TO MEET 3:1.
   --rule measures 1.51:1 against --paper, and it was the ONLY boundary on every
   text box on this site — no fill difference, no shadow, a hairline at under
   half the non-text minimum. To anybody with reduced contrast sensitivity the
   fields were not visibly controls at all. --ink-faint is 5.07:1 here.

   The inset shading is the second half of it and is doing a job rather than
   decorating: a field is a recess, and saying so with light is the signal that
   works when the border is the thing somebody cannot see. */
.ask textarea,
.ask input {
  width: 100%;
  font: inherit;
  font-size: .95rem;
  color: var(--ink);
  background: var(--paper);
  border: 1px solid var(--ink-faint);
  box-shadow: inset 0 1px 2px rgba(22,20,15,.07);
  padding: .6rem .7rem;
  border-radius: 0;
}
.ask textarea { resize: vertical; min-height: 5.5rem; }
.ask textarea:focus,
.ask input:focus { outline: 2px solid var(--accent); outline-offset: 1px; }
.ask__actions { display: flex; gap: .6rem; margin-top: .2rem; }
.ask__said:empty { display: none; }
.ask__said {
  margin: .7rem 0 0;
  font-size: .85rem;
  color: var(--accent-ink);
}

/* ===========================================================================
   Who runs on it
   ---------------------------------------------------------------------------
   A row of logos, each one turning over on its own to show the next company.
   The turn is the point: a short list laid flat reads as a short list, while a
   strip that keeps changing reads as one too long to show at once — without
   claiming a single name that is not true.

   NO BOXES. Every logo was in a bordered plate, which made the row look like a
   set of buttons and made each mark smaller than the frame around it. The
   frames are gone and the marks are as large as the row will allow.

   The ground stays the same near-white as the rest of the page rather than the
   deeper paper: plenty of logos are supplied with a white background baked in,
   and on a darker strip every one of those would sit in a white rectangle of
   its own — the boxes back again, drawn by the customer's own file.
   =========================================================================== */

.customers {
  padding-block: 3.5rem;
  border-top: 1px solid var(--rule-soft);
  border-bottom: 1px solid var(--rule-soft);
  background: var(--paper);
}

.customers__lede {
  margin: 0 0 2.2rem;
  text-align: center;
  font-family: var(--mono);
  font-size: .7rem;
  letter-spacing: .18em;
  text-transform: uppercase;
  /* The smallest, most widely tracked text on the page. --ink-faint is legal
     here at 5.07:1 and has nothing to spare; this does. */
  color: var(--ink-soft);
}

/* Flex rather than a fixed column count, because the number of logos is the
   number of customers and that is not ours to pad. Four columns holding two
   marks reads as two missing ones. */
.customers__row {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: center;
  /* Narrower than it was, with the plate below, so FOUR of them fit on one line
     from the 56rem breakpoint upward: 4 x 11rem plus three 2.5rem gaps is 824px
     inside an 856px shell. The row therefore never gains a line when the server
     answers with more names than the markup shipped, which was a ~208px shove
     of everything below it waiting to happen. */
  gap: 1.5rem 2.5rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

/* THE STRIP CAN BE STOPPED, AND UNTIL NOW IT COULD NOT BE. Text that rewrites
   itself every 2.6 seconds, for ever, beside copy somebody is reading is a
   WCAG 2.2.2 failure outright — moving content over five seconds needs a pause,
   stop or hide, and there was no button and no keyboard way to reach one.

   Built by customers.js rather than written here, so it does not exist on a
   page where nothing is moving: a Pause button with scripts blocked would be
   another control that silently does nothing. */
.customers__stop {
  display: block;
  margin: 1.4rem auto 0;
  padding: .35rem .8rem;
  background: transparent;
  border: 1px solid var(--ink-faint);
  color: var(--ink-soft);
  font-family: var(--mono);
  font-size: .68rem;
  letter-spacing: .14em;
  text-transform: uppercase;
  cursor: pointer;
  transition: color .12s ease, border-color .12s ease, background-color .12s ease;
}
.customers__stop:hover { color: var(--ink); border-color: var(--ink); background: var(--paper-deep); }

/* `perspective` here rather than on the row so each one turns about its own
   centre instead of sharing a vanishing point with its neighbours, which at
   this width looks like a mistake rather than an effect. */
.customer {
  perspective: 700px;
  height: 5rem;
  flex: 0 1 11rem;
}

.customer__face {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 100%;
  /* No border, no fill: the mark stands on the page. */
  font-family: var(--display, inherit);
  font-weight: 700;
  font-size: 1.35rem;
  color: var(--ink-soft);
  text-align: center;
  /* Long names shrink rather than break the row. */
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  transition: transform .55s ease, color .55s ease;
  transform-style: preserve-3d;
}

/* As large as the row allows. A logo is the whole point of the strip; it
   should not be a detail inside something else. */
.customer__logo {
  max-height: 4.4rem;
  max-width: 100%;
  object-fit: contain;
  /* NO mix-blend-mode HERE, AND IT IS NOT AN OVERSIGHT. `multiply` is the
     usual trick for a logo supplied on a white rectangle, and it does nothing
     on this row: the plate sets `perspective` and the face sets
     `transform-style: preserve-3d` for the turn, each of which starts its own
     stacking context, and blending is isolated inside one. It applies, it
     computes, and the white box stays exactly where it was.

     So the white is taken out of the picture instead, when it is uploaded —
     see shrinkLogo in components/CompanyAssets.tsx. That fixes it here and at
     the foot of every email as well, which no stylesheet of ours could reach. */
}

/* The invitation is not a company and should not pretend to be one. Quieter
   than a real mark, so it reads as the end of the list rather than another
   name on it. */
.customer--invite .customer__face {
  font-weight: 600;
  font-size: 1.05rem;
  color: var(--ink-faint);
}

/* Mid-turn: edge on, and blank for the moment nobody can read it anyway. The
   script swaps the face at this point, so what comes back is the new one. */
.customer--turning .customer__face {
  transform: rotateX(90deg);
  color: transparent;
}

.customer--turning .customer__logo {
  opacity: 0;
}

/* SOMEBODY WHO HAS ASKED FOR LESS MOVEMENT GETS NONE — AND THAT NOW MEANS THE
   NAMES AS WELL AS THE TURN.
   This used to remove the rotation and deliberately keep the content change,
   on the grounds that the strip is information rather than decoration. It is
   information, and text that silently rewrites itself every 2.6 seconds beside
   the copy somebody is reading is the thing a reduced-motion setting is asking
   us to stop. customers.js starts paused under this query instead, so the row
   holds still and the Pause button reads Play — a person who wants the rest of
   the names presses it and gets them one at a time. Nothing is withheld; it
   simply waits to be asked. */
@media (prefers-reduced-motion: reduce) {
  .customer__face { transition: none; }
  .customer--turning .customer__face { transform: none; }
}


/* ===========================================================================
   COMPARISON — "Against what you pay now" (#compare in index.html)

   AT THE FOOT OF THE FILE ON PURPOSE. This section was written while other
   people were editing the pricing blocks above. A rule appended here cannot
   collide with a change made in the middle of the stylesheet, and everything
   below is either a token from the top of this file or a class of its own.

   NO NEW COLOURS, and that is not laziness. Every value here is one of the
   tokens that were MEASURED against paper, surface and raised before they
   shipped — see @DECISIONS.md. A comparison table is almost entirely small
   text, which is exactly where the old palette turned out to be failing AA at
   3.59:1, found only by measuring the running page.

   COLOUR IS NEVER THE ONLY SIGNAL. "Included", "Not in these plans" and
   "Depends on the licence" each carry their own WORD and their own SHAPE — a
   filled square, a rule, an outlined square. One man in twelve cannot separate
   red from green, and the staff list already learned this expensively when two
   coloured dots per person had to become labels.
   =========================================================================== */

/* ── The worked sum ─────────────────────────────────────────────────────── */

/* FOUR CALLOUTS ON ONE SCROLL USED TO BE THE SAME BOX FOUR TIMES.
   .sums, .addon-band and .coming were pixel-identical — 1px --rule, a 3px
   accent left edge, --paper-deep — and .pricing__honest was the same shape in
   grey. They carry four different kinds of statement: a worked arithmetic
   proof, a promise about the bill, a roadmap, and the warning that free ends.
   A reader had no way to tell which was which before reading it.

   Each one says what it is now:
     .sums          a proof, and the only one that lifts off the page
     .addon-band    a settled promise — inked left edge, no accent
     .coming        the future, drawn in dashes and not yet filled in
     .pricing__honest  unchanged: a rule beside prose, not a box at all */
.sums {
  margin: 0 0 3rem;
  padding: 1.4rem 1.6rem 1.2rem;
  border: 1px solid var(--rule);
  border-left: 3px solid var(--accent);
  background: var(--paper-deep);
  box-shadow: var(--lift-1);
}

.sums__head {
  font-family: var(--mono);
  font-size: .72rem;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--accent);
  margin: 0 0 .5rem;
}

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

/* EVERY ROW CARRIES ITS OWN TOP RULE, including the first. Excusing the first
   one looks tidier and breaks the moment pricing.js hides a row: :first-child
   still matches the hidden element, so the rule vanishes from a row that is on
   screen and the list starts with a gap. */
.sums__row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto auto;
  align-items: baseline;
  gap: .25rem 1.2rem;
  padding: .5rem 0;
  border-top: 1px solid var(--rule-soft);
}

.sums__what { font-size: .97rem; }
.sums__what em { font-style: normal; color: var(--ink-faint); }

 /* --ink-soft. This is the smallest text in the section — .78rem mono — and it
    sits on a card whose ground is --paper-deep at least some of the time, where
    --ink-faint is 4.56:1 with no headroom at all. */
.sums__work {
  font-family: var(--mono);
  font-size: .78rem;
  color: var(--ink-soft);
  white-space: nowrap;
}

.sums__total {
  font-family: var(--display);
  font-weight: 700;
  font-size: 1.15rem;
  line-height: 1.2;
  white-space: nowrap;
  text-align: right;
  min-width: 5.5rem;
}

.sums__row--ours .sums__what { font-weight: 600; }
.sums__row--ours .sums__total { color: var(--accent); }

.sums__after {
  margin: 1rem 0 0;
  font-size: .92rem;
  color: var(--ink-soft);
  max-width: 44rem;
}

/* ── The table ──────────────────────────────────────────────────────────── */

/* Only worth saying where the table cannot fit. aria-hidden in the markup,
   because the scrolling region announces itself to a screen reader already and
   being told to scroll sideways is no help to somebody not looking at it. */
.cmp__swipe { display: none; }

.cmp__wrap {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  border: 1px solid var(--rule);
  background: var(--paper);
}

/* The global focus ring is :where(a, button) only, and this is neither — but it
   is focusable, because a table wider than the screen is otherwise reachable
   with a finger and with nothing else. */
.cmp__wrap:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
}

.cmp {
  width: 100%;
  border-collapse: collapse;
  font-size: .92rem;
}

.cmp th,
.cmp td {
  text-align: left;
  vertical-align: top;
  padding: .75rem .9rem;
  border-top: 1px solid var(--rule-soft);
  min-width: 8.5rem;
}

.cmp thead th {
  border-top: 0;
  border-bottom: 1px solid var(--rule);
  font-family: var(--display);
  font-size: 1rem;
  font-weight: 700;
  white-space: nowrap;
}

/* THE NAME OF THE ROW STAYS PUT WHILE THE PLANS SCROLL PAST IT. Without this,
   scrolling a six-column table on a phone leaves five columns of "Included"
   with nothing on screen saying what is included. */
.cmp tbody th[scope="row"] {
  position: sticky;
  left: 0;
  z-index: 1;
  min-width: 11.5rem;
  font-family: var(--body);
  font-weight: 600;
  background: var(--paper);
  /* A BOX-SHADOW RATHER THAN border-right, and it is not a preference. Under
     border-collapse: collapse the borders belong to the TABLE, not to the
     cell, so they do not travel with a sticky cell — the edge slides away and
     the frozen column bleeds into the one scrolling under it. A shadow is
     painted by the cell and stays where the cell is.

     THE SECOND HALF OF THIS PAIR IS A REAL CAST SHADOW, and it is the clearest
     piece of depth on the site because it is depth that is TRUE: this column
     genuinely is above the ones sliding underneath it. With a hairline alone
     the frozen names and the scrolling plans read as one flat grid and nothing
     says which part is moving. Painted, never animated — the shadow is simply
     there, and what moves past it is the content. */
  box-shadow: 1px 0 0 var(--rule), 7px 0 12px -7px rgba(22,20,15,.28);
}

.cmp td { color: var(--ink-soft); }

/* The price row is sentences rather than one word, so it reads at the size of
   the rest of the page instead of the size of a label. */
.cmp__price { font-size: .88rem; line-height: 1.5; }

/* Our column, boxed the way the chosen plan is boxed in the pricing block
   above rather than tinted a colour of its own. */
.cmp .cmp__ours {
  background: var(--paper-deep);
  border-left: 2px solid var(--ink);
  border-right: 2px solid var(--ink);
}
.cmp thead th.cmp__ours { border-top: 2px solid var(--ink); color: var(--accent); }
.cmp tbody tr:last-child .cmp__ours { border-bottom: 2px solid var(--ink); }
.cmp tbody td.cmp__ours { color: var(--ink); }

/* The three answers. The shape is drawn with an empty pseudo-element, so there
   is nothing for a screen reader to read out beside the word already there. */
.cmp__yes,
.cmp__no,
.cmp__part {
  display: inline-block;
  position: relative;
  padding-left: 1.05rem;
}
.cmp__yes::before,
.cmp__no::before,
.cmp__part::before {
  content: "";
  position: absolute;
  left: 0;
}

.cmp__yes { color: var(--ink); }
.cmp__yes::before {
  top: .45rem;
  width: .45rem; height: .45rem;
  background: var(--accent);
}

.cmp__part { color: var(--ink-soft); }
.cmp__part::before {
  top: .45rem;
  width: .45rem; height: .45rem;
  border: 1px solid var(--ink-faint);
}

.cmp__no { color: var(--ink-faint); }
.cmp__no::before {
  top: .68rem;
  width: .55rem; height: 1px;
  background: var(--ink-faint);
}

/* The qualifier under "Included" for company email. It is there because the
   one word on its own would imply mail leaves the building today, which it
   does not — see the comment on the section in index.html. */
/* THE OUTSIDE-MAIL CAVEAT, and the one cell in the table nobody may fail to
   read. It sits inside .cmp__ours, whose ground is --paper-deep, where
   --ink-faint measures 4.56:1 on .8rem text — legal and with nothing to spare.
   --ink-soft is 7.38:1 there. */
.cmp__qual {
  display: block;
  margin-top: .3rem;
  padding-left: 1.05rem;
  font-size: .8rem;
  line-height: 1.45;
  color: var(--ink-soft);
}

.cmp__early {
  margin: 1.2rem 0 0;
  font-size: .92rem;
  color: var(--ink-soft);
  max-width: 44rem;
}

/* ── On the way ─────────────────────────────────────────────────────────── */

/* DRAWN IN DASHES, BECAUSE NONE OF IT IS BUILT YET. The roadmap was the same
   filled box as the worked sum above it and the promise in the pricing section,
   which put a list of things that do not exist in the same treatment as a proof
   and a guarantee. A dashed outline on the open paper is the drawing convention
   for a line not yet inked, and it is the one box here that should not look
   settled. See the note above .sums. */
.coming {
  margin-top: 3rem;
  padding: 1.6rem 1.8rem;
  border: 1px dashed var(--ink-faint);
  background: transparent;
}

.coming__tag {
  font-family: var(--mono);
  font-size: .7rem;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--accent);
  margin: 0 0 .4rem;
}

.coming__title { margin: 0 0 1.1rem; font-size: 1.25rem; }

.coming__rows {
  display: grid;
  gap: 1.3rem 2.5rem;
  grid-template-columns: repeat(auto-fit, minmax(min(18rem, 100%), 1fr));
  margin: 0;
}
.coming__rows dt { font-weight: 600; margin-bottom: .25rem; }
.coming__rows dd { margin: 0; color: var(--ink-soft); font-size: .93rem; }

/* ── Narrow screens ─────────────────────────────────────────────────────── */

@media (max-width: 56rem) {
  .cmp__swipe {
    display: block;
    font-family: var(--mono);
    font-size: .72rem;
    letter-spacing: .14em;
    text-transform: uppercase;
    color: var(--ink-faint);
    margin: 0 0 .5rem;
  }
}

@media (max-width: 34rem) {
  .sums { padding: 1.2rem 1.1rem 1rem; }

  /* THE FROZEN COLUMN WAS EATING 55% OF THE SCROLL PORT. At 375px the wrap is
     335px and the row name held 11.5rem — 184px — leaving 151px, barely one
     8.5rem data column. Reading one row across five competitors meant five
     separate swipes with the name column permanently occupying most of the
     screen. 8rem and 7.5rem leave 207px, which is one column whole and most of
     the next, so a swipe now reveals a comparison rather than a cell. */
  .cmp { font-size: .86rem; }
  .cmp th, .cmp td { min-width: 7.5rem; padding: .6rem .7rem; }
  .cmp tbody th[scope="row"] { min-width: 8rem; }

  /* The price line on the object the whole hero is built around, wrapping in
     the middle of itself: 33 characters of .72rem mono tracked at .14em is
     about 280px, plus the tick, two gaps and 27px of padding — ~325px in a
     335px box. Tighter tracking and a slightly smaller face bring it inside,
     and .plate__foot may wrap between its two spans if a longer currency ever
     makes it. */
  .plate__foot { font-size: .68rem; letter-spacing: .08em; }

  /* THE WORKING MOVES UNDER THE NAME instead of being squeezed between it and
     the total. At 375px the three columns left "50 x $14 x 12" about one
     character wide and wrapped the total onto two lines, which is the same
     failure the date column had in the specs list. */
  .sums__row { grid-template-columns: minmax(0, 1fr) auto; }
  .sums__what  { grid-column: 1; grid-row: 1; }
  .sums__total { grid-column: 2; grid-row: 1; }
  .sums__work  { grid-column: 1 / -1; grid-row: 2; }

  .coming { padding: 1.3rem 1.2rem; }
}

/* --- said differently with and without scripts -----------------------------
   The "Ask us" button is removed when ask.js has not run — [data-ask] gains
   .is-live only from the script — and the sentence under it used to open with
   "Or" in both states, offering an alternative to a control that was not
   there. These two spans carry the difference.

   THE DEFAULT IS THE NO-SCRIPT STATE, because that is the state the page
   ships in and the one it must be right in before anything runs.
   -------------------------------------------------------------------------- */
.only-with-js { display: none; }
.only-without-js { display: inline; }
.js .only-with-js { display: inline; }
.js .only-without-js { display: none; }
