﻿/* ============================================================
   FogMonkey — site.css  (SINGLE consolidated stylesheet)
   Merges the former site.css + checkout.css + auth.css.
   Design tokens live in fogmonkey-theme.css (light/dark) — this
   file only *uses* them (aliased --font/--display below).

   Header is GLOBAL: one .nav in _Layout, with an optional centered
   .nav-context slot pages fill via @section NavContext.
   The header shade is GLOBAL too: .fm-main carries one band that is
   identical on every page.

   Sections:
     1. Base / reset            5. Hero + search (landing)
     2. Utilities               6. Results
     3. Components              7. Auth (sign up / log in)
     4. Global nav + context    8. Checkout (contact / pay + rail)
                                9. Processing
                               10. Confirmation
                               11. My Domains
                               12. Mobile (one block)
   ============================================================ */

:root {
  --font: var(--font-ui);
  --display: var(--font-display);
}

/* ---------- 1. base / reset ---------- */
* {
  box-sizing: border-box;
}
body {
  margin: 0;
  background: var(--surface);
  font-family: var(--font);
  color: var(--ink);
  -webkit-font-smoothing: antialiased;
}
a {
  color: inherit;
  text-decoration: none;
}

/* Inline links inside running prose. The reset above deliberately strips link styling so that cards,
   nav items and buttons can be anchors without looking like links - which means every prose context has
   to opt back IN here, or its links render as plain body text and are unfindable. That is not just a
   polish issue: WCAG 2.1 SC 1.4.1 (Use of Color) requires a non-colour cue, and on the checkout
   acceptance line the customer has to be able to reach the documents ToS section 9 says they accept.

   Colour is --brandink, NOT --brand. On --surface, --brand (#ef6a41) measures ~3.0:1, which fails AA for
   normal text (4.5:1). --brandink is ~5.6:1 light and ~9.9:1 dark, and is theme-aware. Do not "brighten"
   this to --brand - the dead .co-agree .txt a rule below makes exactly that mistake.

   The underline is the accessibility cue and carries the requirement on its own; the colour is secondary.
   Keep both.

   .dm-warn-box was missed until 2026-09-02 and is the clearest example of why this list is a trap:
   BOTH domain-status banners route the customer to support through an inline link ("tell us and we
   will look into it", "let us know"), and both rendered as flat body text on the amber panel. The
   suspension banner's link is the only escape hatch offered to someone whose domain has already
   stopped resolving. --brandink measures 5.06:1 on --warnbg light and 8.89:1 dark, so the standard
   treatment applies here unchanged - it just had to be asked for.

   .dm-sub and .au-wrap .sub were added the SAME DAY, after the operator reported the same fault a
   third time. Patching one class per report is what made this recur, so the tree was swept for
   customer-facing prose links instead of fixing only the one reported: .dm-sub carries the privacy
   opt-out route on domain details, and .au-wrap .sub carries all three sign-in recovery links
   ("sign in" and "reset it here" on CantSignIn, "tell us what happened" on ForgotPassword) - the
   routes belonging to someone who is by definition locked out. Everything else already had a rule:
   .dm-mut, .dm-warn-box, .au-alt/.au-forgot, .pr-support, .ab-inner a:not(.btn), .legal a.

   ADDING A NEW PROSE CLASS? Add it here in the same change. Nothing warns you: the global reset
   above makes an unlisted prose link render as flat body text, which looks deliberate. */
.co-check .txt a,   /* checkout: Terms / Privacy / Registration Agreement acceptance */
.au-terms a,        /* account creation: Terms & Privacy */
.dm-mut a,          /* privacy page: delete-account note */
.dm-warn-box a,     /* domain details: suspension + verification banners */
.dm-sub a,          /* domain details: the privacy opt-out route */
.dm-note a,         /* domain details: the same route, inside the privacy block */
.au-wrap .sub a,    /* sign-in recovery: "reset it here", "sign in", "tell us what happened" */
details p a {       /* homepage FAQ answers */
  color: var(--brandink);
  font-weight: 600;
  text-decoration: underline;
  text-underline-offset: 2px;
  text-decoration-thickness: 1px;
}
.co-check .txt a:hover,
.au-terms a:hover,
.dm-mut a:hover,
.dm-warn-box a:hover,
.dm-sub a:hover,
.dm-note a:hover,
.au-wrap .sub a:hover,
details p a:hover {
  text-decoration-thickness: 2px;
}
.co-check .txt a:focus-visible,
.au-terms a:focus-visible,
.dm-mut a:focus-visible,
.dm-warn-box a:focus-visible,
.dm-sub a:focus-visible,
.dm-note a:focus-visible,
.au-wrap .sub a:focus-visible,
details p a:focus-visible {
  outline: 2px solid var(--brandink);
  outline-offset: 2px;
  border-radius: 3px;
}

.page {
  min-height: 100dvh;
  display: flex;
  flex-direction: column; /* full-width frame; content centers at 1180 */
}

/* GLOBAL header shade — one band, same on every page, ~320px fade under the nav */
.fm-main {
  flex: 1;
  background: radial-gradient(
      130% 320px at 50% -36px,
      var(--heroA) 0%,
      var(--heroB) 46%,
      transparent 78%
    )
    no-repeat;
}
.fm-main:has(> .co-body) {
  display: flex;
  flex-direction: column;
} /* checkout only: lets co-body fill height */

@keyframes ck {
  0%,
  49% {
    opacity: 1;
  }
  50%,
  100% {
    opacity: 0;
  }
}
@keyframes spin {
  to {
    transform: rotate(360deg);
  }
}
.ck {
  display: inline-block;
  width: 2px;
  height: 1.05em;
  vertical-align: -0.15em;
  margin-left: 1px;
  background: var(--brand);
  animation: ck 1.05s steps(1) infinite;
}

/* ---------- 2. utilities ---------- */
.grow {
  flex: 1 1 0;
  min-width: 0;
}
.grow2 {
  flex: 2 1 0;
  min-width: 0;
}
.mt-12 {
  margin-top: 12px;
}
.mt-16 {
  margin-top: 16px;
}
.w-100 {
  width: 100%;
}

/* ---------- 3. components ---------- */
.btn {
  border: none;
  border-radius: 14px;
  background: var(--brand);
  color: #fff;
  font: 700 14px var(--font);
  padding: 12px 22px;
  cursor: pointer;
  display: inline-block;
  text-align: center;
}
.btn:hover {
  filter: brightness(0.92);
}
.btn:disabled,
.btn.is-disabled {
  opacity: 0.45;
  cursor: not-allowed;
}
.btn.sec {
  background: var(--soft);
  color: var(--ink);
  border: 1.5px solid var(--line);
}
.btn.sec:hover {
  background: var(--line);
  filter: none;
}
/* Destructive action (e.g. request account deletion) - outlined in the error tone, not loud. */
.btn.danger {
  background: var(--errbg);
  color: var(--err);
  border: 1.5px solid var(--errline);
}
.btn.danger:hover {
  filter: none;
  background: var(--errline);
}
.btn.danger:disabled {
  opacity: 0.6;
  cursor: default;
}
.btn.block {
  width: 100%;
}
.btn.lg {
  font-size: 16px;
  padding: 16px;
}

.tld {
  padding: 6px 15px;
  border-radius: 20px;
  background: var(--brand2);
  color: var(--brand);
  font: 700 12px var(--font);
  display: inline-block;
}

/* form field primitives */
.lbl {
  font: 700 12px var(--font);
  color: var(--ink);
  margin: 0 0 6px;
  display: block;
}
.opt {
  font-weight: 500;
  color: var(--faint);
}
.field {
  margin-bottom: 15px;
}
.inp {
  width: 100%;
  height: 50px;
  border: 1.5px solid var(--line);
  border-radius: 13px;
  background: var(--field);
  padding: 0 16px;
  font: 500 14.5px var(--font);
  color: var(--ink);
  outline: none;
}
.inp:focus {
  border-color: var(--brand);
}
.inp.err {
  border-color: var(--err);
  box-shadow: 0 0 0 3px rgba(217, 105, 78, 0.14);
}
input.inp::placeholder {
  color: var(--faint);
  font-weight: 500;
}
select.inp {
  cursor: pointer;
  -webkit-appearance: none;
  appearance: none;
  background-image:
    linear-gradient(45deg, transparent 50%, var(--faint) 50%),
    linear-gradient(135deg, var(--faint) 50%, transparent 50%);
  background-position:
    calc(100% - 20px) 22px,
    calc(100% - 15px) 22px;
  background-size:
    5px 5px,
    5px 5px;
  background-repeat: no-repeat;
}

/* wordmark */
/* Tracking is -0.045em to match the .wm class in fogmonkey-logo.svg, so the header lockup and the
   brand asset are the same wordmark rather than two near-misses. */
.wm {
  display: flex;
  align-items: center;
  gap: 11px;
  font-family: var(--display);
  font-weight: 800;
  font-size: 24px;   /* nudged up from 21px so the lockup carries the header */
  letter-spacing: -0.045em;
  color: var(--ink);
}
/* The two halves MUST sit inside one flex child. .wm is display:flex with gap:11px, so making
   "Fog" and "Monkey" direct children puts that 11px gap in the middle of the word. */
