/* 722web component library.
 *
 * Every value here is a token from tokens.css. If a component needs a value
 * that is not a token, the token is added there first.
 *
 * Components: app shell, header, panel, table, button, badge, field, dialog,
 * banner, empty state.
 */

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

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

body {
  margin: 0;
  font-family: var(--font-sans);
  font-size: var(--text-base);
  line-height: var(--leading-normal);
  color: var(--color-text);
  background: var(--color-canvas);
  -webkit-font-smoothing: antialiased;
}

h1,
h2,
h3,
h4 {
  margin: 0;
  font-family: var(--font-heading);
  font-weight: var(--weight-semibold);
  line-height: var(--leading-tight);
  letter-spacing: -0.01em;
}

h1 {
  font-size: var(--text-2xl);
}
h2 {
  font-size: var(--text-xl);
}
h3 {
  font-size: var(--text-lg);
}

p {
  margin: 0 0 var(--space-3);
}

a {
  color: var(--color-accent);
  text-decoration: none;
}

a:hover {
  text-decoration: underline;
}

:focus-visible {
  outline: 2px solid var(--color-focus-ring);
  outline-offset: 2px;
}

/* --- App shell --------------------------------------------------------- */
.app-header {
  position: sticky;
  top: 0;
  z-index: 20;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  height: var(--header-height);
  padding: 0 var(--space-5);
  background: var(--color-surface);
  border-bottom: 1px solid var(--color-border);
}

.app-header__brand {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  font-size: var(--text-md);
  font-weight: var(--weight-semibold);
  color: var(--color-text);
  letter-spacing: -0.01em;
}

.app-header__brand:hover {
  text-decoration: none;
}

/* 2.256.0. An IT Service Org's logo beside 722web's, for the org's own
   people (core.context_processors: org_logo_url). */
.app-header__org-logo {
  display: block;
  width: auto;
  height: auto;
  max-height: 32px;
  max-width: 140px;
  padding-left: var(--space-3);
  border-left: 1px solid var(--color-border);
  object-fit: contain;
}

/* Retained for anything still asking for it; the mark itself is an image now. */
.app-header__mark {
  display: none;
}

.app-header__nav {
  display: flex;
  align-items: center;
  gap: var(--space-4);
}

.app-header__nav a {
  color: var(--color-text-muted);
  font-weight: var(--weight-medium);
}

.app-header__nav a:hover,
.app-header__nav a[aria-current="page"] {
  color: var(--color-text);
  text-decoration: none;
}

.app-header__identity {
  color: var(--color-text-muted);
  font-size: var(--text-sm);
}

/* 2.177.0. A support agent's sign-out is a POST, so it is a form in the
   header; the button reads as the link beside it. */
.app-header__form { display: inline; margin: 0; }
.app-header__form .btn { padding: 0; font: inherit; color: var(--color-text-muted); }
.app-header__form .btn:hover { color: var(--color-text); }

.app-main {
  max-width: var(--content-max);
  margin: 0 auto;
  padding: var(--space-6) var(--space-5) var(--space-8);
}

/* The three landing pages. Full width rather than the reading column: these
   are dashboards, and a table of sites or customers gains from the room where
   a paragraph would not. The padding stays, so content never touches the edge
   of the window. */
.app-main--wide {
  max-width: none;
}

/* 2.231.0. "Site: name" above the heading of every page under the site menu,
   so whoever is reading or editing knows whose it is (Kelly's picture). */
.site-context {
  margin: 0 0 var(--space-3);
  font-size: var(--text-md);
  line-height: 1.3;
  color: var(--color-text);
  overflow-wrap: anywhere;
}

.site-context strong { font-weight: var(--weight-semibold); }

.page-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-4);
  margin-bottom: var(--space-5);
}

.page-head__subtitle {
  margin: var(--space-1) 0 0;
  color: var(--color-text-muted);
}

/* More than one action beside a heading. Wraps rather than shrinking the
   buttons, so a narrow screen stacks them instead of clipping the labels. */
.page-head__actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
  flex-shrink: 0;
}

/* --- Panel ------------------------------------------------------------- */
.panel {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-sm);
}

.panel__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  padding: var(--space-4) var(--space-5);
  border-bottom: 1px solid var(--color-border);
}

.panel__title {
  font-size: var(--text-md);
  font-weight: var(--weight-semibold);
}

/* 2.223.0. A title and its badge, kept together on the left of a head
   that also has a button. */
.panel__head-group {
  display: flex;
  align-items: center;
  gap: var(--space-3);
}

/* 2.223.0. Billing setup: when it was last tested, and the time toggle. */
.billing-last-test {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  flex-wrap: wrap;
}

.billing-last-test .field__help { margin: 0; }

/* A setting's name is one long word; on a phone it breaks rather than
   pushing the table past the panel. */
.billing-steps td { overflow-wrap: anywhere; }

.panel__body {
  padding: var(--space-5);
}

/* --- Table ------------------------------------------------------------- */
.table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--text-base);
}

.table th {
  padding: var(--space-3) var(--space-5);
  text-align: left;
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--color-text-muted);
  background: var(--color-surface-sunken);
  border-bottom: 1px solid var(--color-border);
}

.table td {
  padding: var(--space-3) var(--space-5);
  border-bottom: 1px solid var(--color-border);
  vertical-align: middle;
}

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

.table tbody tr:hover {
  background: var(--color-surface-sunken);
}

.table__actions {
  display: flex;
  justify-content: flex-end;
  gap: var(--space-2);
  opacity: 0;
  transition: opacity var(--transition-fast);
}

.table tbody tr:hover .table__actions,
.table tbody tr:focus-within .table__actions {
  opacity: 1;
}

/* --- Button ------------------------------------------------------------ */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-4);
  min-height: 34px;
  font-family: inherit;
  font-size: var(--text-base);
  font-weight: var(--weight-medium);
  line-height: 1;
  border-radius: var(--radius-sm);
  border: 1px solid transparent;
  cursor: pointer;
  transition: background var(--transition-fast), border-color var(--transition-fast);
}

.btn:hover {
  text-decoration: none;
}

.btn--primary {
  background: var(--color-button);
  border-color: var(--color-button);
  color: var(--color-on-accent);
}

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

.btn--secondary {
  background: var(--color-surface);
  border-color: var(--color-border-strong);
  color: var(--color-text);
}

.btn--secondary:hover {
  background: var(--color-surface-sunken);
}

/* 2.230.0. A block button's own color (Kelly): Button Color fills a Filled
   (Solid) button, its text in the ink that reads on it; Outline Color draws
   an Outlined one's edge and words. Set on the button by
   `block_extras.button_paint`, which also adds the class; the `[style]` and
   `.btn` raise these over the drawer's and a colored bar's link rules, which
   would otherwise repaint a folded button's words. A color the button's Aa
   gives its text is in the same `style` and still wins. */
.btn.btn--primary.btn--own-color[style] {
  background: var(--btn-color);
  border-color: var(--btn-color);
  color: var(--btn-ink, var(--color-text-inverse));
}
.btn.btn--primary.btn--own-color[style]:hover {
  background: color-mix(in srgb, var(--btn-color) 85%, var(--color-text));
  border-color: color-mix(in srgb, var(--btn-color) 85%, var(--color-text));
}
.btn.btn--secondary.btn--own-color[style] {
  border-color: var(--btn-color);
  color: var(--btn-color);
}
.btn.btn--secondary.btn--own-color[style]:hover {
  background: color-mix(in srgb, var(--btn-color) 10%, transparent);
}

.btn--danger {
  background: var(--color-danger);
  border-color: var(--color-danger);
  color: var(--color-text-inverse);
}

/* Removing a site from Production or QA is reversible -- publishing again puts
   it back -- so it is not the same weight as the delete beside it. Amber says
   "this changes what the public sees" without saying "this is permanent". */
.btn--warning {
  background: var(--color-warning);
  border-color: var(--color-warning);
  color: var(--color-text-inverse);
}

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

.btn--danger:hover {
  background: var(--color-danger-hover);
}

.btn--icon {
  padding: var(--space-2);
  min-width: 30px;
  min-height: 30px;
}

/* 2.256.0. A button that reads as a link: a secondary action beside a form
   ("Make a new link"), where a full button would compete with Save. */
.btn--link {
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  font-size: var(--text-sm);
  color: var(--color-accent);
  cursor: pointer;
}

.btn--link:hover { text-decoration: underline; }

/* 2.256.0. A sign-up link to copy: the address, read-only, and Copy. */
.copy-field {
  display: flex;
  gap: var(--space-2);
  align-items: center;
  margin: var(--space-2) 0;
}

.copy-field__input {
  flex: 1;
  min-width: 0;
  font-family: var(--font-mono, monospace);
  font-size: var(--text-sm);
}

.copy-field--compact .copy-field__input { font-size: var(--text-xs); }
.copy-field--compact .btn { padding-top: 2px; padding-bottom: 2px; }

.copy-field__renew { margin: 0 0 var(--space-4); }

.org-signup__settings { max-width: 520px; }

.btn--block {
  width: 100%;
}

.btn[disabled] {
  opacity: 0.55;
  cursor: not-allowed;
}

/* --- Badge ------------------------------------------------------------- */
.badge {
  display: inline-flex;
  align-items: center;
  padding: 2px var(--space-2);
  border-radius: 999px;
  font-size: var(--text-xs);
  font-weight: var(--weight-medium);
  letter-spacing: 0.01em;
}

.badge--neutral {
  background: var(--color-surface-sunken);
  color: var(--color-text-muted);
}
.badge--accent {
  background: var(--color-accent-subtle);
  color: var(--color-accent);
}
.badge--success {
  background: var(--color-success-subtle);
  color: var(--color-success);
}
.badge--warning {
  background: var(--color-warning-subtle);
  color: var(--color-warning);
}
.badge--danger {
  background: var(--color-danger-subtle);
  color: var(--color-danger);
}

/* --- Form fields ------------------------------------------------------- */
.field {
  margin-bottom: var(--space-4);
}

.field__label {
  display: block;
  margin-bottom: var(--space-2);
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  color: var(--color-text);
}

/* The list is enumerated rather than `.field input`, so that checkboxes,
   radios and colour swatches keep their native box. Every type a form block
   can produce has to appear here: a `kind` this list forgets renders as a raw
   browser input -- narrower, shorter, and sitting a few pixels off the one
   beside it. That is what `tel` and `date` did: they have been Form block
   `kind` choices and absent from this list in every tarball back to 2.139.0,
   so a telephone box has always sat lower than the email box beside it. */
.field__control,
.field input[type="text"],
.field input[type="email"],
.field input[type="password"],
.field input[type="tel"],
.field input[type="date"],
.field select,
.field textarea {
  width: 100%;
  padding: var(--space-2) var(--space-3);
  min-height: 36px;
  font-family: inherit;
  font-size: var(--text-base);
  color: var(--color-text);
  background: var(--color-surface);
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-sm);
  transition: border-color var(--transition-fast);
}

.field input:focus,
.field select:focus,
.field textarea:focus {
  border-color: var(--color-accent);
  outline: 2px solid var(--color-focus-ring);
  outline-offset: 0;
}

.field__error {
  margin-top: var(--space-2);
  font-size: var(--text-sm);
  color: var(--color-danger);
}

/* --- Alert / banner ---------------------------------------------------- */
.alert {
  padding: var(--space-3) var(--space-4);
  border-radius: var(--radius-sm);
  font-size: var(--text-base);
  margin-bottom: var(--space-4);
}

.alert--danger {
  background: var(--color-danger-subtle);
  color: var(--color-danger);
}
.alert--warning {
  background: var(--color-warning-subtle);
  color: var(--color-warning);
}
.alert--info {
  background: var(--color-accent-subtle);
  color: var(--color-accent);
}

.testing-banner {
  padding: var(--space-2) var(--space-5);
  background: var(--color-warning-subtle);
  color: var(--color-warning);
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  text-align: center;
  border-bottom: 1px solid var(--color-border);
}

/* --- Empty state ------------------------------------------------------- */
.empty-state {
  padding: var(--space-7) var(--space-5);
  text-align: center;
  color: var(--color-text-muted);
}

.empty-state__title {
  margin-bottom: var(--space-2);
  font-weight: var(--weight-semibold);
  color: var(--color-text);
}

/* --- Auth screens ------------------------------------------------------ */
.auth {
  display: flex;
  /* 2.256.0. Kelly: "raise the login form a bit ... on a big screen it feels
     just a tad low with all the toolbars". Placed from the top rather than
     centred: a fixed share of the window above it, never less than the
     padding, so a short window still starts it near the top. */
  align-items: flex-start;
  justify-content: center;
  min-height: 100vh;
  padding: var(--space-5);
  padding-top: max(var(--space-5), 12vh);
}

/* 2.256.0. Sign-up: the platform's logo, and an IT Service Org's logo beside
   it, never instead of it (Kelly: "Dual branding"). */
.auth__brands {
  display: flex;
  align-items: center;
  gap: var(--space-3);
}

.auth__brands-divider {
  width: 1px;
  height: 32px;
  background: var(--color-border);
}

.auth__org-logo {
  display: block;
  width: auto;
  height: auto;
  max-height: 40px;
  max-width: 160px;
  object-fit: contain;
}

.auth__brand-with {
  font-size: var(--text-sm);
  color: var(--color-text-muted);
}

.auth__title {
  margin: 0 0 var(--space-4);
  font-size: var(--text-lg);
  font-weight: var(--weight-semibold);
}

.signup__agree {
  align-items: flex-start;
  font-size: var(--text-sm);
}

.signup__agree input {
  margin-top: 0.2em;
}

.signup__note {
  margin-top: var(--space-3);
  text-align: center;
}

/* 2.257.0. An IT Service Org's sign-up: a longer form, in groups, with
   short fields in pairs that stack on a phone. */
.auth__card--form { max-width: 600px; }

.signup__group {
  margin: 0 0 var(--space-4);
  padding: 0;
  border: 0;
}

.signup__group legend {
  margin-bottom: var(--space-2);
  padding: 0;
  font-weight: var(--weight-semibold);
}

.signup__pair {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-3);
}

@media (max-width: 520px) {
  .signup__pair { grid-template-columns: 1fr; }
}

.field__optional {
  font-weight: normal;
  color: var(--color-text-muted);
}

.auth__card {
  width: 100%;
  max-width: 380px;
}

.auth__brand {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-2);
  margin-bottom: var(--space-5);
  text-align: center;
}

.auth__brand-name {
  font-size: var(--text-lg);
  font-weight: var(--weight-semibold);
  letter-spacing: -0.01em;
}

.auth__meta {
  margin-top: var(--space-4);
  text-align: center;
  font-size: var(--text-xs);
  color: var(--color-text-muted);
}

/* --- Footer ------------------------------------------------------------ */
/* Fixed to the viewport, so it is there on a short screen as well as a long
   one. body reserves its height below, so it never covers the last row of a
   table — a footer that hides content is worse than no footer. */
.app-footer {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 60;
  display: flex;
  justify-content: center;
  align-items: baseline;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-4);
  background: var(--color-surface);
  border-top: 1px solid var(--color-border);
  font-size: var(--text-xs);
  letter-spacing: 0.02em;
  color: var(--color-text-muted);
}

/* The wordmark, quieter than in the header: this is a signature, not a title. */
.app-footer__brand {
  font-weight: 600;
  color: var(--color-text);
}


/* 2.207.0. The Terms of Service and Privacy Policy links: the footer's own
   muted ink, underlined so they read as links. With them the footer is wider
   than a phone, so it wraps whole items onto a second line rather than
   squeezing each one into a column of words; two lines still fit in the
   room the body reserves below. */
.app-footer {
  flex-wrap: wrap;
  row-gap: 0;
}

.app-footer__link {
  color: inherit;
  text-decoration: underline;
}

body {
  padding-bottom: calc(var(--space-7) + var(--space-2));
}

/* Printing a fixed footer repeats it on every page. */
@media print {
  .app-footer { position: static; }
  body { padding-bottom: 0; }
}

/* --- Single sign-on ---------------------------------------------------- */
.sso-list {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.sso-divider {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  margin: var(--space-4) 0;
  color: var(--color-text-muted);
  font-size: var(--text-xs);
  text-transform: uppercase;
  letter-spacing: 0.06em;
}

.sso-divider::before,
.sso-divider::after {
  content: "";
  flex: 1;
  height: 1px;
  background: var(--color-border);
}

/* --- Sign-in by code and passkeys (2.241.0) ---------------------------- */
.signin-again,
.auth__alt {
  margin: var(--space-3) 0 0;
  text-align: center;
  font-size: var(--text-sm);
}

/* Reads as the link it is beside on the password form. */
.signin-again__button {
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  color: var(--color-accent);
  cursor: pointer;
}

.signin-again__button:hover { text-decoration: underline; }

.auth__card--wide { max-width: 520px; }

/* 2.331.0. Signing in on a phone or tablet (Kelly, 2026-10-24: "simple and
   seamless"). Text under 16px makes iOS zoom the page as the box is tapped,
   and buttons 20 to 34px tall are hard to hit with a thumb: 16px and 44px
   where the pointer is a finger. A mouse keeps the sizes it had. */
@media (pointer: coarse) {
  .auth .field input[type="text"],
  .auth .field input[type="email"],
  .auth .field input[type="password"],
  .auth .field input[type="tel"] {
    font-size: 16px;
    min-height: 44px;
  }
  .auth .btn { min-height: 44px; }
  .auth .signin-again__button { min-height: 44px; padding: 0 var(--space-2); }
}

.account__title {
  margin: 0 0 var(--space-2);
  font-size: var(--text-lg);
}

.account__heading {
  margin: var(--space-5) 0 var(--space-1);
  font-size: var(--text-base);
}

.account__passkeys {
  margin: var(--space-3) 0;
  padding: 0;
  list-style: none;
  border-top: 1px solid var(--color-border);
}

.account__passkey {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2) var(--space-3);
  padding: var(--space-2) 0;
  border-bottom: 1px solid var(--color-border);
}

.account__passkey-name { font-weight: var(--weight-medium); }

.account__passkey-meta {
  flex: 1;
  color: var(--color-text-muted);
  font-size: var(--text-sm);
}

.account__passkey form { margin: 0; }

.account__add { margin-top: var(--space-4); }

/* --- Table caption ----------------------------------------------------- */
.table-caption {
  padding: var(--space-3) var(--space-5);
  font-size: var(--text-sm);
  font-weight: var(--weight-semibold);
  color: var(--color-text-muted);
  background: var(--color-surface);
  border-bottom: 1px solid var(--color-border);
}

.table__secondary {
  margin-top: 2px;
  font-size: var(--text-xs);
  color: var(--color-text-muted);
}

/* --- Dialog ------------------------------------------------------------ */
.dialog {
  width: min(560px, calc(100vw - var(--space-6)));
  padding: 0;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  background: var(--color-surface);
  color: var(--color-text);
}

.dialog::backdrop {
  background: rgba(22, 32, 44, 0.45);
}

.dialog__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  padding: var(--space-4) var(--space-5);
  border-bottom: 1px solid var(--color-border);
}

.dialog__title {
  font-size: var(--text-md);
  font-weight: var(--weight-semibold);
}

.dialog__body {
  padding: var(--space-5);
  max-height: 60vh;
  overflow-y: auto;
}

.dialog__foot {
  display: flex;
  /* 2.419.0. The New site window's four buttons wrap rather than spill on
     a narrow screen. */
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: var(--space-2);
  padding: var(--space-4) var(--space-5);
  border-top: 1px solid var(--color-border);
  background: var(--color-surface-sunken);
  border-radius: 0 0 var(--radius-lg) var(--radius-lg);
}

.field--inline {
  display: flex;
  align-items: center;
  gap: var(--space-2);
}

.field--inline .field__label {
  margin-bottom: 0;
}

.field--inline input[type="checkbox"] {
  width: auto;
  min-height: 0;
}

.field__help {
  margin-top: var(--space-2);
  font-size: var(--text-xs);
  color: var(--color-text-muted);
}

/* --- Stat grid --------------------------------------------------------- */
.stat-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  gap: var(--space-4);
}

.stat {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  padding: var(--space-5);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-sm);
  color: var(--color-text);
}

a.stat:hover {
  border-color: var(--color-accent);
  text-decoration: none;
}

.stat__value {
  font-size: var(--text-2xl);
  font-weight: var(--weight-semibold);
  letter-spacing: -0.02em;
}

.stat__label {
  font-size: var(--text-xs);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--color-text-muted);
}

/* --- Misc -------------------------------------------------------------- */
.table__actions--always {
  opacity: 1;
}

.inline-form {
  display: inline;
}

.link-button {
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  color: var(--color-accent);
  cursor: pointer;
  text-decoration: underline;
}

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

.field textarea {
  min-height: 72px;
  resize: vertical;
}

/* A box for markup rather than for prose. Monospace, because a customer is
   reading their own tags back and looking for the one the server refused, and
   proportional type hides the difference between a hyphen and an underscore in
   an embed URL. */
.field__code {
  min-height: 9rem;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: var(--text-sm);
  line-height: 1.5;
  white-space: pre;
  overflow-wrap: normal;
  overflow-x: auto;
  tab-size: 2;
}

/* --- Publish flow ------------------------------------------------------- */
.publish-flow {
  display: grid;
  gap: var(--space-4);
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  margin-bottom: var(--space-5);
}

.publish-stage__meta {
  color: var(--color-text-muted);
  font-size: var(--text-sm);
}

/* 2.390.0. Kelly: a big green LIVE above the date production last went live,
   a big OFF LINE when it is not. */
/* 2.395.0. A site's own sign-in: its logo, or its name in its heading font. */
.auth__site-logo { display: block; max-height: 72px; max-width: 240px; margin: 0 auto; }
.auth__site-name {
  display: block;
  font-family: var(--font-heading, var(--font-sans));
  font-size: var(--text-xl);
  font-weight: 700;
  color: var(--color-text);
  text-align: center;
}

.publish-state {
  display: inline-block;
  align-self: flex-start;
  margin: 0 0 var(--space-2);
  padding: var(--space-1) var(--space-4);
  border-radius: var(--radius-sm);
  font-size: var(--text-xl);
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}
.publish-state--live { background: var(--color-success); color: var(--color-text-inverse); }
.publish-state--off { background: var(--color-text-muted); color: var(--color-text-inverse); }

/* 2.390.0. Production Publish History, closed until clicked. */
.publish-history { margin-bottom: var(--space-5); }
.publish-history > .publish-history__summary { cursor: pointer; list-style: none; }
.publish-history > .publish-history__summary::-webkit-details-marker { display: none; }
.publish-history > .publish-history__summary::before {
  content: "\25B8";
  margin-right: var(--space-2);
  color: var(--color-text-muted);
}
.publish-history[open] > .publish-history__summary::before { content: "\25BE"; }
.publish-history:not([open]) > .publish-history__summary { border-bottom: 0; }
.publish-history__summary .panel__title { margin-right: auto; }
.publish-history__count { color: var(--color-text-muted); font-size: var(--text-sm); }
.publish-history__tools { display: flex; justify-content: flex-end; padding: var(--space-3) var(--space-5) 0; }

/* 2.267.0. Kelly: "production should look just like QA". The QA page's
   notice is a label in the corner rather than a strip at the top: in the
   page's flow it pushed the page down while a nav bar kept visible sat at the
   top of the window over it, so QA showed an empty band of the bar's colour
   under the bar that production does not have. Out of the flow, QA is laid
   out as production is. It takes no clicks, so nothing under it is lost. */
.qa-banner {
  position: fixed;
  left: var(--space-3);
  bottom: var(--space-3);
  z-index: 70;
  max-width: calc(100vw - 2 * var(--space-3));
  margin: 0;
  padding: var(--space-1) var(--space-3);
  border: 1px solid var(--color-warning);
  border-radius: var(--radius-md);
  background: var(--color-warning-subtle);
  box-shadow: var(--shadow-sm);
  color: var(--color-warning);
  font-size: var(--text-xs);
  font-weight: var(--weight-medium);
  pointer-events: none;
  opacity: 0.92;
}

/* --- Media library ------------------------------------------------------ */
.media-grid {
  display: grid;
  gap: var(--space-4);
  grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
}

.media-item {
  position: relative;
  margin: 0;
  padding: var(--space-2);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  background: var(--color-surface);
}

.media-item img {
  width: 100%;
  height: 120px;
  object-fit: contain;
  background: var(--color-surface-sunken);
  border-radius: var(--radius-sm);
}

.media-item__name {
  display: block;
  margin-top: var(--space-2);
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  overflow-wrap: anywhere;
}

.media-item__url {
  display: block;
  font-size: var(--text-xs);
  color: var(--color-text-muted);
  overflow-wrap: anywhere;
}

.media-item form {
  position: absolute;
  top: var(--space-2);
  right: var(--space-2);
}

.palette-grid {
  display: grid;
  gap: var(--space-4);
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
}

/* --- Campaigns ---------------------------------------------------------- */
.campaign-body {
  margin: 0;
  padding: var(--space-4);
  background: var(--color-surface-sunken);
  border-radius: var(--radius-sm);
  font-family: var(--font-mono);
  font-size: var(--text-sm);
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

/* --- Forms screen ------------------------------------------------------- */
/* 2.235.0. Kelly: the forms by heading "on the left in a scrollable list",
   the chosen one's submissions beside it. One column on a phone. */
/* 2.400.0. A form made on the Forms screen: its fields and steps as rows,
   each with its boxes in a row that wraps, and its Up, Down and Remove at
   the end. A step's row is shaded, as it starts a new page of the form. */
.saved-form__rows { list-style: none; margin: 0 0 var(--space-4); padding: 0; }
.saved-form__row {
  display: flex;
  gap: var(--space-3);
  align-items: flex-end;
  padding: var(--space-3) 0;
  border-bottom: 1px solid var(--color-border);
}
.saved-form__row--step {
  padding-inline: var(--space-3);
  border-radius: var(--radius-sm);
  background: var(--color-surface-sunken);
}
.saved-form__cells {
  display: flex;
  flex: 1;
  flex-wrap: wrap;
  gap: var(--space-2) var(--space-3);
  align-items: flex-end;
}
.saved-form__cells .field { flex: 1 1 10rem; margin: 0; }
.saved-form__moves { display: flex; gap: var(--space-1); }
.saved-form__add { display: flex; flex-wrap: wrap; gap: var(--space-2); }
.forms-inbox {
  display: grid;
  grid-template-columns: minmax(12rem, 18rem) minmax(0, 1fr);
  gap: var(--space-4);
  align-items: start;
}
.forms-inbox__list {
  max-height: 60vh;
  overflow-y: auto;
  margin: 0;
  padding: var(--space-2);
  list-style: none;
}
.forms-inbox__form {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius-sm);
  color: var(--color-text);
  text-decoration: none;
}
.forms-inbox__form:hover { background: var(--color-surface-sunken); text-decoration: none; }
.forms-inbox__form--chosen {
  background: var(--color-surface-sunken);
  font-weight: var(--weight-semibold);
}
.forms-inbox__name { min-width: 0; overflow-wrap: anywhere; }
.forms-inbox__count {
  flex-shrink: 0;
  font-size: var(--text-sm);
  color: var(--color-text-muted);
}
.forms-inbox__count .badge { margin-left: var(--space-1); }
@media (max-width: 48rem) {
  .forms-inbox { grid-template-columns: minmax(0, 1fr); }
}

/* --- Forum -------------------------------------------------------------- */
.forum-crumbs {
  margin-bottom: var(--space-4);
  font-size: var(--text-sm);
  color: var(--color-text-muted);
}

.forum-posts {
  list-style: none;
  margin: 0 0 var(--space-5);
  padding: 0;
}

.forum-post {
  padding: var(--space-4);
  margin-bottom: var(--space-3);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
}

.forum-post__meta {
  display: flex;
  justify-content: space-between;
  gap: var(--space-3);
  margin-bottom: var(--space-2);
  font-size: var(--text-sm);
  color: var(--color-text-muted);
}


/* --- Wordmark ------------------------------------------------------------ */
/* 2.366.0. The ArtistryBlocks logo, mark and name on one line: Kelly's own
   file, an image (static/img/logo.png, 707x120). Sized by its height; the
   width follows. It was the "722web.com" lettering set in the interface font. */
