
:root{
  --bg:#f1f2f5; --surface:#fff; --surface-2:#f7f8fa; --surface-3:#eef0f4;
  --ink:#14161d; --ink-2:#5a6270; --ink-3:#878e9b;
  --line:#e4e7ec; --line-2:#eef0f3;
  --accent:#5b36e0; --accent-ink:#4526b8; --accent-soft:#f0ecff; --accent-line:#dcd2ff;
  --ok:#0b7a52; --ok-soft:#e7f5ee; --ok-line:#c3e5d4;
  --warn:#c2410c; --warn-soft:#fff1e6; --warn-line:#fbc9a3;
  --err:#c02626; --err-soft:#fdecec; --err-line:#f4c9c6;
  --radius:10px;
  --rail:76px; --panel:268px;
  --shadow-1:0 1px 2px rgba(16,20,30,.05);
  --shadow-2:0 1px 3px rgba(16,20,30,.06),0 10px 28px rgba(16,20,30,.06);
}
*{box-sizing:border-box}
html,body{height:100%}
body{margin:0;background:var(--bg);color:var(--ink);
  font:15px/1.5 system-ui,-apple-system,"Segoe UI",Roboto,"Helvetica Neue",sans-serif;
  -webkit-font-smoothing:antialiased}
a{color:var(--accent-ink)}
.vh{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap}
.skip{position:absolute;left:-9999px;top:0;z-index:100;background:#fff;padding:10px 14px;
  border-radius:0 0 8px 0}
.skip:focus{left:0}

/* ── shell ───────────────────────────────────────────────────────────────── */
.app{overflow:hidden}
.shell{display:grid;grid-template-columns:var(--rail) var(--panel) minmax(0,1fr);
  height:100vh;height:100dvh}

/* ── rail ────────────────────────────────────────────────────────────────── */
.rail{background:var(--surface);border-right:1px solid var(--line);
  display:flex;flex-direction:column;align-items:center;gap:2px;padding:14px 0;overflow-y:auto}
.rail-brand{display:block;width:34px;height:34px;margin-bottom:16px;flex:none}
.mark{display:block;width:100%;height:100%}
.rail-item{display:flex;flex-direction:column;align-items:center;gap:5px;
  width:60px;padding:10px 2px 8px;border-radius:11px;flex:none;
  color:var(--ink-2);text-decoration:none;font-size:11px;font-weight:500;text-align:center;
  letter-spacing:.1px}
.rail-item .ico{width:21px;height:21px;display:block}
.rail-item:hover{background:var(--surface-2);color:var(--ink)}
.rail-item.is-active{background:var(--accent-soft);color:var(--accent-ink);font-weight:600}

/* ── panel ───────────────────────────────────────────────────────────────── */
.panel-col{background:var(--surface);border-right:1px solid var(--line);
  display:flex;flex-direction:column;min-height:0;min-width:0}
.panel-head{padding:15px 16px 13px;border-bottom:1px solid var(--line-2);flex:none}
.wordmark{font-size:15px;font-weight:650;letter-spacing:-.3px;color:var(--ink);
  display:flex;align-items:center;gap:6px;margin-bottom:9px}
.envtag{padding:1px 6px;border-radius:5px;background:var(--accent-soft);
  color:var(--accent-ink);font-size:10.5px;font-weight:600;letter-spacing:.2px;
  text-transform:uppercase}
.site-one{font-size:13px;color:var(--ink-2);white-space:nowrap;overflow:hidden;
  text-overflow:ellipsis}
.site-switch select{width:100%;font-size:13px;padding:6px 8px}
.panel-body{flex:1;min-height:0;overflow-y:auto;padding:14px 10px 18px}
.panel-title{font-size:12px;text-transform:uppercase;letter-spacing:.6px;color:var(--ink-3);
  font-weight:650;margin:2px 0 10px;padding:0 8px}
.pnav{display:flex;flex-direction:column;gap:1px}
.pnav a{display:block;padding:8px 9px;border-radius:8px;text-decoration:none;color:var(--ink);
  font-size:14px;line-height:1.35}
.pnav a:hover{background:var(--surface-2)}
.pnav a.is-active{background:var(--accent-soft);color:var(--accent-ink);font-weight:600}
.pnav .hint{display:block;font-size:11.5px;color:var(--ink-3);font-weight:400;margin-top:1px}
.pnav a.is-active .hint{color:var(--accent-ink);opacity:.75}
.panel-foot{flex:none;border-top:1px solid var(--line-2);padding:11px 16px;
  display:flex;align-items:center;justify-content:space-between;gap:10px;font-size:12.5px}
.panel-foot .who{color:var(--ink-3);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.panel-foot form{flex:none}
.panel-foot button{padding:5px 11px;font-size:12.5px}

/* ── page list in the panel (Pages) ──────────────────────────────────────── */
.plist{display:flex;flex-direction:column;gap:1px}
.plist-row{display:flex;align-items:center;gap:2px;border-radius:8px}
.plist-row:hover{background:var(--surface-2)}
.plist-row.is-active{background:var(--accent-soft)}
.plist-row > a{flex:1;min-width:0;display:block;padding:8px 4px 8px 9px;text-decoration:none;
  color:var(--ink);font-size:14px;line-height:1.35}
.plist-row.is-active > a{color:var(--accent-ink);font-weight:600}
.plist-row .plist-title{display:block;overflow-wrap:anywhere}
.plist-row .route{display:block;font-size:11.5px;color:var(--ink-3);font-weight:400;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
  font-family:ui-monospace,SFMono-Regular,Menlo,monospace}
.plist-row.is-active .route{color:var(--accent-ink);opacity:.75}
.plist-row .draft{display:inline-block;margin-left:6px;padding:0 5px;border-radius:4px;
  background:var(--warn-soft);color:var(--warn);font-size:10px;font-weight:600;
  text-transform:uppercase;letter-spacing:.3px;vertical-align:1px}
.icon-btn{flex:none;background:none;border:0;color:var(--ink-3);cursor:pointer;
  padding:6px 8px;border-radius:7px;font-size:15px;line-height:1}
.icon-btn:hover{background:var(--surface-3);color:var(--ink)}
.panel-block{margin-top:16px;padding:12px 9px 2px;border-top:1px solid var(--line-2)}
.panel-block h3{font-size:12px;text-transform:uppercase;letter-spacing:.6px;color:var(--ink-3);
  font-weight:650;margin:0 0 7px}
.panel-block p{margin:0 0 9px;font-size:12.5px;color:var(--ink-2);line-height:1.45}
.panel-block button{width:100%}
.help details{margin:0 0 8px}
.help summary{cursor:pointer;font-size:13px;color:var(--ink);line-height:1.4}
.help details p{margin:6px 0 4px}

/* ── canvas ──────────────────────────────────────────────────────────────── */
.canvas{min-width:0;min-height:0;overflow-y:auto;background:var(--bg)}
.canvas.doc{padding:30px 34px 70px}
.canvas-inner{max-width:940px}
.canvas.stage{overflow:hidden;display:flex;flex-direction:column;padding:0}

/* ── the preview stage ───────────────────────────────────────────────────── */
.stage-bar{flex:none;display:flex;align-items:center;gap:12px;flex-wrap:wrap;
  padding:11px 18px;background:var(--surface);border-bottom:1px solid var(--line)}
.stage-id{min-width:0;display:flex;align-items:baseline;gap:9px;flex-wrap:wrap}
.stage-id h1{font-size:15px;font-weight:650;margin:0;white-space:nowrap;overflow:hidden;
  text-overflow:ellipsis}
.stage-id .route{font-size:12.5px;color:var(--ink-3);
  font-family:ui-monospace,SFMono-Regular,Menlo,monospace}
.stage-tools{margin-left:auto;display:flex;align-items:center;gap:9px;flex-wrap:wrap}
.seg{display:inline-flex;background:var(--surface-2);border:1px solid var(--line);
  border-radius:9px;padding:2px;gap:2px}
.seg button{background:none;border:0;color:var(--ink-2);padding:5px 11px;border-radius:7px;
  font:inherit;font-size:12.5px;cursor:pointer}
.seg button:hover{color:var(--ink);background:var(--surface-3)}
.seg button.is-active{background:var(--surface);color:var(--ink);font-weight:600;
  box-shadow:var(--shadow-1)}
.stage-view{flex:1;min-height:0;overflow:auto;padding:20px;display:flex;justify-content:center;
  align-items:stretch;background:var(--bg)}
.frame{width:100%;max-width:100%;background:#fff;border:1px solid var(--line);
  border-radius:12px;box-shadow:var(--shadow-2);overflow:hidden;
  transition:max-width .18s ease}
.frame[data-w="tablet"]{max-width:834px}
.frame[data-w="mobile"]{max-width:414px}
.frame iframe{display:block;width:100%;height:100%;min-height:520px;border:0;background:#fff}
/* While a page is being edited, nothing that navigates away is on screen. */
html.is-page-editing .rail,html.is-page-editing .panel-col,
html.is-page-editing .trial-foot,html.is-page-editing .edit-away{display:none}
html.is-page-editing .shell{grid-template-columns:minmax(0,1fr);grid-template-rows:minmax(0,1fr)}
/* The editing dock beside the canvas (D24); a bottom sheet on a phone. */
.stage-view.is-editing{gap:16px}
.edit-dock{flex:none;width:300px;align-self:flex-start;max-height:100%;overflow:auto;
  display:flex;flex-direction:column;gap:10px;padding:14px;background:var(--surface);
  border:1px solid var(--line);border-radius:12px;box-shadow:var(--shadow-1)}
.edit-dock[hidden],.edit-dock [hidden]{display:none}
.edit-msg{margin:0;font-size:13px;color:var(--ink-2);line-height:1.45}
.edit-msg.err{color:var(--err)}
.edit-fmt{display:flex;gap:6px;margin-bottom:6px}
.edit-fmt button{padding:4px 11px}
.edit-text{min-height:90px;padding:9px 10px;border:1px solid var(--line);border-radius:8px;
  background:var(--surface);font-size:14px;line-height:1.5;overflow-wrap:anywhere}
.edit-text:focus{outline:2px solid var(--accent);outline-offset:1px}
.edit-current{display:block;max-width:100%;max-height:160px;margin-bottom:8px;
  border-radius:8px;background:var(--surface-2)}
.edit-field{display:flex;flex-direction:column;gap:4px;font-size:12px;color:var(--ink-2)}
.edit-label{margin:8px 0 6px;font-size:12px;color:var(--ink-2)}
.edit-media{display:grid;grid-template-columns:repeat(3,1fr);gap:6px;max-height:220px;
  overflow:auto;margin-bottom:8px}
.edit-media button{padding:0;aspect-ratio:1;overflow:hidden;background:var(--surface-2);
  border:2px solid transparent;border-radius:7px}
.edit-media button.is-picked{border-color:var(--accent)}
.edit-media img{display:block;width:100%;height:100%;object-fit:cover}
.edit-upload{cursor:pointer;font-size:13px;text-align:center}
.edit-actions{margin:0;display:flex;gap:8px}
.edit-prompt{margin:0 0 8px;padding:9px 10px;background:var(--surface-2);
  border:1px solid var(--line);border-radius:8px;font-size:13px;line-height:1.45;
  overflow-wrap:anywhere}

/* ── documents ───────────────────────────────────────────────────────────── */
h1{font-size:22px;margin:0 0 4px;letter-spacing:-.2px}
h2{font-size:16px;margin:26px 0 10px}
.sub{color:var(--ink-2);margin:0 0 20px}
/* A page title with its one primary action beside it, e.g. Team's "+ Add user". */
.page-head{display:flex;align-items:flex-start;justify-content:space-between;gap:12px;
  flex-wrap:wrap}
.page-head>button{margin-top:2px}
.panel{background:var(--surface);border:1px solid var(--line);border-radius:var(--radius);
  padding:16px 18px;margin-bottom:16px;box-shadow:var(--shadow-1)}
.toolbar{display:flex;gap:10px;flex-wrap:wrap;align-items:end;margin-bottom:14px}
.toolbar label{display:flex;flex-direction:column;gap:4px;font-size:12px;color:var(--ink-2)}
/* Field groups on create/edit forms. Distinct from .toolbar, which is a row of
   controls that acts on a list — a form laid out as a toolbar wraps unevenly and
   reads as filters rather than as fields you are expected to fill in. */
.form-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(240px,1fr));
  gap:12px 16px;margin-bottom:18px}