.wm-txt { white-space: nowrap; }
.wm-a { color: var(--brand); }   /* "Fog"    - coral, softened automatically on dark */
.wm-b { color: var(--ink); }     /* "Monkey" - ink on light, cream on dark */
.wmdot {
  width: 31px;   /* tracks the 24px wordmark so the pair stays balanced */
  height: 31px;
  border-radius: 50%;
  background: radial-gradient(circle at 35% 30%, #ffb59b, var(--brand));
  flex: none;
}

/* Monkey mark - see .hero-mark. It sits in the hero rather than the header: at header size the
   globe wireframe, tail and face are below the size where they read, so it cost band height
   without being legible. */

/* ---------- 4. global nav + context ---------- */
.nav {
  display: flex;
  align-items: center;
  gap: 20px;
  padding: 20px max(40px, calc((100% - 1180px) / 2 + 40px));
  position: sticky;
  top: 0;
  z-index: 50;
  background: var(--surface);
  transition: box-shadow 0.2s ease, border-color 0.2s ease;
}
/* Definition appears only once the page is scrolled, so the top of the page stays clean. */
.nav.scrolled {
  box-shadow: 0 6px 20px -14px rgba(0, 0, 0, 0.4);
  border-bottom: 1px solid var(--line);
}
.nav.has-context {
  border-bottom: 1px solid var(--line);
  padding: 16px max(40px, calc((100% - 1180px) / 2 + 40px));
}
.nav .links {
  display: flex;
  align-items: center;
  gap: 26px;
  font-size: 15px;
  color: var(--muted);
  font-weight: 600;
}
.nav .links .cta {
  padding: 10px 20px;
  border-radius: 22px;
  background: var(--brand);
  color: #fff;
  cursor: pointer;
}
/* A quiet pill for a destination that is neither an action nor an account thing. Same shape and
   metrics as the Account trigger so the right-hand side of the header reads as one set of controls,
   a step lighter so it never competes with Log in or the cart count. margin-left:auto pushes the
   whole group right - it is the first of them, so it carries the push the Account menu used to. */
.nav-pill {
  display: inline-flex; align-items: center;
  margin-left: auto; flex: none;
  padding: 8px 16px;
  border: 1.5px solid var(--line); border-radius: 22px;
  background: transparent;
  font: 600 15px var(--font); color: var(--muted); text-decoration: none;
}
.nav-pill:hover { border-color: var(--brand); color: var(--ink); }

/* ---- The Account menu (#165) -------------------------------------------------------------------
   ONE menu at every width, which is what replaced both a header row of email + Support + Log out
   and the console's own .acct-nav sidebar. The hamburger went with them: this trigger IS the menu
   button, so there is no second control that only exists below 768px, and no set of dropdown rules
   that only the narrow breakpoint ever exercised. */
.acct-menu { position: relative; flex: none; }
.acct-trigger {
  display: inline-flex; align-items: center; gap: 8px;
  max-width: 220px;
  padding: 8px 14px;
  border: 1.5px solid var(--line); border-radius: 22px;
  background: var(--surface);
  font: 600 15px var(--font); color: var(--muted);
  cursor: pointer;
}
.acct-trigger:hover { border-color: var(--brand); color: var(--ink); }
/* The local part still needs capping: it is shorter than the address but not bounded. min-width:0
   is what lets a flex child shrink far enough to actually ellipsis. */
.acct-trigger .who {
  min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.acct-caret {
  width: 16px; height: 16px; flex: none;
  fill: none; stroke: currentColor; stroke-width: 2;
  stroke-linecap: round; stroke-linejoin: round;
  transition: transform .15s ease;
}
.acct-menu.open .acct-caret { transform: rotate(180deg); }

.acct-panel {
  display: none;
  position: absolute; top: calc(100% + 8px); right: 0;
  min-width: 224px;
  padding: 8px;
  background: var(--surface);
  border: 1px solid var(--line); border-radius: 14px;
  box-shadow: 0 18px 40px -20px rgba(0, 0, 0, 0.35);
  z-index: 50;
}
.acct-menu.open .acct-panel { display: block; }
.acct-item {
  display: block; padding: 10px 12px; border-radius: 10px;
  font: 600 15px var(--font); color: var(--ink); text-decoration: none;
}

/* Who you are signed in as, now that the trigger says "Account" instead. A LABEL - no hover, no
   pointer - sitting above Log out, which is the action that most needs it. An address has no natural
   break points, so it is allowed to wrap rather than forced onto one line and clipped: the panel is
   224px and plenty of real addresses are wider than that. */
.acct-who {
  padding: 10px 12px 12px;
  margin-top: 4px;
  border-top: 1px solid var(--line);
}
.acct-who .lbl {
  display: block;
  font: 600 11.5px var(--font);
  color: var(--faint);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  margin-bottom: 3px;
}
.acct-who .addr {
  display: block;
  font: 600 13.5px var(--font);
  color: var(--muted);
  overflow-wrap: anywhere;
}
.acct-item:hover { background: var(--soft); }
/* Same treatment the retired sidebar used for the current section, so the indication a customer
   learned there did not change meaning when it moved into the menu. */
.acct-item.on { background: var(--brand2); color: var(--brandink); }
/* Sign-out is a POST, and it is the one destructive item here - separated rather than sitting in
   the run of navigation links. */
.acct-panel .logout-form {
  display: block;
  margin-top: 6px; padding-top: 8px;
  border-top: 1px solid var(--line);
}
.acct-panel .cta {
  display: block; width: 100%;
  padding: 10px 14px; border-radius: 12px;
  background: var(--brand); color: #fff;
  font: 700 14px var(--font); border: none; cursor: pointer;
}

/* Cart pill. Lives outside .links so the count survives the mobile hamburger; margin-left:auto only
   when there is no .links sibling ahead of it is unnecessary here because .links already carries it,
   so the pill simply sits to the left of the menu. All colours are theme tokens - a literal hex here
   would break dark mode, which is the one rule this project's brand work keeps re-learning. */
.cart-pill {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  flex: none;
  padding: 8px 14px 8px 12px;
  border-radius: 22px;
  border: 1.5px solid var(--line);
  background: var(--field);
  color: var(--ink);
  font: 700 14px var(--font);
  cursor: pointer;
  transition: border-color 0.15s ease, background 0.15s ease;
}
.cart-pill:hover {
  border-color: var(--brand);
  background: var(--brand2);
}
.cart-pill svg {
  width: 18px;
  height: 18px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.9;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.cart-pill .cart-count {
  min-width: 20px;
  height: 20px;
  padding: 0 6px;
  border-radius: 10px;
  background: var(--brand);
  color: #fff;
  font: 700 12px var(--font);
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.cart-pill[hidden] {
  display: none;
}

.nav-context {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  min-width: 0;
}
/* Back control. Was a 34px circle containing a bare `‹`, which read as decoration rather than a
   button and left people unsure it was clickable.
   Three things were wrong and the word fixes all of them:

   1. CLARITY - a lone chevron states nothing. A long arrow plus "Back" does. `←` is also the
      conventional BACK signal; `‹` reads as "previous item" (carousel/pagination).
   2. ACCESSIBILITY - the link's only text was U+2039, so its accessible name came from `title`,
      which assistive tech treats as unreliable. It now has real text, with aria-label adding the
      destination. WCAG 2.5.3 is satisfied because the visible word is contained in that label.
   3. HIT TARGET - 34px was under the 44px the design brief specifies. The pill is far wider and
      36px tall, so it is comfortably clickable even if still short of 44 vertically.

   The border can stay --line here. As a bare ring it needed --faint to be perceivable at all
   (1.23:1 is under WCAG 1.4.11's 3:1), but once a high-contrast text label identifies the control
   the boundary is no longer the only indicator, so the lighter border is fine and less shouty.
   Deliberately no brand tint: this is backwards navigation, not an action, and coral would put it
   in competition with the real CTA on the same screen. */
.nav-back {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  height: 36px;
  padding: 0 15px;
  border-radius: 18px;
  border: 1.5px solid var(--line);
  background: var(--field);
  color: var(--ink);
  font: 700 13px var(--font);
  flex: none;
  white-space: nowrap;
  transition: border-color 0.15s ease, background-color 0.15s ease;
}
/* There was no hover state at all, so the control gave no feedback that it was interactive. */
.nav-back:hover {
  border-color: var(--ink);
  background: var(--soft);
}
/* stroke:currentColor so the arrow tracks the label in both themes and on hover. */
.nav-back svg {
  flex: none;
  stroke: currentColor;
}

.results-search {
  flex: 1;
  max-width: 460px;
  display: flex;
  align-items: center;
  gap: 8px;
  height: 46px;
  background: var(--soft);
  border: 1.5px solid var(--line);
  border-radius: 14px;
  padding: 0 6px 0 16px;
}
.results-search input {
  flex: 1;
  min-width: 0;
  border: none;
  background: transparent;
  outline: none;
  font: 600 15px var(--font);
  color: var(--ink);
}
.results-go {
  flex: none;
  width: 34px;
  height: 34px;
  border: none;
  border-radius: 10px;
  background: var(--brand);
  color: #fff;
  font-size: 16px;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
}
.results-go:hover {
  filter: brightness(0.92);
}

.co-steps {
  display: flex;
  align-items: center;
  gap: 10px;
  font: 700 13px var(--font);
  color: var(--muted);
  white-space: nowrap;
}
.co-steps .on {
  color: var(--ink);
}
.co-steps .done {
  color: var(--ok);
}
.co-steps .sep {
  color: var(--faint);
}

/* footer */
.foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 20px max(40px, calc((100% - 1180px) / 2 + 40px));
  border-top: 1px solid var(--line);
  font-size: 12px;
  color: var(--muted);
}
.foot .links {
  display: flex;
  flex-wrap: wrap;
  gap: 20px;
}
.foot .links a {
  color: var(--muted);
  text-decoration: none;
}
.foot .links a:hover {
  color: var(--ink);
  text-decoration: underline;
}

/* theme toggle (rendered by _Layout) */
.theme-toggle {
  position: fixed;
  right: 20px;
  bottom: 20px;
  z-index: 100;
  width: 42px;
  height: 42px;
  border-radius: 50%;
  border: 1.5px solid var(--line);
  background: var(--surface);
  color: var(--ink);
  font-size: 18px;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 8px 22px -12px rgba(0, 0, 0, 0.3);
}
.theme-toggle:hover {
  border-color: var(--brand);
}

/* ---------- 5. hero + search (landing) ---------- */
.hero {
  padding: 44px 40px 16px;
  text-align: center;
}
.hero .eyebrow {
  font: 700 20px var(--font);
  color: var(--brand);
  margin-bottom: 18px;
}
/* The monkey mark (inline SVG - see Pages/Shared/_MonkeyMark.cshtml).
   Both themes come from ONE vector; there is no light/dark asset pair any more.

   Body colour is var(--brand), so dark gets the softened apricot #e08d5f automatically. The old
   dark art was a PNG with #ef6a41 baked in - the exact colour this project's own dark rule says
   never to use on a dark surface. Recolouring is the whole reason this is inlined.

   The face is negative space on light (it shows the page surface, which is the art's intent) and
   cream on dark, where negative space would go dark-brown. The cream is a literal because it is a
   constant of the artwork rather than a theme value - the same reasoning as --chip staying Visa
   navy in both themes. Eyes, mouth, ear insides and the globe panels need no rules: even-odd
   nesting resolves them correctly in both themes. */
.mk-body { fill: var(--brand); }
.mk-face { fill: none; }
:root[data-theme="dark"] .mk-face { fill: #f4ede2; }

/* Hero lockup: the mark to the LEFT of the headline, sized so the two read as one unit. This is
   the only place it is large enough for its detail (globe wireframe, tail, face) to resolve. */
.hero-lockup {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 28px;
  margin: 0 auto 18px;
}
.hero-lockup .mk {
  width: 136px;   /* 120 x 392/346 - source ratio, never distorted */
  height: 120px;
  flex: none;
}
.hero h1 {
  font-family: var(--display);
  font-size: 60px;
  line-height: 1.04;
  font-weight: 800;
  letter-spacing: -0.03em;
  margin: 0;
  max-width: 920px;
  text-align: left;   /* reads as a lockup beside the mark; re-centred when stacked on mobile */
}
.hero .sub {
  font-size: 18px;
  color: var(--muted);
  max-width: 680px;
  margin: 0 auto 38px;
  line-height: 1.55;
}

.search {
  display: flex;
  gap: 11px;
  max-width: 600px;
  margin: 0 auto 22px;
}
.search input {
  flex: 1;
  height: 66px;
  min-height: 66px;
  padding: 0 24px;
  border: 2px solid var(--brand);
  border-radius: 20px;
  background: var(--field);
  color: var(--ink);
  font: 600 19px var(--font);
  box-shadow: 0 12px 30px -12px rgba(239, 106, 65, 0.45);
  outline: none;
  -webkit-appearance: none;
  appearance: none;
}
.search button {
  height: 66px;
  padding: 0 36px;
  border-radius: 20px;
  font-size: 17px;
}

/* ---------- empty-search hint (both search forms) ----------
   Injected by the guard in _Layout, so it exists in the DOM only after a blank submit.

   The two forms need different placement and that is not cosmetic. The hero form can afford to
   grow, so its hint sits IN FLOW on a wrapped row - honest layout, nothing covered. The header
   search lives inside a fixed-height nav where an in-flow child would stretch the bar, so its hint
   is absolutely positioned as a small callout beneath the box instead. */
.search-hint {
  font: 600 13px var(--font);
  color: var(--brandink);
  line-height: 1.45;
}
.search-hint:empty {
  display: none;
}

.search {
  flex-wrap: wrap;
}
.search .search-hint {
  flex-basis: 100%;
  margin-top: -6px;
  text-align: center;
}

/* The field itself picks up the warning colour so the message and its cause read as one thing.
   Kept to border + ring: recolouring the text would hurt contrast on the dark theme. */
.search.is-blank input,
.results-search.is-blank {
  border-color: var(--warn);
  box-shadow: 0 0 0 3px var(--warnbg);
}

.results-search {
  position: relative;
}
.results-search .search-hint {
  position: absolute;
  top: calc(100% + 8px);
  left: 0;
  z-index: 30;
  max-width: 300px;
  padding: 9px 13px;
  border: 1.5px solid var(--line);
  border-radius: 12px;
  background: var(--surface);
  box-shadow: var(--shadow-card);
}

/* On a phone the header search shrinks to roughly 90px of usable width, and an absolutely
   positioned box takes its shrink-to-fit width from that containing block - the message rendered as
   a one-word-per-line column about nine lines tall. Below this breakpoint the callout detaches from
   the form and spans the viewport instead.

   `top` is set inline by the guard in _Layout, from the form's own bounding rect, because the nav's
   height is not a constant: the maintenance banner adds a row, and the wrapped mobile nav is taller
   than the desktop one. A hardcoded offset here would be wrong in exactly the situations that
   matter most. */
@media (max-width: 700px) {
  .results-search .search-hint {
    position: fixed;
    left: 12px;
    right: 12px;
    max-width: none;
  }
}

/* ---------- home: privacy badge + Privacy by default (#173) ---------------------------------- */

/* The hero's claim, as a pill. Replaces the "Domains, minus the hassle" eyebrow: this page's actual
   differentiator on this chain is that SRSPlus publishes registrant details and our proxy is the only
   thing stopping it, which is worth more than a tagline. */
.hero-badge {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  justify-content: center;
  max-width: 100%;
  padding: 8px 16px;
  margin: 0 auto 6px;
  border: 1.5px solid var(--line);
  border-radius: 24px;
  background: var(--surface);
  font: 600 13.5px var(--font);
  color: var(--ink);
}
.hero-badge .lk {
  font-size: 13px;
  line-height: 1;
}
.hero-badge b {
  font-weight: 800;
}
/* The divider between the two halves. A border rather than a character, so it cannot be read out or
   selected, and it collapses cleanly when the pill wraps on a narrow screen. */
.hero-badge .sep {
  width: 1px;
  align-self: stretch;
  min-height: 14px;
  background: var(--line);
}
/* GREEN, not brand. "$0, on every domain that allows it" states that something is included and
   available, which is what --ok means everywhere else on this site - the availability dot on a search
   card, the "Privacy included" line on the cart rail. In coral it read as a promotional flash. */
.hero-badge .hl {
  color: var(--ok);
  font-weight: 700;
}

/* .eyebrow carries NO styling of its own - the only rules for it are `.hero .eyebrow` and
   `.mkt-head .eyebrow`, so this section's rendered as plain body text and the label was invisible as
   a label. Small, tracked and uppercase here rather than borrowed from .mkt-head, whose 20px
   sentence-case treatment is a section heading in its own right and would compete with the h2. */
.pd .eyebrow {
  font: 800 12px var(--display);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--brand);
  margin-bottom: 10px;
}

.pd {
  display: grid;
  grid-template-columns: 1.05fr 1fr;
  gap: 40px;
  align-items: center;
  max-width: 1080px;
  margin: 0 auto;
  padding: 56px 40px 8px;
}
.pd-copy h2 {
  font-family: var(--display);
  font-size: 34px;
  font-weight: 800;
  letter-spacing: -0.02em;
  line-height: 1.15;
  margin: 8px 0 14px;
}
.pd-copy p {
  font-size: 15.5px;
  line-height: 1.65;
  color: var(--muted);
  margin: 0 0 18px;
}
.pd-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.pd-list li {
  position: relative;
  padding-left: 26px;
  font-size: 14.5px;
  font-weight: 600;
  color: var(--ink);
}
/* The tick is generated rather than typed into the markup: it is decoration for a list that already
   reads as a list, and a literal character would be announced on every item. */
.pd-list li::before {
  content: "✓";
  position: absolute;
  left: 0;
  top: -1px;
  font-weight: 800;
  color: var(--ok);
}

/* THE CARD IS LIGHT IN THE WARM THEME AND DARK IN THE DARK ONE (#202).
   It used to be dark in both - "a picture of a terminal-ish lookup, not a panel of our own UI" -
   and that framing was deliberate. It was overruled on the rendered page: a near-black slab against
   a cream section read as a hole punched in the layout rather than as the record it is quoting.
   The dark theme keeps the original treatment unchanged; see the dark block below, which is what
   that decision costs.

   The GREEN VALUES ARE LOAD-BEARING in both (see .pd-rows dd) and are darkened here rather than
   dropped - #2f7d55 clears 4.7:1 on this background where --ok (#2f9e6f) manages only 3.2:1 and
   would fail AA on 12.5px type. Literal rather than tokens, because these are tuned against each
   other and against the card, not against the page. */
.pd-card {
  border-radius: 18px;
  padding: 24px 26px 20px;
  background: #fdf4ec;
  border: 1px solid #e7d2be;
  box-shadow:
    0 2px 4px -2px rgba(94, 62, 40, 0.1),
    0 16px 36px -20px rgba(94, 62, 40, 0.4);
}
.pd-cardhead {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding-bottom: 12px;
  margin-bottom: 14px;
  border-bottom: 1px solid #eeddcb;
}
.pd-cardhead .ttl {
  font: 800 11px var(--display);
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--faint);
}
.pd-badge {
  font: 700 10.5px var(--font);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: #27684a;
  background: rgba(47, 158, 111, 0.12);
  border: 1px solid rgba(47, 158, 111, 0.3);
  padding: 3px 9px;
  border-radius: 20px;
}
.pd-rows {
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.pd-rows > div {
  display: grid;
  grid-template-columns: 96px 1fr;
  gap: 16px;
  align-items: baseline;
}
.pd-rows dt {
  margin: 0;
  font: 600 12px var(--mono, ui-monospace, SFMono-Regular, Menlo, monospace);
  color: var(--faint);
}
/* Green because these are the values that are NOT yours - the substitution is the product, so the
   eye should land on them. */
.pd-rows dd {
  margin: 0;
  font: 600 12.5px var(--mono, ui-monospace, SFMono-Regular, Menlo, monospace);
  color: #2f7d55;
  overflow-wrap: anywhere;
}
.pd-foot {
  margin: 16px 0 0;
  padding-top: 13px;
  border-top: 1px solid #eeddcb;
  font-size: 12.5px;
  line-height: 1.6;
  color: var(--faint);
}
.pd-foot b {
  color: var(--ink);
}

/* ---- the record card in DARK mode -------------------------------------------------------------
   Unchanged by #202, which only moved the warm theme. Back when the card was dark in both, it was
   #221d1a sitting on --surface #211b16 - a difference of one or two values per channel - so the
   thing the section is built around simply dissolved into the page.

   It cannot solve that by getting LIGHTER, because a light panel here would read as one of our own
   surfaces, and the whole framing is that this is somebody else's system answering a query. So it
   goes the other way: near-black, clearly RECESSED from the page, with the edge doing the work.

   Three things carry it, and all three are needed:
     - a real value gap from --surface (#0e0b09 against #211b16)
     - a lifted border, brighter than --line, so the card has a visible edge at all
     - a green-tinted ring picking up the values inside it, which ties the "PROTECTED" badge and the
       record lines into one object instead of leaving them as text floating on a dark rectangle. */
:root[data-theme="dark"] .pd-card {
  background: #0e0b09;
  border-color: #4d4137;
  box-shadow:
    0 0 0 1px rgba(73, 196, 138, 0.14),
    0 30px 60px -34px rgba(0, 0, 0, 0.9);
}
:root[data-theme="dark"] .pd-cardhead,
:root[data-theme="dark"] .pd-foot {
  border-color: #382f28;
}
/* The badge is the one element allowed to glow - it is the card's verdict. */
:root[data-theme="dark"] .pd-badge {
  background: rgba(73, 196, 138, 0.16);
  border-color: rgba(73, 196, 138, 0.42);
  color: #6fe0a6;
}

/* EVERY TEXT COLOUR ON THE CARD HAS TO BE RESTATED HERE, and that is the real cost of #202.
   Before it, the base rules were dark-on-dark and served BOTH themes, so the dark block only had to
   override the card shell. Now the base rules are the warm theme, and anything not repeated below
   would inherit a colour chosen for cream - muted browns and a darkened green on near-black. None
   of it would fail a build or a test; it would just quietly be wrong for anyone on dark.

   So: if you add or recolour anything inside .pd-card, add its dark counterpart in the same change. */
:root[data-theme="dark"] .pd-cardhead .ttl {
  color: #9d9088;
}
:root[data-theme="dark"] .pd-rows dt {
  color: #8b7f77;
}
:root[data-theme="dark"] .pd-rows dd {
  color: #7ee0a8;
}
:root[data-theme="dark"] .pd-foot {
  color: #9d9088;
}
:root[data-theme="dark"] .pd-foot b {
  color: #d8cec6;
}

.pills {
  display: flex;
  gap: 9px;
  justify-content: center;
}

/* ---------- 5b. marketing / below-fold (landing) ---------- */
.mkt {
  padding: 30px max(40px, calc((100% - 1080px) / 2 + 40px));
}
.mkt.alt {
  background: var(--soft);
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
}
.mkt-head {
  max-width: 640px;
  margin: 0 auto 26px;
  text-align: center;
}
.mkt-head .eyebrow {
  font: 700 20px var(--font);
  color: var(--brand);
  margin-bottom: 14px;
}
.mkt-head h2 {
  font-family: var(--display);
  font-size: 34px;
  line-height: 1.1;
  font-weight: 800;
  letter-spacing: -0.02em;
  margin: 0 0 14px;
}
.mkt-head p {
  font-size: 17px;
  color: var(--muted);
  line-height: 1.55;
  margin: 0;
}
.mkt-grid {
  display: grid;
  /* THREE, not four. The "Private by default" card was removed (#173) because the Privacy by default
     section above now makes that argument in full; a 4-column grid holding 3 cards would leave a
     conspicuous empty quarter beside them. */
  grid-template-columns: repeat(3, 1fr);
  gap: 18px;
  max-width: 1080px;
  margin: 0 auto;
}
.mkt-card {
  background: var(--field);
  border: 1.5px solid var(--line);
  border-radius: 18px;
  padding: 26px 22px;
}
/* Tile header: icon + title on one row (compact, and avoids the icon sitting on an empty row - worse on mobile). */
.mkt-cardhead {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-bottom: 10px;
}
.mkt-ic {
  flex: 0 0 auto;
  width: 38px;
  height: 38px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 11px;
  background: var(--brand2);
  color: var(--brandink);
  font-size: 18px;
  font-weight: 800;
}
.mkt-cardhead h3 {
  font-family: var(--display);
  font-size: 17px;
  font-weight: 700;
  margin: 0;
  line-height: 1.15;
}
.mkt-step h3 {
  font-family: var(--display);
  font-size: 18px;
  font-weight: 700;
  margin: 0 0 8px;
}
.mkt-card p,
.mkt-step p {
  font-size: 14.5px;
  color: var(--muted);
  line-height: 1.5;
  margin: 0;
}
.mkt-incl {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 14px 40px;
  max-width: 820px;
  margin: 0 auto;
}
.mkt-inclrow {
  display: flex;
  align-items: center;
  gap: 12px;
  font-size: 16px;
  font-weight: 600;
}
.mkt-incl .tick {
  flex: 0 0 auto;
  width: 26px;
  height: 26px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: var(--brand);
  color: #fff;
  font-size: 14px;
  font-weight: 800;
}
.mkt-steps {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 22px;
  max-width: 900px;
  margin: 0 auto;
}
.mkt-step {
  text-align: center;
}
.mkt-step .num {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  background: var(--brand);
  color: #fff;
  font-family: var(--display);
  font-size: 20px;
  font-weight: 800;
  margin-bottom: 14px;
}
.mkt-cta {
  text-align: center;
  margin-top: 40px;
}
.mkt-faq {
  max-width: 720px;
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.mkt-faq details {
  background: var(--field);
  border: 1.5px solid var(--line);
  border-radius: 14px;
  padding: 16px 20px;
}
.mkt-faq summary {
  font-family: var(--display);
  font-size: 16px;
  font-weight: 700;
  cursor: pointer;
  list-style: none;
}
.mkt-faq summary::-webkit-details-marker {
  display: none;
}
.mkt-faq summary::after {
  content: "+";
  float: right;
  color: var(--brand);
  font-weight: 800;
}
.mkt-faq details[open] summary::after {
  content: "\2212";
}
.mkt-faq details p {
  margin: 12px 0 0;
  font-size: 14.5px;
  color: var(--muted);
  line-height: 1.55;
}
@media (max-width: 980px) {
  .mkt-grid {
    grid-template-columns: 1fr 1fr;
  }
  /* The copy and the record stack before they get narrow enough to hyphenate an email address. */
  .pd {
    grid-template-columns: 1fr;
    gap: 28px;
    padding: 44px 22px 4px;
  }
}
@media (max-width: 640px) {
  .pd {
    padding: 36px 20px 0;
  }
  .pd-copy h2 {
    font-size: 27px;
  }
  /* The label column becomes a line of its own rather than squeezing the value: at 360px an 88px
     label leaves ~200px for "5335 Gate Parkway, Jacksonville, FL 32256, US", which wraps to four
     ragged lines and stops reading as a record. */
  .pd-rows > div {
    grid-template-columns: 1fr;
    gap: 1px;
  }
  .pd-card {
    padding: 18px 16px 16px;
  }
}
@media (max-width: 640px) {
  .mkt {
    padding: 48px 22px;
  }
  .mkt-head h2 {
    font-size: 28px;
  }
  .mkt-grid,
  .mkt-steps,
  .mkt-incl {
    grid-template-columns: 1fr;
  }
}

/* ---------- 6. results ---------- */
.results {
  max-width: 820px;
  margin: 0 auto;
  padding: 38px 40px 48px;
}
.results .count {
  font-size: 14px;
  color: var(--muted);
  margin: 0 0 20px;
  font-weight: 600;
}
.results .count b {
  color: var(--ink);
  font-weight: 800;
}
.search-error {
  margin: 4px 0;
  padding: 14px 16px;
  border-radius: 12px;
  background: var(--errbg);
  border: 1px solid var(--errline);
  color: var(--err);
  font-size: 14px;
  font-weight: 600;
}

/* Case C (#203): the customer asked for a specific TLD and somebody already has it. Deliberately
   NOT .search-error - nothing failed, and a red box over "that one is taken" reads as a fault on
   our side. The alternates below were checked in the same registrar call, so this costs nothing
   to say. */
.taken-lead {
  margin: 0 0 18px;
  padding: 14px 16px;
  border-radius: 12px;
  background: var(--line2);
  border: 1px solid var(--line);
  font-size: 14px;
  line-height: 1.55;
  color: var(--muted);
}
.taken-lead b {
  color: var(--ink);
  font-weight: 800;
}
.taken-lead .tl-head {
  display: block;
  font-size: 15px;
  color: var(--ink);
  font-weight: 800;
  margin-bottom: 3px;
}

.maintenance-banner {
  padding: 10px 20px;
  text-align: center;
  font-size: 13px;
  font-weight: 700;
  background: #fbbf24;
  color: #1a2230;
}

/* Registrations paused. Same shape as .maintenance-banner - it sits in the same slot and the two can
   stack - but a distinct, cooler colour on purpose: amber is this site's "something is wrong" and a
   deliberate operator pause is not that. Stacked, the difference is what tells them apart. */
.pause-banner {
  padding: 10px 20px;
  text-align: center;
  font-size: 13px;
  font-weight: 700;
  background: #dbeafe;
  color: #1e3a5f;
  border-bottom: 1px solid #93c5fd;
}

.row {
  display: flex;
  flex-wrap: wrap;
  /* stretch, not center: .result-list is a grid, so cards in the same row are already equal HEIGHT.
     Centring floated each card's content in the middle of its own box, so a short card's name and
     price sat at a different y than a tall one's - the "uneven" symptom. Stretching lets the two
     columns anchor their content to the same top and bottom edges. */
  align-items: stretch;
  gap: 22px;
  padding: 22px 26px;
  border-radius: 18px;
  margin-bottom: 13px;
  background: var(--field);
  border: 1.5px solid var(--okline);
}
.row.taken {
  background: var(--soft);
  border: 1.5px solid var(--line);
}
.row.taken .name,
.row.taken .takenlbl {
  opacity: 0.72;
} /* dim the text, not the whole card */
.row.unpriced {
  border: 1.5px solid var(--line);
}
/* min-width:0 is load-bearing (the `.grow` idiom). Flex items default to min-width:auto, and a
   domain name is ONE unbreakable token, so without this .id refuses to shrink below the full width
   of the name at 22px. In the 2-column grid that leaves ~279px, so a name past ~23 characters made
   .row wrap and dropped the whole buybox onto a second line, doubling that card's height - with or
   without a promo badge. */
.row .id {
  flex: 1 1 0;
  min-width: 0;
}
.row .name {
  font-family: var(--display);
  font-size: 22px;
  font-weight: 700;
  /* Let a long name wrap inside the card rather than overflowing the rounded border. `anywhere`
     (not `break-word`) also shrinks min-content, so the name can never force the layout again. */
  overflow-wrap: anywhere;
}
.row .name .tldname {
  color: var(--brand);
  white-space: nowrap; /* never split ".com" across two lines */
}
.row.taken .name .tldname {
  color: var(--muted);
}
.avail {
  display: flex;
  align-items: center;
  gap: 7px;
  margin-top: 5px;
}
.avail .dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--ok);
}
.avail .lbl {
  font: 700 13px var(--font);
  color: var(--ok);
}
/* "Privacy included" - the same bullet as .avail, deliberately NOT the same weight. Availability is
   the answer the customer came for and has to stay the loudest thing on the card; privacy is a
   supporting fact. Identical green-on-green lines compete for the same attention and make the card
   read as two verdicts instead of one. */
.privacy-incl {
  margin-top: 3px;
}
.privacy-incl .lbl {
  font-weight: 600;
  color: var(--muted);
}
.takenlbl,
.unknownlbl {
  font-size: 13px;
  color: var(--muted);
  margin-top: 4px;
}
.price {
  flex: 0 0 auto;
  font-family: var(--display);
  font-size: 20px;
  font-weight: 800;
}
.price .per {
  font-size: 13px;
  color: var(--muted);
  font-weight: 600;
}
.note {
  flex: 0 0 auto;
  align-self: center; /* .row stretches now; a one-line note should still read as centred */
  font-size: 14px;
  color: var(--muted);
  font-weight: 600;
}
/* Badges live inside .id, under the name - NOT in the buybox, where their conditional presence and
   long text used to add height to only some cards. They are block-level children of .id, so they no
   longer need the flex sizing they carried when they were direct children of .row. Full card width
   to wrap into; the radius relaxes from a pill so a wrapped two-line badge still looks deliberate. */
.promo-badge,
.premium-badge,
.noprivacy-badge {
  margin-top: 8px;
  max-width: 100%;
  width: fit-content;
  font-size: 12.5px;
  font-weight: 700;
  line-height: 1.45;
  border-radius: var(--r-pill);
  padding: 5px 12px;
}
.promo-badge {
  color: var(--brandink);
  background: var(--brand2);
}
/* Premium (registry-priced) name badge - same pill as .promo-badge, distinct amber treatment. */
.premium-badge {
  color: #7a4b00;
  background: #ffd97a;
}
/* "No WHOIS privacy on this TLD" - a correction to a promise the rest of the site makes, so it is
   deliberately NOT styled as an alarm. It is neutral-grey rather than the error red used for a
   failure: nothing has gone wrong, one advertised extra simply does not exist here, and dressing
   that as a warning would push customers off a name that is otherwise perfectly fine. The sentence
   is long by design, so this one wraps to full width instead of sizing to fit. */
.noprivacy-badge {
  width: auto;
  color: var(--muted);
  background: var(--line2);
  border-radius: 12px;
  font-weight: 600;
}
.row .buy {
  flex: 0 0 auto;
  padding: 13px 28px;
  border-radius: 16px;
}

/* Multi-year: the right-hand purchase block (term selector + total + breakdown + Buy). Stacks so a
   long breakdown line ("$8.99 first year, then $14.99/yr") never crowds the Buy button.
   justify-content: flex-end pins Buy to the bottom of the stretched card, so Buy buttons align
   across a grid row even when one card's name wrapped to two lines and its neighbour's didn't. */
.buybox {
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  align-items: flex-end;
  gap: 8px;
  text-align: right;
}
.buybox .term {
  display: flex;
  align-items: center;
  gap: 8px;
}
/* Term label/select are NOT scoped to .buybox: the cart page reuses them, and a select left to the
   native styling renders a white box with dark text on the dark theme - the same unreadable field the
   dark-contrast pass fixed elsewhere. Keeping the rule on the class means any future reuse inherits
   the themed treatment instead of silently falling back to the UA default. */
.term-lbl {
  font: 600 12.5px var(--font);
  color: var(--muted);
}
.term-select {
  font: 600 14px var(--font);
  padding: 7px 10px;
  border-radius: 12px;
  border: 1.5px solid var(--line);
  background: var(--field);
  color: inherit;
  cursor: pointer;
}
.buybox .price {
  margin-top: 2px;
}
.price-breakdown {
  font-size: 12.5px;
  color: var(--muted);
  font-weight: 600;
}
/* Premium renewal disclosure: the per-year renewal line under the buy price ("Same price next year"
   / "Renews at $X/yr"). Muted like .price-breakdown - it is a fact, not an alarm - and right-aligned
   with the rest of the buybox stack. The parallel line on the Pay rail reuses .term. */
.renews {
  font-size: 12.5px;
  color: var(--muted);
  font-weight: 600;
}
/* The premium badge doubles as the "what is this?" explainer trigger, so in search it is a <button>.
   Strip the UA button chrome back to the pill the .premium-badge fill already draws; the cart keeps a
   plain <div> and is unaffected. The trailing "?" is a quiet affordance, not a second colour. */
button.premium-badge {
  border: 0;
  font-family: inherit;
  text-align: left;
  cursor: pointer;
}
.premium-badge .pi-q {
  margin-left: 6px;
  opacity: 0.7;
  font-weight: 700;
}
/* Compact premium pill for the dense checkout rails (contact, pay): the same amber pill, smaller, so
   it sits inside an order-summary row without dominating it. The cart's renewal sub-line is muted
   like the search card's .renews. */
.premium-badge.sm {
  margin-top: 4px;
  padding: 3px 9px;
  font-size: 11.5px;
}
.cl-renews {
  margin-top: 6px;
  font-size: 12.5px;
  font-weight: 600;
  color: var(--muted);
}

/* H7: results as a responsive card grid - one column on mobile (as before), a denser
   multi-column grid on desktop so many active TLDs don't waste the horizontal space. */
.result-list {
  display: grid;
  grid-template-columns: 1fr;
  gap: 13px;
}
.result-list .row {
  margin-bottom: 0; /* the grid gap owns vertical spacing now */
}
@media (min-width: 769px) {
  .results {
    max-width: 1080px;
  }
  .result-list {
    grid-template-columns: 1fr 1fr;
    gap: 16px;
  }
}

/* Search empty-state value strip - fills the space before a query is typed. */
.search-empty {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 16px;
  margin-top: 28px;
}
.se-item {
  display: flex;
  gap: 12px;
  align-items: flex-start;
  padding: 18px;
  border-radius: 14px;
  background: var(--field);
  border: 1.5px solid var(--line);
}
.se-item .se-ic {
  flex: 0 0 auto;
  width: 34px;
  height: 34px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 10px;
  background: var(--brand2);
  color: var(--brandink);
  font-weight: 800;
}
.se-item b {
  display: block;
  font-size: 14.5px;
}
.se-item span {
  font-size: 13px;
  color: var(--muted);
  line-height: 1.45;
}
@media (max-width: 700px) {
  .search-empty {
    grid-template-columns: 1fr;
  }
}

/* Turnstile search interstitial (bot gate). Centred, calm, matches the auth pages' width. */
.verify-wrap {
  max-width: 460px;
  margin: 8vh auto 0;
  text-align: center;
}
.verify-wrap h1 {
  font-family: var(--display);
  font-size: 28px;
  font-weight: 800;
}
.verify-wrap .sub {
  color: var(--muted);
  margin: 8px 0 24px;
}
.verify-wrap .cf-turnstile {
  display: flex;
  justify-content: center;
  margin: 18px 0;
}

/* ---------- 6b. legal / policy pages (H4 - draft, reachable by URL, not yet linked) ---------- */
.legal {
  max-width: 800px;
  margin: 0 auto;
  padding: 30px 40px 90px;
  color: var(--ink);
  line-height: 1.65;
}
.legal-back {
  display: inline-block;
  margin: 6px 0 18px;
  color: var(--muted);
  font-weight: 600;
  text-decoration: none;
}
.legal-back:hover {
  color: var(--ink);
}
.legal h1 {
  font: 800 30px var(--display);
  letter-spacing: -0.02em;
  margin: 0 0 18px;
}
.legal h2 {
  font: 800 18px var(--display);
  margin: 34px 0 10px;
}
.legal h3 {
  font: 700 15px var(--display);
  margin: 22px 0 8px;
}
.legal p,
.legal li {
  font-size: 15px;
}
.legal ul {
  padding-left: 22px;
  margin: 10px 0;
}
.legal li {
  margin: 6px 0;
}
.legal a {
  color: var(--brand);
}
.legal strong {
  font-weight: 700;
}
.legal em {
  color: var(--muted);
}
.legal hr {
  border: none;
  border-top: 1px solid var(--line);
  margin: 30px 0;
}
/* [BRACKETED] placeholders are backtick code spans in the drafts - tint them so unfilled items stand out. */
.legal code {
  font-size: 13px;
  padding: 1px 6px;
  border-radius: 5px;
  background: var(--warnbg);
  color: var(--warn);
  font-weight: 600;
}

/* ---------- 6c. cookie notice (H9 - informational, essential-only) ---------- */
.cookie-bar {
  position: fixed;
  left: 16px;
  right: 16px;
  bottom: 16px;
  z-index: 60;
  max-width: 720px;
  margin: 0 auto;
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 12px 16px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 14px;
  box-shadow: 0 18px 40px -20px rgba(0, 0, 0, 0.35);
  font-size: 13px;
  color: var(--muted);
}
.cookie-bar .cb-txt {
  flex: 1 1 auto;
}
.cookie-bar b {
  color: var(--ink);
}
.cookie-bar a {
  color: var(--brand);
}
.cookie-bar .cb-ok {
  flex: 0 0 auto;
  padding: 8px 16px;
  border-radius: 10px;
  border: none;
  background: var(--brand);
  color: #fff;
  font: 700 13px var(--font);
  cursor: pointer;
}

/* ---------- 7. auth (sign up / log in) ---------- */
.au-wrap {
  max-width: 440px;
  margin: 0 auto;
  padding: 8px 22px 44px;
}
.au-top {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-bottom: 22px;
}
.au-top .au-held {
  flex: 1;
  margin-bottom: 0;
}
.au-held {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 12px 14px;
  background: var(--field);
  border: 1.5px solid var(--line);
  border-radius: 14px;
  margin-bottom: 22px;
  box-shadow: 0 6px 18px -12px rgba(0, 0, 0, 0.25);
}
.au-held .badge {
  width: 34px;
  height: 34px;
  border-radius: 10px;
  background: var(--field);
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--display);
  font-weight: 800;
  font-size: 13px;
  color: var(--brand);
}
.au-held .nm {
  font: 700 13px var(--font);
  color: var(--ink);
}
.au-held .meta {
  font-size: 11.5px;
  color: var(--brand);
  font-weight: 600;
}
.au-wrap h1 {
  font-family: var(--display);
  font-size: 25px;
  font-weight: 800;
  letter-spacing: -0.02em;
  margin: 0 0 6px;
}
.au-wrap .sub {
  font-size: 13.5px;
  color: var(--muted);
  margin: 0 0 18px;
  line-height: 1.5;
}
.au-social {
  display: flex;
  flex-direction: column;
  gap: 9px;
  margin-bottom: 16px;
}
.au-sbtn {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  height: 47px;
  border: 1.5px solid var(--line);
  border-radius: 14px;
  background: var(--field);
  font: 700 13.5px var(--font);
  color: var(--ink);
  cursor: pointer;
}
/* Provider marks are inline SVG carrying their own brand colours, so this rule only sizes them.
   Deliberately no background, no border-radius and no color/fill: Google's and Microsoft's sign-in
   branding both require the mark unmodified, which makes these the one exception to the "everything
   reads a theme token" rule. Do not add fill:currentColor or a dark-mode override here.

   The old .ic.apple / .ic.google / .ic.fb rules are gone: they styled a typed letter or glyph as a
   pseudo-logo, and Apple/Facebook were never configured providers - leftovers from the design comps. */
.au-sbtn .ic {
  width: 18px;
  height: 18px;
  flex: none;
  display: block;
}
.au-divider {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-bottom: 18px;
}
.au-divider .line {
  flex: 1;
  height: 1px;
  background: var(--line);
}
.au-divider span {
  font-size: 11.5px;
  color: var(--faint);
  font-weight: 600;
}
.au-pw {
  display: flex;
  align-items: center;
  justify-content: space-between;
}
.au-pw input {
  flex: 1;
  border: none;
  background: transparent;
  outline: none;
  font: 500 14.5px var(--font);
  color: var(--ink);
}
.au-show {
  font-size: 12px;
  font-weight: 700;
  color: var(--brand);
  cursor: pointer;
  margin-left: 10px;
}
.au-hint {
  font-size: 11px;
  color: var(--faint);
  margin-top: 6px;
}
.au-alt {
  text-align: center;
  margin-top: 16px;
  font-size: 13px;
  color: var(--muted);
}
.au-alt a {
  color: var(--brand);
  font-weight: 700;
}
.au-forgot {
  text-align: center;
  margin-top: 16px;
  font-size: 13px;
  color: var(--brand);
  font-weight: 700;
}
.au-terms {
  font-size: 11px;
  color: var(--faint);
  text-align: center;
  margin: 18px 0 0;
  line-height: 1.5;
}

/* ---------- 8. checkout (contact / pay + order rail) ---------- */
/* Checkout gate panel (issue #121). Its own container rather than .co-body/.co-form: those are
   halves of a two-column checkout grid, and with no order summary beside it the form half stretched
   to 1180px, leaving 14px text marooned across a very wide, very empty page. This is a single
   centred column sized for reading. */
.gate {
  max-width: 560px;
  margin: 0 auto;
  padding: 56px 22px 72px;
  text-align: center;
}
.gate .gate-icon {
  width: 56px;
  height: 56px;
  margin: 0 auto 20px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  background: var(--soft);
  border: 1.5px solid var(--line);
  font-size: 26px;
  line-height: 1;
}
.gate h1 {
  font-family: var(--display);
  font-size: 27px;
  font-weight: 800;
  letter-spacing: -0.02em;
  margin: 0 0 12px;
  text-wrap: balance;
}
.gate .gate-lede {
  font-size: 16px;
  line-height: 1.6;
  color: var(--ink);
  margin: 0 0 10px;
}
.gate .gate-addr {
  font-weight: 700;
  word-break: break-all;
}
.gate .gate-sub {
  font-size: 14.5px;
  line-height: 1.6;
  color: var(--muted);
  margin: 0 0 26px;
}
.gate .gate-actions {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
}
.gate .gate-actions .btn { min-width: 220px; }
.gate .gate-hint {
  font-size: 13.5px;
  color: var(--muted);
  margin: 0;
}
@media (max-width: 620px) {
  .gate { padding: 36px 20px 56px; }
  .gate h1 { font-size: 23px; }
  .gate .gate-actions .btn { width: 100%; min-width: 0; }
}

.co-body {
  display: flex;
  align-items: stretch;
  max-width: 1180px;
  margin: 0 auto;
  flex: 1;
  width: 100%;
}
.co-form {
  flex: 1;
  padding: 40px 44px 48px;
}
.co-form h1 {
  font-family: var(--display);
  font-size: 30px;
  font-weight: 800;
  letter-spacing: -0.02em;
  margin: 0 0 8px;
}
.co-form h1.mb {
  margin-bottom: 24px;
}
.co-form .intro {
  font-size: 14px;
  color: var(--muted);
  margin: 0 0 8px;
  line-height: 1.55;
  max-width: 560px;
}
/* INFORMATIONAL, not an alert. This was a filled brand-tint pill with --brandink text - the same
   warm coral family the checkout failure box is drawn in - which read as "something is wrong with
   these details" on the one screen where a customer is scanning their own details for mistakes.
   Nothing has gone wrong here; we are telling them where the values came from.

   Deliberately the same treatment as .co-stripe-note, the neutral note idiom already used further
   down this same form, rather than a new one: two quiet notes on one page should not be two
   different shapes. */
.co-autofill {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 9px 14px;
  background: var(--soft);
  border: 1px solid var(--line);
  border-radius: 11px;
  margin-bottom: 26px;
  font-size: 12.5px;
  color: var(--muted);
  font-weight: 500;
}
/* The refresh glyph carries the meaning on its own; at 600 weight in brand ink it was the loudest
   thing on the form. */
.co-autofill span {
  color: var(--faint);
  font-size: 14px;
  line-height: 1;
}
.co-section {
  font: 800 11.5px var(--display);
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--muted); /* secondary text, not the near-invisible --faint - readable in both themes */
  margin: 0 0 14px;
}
.co-section.gap {
  margin-top: 24px;
}
.co-fieldrow {
  display: flex;
  gap: 14px;
}
.co-fieldrow > .field {
  flex: 1 1 0;
  min-width: 0;
} /* fields auto-share the row */
.co-fieldrow > .field.wide {
  flex: 2 1 0;
} /* e.g. City */