.wordmark {
  display: block;
  width: auto;
  height: 30px;
  flex: none;
}

.wordmark--large { height: 44px; }
.wordmark--small { height: 22px; }

/* The console's "Platform", beside the logo. */
.app-header__tag {
  padding: 2px var(--space-2);
  border: 1px solid var(--color-border);
  border-radius: 999px;
  font-size: var(--text-xs);
  font-weight: var(--weight-medium);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--color-text-muted);
}

/* 2.366.0. The stacked logo at the top of a sign-in or notice page, and the
   word under it ("Platform", "Support"). */
.auth__logo {
  display: block;
  width: 200px;
  height: auto;
}

.auth__logo--wide {
  width: auto;
  height: 36px;
}

.auth__brand-tag {
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-text-muted);
}

.auth__brand {
  margin-bottom: var(--space-5);
  text-align: center;
}

/* --- Template preview ---------------------------------------------------- */
.preview-pages {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin-bottom: var(--space-4);
}

/* A frame, so it reads as a preview of a site rather than as part of the
   console. The chrome is decorative and hidden from assistive technology. */
.preview-frame {
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  overflow: hidden;
  background: var(--color-surface);
}

.preview-frame__chrome {
  display: flex;
  gap: 6px;
  padding: var(--space-3) var(--space-4);
  background: var(--color-surface-sunken);
  border-bottom: 1px solid var(--color-border);
}

.preview-frame__chrome span {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: var(--color-border-strong);
}

.preview-frame__page {
  /* The preview is a document in its own right; the console's type should not
     leak into it. */
  container-type: inline-size;
}

/* Two ways to supply a key, side by side so the choice is visible at once. */
.key-options {
  display: grid;
  gap: var(--space-5);
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  margin-top: var(--space-4);
}

.key-options h3 {
  margin: 0 0 var(--space-2);
  font-size: var(--text-base);
}

/* --- Template preview stage ---------------------------------------------- */
/* The preview is a real page in an iframe, so the console's stylesheet cannot
   leak into something meant to look like a customer's site, and the template's
   palette can override the tokens without affecting the page around it. */
.preview-stage {
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  overflow: hidden;
  background: var(--color-surface);
  box-shadow: var(--shadow-sm);
}

.preview-stage__chrome {
  display: flex;
  gap: 6px;
  padding: var(--space-3) var(--space-4);
  background: var(--color-surface-sunken);
  border-bottom: 1px solid var(--color-border);
}

.preview-stage__chrome span {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: var(--color-border-strong);
}

.preview-stage__frame {
  display: block;
  width: 100%;
  height: 78vh;
  min-height: 520px;
  border: 0;
  background: var(--color-surface);
}

/* --- Template tiles ------------------------------------------------------ */
.template-grid {
  display: grid;
  gap: var(--space-4);
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  padding: var(--space-4);
}

.template-tile {
  display: flex;
  flex-direction: column;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  overflow: hidden;
  transition: box-shadow 120ms ease, border-color 120ms ease;
}

.template-tile:hover,
.template-tile:focus-within {
  border-color: var(--color-accent);
  box-shadow: var(--shadow-md);
}

/* The thumbnail is the page itself, scaled — never a screenshot, which would
   drift from what the template actually produces. */
.template-tile__thumb {
  position: relative;
  height: 200px;
  overflow: hidden;
  border-bottom: 1px solid var(--color-border);
  background: var(--color-surface-sunken);
}

/* 2.211.2. A laptop's screen, shrunk to a quarter: four times the tile's
   width, so wider than the 48rem breakpoint at the narrowest tile (280px,
   1120px framed), and 800px tall. The frame was 250% of the tile and 500px
   tall. Under a 307px tile that is under the breakpoint, so the tile showed
   the phone layout; and in a 328px tile, 814x500, Media -- Bold's heading
   took two lines and its words ended 66px into its picture, which takes the
   lower 62% of a hero as tall as the screen. Framed width times scale is the
   tile's width, and 800px times 0.25 is the thumbnail's 200px, so the frame
   fills it exactly. */
.template-tile__thumb iframe {
  width: 400%;
  height: 800px;
  border: 0;
  transform: scale(0.25);
  transform-origin: top left;
  /* Decorative here: the whole tile is the link, and a frame that swallowed
     clicks would make the tile look interactive without being so. */
  pointer-events: none;
}

/* Covers the frame so the tile is one target rather than several. */
.template-tile__link {
  position: absolute;
  inset: 0;
  z-index: 1;
}

.template-tile__body {
  flex: 1;
  padding: var(--space-4);
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.template-tile__name {
  font-weight: 600;
  color: var(--color-text);
}

.template-tile__meta {
  font-size: var(--text-sm);
  color: var(--color-text-muted);
}

.template-tile__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin-top: auto;
  padding-top: var(--space-2);
}

/* --- Background job progress --------------------------------------------- */
.job {
  display: flex;
  align-items: flex-start;
  gap: var(--space-4);
}

.job__spinner {
  flex: none;
  width: 28px;
  height: 28px;
  border: 3px solid var(--color-border);
  border-top-color: var(--color-accent);
  border-radius: 50%;
  animation: job-spin 900ms linear infinite;
}

/* Finished, one way or the other: a spinner still turning after the answer has
   arrived says the opposite of the truth. */
[data-job-state="done"] .job__spinner {
  border-color: var(--color-success);
  animation: none;
}

[data-job-state="failed"] .job__spinner {
  border-color: var(--color-danger);
  animation: none;
}

.job__step {
  font-weight: 600;
  color: var(--color-text);
}

.job__detail {
  margin-top: var(--space-1);
  font-size: var(--text-sm);
  color: var(--color-text-muted);
}

.job__actions {
  margin-top: var(--space-4);
}

@keyframes job-spin {
  to { transform: rotate(360deg); }
}

/* Respect a preference for less movement: a spinner is decoration, and the
   step text already says what is happening. */
@media (prefers-reduced-motion: reduce) {
  .job__spinner { animation: none; }
}

/* --- Navbar submenu ------------------------------------------------------ */
/* Built on <details>, so it opens by click and by keyboard and closes on
   Escape without any JavaScript — a published site carries no scripts of its
   own, so a scripted menu would never open. */
.navbar__item--has-menu {
  position: relative;
}

.navbar__dropdown > summary {
  cursor: pointer;
  list-style: none;
  display: inline-flex;
  align-items: center;
  gap: 0.35em;
}

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

/* The affordance, drawn rather than an image so it inherits the text colour. */
.navbar__dropdown > summary::after {
  content: "";
  width: 0.4em;
  height: 0.4em;
  border-right: 2px solid currentColor;
  border-bottom: 2px solid currentColor;
  transform: translateY(-0.15em) rotate(45deg);
  transition: transform 120ms ease;
}

.navbar__dropdown[open] > summary::after {
  transform: translateY(0.1em) rotate(-135deg);
}

.navbar__submenu {
  position: absolute;
  z-index: 40;
  min-width: 200px;
  margin: var(--space-2) 0 0;
  padding: var(--space-2);
  list-style: none;
  /* 2.229.0. The bar's Dropdown background when it has one (Kelly: "Some
     editors might want the drop down background color to be different"),
     with the ink that reads on it; the theme's surface otherwise, as until
     now. The phone's drawer paints its own levels. */
  background: var(--nav-dropdown-bg, var(--color-surface));
  color: var(--nav-dropdown-text, currentColor);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-md);
}

.navbar__submenu a {
  display: block;
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius-sm);
  white-space: nowrap;
}

/* 2.229.0. On a Dropdown background the bar chose, its links take the ink
   that reads on it rather than the link colour, which was drawn for the
   theme's surface. A link given a colour of its own (its "Aa") keeps it. */
.navbar[style*="--nav-dropdown-bg"] .navbar__submenu a { color: inherit; }

.navbar__submenu a:hover,
.navbar__submenu a:focus {
  /* 2.229.0: a tint of the dropdown's own ink on a colour the bar chose. */
  background: var(--nav-dropdown-hover, var(--color-surface-sunken));
}

/* On a narrow screen a floating panel would run off the edge, so it becomes
   part of the flow instead. */
@media (max-width: 640px) {
  .navbar__submenu {
    position: static;
    box-shadow: none;
    border: 0;
    padding-left: var(--space-4);
  }
}


/* --- The mark ------------------------------------------------------------ */
/* Square by construction: 2.366.0's ArtistryBlocks mark was padded to a
   square on a transparent ground, so a square box cannot squash it. */
.mark {
  display: block;
  width: 40px;
  height: 40px;
  border-radius: var(--radius-sm);
  flex: none;
}

.mark--inline {
  width: 1.15em;
  height: 1.15em;
  margin-right: 0.4em;
  align-self: center;
}

.mark--large {
  width: 64px;
  height: 64px;
}

/* --- Section eyebrow ------------------------------------------------------ */
/* Says what a section is before the heading has to. Without it a designer
   stacks two headings to get the same effect. */
.section-eyebrow {
  margin: 0 0 var(--space-2);
  /* 2.202.0. The theme's eyebrow font, the body font unless it says. */
  font-family: var(--font-eyebrow, var(--font-sans));
  font-size: var(--text-sm);
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--color-text-muted);
}

/* 2.235.0. A section heading's horizontal alignment (Kelly), within the
   block's width: at either edge, in the middle, or in the middle of the
   left or the right half. Left is how a heading always sat. */
.section-heading-box--center { text-align: center; }
.section-heading-box--right { text-align: right; }
.section-heading-box--middle_left,
.section-heading-box--middle_right { width: 50%; text-align: center; }
.section-heading-box--middle_left { margin-right: auto; }
.section-heading-box--middle_right { margin-left: auto; }

/* --- A ghost button, for a second call to action -------------------------- */
/* Outlined rather than filled, so a hero can offer "call now" beside "enquire"
   without the two competing. */
.btn--ghost {
  background: transparent;
  color: currentColor;
  border: 1px solid currentColor;
}

.btn--ghost:hover,
.btn--ghost:focus {
  background: rgba(255, 255, 255, 0.12);
}

/* --- Form layout ---------------------------------------------------------- */
/* Two columns of fields, and every field on the same row lines up.

   The outer grid was always here, but each field laid its own label and input
   out in normal flow -- so "Email address" on one line and "Company or
   organisation name" wrapping to two put the two inputs beside each other
   eighteen pixels apart. Each field now spans two rows of the outer grid and
   takes them as a subgrid: labels share a row, inputs share the row under it,
   and the label row is as tall as the tallest label in it. */
.block-form__fields {
  display: grid;
  column-gap: var(--space-4);
  row-gap: var(--space-4);
  grid-template-columns: repeat(2, minmax(0, 1fr));
}

.block-form__fields > .field {
  display: grid;
  grid-row: span 2;
  grid-template-rows: subgrid;
  /* The gap between a label and its input, in one place rather than as a
     margin under the label: a margin is added to the row gap above, which is
     how the space between the words and the box came to differ from the space
     between one field and the next. */
  row-gap: var(--space-2);
  margin-bottom: 0;
}

.block-form__fields > .field > .field__label {
  margin-bottom: 0;
}

.block-form__fields .field--full {
  grid-column: 1 / -1;
}

/* Inputs beside the label rather than under it. The field stops spanning two
   rows and becomes two columns; the fields on a row are stretched to the same
   height by the outer grid, so inputs centred in them start level. */
.block-form--beside .block-form__fields > .field {
  grid-row: auto;
  grid-template-rows: auto;
  grid-template-columns: minmax(0, 7rem) minmax(0, 1fr);
  column-gap: var(--space-3);
  align-items: center;
}

/* A paragraph is taller than the line of text naming it, so it is the one
   control that reads wrongly centred. */
.block-form--beside .block-form__fields > .field:has(textarea) {
  align-items: start;
}

.block-form--beside .block-form__fields > .field:has(textarea) > .field__label {
  padding-top: calc(var(--space-2) + 1px);
}

/* 2.200.0. A group of choices -- Choose one, Tick boxes -- is a fieldset:
   the browser's frame taken off and its choices one under another. It spans
   the two rows a field takes without using them as a subgrid, because its
   legend is not a grid item. Beside or below, it reads the same. */
.block-form__fields > .field--choices,
.block-form--beside .block-form__fields > .field--choices {
  display: block;
  border: 0;
  margin: 0;
  padding: 0;
  min-width: 0;
}

.block-form__fields > .field--choices > .field__label {
  padding: 0;
  margin-bottom: var(--space-2);
}

.field--choices .field__check + .field__check {
  margin-top: var(--space-1);
}

/* One column on a narrow screen: two half-width fields side by side on a phone
   are two fields nobody can type in. Labels beside inputs go under them at the
   same width, for the same reason -- seven rems of label out of a phone's
   width leaves nothing to type in. */
@media (max-width: 640px) {
  .block-form__fields {
    grid-template-columns: 1fr;
  }

  .block-form--beside .block-form__fields > .field {
    grid-row: span 2;
    grid-template-rows: subgrid;
    grid-template-columns: minmax(0, 1fr);
    row-gap: var(--space-2);
    align-items: stretch;
  }

  .block-form--beside .block-form__fields > .field:has(textarea) > .field__label {
    padding-top: 0;
  }
}

/* --- Pricing tier image --------------------------------------------------- */
.pricing__image {
  display: block;
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  margin-bottom: var(--space-4);
  border-radius: var(--radius-sm);
}

/* --- Sticky navbar, phone and call to action ------------------------------ */
/* A sticky bar needs a background, or the page scrolls through it. But the
   block may have chosen one, and this painted over it -- so a dark nav bar
   showed the block's colour at each end, where this element does not reach,
   and the theme's surface in the middle. Two colours in one bar, and neither
   of them wrong on its own.

   `inherit` takes whatever the block set, and falls back to the surface only
   when the block set nothing. */
/* Moved to editor.css, which loads last, and changed from sticky to fixed:
   a sticky element slides within its parent, and a nav bar's block wrapper is
   exactly as tall as the nav bar -- so there was nowhere to slide and the
   setting did nothing at all. */

/* The rule under a nav bar goes on the block, not on the bar inside it.
   On the bar it stopped where the bar stopped, so a full-width block showed
   its own background for that one pixel past each end -- which read as the
   dark strip hanging down slightly at the left and right. */
.block--navbar { border-bottom: 1px solid var(--color-border); }

/* The fallback, on the block rather than on the bar: a section with no
   background of its own gives the sticky bar something opaque to inherit,
   and one that set a colour keeps it.

   2.203.0: the page's background, not the theme's surface. Kelly's "Use the
   page background" covers the entire bar -- the section as well as the bar
   inside it, which paints `--nav-bg` (editor.css). */
.block--navbar { background-color: var(--color-canvas); }

/* A block that set its own background says what colour text belongs on it.
   Anything with a colour of its own still wins: this is the default, not an
   override. */
.block[style*="--block-text"] { color: var(--block-text); }
.block[style*="--block-text"] .navbar__brand-text,
.block[style*="--block-text"] .navbar__menu a,
.block[style*="--block-text"] .navbar__links a,
.block[style*="--block-text"] .navbar__phone { color: inherit; }

.navbar__actions {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  margin-left: auto;
}

.navbar__phone {
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}

/* --- Compact feature grid ------------------------------------------------- */
/* Names only: a grid of place names should not render as cards full of white
   space. */
.feature-grid--compact {
  gap: var(--space-2);
}

.feature-grid--compact .feature-grid__item {
  padding: var(--space-3) var(--space-2);
  text-align: center;
  border: 0;
  border-bottom: 1px solid var(--color-border);
  box-shadow: none;
  background: none;
}

.feature-grid--compact .feature-grid__title {
  margin: 0;
  font-size: var(--text-sm);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  font-weight: 500;
}

/* --- Carousel ------------------------------------------------------------- */
/* Scroll-snap and anchor links, no JavaScript: a published site carries no
   scripts of its own, so a scripted carousel would never move. Swipe, keyboard
   and screen reader all work without one. */
.carousel {
  position: relative;
}

.carousel__track {
  display: flex;
  gap: var(--space-3);
  margin: 0;
  padding: 0;
  list-style: none;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scroll-behavior: smooth;
  /* A visible focus ring matters here: the track is focusable so it can be
     scrolled with the arrow keys. */
  border-radius: var(--radius-md);
}

.carousel__track:focus-visible {
  outline: 2px solid var(--color-accent);
  outline-offset: 3px;
}

.carousel__slide {
  flex: 0 0 100%;
  scroll-snap-align: center;
}

.carousel--2 .carousel__slide { flex-basis: calc(50% - var(--space-3) / 2); }
.carousel--3 .carousel__slide { flex-basis: calc(33.333% - var(--space-3) * 2 / 3); }

.carousel__slide img {
  display: block;
  width: 100%;
  aspect-ratio: 3 / 2;
  object-fit: cover;
  border-radius: var(--radius-md);
}

.carousel__empty {
  display: grid;
  place-items: center;
  aspect-ratio: 3 / 2;
  background: var(--color-surface-sunken);
  border: 1px dashed var(--color-border-strong);
  border-radius: var(--radius-md);
  color: var(--color-text-muted);
  font-size: var(--text-sm);
}

.carousel__caption {
  margin: var(--space-2) 0 0;
  font-size: var(--text-sm);
  color: var(--color-text-muted);
}

.carousel__dots {
  display: flex;
  justify-content: center;
  gap: var(--space-2);
  margin-top: var(--space-4);
}

.carousel__dot {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: var(--color-border-strong);
}

.carousel__dot:hover,
.carousel__dot:focus-visible,
.carousel__dot[aria-current="true"] {
  background: var(--color-accent);
}

/* Two slides side by side on a phone are two slides nobody can see. */
@media (max-width: 640px) {
  .carousel--2 .carousel__slide,
  .carousel--3 .carousel__slide { flex-basis: 85%; }
}

/* Snapping animates the scroll; somebody who asked for less movement gets a
   jump instead. */
@media (prefers-reduced-motion: reduce) {
  .carousel__track { scroll-behavior: auto; }
}

/* Height, for a carousel of full-bleed photographs. Same dvh reasoning as the
   hero: 100vh is measured without a phone's collapsing address bar. */
.carousel--tall .carousel__track {
  height: 66vh;
  height: 66dvh;
}

.carousel--full .carousel__track {
  height: 100vh;
  height: 100dvh;
}

.carousel--tall .carousel__slide img,
.carousel--full .carousel__slide img {
  height: 100%;
  aspect-ratio: auto;
}

/* No scrollbar, at any height. 2.218.0: it was hidden on the tall and full
   ones only, so one as tall as its photographs had a bar along its foot
   (Kelly: "lose the slider. It's not needed", as the hero lost its in
   2.171.0). The arrows and dots move it; a swipe and the arrow keys still
   do, because it is still a scroll container. */
.carousel__track { scrollbar-width: none; }

.carousel__track::-webkit-scrollbar { display: none; }

.carousel__controls {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-3);
}

.carousel__arrow {
  position: absolute;
  top: 40%;
  width: 2.5rem;
  height: 2.5rem;
  border-radius: 50%;
  background: rgba(0, 0, 0, 0.35);
}

/* 2.264.0. A chevron, "<" (and ">" on the right, turned round), in place of
   the diagonal line that read as a circle struck through (Kelly: "The
   circle with a slash though it doesn't really communicate advance"). The
   dark circle stays, so the arrow shows on any photograph. */
.carousel__arrow::before {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: 0.7rem;
  height: 0.7rem;
  border-left: 2.5px solid var(--color-text-inverse);
  border-bottom: 2.5px solid var(--color-text-inverse);
  transform: translate(-30%, -50%) rotate(45deg);
}

.carousel__arrow--prev { left: var(--space-3); }
.carousel__arrow--next { right: var(--space-3); rotate: 180deg; }

.carousel__arrow:hover,
.carousel__arrow:focus-visible { background-color: rgba(0, 0, 0, 0.6); }

/* --- The pause control ---------------------------------------------------
   Ships hidden and is unhidden by the script, because without the script
   nothing advances and a button that stops nothing is worse than none.
   Anything that moves for more than five seconds has to be stoppable by
   everyone -- hovering is not a control a keyboard or a touch screen has. */
.slides-pause {
  padding: var(--space-1) var(--space-3);
  border: 1px solid rgba(255, 255, 255, 0.6);
  border-radius: var(--radius-pill, 999px);
  background: rgba(0, 0, 0, 0.35);
  color: var(--color-text-inverse);
  font-size: var(--text-sm);
  cursor: pointer;
}

.slides-pause:hover,
.slides-pause:focus-visible { background: rgba(0, 0, 0, 0.6); }

.slides-pause[hidden] { display: none; }

/* --- What a QA publish will sweep up -------------------------------------- */
.publish-sweep {
  margin-bottom: var(--space-4);
  padding: var(--space-3);
  border-left: 3px solid var(--color-warning);
  background: var(--color-surface-sunken);
}

/* The same panel, marked as a caution rather than a statement of fact. */
.publish-sweep--warn { border-left-color: var(--color-danger); }

.publish-sweep__lead {
  margin: 0;
  font-size: var(--text-sm);
  color: var(--color-text-muted);
}

.publish-sweep__list {
  margin: var(--space-2) 0 0;
  padding-left: var(--space-4);
  font-size: var(--text-sm);
}

.publish-sweep__list li { margin-bottom: var(--space-1); }

/* --- The document library navigator ---------------------------------------
   A details/summary tree, so the whole navigator opens and closes with no
   script on a published site -- the same reason the navbar dropdowns are built
   that way. On a phone it stacks above the documents rather than sitting
   beside them: a fixed rail on a narrow screen is most of the screen. */
.doclib {
  display: grid;
  gap: var(--space-5);
}

@media (min-width: 60rem) {
  .doclib { grid-template-columns: 16rem 1fr; }
}

/* 2.274.0. The document viewer (Kelly's picture): the sections and documents
   on the left, the document in the middle, its table of contents on the
   right, which stays in view as the document scrolls. Three columns where
   there is room for them; below that the contents follow the document. */
@media (min-width: 72rem) {
  .doclib:has(> .doclib__contents) { grid-template-columns: 16rem minmax(0, 1fr) 15rem; }
  .doclib__contents {
    position: sticky;
    top: var(--space-5);
    max-height: calc(100vh - 2 * var(--space-5));
    overflow-y: auto;
  }
}
.doclib__contents { align-self: start; font-size: var(--text-sm); }
.doclib__contents-title {
  margin: 0 0 var(--space-3);
  font-size: var(--text-sm);
  font-weight: var(--weight-semibold);
}
.doclib__contents ol { margin: 0; padding: 0; list-style: none; display: grid; gap: var(--space-2); }
.doclib__contents a { color: var(--color-text-muted); text-decoration: none; }
.doclib__contents a:hover,
.doclib__contents a:focus-visible { color: var(--color-text); text-decoration: underline; }
.doclib__contents a[aria-current="true"] { color: var(--color-text); font-weight: var(--weight-semibold); }
.doclib__contents-item--3 { padding-left: var(--space-3); }
.doclib__contents-item--4,
.doclib__contents-item--5,
.doclib__contents-item--6 { padding-left: var(--space-5); }
/* A heading jumped to lands clear of the top of the screen. */
.doclib__article [id^="section-"] { scroll-margin-top: var(--space-5); }
@media (prefers-reduced-motion: no-preference) {
  html:has(.doclib__contents) { scroll-behavior: smooth; }
}

.doclib__nav {
  padding: var(--space-3);
  border-radius: var(--radius-md);
  background: var(--color-surface-sunken);
  align-self: start;
}

.doclib__nav-title {
  margin: 0 0 var(--space-2);
  font-size: var(--text-sm);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--color-text-muted);
}

.doclib__group-name,
.doclib__subgroup-name {
  cursor: pointer;
  padding: var(--space-1) 0;
  font-weight: 600;
}

.doclib__subgroup { margin-left: var(--space-3); }

.doclib__subgroup-name { font-weight: 500; }

.doclib__list {
  margin: 0 0 var(--space-2);
  padding-left: var(--space-4);
  list-style: none;
}

.doclib__list li { margin: var(--space-1) 0; }

.doclib__empty,
.doclib__notice { color: var(--color-text-muted); }

/* --- Reviewing an ingestion ------------------------------------------------ */
.stage {
  margin: 0 0 var(--space-5);
  padding: var(--space-4);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
}

.stage label {
  display: block;
  margin-bottom: var(--space-3);
  font-size: var(--text-sm);
  font-weight: 600;
}

.stage input,
.stage textarea { width: 100%; font-weight: 400; }

.diff {
  max-height: 24rem;
  padding: var(--space-3);
  border-radius: var(--radius-md);
  background: var(--color-surface-sunken);
  font-size: var(--text-sm);
  overflow: auto;
}

.doclib__search {
  display: flex;
  gap: var(--space-2);
  margin-bottom: var(--space-3);
}

.doclib__search input { min-width: 0; flex: 1; }

.doclib__list a[aria-current="page"] {
  font-weight: 600;
  color: var(--color-accent);
}

.doclib__file a::before {
  content: "\2193\00a0";      /* a downward arrow: this one is taken away */
  opacity: 0.6;
}

/* An article is prose, so it gets reading measure and room between blocks
   rather than the component spacing the rest of the console uses. */
.doclib__article { max-width: 44rem; }

.doclib__article h2 { margin-top: var(--space-6); }

.doclib__article h3 { margin-top: var(--space-5); }

.doclib__article p,
.doclib__article ul,
.doclib__article ol { margin-bottom: var(--space-4); line-height: 1.7; }

.doclib__article pre {
  padding: var(--space-3);
  border-radius: var(--radius-md);
  background: var(--color-surface-sunken);
  overflow-x: auto;
}

.doclib__article table { width: 100%; margin-bottom: var(--space-4); }

.doclib__article blockquote {
  margin: 0 0 var(--space-4);
  padding-left: var(--space-4);
  border-left: 3px solid var(--color-border);
  color: var(--color-text-muted);
}

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

.doclist__item {
  padding: var(--space-3) 0;
  border-bottom: 1px solid var(--color-border);
}

.doclist__title { font-weight: 600; }

.doclist__description { margin: var(--space-1) 0 0; }

.doclist__meta {
  margin: var(--space-1) 0 0;
  font-size: var(--text-sm);
  color: var(--color-text-muted);
}

/* --- Shelves, 2.219.0 ---------------------------------------------------- */
/* One row that scrolls sideways: a Documents block's shelf and banner cards,
   a Blog posts block's overlay shelf. It scrolls as it is; the arrows are
   frontend/src/listings.ts, which shows each only when there is somewhere to
   go and then hides the scrollbar they stand in for. Where nothing hovers --
   a phone -- the row is swiped and the arrows stay away. */
.shelf { position: relative; }

.shelf__track {
  display: flex;
  gap: var(--space-4);
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scroll-snap-type: x proximity;
  padding-bottom: var(--space-2);
}

.shelf__track > * { flex: 0 0 auto; scroll-snap-align: start; }

.shelf[data-ready] .shelf__track { scrollbar-width: none; }
.shelf[data-ready] .shelf__track::-webkit-scrollbar { display: none; }

.shelf__arrow {
  position: absolute;
  top: var(--shelf-arrow-top, 50%);
  z-index: 2;
  display: grid;
  place-items: center;
  width: 2.5rem;
  height: 2.5rem;
  padding: 0 0 0.15em;
  border: 1px solid var(--color-border);
  border-radius: 50%;
  background: var(--color-surface);
  color: var(--color-text);
  font-size: 1.75rem;
  line-height: 1;
  cursor: pointer;
  transform: translateY(-50%);
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.18);
}

.shelf__arrow[hidden] { display: none; }
.shelf__arrow--back { left: var(--space-2); }
.shelf__arrow--on { right: var(--space-2); }
.shelf__arrow:focus-visible { outline: 2px solid var(--color-accent); outline-offset: 2px; }

@media (hover: none) { .shelf__arrow { display: none; } }

/* --- Documents block layouts, 2.219.0 ------------------------------------ */
/* Kelly, 2026-10-06, after rows from an app store: a shelf, ranked columns,
   banner cards and cards beside the list. A document's picture is its own,
   or a tile of its type in that type's colour (tokens.css, --doctype-*). */