.form-grid label{display:flex;flex-direction:column;gap:4px;font-size:12px;color:var(--ink-2)}
.form-grid label.wide{grid-column:1/-1}
.field-hint{color:var(--ink-3);font-size:12px}
.form-grid textarea{min-height:90px;resize:vertical}
input,select,textarea{font:inherit;padding:7px 9px;border:1px solid var(--line);
  border-radius:8px;background:var(--surface);color:var(--ink);max-width:100%}
input:focus,select:focus,textarea:focus{outline:2px solid var(--accent);outline-offset:1px}
button{font:inherit;padding:7px 13px;border-radius:8px;border:1px solid var(--accent);
  background:var(--accent);color:#fff;cursor:pointer;font-weight:550}
button:hover{background:var(--accent-ink);border-color:var(--accent-ink)}
button.ghost{background:var(--surface);color:var(--ink);border-color:var(--line);font-weight:500}
button.ghost:hover{background:var(--surface-2);border-color:var(--ink-3)}
button.danger{background:var(--err);border-color:var(--err)}
button.danger:hover{background:#a11f1f;border-color:#a11f1f}
button:disabled{opacity:.55;cursor:not-allowed}
.btn-link{display:inline-block;padding:7px 13px;border-radius:8px;border:1px solid var(--line);
  background:var(--surface);color:var(--ink);text-decoration:none;font-size:14px}
.btn-link:hover{background:var(--surface-2);border-color:var(--ink-3)}

.table-wrap{overflow-x:auto}
table{border-collapse:collapse;width:100%;font-size:14px}
th,td{text-align:left;padding:9px 10px;border-bottom:1px solid var(--line-2);vertical-align:top}
th{font-size:12px;text-transform:uppercase;letter-spacing:.4px;color:var(--ink-3);
  font-weight:650;white-space:nowrap}
tbody tr:hover{background:var(--surface-2)}
tbody tr:last-child td{border-bottom:0}
.empty{padding:34px 10px;text-align:center;color:var(--ink-2)}

/* Home's derived checklist. The marker is a pseudo-element rather than an emoji or
   an inline SVG per row: it has to take the row's colour, and a tick glyph renders
   at a different weight on every platform. */
h2.flush{margin-top:0}
.home-hero{margin:4px 0 20px}
.home-kicker{margin:0 0 6px;font-size:12px;font-weight:650;letter-spacing:.6px;
  text-transform:uppercase;color:var(--accent)}
.home-hero h1{font-size:28px;line-height:1.2;letter-spacing:-.4px;margin:0}
.home-progress{display:flex;align-items:center;gap:12px;margin-top:14px;max-width:420px}
.home-progress-text{font-size:13px;color:var(--ink-2);white-space:nowrap}
progress.bar{flex:1;width:100%;height:8px;border:0;border-radius:99px;overflow:hidden;
  background:var(--surface-3);appearance:none;-webkit-appearance:none}
progress.bar::-webkit-progress-bar{background:var(--surface-3);border-radius:99px}
progress.bar::-webkit-progress-value{background:var(--accent);border-radius:99px}
progress.bar::-moz-progress-bar{background:var(--accent);border-radius:99px}
.trial{display:flex;align-items:center;gap:20px;margin:0 0 18px;padding:20px 22px;
  border-radius:16px;border:1px solid var(--accent-line);
  background:linear-gradient(135deg,var(--accent-soft),var(--surface) 70%)}
.trial-main{flex:1;min-width:0}
.trial-label{font-size:12px;font-weight:650;letter-spacing:.6px;text-transform:uppercase;
  color:var(--accent-ink)}
.trial-big{font-size:34px;font-weight:700;letter-spacing:-.8px;line-height:1.1;margin:4px 0 10px}
.trial-big span{font-size:16px;font-weight:550;letter-spacing:0;color:var(--ink-2)}
.trial p{margin:10px 0 0;font-size:13.5px;color:var(--ink-2)}
.trial.is-urgent{border-color:var(--warn-line);background:linear-gradient(135deg,var(--warn-soft),var(--surface) 70%)}
.trial.is-over{border-color:var(--err-line);background:linear-gradient(135deg,var(--err-soft),var(--surface) 70%)}
.journey{list-style:none;margin:0;padding:0}
.jstep{display:flex;align-items:center;gap:12px;padding:13px 4px;border-bottom:1px solid var(--line-2)}
.jstep:last-child{border-bottom:0}
/* Fixed column so the 16px tick and the 22px number line up on one axis. */
.jstep-col{flex:none;width:24px;display:flex;justify-content:center}
.jstep-mark{width:22px;height:22px;border-radius:50%;display:flex;align-items:center;
  justify-content:center;font-size:11.5px;font-weight:650;color:var(--ink-3);
  border:1.5px solid var(--line)}
.jstep-mark.is-done{width:16px;height:16px;background:var(--ok);border-color:var(--ok)}
.jstep-mark.is-done::after{content:"";width:3.5px;height:7px;margin-top:-1.5px;
  border-right:1.75px solid #fff;border-bottom:1.75px solid #fff;transform:rotate(42deg)}
.jstep-body{flex:1;min-width:0}
.jstep-title{font-size:14.5px;font-weight:550;color:var(--ink)}
.jstep.is-done .jstep-title{color:var(--ink-2);font-weight:500}
.jstep-detail{font-size:13px;color:var(--ink-3);margin-top:2px;line-height:1.45}
.jstep.is-next{background:var(--accent-soft);border-radius:12px;border-bottom-color:transparent;
  padding:16px 14px;margin:4px -10px}
.jstep.is-next .jstep-mark{border-color:var(--accent);color:var(--accent-ink);background:var(--surface)}
.jstep.is-next .jstep-title{font-size:15.5px}
.jstep .btn-link{flex:none}
.jstep-prompt{margin-top:6px;font-size:13px;color:var(--ink-2)}
.jstep-prompt summary{cursor:pointer;color:var(--accent-ink);font-weight:550}
.jstep-prompt p{margin:6px 0 0;padding:10px 12px;border-radius:8px;background:var(--surface);
  border:1px solid var(--line-2);line-height:1.5}
/* The trial along the foot of the Pages canvas. One link: the whole bar opens Billing. */
.trial-foot{position:sticky;bottom:0;z-index:5;display:flex;align-items:center;gap:16px;
  padding:11px 20px;background:var(--accent-soft);border-top:1px solid var(--accent-line);
  color:var(--accent-ink);text-decoration:none;font-size:13.5px;font-weight:600}
.trial-foot:hover{background:var(--accent-line)}
.canvas.stage > .trial-foot{flex:none}
.trial-foot .bar{flex:1;max-width:320px}
.trial-foot-cta{margin-left:auto;white-space:nowrap}
.trial-foot.is-urgent{background:var(--warn-soft);border-top-color:var(--warn-line);color:var(--warn)}
.trial-foot.is-over{background:var(--err-soft);border-top-color:var(--err-line);color:var(--err)}
@media (max-width:720px){
  .trial{flex-direction:column;align-items:stretch}
  .jstep{flex-wrap:wrap}
  .jstep .btn-link{margin-left:36px}
  .trial-foot .bar{display:none}
}
.pill{display:inline-block;padding:2px 9px;border-radius:999px;font-size:12px;
  border:1px solid var(--line);background:var(--surface-3);color:var(--ink-2);white-space:nowrap}
.pill.ok{background:var(--ok-soft);border-color:var(--ok-line);color:var(--ok)}
.pill.warn{background:var(--warn-soft);border-color:var(--warn-line);color:var(--warn)}
.pill.err{background:var(--err-soft);border-color:var(--err-line);color:var(--err)}
/* The standing billing banner. Same soft/line palette as the pills, so a page that
   carries one still reads as the dashboard rather than as an error screen. */
.notice{margin:0 0 18px;padding:10px 14px;border-radius:8px;border:1px solid var(--line);
  background:var(--surface-3);color:var(--ink-2);font-size:13.5px}
.notice a{color:inherit;font-weight:600}
.notice.warn{background:var(--warn-soft);border-color:var(--warn-line);color:var(--warn)}
.notice.err{background:var(--err-soft);border-color:var(--err-line);color:var(--err)}
.muted{color:var(--ink-2);font-size:13px}
.err{color:var(--err)}
.mono{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12.5px}
/* Plan cards on the Billing tab — moseik.ca/pricing's card, in the dashboard's own
   palette rather than the marketing site's dark glass. A grid that collapses to one
   column rather than a fixed three: this tab is opened on a phone as often as
   anywhere else, and three cards squeezed side by side is where a price becomes
   unreadable. */
.ladder{margin:14px 0 6px}
/* The cadence toggle borrows .seg, the shell's segmented control, so the dashboard
   has one idiom for "pick one of these" — this only makes it pill-shaped and centres
   it over the grid. (No backticks in here: this stylesheet is a template literal, and
   a prose backtick closes the string.) */
.pc-seg{border-radius:999px;padding:3px;width:max-content;margin:0 auto 18px}
.pc-seg button{border-radius:999px;padding:6px 15px;font-size:12.5px}
.pc-seg button[aria-pressed="true"]{background:var(--accent);color:#fff;font-weight:600}
.pc-seg button[aria-pressed="true"]:hover{color:#fff}
.pc-seg button:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
/* Each card is a flex column so its action lands at the same height across the row
   and the page ceiling can be pinned to the foot. */
.plans{display:grid;gap:16px;grid-template-columns:repeat(auto-fit,minmax(238px,1fr))}
.plan{position:relative;display:flex;flex-direction:column;padding:22px 20px 20px;
  border:1px solid var(--line);border-radius:14px;background:var(--surface);
  box-shadow:var(--shadow-1);transition:border-color .18s ease,box-shadow .18s ease}
.plan:hover,.plan:focus-within{border-color:var(--accent-line);box-shadow:var(--shadow-2)}
/* The tier the pricing page pushes carries the accent at rest, so it reads as
   recommended rather than as merely hovered. */
.plan--featured{border-color:var(--accent-line)}
/* The tier they are on is marked by weight, not by colour alone. */
.plan--current{border-color:var(--accent);box-shadow:inset 0 0 0 1px var(--accent)}
/* Straddles the top border rather than sitting in the flex flow: the cards in a row
   share a height, so a badge in the flow would push this one's heading down and break
   the row across the set. */
.pc-badge{position:absolute;top:0;right:18px;transform:translateY(-50%);margin:0;
  padding:3px 10px;border-radius:999px;background:var(--accent);color:#fff;
  font-size:10.5px;font-weight:650;letter-spacing:.5px;text-transform:uppercase;
  white-space:nowrap}
/* A tier sold on one cadence states that fact in the same slot. Muted on purpose: a
   second accent pill would read as a second recommendation. */
.pc-badge--fact{background:var(--surface);border:1px solid var(--line);color:var(--ink-2);
  font-weight:550}
.plan h3{margin:0;font-size:15.5px;font-weight:650;display:flex;align-items:center;
  gap:7px;flex-wrap:wrap}
.pc-for{margin:7px 0 0;font-size:13px;line-height:1.5;color:var(--ink-2);min-height:2lh}
.pc-price{margin:16px 0 0;padding-top:16px;border-top:1px solid var(--line)}
/* Both rates ship in the markup and the toggle reveals one. A card with a single
   unmodified rate — a tier sold on one cadence, or one whose other Price is
   unreachable — matches neither hide rule and stays visible in both positions. Do not
   "tidy" a modifier onto it: that blanks its price in one of the two. */
/* The min-height is the whole three-line rate — amount, cadence label, year total —
   held even by the two-line rates that have no year total: a monthly one, and every
   rate on a monthly-only tier. Measured, because without it the annual position is
   20px taller than the monthly one, so pressing the toggle slid every button and
   bullet list down the page and left the monthly-only card's out of line with the
   other two in both positions. */
/* align-content, not just align-items: the min-height above is slack on a two-line
   rate, and a wrapped flex container stretches its LINES apart to absorb it — which
   dropped the monthly-only card's cadence label 18px below the other two. Packed to
   the top, the slack collects at the foot where nothing is looking. */
.pc-rate{display:flex;align-items:baseline;align-content:start;flex-wrap:wrap;
  gap:2px 8px;min-height:70px}
.ladder[data-interval="monthly"] .pc-annual{display:none}
.ladder[data-interval="annual"] .pc-monthly{display:none}
.pc-amount{font-size:30px;font-weight:700;letter-spacing:-1px;line-height:1;color:var(--ink)}
.pc-tax{font-size:12.5px;color:var(--ink-3)}
/* Always its own line, never wrapped up beside the amount: left to flex-wrap it rides
   alongside a short figure and drops below a long one, which moves that card's button
   on every toggle. */
.pc-per{flex:0 0 100%;font-size:11px;font-weight:600;letter-spacing:.6px;
  text-transform:uppercase;color:var(--accent-ink)}
.pc-year{flex:0 0 100%;font-size:12px;color:var(--ink-3)}
/* Reserved whether or not there is a button, so the lists line up across the row —
   the tier they are on, and an unpriced one, have no action. */
.pc-act{margin:16px 0 0;min-height:35px}
.pc-act button{width:100%}
.pc-listlabel{margin:18px 0 0;font-size:11px;font-weight:600;letter-spacing:.6px;
  text-transform:uppercase;color:var(--ink-3)}
.pc-list{margin:10px 0 0;padding:0;list-style:none;display:flex;flex-direction:column;
  flex:1;gap:8px;font-size:13px;line-height:1.5;color:var(--ink-2)}
.pc-list li{position:relative;padding-left:21px}
/* The tick is drawn, not typed: generated text content is read aloud by some screen
   readers, and "check mark" before every line is noise. */
.pc-list li::before{content:"";position:absolute;left:2px;top:.36em;width:5px;height:9px;
  border-right:2px solid var(--accent);border-bottom:2px solid var(--accent);
  transform:rotate(42deg)}
/* The page ceiling is the line people shop on, so it reads as a fact rather than one
   more bullet — and it is pinned to the foot, so cards with 7, 4 and 3 bullets do not
   leave the shortest one trailing dead space. */
.pc-limit{margin-top:auto;padding-top:12px;border-top:1px solid var(--line-2);
  color:var(--ink);font-weight:600}
/* Qualified with the list so it outranks the tick above; unqualified it loses on
   specificity and the tick floats up over the rule. */
.pc-list li.pc-limit::before{top:calc(12px + .36em)}

.note{background:var(--surface-2);border:1px solid var(--line-2);border-radius:9px;
  padding:11px 13px;font-size:13px;color:var(--ink-2);line-height:1.5}

.modal{position:fixed;inset:0;background:rgba(16,20,30,.42);display:flex;
  align-items:center;justify-content:center;padding:20px;z-index:50}
.modal[hidden]{display:none}
.modal-card{background:var(--surface);border-radius:14px;padding:24px;max-width:620px;width:100%;
  max-height:85vh;overflow:auto;position:relative;box-shadow:0 12px 48px rgba(16,20,30,.22)}
.modal-x{position:absolute;top:9px;right:11px;background:none;border:0;color:var(--ink-3);
  font-size:22px;line-height:1;cursor:pointer;padding:4px 8px;border-radius:7px}
.modal-x:hover{background:var(--surface-2);color:var(--ink)}
dl.kv{display:grid;grid-template-columns:minmax(120px,auto) 1fr;gap:7px 14px;margin:0}
dl.kv dt{color:var(--ink-3);font-size:13px}
dl.kv dd{margin:0;overflow-wrap:anywhere}

.login-body{display:flex;align-items:center;justify-content:center;min-height:100vh;padding:20px;
  background:var(--bg)}
.login-card{background:var(--surface);border:1px solid var(--line);border-radius:16px;
  padding:34px;max-width:410px;width:100%;box-shadow:var(--shadow-2)}
.login-brand{display:flex;align-items:center;gap:10px;margin-bottom:22px}
.login-brand .mark{width:34px;height:34px;flex:none}
.login-brand .wordmark{font-size:20px;margin:0}
.login-card h1{margin:0 0 18px;font-size:19px}
.login-form{display:flex;flex-direction:column;gap:13px}
.login-form label{display:flex;flex-direction:column;gap:5px;font-size:13px;color:var(--ink-2)}
.login-form button{padding:9px 13px}
/* ── two-step verification ───────────────────────────────────────────────── */
/* One field on every screen, so the login card's own width is right and there is
   nothing here to widen it for. The code box is set larger than a normal input:
   it holds six digits that somebody is copying off a phone, and at body size
   people lose their place partway through. */
.login-form input[autocomplete="one-time-code"]{font-size:20px;letter-spacing:.22em;
  font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;padding:10px 12px}
/* The resend form is a second <form>, so it needs its own gap collapsed or the
   page reads as two competing actions rather than one action and a fallback. */
.login-form.resend{margin-top:16px}
/* Cancel is a THIRD stacked form on the consent screen, under the resend link. The
   negative margin above is right for one link tucked under a button and wrong for two
   links in a row — they ended up almost touching. This separates the way out from the
   way forward, which is the distinction the spacing should carry. */
.login-form.secondary-action{margin-top:12px}
/* A form button that has to read as a link: "send another code" is a fallback,
   not the primary action, and a second real button would make the page look like
   it is asking twice. */
.linklike{background:none;border:0;padding:0;color:var(--accent);cursor:pointer;
  font:inherit;text-decoration:underline;text-align:left}
/* Both of these exist because the generic button rules OUT-SPECIFY .linklike and were
   quietly winning: button:hover (0,1,1) paints an accent fill over a control meant to
   read as a link, and .login-form button (0,1,1) restores the padding .linklike (0,1,0)
   had just removed. So "send another code" looked like a link until you moved the mouse
   over it, and then looked like a second primary button — on /enrol and /verify as well
   as the consent screen. Reported from a live authorization. Both overrides are
   class-qualified so they actually win.
   NOTE: no backticks in this comment. It lives inside a template literal, and one
   stray backtick closes the whole stylesheet — the trap this repo already documents. */
.linklike:hover{background:none;border-color:transparent;color:var(--accent-ink)}
.login-form .linklike{padding:0}
.ok-note{color:var(--ok);font-size:13px;margin:0 0 4px}
/* ── the site picker ─────────────────────────────────────────────────────── */
/* Cards, not table rows: the thumbnail is the point, and a screenshot squeezed
   into a table cell stops being recognisable. auto-fill rather than a fixed
   column count so two sites do not stretch to fill a 1600px window and eight do
   not squeeze — the card width is what stays constant. */
.picker-body{background:var(--bg);min-height:100vh;padding:0 20px 60px}
.picker{max-width:1080px;margin:0 auto}
.picker-head{display:flex;align-items:center;justify-content:space-between;gap:16px;
  padding:26px 0 30px}
.picker-head .login-brand{margin:0}
.picker h1{font-size:24px;margin:0 0 5px}
.picker .sub{margin:0 0 26px}
.site-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(268px,1fr));gap:18px}
.site-card{display:flex;flex-direction:column;background:var(--surface);
  border:1px solid var(--line);border-radius:14px;overflow:hidden;text-decoration:none;
  color:var(--ink);box-shadow:var(--shadow-1);transition:box-shadow .15s ease,border-color .15s ease}
.site-card:hover{border-color:var(--accent-line);box-shadow:var(--shadow-2)}
.site-card:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
/* Fixed 8:5 box with the image cropped to fill it, so a tall capture and a short
   one make the same shape and the grid rows stay level. */
.site-shot-wrap{display:block;aspect-ratio:8/5;background:var(--surface-3);
  border-bottom:1px solid var(--line-2);overflow:hidden}
.site-shot{display:block;width:100%;height:100%;object-fit:cover;object-position:top center}
/* The no-thumbnail state. A site whose home page has not been photographed yet is
   ordinary, not broken, so it gets a deliberate-looking placeholder rather than a
   dead <img>. */
.site-shot.is-empty{display:flex;align-items:center;justify-content:center;
  font-size:44px;font-weight:600;color:var(--ink-3);
  background:linear-gradient(150deg,var(--surface-2),var(--surface-3))}
.site-meta{display:block;padding:13px 15px 15px;min-width:0}
.site-name{display:block;font-size:15px;font-weight:600;line-height:1.3;
  overflow-wrap:anywhere}
.site-host{display:block;font-size:12.5px;color:var(--ink-2);margin-top:3px;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.site-host.is-pending{color:var(--ink-3)}
.site-flag{color:var(--warn)}
.site-access{display:block;font-size:12px;color:var(--ink-3);margin-top:8px}
.site-card.is-new{border-style:dashed;box-shadow:none}
.site-shot.is-plus{font-size:52px;font-weight:300;color:var(--accent);
  background:linear-gradient(150deg,var(--accent-soft),var(--surface-2))}
/* ── welcome + start a new website ───────────────────────────────────────── */
.welcome{max-width:960px;margin:6vh auto 0;text-align:center}
/* /new: one question, centred in the space under the header (header ~86px + foot pad). */
.welcome.narrow{max-width:620px;min-height:calc(100vh - 150px);margin:0 auto;display:flex;
  flex-direction:column;justify-content:center}
.welcome-kicker{margin:0 0 10px;font-size:12px;font-weight:650;letter-spacing:.7px;
  text-transform:uppercase;color:var(--accent)}
.picker .welcome h1{font-size:34px;line-height:1.15;letter-spacing:-.6px;margin:0 0 14px}
.welcome-lede{margin:0 auto 28px;max-width:480px;font-size:16px;line-height:1.55;color:var(--ink-2)}
.welcome-cta{display:inline-block;padding:13px 26px;border-radius:12px;border:0;
  background:var(--accent);color:#fff;font-size:15.5px;font-weight:600;text-decoration:none;
  box-shadow:0 6px 20px rgba(91,54,224,.28);cursor:pointer}
.welcome-cta:hover{background:var(--accent-ink);color:#fff}
.welcome-points{list-style:none;padding:0;margin:48px 0 0;display:grid;
  grid-template-columns:repeat(3,1fr);gap:18px;text-align:left}
.welcome-points li{display:flex;flex-direction:column;gap:6px;background:var(--surface);
  border:1px solid var(--line);border-radius:16px;padding:22px 22px 24px;
  font-size:14px;line-height:1.5;color:var(--ink-2);box-shadow:var(--shadow-1)}
.welcome-points strong{display:block;color:var(--ink);font-size:18px;line-height:1.25;
  letter-spacing:-.2px;font-weight:650}
.welcome-icon{display:flex;align-items:center;justify-content:center;width:42px;height:42px;
  border-radius:12px;background:var(--accent-soft);color:var(--accent);margin-bottom:8px}
.welcome-ico{width:22px;height:22px}
.welcome-form{display:flex;flex-direction:column;align-items:center;gap:24px;margin:0 0 20px}
.welcome-form label{width:100%}
.welcome-form input{width:100%;font-size:18px;padding:15px 16px;text-align:center}
.welcome-field{display:flex;flex-direction:column;gap:8px;text-align:left;font-size:14px;
  font-weight:600;color:var(--ink)}
.welcome-form select{width:100%;font-size:16px;padding:13px 14px;border:1px solid var(--line);
  border-radius:10px;background:var(--surface);color:var(--ink);font-family:inherit}
.welcome-hint{margin:-14px 0 0;width:100%;text-align:left;font-size:13px;line-height:1.5;
  color:var(--ink-3)}
@media (max-width:720px){
  .welcome-points{grid-template-columns:1fr}
  .picker .welcome h1{font-size:27px}
}

/* The way back to the picker, beside the switcher in the panel head. */
.site-pick{display:flex;align-items:center;gap:9px}
.site-pick .site-switch{flex:1;min-width:0}
.site-all{flex:none;font-size:12px;color:var(--ink-2);text-decoration:none;white-space:nowrap}
.site-all:hover{color:var(--accent-ink);text-decoration:underline}

.social{display:flex;flex-direction:column;gap:9px}
.social-btn{display:block;text-align:center;padding:10px;border:1px solid var(--line);
  border-radius:8px;text-decoration:none;color:var(--ink);background:var(--surface)}
.social-btn:hover{background:var(--surface-2)}
/* A real button now (the endpoint is POST-only); class-qualified so the generic
   button fill and hover do not win. */
.social-form{margin:0}
.picker-new{margin-top:16px;font-size:14px}
.picker-new summary{cursor:pointer;color:var(--accent)}
.picker-new .login-form{margin-top:14px}
.social .social-btn{width:100%;font:inherit;font-weight:500;cursor:pointer;color:var(--ink);
  background:var(--surface);border:1px solid var(--line)}
.social .social-btn:hover{background:var(--surface-2);color:var(--ink);border-color:var(--line)}
.or{display:flex;align-items:center;gap:10px;color:var(--ink-3);font-size:12px;margin:16px 0}
.or::before,.or::after{content:"";flex:1;height:1px;background:var(--line)}

/* The restore control in the details modal: the picker is revealed next to the
   button by client-js, so the two have to wrap as a unit rather than as a line. */
.restore-row{display:flex;align-items:center;gap:9px;flex-wrap:wrap;margin:0 0 12px}
.restore-row select{flex:1;min-width:200px}
.modal-card h3{font-size:14px;margin:20px 0 8px}

/* Permission checklists (Team & access, and the invite form). One row per
   permission, the label beside the box and the explanation under it — the
   explanation is the only place the vocabulary is spelled out for a client now
   that the glossary panel is gone. */
.perms{display:flex;flex-direction:column;gap:2px;margin:0 0 16px}
.perm{display:flex;gap:10px;align-items:flex-start;padding:8px 9px;border-radius:8px;
  cursor:pointer}
.perm:hover{background:var(--surface-2)}
.perm input{margin:2px 0 0;flex:none}
.perm-label{display:block;font-size:14px}
.perm-detail{display:block;font-size:12px;color:var(--ink-3);line-height:1.4}
.perm-list{margin:0 0 18px;padding-left:20px;color:var(--ink-2);font-size:14px}
.perm-list li{margin:3px 0}

/* ── the invitation card ─────────────────────────────────────────────────── */
/* Deliberately echoes the invitation EMAIL: same eyebrow, same accent-soft panel,
   same primary button. The email is the only thing the invitee has seen of us, so
   a page that looks unrelated to it reads as the wrong site. invite-email.ts
   carries the same palette inline.

   NO BACKTICKS anywhere below: this stylesheet is one template literal, and a
   prose backtick in a comment closes it — esbuild then blames a word 200 lines
   away. */
.eyebrow{font-size:11.5px;font-weight:700;letter-spacing:.09em;text-transform:uppercase;
  color:var(--accent-ink);margin:0 0 8px}
.invite-card .eyebrow+h1{margin-top:0}
.invite-card h1{line-height:1.3}
/* The :not(.muted) is load-bearing: the small print underneath keeps its own
   smaller size, where a bare p rule would flatten two voices into one. */
.invite-card>p:not(.muted){font-size:14.5px;line-height:1.55;color:var(--ink-2);margin:0 0 14px}
.perm-panel{background:var(--accent-soft);border:1px solid var(--accent-line);
  border-radius:12px;padding:14px 16px;margin:0 0 18px}
.perm-panel .perm-list{margin:0;color:var(--ink)}
.perm-panel h2{font-size:11.5px;font-weight:700;letter-spacing:.06em;text-transform:uppercase;
  color:var(--accent-ink);margin:0 0 8px}
/* Domains: the moseik.app address form, the suffix fixed beside the input. */
.addr-form label{display:block;font-size:12px;color:var(--ink-2);margin-bottom:4px}
.addr-row{display:flex;gap:10px;flex-wrap:wrap;align-items:center;margin-bottom:10px}
.addr-input{display:inline-flex;align-items:center;gap:2px;flex:1 1 260px;min-width:0}
.addr-input input{flex:1;min-width:0}
/* Wendell: a pill bottom right, and his chat in a panel above it. Gone while a page is
   being edited, which owns that corner. On a phone the panel fills the screen and the
   pill stays above it as the way out. */
.wendell-bubble{position:fixed;right:20px;bottom:20px;z-index:42;display:inline-flex;
  align-items:center;gap:8px;padding:11px 18px 11px 14px;border-radius:999px;
  font-size:14px;font-weight:600;box-shadow:0 6px 20px rgba(23,20,48,.25)}
.wendell-bubble svg{width:20px;height:20px;flex:none;fill:none;stroke:currentColor;
  stroke-width:1.8;stroke-linejoin:round}
.wendell-panel{position:fixed;right:20px;bottom:76px;z-index:41;
  width:min(400px,calc(100vw - 40px));height:min(640px,calc(100vh - 110px));border:0;
  border-radius:14px;background:#fff;box-shadow:0 12px 40px rgba(23,20,48,.28)}
.wendell-panel[hidden]{display:none}
body:has(.trial-foot) .wendell-bubble{bottom:68px}
body:has(.trial-foot) .wendell-panel{bottom:124px;height:min(640px,calc(100vh - 158px))}
html.is-page-editing .wendell-bubble,html.is-page-editing .wendell-panel{display:none}
/* On Pages the chat is a column beside the preview, so a change lands where it is seen. */
.stage-view.has-wendell{gap:16px}
.wendell-panel.is-docked{position:static;flex:none;width:380px;height:auto;min-height:520px;
  align-self:stretch;border:1px solid var(--line);border-radius:12px;box-shadow:var(--shadow-1)}
@media (max-width:900px){
  .wendell-panel.is-docked{position:fixed;right:20px;bottom:76px;z-index:41;
    width:min(400px,calc(100vw - 40px));height:min(640px,calc(100vh - 110px));min-height:0}
}
@media (max-width:560px){
  .wendell-bubble,body:has(.trial-foot) .wendell-bubble{right:12px;bottom:12px}
  .wendell-panel,.wendell-panel.is-docked,body:has(.trial-foot) .wendell-panel{top:0;right:0;bottom:auto;left:0;
    width:100%;height:calc(100vh - 70px);height:calc(100dvh - 70px);border-radius:0}
}
/* Details & history: the restore control sits apart from the page's details. */
.restore-box{margin-top:18px;padding:14px 16px 4px;background:var(--surface-2);
  border:1px solid var(--line);border-radius:10px}
.restore-box h3{margin-top:0}
.restore-box select{width:100%}
/* The payment confirmation: one centred card, not a page of dashboard. */
.confirm-wrap{min-height:70vh;display:flex;align-items:center;justify-content:center}
.confirm-card{width:100%;max-width:440px;text-align:center;padding:34px 28px}
.confirm-card h1{margin:0 0 8px}
.confirm-card p{color:var(--ink-2);margin:0 0 14px}
.confirm-card .confirm-next{margin:22px 0 10px;font-size:13.5px}
.confirm-check{display:block;width:64px;height:64px;margin:0 auto 18px}
.confirm-check circle{fill:var(--ok)}
.confirm-check path{fill:none;stroke:#fff;stroke-width:4;stroke-linecap:round;stroke-linejoin:round}
.btn-link.primary{background:var(--accent);border-color:var(--accent);color:#fff;font-weight:600;
  padding:10px 18px}
.btn-link.primary:hover{background:var(--accent-ink);border-color:var(--accent-ink)}
/* ── Connected AI Agents, and the page that explains how to connect one ────────

   Both pages are aimed at a client, not at whoever wired the integration up, and
   the first version of them read as technical documentation: a bare table, and
   an endpoint URL sitting in body-sized <code> among six headings of prose. The
   two things a person actually comes here to do are COPY THE ADDRESS and START A
   CONNECTION, so those get to be the loudest things on the page. */

/* A wider measure for the agents table. The 940px doc measure is tuned for
   PROSE; a six-column row in it wraps into a stack, which is what it did. */
.canvas-inner.wide{max-width:1240px}
.canvas-inner.full{max-width:none}

/* One connected assistant, as a card rather than a table row. Grid, so every
   card's columns line up down the page the way a table's would — and shared
   verbatim with the header row via a custom property, because two grids that
   have to agree and are declared twice will eventually stop agreeing. */
.agent-grid{--agent-cols:minmax(150px,1.4fr) 230px 1fr 118px 150px 118px}
.agent-row{display:grid;grid-template-columns:var(--agent-cols);
  gap:16px;align-items:center;padding:14px 18px;background:var(--surface);
  border:1px solid var(--line);border-radius:var(--radius);margin:0 0 10px;
  box-shadow:var(--shadow-1)}
.agent-row:nth-of-type(even){background:var(--surface-2)}
.agent-head{display:grid;grid-template-columns:var(--agent-cols);
  gap:16px;padding:0 18px 7px;font-size:11.5px;font-weight:700;letter-spacing:.05em;
  text-transform:uppercase;color:var(--ink-3)}
/* Every column but the first is centred, header and cell alike, so a value sits
   under its own title instead of drifting left of it. */
.agent-head>*+*,.agent-row>*+*{text-align:center}
.agent-name{font-weight:650;color:var(--ink)}
.agent-sub{font-size:12.5px;color:var(--ink-2);margin-top:2px;word-break:break-word}
/* "Probably an earlier connection of the same assistant". Warn-coloured rather than
   error-coloured, and no icon: it is a GUESS built on a name and an origin the client
   chose for itself, so it has to read as a hint worth checking, not as a verdict. Loud
   enough to notice while scanning, quiet enough that nobody deletes a row on its word
   alone -- which is exactly what went wrong the first time these rows piled up. */
.agent-sub.earlier{color:var(--warn)}
.agent-when{font-size:13.5px;color:var(--ink)}
.agent-when .exact{display:block;font-size:11.5px;color:var(--ink-3);margin-top:2px}
.agent-row button{width:100%}
/* ⚠️ NAMED agent-perm, NOT perm. A rule set named .perm / .perms already exists
   further up this stylesheet: it is the team invite's permission CHECKBOX list,
   which flows in a COLUMN and sets display:flex on each item. A second .perms
   here overrode only the properties it restated, so the pills inherited the
   column direction and every one rendered as a full-width block — which is
   exactly how this shipped and had to be redone. Redefining half of a class
   somebody else owns is not an override, it is a collision.

   NOTE: no backticks anywhere in this file's comments. This whole stylesheet is
   a template literal, so one backtick ends the string and the build then blames
   a line nowhere near it. */
.agent-perms{display:flex;flex-wrap:wrap;gap:6px;justify-content:center}
.agent-perm{display:inline-block;font-size:12px;font-weight:600;line-height:1.5;
  padding:2px 11px;border-radius:999px;text-align:center;white-space:nowrap;
  background:var(--accent-soft);border:1px solid var(--accent-line);color:var(--accent-ink)}
.agent-perm.publish{background:var(--ok-soft);border-color:var(--ok-line);color:var(--ok)}
@media (max-width:1080px){
  .agent-head{display:none}
  .agent-row{grid-template-columns:1fr;gap:8px;text-align:left}
  .agent-row>*+*{text-align:left}
  .agent-perms{justify-content:flex-start}
  .agent-row button{width:auto}
}

/* The MCP address — the one thing on the connect page that must be impossible to
   miss and trivial to copy. */
.endpoint{display:flex;align-items:center;gap:10px;flex-wrap:wrap;
  background:var(--surface);border:1px solid var(--accent-line);border-radius:12px;
  padding:14px 16px;margin:0 0 10px}
.endpoint code{font-size:17px;font-weight:600;color:var(--accent-ink);
  font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;
  word-break:break-all;flex:1 1 260px;background:none;padding:0}
.copy-btn{flex:0 0 auto}
.copy-btn.copied,.prod-copy.copied{background:var(--ok);border-color:var(--ok)}
/* A command line, for the one client that takes one. Quieter than the address
   above it on purpose — it is the alternative, not the main route. */
.cmd{display:flex;align-items:center;gap:10px;background:var(--surface-3);
  border:1px solid var(--line);border-radius:10px;padding:11px 13px;margin:0 0 8px}
.cmd code{flex:1 1 auto;font-size:13.5px;color:var(--ink);word-break:break-all;
  font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;background:none;padding:0}

/* Numbered steps, so "how do I do this" is three short things and not six
   headings of prose. */
.steps{list-style:none;counter-reset:step;padding:0;margin:0 0 22px}
.steps li{counter-increment:step;position:relative;padding:0 0 0 40px;margin:0 0 16px}
.steps li::before{content:counter(step);position:absolute;left:0;top:-1px;
  width:26px;height:26px;border-radius:50%;background:var(--accent-soft);
  border:1px solid var(--accent-line);color:var(--accent-ink);font-size:13px;
  font-weight:700;display:flex;align-items:center;justify-content:center}
.steps li h3{margin:0 0 5px;font-size:15px;font-weight:650}
.steps li p{margin:0 0 8px;color:var(--ink-2);font-size:14px}

.ok-note{background:var(--ok-soft);border:1px solid var(--ok-line);color:var(--ok);
  border-radius:9px;padding:10px 13px;margin:0 0 12px;font-size:14px}
/* A field label that carries its own "(optional)" on the same line, so the hint
   does not become a second line of text under the question. */
.field-label{display:flex;align-items:baseline;gap:7px;font-weight:650;
  color:var(--accent-ink)}
.field-optional{font-weight:400;font-size:12.5px;color:var(--ink-3)}
/* The way back out of a page you reached by pressing a button. */
.back-link{display:inline-block;font-size:13.5px;color:var(--ink-2);
  text-decoration:none;margin:0 0 2px}
.back-link:hover{color:var(--accent-ink);text-decoration:underline}
/* A bordered aside — used for the Wendell offer, which is a different route
   rather than a footnote to this one. */
.aside-card{background:var(--surface-2);border:1px solid var(--line);
  border-radius:12px;padding:18px 20px;margin:26px 0 0}
.aside-card h2{margin:0 0 6px;font-size:16px}
.aside-card p{margin:0 0 12px;color:var(--ink-2);font-size:14px}
.aside-card .login-form{margin:12px 0 0;max-width:none}

/* The green tick on the "added to your dashboard" confirmation. A confirmation
   that looks like every other page is one people re-read to check it worked. */
.done-mark{display:flex;align-items:center;justify-content:center;width:42px;height:42px;
  border-radius:50%;background:var(--ok-soft);border:1px solid var(--ok-line);color:var(--ok);
  margin:0 0 14px}
.done-mark svg{width:22px;height:22px}

.confirm{display:inline-flex;gap:7px;align-items:center;flex-wrap:wrap;max-width:100%;min-width:0}
/* A refusal is a sentence, not a label. Without this it sets the width of whatever
   holds it and overflows the card. */
.confirm > span{min-width:0;overflow-wrap:anywhere}
.confirm .q{font-size:13px}

/* ── connected products ──────────────────────────────────────────────────── */
/* One card per product, carrying its own state. There is no separate "what is
   connected" table: it said the same thing twice and put the answer to "is this on?"
   somewhere other than the control that turns it on. */
/* Two independent columns, so each stacks at its own card heights and a short card
   never leaves a gap beside a tall one. The server deals cards out alternately. */
.prod-cards{display:flex;gap:14px;align-items:flex-start;max-width:940px}
.prod-col{flex:1 1 0;min-width:0;display:flex;flex-direction:column;gap:14px}
/* One column once two would be too narrow for the connect form inside a card. */
@media (max-width:760px){.prod-cards{flex-direction:column;align-items:stretch}}
.prod-card{background:var(--surface);border:1px solid var(--line);border-radius:12px;
  box-shadow:var(--shadow-2);overflow:hidden}
.prod-card__body{padding:20px 22px}
.prod-card__brand{display:flex;align-items:center;justify-content:space-between;gap:10px;
  margin:0 0 12px}
.prod-card__state{flex:none}
.prod-card__name{margin:0 0 6px;font-size:17px;line-height:1.2}
.prod-card__does{margin:0;color:var(--ink-2);font-size:14px}
/* Every wordmark is contained in the SAME box, and the box is deliberately TALL
   enough that width is what binds for almost all of them — so they render at a
   matching width instead of a matching height.
   A fixed height with intrinsic width was the obvious first try and it looked wrong:
   a long horizontal mark came out nearly twice the width of a stacked one (Lime
   Recruiter). Aspect ratios genuinely differ, so only a stacked lockup still falls
   short of the full width, and it is the one that should. */
.prod-logo{width:132px;height:42px;object-fit:contain;object-position:left center;
  display:block}
/* For a product with no art on file — an initial, never a broken image. */
.prod-mark{display:grid;place-items:center;width:34px;height:34px;border-radius:9px;
  background:var(--accent-soft);border:1px solid var(--accent-line);
  color:var(--accent-ink);font-weight:700;font-size:15px}

/* What was saved, restated on every load. A definition list because these are
   labelled facts, not a form the customer is being asked to fill in again. */
.prod-conn{margin:16px 0 0;padding:14px 16px;border-radius:9px;
  background:var(--ok-soft);border:1px solid var(--ok-line);
  display:flex;gap:14px;align-items:flex-start;flex-wrap:wrap}
.prod-conn__facts{margin:0;flex:1;min-width:190px;display:grid;
  grid-template-columns:auto 1fr;gap:3px 12px;font-size:13.5px;align-items:baseline}
.prod-conn__facts dt{color:var(--ok);font-weight:600}
.prod-conn__facts dd{margin:0;color:var(--ink);overflow-wrap:anywhere}
.prod-conn__off{flex:none;align-self:center}
.prod-conn__to{margin:0;flex:1;min-width:160px;font-size:13.5px;color:var(--ink);
  overflow-wrap:anywhere}
.prod-card.is-wired .prod-conn{padding:10px 14px;margin-top:12px}
.prod-actions{margin:14px 0 0}
/* The self-serve alternative: a quiet link, because the prompt is the main path. */
.prod-self{margin-top:10px}
.prod-self>summary{cursor:pointer;font-size:13px;color:var(--accent-ink);width:max-content}
.prod-self[open]>summary{margin-bottom:12px}
.prod-self .prod-fields{margin:0}
.prod-self .form-grid{grid-template-columns:1fr}

/* Not connectable yet: brand stays legible and the card has nothing to press, so it
   reads as early rather than broken. The logo is NOT desaturated — a greyed wordmark
   looks like a rendering fault, and the pill already carries the message. */
.prod-card.is-soon{box-shadow:none;background:var(--surface-2)}
.prod-card.is-soon .prod-logo{opacity:.85}
.prod-soon{margin:18px 0 0}

/* Wired by the site's agent or by staff, not from here. Styled as a live card rather
   than a muted one: this IS available today, and the only thing missing is a control,
   because there is no decision for a person to take. The lines below the pill are what
   the client fetches from the other service, and the half that fails silently. */
.prod-card.is-wired .prod-soon{margin:14px 0 12px}
.prod-readout--warn{color:var(--ink);border-left:3px solid var(--warn-line);
  background:var(--warn-soft);padding:10px 12px;border-radius:0 8px 8px 0;
  margin-bottom:0}

/* The CTA is a <summary>, so the reveal needs no JS and cannot get out of step with
   the DOM. No chevron: there is nothing to choose between, and a caret next to a
   product name reads as a picker for products the customer does not have. */
.prod-reveal{border-top:1px solid var(--line-2);margin-top:18px}
.prod-cta{list-style:none;cursor:pointer;display:inline-block;margin:16px 0 0;
  padding:9px 16px;border-radius:8px;border:1px solid var(--accent);
  background:var(--accent);color:#fff;font-weight:600;font-size:14px;user-select:none}
.prod-cta::-webkit-details-marker{display:none}
.prod-cta:hover{background:var(--accent-ink);border-color:var(--accent-ink)}
.prod-cta:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
details[open]>.prod-cta{background:var(--surface);color:var(--ink-2);
  border-color:var(--line);font-weight:500}
details[open]>.prod-cta:hover{background:var(--surface-2);border-color:var(--ink-3)}
.prod-fields{margin:18px 0 0}
/* Narrower tracks than the page default: these are two short fields, and a 1fr column
   makes an account id look like it wants a paragraph. */
.prod-fields .form-grid{margin-bottom:14px;
  grid-template-columns:repeat(auto-fit,minmax(200px,260px))}
.prod-lbl{display:flex;align-items:baseline;gap:6px}
.prod-lbl em{font-style:normal;font-size:11.5px;color:var(--ink-3)}
.prod-readout{margin:0 0 16px;font-size:13.5px;color:var(--ink-2)}
.prod-readout .mono{color:var(--ink)}

/* ── narrow ──────────────────────────────────────────────────────────────── */
/* The three columns stack into two rows: the rail becomes a horizontal strip and
   the panel a scrollable band above the canvas. No JS drawer — a drawer is state,
   and state that can disagree with the URL is a bug waiting for a small screen. */
@media (max-width:900px){
  .app{overflow:auto}
  .shell{grid-template-columns:1fr;grid-template-rows:auto auto minmax(0,1fr);height:auto;
    min-height:100dvh}
  .rail{flex-direction:row;justify-content:flex-start;gap:6px;overflow-x:auto;
    border-right:0;border-bottom:1px solid var(--line);padding:8px 12px}
  .rail-brand{width:28px;height:28px;margin:0 8px 0 0;align-self:center}
  .rail-item{flex-direction:row;gap:7px;width:auto;padding:8px 12px;font-size:13px}
  .panel-col{border-right:0;border-bottom:1px solid var(--line)}
  .panel-head{display:flex;align-items:center;gap:12px;padding:10px 14px}
  .wordmark{margin:0}
  /* .site-pick is the flex child now, not the label inside it — the switcher and
     the "All sites" link share a row and have to grow as a unit. A backtick has
     no place in here: this stylesheet is a template literal. */
  .site-pick{flex:1;min-width:0}
  .site-one{flex:1;min-width:0}
  .picker-head{padding:18px 0 22px}
  .site-grid{grid-template-columns:repeat(auto-fill,minmax(240px,1fr));gap:14px}
  .panel-body{max-height:none;padding:10px}
  .panel-title{margin-bottom:6px}
  .pnav{flex-direction:row;flex-wrap:wrap;gap:4px}
  .pnav a{padding:7px 11px;border:1px solid var(--line);border-radius:999px;font-size:13px}
  .pnav .hint{display:none}
  .canvas.doc{padding:20px 16px 56px}
  .canvas.stage{overflow:visible}
  .stage-view{padding:12px}
  .frame iframe{min-height:70vh}
  .edit-dock{position:fixed;left:0;right:0;bottom:0;z-index:20;width:auto;max-height:55vh;
    border-radius:14px 14px 0 0}
  /* Room to scroll the page above the sheet. */
  .stage-view.is-editing{padding-bottom:58vh}
}

/* Domains tab. An address is a thing with a STATE, so each one is a card carrying
   its own status colour rather than a row in a five-column table — on a phone that
   table wrapped into unreadable columns, and "what this means" was the column that
   got squeezed. Same soft/line palette as .pill, so the page still reads as the
   dashboard and not as an alert screen. */
/* Removing an address is destructive but rare, and a solid red button reads as the
   thing to press. Outlined, in the same red, so it is findable without competing
   with the primary action beside it. */
button.quiet-danger{background:var(--surface);color:var(--err);border-color:var(--err-line);
  font-weight:500}
button.quiet-danger:hover{background:var(--err-soft);border-color:var(--err)}

/* Adding a domain sits inside the addresses panel rather than in its own — one
   place that answers what reaches my site and how to add another. */
.dom-add{margin-top:18px;padding-top:16px;border-top:1px solid var(--line-2)}
.dom-add__field{flex:1;min-width:180px}
.dom-add__field input{width:100%;box-sizing:border-box}

/* The add-an-address modal: a native popover, centred by the UA's inset:0 and
   margin:auto. Alias or forward is chosen first; each choice reveals its own form. */
.dom-modal{width:min(520px,calc(100vw - 32px));box-sizing:border-box;padding:20px;
  border:1px solid var(--line);border-radius:14px;background:var(--surface);
  color:var(--ink);box-shadow:var(--shadow-2)}
.dom-modal::backdrop{background:rgba(16,20,30,.35)}
.dom-modal__head{display:flex;align-items:center;justify-content:space-between;margin:0 0 14px}
.dom-modal__head h2{margin:0;font-size:16px}
button.dom-modal__close{background:none;border:0;color:var(--ink-2);font-size:20px;
  line-height:1;padding:4px 8px}
button.dom-modal__close:hover{background:var(--surface-2);color:var(--ink)}
.dom-kind{display:grid;grid-template-columns:1fr 1fr;gap:10px;margin:0 0 16px;padding:0;border:0}
.dom-kind__opt{display:flex;flex-direction:column;gap:3px;padding:12px 14px;cursor:pointer;
  border:1px solid var(--line);border-radius:10px;transition:border-color .15s ease}
.dom-kind__opt:hover{border-color:var(--accent-line)}
.dom-kind__opt input{position:absolute;opacity:0;pointer-events:none}
.dom-kind__opt:has(input:checked){border-color:var(--accent);background:var(--accent-soft);
  box-shadow:inset 0 0 0 1px var(--accent)}
.dom-kind__opt:has(input:focus-visible){outline:2px solid var(--accent);outline-offset:2px}
.dom-kind__title{font-weight:650;font-size:14px}
.dom-kind__hint{font-size:12.5px;color:var(--ink-2)}
.dom-kind__form{display:none}
.dom-kind__form .toolbar{margin-bottom:6px;align-items:center}
.dom-kind__form p.muted{margin:0}
.dom-modal:has(input[value="alias"]:checked) .dom-kind__form--alias,
.dom-modal:has(input[value="forward"]:checked) .dom-kind__form--forward{display:block}
@media (max-width:520px){.dom-kind{grid-template-columns:1fr}}

/* A slide switch over a real checkbox, so it submits and is keyboard-operable as one. */
.toolbar .dom-switch{display:inline-flex;flex-direction:row;align-items:center;gap:8px;
  font-size:13px;color:var(--ink-2);
  cursor:pointer;white-space:nowrap}
.dom-switch input{appearance:none;margin:0;padding:0;width:34px;height:20px;border-radius:999px;
  border:0;background:var(--line);position:relative;cursor:pointer;transition:background .15s ease}
.dom-switch input::after{content:"";position:absolute;top:2px;left:2px;width:16px;height:16px;
  border-radius:50%;background:#fff;box-shadow:0 1px 2px rgba(16,20,30,.25);
  transition:transform .15s ease}
.dom-switch input:checked{background:var(--accent)}
.dom-switch input:checked::after{transform:translateX(14px)}
.dom-switch input:focus{outline:none}
.dom-switch input:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
.dom-foot{margin:14px 0 0;font-size:13px}

/* One bought domain — its apex and its www — is one group, and the group is what
   the page navigates by. Eleven domains were twenty-two flat cards over a sixty-row
   table; the heading carries the name, the state and the way in. */
.dom-group{margin:0 0 20px}
.dom-group__head{display:flex;align-items:center;flex-wrap:wrap;gap:7px 12px;margin:0 0 9px}
.dom-group__name{margin:0;font-size:14.5px;font-weight:650;color:var(--ink);
  overflow-wrap:anywhere}
.dom-group__name a{color:inherit}
/* Pushed to the end of the row, so the way in sits in the same place on every group
   however long the name is. */
.dom-group__link{margin-left:auto;font-size:13px;white-space:nowrap}
.dom-back{margin:0 0 18px;font-size:13px}
.dom-scope{font-size:14px;font-weight:600;color:var(--ink-3);overflow-wrap:anywhere}

.dom-list{display:grid;gap:8px;margin:0 0 4px}
.dom-card{position:relative;background:var(--surface);border:1px solid var(--line);
  border-radius:11px;padding:11px 15px 11px 20px;box-shadow:var(--shadow-1);
  display:flex;flex-wrap:wrap;gap:8px 16px;align-items:center}
/* The state reads as a colour before it reads as a word. */
.dom-card::before{content:"";position:absolute;left:0;top:0;bottom:0;width:4px;
  border-radius:11px 0 0 11px;background:var(--line)}
.dom-card.ok::before{background:var(--ok)}
.dom-card.warn::before{background:var(--warn)}
.dom-card.err::before{background:var(--err)}
.dom-card.is-main{border-color:var(--accent-line);background:var(--accent-soft)}
.dom-main{flex:1;min-width:210px}
.dom-host{display:flex;align-items:center;flex-wrap:wrap;gap:8px;margin:0 0 5px}
.dom-host:last-child{margin-bottom:0}
.dom-host .mono{font-size:14px;font-weight:600;color:var(--ink);overflow-wrap:anywhere}
.dom-note{margin:0;color:var(--ink-2);font-size:13px;line-height:1.45;max-width:56ch}
.dom-tag{padding:1px 8px;border-radius:5px;background:var(--surface-3);
  border:1px solid var(--line);color:var(--ink-3);font-size:11px;font-weight:600;
  letter-spacing:.2px;white-space:nowrap}
.dom-tag.is-main{background:var(--accent);border-color:var(--accent);color:#fff}
.dom-act{align-self:center;display:flex;gap:8px;flex-wrap:wrap;min-width:0;max-width:100%}

/* Observed-vs-required DNS, as a table — the shape a client has already met at
   their registrar, and the right one for a comparison of two values side by side.
   It replaces a card list that was chosen when a five-column table squeezed the
   advice column on a phone; this one is four columns and drops the advice out of
   the grid entirely, so that reason is gone. Under 720px it collapses to stacked
   labelled rows rather than scrolling sideways. */
.dns-scroll{margin:12px 0 4px;overflow-x:auto}
.dns-table{width:100%;border-collapse:collapse;font-size:13.5px}
/* The first three columns shrink to their content and never break a hostname in
   half: "proofdigital.app" wrapping to "proofdigital.a / pp" is unreadable and was
   what a bare overflow-wrap did to them. width:1% + nowrap is the shrink-to-fit
   idiom; the last column takes whatever is left and is the only one that wraps. */
.dns-table th:nth-child(-n+3),.dns-table td:nth-child(-n+3){width:1%;white-space:nowrap}
.dns-table th:nth-child(2),.dns-table td:nth-child(2),
.dns-table th:nth-child(3),.dns-table td:nth-child(3){padding-right:26px}
.dns-table td:nth-child(4){width:auto;overflow-wrap:anywhere}
.dns-table th{text-align:left;font-weight:500;font-size:12px;letter-spacing:.02em;
  color:var(--ink-3);padding:0 14px 8px 0;border-bottom:1px solid var(--line-2)}
.dns-table td{padding:13px 14px 13px 0;border-bottom:1px solid var(--line-2);
  vertical-align:top;color:var(--ink-2)}
.dns-table tr:last-child td{border-bottom:0}
/* The one column carrying a verdict. Colour is the signal, so it goes on the value
   and not on the whole row — a full row of red reads as "this domain is broken"
   when one of four records is wrong. */
.dns-cur .mono{font-weight:600}
.dns-cur.ok .mono{color:var(--ok)}
.dns-cur.warn .mono{color:var(--warn)}
.dns-cur.err .mono{color:var(--err)}
.dns-advice{display:block;margin-top:5px;font-size:12.5px;line-height:1.45;
  font-weight:400;color:var(--ink-3);max-width:52ch}

@media (max-width: 720px){
  .dns-table,.dns-table tbody,.dns-table tr,.dns-table td{display:block;width:100%}
  .dns-table thead{display:none}
  .dns-table tr{padding:12px 0;border-bottom:1px solid var(--line-2)}
  .dns-table td{border:0;padding:2px 0;display:flex;gap:10px;align-items:baseline}
  /* Undo the desktop shrink-to-fit. Width and wrapping only — NOT display, which
     would out-specify the flex rule above and take the label back out of line. */
  .dns-table td:nth-child(-n+3){width:100%;white-space:normal}
  /* The header text comes back as a label per cell, so a stacked row still says
     which value is which — the thing a horizontal scroll cannot do. */
  .dns-table td::before{content:attr(data-label);flex:0 0 108px;font-size:12px;
    color:var(--ink-3)}
  .dns-advice{margin-left:0}
}

/* The DNS sheet. Records in the order they are added, each with the reason it
   exists beside it — a client reads this once, at their registrar, with a form
   open in another tab. */
.dom-steps{counter-reset:dom-step;display:grid;gap:14px;margin:14px 0 0}
.dom-step{counter-increment:dom-step;position:relative;padding-left:38px}
.dom-step::before{content:counter(dom-step);position:absolute;left:0;top:1px;
  width:25px;height:25px;border-radius:999px;background:var(--accent);color:#fff;
  display:grid;place-items:center;font-size:12.5px;font-weight:700}
.dom-step h3{margin:2px 0 6px;font-size:14px;line-height:1.25}
.dom-step p{margin:0 0 9px;color:var(--ink-2);font-size:13px;line-height:1.45}
.dom-rec{display:grid;grid-template-columns:auto 1fr;gap:5px 12px;margin:0;
  padding:12px 14px;border-radius:9px;background:var(--surface-2);
  border:1px solid var(--line-2)}
.dom-rec dt{color:var(--ink-3);font-size:11px;text-transform:uppercase;
  letter-spacing:.4px;font-weight:650;align-self:center}
.dom-rec dd{margin:0;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;
  font-size:13px;color:var(--ink);overflow-wrap:anywhere;align-self:center}
/* Cloudflare stops exposing the ownership token once a hostname validates, so a
   client who never copied it has no way back to it. Accented, not muted. */
.dom-keep{margin:16px 0 0;padding:12px 14px;border-radius:9px;
  background:var(--accent-soft);border:1px solid var(--accent-line)}
.dom-keep h3{margin:0 0 4px;font-size:13.5px;color:var(--accent-ink)}
.dom-keep p{margin:0 0 9px;font-size:12.5px;color:var(--ink-2);line-height:1.45}
@media (max-width:560px){
  .dom-rec{grid-template-columns:1fr;gap:2px}
  .dom-rec dt{margin-top:6px}
}