.inp-static {
  display: flex;
  align-items: center;
  justify-content: space-between;
  color: var(--faint);
  font-weight: 500;
}
.card-brand {
  width: 26px;
  height: 16px;
  border-radius: 3px;
  background: var(--chip);
  flex: none;
}
.stripe-hint {
  font-size: 11.5px;
  color: var(--faint);
  margin-top: 4px;
}

.co-save {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 15px 16px;
  background: var(--soft);
  border: 1px solid var(--line);
  border-radius: 13px;
  margin-top: 8px;
  cursor: pointer;
}
.co-agree {
  display: flex;
  align-items: center;
  gap: 12px;
  margin: 14px 0 6px;
  cursor: pointer;
}
.co-save .box,
.co-agree .box {
  width: 22px;
  height: 22px;
  border-radius: 7px;
  background: var(--brand);
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 13px;
  flex: none;
}
.co-save .txt {
  font-size: 13px;
  color: var(--ink);
}
.co-save .txt span {
  color: var(--muted);
}
.co-agree .txt {
  font-size: 13px;
  color: var(--muted);
}
.co-agree .txt a {
  color: var(--brand);
  font-weight: 700;
}

.co-rail {
  width: 380px;
  flex: none;
  background: var(--soft);
  border-left: 1px solid var(--line);
  padding: 40px 32px;
  display: flex;
  flex-direction: column;
}
.co-rail .badge {
  width: 44px;
  height: 44px;
  border-radius: 11px;
  background: var(--field);
  border: 1px solid var(--line);
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--display);
  font-weight: 800;
  font-size: 13px;
  color: var(--brand);
}
.co-item {
  display: flex;
  align-items: center;
  gap: 12px;
  padding-bottom: 18px;
  border-bottom: 1px solid var(--line);
  margin-bottom: 16px;
}
.co-item .nm {
  font: 700 15px var(--font);
}
.co-item .term {
  font-size: 12.5px;
  color: var(--muted);
}
/* Privacy on the order rail is a REASSURANCE LINE, not a priced row - it never gets an amount
   column, because privacy is inside the domain fee. Sized below the term line so the rail still
   reads name > term > price; the included case is deliberately quieter than the warning. */