.doctype--pdf, .docbanner--pdf { --doctype-color: var(--doctype-pdf); }
.doctype--doc, .docbanner--doc { --doctype-color: var(--doctype-doc); }
.doctype--sheet, .docbanner--sheet { --doctype-color: var(--doctype-sheet); }
.doctype--slides, .docbanner--slides { --doctype-color: var(--doctype-slides); }
.doctype--archive, .docbanner--archive { --doctype-color: var(--doctype-archive); }
.doctype--text, .docbanner--text { --doctype-color: var(--doctype-text); }

.docpic {
  position: relative;
  display: block;
  overflow: hidden;
  border-radius: var(--radius-md);
  background: var(--color-surface-sunken);
}

.docpic--square { aspect-ratio: 1; border-radius: 22%; }
.docpic--tall { aspect-ratio: 2 / 3; }
.docpic--wide { aspect-ratio: 16 / 9; }

.docpic__image {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.doctype {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  container-type: inline-size;
  background: var(--doctype-color);
  color: var(--color-text-inverse);
}

/* A page with its corner turned, where the tile is shaped like one. */
.docpic--tall .doctype::before {
  content: "";
  position: absolute;
  top: 0;
  right: 0;
  width: 26%;
  aspect-ratio: 1;
  background: linear-gradient(225deg, var(--color-surface) 50%, rgba(255, 255, 255, 0.32) 50%);
}

.doctype__label {
  font-size: 1.25rem;
  font-size: clamp(0.7rem, 24cqi, 3.25rem);
  font-weight: 800;
  letter-spacing: 0.04em;
  line-height: 1;
}

.doctile, .docbanner, .docranked__link, .doccard { color: inherit; text-decoration: none; }

.doctile:focus-visible, .docbanner:focus-visible, .docranked__link:focus-visible,
.doccard:focus-visible {
  outline: 2px solid var(--color-accent);
  outline-offset: 3px;
}

.doctile:hover :is(.doctile__title), .docranked__link:hover .docranked__title,
.doccard:hover .doccard__title { text-decoration: underline; }

.doctile__title, .doccard__title, .docranked__title, .docbanner__title {
  display: block;
  font-weight: var(--weight-semibold, 600);
}

.doctile__meta, .doccard__meta, .docranked__meta {
  display: block;
  font-size: var(--text-xs);
  color: var(--color-text-muted);
}

.doctile__description, .doccard__description, .docranked__description,
.docbanner__description {
  display: -webkit-box;
  overflow: hidden;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  font-size: var(--text-sm);
  color: var(--color-text-muted);
}

/* A shelf: pictures in a row with a name under each. */
.docshelf--square { --shelf-arrow-top: 4.5rem; }
.docshelf--tall { --shelf-arrow-top: 6.4rem; }
.docshelf--wide { --shelf-arrow-top: 4.5rem; }
.doctile { display: flex; flex-direction: column; gap: var(--space-1); width: 9rem; }
.docshelf--tall .doctile { width: 8.5rem; }
.docshelf--wide .doctile { width: 16rem; }
.doctile .docpic { margin-bottom: var(--space-1); }
.doctile__title { font-size: var(--text-sm); }

/* Banner cards: wide, each in its type's colour, the words on a band. */
.docshelf--banners { --shelf-arrow-top: 34%; }
.docbanner {
  display: flex;
  flex-direction: column;
  flex-basis: min(22rem, 85%);
  overflow: hidden;
  border-radius: calc(var(--radius-md) * 2);
  background: var(--doctype-color);
  color: var(--color-text-inverse);
}

.docbanner .docpic { border-radius: 0; }
.docbanner__band { display: flex; flex-direction: column; gap: var(--space-1); padding: var(--space-4) var(--space-5) var(--space-5); }
.docbanner__title { font-size: var(--text-md); }
.docbanner__description { color: rgba(255, 255, 255, 0.88); }
.docbanner__meta { font-size: var(--text-xs); color: rgba(255, 255, 255, 0.8); }
.docbanner:hover .docbanner__title { text-decoration: underline; }

/* Ranked columns: numbered down each column, then the next. */
.docranked {
  margin: 0;
  padding: 0;
  list-style: none;
  columns: 3 17rem;
  column-gap: var(--space-6);
}

.docranked__item {
  display: grid;
  grid-template-columns: 1.75rem minmax(0, 1fr);
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2) 0;
  break-inside: avoid;
}

.docranked__number {
  font-size: var(--text-md);
  font-weight: var(--weight-medium);
  font-variant-numeric: tabular-nums;
  color: var(--color-text-muted);
  text-align: center;
}

.docranked__link {
  display: grid;
  grid-template-columns: 4rem minmax(0, 1fr);
  align-items: center;
  gap: var(--space-3);
}

.docranked--tall .docranked__link { grid-template-columns: 3.25rem minmax(0, 1fr); }
.docranked--wide .docranked__link { grid-template-columns: 6.5rem minmax(0, 1fr); }
.docranked__text { display: flex; flex-direction: column; gap: 0.125rem; min-width: 0; }

/* Cards: a picture inside a rounded card, the words under it. */
.doccards {
  display: grid;
  /* Two to a row on a phone, as an app store's are. */
  grid-template-columns: repeat(auto-fill, minmax(min(13rem, 42%), 1fr));
  gap: var(--space-5);
  margin: 0;
  padding: 0;
  list-style: none;
}

.doccards__item { display: flex; }

.doccard {
  display: flex;
  flex: 1;
  flex-direction: column;
  padding: var(--space-3);
  border: 1px solid var(--color-border);
  border-radius: calc(var(--radius-md) * 2);
  background: var(--color-surface);
  transition: border-color 0.15s ease;
}

.doccard:hover { border-color: var(--color-border-strong); }
.doccard .docpic--square { border-radius: var(--radius-md); }
.doccard__body { display: flex; flex-direction: column; gap: var(--space-1); padding: var(--space-3) var(--space-1) var(--space-1); }

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

/* --- Private gallery, 2.163.0 ------------------------------------------ */
/* The way in, where the photographs will be: an address, then a code. */
/* 2.285.0. The way in, as a card: Kelly found it "too long and too thin",
   and the code box like the sign-in page's. */
.private-gallery {
  max-width: 26rem;
  margin: var(--space-4) auto;
  padding: var(--space-6) var(--space-5);
  text-align: center;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  box-shadow: 0 1px 2px rgb(0 0 0 / 0.04), 0 8px 24px rgb(0 0 0 / 0.06);
}

.private-gallery__lead { margin: 0 0 var(--space-2); }

.private-gallery__form {
  display: grid;
  gap: var(--space-3);
  margin-top: var(--space-4);
}

.private-gallery__label {
  font-size: var(--text-sm);
  letter-spacing: 0.04em;
  color: var(--color-text-muted);
}

.private-gallery__input {
  height: 3rem;
  padding: 0 var(--space-3);
  font: inherit;
  text-align: center;
  border: 1px solid color-mix(in srgb, var(--color-text) 28%, transparent);
  border-radius: var(--radius-md);
  background: var(--color-surface);
  color: var(--color-text);
}

.private-gallery__go { min-height: 3rem; }

.private-gallery__notice {
  margin: 0;
  font-size: var(--text-sm);
  line-height: 1.6;
  color: var(--color-text-muted);
}

.private-gallery__notice--error { color: var(--color-danger); }

.private-gallery__again { margin-top: var(--space-2); }

.private-gallery__again .btn {
  padding: 0;
  background: none;
  border: 0;
  font-size: var(--text-sm);
  color: var(--color-text-muted);
  text-decoration: underline;
  text-underline-offset: 0.2em;
}

/* 2.285.0. A six-digit code: short and large, each digit apart, as the
   sign-in page's. */
input.code-box {
  display: block;
  width: 100%;
  max-width: 15rem;
  height: 3.75rem;
  margin: 0 auto;
  padding: 0 var(--space-2);
  font: inherit;
  font-size: 2rem;
  font-weight: var(--weight-semibold);
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.45em;
  text-indent: 0.45em;
  text-align: center;
  border: 1px solid color-mix(in srgb, var(--color-text) 28%, transparent);
  border-radius: var(--radius-md);
  background: var(--color-surface);
  color: var(--color-text);
}

input.code-box::placeholder { color: var(--color-border); }

input.code-box:focus,
.private-gallery__input:focus {
  outline: 2px solid var(--color-accent);
  outline-offset: 2px;
  border-color: var(--color-accent);
}

input.code-box--small { max-width: 11rem; height: 3rem; font-size: 1.5rem; margin: 0; }

.private-gallery__note {
  font-size: var(--text-sm);
  color: var(--color-text-muted);
}

/* --- Private gallery stars and filter, 2.164.0 ------------------------- */
/* 2.285.0. Kelly: the filter "looks cheap". A quiet bar: each person a chip,
   the stars a select of whole sentences. */
.pg-filter {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3) var(--space-5);
  margin-bottom: var(--space-4);
  padding: var(--space-3) var(--space-4);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  background: var(--color-surface);
}

.pg-filter__label {
  font-size: var(--text-sm);
  letter-spacing: 0.04em;
  color: var(--color-text-muted);
}

.pg-filter__who {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
  margin: 0;
  padding: 0;
  border: 0;
  min-width: 0;
}

.pg-filter__who legend { float: left; margin-right: var(--space-2); padding: 0; }

.pg-chip { position: relative; display: inline-flex; cursor: pointer; }
.pg-chip input { position: absolute; opacity: 0; pointer-events: none; }
.pg-chip span {
  display: inline-flex;
  align-items: center;
  gap: 0.35em;
  min-height: 2rem;
  padding: 0 0.85em;
  border: 1px solid color-mix(in srgb, var(--color-text) 28%, transparent);
  border-radius: 999px;
  font-size: var(--text-sm);
  color: var(--color-text);
  background: var(--color-surface);
}
.pg-chip input:checked + span {
  border-color: var(--color-accent);
  background: var(--color-accent);
  color: var(--color-text-inverse);
}
.pg-chip input:checked + span::before { content: "\2713"; }
.pg-chip input:focus-visible + span { outline: 2px solid var(--color-accent); outline-offset: 2px; }

.pg-filter__least { display: inline-flex; align-items: center; gap: var(--space-2); }

/* A select with the page's own look: no system box, a drawn chevron. */
.pg-select {
  appearance: none;
  min-height: 2rem;
  padding: 0 2.25em 0 0.85em;
  border: 1px solid color-mix(in srgb, var(--color-text) 28%, transparent);
  border-radius: 999px;
  font: inherit;
  font-size: var(--text-sm);
  color: var(--color-text);
  background-color: var(--color-surface);
  background-image:
    linear-gradient(45deg, transparent 50%, currentColor 50%),
    linear-gradient(135deg, currentColor 50%, transparent 50%);
  background-position: calc(100% - 1.1em) 55%, calc(100% - 0.75em) 55%;
  background-size: 0.35em 0.35em;
  background-repeat: no-repeat;
  cursor: pointer;
}
.pg-select:focus-visible { outline: 2px solid var(--color-accent); outline-offset: 2px; }

.pg-stars {
  display: flex;
  align-items: center;
  gap: 2px;
  margin-top: var(--space-1);
}

.pg-stars__label { margin-right: var(--space-1); font-size: var(--text-sm); }

/* A star is a button: the whole of the voting, and what a keyboard reaches. */
.pg-star {
  padding: 0 2px;
  border: 0;
  background: none;
  font-size: 1.25rem;
  line-height: 1;
  color: var(--color-border);
  cursor: pointer;
}

.pg-star--on { color: var(--color-accent); }

.pg-download { margin: 0 0 var(--space-4); }

.pg-photo-download { font-size: var(--text-sm); }

.pg-votes { margin: var(--space-1) 0 0; font-size: var(--text-sm); color: var(--color-text-muted); }

.pg-votes:empty { display: none; }

/* --- Theme editor -------------------------------------------------------- */
/* Form on the left, live preview on the right, stacking on a narrow screen.
   The preview is deliberately not full width: a colour judged across a whole
   monitor is not the colour a visitor sees in a card. */
.theme-editor {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: var(--space-5);
  align-items: start;
}

@media (max-width: 960px) {
  .theme-editor { grid-template-columns: minmax(0, 1fr); }
}

.theme-editor__group {
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  padding: var(--space-4);
  margin-bottom: var(--space-4);
}

.theme-editor__legend {
  font-size: var(--text-sm);
  font-weight: var(--weight-semibold);
  padding: 0 var(--space-2);
}

.theme-editor__fields {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: var(--space-3);
}

.theme-editor__swatches {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
  gap: var(--space-3);
}

.field--swatch input[type="color"] {
  width: 100%;
  height: 2.25rem;
  padding: 2px;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  background: var(--color-surface);
}

.theme-editor__specimen {
  display: flex;
  align-items: baseline;
  gap: var(--space-3);
  margin-top: var(--space-2);
}

.theme-editor__specimen-label {
  font-size: var(--text-xs);
  color: var(--color-text-muted);
  min-width: 4.5rem;
}

.theme-editor__specimen-text { font-size: var(--text-lg); }

[data-specimen="heading"] .theme-editor__specimen-text {
  font-family: var(--specimen-heading, var(--font-heading));
}

/* 2.202.0. The eyebrow and subheading specimens: the body font until chosen. */
[data-specimen="eyebrow"] .theme-editor__specimen-text {
  font-family: var(--specimen-eyebrow, var(--font-eyebrow, var(--font-sans)));
}

[data-specimen="subheading"] .theme-editor__specimen-text {
  font-family: var(--specimen-subheading, var(--font-subheading, var(--font-sans)));
}

[data-specimen="body"] .theme-editor__specimen-text {
  font-family: var(--specimen-body, var(--font-sans));
}

.theme-editor__preview { position: sticky; top: var(--space-4); }

.theme-editor__preview-note {
  font-size: var(--text-xs);
  color: var(--color-text-muted);
  margin-bottom: var(--space-2);
}

/* Everything below reads its colours and fonts from the custom properties the
   preview script sets on .theme-preview, exactly as a published page reads
   them from :root. Nothing here hardcodes a theme value. */
.theme-preview {
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  overflow: hidden;
  background: var(--color-canvas);
  color: var(--color-text);
  font-family: var(--font-sans);
}

.theme-preview__nav {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
  background: var(--color-surface);
  border-bottom: 1px solid var(--color-border);
}

.theme-preview__brand {
  font-family: var(--font-heading);
  font-weight: var(--weight-semibold);
}

.theme-preview__links {
  display: flex;
  gap: var(--space-3);
  font-size: var(--text-sm);
  color: var(--color-text-muted);
}

.theme-preview__body { padding: var(--space-4); }

/* 2.202.0. The eyebrow and subheading, in the fonts the theme gives them. */
.theme-preview__eyebrow {
  font-family: var(--font-eyebrow, var(--font-sans));
  font-size: var(--text-xs);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  margin-bottom: var(--space-1);
}

.theme-preview__subheading {
  font-family: var(--font-subheading, var(--font-sans));
  font-size: var(--text-lg);
  margin-bottom: var(--space-3);
}

.theme-preview__h1 {
  font-family: var(--font-heading);
  font-size: var(--text-2xl);
  line-height: var(--leading-tight);
  margin-bottom: var(--space-2);
}

.theme-preview__h2 {
  font-family: var(--font-heading);
  font-size: var(--text-lg);
  color: var(--color-text-muted);
  margin-bottom: var(--space-3);
}

.theme-preview__text {
  font-size: var(--text-base);
  line-height: var(--leading-normal);
  margin-bottom: var(--space-3);
}

.theme-preview__muted {
  font-size: var(--text-sm);
  color: var(--color-text-muted);
  margin-bottom: var(--space-4);
}

.theme-preview__buttons {
  display: flex;
  gap: var(--space-3);
  margin-bottom: var(--space-4);
}

.theme-preview__btn {
  display: inline-block;
  padding: var(--space-2) var(--space-4);
  border-radius: var(--radius-sm);
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
}

.theme-preview__btn--primary {
  background: var(--color-accent);
  color: var(--color-on-accent);
}

.theme-preview__btn--hover {
  background: var(--color-accent-hover);
  color: var(--color-text-inverse);
}

.theme-preview__btn--primary:hover {
  background: var(--color-accent-hover);
}

.theme-preview__btn--secondary {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  color: var(--color-text);
}

.theme-preview__card {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  padding: var(--space-4);
}

.theme-preview__card-title {
  font-family: var(--font-heading);
  display: block;
  margin-bottom: var(--space-2);
}


/* The transport failure behind a verification error. Collapsed, because the
   sentence above it is the part a customer acts on. */
.domain__detail summary {
  font-size: var(--text-xs);
  color: var(--color-text-muted);
  cursor: pointer;
}

.domain__detail code {
  display: block;
  margin-top: var(--space-2);
  padding: var(--space-2);
  background: var(--color-surface-sunken);
  border-radius: var(--radius-sm);
  font-size: var(--text-xs);
  color: var(--color-text-muted);
  overflow-wrap: anywhere;
}

/* A pasted list of redirects. Monospace because the arrows and the paths line
   up when they are, and a list that lines up is a list somebody can scan. */
.redirects__bulk {
  width: 100%;
  padding: var(--space-3);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  background: var(--color-surface);
  color: var(--color-text);
  font-family: var(--font-mono, ui-monospace, "SF Mono", Menlo, Consolas, monospace);
  font-size: var(--text-sm);
  margin-bottom: var(--space-3);
}

/* Where a published stage can be looked at, or why it cannot be. */
.publish-stage__address {
  font-size: var(--text-sm);
  margin-top: var(--space-2);
}

.publish-stage__address--waiting { color: var(--color-text-muted); }

/* 2.235.0. Each stage's remove button at the foot of its column on the
   Publish page (Kelly), moved from the Sites page's row: the columns' bodies
   are as tall as the tallest, and each button sits at the bottom, so the
   three line up. */
.publish-stage { display: flex; flex-direction: column; }
.publish-stage > .panel__body { display: flex; flex-direction: column; flex: 1 1 auto; }
.publish-stage__foot,
.publish-stage > .panel__body > .publish-stage__remove { margin-top: auto; }
.publish-stage__foot {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: var(--space-3);
}
.publish-stage__remove { padding-top: var(--space-4); text-align: center; }
.publish-stage__foot .publish-stage__remove { padding-top: 0; }
.publish-stage__remove form { display: inline; }

/* A blocked stage keeps its button rather than losing it: a control that
   disappears leaves somebody hunting for it. */
.publish-stage__remove .btn:disabled {
  opacity: 0.4;
  cursor: not-allowed;
}

/* 2.235.0. A site's licence in brief, where its remove buttons were on the
   Sites page (Kelly): Billed, Last invoice and Next invoice, each a small
   heading over its value. */
.site-billing {
  display: flex;
  gap: var(--space-5);
  margin: 0;
}
.site-billing dt {
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--color-text-muted);
}
.site-billing dd { margin: 0; font-size: var(--text-sm); white-space: nowrap; }

/* --- Hero layouts -------------------------------------------------------- */
/* `over` is the hero as it always was: text positioned over a full-bleed
   background. The two below arrange text and picture instead, which is what
   every reference design that was not a photograph-with-a-headline turned out
   to be. */






/* A split hero sits on its own background colour rather than over a
   photograph, so the text is dark on light and needs no overlay. */

/* Text in a panel over the background. Offset rather than centred: the point
   is that the photograph is still visible beside it. */

/* Stacked on a narrow screen. A picture beside text at 390px is two things
   too small to read rather than one of each. */
@media (max-width: 48rem) {
  .hero__row { flex-direction: column; }
  .hero--picture-left .hero__row { flex-direction: column; }
  .hero__side { width: 100%; }
  .hero__row .hero__inner { max-width: none; }
}

/* --- A background that stays put ---------------------------------------- */
/* The block scrolls over its own background, so a tall photograph shows a
   different part of itself as the page moves. No script: this is one CSS
   property, which is what lets it work on a published page where no script
   runs at all.

   iOS Safari ignores `fixed` and paints the background normally. That is a
   still photograph instead of a moving one, which is a fair degradation and
   the reason this is not built with a scroll listener nobody would see run. */
.block--fixed-bg {
  background-attachment: fixed;
  background-size: cover;
  background-position: center;
  /* Something to scroll past. A band the height of its text would move too
     little for the effect to read as anything. */
  min-height: 22rem;
  display: flex;
  align-items: center;
}

/* Somebody who has asked for less motion has asked for exactly this. */
@media (prefers-reduced-motion: reduce) {
  .block--fixed-bg { background-attachment: scroll; }
}

/* 2.203.0. The split menu either side of a centred brand is two menus in the
   bar's centre zone now (editor.css, "The nav bar"); the rules for the old
   split layout's two lists went with the layout. */

/* --- Column treatments --------------------------------------------------- */
/* `plain` is a heading and some text, which is what a column has always been.
   The two below are the same content presented differently, not different
   blocks: a customer choosing between them should not have to rebuild. */

.columns__image {
  display: block;
  width: 100%;
  height: auto;
  object-fit: cover;
  aspect-ratio: 4 / 3;
  margin-bottom: var(--space-4);
}

/* The button sits at the foot of the column, level across all of them, so
   three columns of unequal text do not stagger their buttons up the page. */
.columns__column { display: flex; flex-direction: column; }
.columns__column .rich-text { flex: 1 1 auto; }
.columns__button { align-self: flex-start; margin-top: var(--space-5); }

/* Cards: each column on its own surface, with a rule under the heading. */
.columns--card .columns__column {
  background: var(--color-surface);
  padding: var(--space-6);
  border-radius: var(--radius-sm);
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.06);
}

.columns--card .columns__heading {
  padding-bottom: var(--space-4);
  border-bottom: 1px solid var(--color-border);
  margin-bottom: var(--space-4);
}

.columns--card .columns__image {
  /* Out to the card's edges: a picture inset by the padding reads as a
     mistake rather than as a margin. */
  margin: calc(var(--space-6) * -1) calc(var(--space-6) * -1) var(--space-5);
  width: auto;
  border-radius: var(--radius-sm) var(--radius-sm) 0 0;
}

/* Picture-led: the picture is the column, and the text is a caption under it. */
.columns--picture .columns__image { aspect-ratio: 3 / 4; margin-bottom: var(--space-3); }
.columns--picture .columns__heading { font-size: var(--text-lg); margin: 0; }
.columns--picture .rich-text { color: var(--color-text-muted); }

/* --- Testimonials -------------------------------------------------------- */
/* One or several. A single one keeps the shape it always had; several sit in a
   row that wraps rather than a track that scrolls, so every quote is on the
   page at once and none of them is behind a control nobody presses. */
.testimonials--many {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
  gap: var(--space-6);
  align-items: start;
}

.testimonials .testimonial__portrait {
  display: block;
  width: 6rem;
  height: 6rem;
  border-radius: 50%;
  object-fit: cover;
  margin: 0 auto var(--space-4);
}

/* Cards: each quote on its own surface, with the portrait overlapping the top
   edge -- which is why a card with a portrait has room above it and the
   picture is pulled up rather than the card being padded twice.

   The surface and its ink are the block's own choice since 2.155.0, falling
   back to the theme's. They were the theme's surface and the block's text
   colour, which are chosen against different backgrounds: on a block given a
   dark colour the quotation turned light and the card stayed pale, so the
   words went white on white.

   The ink falls back to the theme's text, not to the block's, since 2.155.1.
   2.155.0 let it inherit, which left the white-on-white card exactly as it
   was until somebody found the new picker. The card is the theme's surface
   until somebody changes it, and the theme's text is the colour chosen to
   sit on that surface -- so a card left alone reads, whatever the block
   around it is. */
.testimonials--card .testimonial {
  background: var(--testimonial-card, var(--color-surface));
  color: var(--testimonial-card-ink, var(--color-text));
  padding: var(--space-6);
  border-radius: var(--radius-sm);
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.06);
  text-align: center;
}

/* The room the portrait is pulled up into, and only where there is one. A
   card without a picture reserved 48px above itself and left it empty, so the
   gap above the block measured 72 where its spacing said 24 -- a setting
   overruled by space held for something that was not there. */
.testimonials--card .testimonial:has(.testimonial__portrait) {
  margin-top: 3rem;
}

.testimonials--card .testimonial__portrait { margin-top: -5rem; }

/* The line under the name is the card's ink too, softened rather than the
   theme's muted grey -- which is chosen against the theme's pale surface and
   disappears on a dark card. */
.testimonials--card .testimonial__role {
  color: color-mix(in srgb,
                   var(--testimonial-card-ink, var(--color-text-muted)) 75%,
                   transparent);
}

.testimonials--card .testimonial__by {
  display: block;
  margin-top: var(--space-5);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  font-size: var(--text-xs);
}

/* --- Underlined form fields ---------------------------------------------- */
/* One rule per field instead of a box. A row of white boxes over a photograph
   reads as a dialog dropped on top of it; a rule sits on the picture instead
   of covering it.

   The border is on the field itself rather than the row, so the underline is
   the width of the input and lines up with the one above it whatever the
   label says. */
.block-form--underline .field input,
.block-form--underline .field textarea,
.block-form--underline .field select {
  border: 0;
  border-bottom: 1px solid var(--color-border);
  border-radius: 0;
  padding-inline: 0;
  background: transparent;
}

.block-form--underline .field input:focus,
.block-form--underline .field textarea:focus,
.block-form--underline .field select:focus {
  /* Kept visible: removing the box must not remove the focus ring, or the
     form becomes unusable by keyboard. */
  outline: 2px solid var(--color-accent);
  outline-offset: 2px;
  border-bottom-color: var(--color-accent);
}

.block-form--underline .field__label {
  letter-spacing: 0.12em;
  text-transform: uppercase;
  font-size: var(--text-xs);
  color: var(--color-text-muted);
}

/* --- Blog post listing --------------------------------------------------- */
/* A grid of cards that wraps, rather than a track that scrolls: every post is
   on the page at once and none is behind a control nobody presses. */
.blog-posts--card {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
  gap: var(--space-6);
}

.blog-posts__item {
  display: block;
  background: var(--color-surface);
  color: inherit;
  text-decoration: none;
  border-radius: var(--radius-sm);
  overflow: hidden;
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.06);
}

/* The whole card is the link, so the title does not need to be underlined to
   be understood as one -- but it still has to answer to a keyboard. */
.blog-posts__item:focus-visible {
  outline: 2px solid var(--color-accent);
  outline-offset: 3px;
}

.blog-posts__image {
  display: block;
  width: 100%;
  height: auto;
  object-fit: cover;
  aspect-ratio: 3 / 4;
}

.blog-posts__title {
  margin: var(--space-4) var(--space-5) 0;
  font-size: var(--text-md);
}

.blog-posts__summary {
  margin: var(--space-2) var(--space-5) var(--space-5);
  color: var(--color-text-muted);
  font-size: var(--text-sm);
}

/* A list: no card, no picture wider than a thumbnail, one per row. */
.blog-posts--list { display: flex; flex-direction: column; gap: var(--space-4); }
.blog-posts--list .blog-posts__item { box-shadow: none; background: none; }
.blog-posts--list .blog-posts__image { aspect-ratio: 16 / 9; }

.blog-posts__empty { color: var(--color-text-muted); }

/* --- Blog posts: the date, author, tags and Read more, 2.219.0 ----------- */
/* Each only when its switch is on. In Cards and A list they sit among the
   card's own margins; the newer styles lay their words out in a column with
   gaps instead (`.blog-posts__body`). */
.blog-posts__details {
  margin: var(--space-1) var(--space-5) 0;
  font-size: var(--text-sm);
  color: var(--color-text-muted);
}

.blog-posts__tags {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-1);
  margin: var(--space-3) var(--space-5) var(--space-5);
  padding: 0;
  list-style: none;
}

.blog-posts__tag {
  padding: 0.125rem var(--space-2);
  border-radius: 999px;
  background: var(--color-surface-sunken);
  font-size: var(--text-xs);
}

.blog-posts__more {
  display: inline-block;
  margin: var(--space-3) var(--space-5) var(--space-5);
  color: var(--color-accent);
  font-weight: var(--weight-semibold, 600);
  text-decoration: underline;
  text-underline-offset: 0.2em;
}

/* What follows the summary takes the card's last margin from it. */
.blog-posts__item > :is(.blog-posts__summary, .blog-posts__tags):has(+ :is(.blog-posts__tags, .blog-posts__more)) {
  margin-bottom: 0;
}

/* --- Blog posts: the newer styles, 2.219.0 ------------------------------- */
/* Kelly, 2026-10-06: "Featured + grid, Side by side, Masonry, Overlay and
   shelf". These are not boxed as Cards are: a picture with its words. */
:is(.blog-posts--featured, .blog-posts--side, .blog-posts--alternating, .blog-posts--masonry,
    .blog-posts--overlay, .blog-posts--overlay_shelf) .blog-posts__item {
  background: none;
  border-radius: 0;
  box-shadow: none;
  overflow: visible;
}

.blog-posts__body { display: flex; flex-direction: column; gap: var(--space-2); }
.blog-posts__body > * { margin: 0; }
.blog-posts__body > .blog-posts__more { align-self: flex-start; }

:is(.blog-posts--featured, .blog-posts--side, .blog-posts--alternating, .blog-posts--masonry) .blog-posts__image {
  border-radius: var(--radius-md);
}

.blog-posts__item:hover .blog-posts__title { text-decoration: underline; text-underline-offset: 0.15em; }

/* Featured and grid: the newest post wide, its picture beside its words;
   the rest in a grid under it. */
.blog-posts--featured {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
  gap: var(--space-7) var(--space-5);
}

.blog-posts--featured .blog-posts__item { display: flex; flex-direction: column; gap: var(--space-3); }
.blog-posts--featured .blog-posts__image { aspect-ratio: 3 / 2; }

.blog-posts--featured .blog-posts__item--lead {
  grid-column: 1 / -1;
  flex-flow: row wrap;
  align-items: center;
  gap: var(--space-5) var(--space-7);
}

.blog-posts--featured .blog-posts__item--lead .blog-posts__image { flex: 3 1 20rem; width: 0; min-width: min(20rem, 100%); }
.blog-posts--featured .blog-posts__item--lead .blog-posts__body { flex: 2 1 16rem; }
.blog-posts--featured .blog-posts__item--lead .blog-posts__title { font-size: var(--text-2xl); line-height: var(--leading-tight, 1.25); }

/* Side by side: one post to a row, the picture beside its words; turned
   about on every other row when alternating. Under each other where the
   row is too narrow for both. */
.blog-posts--side, .blog-posts--alternating { display: flex; flex-direction: column; gap: var(--space-7); }

:is(.blog-posts--side, .blog-posts--alternating) .blog-posts__item {
  display: flex;
  flex-flow: row wrap;
  align-items: center;
  gap: var(--space-4) var(--space-6);
}

.blog-posts--alternating .blog-posts__item:nth-child(even) { flex-direction: row-reverse; }
:is(.blog-posts--side, .blog-posts--alternating) .blog-posts__image { flex: 2 1 16rem; width: 0; min-width: min(16rem, 100%); aspect-ratio: 4 / 3; }
:is(.blog-posts--side, .blog-posts--alternating) .blog-posts__body { flex: 3 1 18rem; }
:is(.blog-posts--side, .blog-posts--alternating) .blog-posts__title { font-size: var(--text-xl); }

/* Masonry: columns of pictures at their own heights, read down each column. */
.blog-posts--masonry { columns: 3 15rem; column-gap: var(--space-5); }

.blog-posts--masonry .blog-posts__item {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  margin-bottom: var(--space-6);
  break-inside: avoid;
}

.blog-posts--masonry .blog-posts__image { aspect-ratio: auto; }

.blog-posts--masonry .blog-posts__item--no-picture {
  padding: var(--space-5);
  border-radius: var(--radius-md);
  background: var(--color-surface-sunken);
}

.blog-posts--masonry .blog-posts__item--no-picture .blog-posts__tag { background: var(--color-surface); }

/* Overlay: the words on the picture, over a fade to dark at its foot; a
   post without a picture on the site's accent colour. As a grid, or one
   row that scrolls sideways. */
.blog-posts--overlay {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(16rem, 1fr));
  gap: var(--space-4);
}

.blog-posts--overlay_shelf > .blog-posts__item { flex-basis: min(18rem, 80%); }

:is(.blog-posts--overlay, .blog-posts--overlay_shelf) .blog-posts__item {
  position: relative;
  display: flex;
  align-items: flex-end;
  aspect-ratio: 4 / 5;
  overflow: hidden;
  border-radius: calc(var(--radius-md) * 2);
  background: var(--color-accent);
  color: var(--color-accent-ink);
}

:is(.blog-posts--overlay, .blog-posts--overlay_shelf) .blog-posts__image {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  aspect-ratio: auto;
}

:is(.blog-posts--overlay, .blog-posts--overlay_shelf) .blog-posts__item:not(.blog-posts__item--no-picture) {
  color: var(--color-text-inverse);
}

:is(.blog-posts--overlay, .blog-posts--overlay_shelf) .blog-posts__item:not(.blog-posts__item--no-picture)::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(to top, rgba(0, 0, 0, 0.82) 0%, rgba(0, 0, 0, 0.5) 38%, rgba(0, 0, 0, 0) 68%);
}

:is(.blog-posts--overlay, .blog-posts--overlay_shelf) .blog-posts__body {
  position: relative;
  z-index: 1;
  width: 100%;
  padding: var(--space-5);
}

:is(.blog-posts--overlay, .blog-posts--overlay_shelf) :is(.blog-posts__summary, .blog-posts__details) {
  color: inherit;
  opacity: 0.88;
}

:is(.blog-posts--overlay, .blog-posts--overlay_shelf) .blog-posts__summary {
  display: -webkit-box;
  overflow: hidden;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 3;
}

:is(.blog-posts--overlay, .blog-posts--overlay_shelf) .blog-posts__tag { background: rgba(255, 255, 255, 0.2); }
:is(.blog-posts--overlay, .blog-posts--overlay_shelf) .blog-posts__more { color: inherit; }

/* --- Hero heading lines -------------------------------------------------- */
/* Five placements, not three. On a wide hero "left" and "far left" are
   different things: one sits at the text margin, the other at the edge. */

/* A subheading-sized line is body copy at heading rhythm, so it keeps the
   spacing of the lines around it rather than a paragraph's. */

/* --- The menu on a narrow screen ----------------------------------------- */
/* A drawer, not a stack of links pushed under the bar. The first version
   dropped the menu into the flow below the logo, so it overlapped what was
   already there and the links sat on whatever the hero was showing.

   A checkbox, not a script. A published page here runs no JavaScript at all,
   so a menu that needs it is a menu that opens in the editor and nowhere else.

   Two levels, one at a time: the top list, and a submenu that covers it with a
   Back row -- which is what a phone menu is expected to do, and what pushing a
   nested list down the page is not. */
.navbar__toggle { position: absolute; opacity: 0; pointer-events: none; }
.navbar__toggle-label { display: none; }

/* The phone drawer moved to editor.css, which loads after this file. Its
   `.navbar__menu { display: flex }` beat these rules at every width, so the
   menu never became a drawer and the hamburger did nothing -- the fourth
   fault from the same cause, after gallery spacing, the staggered display and
   the sticky bar's colour. Block layout belongs in the file that wins. */


/* On a wide screen the submenu is a dropdown and the Back row has no meaning:
   the panel closes by clicking away from it. */
@media (min-width: 48.0625rem) {
  .navbar__back { display: none; }
  .navbar__chevron { display: none; }
}

/* --- Social links --------------------------------------------------------- */
/* The icons are paths in the page, not an icon font and not a sprite from
   somewhere else: a published site should not ask a third party for its own
   furniture, and should not go blank when that third party has an outage. */
.social {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-4);
  margin: 0;
  padding: 0;
  list-style: none;
}

/* Five positions, because a footer is not always centred. The two middle
   ones are quarter points rather than flex keywords, which offer nothing
   between "start" and "center": the row is pushed by a margin instead.

   Vertically centred against whatever shares the line, which is what `align`
   on the row does for it. */
.social { align-items: center; }
.social--left { justify-content: flex-start; }
.social--center { justify-content: center; }
.social--right { justify-content: flex-end; }

.social--left_center {
  justify-content: flex-start;
  margin-left: 25%;
}

.social--right_center {
  justify-content: flex-end;
  margin-right: 25%;
}

/* On a phone the quarter points collapse to the ends: a quarter of a narrow
   screen is not a position, it is a squeeze. */
@media (max-width: 30rem) {
  .social--left_center { margin-left: 0; }
  .social--right_center { margin-right: 0; }
}

.social__link {
  display: flex;
  align-items: center;
  justify-content: center;
  /* A full touch target whatever the icon inside it measures. */
  width: 2.75rem;
  height: 2.75rem;
  color: inherit;
  border-radius: 50%;
  text-decoration: none;
}

.social__link:hover { background: var(--color-surface-sunken); }

.social__link:focus-visible {
  outline: 2px solid var(--color-accent);
  outline-offset: 2px;
}

/* currentColor, so the icons follow the theme and whatever colour the block
   they sit in has set. */
.social__icon { width: 1.5rem; height: 1.5rem; fill: currentColor; }

.social--small .social__icon { width: 1.125rem; height: 1.125rem; }
.social--large .social__icon { width: 2rem; height: 2rem; }

.social__heading { margin-bottom: var(--space-4); }

/* In a footer the row sits under the rest with a little air, rather than
   crowding the copyright line. */
.site-footer .social { margin-bottom: var(--space-4); }

/* 2.355.0. The template viewer's "Show me more fonts": its packs under
   the button, the button gone once it is open. */
.preview-looks__more { margin-top: var(--space-3); }
.preview-looks__more > summary { list-style: none; cursor: pointer; }
.preview-looks__more > summary::-webkit-details-marker { display: none; }
.preview-looks__more[open] > summary { display: none; }

/* 2.351.0. The footer's Icon color and Hover color, where chosen. */
.social--painted .social__link { color: var(--social-color); }
.social--hover-painted .social__link:hover { color: var(--social-hover); }

/* --- Settings dialog and form fields ------------------------------------- */
/* Written out rather than left to the framework's defaults. A form rendered by
   `as_p` puts a sentence in a single-line box and a checkbox above its own
   label -- and the shape of a field is an instruction to whoever fills it in,
   whether or not anybody meant it as one. */
.settings-dialog {
  width: min(38rem, calc(100vw - var(--space-6)));
  max-height: 85vh;
  padding: 0;
  border: 0;
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-lg);
  color: var(--color-text);
  background: var(--color-surface);
}

.settings-dialog::backdrop { background: rgba(15, 23, 42, 0.45); }

.settings {
  display: flex;
  flex-direction: column;
  max-height: 85vh;
  overflow: auto;
  padding: var(--space-6);
  gap: var(--space-6);
}

.settings__group {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
}

.settings__heading {
  margin: 0;
  padding-bottom: var(--space-2);
  border-bottom: 1px solid var(--color-border);
  font-size: var(--text-sm);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--color-text-muted);
}

.settings__loading { padding: var(--space-6); color: var(--color-text-muted); }

/* The actions stay put while the fields scroll: a Save button below the fold
   of a long form is a Save button people hunt for. */
.settings__actions {
  position: sticky;
  bottom: calc(var(--space-6) * -1);
  display: flex;
  gap: var(--space-3);
  padding: var(--space-4) 0 0;
  margin-top: auto;
  background: var(--color-surface);
  border-top: 1px solid var(--color-border);
}

/* A field, and the button that offers to write it. */
.field__control { display: flex; align-items: flex-start; gap: var(--space-2); }
.field__control > input,
.field__control > textarea,
.field__control > select { flex: 1 1 auto; min-width: 0; }

.field__control textarea { resize: vertical; min-height: 4.5rem; }

.field__suggest { flex: 0 0 auto; align-self: flex-start; }
.field__suggest[aria-busy="true"] { opacity: 0.6; cursor: progress; }

.field__check { display: flex; align-items: center; gap: var(--space-2); }

/* Two or three choices on one line, wrapping to their own when the panel is
   narrow. A radio group stacked vertically for two short options reads as a
   list of unrelated things rather than one decision. */
.field__choices {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2) var(--space-5);
  margin-top: var(--space-1);
}
.field__error { color: var(--color-danger); font-size: var(--text-xs); }

/* 2.242.0. A tick-several list in a dialog (Team's Roles and Site(s)): the
   label heads it, the choices wrap beside one another. */
.field__ticks { margin: 0; padding: 0; border: 0; min-width: 0; }
.field__ticks > div {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2) var(--space-5);
  margin-top: var(--space-1);
}
.field__ticks label { display: flex; align-items: center; gap: var(--space-2); }

/* --- The search result preview ------------------------------------------ */
/* Shown, not counted. "58 of 60 characters" asks somebody to imagine the
   result; the point is that they should not have to. */
.serp {
  padding: var(--space-4);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  background: var(--color-surface-sunken);
  font-family: arial, sans-serif;
  max-width: 38rem;
}

.serp__crumbs {
  margin: 0;
  font-size: 12px;
  line-height: 1.3;
  color: var(--serp-url);
}

.serp__title {
  margin: var(--space-1) 0 0;
  font-size: 20px;
  line-height: 1.3;
  color: var(--serp-title);
}

.serp__description {
  margin: var(--space-1) 0 0;
  font-size: 14px;
  line-height: 1.58;
  color: var(--serp-text);
}

.serp__missing { color: var(--color-text-muted); font-style: italic; }

.serp__note {
  margin: var(--space-2) 0 0;
  font-size: var(--text-xs);
  color: var(--color-text-muted);
}

.serp__note--warning { color: var(--color-warning); }

/* What a suggestion button is doing, or why it did not. Beside the field it
   was pressed for, because a message at the top of a long screen is a message
   about a field somebody has scrolled away from. */
.field__note {
  margin: var(--space-1) 0 0;
  font-size: var(--text-xs);
  color: var(--color-text-muted);
}

/* --- Choosing a page on the visibility screen ---------------------------- */
/* Every page named, one page's fields shown. Forty forms on one screen is a
   screen nobody reaches the end of, and the Save for the page somebody is
   looking at was thousands of pixels from the field they had just changed. */
.seo-pages__nav {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin-bottom: var(--space-5);
  padding-bottom: var(--space-4);
  border-bottom: 1px solid var(--color-border);
}

.seo-pages__tab {
  padding: var(--space-2) var(--space-3);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  text-decoration: none;
  color: var(--color-text);
  font-size: var(--text-sm);
}

.seo-pages__tab:hover { background: var(--color-surface-sunken); }

.seo-pages__tab--current {
  background: var(--color-button);
  border-color: var(--color-button);
  color: var(--color-text-inverse);
}

/* Which pages still say nothing, without opening each one. */
.seo-pages__flag { color: var(--color-warning); font-weight: 700; }
.seo-pages__tab--current .seo-pages__flag { color: inherit; }

/* --- Drafting a template ------------------------------------------------- */
/* The worked examples. A good brief is long, and nobody guesses that from a
   placeholder, so one is shown rather than described. */
.examples { margin: var(--space-4) 0; }
.examples > summary { cursor: pointer; color: var(--color-accent); }

.examples__body {
  display: grid;
  gap: var(--space-4);
  margin-top: var(--space-4);
}

.examples__item {
  padding: var(--space-4);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  background: var(--color-surface-sunken);
}

.examples__name { margin: 0 0 var(--space-1); font-size: var(--text-md); }
.examples__summary { margin: 0 0 var(--space-3); color: var(--color-text-muted); }

.examples__brief {
  margin: 0 0 var(--space-3);
  font-size: var(--text-sm);
  line-height: 1.6;
  white-space: pre-wrap;
}

/* 2.202.0. What an example sets on the form, above its words. */
.examples__choices {
  display: grid;
  grid-template-columns: max-content 1fr;
  gap: var(--space-1) var(--space-3);
  margin: 0 0 var(--space-3);
  font-size: var(--text-sm);
}
.examples__choices dt { color: var(--color-text-muted); }
.examples__choices dd { margin: 0; }

/* 2.202.0. The drafting form's choices: the pages, and the palettes and font
   groups as cards to pick from. The chosen personality's group is listed
   first and marked Recommended (draft-form.ts sets data-recommended). */
.draft-form [hidden] { display: none; }
.draft-form__hint { color: var(--color-text-muted); font-size: var(--text-sm); }
.draft-form__other { margin-top: var(--space-3); }

.draft-form__pages {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(11rem, 1fr));
  gap: var(--space-2) var(--space-4);
  margin-top: var(--space-1);
}
/* A category's own pages, in the grid with the rest. */
.draft-form__extras { display: contents; }

.draft-form__groups {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  margin-top: var(--space-1);
}
.draft-form__group[data-recommended] { order: -1; }
.draft-form__group-name {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin: 0 0 var(--space-2);
  font-size: var(--text-sm);
}
.draft-form__recommended { display: none; }
.draft-form__group[data-recommended] .draft-form__recommended { display: inline-flex; }

.palette-cards,
.font-cards {
  display: grid;
  gap: var(--space-3);
}
.palette-cards { grid-template-columns: repeat(auto-fill, minmax(8.5rem, 1fr)); }
.font-cards { grid-template-columns: repeat(auto-fill, minmax(13rem, 1fr)); }

.palette-card,
.font-card {
  display: flex;
  flex-direction: column;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  background: var(--color-surface);
  cursor: pointer;
}
.palette-card { gap: var(--space-2); padding: var(--space-2); }
.font-card { gap: var(--space-1); padding: var(--space-3); }
.palette-card:has(input:checked),
.font-card:has(input:checked) {
  border-color: var(--color-accent);
  box-shadow: 0 0 0 2px var(--color-accent);
}
.palette-card:has(input:focus-visible),
.font-card:has(input:focus-visible) {
  outline: 2px solid var(--color-accent);
  outline-offset: 2px;
}

.palette-card__swatches {
  display: flex;
  height: 2.5rem;
  overflow: hidden;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
}
.palette-card__swatches > span { flex: 1; }
.palette-card__name { font-size: var(--text-sm); }

.font-card__name {
  margin-bottom: var(--space-1);
  color: var(--color-text-muted);
  font-size: var(--text-xs);
}
.font-card__eyebrow { font-size: 0.7rem; letter-spacing: 0.12em; text-transform: uppercase; }
.font-card__heading { font-size: 1.35rem; font-weight: 700; line-height: 1.2; }
.font-card__subheading { font-size: 1rem; }
.font-card__text { font-size: 0.875rem; }

/* --- The nav bar's rows and zones (2.203.0) ------------------------------ */
/* Here rather than in editor.css since 2.208.0: the drafting form arranges
   the bar too, and it is not an editor screen. Moved as they were, less
   three colour fallbacks: this file holds tokens only, and both tokens
   are defined in tokens.css, so the fallbacks were never used. */
.nav-arrangement { display: flex; flex-direction: column; gap: var(--space-3); }
.nav-arrangement__rows {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  margin: 0;
  padding: 0;
  border: 0;
}
.nav-arrangement__rows legend { float: left; margin: 0 var(--space-2) 0 0; padding: 0; }
.nav-arrangement__row-choice { display: inline-flex; align-items: center; gap: var(--space-1); font-size: var(--text-sm); }
.nav-arrangement__grid { display: flex; flex-direction: column; gap: var(--space-3); }
.nav-arrangement__row { display: flex; gap: var(--space-2); align-items: stretch; }
.nav-arrangement__row-name {
  flex: none;
  width: 3.25rem;
  padding-top: 1.4rem;
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
  color: var(--color-text-muted);
}
.nav-arrangement__zone-column { flex: 1 1 0; min-width: 0; display: flex; flex-direction: column; }
.nav-arrangement__zone-name {
  margin: 0 0 var(--space-1);
  font-size: 0.6875rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--color-text-muted);
}
.nav-arrangement__zone {
  flex: 1 1 auto;
  min-height: 2.75rem;
  display: flex;
  flex-wrap: wrap;
  align-content: flex-start;
  gap: var(--space-1);
  padding: var(--space-1);
  border: 1px dashed var(--color-border-strong);
  border-radius: var(--radius-sm);
  background: var(--color-surface-sunken);
}
.nav-arrangement__zone--over { border-color: var(--color-accent); background: color-mix(in srgb, var(--color-accent) 8%, transparent); }
.nav-arrangement__chip {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  min-height: 1.9rem;
  padding: 0 var(--space-2);
  border: 1px solid var(--color-text-muted);
  border-radius: var(--radius-sm);
  background: var(--color-surface);
  color: var(--color-text);
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  cursor: grab;
  user-select: none;
}
.nav-arrangement__chip:focus-visible { outline: 2px solid var(--color-focus-ring); outline-offset: 1px; }
.nav-arrangement__chip--half { border-style: dashed; }
.nav-arrangement__chip--dragging { opacity: 0.5; }
.nav-arrangement__merge {
  min-width: 1.25rem;
  min-height: 1.25rem;
  padding: 0;
  border: 0;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--color-text-muted);
  font: inherit;
  line-height: 1;
  cursor: pointer;
}
.nav-arrangement__merge:hover { background: var(--color-surface-sunken); color: var(--color-text); }

/* 2.208.0. The drafting form's nav bar designer, and its home page heroes
   with the example each opens. */
.draft-form__nav-design {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  margin-top: var(--space-3);
  padding: var(--space-3);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  background: var(--color-surface);
}
.draft-form__nav-design > select { max-width: 16rem; }
.draft-form__nav-rows { margin-top: var(--space-2); }

.hero-cards {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(13rem, 1fr));
  gap: var(--space-3);
  margin-top: var(--space-1);
}
.hero-card {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  padding: var(--space-3);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  background: var(--color-surface);
}
.hero-card:has(input:checked) {
  border-color: var(--color-accent);
  box-shadow: 0 0 0 2px var(--color-accent);
}
.hero-card:has(input:focus-visible) {
  outline: 2px solid var(--color-accent);
  outline-offset: 2px;
}
.hero-card__pick { display: flex; flex: 1; flex-direction: column; gap: var(--space-1); cursor: pointer; }
.hero-card__name { font-weight: var(--weight-semibold); }
.hero-card__text { color: var(--color-text-muted); font-size: var(--text-sm); }
.hero-card__example { align-self: flex-start; }

/* 2.209.0. Each design drawn small: the example page at a computer's width,
   scaled to a fifth, so its picture sits where it does on a desktop. */
.hero-card__picture {
  position: relative;
  display: block;
  height: 8rem;
  overflow: hidden;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  background: var(--color-surface-sunken);
}
.hero-card__picture iframe {
  width: 500%;
  height: 40rem;
  border: 0;
  transform: scale(0.2);
  transform-origin: top left;
  /* The tile is the choice; a frame that took the click would not choose. */
  pointer-events: none;
}

/* 2.209.0. Kelly: the two design sections stand out, and a note at the top. */
.draft-form__section-title {
  font-size: var(--text-md);
  font-weight: 700;   /* Kelly: bold, so it stands out. No bold token. */
}
.draft-form__note {
  margin: 0 0 var(--space-4);
  padding: var(--space-3) var(--space-4);
  border-left: 3px solid var(--color-accent);
  border-radius: var(--radius-sm);
  background: var(--color-surface-sunken);
  font-size: var(--text-sm);
}

/* 2.209.0. "Create a template", folded until it is wanted: the panel's own
   head is the thing to click, with a chevron that turns. */
.create-template { margin-bottom: var(--space-5); }
.create-template__head { cursor: pointer; list-style: none; }
.create-template__head::-webkit-details-marker { display: none; }
.create-template:not([open]) > .create-template__head { border-bottom: 0; }
.create-template__head .panel__title { margin-right: auto; }
.create-template__hint::after {
  content: "";
  display: inline-block;
  width: 0.55rem;
  height: 0.55rem;
  border-right: 2px solid var(--color-text-muted);
  border-bottom: 2px solid var(--color-text-muted);
  transform: rotate(45deg);
  transition: transform var(--transition-fast);
}
.create-template[open] .create-template__hint::after { transform: rotate(-135deg); }
.create-template__head:focus-visible { outline: 2px solid var(--color-accent); outline-offset: 2px; }

.dialog.hero-example { width: min(72rem, calc(100vw - var(--space-6))); }

/* 2.214.0. The Plans screen's sections and rows are dragged into order by
   the handle beside their names (plan-order.js). The handle sits in a table
   heading, so it is set back to the page's own type rather than the
   heading's small capitals. The status says what the last drop saved, in
   the corner of the window, since the drop may be far down the page. */
/* 2.218.0: and the document libraries' handles (sort-order.js). */
.plans-grid__handle,
.sort-handle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.75rem;
  height: 1.75rem;
  margin-right: var(--space-2);
  padding: 0;
  font: inherit;
  font-size: 1.1rem;
  line-height: 1;
  text-transform: none;
  letter-spacing: normal;
  color: var(--color-text-muted);
  background: transparent;
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  cursor: grab;
  touch-action: none;
  vertical-align: middle;
}
.plans-grid__handle:hover,
.sort-handle:hover {
  color: var(--color-text);
  border-color: var(--color-border-strong);
}
.plans-grid__handle:focus-visible,
.sort-handle:focus-visible {
  outline: 2px solid var(--color-focus-ring);
  outline-offset: 1px;
}
.plans-grid--dragging,
.plans-grid--dragging .plans-grid__handle,
.sort--dragging,
.sort--dragging .sort-handle {
  cursor: grabbing;
  user-select: none;
}
.plans-grid .is-dragged > tr > *,
.plans-grid tr.is-dragged > *,
.sort--dragging tr.is-dragged > *,
.sort--dragging div.is-dragged {
  background: var(--color-surface-sunken);
  box-shadow: inset 0 0 0 1px var(--color-accent);
}
/* 2.224.0. A plan's product code, edited under its name. */
.plans-grid__code {
  margin-top: var(--space-1);
  font-family: var(--font-mono, ui-monospace, monospace);
  font-size: var(--text-sm);
}

.plans-grid__status,
.sort-status {
  position: fixed;
  right: var(--space-5);
  /* Above the fixed footer bar: the room the body keeps for it, and a gap. */
  bottom: calc(var(--space-7) + var(--space-2) + var(--space-3));
  z-index: 61;
  max-width: 28rem;
  margin: 0;
  padding: var(--space-3) var(--space-4);
  font-size: var(--text-sm);
  color: var(--color-text);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-lg);
}
.plans-grid__status:empty,
.sort-status:empty {
  opacity: 0;
  pointer-events: none;
}
.plans-grid__status--error,
.sort-status--error {
  color: var(--color-danger);
  border-color: var(--color-danger);
}

/* 2.209.0. The Plan page: one tile per plan, cheapest first. Every tile lists
   every feature in the same order with rows of one height, so a row reads
   across the tiles. The plan the site is on is the one raised and marked. */
.plan-tiles {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(17rem, 1fr));
  gap: var(--space-5);
  align-items: start;
  margin-top: var(--space-6);
}
/* 2.397.0. Kelly, 2026-11-01: "the descriptions need to all have the same
   height so that they align vertically". Each tile is a head and a body on
   two of the row's lines (subgrid; it was a flex column), so the heads of
   one row are as tall as the tallest; the summary takes the rest, and every
   price and button sits at the same height. */