.co-item .privacy-incl-line {
  margin-top: 3px;
  font-size: 12px;
  color: var(--ok);
  font-weight: 600;
}
.co-item .privacy-none-line {
  margin-top: 3px;
  font-size: 12px;
  color: var(--warn);
  font-weight: 600;
}
.co-term {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 6px;
}
.co-term-lbl {
  font-size: 12.5px;
  color: var(--muted);
}
.co-term select {
  font: 600 13px var(--font);
  padding: 5px 8px;
  border-radius: 10px;
  border: 1.5px solid var(--line);
  background: var(--field);
  color: inherit;
  cursor: pointer;
}
.co-termnote {
  font-size: 12px;
  color: var(--muted);
  margin: -12px 0 18px;
  min-height: 14px;
}
.co-lines {
  display: flex;
  flex-direction: column;
  gap: 10px;
  font-size: 14px;
  margin-bottom: 16px;
}
.co-lines .ln {
  display: flex;
  justify-content: space-between;
  color: var(--muted);
}
.co-lines .ln b {
  color: var(--ink);
  font-weight: 600;
}
/* Stripe elements loading state - a spinner over the fields until the Payment Element is interactive. */
.co-stripe-fields {
  position: relative;
  min-height: 130px;
}
.stripe-loading {
  position: absolute;
  inset: 0;
  z-index: 2;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 12px;
  background: var(--field);
  border-radius: 13px;
  color: var(--muted);
  font-size: 13px;
  font-weight: 600;
}

.co-total {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  padding-top: 16px;
  border-top: 1px solid var(--line);
  margin-bottom: 22px;
}
.co-total .lbltot {
  font-weight: 700;
  font-size: 15px;
}
.co-total .amt {
  font-family: var(--display);
  font-weight: 800;
  font-size: 22px;
}
.co-trust {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  margin-top: 16px;
  font-size: 11.5px;
  color: var(--faint);
  font-weight: 600;
}
.co-refund {
  font-size: 11.5px;
  color: var(--faint);
  text-align: center;
  line-height: 1.5;
  margin: 14px 0 0;
}

/* ---------- 9. processing (3 outcomes) ---------- */
.pr-wrap {
  max-width: 460px;
  margin: 0 auto;
  min-height: 55vh;
  padding: 40px 30px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
}
.pr-wrap h1 {
  font-family: var(--display);
  font-size: 23px;
  font-weight: 800;
  letter-spacing: -0.02em;
  margin: 0 0 10px;
  line-height: 1.15;
}
.pr-wrap p {
  font-size: 13.5px;
  color: var(--muted);
  line-height: 1.55;
  margin: 0 0 4px;
}
/* .pr-spinner and .busy-overlay* now live in busy-overlay.css - the ops console loads admin.css,
   not this file, and needs the same overlay. */
.pr-icon {
  width: 70px;
  height: 70px;
  border-radius: 22px;
  background: var(--brand2);
  color: var(--brand);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 30px;
  margin-bottom: 26px;
}
.pr-icon.warn {
  border-radius: 50%;
  background: var(--warnbg);
  border: 1.5px solid #eacd97;
  color: var(--warn);
}
.pr-donote {
  margin-top: 28px;
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 11.5px;
  color: var(--faint);
  font-weight: 600;
}
.pr-donote .dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--ok);
}
.pr-emailbox {
  width: 100%;
  padding: 12px 14px;
  background: var(--soft);
  border: 1px solid var(--line);
  border-radius: 13px;
  font-size: 12px;
  color: var(--muted);
  text-align: left;
  margin-top: 6px;
}
.pr-emailbox b {
  color: var(--ink);
}
.pr-refund {
  width: 100%;
  padding: 13px 15px;
  background: var(--okbg);
  border: 1px solid var(--okline);
  border-radius: 13px;
  display: flex;
  align-items: center;
  gap: 10px;
  text-align: left;
  margin: 8px 0;
}
.pr-refund .ck {
  width: 24px;
  height: 24px;
  border-radius: 50%;
  background: var(--ok);
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 13px;
  flex: none;
  animation: none;
}
.pr-refund span:last-child {
  font-size: 12px;
  color: var(--ok);
  line-height: 1.4;
}
.pr-support {
  margin-top: 14px;
  font-size: 12.5px;
  color: var(--brand);
  font-weight: 700;
}

/* ---------- 10. confirmation ---------- */
.cf-wrap {
  max-width: 460px;
  margin: 0 auto;
}
.cf-hero {
  padding: 34px 22px 28px;
  text-align: center;
}
.cf-check {
  width: 74px;
  height: 74px;
  border-radius: 50%;
  background: var(--ok);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 36px;
  color: #fff;
  margin: 6px auto 20px;
  box-shadow: 0 14px 30px -10px rgba(47, 158, 111, 0.6);
}
/* The renewal result page reuses this hero for outcomes that are NOT good news - paused, not paid,
   refunded, and the one that needs a human. A green tick over "we could not renew" would be worse
   than no mark at all, so the mark changes colour with the outcome while the layout does not. */
.cf-check.warn {
  background: var(--warn);
  box-shadow: 0 14px 30px -10px rgba(201, 138, 46, 0.55);
}
.cf-check.err {
  background: var(--err);
  box-shadow: 0 14px 30px -10px rgba(196, 71, 44, 0.55);
}
.cf-eyebrow {
  font: 700 12px var(--font);
  color: var(--brand);
  margin-bottom: 8px;
}
.cf-hero h1 {
  font-family: var(--display);
  font-size: 30px;
  font-weight: 800;
  letter-spacing: -0.025em;
  margin: 0 0 8px;
  line-height: 1.05;
}
.cf-hero p {
  font-size: 13.5px;
  color: var(--muted);
  line-height: 1.5;
  margin: 0 26px;
}
.cf-body {
  padding: 6px 22px 28px;
}
.cf-card {
  border: 1px solid var(--line);
  border-radius: 16px;
  overflow: hidden;
  margin-bottom: 16px;
}
.cf-card .hd {
  padding: 11px 15px;
  background: var(--soft);
  font: 800 12px var(--display);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--faint);
}
.cf-steps {
  padding: 15px 15px;
  display: flex;
  flex-direction: column;
  gap: 14px;
}
.cf-step {
  display: flex;
  gap: 11px;
  align-items: flex-start;
}
.cf-step .mk {
  width: 24px;
  height: 24px;
  border-radius: 50%;
  font-size: 12px;
  display: flex;
  align-items: center;
  justify-content: center;
  flex: none;
}
.cf-step .mk.ok {
  background: var(--ok);
  color: #fff;
}
.cf-step .mk.next {
  background: var(--brand2);
  color: var(--brand);
}
.cf-step .tx {
  font-size: 14.5px;
}
.cf-step .tx .mut {
  color: var(--muted);
  font-size: 13.5px;
}
.cf-order {
  display: flex;
  justify-content: space-between;
  align-items: center;
  /* 26px = .cf-body's old 22px gutter plus the 4px this had inside it. Same optical position as
     when it was a child of .cf-body. */
  padding: 0 26px 16px;
  font-size: 14.5px;
}
.cf-order .mut {
  color: var(--muted);
}
.cf-order .amt {
  font-family: var(--display);
  font-weight: 800;
}
.cf-actions {
  padding: 0 22px 28px;
}
.cf-actions .btn {
  width: 100%;
}
.cf-actions .btn + .btn {
  margin-top: 10px;
}

/* ---- Confirmation on a wide screen ----------------------------------------
   The page is a 460px column, which is right on a phone and leaves a desktop
   showing a tall ribbon of content between two empty margins - a single
   registered name is barely a third of the fold. Above 900px the celebration and
   the receipt sit side by side: the hero holds the left column (and stays put
   while a long list of names scrolls past it), the cards take the right.
   Everything below 900px is untouched. */
@media (min-width: 900px) {
  .cf-wrap.split {
    max-width: 920px;
    display: grid;
    grid-template-columns: minmax(0, 4fr) minmax(0, 5fr);
    /* Three content rows and a spring. Without the 1fr the grid would stretch the hero/receipt/actions
       rows to match the card column, and the left side would drift apart down the page. */
    grid-template-rows: auto auto auto 1fr;
    column-gap: 40px;
    padding: 12px 22px 0;
  }
  .split > .cf-hero { grid-column: 1; grid-row: 1; }
  .split > .cf-body { grid-column: 2; grid-row: 1 / -1; }
  .split > .cf-order { grid-column: 1; grid-row: 2; }
  .split > .cf-actions { grid-column: 1; grid-row: 3; }
  .split .cf-hero {
    text-align: left;
    padding: 26px 0 22px;
  }
  .split .cf-order {
    padding: 0 0 14px;
    border-top: 1px solid var(--line);
    padding-top: 14px;
  }
  .split .cf-actions {
    padding: 0;
  }
  .split .cf-check {
    margin: 0 0 22px;
  }
  .split .cf-hero h1 {
    font-size: 34px;
  }
  .split .cf-hero p {
    margin: 0;
    max-width: 34ch;
  }
  .split .cf-body {
    padding: 26px 0 40px;
  }
  /* Two short buttons read as a pair here; stacked full-width they looked like
     two competing primary actions. */
  .split .cf-actions {
    display: flex;
    gap: 10px;
  }
  .split .cf-actions .btn {
    width: auto;
    flex: 1;
  }
  .split .cf-actions .btn + .btn {
    margin-top: 0;
  }
}

/* ---------- 11. my domains ---------- */
.md-wrap {
  max-width: 920px;
  margin: 0 auto;
  padding: 20px 20px 40px;
}
/* Orders / My Domains card list: one column on mobile, a denser 2-up grid on desktop so the account
   pages use the horizontal space (mirrors the H7 .result-list pattern). */
.md-list {
  display: grid;
  grid-template-columns: 1fr;
  gap: 11px;
}
.md-list .md-card {
  margin-bottom: 0; /* the grid gap owns vertical spacing now */
}
@media (min-width: 769px) {
  .md-list {
    grid-template-columns: 1fr 1fr;
    gap: 14px;
  }
}
.md-wrap h1 {
  font-family: var(--display);
  font-size: 26px;
  font-weight: 800;
  letter-spacing: -0.02em;
  margin: 6px 0 4px;
}
.md-count {
  font-size: 12.5px;
  color: var(--muted);
  margin: 0 0 18px;
}
.md-card {
  border: 1px solid var(--okline);
  border-radius: 15px;
  padding: 15px 16px;
  margin-bottom: 11px;
}
.md-card .row1 {
  display: flex;
  align-items: center;
  justify-content: space-between;
}
.md-card .nm {
  font-family: var(--display);
  font-size: 16px;
  font-weight: 700;
}
.md-badge {
  font: 700 10.5px var(--font);
  color: var(--ok);
  background: var(--okbg);
  padding: 4px 9px;
  border-radius: 20px;
}
.md-dates {
  font-size: 12px;
  color: var(--muted);
  margin-top: 6px;
}
.md-add {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  margin-top: 9px;
}
.md-add .plus {
  color: var(--brand);
  font-weight: 800;
}
.md-empty {
  text-align: center;
  padding: 50px 30px;
}
.md-empty .icon {
  width: 70px;
  height: 70px;
  border-radius: 22px;
  background: var(--brand2);
  color: var(--brand);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 30px;
  margin: 0 auto 22px;
}
.md-empty h2 {
  font-family: var(--display);
  font-size: 22px;
  font-weight: 800;
  margin: 0 0 10px;
}
.md-empty p {
  font-size: 13.5px;
  color: var(--muted);
  line-height: 1.55;
  margin: 0 0 22px;
}

/* ============================================================
   12. MOBILE — single block (<= 768px)
   ============================================================ */
@media (max-width: 768px) {
  .nav {
    /* Deliberately NOT `position: relative` here - that used to override the sticky from the base
       rule, so the header scrolled away on mobile only. Sticky still establishes a containing block
       for the absolutely-positioned .nav .links dropdown below, so relative bought nothing. */

    /* COMPACTED so the wordmark, About, the cart and Account can share one row. The desktop 20px
       gutter and 12px gap cost 76px of a 390px screen before any control is drawn - more than the
       About pill itself. Horizontal only: the vertical padding is what gives these pills their touch
       height, and they are already under the 44px guidance without shaving it further. */
    padding: 8px 12px 14px;
    gap: 7px;
    flex-wrap: wrap;
  }
  /* WRAP, NOT NOWRAP. `nowrap` did not make these fit - it made the overflow invisible. The items
     that carry flex:none (the About pill, the cart, the Account menu) will not shrink, so a row that
     cannot fit simply runs past the viewport, and .nav-pill's margin-left:auto then drags it back
     ACROSS the context slot: on Checkout/Contact the step indicator and the About pill rendered on
     top of each other, as literally unreadable overlapping text.

     Wrapping puts the context on its own line instead. The header gets taller; nothing is hidden
     behind another element or pushed off-screen. Pages that move their context into the content
     (see .page-search) never reach this at all. */
  .nav.has-context {
    padding: 10px 12px;
    flex-wrap: wrap;
  }
  /* The hamburger and the whole .nav .links dropdown that lived here are GONE (#165). They existed
     to collapse a header row of email + Support + Log out, which is now the Account menu - one
     control, rendered identically at every width, so the narrow breakpoint no longer needs a second
     navigation of its own. Signed out there is a single Log in button, which needs no collapsing.

     The panel keeps the desktop's right-anchored position rather than stretching to the viewport:
     it is anchored to a trigger that sits at the right edge at every width, and 224px of menu on a
     360px screen is a menu, not a wall. */
  /* ONE ROW, and the pill can no longer be the reason it is not. "Account" is a known width, and
     the menu is allowed to shrink rather than carrying flex:none - so if the row still runs short at
     some width, the label ellipses instead of the whole control wrapping to a second line and taking
     its off-screen dropdown with it. */
  .acct-menu { flex: 0 1 auto; min-width: 0; }
  .acct-trigger {
    max-width: 100%;
    min-width: 0;
    padding-left: 11px;
    padding-right: 11px;
    gap: 6px;
  }

  /* Same trim on the other two, so the three read as one set rather than three different insets. */
  .nav-pill {
    padding-left: 11px;
    padding-right: 11px;
  }
  .cart-pill {
    padding-left: 9px;
    padding-right: 10px;
    gap: 5px;
  }

  /* THE PANEL IS PINNED TO THE VIEWPORT, not to the trigger's right edge.
     Anchoring it to the trigger is right while the trigger sits at the right of the header. When the
     row wraps, the trigger moves to the LEFT of the second line and the panel opens leftwards from
     there - off the side of the screen, with the menu items clipped. That is the failure a customer
     actually meets, and it does not depend on whether the row happens to fit today: any width, any
     future item in that row, same result. Pinning it removes the dependency.

     top follows --nav-h, which _Layout measures from the nav's real height - so it sits under the
     header whether that header is one row or two. max-width keeps it inside a narrow screen. */
  .acct-panel {
    position: fixed;
    top: calc(var(--nav-h, 56px) + 6px);
    right: 12px;
    left: auto;
    max-width: calc(100vw - 24px);
  }
  /* Log in keeps its desktop pill shape here now. It was full-width because it was the last item in
     a stacked dropdown; sitting in the header row, a button spanning the viewport would read as the
     page's primary action rather than as the way back in. */
  .wm {
    font-size: 18px;   /* same nudge as desktop, kept proportional */
    gap: 8px;
  }
  .wmdot {
    width: 24px;
    height: 24px;
  }
  .wmlogo {
    width: 38.5px;   /* keeps the 392:346 ratio at the smaller mobile height */
    height: 34px;
  }

  /* FOOTER (issue #111). The footer had NO mobile rule at all - it stayed a space-between row, so
     the copyright wrapped to two lines on the left while six links wrapped raggedly against it, and
     the result read as neither a row nor a list. It stacks at the same 768px the header does, so the
     page has one breakpoint rather than a header that has collapsed above a footer that has not.

     DOM order is kept - copyright first, then links. Flipping them with `order` would be the more
     conventional footer, but it puts reading order out of step with focus order, and a copyright
     line above its own links is not wrong. Not worth the mismatch. */
  .foot {
    flex-direction: column;
    align-items: flex-start;
    gap: 14px;
    /* The house mobile gutter, as .nav uses. The base rule's max(40px, ...) floor keeps 40px each
       side, which on a 390px screen spends a fifth of the width on margins. */
    padding: 24px 20px 28px;
  }
  .foot .links {
    flex-direction: column;
    align-items: flex-start;
    /* Rhythm comes from each link's own padding rather than the gap, so the spacing between two
       links IS their tap target rather than dead space between two 12px-tall ones. */
    gap: 0;
    width: 100%;
  }
  .foot .links a {
    display: block;
    width: 100%;
    /* 10px each side of a 13px line lands each row at ~37px tall, measured. Short of the 44px touch
       guidance, and deliberately: these are footer fine print rather than primary actions, and six
       links at 44px would make the footer taller than the content above it on a short page. It is
       more than double the 16px the un-stacked links used to offer. */
    padding: 10px 0;
    font-size: 13px;
  }

  .nav-context {
    justify-content: flex-start;
    flex: 1 1 auto;
    min-width: 0;
  }
  .results-search {
    max-width: none;
    min-width: 0;
    height: 44px;
  }
  .co-steps {
    font-size: 11.5px;
    gap: 7px;
  }

  .hero {
    padding: 30px 20px 26px;
  }
  /* Scaled from the desktop 20px by the same ratio the old 13px/11.5px pair used, so the mobile
     eyebrow tracks the desktop change instead of staying at its old size and winning below 768px. */
  .hero .eyebrow {
    font-size: 18px;
    margin-bottom: 12px;
  }
  /* Stack on mobile. Side-by-side would squeeze a 32px headline that already wraps to two lines,
     leaving both the mark and the words too small to work. */
  .hero-lockup {
    flex-direction: column;
    gap: 14px;
    margin-bottom: 13px;
  }
  .hero-lockup .mk {
    width: 86px;
    height: 76px;
  }
  .hero h1 {
    font-size: 32px;
    line-height: 1.02;
    letter-spacing: -0.025em;
    margin-bottom: 0;
    text-align: center;
  }
  .hero .sub {
    font-size: 14px;
    margin-bottom: 24px;
  }
  .search {
    flex-direction: column;
    gap: 12px;
    margin-bottom: 0;
  }
  .search input {
    height: 58px;
    min-height: 58px;
    font-size: 16px;
    border-radius: 18px;
    padding: 0 18px;
  }
  .search button {
    height: auto;
    padding: 16px;
    border-radius: 18px;
    width: 100%;
  }
  .pills {
    margin-top: 18px;
    gap: 8px;
  }

  .results {
    padding: 6px 18px 24px;
  }
  .legal {
    padding: 18px 18px 60px;
  }
  .legal h1 {
    font-size: 25px;
  }
  .results .count {
    font-size: 12px;
    margin-bottom: 14px;
  }
  .row {
    /* row-gap 0, but keep a column gap so the name/badge never butts into the buybox */
    gap: 0 14px;
    padding: 16px 17px;
    border-radius: 16px;
    margin-bottom: 11px;
  }
  .row .name {
    font-size: 17px;
  }
  /* Narrow screens stack the purchase block UNDER the name instead of squeezing it into a side
     column. This used to happen by accident - a long name forced .row to wrap - and min-width:0
     removed the accident, so it is stated deliberately here. Short names now stack too, which is
     what the phone layout wanted all along. */
  .row .id {
    flex: 1 1 100%;
  }
  .buybox {
    flex: 1 0 100%;
  }
  .avail .lbl {
    font-size: 11.5px;
  }
  .price {
    font-size: 17px;
  }
  /* Was `.row .buy { flex: 1 0 100% }`, written when .buy was a direct child of the horizontal .row.
     It now sits in the COLUMN-direction .buybox, where flex-basis resolves against the height axis
     and flex-grow would stretch the button down the whole card. Width is what was actually wanted. */
  .buybox .buy {
    width: 100%;
    padding: 12px;
    border-radius: 14px;
  }

  /* checkout two-column stacks */
  .co-body {
    flex-direction: column;
  }
  .co-form {
    padding: 26px 20px 30px;
  }
  .co-form h1 {
    font-size: 24px;
  }
  .co-fieldrow {
    flex-direction: column;
    gap: 0;
  }
  .co-fieldrow > .field,
  .co-fieldrow > .field.wide {
    flex: 1 1 auto;
  }
  .co-rail {
    width: auto;
    border-left: none;
    border-top: 1px solid var(--line);
    padding: 28px 20px;
  }

  .cf-hero h1 {
    font-size: 26px;
  }
}