.plan-tile {
  position: relative;
  display: grid;
  grid-row: span 2;
  grid-template-rows: subgrid;
  row-gap: 0;
  align-self: stretch;
  padding: var(--space-5);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  background: var(--color-surface);
  box-shadow: var(--shadow-sm);
}
.plan-tile--current {
  border: 2px solid var(--color-accent);
  box-shadow: var(--shadow-lg);
}
.plan-tile__flag {
  position: absolute;
  top: 0;
  left: 50%;
  transform: translate(-50%, -50%);
  margin: 0;
  padding: var(--space-1) var(--space-3);
  border-radius: 999px;
  background: var(--color-accent);
  color: var(--color-surface);
  font-size: var(--text-sm);
  font-weight: var(--weight-semibold);
  white-space: nowrap;
}
.plan-tile__head { display: flex; flex-direction: column; gap: var(--space-2); }
.plan-tile__name {
  margin: 0;
  font-size: var(--text-2xl);
  font-weight: var(--weight-semibold);
  letter-spacing: -0.01em;
}
.plan-tile__summary {
  min-height: 4.2em;
  flex: 1;
  margin: 0;
  color: var(--color-text-muted);
  font-size: var(--text-sm);
  line-height: 1.4;
}
.plan-tile__action { margin: var(--space-2) 0 var(--space-4); }
.plan-tile__here {
  border-color: var(--color-border);
  background: var(--color-surface-sunken);
  color: var(--color-text-muted);
  cursor: default;
}
.plan-tile--current .plan-tile__here {
  border-color: var(--color-accent);
  color: var(--color-accent);
  background: var(--color-surface);
}
.plan-tile__limits {
  margin: 0 0 var(--space-3);
  padding: var(--space-3) 0;
  border-top: 1px solid var(--color-border);
  border-bottom: 1px solid var(--color-border);
}
.plan-tile__limit {
  display: flex;
  justify-content: space-between;
  gap: var(--space-3);
  padding: 2px 0;
  font-size: var(--text-sm);
}
.plan-tile__limit dt { color: var(--color-text-muted); }
.plan-tile__limit dd {
  margin: 0;
  font-weight: var(--weight-semibold);
  font-variant-numeric: tabular-nums;
}
.plan-tile__group {
  margin: var(--space-3) 0 var(--space-1);
  font-size: var(--text-sm);
  font-weight: var(--weight-semibold);
}
.plan-tile__features { margin: 0; padding: 0; list-style: none; }
.plan-tile__feature {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  min-height: 1.75rem;
  font-size: var(--text-sm);
}
.plan-tile__label { overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
.plan-tile__mark {
  flex: none;
  width: 1.1rem;
  font-weight: var(--weight-semibold);
  color: var(--color-success);
  text-align: center;
}
.plan-tile__feature--off { color: var(--color-text-muted); }
.plan-tile__feature--off .plan-tile__mark { color: var(--color-border-strong); }
.plan-request {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  margin-top: var(--space-4);
  padding: var(--space-3) var(--space-4);
  border: 1px solid var(--color-accent);
  border-radius: var(--radius-md);
  background: var(--color-accent-subtle);
}
.plan-request__text { margin: 0; font-size: var(--text-sm); }
/* 2.227.0. The site's billing at a glance, folding (Kelly: "collapsable"):
   the light blue box the trial sentence and the monthly/yearly switch sat
   in, with the rows above them. */
.billing-summary {
  margin-top: var(--space-4);
  padding: var(--space-3) var(--space-4);
  border: 1px solid var(--color-accent);
  border-radius: var(--radius-md);
  background: var(--color-accent-subtle);
}
.billing-summary__head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--space-1) var(--space-3);
  cursor: pointer;
}
.billing-summary__title { font-weight: var(--weight-semibold, 600); }
.billing-summary__glance { color: var(--color-text-muted); font-size: var(--text-sm); }
.billing-summary__glance .badge { margin-left: var(--space-2); }
.billing-summary[open] > .billing-summary__head { margin-bottom: var(--space-3); }
.billing-summary__rows {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(8.5rem, 1fr));
  gap: var(--space-3) var(--space-4);
  margin: 0;
}
.billing-summary__row { min-width: 0; }
.billing-summary__row dt { color: var(--color-text-muted); font-size: var(--text-xs); }
.billing-summary__row dd { margin: 2px 0 0; font-size: var(--text-sm); overflow-wrap: anywhere; }
/* 2.227.0. A table wider than a phone scrolls inside its panel rather than
   widening the page. */
.table-scroll { overflow-x: auto; }
/* The customer's sites' billing: its own page since 2.228.0 (Billing, beside
   My templates and AI), above the Sites list in 2.227.0. */
.customer-billing { margin: 0 0 var(--space-4); }
.customer-billing .table th,
.customer-billing .table td { padding: var(--space-2) var(--space-3); font-size: var(--text-sm); }
.customer-billing .table { background: var(--color-surface); border-radius: var(--radius-sm); }
.deleted-sites { margin-top: var(--space-4); }
/* 2.235.0. Folded until clicked: the heading is the summary, with its
   disclosure triangle, and opening it shows Show local time and the list. */
.deleted-sites__summary { display: list-item; cursor: pointer; }
.deleted-sites__tools {
  display: flex;
  justify-content: flex-end;
  padding: var(--space-3) var(--space-5) 0;
}
/* Each row's site named in a row header: read as the row's name, not as a
   column's heading. */
.customer-billing .table tbody th,
.deleted-sites .table tbody th {
  font-size: inherit;
  font-weight: var(--weight-medium);
  text-transform: none;
  letter-spacing: normal;
  color: var(--color-text);
  background: none;
}
.customer-billing .table tbody th { padding: var(--space-2) var(--space-3); }
.customer-billing .table tbody tr:last-child th,
.deleted-sites .table tbody tr:last-child th { border-bottom: none; }
.billing-summary .plan-request {
  margin-top: var(--space-3);
  padding: var(--space-3) 0 0;
  border: 0;
  border-top: 1px solid var(--color-accent);
  border-radius: 0;
  background: none;
}
/* 2.222.0. Monthly or yearly, changed during the free trial. */
.plan-cadence { display: flex; align-items: center; gap: var(--space-3); }
.plan-cadence__choices {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  margin: 0;
  padding: 0;
  border: 0;
  font-size: var(--text-sm);
}
.plan-cadence__choices legend { float: left; margin: 0 var(--space-2) 0 0; padding: 0; }
.plan-note { margin-top: var(--space-5); color: var(--color-text-muted); font-size: var(--text-sm); }
.plan-move__heading { margin: var(--space-3) 0 var(--space-1); font-size: var(--text-sm); }
/* 2.240.0. A plan's price, above its button and in the switch dialog. */
.plan-tile__price,
.plan-move__price { margin: var(--space-2) 0; text-align: center; font-size: var(--text-sm); font-variant-numeric: tabular-nums; }
.plan-move__list { margin: 0 0 var(--space-3); padding-left: var(--space-5); font-size: var(--text-sm); }

/* 2.209.0. QA testing's switch: green while QA is live, red while it is off,
   as Kelly drew it on the Domains screen. */
.qa-switch { display: inline-flex; }
.qa-switch__button { color: var(--color-surface); border-color: transparent; }
.qa-switch__button--on { background: var(--color-success); }
.qa-switch__button--off { background: var(--color-danger); }
.qa-switch__button:hover { filter: brightness(0.92); }
.qa-switch__button:focus-visible { outline: 2px solid var(--color-focus-ring); outline-offset: 2px; }
.publish-stage__qa-switch {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
  margin: var(--space-3) 0;
}
.publish-stage__qa-switch .publish-stage__meta { margin: 0; }
/* 2.209.0. The addresses QA may be seen from. */
.qa-allowed { max-width: 32rem; margin: var(--space-3) 0; }
.qa-allowed__state { margin: 0 0 var(--space-2); font-size: var(--text-sm); font-weight: var(--weight-medium); }
.qa-allowed .field { margin-bottom: var(--space-2); }

/* 2.287.0. The Domains screen's two sections, QA and Production. */
.domains-section { margin-top: var(--space-6); }
.domains-section__title { margin: 0; font-size: var(--text-lg); }
.domains-section__subhead { border-top: 1px solid var(--color-border); }
/* 2.409.0. Find a domain, through Name.com. */
.domains-find { margin: var(--space-4) 0; }
.domains-find__label { display: block; margin-bottom: var(--space-2); }
.domains-find__row { display: flex; gap: var(--space-2); max-width: 32rem; }
.domains-find__row input { flex: 1; min-width: 0; }
.domains-find__results { margin: var(--space-3) 0 var(--space-2); max-width: 40rem; }

/* 2.209.0. The Domains screen's opening words. */
.domains-intro__lead { margin: 0 0 var(--space-2); }
.domains-intro__ways { margin: 0 0 var(--space-3); padding-left: var(--space-6); }
.domains-intro__ways li { margin-bottom: var(--space-2); }
.domains-intro__note { margin: 0; }

/* 2.209.0. Brand settings: the tab icon as a browser tab draws it, and large. */
.brand-icon {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-5);
  margin-bottom: var(--space-4);
}
.brand-icon__tab {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  min-width: 14rem;
  max-width: 100%;
  padding: var(--space-2) var(--space-4);
  border: 1px solid var(--color-border);
  border-bottom: 0;
  border-radius: var(--radius-md) var(--radius-md) 0 0;
  background: var(--color-surface-sunken);
  font-size: var(--text-sm);
}
.brand-icon__image,
.brand-icon__blank { width: 16px; height: 16px; flex: none; object-fit: contain; }
.brand-icon__blank { border: 1px dashed var(--color-border-strong); border-radius: 3px; }
.brand-icon__title { overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
.brand-icon__large {
  width: 64px;
  height: 64px;
  object-fit: contain;
  padding: var(--space-2);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  background: var(--color-surface);
}
[data-brand-icon] .settings + .settings,
[data-brand-icon] .settings + form { margin-top: var(--space-4); }
.hero-example__body { padding: var(--space-4) var(--space-5); }
.hero-example__frame {
  display: block;
  width: 100%;
  height: min(40rem, 68vh);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  background: var(--color-surface);
}

.draft-form__words { margin: var(--space-4) 0; }
.draft-form__words > summary { cursor: pointer; color: var(--color-accent); }

.preview-hint {
  margin: 0 0 var(--space-3);
  color: var(--color-text-muted);
  font-size: var(--text-sm);
}

/* Two related buttons that belong beside each other, in a row that otherwise
   spreads what it holds. */
.panel__actions { display: flex; gap: var(--space-2); }

/* A customer's own templates, above the platform's. */
.template-section {
  margin: var(--space-6) 0 var(--space-4);
  font-size: var(--text-sm);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--color-text-muted);
}

/* --- Two columns, list beside form --------------------------------------- */
/* What somebody has made, beside the way to make another. A list placed after
   the form is a list nobody sees until they have scrolled past everything
   they were not looking for. */
.two-columns {
  display: grid;
  gap: var(--space-5);
  align-items: start;
  grid-template-columns: minmax(0, 3fr) minmax(0, 2fr);
}

/* One column below the fold: two narrow columns on a phone is two things too
   narrow to read. */
@media (max-width: 60rem) {
  .two-columns { grid-template-columns: 1fr; }
  /* The form first there, because a screen with nothing on it yet should open
     on the thing that fills it. */
  .two-columns__side { order: -1; }
}

/* The field no person can see. Positioned off the page rather than
   `display: none`: a script that skips hidden inputs still fills this one,
   which is the entire point of it. */
.block-form__trap {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

/* Where a page anchor lands.
   The console header is sticky, so an anchor scrolled to the very top of the
   viewport ends up underneath it -- which is why clicking a page button took
   the buttons off screen and left somebody scrolling back up to click the
   next one. The margin holds the target below the header, with a little air
   so it does not sit flush against it. */
[id="pages"] {
  scroll-margin-top: calc(var(--header-height) + var(--space-4));
}

/* Said while it matters, and gone once it does not. The polling script sets
   the state on the wrapper, so this needs no script of its own -- and a
   warning that outlives the thing it warns about is one people stop reading. */
.job:not([data-job-state="running"]) .job__warning { display: none; }

.job__warning {
  margin: var(--space-3) 0 0;
  font-size: var(--text-sm);
  color: var(--color-warning);
}

/* --- Composing an email --------------------------------------------------- */
.email-block {
  padding: var(--space-3);
  margin-bottom: var(--space-3);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  background: var(--color-surface);
}

/* Which block a chosen picture will land in. Without a mark, clicking the
   library is a guess. */
.email-block--current { border-color: var(--color-accent); }

.email-block__head {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin-bottom: var(--space-2);
}

.email-block__head strong { flex: 1 1 auto; }

.email-block label { display: block; margin-bottom: var(--space-2); }
.email-block input,
.email-block textarea { width: 100%; }

.email-block__add {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin-top: var(--space-3);
}

.email-library {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(72px, 1fr));
  gap: var(--space-2);
}

.email-library__item {
  padding: 0;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  background: none;
  cursor: pointer;
  overflow: hidden;
  aspect-ratio: 1;
}

.email-library__item img { width: 100%; height: 100%; object-fit: cover; }
.email-library__item:hover { border-color: var(--color-accent); }

/* The real message in a frame, not a drawing of it. */
.email-preview {
  width: 100%;
  height: 480px;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  background: var(--color-canvas);
}

/* --- Gallery display ------------------------------------------------------ */
/* Moved to editor.css, which loads after this file: `.gallery` there sets a
   gap with the same weight, so these never applied and the spacing control did
   nothing at all. */

/* Staggered: a column flow, so photographs of different shapes keep their
   proportions instead of being cropped to match each other. */
/* Staggered had no effect at all: `.gallery[data-columns="3"]` in editor.css
   sets `grid-template-columns`, and it both loads later and matches with the
   same weight -- so the grid kept its rows aligned and the column flow never
   applied. These carry the attribute too, and `display` is overridden on the
   same terms rather than hoped to win.

   A column flow rather than a grid, so photographs of different heights sit
   under each other instead of leaving a gap to the next row. */
.gallery--staggered[data-columns="2"],
.gallery--staggered[data-columns="3"],
.gallery--staggered[data-columns="4"],
.gallery--staggered {
  display: block;
  grid-template-columns: none;
  /* No column-gap here: the spacing choice sets it in editor.css, and a
     default in this file beat it -- so "Space between" moved the gap under
     each picture and never the gap beside it. */
}

/* The counts moved to editor.css with the rest of the gallery layout. */

.gallery--staggered .gallery__item {
  break-inside: avoid;
  margin: 0 0 var(--space-4);
}

.gallery--staggered .gallery__item img { width: 100%; height: auto; }

/* A slideshow, scrolled rather than scripted: a published page runs no
   JavaScript, and scroll-snap does what a carousel does without any. */
.gallery--slideshow {
  display: flex;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  column-count: initial;
}

.gallery--slideshow .gallery__item {
  flex: 0 0 min(80%, 32rem);
  scroll-snap-align: center;
}

/* Full screen through `:target`. The link marks a picture as the target and
   this shows it; closing points at the gallery, which unsets it. No script,
   which is the constraint every published page here works under. */
.gallery__full {
  display: none;
  position: fixed;
  inset: 0;
  z-index: 90;
  align-items: center;
  justify-content: center;
  flex-direction: column;
  gap: var(--space-3);
  padding: var(--space-5);
  background: var(--lightbox-backdrop);
}

.gallery__full:target { display: flex; }

.gallery__full img {
  max-width: 100%;
  max-height: 80vh;
  object-fit: contain;
}

.gallery__full-caption {
  margin: 0;
  color: var(--lightbox-ink);
  font-size: var(--text-sm);
}

.gallery__close {
  position: absolute;
  top: var(--space-4);
  right: var(--space-5);
  /* A full touch target, and large enough to find without hunting. */
  width: 2.75rem;
  height: 2.75rem;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.75rem;
  line-height: 1;
  color: var(--lightbox-ink);
  text-decoration: none;
}

.gallery__open { display: block; cursor: zoom-in; }

/* Where closing a full-screen picture lands. The tile that was clicked, so
   somebody comes back to what they were looking at rather than to the end of
   the gallery -- and clear of a sticky nav bar, which would otherwise cover
   the picture they just returned to. */
.gallery__item { scroll-margin-top: var(--space-8); }

/* --- Cookie notice -------------------------------------------------------- */
/* Along the bottom, over the page rather than pushing it: a banner that moves
   the content somebody came to read is a banner that costs them their place. */
.cookie-notice {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 80;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-4);
  padding: var(--space-4) var(--space-5);
  background: var(--color-text);
  color: var(--color-surface);
  box-shadow: 0 -2px 12px rgba(15, 23, 42, 0.18);
}

.cookie-notice[hidden] { display: none; }

.cookie-notice__text {
  flex: 1 1 20rem;
  margin: 0;
  font-size: var(--text-sm);
  line-height: 1.5;
}

.cookie-notice__text a { color: inherit; text-decoration: underline; }

.cookie-notice__actions {
  display: flex;
  gap: var(--space-2);
  flex: 0 0 auto;
}

/* On a phone the buttons take the width, because a thumb reaching a small
   button at the bottom of a screen is a thumb that misses. */
@media (max-width: 30rem) {
  .cookie-notice__actions { flex: 1 1 100%; }
  .cookie-notice__actions .btn { flex: 1 1 auto; }
}

/* The same banner, shown inside a panel rather than over the screen. */
.cookie-notice--preview {
  position: static;
  box-shadow: none;
  border-radius: var(--radius-sm);
}

/* The backdrop, as a link back to the tile. Anywhere on the darkness closes
   the picture, which is most of the screen and what somebody expects. Behind
   the picture and the X, so clicking either still does its own thing. */
.gallery__dismiss {
  position: absolute;
  inset: 0;
  z-index: 0;
  display: block;
}

.gallery__full img,
.gallery__full-caption,
.gallery__close { position: relative; z-index: 1; }

/* A traceback, folded. It is what somebody wants second, and twenty of them
   open at once is a list nobody can read. */
.log-detail > summary {
  cursor: pointer;
  font-size: var(--text-sm);
  color: var(--color-text-muted);
}

.log-detail pre {
  margin: var(--space-2) 0 0;
  padding: var(--space-3);
  overflow-x: auto;
  font-size: var(--text-sm);
  background: var(--color-canvas);
  border-radius: var(--radius-sm);
}

/* --- The help ------------------------------------------------------------ */
/* Prose, which is a different job from every panel above: one column at a
   readable measure, a contents list beside it on a wide screen and above it on
   a narrow one, and headings that separate rather than decorate. */

.help-crumbs {
  display: flex;
  gap: var(--space-2);
  align-items: baseline;
  margin-bottom: var(--space-3);
  font-size: var(--text-sm);
  color: var(--color-text-muted);
}

/* The topic first, the contents after it. On a wide screen the contents
   becomes a sidebar on the right; on a phone it stacks below, which is where a
   contents list belongs when somebody has already chosen what to read. */
.help-layout {
  display: grid;
  gap: var(--space-6);
  align-items: start;
}

@media (min-width: 60rem) {
  .help-layout {
    grid-template-columns: minmax(0, 1fr) 15rem;
  }
}

/* A measure, not a column width. The app's reading column is 1200px, which is
   right for a table of sites and about twice as wide as a paragraph should be
   before the eye loses the start of the next line. */
.help-body { max-width: 44rem; }

.help-body > h2 {
  margin: var(--space-6) 0 var(--space-2);
  padding-top: var(--space-4);
  border-top: 1px solid var(--color-border);
}

.help-body > h3 { margin: var(--space-4) 0 var(--space-1); }
/* 2.387.0. What's New: a release's date beside its version. */
.whats-new__date {
  margin-left: var(--space-2);
  font-size: var(--text-sm);
  font-weight: 400;
  color: var(--color-text-muted);
}
.help-body p,
.help-body li { line-height: 1.65; }
.help-body ul,
.help-body ol { margin: var(--space-2) 0; padding-left: var(--space-5); }
.help-body li { margin-bottom: var(--space-1); }

.help-body code {
  padding: 1px 4px;
  font-size: 0.9em;
  background: var(--color-canvas);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
}

/* A term and what it means. A table would be tidier and would wrap badly on a
   phone, where most of a definition is the part that matters. */
.help-terms { margin: var(--space-3) 0; }
.help-terms dt { font-weight: 600; margin-top: var(--space-3); }
.help-terms dd { margin: 2px 0 0; color: var(--color-text-muted); line-height: 1.6; }
.help-terms--tight dt { margin-top: var(--space-2); }

.help-contents {
  position: sticky;
  top: var(--space-6);
  padding: var(--space-3);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
}

/* 2.426.1. Kelly, with her picture: "when I scroll down, the top of the help
   desk search is cut off". The header sticks at the top too, 56px tall, so
   the contents stuck 32px down sat under it. Below the header where there is
   one; in the help panel, which has none, as before. */
body:has(.app-header) .help-contents {
  top: calc(var(--header-height) + var(--space-6));
}

.help-contents__title {
  font-size: var(--text-sm);
  font-weight: 600;
  color: var(--color-text-muted);
  margin-bottom: var(--space-2);
}

.help-contents__list {
  margin: 0;
  padding-left: var(--space-4);
  font-size: var(--text-sm);
  line-height: 1.5;
}

.help-contents__list li { margin-bottom: var(--space-2); }

.help-contents__list a[aria-current="page"] {
  font-weight: 600;
  color: var(--color-text);
  text-decoration: none;
}

/* The index. Numbered, because the order is the recommendation. */
.help-index { margin: 0 0 var(--space-6); padding: 0; list-style: none; }
.help-index__item { margin-bottom: var(--space-2); }

.help-index__link {
  display: flex;
  gap: var(--space-3);
  align-items: baseline;
  padding: var(--space-3);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  text-decoration: none;
  color: inherit;
}

.help-index__link:hover { border-color: var(--color-accent); }

.help-index__number {
  min-width: 1.5rem;
  font-variant-numeric: tabular-nums;
  color: var(--color-text-muted);
}

.help-index__text { display: flex; flex-direction: column; gap: 2px; }
.help-index__title { font-weight: 600; }

.help-index__summary {
  font-size: var(--text-sm);
  color: var(--color-text-muted);
  line-height: 1.5;
}

/* Where to go next, at the foot of every topic. Two links, the second pushed
   right, so "next" is where the eye already is. */
.help-onwards {
  display: flex;
  justify-content: space-between;
  gap: var(--space-3);
  margin-top: var(--space-6);
  padding-top: var(--space-4);
  border-top: 1px solid var(--color-border);
}

.help-onwards__link {
  display: flex;
  flex-direction: column;
  gap: 2px;
  text-decoration: none;
  color: inherit;
}

.help-onwards__link--next { text-align: right; margin-left: auto; }
.help-onwards__where { font-size: var(--text-sm); color: var(--color-text-muted); }
.help-onwards__title { font-weight: 600; }

/* The block reference's group jumps, and one entry per block. */
.help-jump {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin: var(--space-3) 0 var(--space-4);
  font-size: var(--text-sm);
}

.help-block {
  margin-bottom: var(--space-4);
  padding-bottom: var(--space-3);
  border-bottom: 1px solid var(--color-border);
}

.help-block:last-child { border-bottom: 0; }
.help-block__name { margin: 0 0 2px; }
.help-block__what { margin: 0; color: var(--color-text-muted); line-height: 1.6; }

/* --- The site menu ------------------------------------------------------- */
/* Everywhere one site can be worked on, behind one control. Built on
   `details` like the nav block's dropdowns and the document navigator: it
   opens by click and by keyboard and needs no script, so it cannot be a menu
   that fails to open because a bundle did not load.

   The same component on the sites row and in the builder's bar. It replaced
   eleven buttons in a table cell, which wrapped to three lines on a laptop and
   still had three whole areas missing from it. */
.site-menu {
  position: relative;
  display: inline-block;
}

.site-menu__button {
  list-style: none;
  /* A summary is not a button, so it needs the affordances one has. */
  cursor: pointer;
  user-select: none;
}

.site-menu__button::-webkit-details-marker { display: none; }

/* Pointing down closed, up open — the one piece of state the control has. */
.site-menu__chevron {
  width: 0;
  height: 0;
  border-left: 4px solid transparent;
  border-right: 4px solid transparent;
  border-top: 5px solid currentColor;
  transition: transform var(--transition-fast);
}

.site-menu[open] .site-menu__chevron { transform: rotate(180deg); }

.site-menu[open] .site-menu__button {
  background: var(--color-surface-sunken);
}

/* Over the page, not in it. In a table cell a panel in the flow would push
   every row below it down by its own height as it opened.

   2.230.0. Its four groups side by side, a column each, as Kelly's picture
   has them (Kelly: "group the dropdown elements and give the user a Layout
   (like we have now in our Nav) to show all the options available"), where
   it was one column of nineteen. Each column is as wide as its words, and a
   note wraps rather than widening its column. The site menu's script moves
   the panel sideways to stay inside the window. */
.site-menu__panel {
  position: absolute;
  z-index: 40;
  top: calc(100% + 4px);
  right: 0;
  display: grid;
  /* 2.235.0: five, with Publishing a column of its own (Kelly). */
  grid-template-columns: repeat(5, max-content);
  gap: var(--space-4) var(--space-7);
  width: max-content;
  max-width: calc(100vw - 2rem);
  /* 2.402.0. The script fits it to the room above or below its button
     (`fitHeight`); this is the most it may be without the script. */
  max-height: calc(100vh - 2rem);
  overflow-y: auto;
  padding: var(--space-4) var(--space-5) var(--space-5);
  text-align: left;
  background: var(--color-surface);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
}

.site-menu__group { min-width: 0; }

/* 2.402.0. Opened upward, where there is more room above its button. */
.site-menu__panel--up {
  top: auto;
  bottom: calc(100% + 4px);
}
/* And floated inside the window when neither above nor below holds it; the
   script sets where. */
.site-menu__panel--float {
  position: fixed;
  bottom: auto;
}

/* Narrower than five columns of words: three (2.235.0), then two, then one
   on a phone. */
@media (max-width: 68rem) {
  .site-menu__panel { grid-template-columns: repeat(3, max-content); }
}
@media (max-width: 56rem) {
  .site-menu__panel { grid-template-columns: repeat(2, max-content); }
}
@media (max-width: 36rem) {
  .site-menu__panel { grid-template-columns: minmax(0, 1fr); width: calc(100vw - 2rem); }
}

/* Bold and as written, as her picture has them. */
.site-menu__heading {
  margin-bottom: var(--space-1);
  /* 2.402.0. A size smaller (Kelly: "make the text a bit smaller in the
     dropdown"); it was --text-md. */
  font-size: var(--text-base);
  font-weight: var(--weight-semibold);
  line-height: 1.3;
  color: var(--color-text);
}

/* Flush with its heading; the hover reaches a little past the words. */
.site-menu__link {
  display: block;
  margin: 0 calc(-1 * var(--space-1));
  padding: 2px var(--space-1);
  border-radius: var(--radius-sm);
  text-decoration: none;
  color: inherit;
}

.site-menu__link:hover,
.site-menu__link:focus-visible {
  background: var(--color-surface-sunken);
}

.site-menu__label {
  display: block;
  font-size: var(--text-base);
  line-height: 1.3;
}

/* What the thing is, small and set in under its name. A menu of fourteen
   bare nouns is a menu people read once and then guess at -- and "Client
   galleries" is not a guess anybody makes correctly. */
.site-menu__note {
  display: block;
  max-width: 10rem;
  padding-left: var(--space-3);
  font-size: var(--text-xs);
  line-height: 1.35;
  color: var(--color-text-muted);
}

/* The two that stay out of the menu, and the menu, on one line. */
.row-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  align-items: center;
}

/* --- The console's grouped navigation ------------------------------------ */
/* 2.169.0. The header carried nine bare links and four screens on none of
   them. The same control as the site menu, so the console has one idea of
   what a menu is: a `details`, opening by click and by keyboard, with the
   screens under it named and explained. */
.nav-menu {
  position: relative;
  display: inline-block;
}

.nav-menu__button {
  display: flex;
  align-items: center;
  gap: var(--space-1);
  list-style: none;
  cursor: pointer;
  user-select: none;
  color: var(--color-text-muted);
  font-weight: var(--weight-medium);
}

.nav-menu__button::-webkit-details-marker { display: none; }

.nav-menu__button:hover,
.nav-menu[open] .nav-menu__button {
  color: var(--color-text);
}

/* Pointing down closed, up open -- the one piece of state the control has. */
.nav-menu__chevron {
  width: 0;
  height: 0;
  border-left: 4px solid transparent;
  border-right: 4px solid transparent;
  border-top: 5px solid currentColor;
  transition: transform var(--transition-fast);
}

.nav-menu[open] .nav-menu__chevron { transform: rotate(180deg); }

/* Over the page rather than in it: in a sticky header a panel in the flow
   would push the page down by its own height as it opened. */
.nav-menu__panel {
  position: absolute;
  z-index: 40;
  top: calc(100% + 10px);
  right: 0;
  width: 21rem;
  max-height: 70vh;
  overflow-y: auto;
  padding: var(--space-2);
  text-align: left;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-lg);
}

.nav-menu__link {
  display: block;
  padding: var(--space-2);
  border-radius: var(--radius-sm);
  text-decoration: none;
  color: inherit;
}

.nav-menu__link:hover,
.nav-menu__link:focus-visible {
  background: var(--color-surface-sunken);
  text-decoration: none;
}

.nav-menu__label {
  display: block;
  font-weight: var(--weight-medium);
  line-height: 1.3;
}