/* ---------- auth: validation + alerts + logout button reset ---------- */
.au-alert {
  border-radius: 12px;
  padding: 11px 14px;
  font-size: 12.5px;
  font-weight: 600;
  margin-bottom: 16px;
}
.au-alert:empty {
  display: none;
}
.au-alert.err {
  background: var(--errbg);
  color: var(--err);
  border: 1px solid var(--errline);
}
.au-alert ul {
  margin: 0;
  padding-left: 18px;
}
.field-error {
  display: block;
  color: var(--err);
  font-size: 11.5px;
  font-weight: 600;
  margin-top: 6px;
}
.field-error:empty {
  display: none;
}
.au-forgot a,
.au-alt a {
  color: var(--brand);
  font-weight: 700;
}

/* logout is a POST form styled to sit inline in the nav like a link/button */
.logout-form {
  display: inline;
  margin: 0;
  padding: 0;
}
.logout-form button {
  border: none;
  cursor: pointer;
  font-family: var(--font);
}
.logout-form button.cta {
  font: 700 15px var(--font);
}

/* ============================================================
   13. CHECKOUT - validation + Stripe Payment Element
   ============================================================ */

/* Form-level and field-level validation messages */
.co-error {
  margin: 10px 0;
  padding: 10px 14px;
  border-radius: 10px;
  background: var(--errbg);
  border: 1px solid var(--errline);
  color: var(--err);
  font-size: 13px;
  font-weight: 600;
}
.co-error:empty { display: none; }

.fld-err {
  display: block;
  margin-top: 5px;
  font-size: 12px;
  font-weight: 600;
  color: var(--err);
}
.fld-err:empty { display: none; }

/* Invalid inputs (jQuery unobtrusive validation adds .input-validation-error) */
.inp.input-validation-error { border-color: var(--err); }

/* Stripe Payment Element mount point */
#payment-element { margin: 6px 0 4px; }

/* Spinner inside the Pay button while the card is authorizing */
.btn-spinner {
  display: inline-block;
  width: 16px;
  height: 16px;
  border-radius: 50%;
  border: 2px solid rgba(255, 255, 255, .45);
  border-top-color: #fff;
  animation: spin .8s linear infinite;
}
/* Opacity alone was not enough on the buy button: a 75%-opacity brand orange still reads as a
   live call to action, which is exactly the wrong signal on a control that cannot be used. A
   disabled button is drawn as an inert surface instead - and .btn.sec's palette is already the one
   tuned for the page background it sits on. */
.btn:disabled {
  opacity: 1;
  cursor: not-allowed;
  background: var(--soft);
  color: var(--muted);
  border: 1.5px solid var(--line);
}
.btn:disabled:hover { filter: none; background: var(--soft); }

/* Real checkbox for "Save for next time" - visually replaced by the .box tick */
.co-save-box { position: absolute; opacity: 0; pointer-events: none; }

/* ---- Checkout: Stripe notice, contact checkboxes, state field ---- */
.co-stripe-note {
  display: flex; align-items: flex-start; gap: 8px;
  margin: 4px 0 14px; padding: 11px 14px;
  border-radius: 12px; background: var(--soft); border: 1px solid var(--line);
  font-size: 12.5px; line-height: 1.5; color: var(--muted);
}
.co-stripe-note b { color: var(--ink); }

.co-check {
  display: flex; align-items: center; gap: 10px;
  padding: 9px 0; font-size: 13.5px; color: var(--ink); cursor: pointer;
}
.co-check input[type="checkbox"] { width: 17px; height: 17px; accent-color: var(--brand); cursor: pointer; }
.co-check .txt { line-height: 1.45; }
/* The agreement line is the longest of the co-check controls (three linked document names) and wraps to
   two or three lines on a phone. The shared rule centres the box against the whole block, which reads as
   misaligned once wrapped - so this one aligns to the first line instead. Scoped, so the other four
   co-check controls keep the centred look they were designed with. */
.co-check.agree { align-items: flex-start; }
.co-check.agree input[type="checkbox"] { margin-top: 1px; flex: none; }

.co-note {
  margin: 6px 0 2px; padding: 10px 13px;
  border-radius: 10px; background: var(--soft);
  font-size: 12.5px; color: var(--muted); line-height: 1.5;
}

.intro.sm { font-size: 13px; margin-bottom: 4px; }
.mt-12 { margin-top: 12px; }

/* [hidden] must win over the display rules on these elements */
[hidden] { display: none !important; }

/* Address Element (billing) sits above the Payment Element - give them breathing room. */
#address-element { margin-bottom: 18px; }

/* ---- Pay: rail consent checkbox ---- */
.co-check.rail {
  align-items: flex-start;
  gap: 10px;
  margin: 4px 0 16px;
  padding: 12px 14px;
  border-radius: 12px;
  background: var(--surface);
  border: 1px solid var(--line);
  font-size: 13px;
}
.co-check.rail .txt { display: flex; flex-direction: column; gap: 3px; }
.co-check.rail .sub { font-size: 11.5px; color: var(--muted); font-weight: 500; line-height: 1.45; }
.co-check.rail input[type="checkbox"] { margin-top: 1px; }

/* ============================================================
   DOMAIN DETAILS (/Domains/Details)
   ============================================================ */

/* Domain cards are links to the detail page - keep them looking like cards, not links. */
.md-card { display: block; text-decoration: none; color: inherit; transition: border-color .15s ease, transform .1s ease; }
.md-card:hover { border-color: var(--brand); transform: translateY(-1px); }

.md-badge.warn { background: var(--errbg); color: var(--err); }

.dm-wrap { max-width: 860px; margin: 0 auto; padding: 28px 22px 56px; }

.dm-back {
  display: inline-block; margin-bottom: 18px;
  font-size: 13px; font-weight: 700; color: var(--muted); text-decoration: none;
}
.dm-back:hover { color: var(--brand); }

.dm-head { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.dm-head h1 {
  font-family: var(--display); font-size: 34px; font-weight: 800;
  letter-spacing: -.02em; margin: 0;
}
.dm-head .dm-refresh { margin-left: auto; }
.dm-sub { font-size: 13.5px; color: var(--muted); margin: 6px 0 26px; }

.dm-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
.dm-card {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: 16px; padding: 20px 22px;
}
.dm-card.wide { grid-column: 1 / -1; }
.dm-card .hd {
  font-size: 12px; font-weight: 800; letter-spacing: .08em; text-transform: uppercase;
  color: var(--faint); margin-bottom: 14px;
}

.dm-list { margin: 0; display: flex; flex-direction: column; gap: 10px; }
.dm-list.two { display: grid; grid-template-columns: 1fr 1fr; gap: 10px 24px; }
.dm-list > div { display: flex; justify-content: space-between; gap: 16px; font-size: 14.5px; }
.dm-list dt { color: var(--muted); margin: 0; }
.dm-list dd { margin: 0; font-weight: 600; color: var(--ink); text-align: right; word-break: break-word; }

/* A dm-list row that carries an explanation, which today is only the privacy row (#171). Without
   this the sentence rendered as right-aligned prose hanging below the value, reading as a caption
   for the whole card rather than for the property it is about - reported from the live page. The
   tint and hairline draw the label, the value and the explanation into one object.

   The label FLOATS rather than sharing a flex row, so the sentence can clear it and use the block's
   full width; inside the flex row it was trapped in the value column and wrapped three times. */
.dm-list > div.dm-block {
  display: block;
  background: var(--soft);
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: 9px 11px;
  margin: 2px 0;
}
.dm-list > div.dm-block dt { float: left; }
/* NO overflow:hidden here, deliberately. It would make the dd a block formatting context, which sits
   BESIDE the floated label rather than flowing around it - so in a narrow card the note underneath
   was confined to a column starting at the label's right edge instead of spanning the block. */
.dm-list > div.dm-block dd { min-width: 0; }

/* Left-aligned and unbolded, unlike the value above it: this is a sentence, and right-aligned prose
   reads as a caption. Clears the floated label so it spans the whole block. */
.dm-note {
  clear: left;
  margin: 7px 0 0;
  text-align: left;
  font-weight: 400;
  font-size: 13px;
  line-height: 1.5;
  color: var(--muted);
}

.dm-ns { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 8px; }
.dm-ns li { display: flex; align-items: center; gap: 10px; font-size: 13.5px; font-weight: 600; }
.dm-ns .seq {
  width: 20px; height: 20px; border-radius: 6px; flex: none;
  background: var(--soft); color: var(--brand);
  display: flex; align-items: center; justify-content: center;
  font-size: 11px; font-weight: 800;
}

.dm-mut { font-size: 14.5px; color: var(--muted); line-height: 1.55; margin: 0; }
.dm-mut.sm { font-size: 13px; margin-top: 12px; }
.dm-mut.warn { color: var(--err); }

.dm-soon {
  margin-top: 18px; padding: 13px 16px;
  border-radius: 12px; background: var(--soft); border: 1px dashed var(--line);
  font-size: 12.5px; color: var(--muted); text-align: center;
}

/* ---- Domain details: auto-renew + saved card ---- */
.dm-flash {
  margin-bottom: 16px; padding: 12px 15px;
  border-radius: 12px; background: var(--soft); border: 1px solid var(--ok, #2f9e6f);
  color: var(--ok, #2f9e6f); font-size: 13px; font-weight: 600;
}

/* The small size, independent of the variant. It only existed as .btn.sec.sm, which welded the
   size to the secondary style - so `class="btn sm"` silently rendered full-size. Size and variant
   are separate decisions; .btn.sec.sm keeps its own margin because that is layout, not size. */
.btn.sm { padding: 9px 16px; font-size: 12.5px; }
.btn.sec.sm { padding: 9px 16px; font-size: 12.5px; margin-top: 12px; }

.dm-card-row {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  margin-top: 16px; padding: 12px 14px;
  border-radius: 12px; background: var(--soft); border: 1px solid var(--line);
}
.dm-card-row .cd { font-size: 13px; font-weight: 700; color: var(--ink); letter-spacing: .02em; }
.dm-card-row .mut { font-size: 11.5px; color: var(--muted); margin-top: 2px; }

.lnk-danger {
  background: none; border: none; padding: 0; cursor: pointer;
  font: 700 12.5px var(--font); color: var(--err); text-decoration: underline;
}
.lnk-danger:hover { opacity: .8; }

.dm-flash.warn { border-color: var(--warn, #c98a2e); color: var(--warn, #c98a2e); }

.dm-warn-box {
  margin-bottom: 14px; padding: 12px 15px;
  border-radius: 12px; background: var(--warnbg, #fbf1de); border: 1px solid var(--warn, #c98a2e);
  color: var(--ink); font-size: 12.5px; line-height: 1.55;
}

/* A warn box placed straight after a page heading has nothing to space it: .dm-head carries no
   bottom margin, because normally the gap comes from the .dm-sub line beneath it. A banner with no
   sub-heading was landing hard against the h1. */
.dm-head + .dm-warn-box { margin-top: 20px; }

/* Privacy is a VALUE here, not a control - #171. It was a disabled checkbox (privacy is included in
   the price, so there is nothing for a customer to buy or cancel), and every attempt to make that
   box LOOK read-only failed the same way: a box reads as clickable however it is painted, and
   dimming it only made the row look unimportant. So it renders exactly like "Registrar lock" two
   rows above - reported, not offered - and the note beneath the row says how it changes. */
.dm-ro-value { color: var(--ink); }

/* ---- About page ---- */
/* Alternating bands rather than cards: the copy is prose, and boxing each paragraph would make a
   short honest page look like a feature matrix - the opposite of what it says about itself. */
.ab-hero { padding-bottom: 8px; }
.ab-band { padding: 40px 40px; }
.ab-band.alt { background: var(--surface); border-block: 1px solid var(--line); }
.ab-inner { max-width: 720px; margin: 0 auto; }
.ab-inner h2 {
  font-family: var(--display);
  font-size: 27px;
  letter-spacing: -0.02em;
  margin: 0 0 16px;
}
.ab-inner p { font-size: 16px; line-height: 1.65; color: var(--muted); margin: 0 0 14px; }
.ab-inner p strong { color: var(--ink); font-weight: 700; }

/* Each promise is a bolded lead plus one plain line, per the copy deck - the lead has to win the
   scan, so it gets its own line rather than running into the sentence. */
.ab-promises { list-style: none; padding: 0; margin: 0; display: grid; gap: 18px; }
.ab-promises li { font-size: 15.5px; line-height: 1.6; color: var(--muted); }
.ab-promises li strong { display: block; color: var(--ink); font-weight: 700; margin-bottom: 3px; }

/* Prose context, so links must opt back into being visible - see the inline-link rule near the top
   of this file. The mailto here is the only route the page offers. */
.ab-inner a:not(.btn) {
  color: var(--brandink);
  font-weight: 600;
  text-decoration: underline;
  text-underline-offset: 2px;
  text-decoration-thickness: 1px;
}
.ab-inner a:not(.btn):hover { text-decoration-thickness: 2px; }
.ab-close .ab-cta { margin-top: 22px; }

@media (max-width: 768px) {
  .ab-band { padding: 30px 20px; }
  .ab-inner h2 { font-size: 23px; }
}

/* ---- Domain details: contact + nameserver edit forms ---- */
/* align-items:flex-end, and it is not cosmetic: a flex row STRETCHES its children, so a button
   sitting beside a label+input pair grew to the height of both and rendered as a slab twice the
   height of every other button on the page. Bottom-aligned, it keeps its own size and lines up with
   the inputs it acts on. */
.dm-fieldrow { display: flex; align-items: flex-end; gap: 14px; margin-bottom: 12px; flex-wrap: wrap; }
.dm-fieldrow > .field { flex: 1 1 160px; min-width: 0; }
/* The 12px was lifting it off a stretched row that no longer exists. */

/* A message box is where someone writes a paragraph. At the full rail it was 1100px wide and three
   lines tall, which reads as a single-line field that happens to wrap. */
.dm-fieldrow textarea.inp { min-height: 132px; resize: vertical; }
.dm-fieldrow .lbl { font-size: 11.5px; margin-bottom: 4px; display: block; }

@media (max-width: 768px) {
  /* align-items must go back to stretch with the direction change. The flex-end that bottom-aligns
     the Save button against its inputs on desktop becomes RIGHT-alignment once this is a column, and
     it collapsed every field to the width of its own label. */
  .dm-fieldrow { flex-direction: column; align-items: stretch; }
  /* flex-basis is measured along the MAIN axis, so the 160px that sets a minimum field WIDTH in a
     row became a 160px field HEIGHT once the row turned into a column - every field padded out with
     ~100px of dead space beneath it. Reported from a phone; it predates the console rework. */
  .dm-fieldrow > .field { flex: 0 0 auto; }
}

@media (max-width: 768px) {
  .dm-grid { grid-template-columns: 1fr; }
  .dm-list.two { grid-template-columns: 1fr; }
}

/* TYPE SCALE, raised a step for the console (#165 follow-up). These sizes were set when a card sat
   in a 1040px shell beside a 200px sidebar; with the sidebar retired the same cards are half as wide
   again, and 11px labels over 13px body read as small print in a space that is not small. Raised
   proportionally rather than uniformly - the card LABEL and the big number carry the most air, so
   they move most. */
/* ---- Account console shell ----------------------------------------------------------------
   The .acct-side sidebar it used to hold is gone (#165): its seven destinations are in the header's
   Account menu, which every page carries, so the console no longer runs a second navigation that
   disagreed with the first. On mobile that sidebar became a full-width strip of horizontally
   scrolling links above the actual page - the layout #167 is about measuring. */
.acct-shell {
  /* THE SAME RAIL THE HEADER USES. The nav resolves to 1100px of content centred in the viewport
     (see its max(40px, ...) padding), and this was 1040px with 22px gutters - so the search box and
     the Account pill overhung the cards on both sides. Nobody noticed while a 200px sidebar filled
     the difference; with it gone the mismatch is what reads as content floating in a void, more than
     the width itself does. 1180 - 80 of padding = 1100, aligned. */
  max-width: 1180px; margin: 0 auto; padding: 28px 40px 56px;
}
.acct-main { min-width: 0; }

/* The in-content search is a PHONE-ONLY copy of the header one - see _AccountLayout. Desktop keeps
   the header version, which is where a customer expects it when there is room for it. */
/* The mobile home for whatever a page puts in the header's context slot - the compact search on the
   results page and in the console, the two-step indicator through checkout. Rendered by the page
   itself, next to the header copy, and shown only below 768px. */
.page-context { display: none; }

/* Breadcrumb (#165 follow-up). The sidebar used to answer "where am I" with a highlighted row that
   was always on screen; behind a menu, a page three levels down had only a back link - which says
   where you came FROM, not where you ARE. Sits above the page's own heading and is deliberately
   quiet: it orients, it is not a title. */
.crumbs {
  display: flex; flex-wrap: wrap; align-items: center; gap: 6px;
  margin-bottom: 14px;
  font-size: 13.5px; font-weight: 600;
}
.crumbs a { color: var(--muted); text-decoration: none; }
.crumbs a:hover { color: var(--brand); text-decoration: underline; text-underline-offset: 2px; }
.crumb-sep { color: var(--faint); }
/* The leaf is the one thing here a customer scans for, so it is the only part in full ink - and it
   can be a domain name, which must not knock the trail into a second line on a phone. */
.crumb-here {
  color: var(--ink);
  max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* THE WIDTH THE CONSOLE ACTUALLY HAD. Every console page wraps its body in .dm-wrap (860px) or
   .md-wrap (920px), NESTED inside this shell - so the shell was never the constraint, and widening
   it alone changed nothing. With the 200px sidebar gone those inner rails leave the content adrift
   in the middle of a wide screen, narrower than the header above it.

   Vertical padding is dropped rather than doubled: the shell already spaces the page, and 28 + 28
   was a gap nobody chose. Horizontal centring inside the shell is kept for the pages that stay
   narrow - a FORM at 1100px is worse than one at 860, so this widens the dashboards and lists and
   leaves the rest alone. */
.acct-shell > .acct-main > .dm-wrap,
.acct-shell > .acct-main > .md-wrap { padding: 0; }
.acct-shell > .acct-main > .dm-wrap.wide,
.acct-shell > .acct-main > .md-wrap { max-width: none; }

/* The trail is rendered by the LAYOUT, above the page's own wrapper, so on a page that stays narrow
   it sat on the shell's rail while the heading below it was centred at 860 - the two lines that
   should read as one block, out of step by 120px. :has() lets the crumbs follow whichever rail the
   page itself chose, without the layout having to be told. */
.acct-main:has(> .dm-wrap:not(.wide)) .crumbs { max-width: 860px; margin-inline: auto; }

/* Overview dashboard cards - dm-card used as a clickable link instead of a static section. */
.dm-card.link { display: block; text-decoration: none; color: inherit; transition: border-color .15s ease, transform .1s ease; }
.dm-card.link:hover { border-color: var(--brand); transform: translateY(-1px); }
.ov-big { font-family: var(--display); font-size: 42px; font-weight: 800; letter-spacing: -.02em; }
.ov-link { display: inline-block; margin-top: 12px; font-size: 13.5px; font-weight: 700; color: var(--brand); }

/* The Overview's three cards, on one row once there is room for them. In the shared two-column grid
   the third sat alone on a second row, which after the sidebar came out left a conspicuous empty
   half-width beside it - filling the reclaimed space with content rather than stretching two cards
   across it. Its own class, not a change to .dm-grid: the domain page's two-column pairing of
   Registration against Automatic renewal is deliberate and is not a three-card dashboard. */
/* THREE cards on one row once there is room. In the shared two-column grid a third card sat alone on
   a second row with an empty half beside it - barely noticeable in an 860px column, conspicuous
   across the full rail. It suits the domain page's contacts too, which come in threes (registration,
   administration, technical) and were previously 2 + 1.

   Applied per page (.ov-grid, .trio) rather than to .dm-grid itself: a two-column pairing is right
   wherever two cards are meant to be read against each other, and this must not silently re-flow
   every grid in the console. */
@media (min-width: 1000px) {
  .dm-grid.ov-grid,
  .dm-grid.trio { grid-template-columns: repeat(3, 1fr); }
}

@media (max-width: 768px) {
  /* ONE inset, not two nested ones (#167).
     The shell's gutter and the card's own padding stack, so console text began 38px from the edge of
     a 360px screen - 21% of the viewport spent on margins before a word was rendered. Worse, the two
     card families disagreed about by how much: .dm-card carries 22px and .md-card 16px, so My
     Domains and a domain's own detail page sat on rails 6px apart.

     The shell keeps a real screen gutter at 12px and the cards come to a single shared 16px, putting
     EVERY console page's text at the same 28px - about 20px more line width per side on the twelve
     .dm-card pages, and the two families finally aligned.

     Measured against the layout as it is now, not as #167 described it: the .acct-nav sidebar it
     blamed is gone (#165), .dm-wrap/.md-wrap already have their padding zeroed inside .acct-main,
     and the customer console has no tables at all. What was left is this. */
  .acct-shell { padding: 20px 12px 40px; }

  /* Horizontal only - the vertical rhythm inside a card is not what is squeezed. */
  .dm-card { padding-left: 16px; padding-right: 16px; }

  /* Renew and RenewComplete build from the same .dm-* parts but render under the DEFAULT layout, not
     the console shell - so the `.acct-shell > .acct-main > .dm-wrap { padding: 0 }` reset never
     reached them and they carried the wrapper's own 22px on top of the card's. At 44px they were the
     tightest pages on the site, and they are reached FROM My Domains at 32px. This lands them on the
     same 28px as everything else. The console's own wrappers are unaffected: the 3-class reset
     outranks this single-class rule whatever the source order. */
  .dm-wrap { padding-left: 12px; padding-right: 12px; }

  /* THE SWAP, and it is keyed on the page having ALREADY rendered its own copy - not on which
     area of the site it is. Any page that includes .page-search gets the header slot hidden and the
     full-width in-content one shown; a page that does not (checkout, with its step indicator) keeps
     whatever it put in the header. One rule, and a new page opts in by rendering the partial.

     It used to be scoped to .acct-shell, on the reasoning that the results page's search is the one
     control a customer needs most on the page they are already searching on. That is right, and it
     is the argument FOR this: squeezed into the header on a phone the box was ~90px wide and showed
     one character of what had been typed. Moving it into the content is how it becomes usable. */
  body:has(.page-context) .nav-context { display: none; }
  .page-context { display: block; }

  /* THE GUTTER. The results and checkout copies render as direct children of .fm-main, where
     nothing supplies one - so the search box sat hard against both edges of the viewport while the
     cards below it kept their inset. The CONSOLE's copy is inside .acct-shell, which already
     provides a gutter, so this is scoped to the ones that are not: padding here and not on the
     element inside means the sticky steps bar's background still spans edge to edge while its text
     stays on the rail. */
  .fm-main > .page-context { padding-left: 20px; padding-right: 20px; }

  /* The search gets the whole width, which is the entire point of moving it - plus room to breathe
     under the header rather than butting straight against it. */
  .page-context .results-search { width: 100%; max-width: none; margin-bottom: 14px; }
  .fm-main > .page-context:has(.results-search) { padding-top: 14px; }

  /* The steps stay put while the form scrolls under them, the way the header does - "where am I in
     checkout" is a question you have partway down a long form, not only at the top of it.

     STICKY ON .page-context ITSELF, NOT on the .co-steps inside it. A sticky element can only travel
     within its own containing block, and .co-steps' block is the short wrapper around it - it would
     come unstuck the instant that wrapper's own box scrolled past, which is the whole height of one
     line of text. .page-context's parent is .fm-main, which is the height of the page.

     --nav-h is measured in _Layout rather than hardcoded: the nav wraps to two rows at these widths
     and the maintenance banner adds another, so the offset is not a constant. The fallback is an
     unwrapped mobile nav. z-index sits below the nav's 50, so the two meet cleanly rather than the
     bar riding over the header. --surface matches the nav exactly, so at rest the two read as one
     header block and the page's gradient band starts below them. */
  .page-context:has(.co-steps) {
    position: sticky;
    top: var(--nav-h, 56px);
    z-index: 40;
    background: var(--surface);
    border-bottom: 1px solid var(--line);
  }
  /* Centred, because the header centred them and they are a progress indicator, not a heading. */
  .page-context .co-steps {
    justify-content: center;
    padding: 11px 0;
    font-size: 12.5px;
  }
}

/* ---- Pager (Orders, My Domains) ---- */
.pager {
  display: flex; align-items: center; justify-content: space-between;
  margin-top: 18px; padding-top: 14px; border-top: 1px solid var(--line);
}
.pager-info { font-size: 12.5px; color: var(--muted); }
.pager-btns { display: flex; gap: 8px; }
.pager-btns .disabled { opacity: .4; pointer-events: none; }

/* ---- Support: ticket list + two-way thread ---- */
.tk-list { display: flex; flex-direction: column; gap: 10px; }
.tk-row {
  display: flex; align-items: center; justify-content: space-between; gap: 14px;
  background: var(--surface); border: 1px solid var(--line); border-radius: 14px;
  padding: 16px 18px; text-decoration: none; color: inherit;
  transition: border-color .15s ease, transform .1s ease;
}
.tk-row:hover { border-color: var(--brand); transform: translateY(-1px); }
.tk-row-main { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.tk-subject { font-weight: 700; font-size: 14.5px; }
.tk-meta { font-size: 12px; color: var(--muted); }

.tk-badge {
  font: 700 10.5px var(--font); padding: 4px 9px; border-radius: 20px; flex: none;
  color: var(--muted); background: var(--soft);
}
.tk-badge-new { color: var(--brandink); background: var(--brand2); }
.tk-badge-open { color: var(--warn); background: var(--warnbg); }
.tk-badge-pendingcustomer { color: var(--muted); background: var(--soft); }
.tk-badge-resolved { color: var(--ok); background: var(--okbg); }

.tk-thread-card { display: flex; flex-direction: column; }
.tk-thread { display: flex; flex-direction: column; gap: 12px; margin-bottom: 18px; }
/* 80% of a 860px card was a readable line; 80% of the full rail is 880px, which is not - a message
   is prose, and prose stops being scannable somewhere around 75 characters. The ch cap holds the
   line length steady whatever the card does, and the percentage still governs on a narrow screen. */
.tk-bubble { max-width: min(80%, 68ch); }
.tk-bubble-body {
  padding: 11px 15px; border-radius: 14px; font-size: 13.5px; line-height: 1.5;
  background: var(--soft); border-top-left-radius: 3px;
}
.tk-bubble-when { font-size: 11px; color: var(--faint); margin-top: 4px; padding: 0 4px; }
.tk-bubble-support { align-self: flex-end; }
.tk-bubble-support .tk-bubble-body {
  background: var(--brand2); color: var(--brandink); border-top-left-radius: 14px; border-top-right-radius: 3px;
}
.tk-bubble-support .tk-bubble-when { text-align: right; }

.tk-reply-form { display: flex; flex-direction: column; gap: 10px; }
/* Tall enough to look like somewhere you write a paragraph. It inherited a single-row height, which
   across the full width read as a search box. */
.tk-reply-form textarea { resize: vertical; min-height: 120px; }
.tk-reply-form .btn { align-self: flex-end; }

@media (max-width: 768px) {
  .tk-row { flex-direction: column; align-items: flex-start; }
  .tk-bubble { max-width: 92%; }
}

/* ---- Account security: two-factor setup + recovery codes ---- */
/* The rounded/white frame lives on the WRAPPER, not the <svg> - so the border-radius never clips the
   QR's finder patterns - and the code renders at (near) its native module size. Scaling it down below
   ~3px/module (the old 176px) made it only intermittently scannable; ~240px keeps ~4px/module. White
   background regardless of theme so it stays scannable in dark mode. */
.tfa-qr {
  margin: 14px 0;
  display: inline-block;
  background: #fff;
  border: 1px solid var(--line);
  border-radius: 14px;
  padding: 14px;
}
/* 260px is a DISPLAY choice, not a constraint - AuthenticatorQr gives the SVG a viewBox, so any
   QR version scales into whatever box is set here instead of being clipped at the right and bottom.
   That distinction is the fix; the number on its own is not.

   Why it was not: the QR's module count depends on the customer's email and on the issuer, which is
   environment-qualified outside production. At the previous 240px, EVERY account cropped in
   Development (65 modules x 4 = 260px), and a moderately long email crops even at 260 (69 modules =
   276px). Sizing to the widest account anyone happened to test with is what broke this twice.

   max-width keeps it inside a narrow viewport, where a fixed 260 would overflow the card. */
.tfa-qr svg {
  display: block;
  width: 260px;
  height: 260px;
  max-width: 100%;
}
.tfa-key {
  font-family: ui-monospace, 'Cascadia Code', Consolas, monospace; letter-spacing: .06em;
  background: var(--soft); padding: 2px 6px; border-radius: 6px;
}
.tfa-codes {
  list-style: none; margin: 12px 0 18px; padding: 14px 16px;
  background: var(--soft); border: 1px solid var(--line); border-radius: 12px;
  display: grid; grid-template-columns: 1fr 1fr; gap: 8px 24px;
}
.tfa-codes li code {
  font-family: ui-monospace, 'Cascadia Code', Consolas, monospace; font-size: 14px; letter-spacing: .04em;
}
/* Cards in a three-up row hold different amounts of copy, so their buttons landed at three different
   heights and the row read as ragged. The card becomes a column and its action block is pushed to
   the bottom, which puts every button on one line however much text sits above it. */
.dm-grid > .dm-card { display: flex; flex-direction: column; }
.dm-grid > .dm-card > .tfa-actions,
.dm-grid > .dm-card > .cx-actions,
/* A form that is nothing but its button - Privacy's "Request account deletion". NOT a form with
   fields in it: the nameserver editor is also a direct child here, and shrink-to-fit collapsed its
   three inputs to a fraction of the card. */
.dm-grid > .dm-card > form:not(:has(.field)),
.dm-grid > .dm-card > .btn {
  /* Pushed to the bottom so buttons in a row of cards share one baseline whatever the copy above
     them runs to. */
  margin-top: auto;
  /* align-self, because a flex column STRETCHES its children: without it the buttons grew to the
     full card width and read as page-level CTAs. The card itself keeps stretch, since the lists and
     paragraphs above genuinely do want the width. */
  align-self: flex-start;
  /* PADDING, not margin: margin-top is spoken for by the auto above, and when a card has no spare
     room the auto collapses to nothing and the button ends up touching the paragraph. Padding is
     the floor under that gap. */
  padding-top: 16px;
}

.tfa-actions { display: flex; align-items: center; gap: 16px; margin-top: 14px; flex-wrap: wrap; }
.tfa-actions form { margin: 0; }

/* Connected accounts (external logins) */
.cx-list { list-style: none; margin: 4px 0 16px; padding: 0; }
.cx-row {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 12px 0; border-bottom: 1px solid var(--line);
}
.cx-row:last-child { border-bottom: none; }
.cx-name { font-weight: 700; display: flex; align-items: center; gap: 10px; }
.cx-badge {
  font: 700 11px var(--font); color: var(--ok); background: var(--okbg, rgba(45,160,90,.12));
  border-radius: 999px; padding: 3px 9px;
}
.cx-actions { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; margin-top: 4px; }
.cx-actions form { margin: 0; }

/* ---------- shopping cart page ---------- */
.cart-page {
  max-width: 780px;
  margin: 0 auto;
  padding: 34px 40px 60px;
}
.cart-title {
  font-family: var(--display);
  font-size: 32px;
  margin: 0 0 22px;
}
.cart-notice {
  border: 1.5px solid var(--brand);
  background: var(--brand2);
  color: var(--brandink);
  font: 600 14px var(--font);
  border-radius: 14px;
  padding: 12px 16px;
  margin-bottom: 18px;
}
/* The action inside a cart notice. Block with its own top margin so the button never sits jammed
   against the sentence above it, and left-aligned with the notice text. */
.cart-notice .cn-act {
  margin: 12px 0 2px;
}

.cart-empty {
  text-align: center;
  padding: 40px 0;
  color: var(--muted);
}
.cart-empty p {
  margin: 0 0 18px;
}

.cart-lines {
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.cart-line {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 18px;
  flex-wrap: wrap;
  border: 1.5px solid var(--line);
  border-radius: 16px;
  background: var(--surface);
  padding: 16px 20px;
}
/* A name that went while it sat in the cart. Muted rather than removed - the customer needs to see
   what happened, and the copy on the line says they are not charged for it. */
.cart-line.unavailable {
  opacity: 0.72;
  background: var(--field);
}
.cart-line .cl-id {
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.cart-line .name {
  font: 700 19px var(--font);
  word-break: break-word;
}
.cart-line .tldname {
  color: var(--muted);
}
.cl-gone {
  font: 600 12.5px var(--font);
  color: var(--muted);
  max-width: 42ch;
}
.cl-actions {
  display: flex;
  align-items: center;
  gap: 16px;
  flex-wrap: wrap;
}
.cl-actions form {
  margin: 0;
  display: flex;
  align-items: center;
  gap: 8px;
}
/* The Update button only matters without JS - with JS the select auto-submits on change. */
.cl-update,
.cl-remove {
  font: 600 13px var(--font);
  color: var(--muted);
  background: none;
  border: none;
  padding: 4px 2px;
  cursor: pointer;
  text-decoration: underline;
}
.cl-update:hover,
.cl-remove:hover {
  color: var(--brandink);
}

.cart-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 18px;
  flex-wrap: wrap;
  margin-top: 20px;
  padding-top: 18px;
  border-top: 1.5px solid var(--line);
}
.cart-total {
  display: flex;
  align-items: baseline;
  gap: 12px;
  margin-left: auto;
}
.cart-total .ct-lbl {
  font: 600 14px var(--font);
  color: var(--muted);
}
.cart-total .ct-amt {
  font: 800 26px var(--font);
}
.cart-go {
  margin-top: 26px;
  text-align: right;
}
.cart-fineprint {
  font: 500 12.5px var(--font);
  color: var(--muted);
  margin: 14px 0 0;
  text-align: right;
  max-width: 56ch;
  margin-left: auto;
}
/* Add-to-cart, after the name is in. Reads as done rather than as another thing to press. */
.btn.buy.in-cart {
  background: var(--brand2);
  color: var(--brandink);
  border: 1.5px solid var(--brand);
}

@media (max-width: 768px) {
  .cart-page {
    padding: 24px 20px 48px;
  }
  .cart-line,
  .cart-foot {
    flex-direction: column;
    align-items: flex-start;
  }
  .cart-total {
    margin-left: 0;
  }
  .cart-go,
  .cart-fineprint {
    text-align: left;
    margin-left: 0;
  }
}

/* A catalogue row we are not allowed to sell (#184). Muted rather than alarming - this is a normal
   state of the world, not an error the operator caused - but it carries the registrar's verbatim
   words, because the operator's next question is "says who". */
.tld-blocked {
  display: flex;
  flex-direction: column;
  gap: 3px;
  max-width: 520px;
  padding: 9px 12px;
  border: 1px solid var(--line);
  border-left: 3px solid var(--warn);
  border-radius: 10px;
  background: var(--soft);
  font-size: 12.5px;
  color: var(--muted);
}
.tld-blocked b {
  color: var(--ink);
  font-size: 13px;
}

/* ---------- multi-item checkout: per-item lists on Pay / Processing / Confirmation ---------- */
.co-item-amt {
  font: 700 15px var(--font);
  flex: none;
  margin-left: auto;
}
/* #169: removing one line at Pay. Quiet and small, under the domain name - it must not compete with
   the Pay button beneath it. A <button> rather than an anchor: the order rail sits inside the payment
   form so this must not navigate, and it also sidesteps the opt-in prose-link list at the top of this
   file, which a new link class would have had to join to look like a link at all. */
.co-item-rm {
  display: inline-block;
  margin-top: 5px;
  padding: 0;
  border: 0;
  background: none;
  font: 600 12px var(--font);
  color: var(--muted);
  text-decoration: underline;
  cursor: pointer;
}
.co-item-rm:hover {
  color: var(--err);
}
.co-item-rm:focus-visible {
  outline: 2px solid var(--brand);
  outline-offset: 2px;
  border-radius: 4px;
}
.co-item-rm[disabled] {
  opacity: 0.5;
  cursor: default;
}
.co-editcart {
  display: block;
  text-align: center;
  font: 600 13px var(--font);
  color: var(--muted);
  margin: 0 0 10px;
  text-decoration: underline;
}
.co-editcart:hover {
  color: var(--brandink);
}

/* Processing: names being registered, and per-item reasons when it fails. */
.pr-items {
  list-style: none;
  margin: 18px auto 4px;
  padding: 0;
  max-width: 420px;
  text-align: left;
}
.pr-item {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
  padding: 9px 14px;
  border: 1.5px solid var(--line);
  border-radius: 12px;
  background: var(--field);
  margin-bottom: 8px;
}
.pr-item .pi-name {
  font: 700 14px var(--font);
}
.pr-item .pi-why {
  font: 600 12.5px var(--font);
  color: var(--muted);
}
.pr-item.failed {
  border-color: var(--brand);
}
/* The single-failure reason, which has no list row to sit in. Same voice as .pi-why so one failed
   name and three failed names read alike. */
.pr-why {
  font: 600 12.5px var(--font);
  color: var(--muted);
  max-width: 42ch;
  margin: 0 auto 4px;
}

/* The registry named a field, so the failure is fixable (#163). Sits directly above the retry
   button, and is deliberately NOT styled as an error: nothing is broken, there is a correction to
   make. It appears only for a Rejected classification - a fault on our side never renders it,
   because "correct this field" over a billing failure would be a lie the customer acts on. */
.pr-fix {
  max-width: 42ch;
  margin: 16px auto 0;
  padding: 12px 14px;
  border-radius: 12px;
  background: var(--line2);
  border: 1px solid var(--line);
  text-align: left;
}
.pr-fix b {
  display: block;
  font: 800 13px var(--font);
  color: var(--ink);
  margin-bottom: 3px;
}
.pr-fix span {
  font: 500 12.5px var(--font);
  color: var(--muted);
  line-height: 1.55;
}

/* Provisioning progress. Registration runs one domain at a time and the cart allows several, so this
   is a wait that can run tens of seconds - a bare spinner gives a customer no way to tell "working"
   from "stuck". Filled by the poll on the Processing page; with JS off it stays at 0% and the page
   reads exactly as it did before, which is why nothing here is load-bearing. */
.pr-progress {
  max-width: 420px;
  margin: 20px auto 8px;
  height: 8px;
  border-radius: 999px;
  background: var(--line);
  overflow: hidden;
}
.pr-progress-fill {
  height: 100%;
  width: 0;
  border-radius: 999px;
  background: var(--brand);
  /* Eased rather than instant: the jump from one domain to the next is a real step, and animating it
     reads as progress instead of as a glitch. */
  transition: width .45s ease;
}
.pr-progress-text {
  font: 600 12.5px var(--font);
  color: var(--muted);
  text-align: center;
}

/* Per-domain state pip. Colour alone is not the signal - the pip changes SHAPE via the ring on
   "working" - because a red/green-only cue is exactly what a colour-blind customer cannot read. */
.pr-item .pi-state {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  flex: 0 0 auto;
  background: var(--line);
}
.pr-item .pi-state[data-state="working"] {
  background: transparent;
  border: 2px solid var(--brand);
  animation: pi-pulse 1s ease-in-out infinite;
}
.pr-item .pi-state[data-state="done"] { background: var(--ok, #1a7f4b); }
.pr-item .pi-state[data-state="failed"] { background: var(--brand); }

@keyframes pi-pulse {
  0%, 100% { opacity: .35; }
  50%      { opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
  .pr-progress-fill { transition: none; }
  .pr-item .pi-state[data-state="working"] { animation: none; opacity: 1; }
}

/* Confirmation: registered list, and the not-charged list on a partial order.
   .cf-card has no padding of its own - its body elements supply it (see .cf-steps), so the horizontal
   inset here is what keeps rows off the card border, and it matches .cf-steps so the two cards line up. */
.cf-list {
  list-style: none;
  margin: 0;
  padding: 4px 15px;
}
.cf-list li {
  display: flex;
  align-items: baseline;
  gap: 12px;
  flex-wrap: wrap;
  padding: 11px 0;
  border-bottom: 1px solid var(--line);
}
.cf-list li:last-child {
  border-bottom: none;
}
.cf-list .ci-name {
  font: 700 15px var(--font);
}
.cf-list .ci-meta {
  font: 600 12.5px var(--font);
  color: var(--muted);
}
.cf-list .ci-amt {
  margin-left: auto;
  font: 700 15px var(--font);
}
.cf-list .ci-support {
  margin-left: auto;
  font: 600 12.5px var(--font);
  color: var(--brandink);
  text-decoration: underline;
}
.cf-card.warn {
  border-color: var(--brand);
}
/* Also a direct child of .cf-card, so it carries its own inset for the same reason. */
.cf-note {
  font: 500 12.5px var(--font);
  color: var(--muted);
  margin: 0;
  padding: 2px 15px 14px;
}

/* ── The privacy qualification marker ───────────────────────────────────────────────────────────
   An asterisk on the home page's GENERAL privacy claims, carrying the sentence that qualifies them.
   The catalogue is going to hold extensions whose registry does not offer the shield, so a blanket
   "privacy included" stops being unconditionally true before a TLD has been chosen.

   ⚠ NO JAVASCRIPT, AND NOT A title= ATTRIBUTE. wwwroot carries no JS and this must not be the first.
   A title tooltip appears on hover only - it is invisible to touch and to keyboard users, and this
   text is a qualification on a claim rather than a decoration, so "most people can read it" is not
   the bar. Three routes to it, all without script:

     - MOUSE      :hover on the marker
     - KEYBOARD   the marker is tabbable, so :focus / :focus-within shows it
     - TOUCH      tapping a tabbable element focuses it, so the same rule fires
     - SCREEN     the text is ALWAYS in the DOM and in the accessibility tree - it is clipped, never
       READERS    display:none - so it is announced inline with the claim whether or not it is shown

   The last one is why .qual-text uses the clip technique rather than display:none or visibility:
   hidden. Both of those remove the element from the accessibility tree, which would make the
   qualification invisible to exactly the users least able to discover a tooltip. */
.qual {
  position: relative;
  display: inline;
  cursor: help;
}

.qual-mark {
  font-weight: 700;
  /* Nudged up so the asterisk reads as a reference mark rather than as punctuation in the sentence. */
  vertical-align: super;
  font-size: .78em;
  line-height: 0;
}

.qual:focus { outline: 2px solid currentColor; outline-offset: 2px; border-radius: 3px; }

.qual-text {
  /* Clipped, not hidden: still rendered, still in the accessibility tree, still announced. */
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.qual:hover .qual-text,
.qual:focus .qual-text,
.qual:focus-within .qual-text {
  /* Promoted from clipped to a bubble. Every property the clip set has to be undone explicitly -
     leaving width:1px behind is how a tooltip renders as a one-character-wide column. */
  position: absolute;
  z-index: 20;
  left: 0;
  top: calc(100% + 6px);
  width: max-content;
  max-width: min(320px, calc(100vw - 32px));
  height: auto;
  padding: 8px 10px;
  overflow: visible;
  clip-path: none;
  white-space: normal;

  font-size: 12.5px;
  font-weight: 500;
  line-height: 1.45;

  /* ⚠ THEME TOKENS, NOT LITERALS. This was #fff on #1f2937 - a COLD grey chip on a warm palette,
     and fixed in both themes, so it read as pasted in from another site and would have stayed dark
     text-on-dark in dark mode.

     --ink and --surface are swapped by :root[data-theme="dark"], so using them INVERTED gives a
     tooltip that is always the opposite of the page it sits on: dark chip on the light theme, light
     chip on the dark one, without a media query or a second rule to keep in sync. */
  color: var(--surface);
  background: var(--ink);
  border-radius: var(--r-input);

  /* The theme swaps this for a 1px ring on dark, where it prefers borders to shadows. */
  box-shadow: var(--shadow-card);
}