.nav-menu__note {
  display: block;
  margin-top: 1px;
  font-size: var(--text-sm);
  line-height: 1.4;
  color: var(--color-text-muted);
}

/* --- What needs attention ------------------------------------------------ */
/* 2.169.0. On both dashboards: the short list of things that want somebody,
   each with the screen that deals with it. Above the counts, because a count
   is the same number whether everything is fine or nothing is. */
.attention {
  list-style: none;
  margin: 0;
  padding: 0;
}

.attention__item {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
  border-top: 1px solid var(--color-border);
}

.attention__item:first-child { border-top: 0; }

/* A dot rather than a word: the colour carries the same thing the tone does,
   and the words beside it say what it is -- so nothing here depends on
   telling two colours apart. */
.attention__mark {
  flex: none;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--color-text-muted);
}

.attention__item--warn .attention__mark { background: var(--color-warning); }

.attention__words {
  flex: 1;
  min-width: 0;
}

.attention__label {
  display: block;
  font-weight: var(--weight-medium);
  line-height: 1.3;
}

.attention__detail {
  display: block;
  margin-top: 2px;
  font-size: var(--text-sm);
  line-height: 1.4;
  color: var(--color-text-muted);
}

.attention__clear {
  margin: 0;
  color: var(--color-text-muted);
}

/* --- Shortcuts ----------------------------------------------------------- */
/* The console's screens on the Overview, in the groups the header uses, each
   saying what it is. A menu is for somebody who knows what they want; this is
   for somebody who does not. */
.shortcuts {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
  gap: var(--space-3);
  padding: var(--space-4);
}

.shortcut {
  display: block;
  padding: var(--space-3);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  color: inherit;
  text-decoration: none;
  transition: border-color var(--transition-fast), background var(--transition-fast);
}

.shortcut:hover,
.shortcut:focus-visible {
  background: var(--color-surface-sunken);
  border-color: var(--color-accent);
  text-decoration: none;
}

.shortcut__label {
  display: block;
  font-weight: var(--weight-medium);
  line-height: 1.3;
}

.shortcut__note {
  display: block;
  margin-top: 2px;
  font-size: var(--text-sm);
  line-height: 1.4;
  color: var(--color-text-muted);
}

/* --- Support tickets, 2.175.0 ---------------------------------------------
   The conversation on a ticket: the customer's turns on one side, support's
   on the other, and the things that happened to the ticket between them as
   a quiet line. Muted colours because a thread of twenty turns in accent
   colour is a wall. */
.thread {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}

.thread__item {
  max-width: 44rem;
  padding: var(--space-3) var(--space-4);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md, 8px);
  background: var(--color-surface);
}

.thread__item--org,
.thread__item--platform { align-self: flex-end; background: var(--color-surface-sunken); }

.thread__item--event {
  align-self: center;
  max-width: none;
  padding: var(--space-1) var(--space-3);
  border: 0;
  background: none;
  text-align: center;
}

.thread__who {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--space-2);
  font-size: var(--text-sm);
  color: var(--color-text-muted);
}

.thread__who strong { color: var(--color-text); }

.thread__body { margin-top: var(--space-2); }
.thread__body p:last-child { margin-bottom: 0; }
/* 2.178.0: files on a message. */
.thread__files { list-style: none; margin: var(--space-2) 0 0; padding: 0; display: flex; flex-wrap: wrap; gap: var(--space-2) var(--space-4); font-size: var(--text-sm); }
.thread__files li { display: inline-flex; gap: var(--space-1); align-items: baseline; }
.thread__files a::before { content: "\1F4CE\00A0"; }

/* --- Analytics (2.200.0) ------------------------------------------------- */
/* A bar per day, drawn by the server. The SVG stretches to the panel's width;
   its height is fixed, so a short range gives wide bars and a year thin ones. */
.analytics-chart {
  display: block;
  margin-block: var(--space-4);
}

.analytics-chart rect {
  fill: var(--color-accent);
}

/* --- The online store: Settings › Online store. 2.215.0 ------------------ */
/* Its three tabs, drawn as the SEO screen's page switcher is. */
.store-tabs {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin-bottom: var(--space-5);
  padding-bottom: var(--space-4);
  border-bottom: 1px solid var(--color-border);
}
.store-tabs__tab {
  padding: var(--space-2) var(--space-4);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  text-decoration: none;
  color: var(--color-text);
  font-size: var(--text-sm);
}
.store-tabs__tab:hover { background: var(--color-surface-sunken); }
.store-tabs__tab--current {
  background: var(--color-button);
  border-color: var(--color-button);
  color: var(--color-text-inverse);
}
/* 2.321.0. The current tab keeps its own colours under the pointer, a shade
   darker, as a primary button does. The plain hover above is more specific
   than `--current` and turned it white on light grey. */
.store-tabs__tab--current:hover {
  background: var(--color-accent-hover);
  border-color: var(--color-accent-hover);
}

.store-form { display: flex; flex-direction: column; gap: var(--space-5); }
.store-form > .panel { margin: 0; }
.store-form__fields { display: flex; flex-direction: column; gap: var(--space-4); }
.store-form__pair,
.store-rates__row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr));
  gap: var(--space-4);
}
.store-rates { display: flex; flex-direction: column; gap: var(--space-3); }
/* 2.284.0. How a profile charges, and each rate's boxes for it. */
.store-charges { border: 0; margin: 0; padding: 0; display: grid; gap: var(--space-2); min-width: 0; }
.store-rates__block {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  padding-bottom: var(--space-3);
  border-bottom: 1px solid var(--color-border);
}
.store-rates__block:last-child { border-bottom: 0; padding-bottom: 0; }
.store-rates__bands { display: flex; flex-direction: column; gap: var(--space-3); }
.store-unweighed { border-left: 3px solid var(--color-warning); padding-left: var(--space-3); }
.store-form__actions { display: flex; flex-wrap: wrap; gap: var(--space-3); }
.store-form input[type="number"],
.store-form input[type="file"] { max-width: 100%; }
.store-form ul[id$="status"],
.store-form ul[id$="photo_mode"] { list-style: none; margin: 0; padding: 0; }
.store-variants input { width: 100%; min-width: 5rem; }
.store-tax-notes {
  margin: 0;
  padding-left: var(--space-5);
  font-size: var(--text-sm);
  color: var(--color-text-muted);
}
.store-add { display: flex; flex-wrap: wrap; gap: var(--space-2); }
.store-categories { list-style: none; margin: 0 0 var(--space-4); padding: 0; }
.store-categories li {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  padding: var(--space-2) 0;
  border-bottom: 1px solid var(--color-border);
}
.store-inline { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-3); }
.store-delete { margin-top: var(--space-5); }

/* --- Online store: product lines, versions and photos (2.237.0) ----------- */
/* A control's "i": a <details>, opened without a script. */
.store-tip { position: relative; display: inline-block; font-size: var(--text-sm); font-weight: normal; }
.store-tip__button {
  list-style: none;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.5rem;
  height: 1.5rem;
  border: 1px solid var(--color-border-strong);
  border-radius: 50%;
  color: var(--color-text-muted);
  font-style: italic;
  font-weight: var(--weight-semibold);
}
.store-tip__button::-webkit-details-marker { display: none; }
.store-tip[open] .store-tip__button { border-color: var(--color-accent); color: var(--color-accent); }
.store-tip__body {
  position: absolute;
  z-index: 20;
  right: 0;
  top: calc(100% + var(--space-2));
  width: min(26rem, 80vw);
  margin: 0;
  padding: var(--space-3) var(--space-4);
  background: var(--color-surface);
  color: var(--color-text);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  box-shadow: 0 6px 20px rgba(0, 0, 0, 0.12);
}
.store-tip__body dt { font-weight: var(--weight-semibold); margin-top: var(--space-2); }
.store-tip__body dt:first-child { margin-top: 0; }
.store-tip__body dd { margin: 0; color: var(--color-text-muted); }
.store-form__tipped { display: flex; align-items: flex-start; gap: var(--space-2); }
.store-form__tipped > .field { flex: 1; }
.store-form__tipped > .store-tip { margin-top: 1.6rem; }

/* The photo picker: the chosen photos in order, then the library. A button
   the script hides stays hidden, over .btn's own display. */
.photo-picker [hidden],
.store-choices [hidden],
[data-choice-add][hidden] { display: none; }
.photo-picker { display: flex; flex-direction: column; gap: var(--space-2); }
.photo-picker__chosen { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: var(--space-3); }
/* 2.265.0. Upload photos, and what it did, on one line. */
.photo-picker__upload { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-3); }
.photo-picker__upload[hidden] { display: none; }
.photo-picker__item {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  width: 9rem;
  padding: var(--space-2);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  background: var(--color-surface);
  cursor: grab;
}
.photo-picker__item:first-child { border-color: var(--color-accent); }
.photo-picker__item img,
.photo-picker__thumb img { width: 100%; aspect-ratio: 1; object-fit: cover; border-radius: var(--radius-sm); }
.photo-picker__name { font-size: var(--text-xs); color: var(--color-text-muted); overflow-wrap: anywhere; }
.photo-picker__moves { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-1); }
.photo-picker__moves .btn { padding: var(--space-1) var(--space-2); }
.photo-picker__remove { font-size: var(--text-xs); display: inline-flex; align-items: center; gap: var(--space-1); }
.photo-picker__library summary { cursor: pointer; color: var(--color-accent); }
.photo-picker__search { display: block; margin: var(--space-2) 0; width: min(20rem, 100%); }
.photo-picker__grid {
  list-style: none;
  margin: var(--space-2) 0 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(7rem, 1fr));
  gap: var(--space-2);
}
.photo-picker__thumb label { display: flex; flex-direction: column; gap: var(--space-1); cursor: pointer; }
.photo-picker__thumb label:focus-visible { outline: 2px solid var(--color-focus-ring); outline-offset: 2px; }

/* Versions: one row each, with their photos in a row below when set so. */
.store-variants__remove { text-align: center; }
.store-variants__photos td { background: var(--color-surface-sunken); }
.store-variants__photos summary { cursor: pointer; }
/* Add versions and Change several at once are forms of their own, below
   the product's. */
[data-store-add-versions],
[data-store-change-versions] { margin-top: var(--space-5); }
.store-group__choice { border: 1px solid var(--color-border); border-radius: var(--radius-md); padding: var(--space-3); margin: 0; }
.store-group__choice legend { font-weight: var(--weight-semibold); padding: 0 var(--space-1); }
.store-group__value { display: inline-flex; align-items: center; gap: var(--space-1); margin-right: var(--space-4); }

/* The menu: categories, their product lines under them. */
.store-menu > li { display: block; }
.store-menu__row { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--space-3); }
.store-menu__actions { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); }
.store-menu__lines { list-style: none; margin: var(--space-2) 0 0; padding: 0 0 0 var(--space-5); }
.store-menu__lines > li { border-bottom: 0; padding: var(--space-1) 0; }
.store-move { display: inline; }
.store-products__line th { background: var(--color-surface-sunken); text-align: left; font-weight: var(--weight-semibold); }

/* A product line's choices, one row each. */
.store-choices { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--space-3); }
.store-choices__row { display: grid; grid-template-columns: minmax(8rem, 1fr) minmax(12rem, 2fr) 5.5rem; gap: var(--space-3); align-items: end; }
.store-choices__moves { display: flex; gap: var(--space-1); }
.store-form + .panel { margin-top: var(--space-5); }
@media (max-width: 40rem) {
  .store-choices__row { grid-template-columns: 1fr; }
}
.store-line-products { margin: 0; padding-left: var(--space-6); }

/* --- Online store: the Shop Designer's steps and look, examples (2.282.0) -- */
.sd-steps { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-3); margin-bottom: var(--space-3); }
.sd-steps__list { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: var(--space-2); }
.sd-steps__step {
  padding: var(--space-1) var(--space-3);
  border: 1px solid var(--color-border-strong);
  border-radius: 999px;
  background: var(--color-surface);
  color: inherit;
  font: inherit;
  cursor: pointer;
}
.sd-look { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-3); }
.sd-look__toggle { display: inline-flex; align-items: center; gap: var(--space-1); }
.rx__examples { margin-bottom: var(--space-3); }
.rx__example-list { list-style: none; margin: var(--space-3) 0 0; padding: 0; display: grid; grid-template-columns: repeat(auto-fill, minmax(14rem, 1fr)); gap: var(--space-3); }
.rx__example { padding: var(--space-3); border: 1px solid var(--color-border); border-radius: var(--radius-md); display: flex; flex-direction: column; gap: var(--space-2); }
.rx__example p { margin: 0; }
.rx__example-summary { font-weight: 600; }

/* --- Online store: a picture's Main star and what it is shown for (2.281.0) - */
.photo-picker__marks { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); }
.photo-picker__main, .photo-picker__for { display: inline-flex; align-items: center; gap: var(--space-1); }
.photo-picker__for select { max-width: 14rem; }

/* --- Online store: a department's filters (2.280.0) ------------------------ */
.store-filters { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(auto-fill, minmax(12rem, 1fr)); gap: var(--space-2); }
.store-filters label { display: flex; align-items: center; gap: var(--space-2); }

/* --- Online store: a line's recipe, as the buyer sees it (2.279.0) --------- */
.rx { display: grid; grid-template-columns: minmax(0, 3fr) minmax(0, 2fr); gap: var(--space-4); align-items: start; }
.rx__summary { margin: 0 0 var(--space-3); font-weight: 600; }
.rx__shop, .rx__panel {
  padding: var(--space-4);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  min-width: 0;
}
.rx__panel { background: var(--color-surface-sunken); }
.rx__preview { display: flex; align-items: center; gap: var(--space-2); font-size: 0.9rem; }
.rx__picture {
  aspect-ratio: 4 / 3;
  max-width: 100%;
  border-radius: var(--radius-md);
  background: var(--color-surface-sunken);
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  color: var(--color-text-muted);
}
.rx__picture img { width: 100%; height: 100%; object-fit: cover; }
.rx__title { margin: 0; font-weight: 600; }
.rx__row { display: grid; gap: var(--space-1); padding: var(--space-2); border-radius: var(--radius-md); }
.rx__row.is-focus { outline: 2px solid var(--color-border-strong); outline-offset: 0; }
.rx__label { font-weight: 600; font-size: 0.9rem; }
.rx__label small { font-weight: 400; margin-left: var(--space-2); }
.rx__pills { display: flex; flex-wrap: wrap; gap: var(--space-2); }
.rx__pill {
  padding: var(--space-1) var(--space-3);
  border: 1px solid var(--color-border-strong);
  border-radius: 999px;
  background: var(--color-surface);
  color: inherit;
  font: inherit;
  cursor: pointer;
}
.rx__pill[aria-pressed="true"] { border-width: 2px; font-weight: 600; }
.rx__pill--off { text-decoration: line-through; opacity: 0.6; }
.rx__pill--add { border-style: dashed; }
.rx__add { align-self: flex-start; }
.rx__eyebrow { margin: 0; font-size: 0.8rem; text-transform: uppercase; letter-spacing: 0.05em; }
.rx__version { margin: 0; }
.rx__price { margin: 0; font-size: 1.5rem; font-weight: 600; }
.rx__edit, .rx__value { display: flex; flex-direction: column; gap: var(--space-2); }
.rx__actions { display: flex; flex-wrap: wrap; gap: var(--space-2); }
.rx__check { display: flex; align-items: center; gap: var(--space-2); }
.rx input[aria-invalid="true"] { border-color: var(--color-danger); }
@media (max-width: 48rem) {
  .rx { grid-template-columns: minmax(0, 1fr); }
}

/* --- Online store: a category's menu, sales (2.238.0) --------------------- */
.store-menu-order { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--space-2); }
.store-menu-order [hidden] { display: none; }
.store-menu-order__row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  padding: var(--space-2) var(--space-3);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
}
.store-menu-order__row--line { background: var(--color-surface-sunken); }
.store-menu-order__label { display: inline-flex; align-items: center; gap: var(--space-2); }
.store-menu-order__moves { display: flex; gap: var(--space-1); }
.store-variants__sale td { background: var(--color-surface-sunken); }
.store-variants__sale summary { cursor: pointer; }
.store-variants__dates { display: flex; flex-wrap: wrap; gap: var(--space-4); margin: var(--space-2) 0; }
.store-variants__dates label { display: inline-flex; align-items: center; gap: var(--space-2); }

/* --- Online store: payments and orders (2.216.0) --------------------------- */
.store-form ul[id$="delivered_mode"],
.store-form ul[id$="replies_to"] { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--space-2); }
.store-payments__state { margin-top: 0; }
.store-payments__actions { display: flex; flex-wrap: wrap; gap: var(--space-3); margin-top: var(--space-4); }
.store-steps { margin: 0 0 var(--space-4); padding-left: var(--space-5); display: grid; gap: var(--space-3); }
.store-steps ul { margin: var(--space-2) 0 0; padding-left: var(--space-5); }
.store-steps code, [data-stripe-platform] code { overflow-wrap: anywhere; }

.store-orders__bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  margin-bottom: var(--space-4);
}
.store-filter { display: flex; flex-wrap: wrap; gap: var(--space-2); }
.store-filter__item {
  padding: var(--space-1) var(--space-3);
  border: 1px solid var(--color-border);
  border-radius: 999px;
  color: var(--color-text);
  text-decoration: none;
  font-size: var(--text-sm);
}
.store-filter__item--current { border-color: var(--color-accent); color: var(--color-accent); font-weight: var(--weight-semibold); }
.store-orders td { vertical-align: top; }
.store-orders .badge { margin-left: var(--space-2); }
.store-pages { display: flex; gap: var(--space-2); padding: var(--space-4); }

.store-order__head {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-4);
  margin-bottom: var(--space-4);
}
.store-order__title { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); margin: 0; font-size: var(--text-xl); }
.store-order__grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(18rem, 1fr)); gap: var(--space-4); }
.store-order__totals p { display: flex; justify-content: space-between; margin: 0 0 var(--space-2); font-variant-numeric: tabular-nums; }
.store-order__address { margin-top: var(--space-3); }
.store-ship__items { border: 0; margin: 0; padding: 0; display: grid; gap: var(--space-2); }
.store-ship__items legend { font-weight: var(--weight-semibold); margin-bottom: var(--space-2); }
.store-ship__item { display: flex; gap: var(--space-2); align-items: center; margin-bottom: var(--space-2); }
.store-message { padding: var(--space-3) 0; border-bottom: 1px solid var(--color-border); }
.store-message--inbound { padding-left: var(--space-3); border-left: 3px solid var(--color-accent); }
.store-message p { margin: 0 0 var(--space-1); }
.store-message__subject { font-weight: var(--weight-semibold); }

/* The packing slip: plain, for a printer. */
.packing-slip { background: var(--color-surface); color: var(--color-text); padding: 0; }
.packing-slip__page { max-width: 44rem; margin: 0 auto; padding: var(--space-6) var(--space-5); font-size: 1rem; }
.packing-slip__head { display: flex; justify-content: space-between; align-items: baseline; border-bottom: 2px solid var(--color-text); margin-bottom: var(--space-5); }
.packing-slip__head h1 { margin: 0 0 var(--space-2); font-size: 1.5rem; }
.packing-slip__to h2 { font-size: 1rem; margin: 0 0 var(--space-2); }
.packing-slip__items { width: 100%; border-collapse: collapse; margin-top: var(--space-5); }
.packing-slip__items th, .packing-slip__items td { text-align: left; padding: var(--space-2); border-bottom: 1px solid var(--color-border-strong); }
.packing-slip__thanks { margin-top: var(--space-6); }
/* A button at the foot of a column of fields keeps its own width. */
.store-form__fields > .btn { align-self: flex-start; }

/* --- Online store: shipping profiles (2.239.0) ----------------------------- */
.store-profiles { margin: 0 0 var(--space-3); padding-left: var(--space-5); display: grid; gap: var(--space-1); }
/* 2.292.0. Settings › Helpdesk: what stops it running, and who may open a ticket. */
.helpdesk-checks { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--space-2); }
.helpdesk-checks li { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--space-2); }
.helpdesk-who { border: 0; margin: 0; padding: 0; display: grid; gap: var(--space-2); }
.helpdesk-who label { display: flex; align-items: center; gap: var(--space-2); }

/* 2.294.0. The support desk on the site's own address. */
.helpdesk-desk { max-width: 72rem; }
.helpdesk-desk .page-head { flex-wrap: wrap; }
.helpdesk-desk .page-head__actions { flex-wrap: wrap; }
.helpdesk-desk__tabs { display: flex; gap: var(--space-3); margin: 0 0 var(--space-3); }
.helpdesk-desk__tabs a[aria-current="page"] { font-weight: var(--weight-semibold); text-decoration: underline; }
.helpdesk-desk__scroll { overflow-x: auto; }

/* 2.368.0. A help desk's figures (components/_desk_figures.html): the cards,
   then the tickets opened each month as columns, then the same months as a
   table with their averages. The columns are drawn from the count alone, each
   a share of the tallest month. */
.desk-figures { display: grid; gap: var(--space-5); }
.desk-figures__months .panel__meta { font-size: var(--text-xs); color: var(--color-text-muted); }
.desk-figures__scroll { overflow-x: auto; margin-top: var(--space-5); }
.desk-figures__month { font-weight: var(--weight-semibold); white-space: nowrap; }
.desk-chart {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  gap: var(--space-2);
  height: 13rem;
}
.desk-chart__column {
  display: grid;
  grid-template-rows: auto minmax(0, 1fr) auto;
  justify-items: center;
  gap: var(--space-1);
  min-width: 0;
}
.desk-chart__track {
  display: flex;
  align-items: flex-end;
  justify-content: center;
  width: 100%;
  height: 100%;
  border-bottom: 1px solid var(--color-border);
}
.desk-chart__bar {
  display: block;
  width: min(100%, 2.5rem);
  min-height: 2px;
  background: var(--color-accent);
  border-radius: var(--radius-sm) var(--radius-sm) 0 0;
}
.desk-chart__count { font-size: var(--text-xs); font-variant-numeric: tabular-nums; color: var(--color-text-muted); }
.desk-chart__label { font-size: var(--text-xs); color: var(--color-text-muted); }

/* 2.369.0. The satisfaction survey: the person's page (surveys/answer.html),
   five ratings as large rows, best first; and the desk's Survey screen's
   panels, each rating's bar coloured from good to poor. */
.survey-form { display: grid; gap: var(--space-4); margin-top: var(--space-4); }
.survey-form__ratings { border: 0; margin: 0; padding: 0; display: grid; gap: var(--space-2); }
.survey-form__rating {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  cursor: pointer;
}
.survey-form__rating:hover { border-color: var(--color-border-strong); }
.survey-form__rating:has(input:checked) { border-color: var(--color-accent); background: var(--color-surface-sunken); }
.survey-form__rating:has(input:focus-visible) { outline: 2px solid var(--color-accent); outline-offset: 2px; }
.survey-form__rating input { margin: 0; }
.survey-form__number {
  display: inline-grid;
  place-items: center;
  width: 2rem;
  height: 2rem;
  border-radius: 999px;
  background: var(--color-surface-sunken);
  font-weight: var(--weight-semibold);
  font-variant-numeric: tabular-nums;
}
.survey-tabs { margin-top: calc(-1 * var(--space-1)); }
.survey-scroll { overflow-x: auto; }
.survey-panels { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 22rem), 1fr)); gap: var(--space-5); }
.survey-bars { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--space-3); }
.survey-bars li { display: grid; grid-template-columns: minmax(9rem, 14rem) minmax(0, 1fr) 2.5rem; align-items: center; gap: var(--space-3); }
.survey-bars__label { font-size: var(--text-sm); }
.survey-bars__track { height: 0.75rem; border-radius: 999px; background: var(--color-surface-sunken); overflow: hidden; }
.survey-bars__bar { display: block; height: 100%; border-radius: 999px; background: var(--color-accent); }
.survey-bars__bar--5 { background: var(--color-success); }
.survey-bars__bar--4 { background: color-mix(in srgb, var(--color-success) 60%, var(--color-surface)); }
.survey-bars__bar--3 { background: color-mix(in srgb, var(--color-warning) 70%, var(--color-surface)); }
.survey-bars__bar--2 { background: color-mix(in srgb, var(--color-danger) 65%, var(--color-surface)); }
.survey-bars__bar--1 { background: var(--color-danger); }
.survey-bars__count { font-variant-numeric: tabular-nums; text-align: right; }
.survey-filter { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2) var(--space-3); margin-bottom: var(--space-4); }
.survey-filter .field__input { width: auto; }
.survey-score {
  display: inline-grid;
  place-items: center;
  min-width: 1.75rem;
  height: 1.75rem;
  border-radius: 999px;
  color: var(--color-surface);
  font-weight: var(--weight-semibold);
}
.survey-score--5 { background: var(--color-success); }
.survey-score--4 { background: color-mix(in srgb, var(--color-success) 80%, var(--color-text)); }
.survey-score--3 { background: var(--color-warning); }
.survey-score--2 { background: color-mix(in srgb, var(--color-danger) 80%, var(--color-warning)); }
.survey-score--1 { background: var(--color-danger); }
.survey-result { display: grid; grid-template-columns: max-content minmax(0, 1fr); gap: var(--space-2) var(--space-5); margin: 0 0 var(--space-4); }
.survey-result dt { font-weight: var(--weight-semibold); color: var(--color-text-muted); }
.survey-result dd { margin: 0; }
.survey-result__comment { white-space: normal; }
@media (max-width: 40rem) {
  .survey-bars li { grid-template-columns: minmax(0, 1fr) 2.5rem; }
  .survey-bars__track { grid-column: 1 / -1; grid-row: 2; }
  .survey-result { grid-template-columns: 1fr; }
}
.helpdesk-desk__ticket { display: grid; grid-template-columns: minmax(0, 1fr) 18rem; gap: var(--space-5); align-items: start; }
.helpdesk-desk__subject { margin: 0 0 var(--space-1); text-wrap: balance; }
.helpdesk-desk__side { display: grid; gap: var(--space-4); }
.helpdesk-desk__details { display: grid; gap: var(--space-1); }
.helpdesk-desk__details .btn { margin-top: var(--space-2); justify-self: start; }
.helpdesk-desk__answers { margin: 0; display: grid; gap: var(--space-1); }
.helpdesk-desk__answers dt { font-weight: var(--weight-semibold); font-size: var(--text-sm); }
.helpdesk-desk__answers dd { margin: 0 0 var(--space-2); overflow-wrap: anywhere; }
.helpdesk-desk__answers-title { font-size: var(--text-md); margin: 0; }
.helpdesk-thread__message--note { border-style: dashed; background: var(--color-surface-sunken); }
.helpdesk-reply__actions { display: flex; flex-wrap: wrap; gap: var(--space-2); }
@media (max-width: 52rem) {
  .helpdesk-desk__ticket { grid-template-columns: minmax(0, 1fr); }
}

/* 2.293.0. The site helpdesk: a visitor's tickets, a ticket's thread, and
   the Support block's words. */
.helpdesk-list { list-style: none; margin: 0 0 var(--space-4); padding: 0; display: grid; gap: var(--space-2); }
.helpdesk-list li { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: var(--space-2); }
.helpdesk-thread { list-style: none; margin: var(--space-4) 0; padding: 0; display: grid; gap: var(--space-3); }
.helpdesk-thread__message { padding: var(--space-3) var(--space-4); border: 1px solid var(--color-border);
  border-radius: var(--radius-md); background: var(--color-surface); }
.helpdesk-thread__message--support { background: var(--color-accent-subtle); }
.helpdesk-thread__who { font-weight: var(--weight-semibold); font-size: var(--text-sm); margin-bottom: var(--space-1); }
.helpdesk-thread__when { font-weight: normal; color: var(--color-text-muted); margin-left: var(--space-2); }
.helpdesk-thread__body { overflow-wrap: anywhere; }
.helpdesk-reply { display: grid; gap: var(--space-2); margin-bottom: var(--space-3); }
.block-support__intro { margin: 0 0 var(--space-4); }
.block-support__off, .block-support__sign-in { margin: 0; }

/* 2.291.0. The store's dashboard: four tiles, the months as columns, top
   items and product lines, and the stock to see to. */
.store-dashboard__tiles { display: grid; grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr));
  gap: var(--space-4); margin: 0 0 var(--space-5); }
.store-dashboard__tile { display: grid; gap: var(--space-1); padding: var(--space-4) var(--space-5);
  border: 1px solid var(--color-border); border-radius: var(--radius-md);
  background: var(--color-surface); color: inherit; text-decoration: none; }
.store-dashboard__tile--link:hover { border-color: var(--color-accent); }
.store-dashboard__tile--warn { border-color: var(--color-warning, var(--color-border));
  background: var(--color-warning-subtle, var(--color-surface)); }
.store-dashboard__label { font-size: var(--text-sm); color: var(--color-text-muted); }
.store-dashboard__figure { font-size: 1.6rem; font-weight: var(--weight-semibold); line-height: 1.2;
  font-variant-numeric: tabular-nums; }
.store-dashboard__note { font-size: var(--text-sm); color: var(--color-text-muted); }
.store-dashboard__aside { font-size: var(--text-sm); color: var(--color-text-muted); }
.store-dashboard__chart { list-style: none; margin: 0; padding: 0; display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr)); gap: var(--space-2); align-items: end;
  height: 14rem; }
.store-dashboard__bar { display: grid; grid-template-rows: auto 1fr auto; height: 100%;
  align-items: end; justify-items: center; gap: var(--space-1); min-width: 0; }
.store-dashboard__amount { font-size: 0.75rem; color: var(--color-text-muted); white-space: nowrap;
  font-variant-numeric: tabular-nums; }
.store-dashboard__column { width: 100%; max-width: 3rem; height: max(var(--share), 2px);
  border-radius: var(--radius-sm) var(--radius-sm) 0 0; background: var(--color-accent); }
.store-dashboard__month { font-size: var(--text-sm); color: var(--color-text-muted); }
.store-dashboard__pair { display: grid; grid-template-columns: repeat(auto-fit, minmax(20rem, 1fr));
  gap: var(--space-5); }
.store-dashboard__groups { list-style: none; margin: 0; padding: var(--space-4) var(--space-5);
  display: grid; gap: var(--space-3); }
.store-dashboard__groups li { display: grid; grid-template-columns: 1fr auto; gap: var(--space-1) var(--space-3); }
.store-dashboard__group-figures { font-size: var(--text-sm); color: var(--color-text-muted);
  font-variant-numeric: tabular-nums; }
.store-dashboard__track { grid-column: 1 / -1; height: 0.5rem; border-radius: 999px;
  background: var(--color-surface-sunken); overflow: hidden; }
.store-dashboard__track span { display: block; height: 100%; width: var(--share);
  background: var(--color-accent); border-radius: inherit; }
.num { text-align: right; font-variant-numeric: tabular-nums; }
.store-dashboard__scroll { overflow-x: auto; }
@media (max-width: 40rem) {
  .store-dashboard__chart { gap: 2px; height: 10rem; }
  .store-dashboard__amount { display: none; }
}

/* 2.289.0. Products › Import: three steps, the file's columns matched, its
   progress. */
.store-import__steps { list-style: none; margin: 0 0 var(--space-4); padding: 0;
  display: flex; flex-wrap: wrap; gap: var(--space-2); counter-reset: import-step; }
.store-import__step { counter-increment: import-step; display: inline-flex; align-items: center;
  gap: var(--space-2); padding: var(--space-1) var(--space-3); border-radius: 999px;
  background: var(--color-surface-sunken); color: var(--color-text-muted); font-size: var(--text-sm); }
.store-import__step::before { content: counter(import-step); display: inline-grid; place-items: center;
  width: 1.4em; height: 1.4em; border-radius: 50%; background: var(--color-border);
  color: inherit; font-weight: var(--weight-semibold); font-size: 0.85em; }
.store-import__step--current { background: var(--color-accent-subtle); color: var(--color-accent); }
.store-import__step--current::before { background: var(--color-accent); color: var(--color-accent-ink); }
.store-import__step--done { background: var(--color-success-subtle); color: var(--color-success); }
.store-import__step--done::before { content: "¹3"; background: var(--color-success); color: var(--color-text-inverse); }
.store-import__aside { margin-left: var(--space-2); color: var(--color-text-muted); font-size: var(--text-sm); }
.store-import__upload { display: grid; gap: var(--space-3); justify-items: start; margin-top: var(--space-4); }
/* 2.388.0. Products › Printify. */
.printify__how { margin: var(--space-3) 0; padding-left: var(--space-5); line-height: 1.65; }
.printify__form { display: grid; gap: var(--space-3); justify-items: start; margin-top: var(--space-4); max-width: 32rem; }
.printify__form .field { width: 100%; }
.printify__sync { margin-top: var(--space-5); padding-top: var(--space-4); border-top: 1px solid var(--color-border); }
.printify__unlink { margin-top: var(--space-5); }
.store-import__columns td, .store-import__columns th { vertical-align: middle; }
.store-import__samples { color: var(--color-text-muted); font-size: var(--text-sm); }
.store-import__samples span { display: block; max-width: 22rem; overflow: hidden;
  text-overflow: ellipsis; white-space: nowrap; }
.store-import__name { width: 100%; min-width: 8rem; }
/* Only a choice or a detail is named. */
.store-import__columns tr:not(:has(option[value="choice"]:checked, option[value="detail"]:checked)) .store-import__name { visibility: hidden; }
.store-import__settings { display: flex; flex-wrap: wrap; align-items: end; gap: var(--space-4); }
.store-import__settings .field { margin: 0; }
.store-import__separator { width: 4rem; text-align: center; }
.store-import__status { border: 0; padding: 0; display: grid; gap: var(--space-1); }
.store-import__status label { display: flex; align-items: center; gap: var(--space-2); }
.store-import__problems { margin: 0; padding-left: var(--space-5); }
.store-import__progress progress { width: 100%; max-width: 36rem; height: 0.9rem; accent-color: var(--color-accent); }
.store-import__count { margin: var(--space-2) 0 var(--space-4); }
.store-import__report-title { font-size: var(--text-md); margin: var(--space-4) 0 var(--space-2); }
.store-import__report { margin: 0 0 var(--space-4); padding-left: var(--space-5); color: var(--color-text-muted); }
@media (max-width: 40rem) {
  .store-import__columns thead { display: none; }
  .store-import__columns tr { display: grid; gap: var(--space-1); padding: var(--space-3) 0; }
  .store-import__columns td, .store-import__columns th { border: 0; padding: 0 var(--space-4); }
}

/* 2.283.0. Shipping zones: the list on Setup, and a zone's countries by region. */
.store-zones { list-style: none; margin: 0 0 var(--space-3); padding: 0; display: grid; gap: var(--space-2); }
.store-zones__zone { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--space-1) var(--space-3); }
.store-zone__covers,
.store-zone__countries { border: 0; margin: 0; padding: 0; display: grid; gap: var(--space-2); min-width: 0; }
.store-zone__search input { width: 100%; max-width: 24rem; }
.store-zone__region { border: 1px solid var(--color-border); border-radius: var(--radius-md, 6px); padding: var(--space-2) var(--space-3); }
.store-zone__region summary { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--space-1) var(--space-3); cursor: pointer; }
.store-zone__region-name { font-weight: 600; }
.store-zone__all { display: flex; flex-wrap: wrap; gap: var(--space-2); margin: var(--space-2) 0; }
.store-zone__list {
  list-style: none;
  margin: var(--space-2) 0 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(14rem, 1fr));
  gap: var(--space-1) var(--space-4);
}
.store-zone__unshippable { color: var(--color-text-muted); }

/* --- Support tickets: the SA's queue in groups (2.240.0) ------------------- */
.ticket-group th { background: var(--color-surface-sunken); text-align: left; font-weight: var(--weight-semibold); }

/* --- Help: search (2.240.0) ------------------------------------------------ */
.help-search { display: flex; gap: var(--space-2); margin: 0 0 var(--space-5); }
.help-search input { flex: 1 1 auto; min-width: 0; }
.help-contents .help-search { margin-bottom: var(--space-4); }
.help-results { list-style: none; margin: 0 0 var(--space-6); padding: 0; display: grid; gap: var(--space-4); }
.help-results__title { font-weight: var(--weight-semibold); font-size: var(--text-md); }
.help-results__snippet { margin: var(--space-1) 0 0; color: var(--color-text-muted); }
.store-guide { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-3); margin: 0 0 var(--space-4); }
.help-note { padding: var(--space-3) var(--space-4); border-left: 3px solid var(--color-border-strong); background: var(--color-surface-sunken); color: var(--color-text-muted); }

/* 2.245.0. The New domain pop-up's two choices, each with its own box.
   2.287.0. QA or Production first (Kelly), and only the chosen one's box. */
.domain-choice { margin: 0 0 var(--space-4); padding: 0; border: 0; min-width: 0; }
.domain-choice__option {
  display: grid;
  grid-template-columns: auto 1fr;
  align-items: center;
  gap: var(--space-2);
  margin-top: var(--space-2);
}
.domain-choice__name { display: inline-flex; align-items: center; gap: var(--space-2); white-space: nowrap; }
.domain-choice__box { display: flex; align-items: center; gap: var(--space-1); min-width: 0; }
.domain-choice__box input[type="text"] { flex: 1; min-width: 6rem; }
.domain-choice__suffix { color: var(--color-text-muted); white-space: nowrap; }
@media (max-width: 36rem) {
  .domain-choice__option { grid-template-columns: auto 1fr; }
  .domain-choice__box { grid-column: 1 / -1; }
}

/* 2.246.0. The six-digit sign-in code: one large box, the digits spaced as
   the email shows them, centred. */
.signin-code__field { margin-bottom: var(--space-4); }
.field.signin-code__field input.signin-code__input {
  display: block;
  width: 100%;
  height: 3.75rem;
  padding: 0 var(--space-3);
  font-size: 2rem;
  font-weight: var(--weight-semibold);
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.5em;
  text-indent: 0.5em;
  text-align: center;
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-md);
  background: var(--color-surface);
  color: var(--color-text);
}
.field.signin-code__field input.signin-code__input::placeholder { color: var(--color-border); }

/* 2.247.0. The SA's Logs page: the filters across, and what a sign-in step
   said, under its badge. */
.logs-filter__row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr));
  gap: var(--space-3);
}
.logs-filter__search { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); }
.logs-filter__search > input { flex: 1 1 16rem; min-width: 0; }
.logs-table td:first-child { white-space: nowrap; }
.logs-table .log-message { margin-top: var(--space-1); overflow-wrap: anywhere; }
.logs-table .log-code { margin-left: var(--space-2); font-size: var(--text-sm); }
.log-detail__list { margin: var(--space-2) 0 0; font-size: var(--text-sm); }
.log-detail__list > div { display: flex; gap: var(--space-2); }
.log-detail__list dt { color: var(--color-text-muted); min-width: 7rem; }
.log-detail__list dd { margin: 0; overflow-wrap: anywhere; }

/* The template filters: the customer's Templates page and, since 2.248.0,
   the SA's (Kelly: "the same Search/Category Filter"). Moved here from
   editor.css, which the console's page does not load. */
.template-filters {
  display: flex;
  align-items: flex-end;
  gap: var(--space-3);
  margin-bottom: var(--space-4);
}

.template-filters .field {
  margin-bottom: 0;
  min-width: 200px;
}

.template-filters input,
.template-filters select {
  width: 100%;
  min-height: 36px;
  padding: var(--space-2) var(--space-3);
  font: inherit;
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-sm);
  background: var(--color-surface);
  color: var(--color-text);
}

/* 2.260.0. Kelly: on a mobile device the portal is for reading, not for
   editing sites -- "hide the Edit site buttons". The platform's phone width,
   the same at which console.js opens the notice that says so
   (accounts.mobile_notice). */
@media (max-width: 48rem) {
  [data-edit-site] { display: none; }
}

/* The notice itself at the screen's left edge, not centred: the portal's
   tables run wider than a phone, so the page is wider than the screen and
   a centred dialog sat half off it. 100vw is the screen's width there. */
dialog[data-mobile-notice] { margin-left: var(--space-4); margin-right: auto; }

/* 2.264.0, here since 2.265.0. A file of a name the library has: the two
   side by side, each named (Kelly: "clearly marked"). In the editor's
   question and the console's -- the media library screen, a product's
   photos -- so in the stylesheet both load. */
.dialog.same-name { width: min(44rem, calc(100vw - var(--space-6))); }
.dialog.same-name .dialog__title { overflow-wrap: anywhere; }
.same-name__pair {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-4);
}
.same-name__figure { margin: 0; }
.same-name__figure figcaption {
  margin-bottom: var(--space-2);
  font-weight: var(--weight-semibold);
}
.same-name__picture {
  display: block;
  width: 100%;
  height: 14rem;
  object-fit: contain;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  background: var(--color-canvas);
}
/* 2.265.0. A video being uploaded, named rather than shown. */
.same-name__file {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--space-4);
  text-align: center;
  overflow-wrap: anywhere;
  color: var(--color-text-muted);
}
/* 2.274.0. Where the picture is used, in the order a publish goes, and the
   new picture's name for Keep both. */
.same-name__used {
  margin-top: var(--space-4);
  padding: var(--space-3) var(--space-4);
  border-radius: var(--radius-md);
  background: var(--color-surface-sunken);
}
.same-name__used-title {
  margin: 0 0 var(--space-2);
  font-size: var(--text-sm);
  font-weight: var(--weight-semibold);
}
.same-name__used-list { margin: 0; display: grid; gap: var(--space-1); }
.same-name__used-list dt { font-size: var(--text-sm); font-weight: var(--weight-semibold); }
.same-name__used-list dd { margin: 0 0 var(--space-2); font-size: var(--text-sm); overflow-wrap: anywhere; }
.same-name__keep { margin-top: var(--space-3); }

/* --- 2.268.0. The Shop Designer ------------------------------------------
   To the mockup Kelly chose: a bar, the structure, then the shop blocks on
   the left, the level canvases stacked in the middle and the block editor
   on the right (frontend/src/shop-designer.ts draws them). */
.sd { display: flex; flex-direction: column; gap: var(--space-3); }
.sd--busy .sd-levels { opacity: 0.7; }
.sd-bar {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-3);
  padding: var(--space-3); background: var(--color-surface);
  border: 1px solid var(--color-border); border-radius: var(--radius-md);
}
.sd-bar__title { display: flex; flex-direction: column; min-width: 0; margin-right: auto; }
.sd-bar__title strong { font-size: var(--text-md); }
.sd-bar__title span { color: var(--color-text-muted); font-size: var(--text-xs); }
.sd-shape {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2) var(--space-5);
  padding: var(--space-3); background: var(--color-surface);
  border: 1px solid var(--color-border); border-radius: var(--radius-md);
}
.sd-shape__pair { display: flex; align-items: center; gap: var(--space-2); }
.sd-shape__ask { font-weight: var(--weight-medium); }
.sd-shape__note { flex-basis: 100%; margin: 0; color: var(--color-warning); font-size: var(--text-sm); }
.sd-work { display: grid; grid-template-columns: 11rem minmax(0, 1fr) 19rem; gap: var(--space-3); align-items: start; }
@media (max-width: 64rem) { .sd-work { grid-template-columns: 10rem minmax(0, 1fr); } .sd-editor { grid-column: 1 / -1; } }
@media (max-width: 40rem) { .sd-work { grid-template-columns: minmax(0, 1fr); } }
.sd-palette, .sd-editor {
  padding: var(--space-3); background: var(--color-surface);
  border: 1px solid var(--color-border); border-radius: var(--radius-md);
}
.sd-editor { position: sticky; top: var(--space-3); }
.sd-heading {
  margin: 0 0 var(--space-2); font-size: var(--text-xs); font-weight: var(--weight-semibold);
  letter-spacing: 0.06em; text-transform: uppercase; color: var(--color-text-muted);
}
.sd-help { margin: 0 0 var(--space-2); color: var(--color-text-muted); font-size: var(--text-xs); }
.sd-tiles { display: flex; flex-direction: column; gap: var(--space-2); }
@media (max-width: 40rem) { .sd-tiles { flex-direction: row; flex-wrap: wrap; } }
.sd-tile {
  display: flex; align-items: center; gap: var(--space-2); width: 100%; padding: var(--space-2);
  border: 1px solid var(--color-border); border-radius: var(--radius-md);
  background: var(--color-surface-sunken); color: inherit; font: inherit; text-align: left; cursor: grab;
}
@media (max-width: 40rem) { .sd-tile { width: auto; } }
.sd-tile:hover { border-color: var(--color-border-strong); }
.sd-tile__mark { width: 1.6rem; height: 1.6rem; flex: 0 0 auto; border-radius: var(--radius-sm); background: var(--color-accent); }
.sd-tile__mark--line { background: color-mix(in srgb, var(--color-accent) 60%, var(--color-surface)); }
.sd-tile__mark--item { background: var(--color-warning-subtle); border: 2px solid var(--color-warning); }
.sd-tile__label small { display: block; color: var(--color-text-muted); font-size: var(--text-xs); }

.sd-levels { display: flex; flex-direction: column; gap: var(--space-3); min-width: 0; }
.sd-level { background: var(--color-surface); border: 1px solid var(--color-border); border-radius: var(--radius-md); overflow: hidden; }
.sd-level__head {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--space-1) var(--space-3);
  padding: var(--space-2) var(--space-3); background: var(--color-surface-sunken);
  border-bottom: 1px solid var(--color-border);
}
.sd-level__note { color: var(--color-text-muted); font-size: var(--text-xs); }
.sd-level__step { margin-left: auto; color: var(--color-text-muted); font-size: var(--text-xs); letter-spacing: 0.05em; text-transform: uppercase; }
.sd-level__body { padding: var(--space-3); min-height: 5.5rem; }
.sd-level__body.is-over { background: var(--color-accent-subtle); outline: 2px dashed var(--color-accent); outline-offset: -6px; }
.sd-level__body.is-refused { background: var(--color-danger-subtle); outline: 2px dashed var(--color-danger); outline-offset: -6px; }
.sd-level--waiting .sd-level__body { opacity: 0.6; }
.sd-empty {
  display: grid; place-items: center; min-height: 4rem; padding: var(--space-3);
  border: 1px dashed var(--color-border); border-radius: var(--radius-md);
  color: var(--color-text-muted); font-size: var(--text-sm); text-align: center;
}
.sd-chips { display: flex; flex-wrap: wrap; gap: var(--space-2); }
.sd-chip {
  display: inline-flex; align-items: center; gap: var(--space-2); padding: var(--space-2) var(--space-3);
  border: 1px solid var(--color-border); border-radius: 999px; background: var(--color-surface);
  color: inherit; font: inherit; font-weight: var(--weight-medium); cursor: pointer;
}
.sd-chip small { color: var(--color-text-muted); font-weight: var(--weight-regular); }
.sd-chip[aria-pressed="true"] { border-color: var(--color-button); background: var(--color-button); color: var(--color-accent-ink); }
.sd-chip[aria-pressed="true"] small { color: inherit; opacity: 0.85; }
.sd-chip.is-over { outline: 2px dashed var(--color-accent); outline-offset: 2px; }
.sd-chip.is-dragging, .sd-card.is-dragging { opacity: 0.4; }

/* The products, as a plain grid until the store designs (2.269.0). */
.sd-shop { padding: var(--space-3); border-radius: var(--radius-md); background: var(--color-canvas); }
.sd-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(9.5rem, 1fr)); gap: var(--space-4); }
.sd-card { position: relative; cursor: pointer; border-radius: var(--radius-md); outline: 2px solid transparent; outline-offset: 3px; }
.sd-card[aria-pressed="true"] { outline-color: var(--color-accent); }
.sd-card__picture {
  display: grid; place-items: center; aspect-ratio: 4 / 3; max-width: 100%; overflow: hidden;
  border-radius: var(--radius-sm); background: var(--color-surface-sunken);
}
.sd-card__picture img { width: 100%; height: 100%; object-fit: cover; }
.sd-card__none { color: var(--color-text-muted); font-size: var(--text-xs); }
.sd-card__name { margin: var(--space-2) 0 2px; font-weight: var(--weight-semibold); overflow-wrap: anywhere; }
.sd-card__price { font-size: var(--text-sm); }
.sd-card__draft {
  position: absolute; top: var(--space-1); left: var(--space-1); padding: 1px var(--space-2);
  border-radius: 999px; background: var(--color-warning-subtle); color: var(--color-warning);
  font-size: var(--text-xs); font-weight: var(--weight-semibold);
}

.sd-field { display: flex; flex-direction: column; gap: var(--space-1); margin-bottom: var(--space-3); }
.sd-field__label { font-weight: var(--weight-medium); font-size: var(--text-sm); }
.sd-field input:not([type="file"]), .sd-field select, .sd-field textarea { width: 100%; }
.sd-actions { display: flex; flex-wrap: wrap; gap: var(--space-2); margin-bottom: var(--space-2); }
.sd-danger { color: var(--color-danger); }
.sd-photos { display: flex; flex-wrap: wrap; gap: var(--space-2); }
.sd-photo { position: relative; width: 3.5rem; aspect-ratio: 1; }
.sd-photo img { width: 100%; height: 100%; object-fit: cover; border-radius: var(--radius-sm); }
.sd-photo__remove {
  position: absolute; top: -6px; right: -6px; width: 1.25rem; height: 1.25rem; padding: 0; line-height: 1;
  border: 1px solid var(--color-border); border-radius: 50%; background: var(--color-surface); cursor: pointer;
}
.sd-upload { align-self: flex-start; }
.sd-toast {
  position: fixed; left: 50%; bottom: calc(var(--space-5) + env(safe-area-inset-bottom, 0px)); z-index: 80;
  transform: translateX(-50%); max-width: calc(100vw - 2rem); padding: var(--space-2) var(--space-4);
  border-radius: var(--radius-md); background: var(--color-text); color: var(--color-surface);
  font-size: var(--text-sm); box-shadow: var(--shadow-sm);
}

/* 2.269.0. The store designs, picked for the block it was opened from: a
   row of little pictures, as in the mockup. The canvas's cards are the
   block's own (blocks/_store_cards.html, editor.css), in the site's theme. */
.sd-designs { display: flex; flex-wrap: wrap; gap: var(--space-2); margin-left: auto; }
.sd-design {
  display: flex; flex-direction: column; align-items: center; gap: 3px; width: 4.75rem;
  padding: var(--space-1) var(--space-1) 5px; border: 1px solid var(--color-border);
  border-radius: var(--radius-md); background: var(--color-surface); color: inherit;
  font: inherit; font-size: var(--text-xs); cursor: pointer;
}
.sd-design svg { display: block; width: 3.25rem; height: 1.9rem; }
.sd-design svg rect { fill: var(--color-border-strong); opacity: 0.45; }
.sd-design[aria-pressed="true"] { border-color: var(--color-accent); box-shadow: 0 0 0 1px var(--color-accent); background: var(--color-accent-subtle); }
.sd-design[aria-pressed="true"] svg rect { fill: var(--color-accent); opacity: 0.75; }
.sd-shop__cards .sd-card { cursor: pointer; }
.sd-shop__cards .sd-card[aria-pressed="true"] { outline: 2px solid var(--color-accent); outline-offset: 4px; border-radius: 4px; }

/* 2.270.0. Designer | Table, and the table: a row a product, each box
   plain until it is pointed at or typed in, as in the mockup. */
.sd-views { display: inline-flex; border: 1px solid var(--color-border); border-radius: var(--radius-md); overflow: hidden; }
.sd-views button { padding: var(--space-1) var(--space-4); border: 0; background: var(--color-surface); color: inherit; font: inherit; cursor: pointer; }
.sd-views button[aria-pressed="true"] { background: var(--color-button); color: var(--color-accent-ink); font-weight: var(--weight-semibold); }
.sd-table { background: var(--color-surface); border: 1px solid var(--color-border); border-radius: var(--radius-md); }
.sd-table__wrap { overflow-x: auto; }
.sd-table__grid { width: 100%; border-collapse: collapse; font-variant-numeric: tabular-nums; }
.sd-table__grid th, .sd-table__grid td {
  padding: var(--space-1) var(--space-2); border-bottom: 1px solid var(--color-border);
  text-align: left; white-space: nowrap;
}
.sd-table__grid th {
  position: sticky; top: 0; background: var(--color-surface-sunken); color: var(--color-text-muted);
  font-size: var(--text-xs); font-weight: var(--weight-semibold);
}
.sd-table__grid input, .sd-table__grid select {
  width: 100%; min-width: 6rem; padding: 4px 6px; border: 1px solid transparent;
  border-radius: var(--radius-sm); background: transparent; color: inherit; font: inherit;
}
.sd-table__grid td:first-child input { min-width: 12rem; }
.sd-table__grid input:hover, .sd-table__grid select:hover { border-color: var(--color-border); }
.sd-table__grid input:focus, .sd-table__grid select:focus { border-color: var(--color-accent); background: var(--color-surface); }
.sd-table__number input, .sd-table__number .sd-table__fixed { text-align: right; min-width: 5rem; }
.sd-table__number .sd-table__fixed { display: block; padding: 4px 6px; color: var(--color-text-muted); }
.sd-table__actions { display: flex; gap: var(--space-1); }
.sd-table__foot { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-3); padding: var(--space-3); }
.sd-table__foot .sd-help { margin: 0; }

/* 2.272.0. Where a product's choices and details are set, said where they
   are used: on its screen and in the Shop Designer. */
.store-options-link {
  margin: 0;
  padding: var(--space-3) var(--space-4);
  border-radius: var(--radius-md);
  background: var(--color-surface-sunken);
  font-size: var(--text-sm);
}
.sd-options { padding-top: var(--space-3); border-top: 1px solid var(--color-border); }
.sd-options .btn { align-self: flex-start; }
.sd-level__options { margin-left: var(--space-2); }

/* 2.297.0. The SA's banners across the top of the customer portal
   (portal_messages): one or two lines each, stacked newest first. Their
   colours are the SA's own, set inline on each. */
.portal-banner {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-2) var(--space-4);
}

.portal-banner[hidden] { display: none; }

.portal-banner__message {
  flex: 1 1 auto;
  margin: 0;
  font-size: var(--text-sm);
  line-height: 1.4;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.portal-banner__button {
  flex: none;
  padding: var(--space-1) var(--space-3);
  border-radius: var(--radius-md);
  font-size: var(--text-sm);
  font-weight: 600;
  text-decoration: none;
  white-space: nowrap;
}

.portal-banner__close {
  flex: none;
  padding: var(--space-1);
  border: 0;
  background: transparent;
  font-size: 1.25rem;
  line-height: 1;
  cursor: pointer;
}

/* On the SA's list, each banner as it will look. */
.portal-banner--sample { border-radius: var(--radius-md); }

/* 2.298.0. The SA's email as it arrives, on its own screen. */
.email-preview {
  display: block;
  width: 100%;
  height: 40rem;
  border: 0;
  border-top: 1px solid var(--color-border);
}

/* 2.303.0. Stripe setup (templates/store/stripe_setup.html): what is left
   for the owner in Stripe, and each step of the last Test. */
.store-checklist { margin: 0 0 var(--space-4); padding-left: var(--space-5); }
.store-checklist li { margin-bottom: var(--space-2); }

.store-test { list-style: none; margin: 0 0 var(--space-4); padding: 0; }
.store-test__step { display: flex; gap: var(--space-2); margin-bottom: var(--space-2); }
.store-test__step--ok > span:first-child { color: var(--color-success); }
.store-test__step--failed > span:first-child,
.store-test__step--failed .store-test__detail { color: var(--color-danger); }

/* --- 2.314.0. SEO: AI Auto Fill ---------------------------------------------
   2.315.0: here, where the console's pages read it; in editor.css, which
   they do not load, until then.
   The button sits at the right of the tab's or the page's heading; a field
   the AI could not fill is edged in the warning colour, its placeholder
   saying it needs the person's input. */
.panel__head:has(.seo-autofill),
.seo-page__head:has(.seo-autofill) { display: flex; align-items: center; gap: var(--space-3); flex-wrap: wrap; }
.seo-autofill { margin: 0 0 0 auto; }
[data-needs-input] { border-color: var(--color-warning); box-shadow: 0 0 0 1px var(--color-warning); }
[data-needs-input]::placeholder { color: var(--color-warning); opacity: 1; }

/* --- 2.315.0. Email Templates: the placeholders to put in, in a row. ------ */
.wording-placeholders { display: flex; flex-wrap: wrap; gap: var(--space-2); }

/* --- 2.323.0. Five designs for the cookie notice (Kelly, 2026-10-23) -----
   The ways the big consent tools (CookieYes, Cookiebot, Secure Privacy) all
   offer: a bar along the bottom, which is the notice as it was and stays the
   default; a bar along the top; a floating bar, inset and rounded; a box in
   the corner, the least in the way; a popup in the center over a dimmed
   page. `Site.cookie_notice_design`; the bottom bar adds no class. */
.cookie-notice--top {
  top: 0;
  bottom: auto;
  box-shadow: 0 2px 12px rgba(15, 23, 42, 0.18);
}

.cookie-notice--floating {
  left: var(--space-4);
  right: var(--space-4);
  bottom: var(--space-4);
  max-width: 60rem;
  margin-inline: auto;
  border-radius: var(--radius-lg);
  box-shadow: 0 12px 32px rgba(15, 23, 42, 0.28);
}

.cookie-notice--corner,
.cookie-notice--popup {
  flex-direction: column;
  align-items: stretch;
  gap: var(--space-3);
  border-radius: var(--radius-lg);
  background: var(--color-surface);
  color: var(--color-text);
}
.cookie-notice--corner .cookie-notice__text,
.cookie-notice--popup .cookie-notice__text { flex: none; }
.cookie-notice--corner .cookie-notice__actions .btn,
.cookie-notice--popup .cookie-notice__actions .btn { flex: 1 1 auto; }

.cookie-notice--corner {
  left: auto;
  right: var(--space-4);
  bottom: var(--space-4);
  width: min(22rem, calc(100% - 2 * var(--space-4)));
  border: 1px solid var(--color-border);
  box-shadow: 0 12px 32px rgba(15, 23, 42, 0.22);
}

/* The page behind dimmed by the box's own shadow, so nothing else has to be
   drawn or removed with it. */
.cookie-notice--popup {
  top: 50%;
  left: 50%;
  right: auto;
  bottom: auto;
  width: min(28rem, calc(100% - 2 * var(--space-4)));
  padding: var(--space-6);
  text-align: center;
  transform: translate(-50%, -50%);
  box-shadow: 0 0 0 100vmax rgba(15, 23, 42, 0.55), 0 24px 60px rgba(15, 23, 42, 0.35);
}

/* The Cookies and Timeout screen's tabs, drawn as the online store's are. */
.page-tabs {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin-bottom: var(--space-5);
  padding-bottom: var(--space-4);
  border-bottom: 1px solid var(--color-border);
}
.page-tabs__tab {
  padding: var(--space-2) var(--space-4);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  text-decoration: none;
  color: var(--color-text);
  font-size: var(--text-sm);
}
.page-tabs__tab:hover { background: var(--color-surface-sunken); }
.page-tabs__tab--current,
.page-tabs__tab--current:hover {
  background: var(--color-button);
  border-color: var(--color-button);
  color: var(--color-text-inverse);
}

/* --- Email sending (2.402.0) --------------------------------------------- */
/* Kelly: "everything fits on a standard size screen with no scrolling.
   Shrink down the white space, use the entire width of the viewport". The
   settings on the left, three across; what is in use and its test on the
   right, so a test is sent without scrolling to it. One column on a phone. */
.page-head--tight { margin-bottom: var(--space-3); }
.page-tabs--tight { margin-bottom: var(--space-3); padding-bottom: var(--space-3); }

/* Less room above and below than a page that scrolls anyway: enough below
   to clear the fixed footer bar. */
.app-main:has(.mail-setup) {
  padding-top: var(--space-4);
  padding-bottom: calc(var(--space-6) + var(--space-3));
}
.mail-setup {
  display: grid;
  grid-template-columns: minmax(0, 3fr) minmax(18rem, 1fr);
  gap: var(--space-4);
  align-items: start;
}
.mail-setup__side {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
}
.mail-setup .panel { margin-bottom: 0; }
.mail-setup .panel__head { padding: var(--space-2) var(--space-4); }
.mail-setup .panel__lead { margin: 0; padding: var(--space-3) var(--space-4); }
.mail-setup__side .panel__lead { font-size: var(--text-sm); }
.mail-setup .settings {
  max-height: none;
  overflow: visible;
  padding: var(--space-3) var(--space-4) var(--space-4);
  gap: var(--space-3);
}
.mail-setup__fields {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--space-3) var(--space-4);
}
.mail-setup__fields .field { margin-bottom: 0; }
.mail-setup__fields .field__label { margin-bottom: var(--space-1); }
/* The control's box is the input's own; the wrapper around it takes no
   padding, border or height of its own here. */
.mail-setup__fields .field__control {
  padding: 0;
  min-height: 0;
  border: 0;
  background: none;
}
.mail-setup__fields .field__help { margin: var(--space-1) 0 0; line-height: 1.35; }
@media (min-width: 80rem) {
  .mail-setup__fields { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}
/* The test: the address and its button on one line, Remove beside. */
.mail-setup__side .field { margin-bottom: 0; }
.mail-setup__side .field__label { margin-bottom: var(--space-1); }
.mail-setup__send { display: flex; gap: var(--space-2); align-items: flex-end; }
.mail-setup__send .field { flex: 1 1 auto; min-width: 0; }
.mail-setup .settings__actions { position: static; padding-top: 0; }

@media (max-width: 64rem) {
  .mail-setup__fields { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 48rem) {
  .mail-setup { grid-template-columns: minmax(0, 1fr); }
  .mail-setup__fields { grid-template-columns: minmax(0, 1fr); }
}

/* Each design on a small page, placed as it is on the screen. */
.cookie-designs {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(16rem, 1fr));
  gap: var(--space-5);
}
.cookie-designs__item { margin: 0; }
.cookie-designs__item figcaption {
  margin-top: var(--space-2);
  font-size: var(--text-sm);
}
.cookie-designs__item--chosen .cookie-preview {
  outline: 2px solid var(--color-accent);
  outline-offset: 2px;
}
.cookie-preview {
  position: relative;
  aspect-ratio: 16 / 10;
  overflow: hidden;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  background: var(--color-surface);
  font-size: 0.6rem;
}
.cookie-preview__page {
  display: flex;
  flex-direction: column;
  gap: 0.6em;
  padding: 1.2em;
}
.cookie-preview__page span {
  display: block;
  height: 0.7em;
  border-radius: 0.35em;
  background: var(--color-surface-sunken);
}
.cookie-preview__page span:first-child { width: 55%; height: 1.4em; }
.cookie-preview .cookie-notice {
  position: absolute;
  padding: 0.8em 1em;
  gap: 0.6em;
}
.cookie-preview .cookie-notice__text { font-size: 1em; }
/* The bars' words take the row's room; the box and the popup stack theirs. */
.cookie-preview .cookie-notice:not(.cookie-notice--corner):not(.cookie-notice--popup) .cookie-notice__text {
  flex-basis: 8em;
}
.cookie-preview .btn { padding: 0.3em 0.8em; font-size: 1em; }
.cookie-preview .cookie-notice--corner { width: 55%; right: 0.8em; bottom: 0.8em; }
.cookie-preview .cookie-notice--floating { left: 0.8em; right: 0.8em; bottom: 0.8em; }
.cookie-preview .cookie-notice--popup { width: 60%; padding: 1em; }

/* 2.329.0. While a passkey is asked for: where the operating system's own
   window is (static/js/passkeys.js). Bold, and set apart, so it is not
   missed (Kelly: "Make sure it's in BOLD!!!"). */
.passkey-wait {
  margin: var(--space-3) 0 0;
  padding: var(--space-3) var(--space-4);
  border: 2px solid var(--color-accent);
  border-radius: var(--radius-sm);
  background: var(--color-accent-subtle);
  color: var(--color-text);
  /* Larger than the page's own text (--text-base, 0.875rem). */
  font-size: 1rem;
  line-height: 1.45;
}
.passkey-wait strong { font-weight: 700; }
.passkey-wait[hidden] { display: none; }

/* --- 2.334.0. The template showcase (templates/themes/showcase.html), open
   to anybody: the brands and the words at the top, then the template tiles,
   each with its own photograph. ------------------------------------------- */
.showcase {
  max-width: 1280px;
  margin: 0 auto;
  padding: var(--space-6) var(--space-4) var(--space-8);
}
.showcase__head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-4) var(--space-6);
  margin-bottom: var(--space-5);
}
.showcase__title { flex: 1 1 320px; }
.showcase__title h1 { margin: 0 0 var(--space-2); }
.showcase__intro { margin: 0; color: var(--color-text-muted); max-width: 60ch; }
.showcase__account { margin: 0; font-size: var(--text-sm); }
.showcase__picture {
  aspect-ratio: 16 / 9;
  max-width: 100%;
  overflow: hidden;
  border-bottom: 1px solid var(--color-border);
  background: var(--color-surface-sunken);
}
.showcase__picture img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.showcase__plain { margin-top: var(--space-6); text-align: center; }
/* The search and category row wraps on a phone, where visitors land. */
.showcase .template-filters { flex-wrap: wrap; }
/* As the sign-in pages' (2.331.0): big enough for a thumb, no zoom. */
@media (pointer: coarse) {
  .showcase .btn { min-height: 44px; }
  .showcase .field input, .showcase .field select { font-size: 16px; min-height: 44px; }
}

/* 2.334.0. The sign-up page's chosen template. */
.signup__template {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  margin-bottom: var(--space-4);
  padding: var(--space-3);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  background: var(--color-surface-sunken);
}
.signup__template p { margin: 0; }
.signup__template-picture {
  width: 96px;
  max-width: 30%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  border-radius: var(--radius-sm);
}

/* 2.334.0. A template showcase's three counters (console/_showcase_counts.html). */
.showcase-counts {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2) var(--space-5);
  margin: var(--space-3) 0 0;
}
.showcase-counts div { display: flex; align-items: baseline; gap: var(--space-2); }
.showcase-counts dt { font-size: var(--text-sm); color: var(--color-text-muted); }
.showcase-counts dd { margin: 0; font-weight: var(--weight-semibold, 600); }


/* 2.335.0. The showcase inside another website (showcase_embed.html): its
   own page, the website's width, no frame chrome. */
.showcase-embed {
  margin: 0;
  padding: var(--space-3);
  background: transparent;
}
.showcase-embed .template-filters { flex-wrap: wrap; }
@media (pointer: coarse) {
  .showcase-embed .btn { min-height: 44px; }
  .showcase-embed .field select { font-size: 16px; min-height: 44px; }
}

/* --- 2.336.0. Continue with Google, GitHub or Facebook
   (templates/accounts/_social_buttons.html). --------------------------- */
.social-list { display: flex; flex-direction: column; gap: var(--space-2); }
.social-button { position: relative; gap: var(--space-3); }
.social-button__mark { display: inline-flex; width: 18px; height: 18px; }
.signup__checked { margin: 0 0 var(--space-4); }
.signup__terms { margin: var(--space-3) 0; }
@media (pointer: coarse) {
  .auth .social-button { min-height: 44px; }
}

/* 2.336.0. The portal sign-in page's Create Account, top right (Kelly). */
.auth { position: relative; }
.auth__corner {
  position: absolute;
  top: var(--space-4);
  right: var(--space-5);
  font-weight: var(--weight-medium);
}
@media (pointer: coarse) {
  .auth__corner { display: inline-flex; align-items: center; min-height: 44px; }
}

/* 2.336.0. The Super Admin's Social sign-in screen. */
.social-steps { margin: 0 0 var(--space-4); padding-left: var(--space-5); }
.social-steps li { margin-bottom: var(--space-1); }
.social-form { margin-top: var(--space-4); max-width: 560px; }
.social-form__actions { display: flex; flex-wrap: wrap; gap: var(--space-2); }

/* 2.337.0. Apple asks for its button black, with its mark in white. */
.social-button--apple,
.social-button--apple:hover {
  background: var(--color-apple);
  border-color: var(--color-apple);
  color: var(--color-text-inverse);
}

/* 2.340.0. The theme screen's Words on the accent, and where they go. */
.theme-editor__auto { margin-top: var(--space-1); font-size: var(--text-sm); }
.theme-preview__on-accent {
  margin-top: var(--space-4);
  padding-top: var(--space-3);
  border-top: 1px solid var(--color-border);
}
.theme-preview__on-accent-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3);
}
.theme-preview__link { color: var(--color-accent); text-decoration: underline; }
.theme-preview__step,
.theme-preview__count {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 999px;
  background: var(--color-accent);
  color: var(--color-on-accent);
  font-weight: var(--weight-semibold);
}
.theme-preview__step { width: 2rem; height: 2rem; }
.theme-preview__count { min-width: 1.4rem; height: 1.4rem; padding: 0 var(--space-1); font-size: var(--text-xs); }
.theme-preview__badge {
  padding: var(--space-1) var(--space-3);
  border-radius: 999px;
  background: var(--color-accent);
  color: var(--color-on-accent);
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
}

/* --- The Knowledge catalog. 2.358.0 ------------------------------------- */
/* The currency on one line with its Save; each row's Up, Down and Remove
   side by side at the row's end. */
.catalog-currency {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: var(--space-3);
}
.catalog-currency .field { margin: 0; }
/* 2.378.0. Auto Update: its box and words, then Save, then the last run. */
.catalog-auto {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: var(--space-3);
  border-top: 1px solid var(--color-border);
}
.catalog-auto__choice { display: flex; gap: var(--space-3); align-items: flex-start; flex: 1 1 24rem; cursor: pointer; }
.catalog-auto__choice input { margin-top: 0.3rem; }
.catalog-auto__said { flex-basis: 100%; margin: 0; }
.catalog-actions {
  display: flex;
  justify-content: flex-end;
  gap: var(--space-2);
  white-space: nowrap;
}
.catalog-actions form { margin: 0; }
/* The section's list and its Add form are two panels, apart. */
[data-catalog-section] + [data-catalog-add] { margin-top: var(--space-5); }

/* --- The Calendar. 2.365.0 --------------------------------------------- */
/* The day's title with its arrows and its day-and-person picker beside it;
   a heading per person above their bookings; a cancelled booking greyed. */
.calendar-day__head { display: flex; flex-wrap: wrap; align-items: center;
  justify-content: space-between; gap: var(--space-3); }
.calendar-day__nav { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); }
.calendar-day__pick { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); margin: 0; }
.calendar-person + .calendar-person { border-top: 1px solid var(--color-border); }
.calendar-person__name { margin: 0; padding: var(--space-4) var(--space-5) var(--space-2); font-size: var(--text-md); }
.calendar-booking--cancelled td { color: var(--color-text-muted); }
.calendar-booking--cancelled td:nth-child(2) { text-decoration: line-through; }
.calendar-facts { display: grid; grid-template-columns: max-content minmax(0, 1fr);
  gap: var(--space-2) var(--space-5); margin: 0 0 var(--space-4); }
.calendar-facts dt { color: var(--color-text-muted); }
.calendar-facts dd { margin: 0; }
/* A week of hours, a day a row: its name, from, to. */
.calendar-hours { display: grid; gap: var(--space-2); padding: 0 var(--space-5) var(--space-3); }
.calendar-hours__day { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); }
.calendar-hours__label { width: 7rem; font-weight: var(--weight-semibold); }
.calendar-hours__day input {
  min-height: 2.5rem;
  padding: var(--space-1) var(--space-2);
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-md);
  font: inherit;
}
.calendar-hours__day .field__error { flex-basis: 100%; margin: 0 0 0 7.5rem; }
/* 2.377.0. Several spans a day, side by side: 9 to 11, and 2 to 6. */
.calendar-hours__spans { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2) var(--space-4); }
.calendar-hours__span { display: flex; align-items: center; gap: var(--space-2); }
[data-calendar-day] + [data-calendar-add],
[data-calendar-people] + [data-calendar-add-person],
.panel + .panel[data-calendar-hours],
.panel + .panel[data-calendar-service-hours],
.panel + .panel[data-calendar-time-off],
.panel + .panel[data-calendar-move],
.panel + .panel[data-calendar-cancel] { margin-top: var(--space-5); }

/* --- 2.360.0. Fill from my site: the suggestions to review --------------- */
.fill-list { list-style: none; margin: 0; padding: 0; }
.fill-list__item { padding: var(--space-4) var(--space-5); border-top: 1px solid var(--color-border); }
.fill-list__choice { display: flex; gap: var(--space-3); align-items: flex-start; cursor: pointer; }
.fill-list__choice input { margin-top: 0.3rem; }
.fill-list__words { display: grid; gap: var(--space-1); }
.fill-list__quote {
  margin: var(--space-2) 0 0 calc(var(--space-3) + 1rem);
  padding-left: var(--space-3);
  border-left: 3px solid var(--color-border);
  font-size: var(--text-sm);
  color: var(--color-text-muted);
}
.fill-actions { display: flex; flex-wrap: wrap; gap: var(--space-3); margin-top: var(--space-5); }
[data-catalog-fill] { margin: 0; }
[data-fill-section] + [data-fill-section] { margin-top: var(--space-5); }

/* --- 2.361.0. The chat screen, on the site's own address ----------------- */
/* A chat's messages: here, not in editor.css, because the chat screen draws
   them too and loads only this. */
.chat__messages { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--space-2); }
.chat__message { display: grid; gap: 2px; max-width: 85%; padding: var(--space-2) var(--space-3); border-radius: var(--radius-md); white-space: pre-wrap; overflow-wrap: anywhere; }
.chat__message--visitor { justify-self: end; background: var(--color-accent-subtle); }
.chat__message--support { justify-self: start; background: var(--color-surface-sunken); }
.chat__who { font-size: var(--text-xs); color: var(--color-text-muted); }
.chat-desk__bar { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-3) var(--space-5); margin-bottom: var(--space-5); }
.chat-desk__available { display: inline-flex; gap: var(--space-2); align-items: center; font-weight: var(--weight-semibold); }
.chat-desk__note { flex-basis: 100%; margin: 0; font-size: var(--text-sm); color: var(--color-text-muted); }
.chat-desk__panes { display: grid; grid-template-columns: minmax(14rem, 1fr) minmax(0, 2.5fr); gap: var(--space-5); }
.chat-desk__list ul { list-style: none; margin: 0 0 var(--space-4); padding: 0; display: grid; gap: var(--space-1); }
.chat-desk__heading { margin: 0 0 var(--space-2); font-size: var(--text-sm); text-transform: uppercase; letter-spacing: 0.06em; color: var(--color-text-muted); }
.chat-desk__chat {
  width: 100%;
  padding: var(--space-2) var(--space-3);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  background: var(--color-surface);
  text-align: left;
  font: inherit;
  cursor: pointer;
}
.chat-desk__chat--open { border-color: var(--color-accent); box-shadow: inset 3px 0 0 var(--color-accent); }
.chat-desk__open { padding: var(--space-4); border: 1px solid var(--color-border); border-radius: var(--radius-md); background: var(--color-surface); min-height: 20rem; }
.chat-desk__who { display: flex; flex-wrap: wrap; gap: var(--space-2); align-items: baseline; margin-bottom: var(--space-3); }
.chat-desk__messages { max-height: 26rem; overflow-y: auto; margin-bottom: var(--space-3); }
.chat-desk__say { display: grid; gap: var(--space-2); }
.chat-desk__say textarea { width: 100%; box-sizing: border-box; font: inherit; padding: var(--space-2); }
.chat-desk__actions { display: flex; flex-wrap: wrap; gap: var(--space-2); align-items: center; }
.chat-desk__said { margin: 0; font-size: var(--text-sm); }
@media (max-width: 48rem) {
  .chat-desk__panes { grid-template-columns: minmax(0, 1fr); }
}
/* 2.362.0. The answers a visitor gave before the chat. */
.chat-desk__answers { display: grid; grid-template-columns: max-content minmax(0, 1fr); gap: var(--space-1) var(--space-3); margin: 0 0 var(--space-3); padding: var(--space-3); border-radius: var(--radius-sm); background: var(--color-surface-sunken); font-size: var(--text-sm); }
.chat-desk__answers[hidden] { display: none; }
.chat-desk__answers dt { font-weight: var(--weight-semibold); }
.chat-desk__answers dd { margin: 0; }
/* 2.364.0. Questions suggested from chats, to approve. */
.catalog-suggestion { padding: var(--space-4) var(--space-5); border-top: 1px solid var(--color-border); }
.catalog-suggestion__form { display: grid; gap: var(--space-2); max-width: 44rem; }
.catalog-suggestion__form input, .catalog-suggestion__form textarea { width: 100%; box-sizing: border-box; font: inherit; padding: var(--space-2); }
.catalog-suggestion__actions { display: flex; gap: var(--space-2); flex-wrap: wrap; }
[data-catalog-suggested] + [data-catalog-section] { margin-top: var(--space-5); }

/* 2.371.0. Build my site: its questions after the drafting form's; the
   store's own only once a store is wanted. */
.build-questions { border: 1px solid var(--color-border); border-radius: var(--radius-md); margin: var(--space-5) 0; padding: var(--space-5); display: grid; gap: var(--space-4); }
.build-questions__title { padding: 0 var(--space-2); font-weight: var(--weight-semibold); }
.build-questions__row { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 14rem), 1fr)); gap: var(--space-4); }
.build-questions__store { display: none; gap: var(--space-4); }
.build-questions:has(input[name="store"][value="yes"]:checked) .build-questions__store { display: grid; }
.build-questions .choice { display: flex; align-items: center; gap: var(--space-2); margin-top: var(--space-1); }

/* 2.372.0. The site's own apps: the AI mark, a design to read, a dashboard,
   and the App block on a page with its mark in the upper left corner. */
.ai-mark {
  display: inline-grid;
  place-items: center;
  min-width: 1.6rem;
  padding: 0 0.3rem;
  border-radius: var(--radius-sm);
  background: var(--color-accent);
  color: var(--color-surface);
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
  letter-spacing: 0.04em;
}
.app-design { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 18rem), 1fr)); gap: var(--space-4); margin: var(--space-4) 0; }
.app-design__table { border: 1px solid var(--color-border); border-radius: var(--radius-md); padding: var(--space-4); }
.app-design__name { margin: 0 0 var(--space-2); font-size: var(--text-md); }
.app-design__fields { margin: 0; padding-left: var(--space-5); display: grid; gap: var(--space-1); }
.app-design__type { color: var(--color-text-muted); font-size: var(--text-sm); }
/* 2.379.0. Examples to start from: a card each, its title, a line, and Use. */
.app-examples__tabs { padding: 0 var(--space-5); flex-wrap: wrap; }
.app-examples {
  list-style: none;
  margin: 0;
  padding: var(--space-4) var(--space-5) var(--space-5);
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 15rem), 1fr));
  gap: var(--space-3);
}
.app-examples__item {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-2);
  padding: var(--space-4);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
}
.app-examples__item--chosen { border-color: var(--color-accent); box-shadow: 0 0 0 1px var(--color-accent); }
.app-examples__summary { color: var(--color-text-muted); font-size: var(--text-sm); flex: 1; }
/* 2.379.0. The forms an app will make, side by side, as they will look. */
.app-forms { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 20rem), 1fr)); gap: var(--space-4); margin: 0 0 var(--space-4); }
.app-forms__form { border: 1px solid var(--color-border); border-radius: var(--radius-md); padding: var(--space-4); background: var(--color-surface-sunken, transparent); }
.app-forms__fields { border: 0; margin: var(--space-3) 0 0; padding: 0; min-width: 0; }
.app-changed { margin: var(--space-3) 0 0; padding: var(--space-3) var(--space-4); border-left: 3px solid var(--color-accent); background: var(--color-accent-subtle); border-radius: var(--radius-sm); }
.app-changed p { margin: 0 0 var(--space-1); }
.app-changed ul { margin: 0; padding-left: var(--space-5); }
.app-dashboard { display: grid; gap: var(--space-5); }
.app-dashboard__charts { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 20rem), 1fr)); gap: var(--space-5); }
.app-chart__title { margin: 0 0 var(--space-3); font-size: var(--text-md); }
.app-block { position: relative; padding-top: var(--space-6); }
.app-block__ai {
  position: absolute;
  top: 0;
  left: 0;
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  padding: 0.15rem 0.45rem;
  border-radius: 999px;
  background: var(--color-accent);
  color: var(--color-surface);
  font-size: 0.7rem;
  font-weight: var(--weight-semibold);
  letter-spacing: 0.05em;
}
.app-block__heading { margin: 0 0 var(--space-4); }
.app-block__note { color: var(--color-text-muted); }
.app-block__scroll { overflow-x: auto; }
.app-block__form { max-width: 36rem; }

/* 2.381.0. The AI Shop Builder's review: each product with its photo, its
   words and its price box. */
.shop-review__product { display: flex; gap: var(--space-3); align-items: flex-start; }
.shop-review__photo { width: 64px; height: 64px; object-fit: cover; border-radius: var(--radius-sm); flex: none; }
.shop-review__words { margin: var(--space-1) 0 0; color: var(--color-text-muted); font-size: var(--text-sm); }
.shop-review__price { max-width: 7rem; }
.shop-builder__kinds { border: 0; margin: 0 0 var(--space-4); padding: 0; min-width: 0; }
.shop-builder__kinds label { margin-right: var(--space-4); }
.shop-builder__count { max-width: 7rem; }
.shop-review .badge { margin-top: var(--space-1); }

/* 2.384.0. The SA's AI screen: the allowance's settings, side by side, and
   each customer's last fourteen days as bars against their limit. */
.ai-limits__row { display: flex; flex-wrap: wrap; gap: var(--space-4); }
.ai-limits__row > .field { flex: 1 1 14rem; min-width: 0; }
.ai-limits__plans { margin-top: var(--space-4); }
.ai-usage__strip {
  position: relative;
  display: flex;
  align-items: flex-end;
  gap: 2px;
  width: 9.5rem;
  height: 2.5rem;
  border-bottom: 1px solid var(--color-border);
}
.ai-usage__bar { flex: 1; min-height: 1px; background: var(--color-accent); border-radius: 1px 1px 0 0; }
.ai-usage__bar--over { background: var(--color-danger); }
.ai-usage__limit {
  position: absolute;
  left: 0;
  right: 0;
  border-top: 1px dashed var(--color-text-muted);
  pointer-events: none;
}

/* 2.417.0. The help, in a panel over the screen somebody is on (Kelly:
   "so the user can review it while they still see the editor or the
   portal they are in"). static/js/help-panel.js. */
.help-panel {
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  z-index: 1100;
  display: flex;
  flex-direction: column;
  width: min(34rem, 100vw);
  background: var(--color-surface);
  border-left: 1px solid var(--color-border);
  box-shadow: var(--shadow-lg);
}

.help-panel[hidden] { display: none; }

.help-panel__head {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
  border-bottom: 1px solid var(--color-border);
}

.help-panel__title {
  margin: 0 auto 0 0;
  font-size: var(--text-md);
}

.help-panel__frame {
  flex: 1;
  width: 100%;
  border: 0;
}

/* 2.418.0. How does it work? Every block's page, by group, on the help's
   index and its own page (templates/support/_how_list.html). */
.help-index__heading { margin-top: var(--space-8); }

.help-how {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(14rem, 1fr));
  gap: var(--space-5);
  margin-top: var(--space-4);
}

.help-how__title {
  margin: 0 0 var(--space-2);
  font-size: var(--text-md);
}

.help-how__list {
  margin: 0;
  padding-left: var(--space-5);
}

.help-how__list li + li { margin-top: var(--space-1); }

/* 2.419.0. Kelly's picture: the New site window wide enough for its four
   buttons in one row (templates/console/_new_site_foot.html). */
.dialog:has([data-new-site-then]) { width: min(44rem, calc(100vw - var(--space-6))); }

/* 2.424.0. The files chosen for a ticket, under its file box
   (static/js/many-files.js). */
.many-files {
  margin: var(--space-2) 0 0;
  padding: 0;
  list-style: none;
}

.many-files__item {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-1) 0;
}

/* 2.427.0. A site's discount code, lost if it is deleted: red capitals
   (Kelly), on the delete page and in its window. */
.discount-warning {
  color: var(--color-danger);
  font-weight: 700;
  text-transform: uppercase;
  line-height: 1.5;
}
