/* ---- theme (#37) ----
 *
 * Light is the default; dark is opt-in via the switch, which sets data-theme="dark" on
 * <html>. Every component already reads these tokens, so the whole console re-skins from
 * this block alone - nothing below here needed to change to flip the default.
 *
 * The light palette follows the MAIN APEX APP, not the issue's "warm cream #f7f4ed". The
 * issue claims cream matches the app shell; the app is demonstrably cool white-on-grey
 * with a blue accent, so the parenthetical is wrong and the screenshot wins. The point is
 * that a team using both all day shouldn't feel them as two products.
 */
:root {
  color-scheme: light;
  --bg: #f3f4f6;        /* the app's page ground */
  --surface: #ffffff;   /* cards sit above it */
  --surface-2: #f9fafb; /* insets, hovers */
  --border: #e5e7eb;
  --text: #111827;
  --text-2: #4b5563;
  --text-3: #6b7280;
  /* Sampled from the wordmark, not guessed: its gradient runs #0078f0 → #1008a0, with
     #1870f0 dominant. #1870f0 itself is 4.53:1 on white - past AA by 0.03, which is too
     thin a margin for every button and link in the console, so this is a shade deeper from
     the same gradient at 5.6:1. Still unmistakably the brand blue. */
  --accent: #0d5fe0;
  /* Hover states are tokens because the alternative already bit us: #37's reskin left the
     old palette's hardcoded hovers behind (near-black for buttons, terracotta for the
     primary), so light mode looked right until you put the cursor on something. A literal
     colour in a rule is a colour that only one theme was ever asked about. */
  --accent-hover: #0a4bb5;   /* a shade deeper - reads as "pressed" on white */
  --surface-hover: #eef0f3;  /* one step past --surface-2, still clearly light */
  --border-hover: #d3d7de;
  --ok: #059669;
  --warn: #b45309;
  --err: #dc2626;
  /* On light, near-black shadows go muddy; on dark they're what gives depth. Tokenised so
     each theme can be honest about it. */
  --shadow-menu: 0 6px 16px rgb(17 24 39 / 0.12);
  --shadow-modal: 0 16px 48px rgb(17 24 39 / 0.18);
  --scrim: rgb(17 24 39 / 0.35);
  /* Chip accents were picked for a dark ground and wash out on white. */
  --chip-image: #1d6fb8;
  --chip-embed: #7c3aad;
  --radius: 10px;
  --ease: cubic-bezier(0.16, 1, 0.3, 1);
  --font: ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  --mono: ui-monospace, "SF Mono", "JetBrains Mono", Menlo, monospace;
}

/* The console's original palette, kept as the dark theme rather than thrown away. */
:root[data-theme="dark"] {
  color-scheme: dark;
  --bg: #0d0d0f;
  --surface: #151518;
  --surface-2: #1c1c21;
  --border: #2a2a31;
  --text: #ececee;
  --text-2: #9a9aa4;
  --text-3: #6b6b75;
  --accent: #4d8dff;    /* the brand blue lifted for contrast on near-black */
  /* Dark lifts on hover where light deepens - these are the console's original values,
     which were the ones hardcoded in the button rules before they were tokenised. */
  --accent-hover: #6ba1ff;
  --surface-hover: #26262c;
  --border-hover: #3a3a44;
  --ok: #4ea87a;
  --warn: #d9a441;
  --err: #d1544f;
  --shadow-menu: 0 8px 24px rgb(0 0 0 / 0.35);
  --shadow-modal: 0 16px 48px rgb(0 0 0 / 0.45);
  --scrim: rgb(0 0 0 / 0.5);
  --chip-image: #6fb1e0;
  --chip-embed: #c99be0;
}

* { box-sizing: border-box; }
html, body { padding: 0; margin: 0; }
/* Always reserve the vertical scrollbar's gutter. Without this, toggling the page scrollbar
   changes the content width by ~15px: filtering the Sites grid down to a few cards removes the
   scrollbar, widens the row, and tips `auto-fill` into an extra column so every card visibly
   shrinks. Reserving the gutter keeps the width - and the column count - constant, and also
   stops the horizontal jump when a transient banner appears or clears. */
html { scrollbar-gutter: stable; }
/* While the full-screen Live Edit overlay is open, lock the page behind it: no background
   scrollbar (and no reserved gutter) bleeding through on the right edge. */
html.le-modal-open { overflow: hidden; scrollbar-gutter: auto; }
body {
  background: var(--bg);
  color: var(--text);
  font-family: var(--font);
  font-size: 14px;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
}
::selection { background: var(--accent); color: #fff; }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 4px; }
a { color: inherit; }

/* Amber banner. --warn is dark amber on light and light amber on dark, so the text can't
   be a fixed near-black - it would vanish on the light theme's darker amber. */
.demobar {
  background: color-mix(in srgb, var(--warn) 18%, var(--surface));
  color: var(--warn);
  border-bottom: 1px solid color-mix(in srgb, var(--warn) 40%, transparent);
  text-align: center; padding: 6px 12px; font-size: 12.5px; font-weight: 500;
}

.topbar {
  display: flex; align-items: center; justify-content: space-between;
  padding: 14px 24px; border-bottom: 1px solid var(--border);
  background: var(--surface); position: sticky; top: 0; z-index: 20;
}
.brand { display: flex; align-items: center; gap: 12px; }
/* Swap the whole asset per theme. The blue wordmark is a gradient - no filter turns that
   into a legible white - so the white file is a separate image and CSS picks one. */
/* align-self matters as much as width here. The rail lays the brand out in a COLUMN flex
   container, whose cross axis is horizontal, so the default align-items:stretch pulls the
   wordmark out to the full width of the rail - and because the height is pinned, it
   stretches rather than scales: 1551x503 was rendering at 187x26, an aspect of 7.19 against
   the file's 3.08. `width: auto` does not save you from stretch. It was right in the old
   top bar only because that was a row, where the cross axis is vertical.
   Sized off the file's real aspect: 26 * (1551/503) = 80.2. */
.brandmark { height: 26px; width: auto; align-self: flex-start; display: block; }
.brandmark.dark { display: none; }
:root[data-theme="dark"] .brandmark.light { display: none; }
:root[data-theme="dark"] .brandmark.dark { display: block; }
.brandsep { width: 1px; height: 22px; background: var(--border); }
.brand strong { display: block; font-size: 14px; letter-spacing: -0.01em; }
.brand .sub { display: block; color: var(--text-3); font-size: 11.5px; }

.themetoggle {
  width: 32px; height: 32px; padding: 0; display: grid; place-items: center;
  font-size: 14px; line-height: 1; color: var(--text-2);
}

/* The old page was one column under a top bar. #37 makes it a rail + content shell, per
   the Lovable reference. main is now just the viewport - the shell owns the layout. */
main { padding: 0; margin: 0; max-width: none; }

.shell { display: flex; align-items: stretch; min-height: 100vh; }

/* ---- left rail (#37) ---- */
.rail {
  width: 224px; flex: 0 0 224px; display: flex; flex-direction: column; gap: 18px;
  padding: 18px 14px; border-right: 1px solid var(--border); background: var(--surface);
  position: sticky; top: 0; height: 100vh;
}
.rail-brand { display: flex; flex-direction: column; gap: 2px; padding: 0 4px; }
.rail-sub { color: var(--text-3); font-size: 11.5px; }
.rail-create { width: 100%; }
.rail-nav { display: flex; flex-direction: column; gap: 2px; }
.rail-nav button {
  display: flex; justify-content: space-between; align-items: center; gap: 8px;
  width: 100%; background: none; border: none; border-radius: 7px;
  padding: 7px 10px; font-size: 13px; color: var(--text-2); text-align: left;
}
.rail-nav button:hover:not(:disabled) { background: var(--surface-2); border-color: transparent; }
.rail-nav button.on { background: color-mix(in srgb, var(--accent) 12%, transparent); color: var(--accent); font-weight: 500; }
.rail-nav .count { font-size: 11px; color: var(--text-3); font-family: var(--mono); }
.rail-nav button.on .count { color: inherit; }
.rail-foot { margin-top: auto; display: flex; align-items: center; gap: 8px; padding: 0 4px; }

.content { flex: 1; min-width: 0; padding: 22px 24px 40px; }
.pagehead { display: flex; align-items: center; gap: 12px; margin-bottom: 16px; }
.pagehead h1 { font-size: 20px; margin: 0; letter-spacing: -0.01em; }
.pagehead .spacer { flex: 1; }
.filters { display: flex; gap: 10px; align-items: center; margin-bottom: 16px; flex-wrap: wrap; }
.filters .spacer { flex: 1; }

.viewtoggle { display: inline-flex; gap: 2px; background: var(--surface-2); border: 1px solid var(--border); border-radius: 8px; padding: 2px; }
.viewtoggle button { background: none; border: none; border-radius: 6px; padding: 4px 10px; font-size: 13px; color: var(--text-3); }
.viewtoggle button.on { background: var(--surface); color: var(--text); }

/* ---- card grid (#37) ---- */
.grid {
  display: grid; gap: 16px;
  grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
}
.sitecard {
  display: flex; flex-direction: column;
  background: var(--surface); border: 1px solid var(--border); border-radius: 12px;
  overflow: hidden; transition: border-color 160ms var(--ease);
}
.sitecard:hover { border-color: color-mix(in srgb, var(--accent) 45%, var(--border)); }
.sitecard.picked { border-color: var(--accent); }

.sitecard-shot {
  position: relative; height: 150px; background: var(--surface-2); overflow: hidden;
  --shot-scale: 0.235;
}
/* The preview renders at desktop width and is scaled into the tile - a 260px-wide iframe
   would show the mobile layout, which isn't the thing being checked.

   The iframe is sized as a MULTIPLE OF THE TILE rather than a fixed 1200px, so that
   scaling it back down lands on exactly 100% whatever the tile happens to be. The grid is
   `minmax(260px, 1fr)`, so the tile width floats with the window; the first cut paired a
   fixed 1200px with a fixed 0.235 and assumed a 282px tile, which meant a ~90px strip off
   the right of every homepage at narrow widths (usually the phone number and the CTA) and
   a band of dead background at wide ones. Rendered viewport works out around 1000-1300px
   - desktop everywhere it matters, and never cropped. */
.sitecard-shot iframe {
  width: calc(100% / var(--shot-scale));
  height: calc(150px / var(--shot-scale));
  border: 0;
  transform: scale(var(--shot-scale)); transform-origin: 0 0;
  pointer-events: none; /* clicks belong to the card, not to someone's homepage */
}
.sitecard-noshot { display: grid; place-items: center; height: 100%; color: var(--text-3); font-size: 12px; }
.sitecard-hit { position: absolute; inset: 0; background: none; border: none; border-radius: 0; padding: 0; cursor: pointer; }
.sitecard-hit:hover { background: color-mix(in srgb, var(--accent) 7%, transparent); }
/* The chip goes on the WRAPPER, not the checkbox. Putting it on the input meant a
   solid var(--surface) fill behind a native checkbox - which on the dark theme read
   as a hard black square. A soft translucent-white pad on the wrapper reads as a
   subtle chip on any thumbnail without recolouring the checkbox itself. */
.sitecard-pick {
  position: absolute; top: 8px; left: 8px; display: grid; place-items: center;
  padding: 3px; border-radius: 5px;
  background: color-mix(in srgb, var(--surface) 78%, transparent);
  backdrop-filter: blur(2px);
}
.sitecard-pick input[type="checkbox"] {
  width: 15px; height: 15px; margin: 0; accent-color: var(--accent); cursor: pointer;
}

.sitecard-body { padding: 11px 12px 12px; display: flex; flex-direction: column; gap: 8px; }
.sitecard-top { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.sitecard-top h3 {
  margin: 0; font-size: 13.5px; font-weight: 600; letter-spacing: -0.01em;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.sitecard-meta { display: flex; flex-wrap: nowrap; align-items: center; gap: 8px; font-size: 11px; color: var(--text-3); }
.sitecard-meta .when { margin-right: auto; white-space: nowrap; }
/* When a build is in flight the progress replaces the timestamp; keep it on the
   right (where it used to sit) rather than jammed against the tag. */
.sitecard-meta .runprog { margin-left: auto; }
.sitecard-meta a { color: var(--accent); text-decoration: none; }
.sitecard-actions { display: flex; gap: 6px; align-items: center; }

/* ---- runs section (#37) ---- */
.runlist { list-style: none; margin: 0; padding: 0; }
.runlist li { border-bottom: 1px solid var(--border); }
.runlist li:last-child { border-bottom: none; }
.runlist a {
  display: flex; align-items: center; gap: 10px; padding: 9px 12px;
  text-decoration: none; font-size: 12.5px;
}
.runlist a:hover { background: var(--surface-2); }
.runlist .runname { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.runlist .when { color: var(--text-3); font-size: 11px; }

/* ---- toolbar ---- */
.toolbar { display: flex; gap: 10px; align-items: center; margin-bottom: 16px; flex-wrap: wrap; }
.toolbar .spacer { flex: 1; }
.search {
  background: var(--surface); border: 1px solid var(--border); color: var(--text);
  border-radius: var(--radius); padding: 8px 12px; font: inherit;
  /* Grow to fill the filters row; the basis keeps the full placeholder visible
     (it was clipped at the old fixed 260px min-width). */
  flex: 1 1 340px; min-width: 340px;
}
.filter {
  background: var(--surface); border: 1px solid var(--border); color: var(--text);
  border-radius: var(--radius); padding: 8px 10px; font: inherit;
}

/* ---- buttons ---- */
button {
  font: inherit; border-radius: 8px; border: 1px solid var(--border);
  background: var(--surface-2); color: var(--text); padding: 7px 12px;
  cursor: pointer; transition: background 160ms var(--ease), border-color 160ms var(--ease), transform 80ms var(--ease);
}
button:hover:not(:disabled) { background: var(--surface-hover); border-color: var(--border-hover); }
button:active:not(:disabled) { transform: translateY(1px); }
button:disabled { opacity: 0.45; cursor: not-allowed; }
/* The "signature inset shadow" #37 asks for: a hairline of light along the top edge, which
   is what stops a flat filled button reading as a rectangle of colour. Kept to one inset
   rather than a stack - it should be felt, not seen. */
button.primary {
  background: var(--accent); border-color: var(--accent); color: #fff;
  box-shadow: inset 0 1px 0 rgb(255 255 255 / 0.22);
}
button.primary:hover:not(:disabled) { background: var(--accent-hover); border-color: var(--accent-hover); }
/* Publish is the money action - give it the blue accent so it stands out from the
   neutral View/Edit/Open controls in the same row. */
button.publish {
  background: var(--accent); border-color: var(--accent); color: #fff;
  box-shadow: inset 0 1px 0 rgb(255 255 255 / 0.22);
}
button.publish:hover:not(:disabled) { background: var(--accent-hover); border-color: var(--accent-hover); }
button.ghost { background: transparent; }
button.sm { padding: 4px 9px; font-size: 12.5px; }

/* Open is an <a> (it navigates to an external preview), but it sits in a row of
   buttons and should read as one. The base `button` rules are element-scoped, so
   an anchor gets none of them - which is why Open rendered as bare link text next
   to View and Edit. Mirror the button look here. */
a.btn {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 6px 12px; border-radius: 7px;
  border: 1px solid var(--border); background: var(--surface);
  color: var(--text-1); font-size: 13px; text-decoration: none;
  cursor: pointer; transition: background var(--dur) var(--ease), border-color var(--dur) var(--ease);
}
a.btn:hover { background: var(--surface-hover); border-color: var(--border-hover); }
a.btn.sm { padding: 4px 9px; font-size: 12.5px; }

/* ---- table ---- */
.card { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); overflow: hidden; }
table { width: 100%; border-collapse: collapse; }
th, td { text-align: left; padding: 11px 14px; border-bottom: 1px solid var(--border); vertical-align: middle; }
th { color: var(--text-3); font-weight: 500; font-size: 11.5px; text-transform: uppercase; letter-spacing: 0.06em; }
tbody tr { transition: background 140ms var(--ease); }
tbody tr:hover { background: var(--surface-2); }
tbody tr:last-child td { border-bottom: none; }
td.name { font-weight: 600; }
td .rid { font-family: var(--mono); font-size: 11px; color: var(--text-3); display: block; font-weight: 400; }
td.actions { text-align: right; white-space: nowrap; }
/* `> * + *`, not `button + button`: the ⋯ is wrapped in span.rowmenu, so its previous
   sibling isn't a button and the old selector skipped it - leaving Fix and ⋯ welded
   together while Edit and Fix were correctly spaced. Spacing siblings by what they ARE
   rather than by what tag they happen to be avoids the next wrapper doing this again. */
td.actions > * + * { margin-left: 6px; }
.linkcell a { color: var(--text-2); font-size: 12.5px; text-decoration: none; border-bottom: 1px solid var(--border); }
.linkcell a:hover { color: var(--accent); border-color: var(--accent); }
.muted { color: var(--text-3); }

/* ---- status pill ---- */
.pill {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 11.5px; font-weight: 500; padding: 3px 9px 3px 7px;
  border-radius: 999px; border: 1px solid var(--border); background: var(--surface-2);
  white-space: nowrap;
}
.pill .dot { width: 6px; height: 6px; border-radius: 50%; background: var(--text-3); flex: none; }
.pill[data-s="Ready"] { color: var(--ok); border-color: color-mix(in srgb, var(--ok) 35%, transparent); }
.pill[data-s="Ready"] .dot { background: var(--ok); }
/* Published - a step beyond Ready (the site is live), so a distinct blue rather than
   reusing Ready's green. */
.pill[data-s="Published"] { color: var(--accent); border-color: color-mix(in srgb, var(--accent) 35%, transparent); }
.pill[data-s="Published"] .dot { background: var(--accent); }
.pill[data-s="Failed"] { color: var(--err); border-color: color-mix(in srgb, var(--err) 35%, transparent); }
.pill[data-s="Failed"] .dot { background: var(--err); }
.pill[data-s="Building"], .pill[data-s="Queued"], .pill[data-s="Publishing"] { color: var(--warn); border-color: color-mix(in srgb, var(--warn) 35%, transparent); }
.pill[data-s="Building"] .dot, .pill[data-s="Queued"] .dot, .pill[data-s="Publishing"] .dot { background: var(--warn); animation: pulse 1.4s var(--ease) infinite; }
@keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.25; } }
@media (prefers-reduced-motion: reduce) {
  * { animation: none !important; transition: none !important; }
}
.tag { font-size: 11px; color: var(--text-3); font-family: var(--mono); }

/* ---- drawer ---- */
.scrim {
  /* --scrim, not rgba(0,0,0,.55): the token was added for exactly this and then not used
     here, so light mode has been dimming behind a half-opaque pure black. On white that
     reads as a hole; the light token is the app's ink at 35%. */
  position: fixed; inset: 0; background: var(--scrim);
  z-index: 40; animation: fade 200ms var(--ease);
}
@keyframes fade { from { opacity: 0; } }
.drawer {
  position: fixed; top: 0; right: 0; bottom: 0; width: min(680px, 100vw);
  background: var(--surface); border-left: 1px solid var(--border);
  z-index: 50; display: flex; flex-direction: column;
  animation: slide 260ms var(--ease);
}
@keyframes slide { from { transform: translateX(24px); opacity: 0; } }
.drawer header {
  display: flex; align-items: center; justify-content: space-between;
  padding: 16px 20px; border-bottom: 1px solid var(--border);
}
.drawer header h2 { margin: 0; font-size: 15px; letter-spacing: -0.01em; }
.drawer .body { overflow-y: auto; padding: 20px; flex: 1; }
.drawer footer {
  padding: 14px 20px; border-top: 1px solid var(--border);
  display: flex; gap: 10px; align-items: center;
}
.drawer footer .spacer { flex: 1; }

/* ---- form ---- */
.field { margin-bottom: 16px; }
.field label { display: block; font-size: 12px; color: var(--text-2); margin-bottom: 5px; font-weight: 500; }
.field input, .field textarea {
  width: 100%; background: var(--bg); border: 1px solid var(--border);
  color: var(--text); border-radius: 8px; padding: 8px 10px; font: inherit;
  transition: border-color 160ms var(--ease);
}
.field input:focus, .field textarea:focus { border-color: var(--accent); outline: none; }
.field textarea { min-height: 76px; resize: vertical; line-height: 1.5; }
.field .help { font-size: 11.5px; color: var(--text-3); margin-top: 4px; }
.field.readonly input { color: var(--text-3); }

/* Radio groups inside a .field.
   The overrides are load-bearing, not tidying: `.field label` is display:block and
   `.field input` is width:100%, so without these a radio renders as a full-width block
   with its dot stretched across the row. Exactly how the Describe-a-fix textarea shipped
   broken - a control placed in a wrapper whose rules it doesn't want. */
.field .radios { display: flex; flex-direction: column; gap: 7px; }
.field label.radio {
  display: flex; align-items: center; gap: 8px;
  margin-bottom: 0; font-weight: 400; font-size: 13px; color: var(--text); cursor: pointer;
}
.field label.radio input[type="radio"] { width: auto; margin: 0; accent-color: var(--accent); }
/* Louder than .help: this one says the client's leads are going nowhere. */
.field .warn { font-size: 11.5px; color: var(--warn); margin-top: 6px; }
.field button.sm { margin-top: 8px; }

/* ---- describe a fix (prompted agent fix) ---- */
/* This prompt box sits in <section class="describe-fix">, NOT in a .field wrapper, so
   it inherited none of the form styling above and rendered as a raw browser textarea:
   roughly 20 columns wide no matter what `rows` says, and draggable on BOTH axes.
   Styled here rather than by wrapping it in .field - it is a standalone control, not a
   labelled form row. It is also the one input people write prose into, so it gets a
   generous default height: the box should invite a sentence or two, not a keyword. */
.describe-fix textarea {
  width: 100%;
  min-height: 140px;
  background: var(--bg);
  border: 1px solid var(--border);
  color: var(--text);
  border-radius: 8px;
  padding: 10px 12px;
  font: inherit;
  line-height: 1.5;
  resize: vertical; /* vertical only - horizontal drag escapes the drawer's width */
  transition: border-color 160ms var(--ease);
}
.describe-fix textarea:focus { border-color: var(--accent); outline: none; }
.describe-fix textarea::placeholder { color: var(--text-3); }
.describe-fix .help { margin-bottom: 10px; }

.banner {
  padding: 9px 12px; border-radius: 8px; font-size: 12.5px; margin-bottom: 14px;
  border: 1px solid var(--border); background: var(--surface-2);
}
.banner.err { color: var(--err); border-color: color-mix(in srgb, var(--err) 35%, transparent); }
.banner.ok { color: var(--ok); border-color: color-mix(in srgb, var(--ok) 35%, transparent); }
.banner.warn { color: var(--warn); border-color: color-mix(in srgb, var(--warn) 35%, transparent); }

.tabs { display: flex; gap: 4px; border-bottom: 1px solid var(--border); margin-bottom: 18px; }
.tabs button {
  background: none; border: none; border-bottom: 2px solid transparent;
  border-radius: 0; color: var(--text-3); padding: 8px 12px;
}
.tabs button[aria-selected="true"] { color: var(--text); border-bottom-color: var(--accent); }

pre.report {
  background: var(--bg); border: 1px solid var(--border); border-radius: 8px;
  padding: 14px; overflow-x: auto; font-family: var(--mono); font-size: 12px;
  line-height: 1.6; white-space: pre-wrap; word-break: break-word; color: var(--text-2);
  margin: 0;
}
.empty { padding: 48px 24px; text-align: center; color: var(--text-3); }

/* Rendered SEO report markdown (SeoReportPane). Reads like a document, not a code block. */
.mdreport { color: var(--text-2); font-size: 13.5px; line-height: 1.65; max-width: 760px; }
.mdreport h1 { font-size: 20px; color: var(--text); margin: 4px 0 10px; }
.mdreport h2 { font-size: 16px; color: var(--text); margin: 22px 0 8px; padding-bottom: 6px; border-bottom: 1px solid var(--border); }
.mdreport h3 { font-size: 14px; color: var(--text); margin: 16px 0 6px; }
.mdreport p { margin: 0 0 10px; }
.mdreport ul, .mdreport ol { margin: 0 0 12px; padding-left: 22px; }
.mdreport li { margin: 3px 0; }
.mdreport code { font-family: var(--mono); font-size: 12px; background: var(--bg); border: 1px solid var(--border); border-radius: 4px; padding: 1px 5px; }
.mdreport a { color: var(--accent); }
.mdreport hr { border: 0; border-top: 1px solid var(--border); margin: 18px 0; }

/* Structured audit metrics panel (SeoReportPane → AuditMetrics). */
.seo-metrics { border: 1px solid var(--border); border-radius: 10px; padding: 14px 16px; margin: 0 0 18px; background: var(--surface-2); }
.seo-metrics-top { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.seo-metrics .metric { font-size: 13px; color: var(--text-2); }
.seo-metrics .metric strong { color: var(--text); font-size: 15px; }
.sev-chip { font-size: 11px; text-transform: capitalize; padding: 2px 8px; border-radius: 999px; border: 1px solid var(--border); color: var(--text-2); white-space: nowrap; }
.sev-chip[data-sev="critical"] { color: var(--err); border-color: color-mix(in srgb, var(--err) 40%, transparent); }
.sev-chip[data-sev="high"] { color: var(--warn); border-color: color-mix(in srgb, var(--warn) 40%, transparent); }
.sev-chip[data-sev="medium"] { color: var(--accent); border-color: color-mix(in srgb, var(--accent) 40%, transparent); }
.seo-metrics-bars { margin-top: 12px; display: flex; flex-direction: column; gap: 6px; }
.seo-bar-row { display: flex; align-items: center; gap: 10px; font-size: 12px; }
.seo-kw-table { width: 100%; border-collapse: collapse; margin-top: 12px; font-size: 13px; }
.seo-kw-table th { text-align: left; font-weight: 600; color: var(--text-2); font-size: 11px; text-transform: uppercase; letter-spacing: 0.03em; padding: 4px 8px; border-bottom: 1px solid var(--border); }
.seo-kw-table td { padding: 5px 8px; border-bottom: 1px solid var(--border); color: var(--text); overflow: hidden; text-overflow: ellipsis; max-width: 260px; white-space: nowrap; }
.seo-kw-table tr:last-child td { border-bottom: none; }
.seo-bar-label { flex: 0 0 42%; color: var(--text-2); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.seo-bar-track { flex: 1; height: 8px; border-radius: 4px; background: var(--bg); overflow: hidden; }
.seo-bar-fill { display: block; height: 100%; background: var(--accent); border-radius: 4px; }
.seo-bar-num { flex: none; width: 22px; text-align: right; color: var(--text-3); font-variant-numeric: tabular-nums; }

/* Core Web Vitals strip (SeoReportPane → CwvStrip). */
.cwv-strip { border: 1px solid var(--border); border-radius: 10px; padding: 12px 16px; margin: 0 0 12px; background: var(--surface-2); }
.cwv-head { display: flex; align-items: center; gap: 10px; margin-bottom: 10px; }
.cwv-title { font-size: 13px; font-weight: 600; color: var(--text); }
.cwv-metrics { display: flex; gap: 8px; flex-wrap: wrap; }
.cwv-metric { display: flex; flex-direction: column; gap: 2px; min-width: 74px; padding: 6px 10px; border-radius: 8px; border: 1px solid var(--border); background: var(--bg); }
.cwv-metric-label { font-size: 10px; letter-spacing: 0.04em; text-transform: uppercase; color: var(--text-3); }
.cwv-metric-val { font-size: 14px; font-variant-numeric: tabular-nums; color: var(--text); }
.cwv-metric[data-rating="good"] { border-color: color-mix(in srgb, var(--ok) 45%, transparent); }
.cwv-metric[data-rating="good"] .cwv-metric-val { color: var(--ok); }
.cwv-metric[data-rating="needs-improvement"] { border-color: color-mix(in srgb, var(--warn) 45%, transparent); }
.cwv-metric[data-rating="needs-improvement"] .cwv-metric-val { color: var(--warn); }
.cwv-metric[data-rating="poor"] { border-color: color-mix(in srgb, var(--err) 45%, transparent); }
.cwv-metric[data-rating="poor"] .cwv-metric-val { color: var(--err); }

.runs { margin-top: 28px; }
.runs h3 { font-size: 12px; text-transform: uppercase; letter-spacing: 0.06em; color: var(--text-3); font-weight: 500; margin: 0 0 10px; }
.runs li { list-style: none; }
.runs ul { margin: 0; padding: 0; }
.runs a { display: flex; gap: 12px; align-items: center; padding: 8px 14px; text-decoration: none; border-bottom: 1px solid var(--border); font-size: 12.5px; }
.runs a:hover { background: var(--surface-2); }
.runs li:last-child a { border-bottom: none; }
.runs .when { color: var(--text-3); font-size: 11.5px; margin-left: auto; font-family: var(--mono); }

/* ---- clone-fix panel ---- */
.drawer.wide { width: min(820px, 100vw); }
.drawer.editor { width: min(680px, 100vw); z-index: 60; }
.scrim2 { position: fixed; inset: 0; background: rgba(0,0,0,0.45); z-index: 55; animation: fade 180ms var(--ease); }
.fixmeta { display: flex; gap: 10px; align-items: center; margin-bottom: 16px; flex-wrap: wrap; }
.drawer .body section { margin-bottom: 26px; }
.drawer .body section h3 {
  font-size: 12px; text-transform: uppercase; letter-spacing: 0.06em;
  color: var(--text-3); font-weight: 500; margin: 0 0 10px;
}
.worklist { list-style: none; margin: 0; padding: 0; }
.worklist li {
  display: flex; gap: 10px; align-items: center; padding: 9px 0;
  border-bottom: 1px solid var(--border); font-size: 13px;
}
.worklist li:last-child { border-bottom: none; }
.worklist .wtext { flex: 1; color: var(--text-2); }
.chip {
  font-size: 10.5px; font-weight: 500; padding: 2px 8px; border-radius: 999px;
  border: 1px solid var(--border); background: var(--surface-2); white-space: nowrap;
  text-transform: uppercase; letter-spacing: 0.04em;
}
.chip[data-k="image"] { color: var(--chip-image); border-color: color-mix(in srgb, var(--chip-image) 35%, transparent); }
.chip[data-k="embed"] { color: var(--chip-embed); border-color: color-mix(in srgb, var(--chip-embed) 35%, transparent); }
.chip[data-k="form"]  { color: var(--ok); border-color: color-mix(in srgb, var(--ok) 35%, transparent); }
.chip[data-k="fidelity"] { color: var(--warn); border-color: color-mix(in srgb, var(--warn) 35%, transparent); }
.chip[data-k="note"] { color: var(--text-3); }
.filelist { list-style: none; margin: 0; padding: 0; }
.filelist li { border-bottom: 1px solid var(--border); }
.filelist li:last-child { border-bottom: none; }
.filerow {
  width: 100%; display: flex; justify-content: space-between; align-items: center;
  background: none; border: none; border-radius: 0; padding: 10px 4px;
  font-family: var(--mono); font-size: 12.5px; text-align: left; color: var(--text);
}
.filerow:hover { background: var(--surface-2); }
.fixform { margin-top: 4px; }
.fixform .field input[type="file"] { padding: 6px; font-family: var(--mono); font-size: 12px; }

/* ---- request photos from client (#36) ---- */
.reqphotos {
  display: flex; flex-wrap: wrap; align-items: center; gap: 8px;
  padding: 10px 12px; margin-bottom: 14px;
  background: var(--surface-2); border: 1px solid var(--border); border-radius: 8px;
}
.reqphotos .muted { font-size: 11.5px; flex: 1; min-width: 220px; }
.reqphotos .linkrow { display: flex; gap: 6px; width: 100%; }
/* Not inside a .field, so it gets no input styling for free - same trap as the
   Describe-a-fix textarea. Styled explicitly. */
.reqphotos .linkrow input {
  flex: 1; min-width: 0; background: var(--bg); border: 1px solid var(--border);
  color: var(--text-2); border-radius: 6px; padding: 6px 8px;
  font-family: var(--mono); font-size: 11.5px;
}
.reqphotos .banner { width: 100%; }

/* ---- the client's public upload page (#36) ----
   Served to a business owner on a phone, with no console chrome around it. Deliberately
   plain: it is the only page here a non-operator ever sees. */
.uploadpage { max-width: 34rem; margin: 10vh auto; padding: 0 1.5rem; }
.uploadpage h1 { font-size: 1.5rem; margin: 0 0 8px; }
.uploadpage .lede { color: var(--text-2); line-height: 1.6; margin: 0 0 22px; }
.uploadpage .fine { color: var(--text-3); font-size: 12px; margin-top: 18px; line-height: 1.5; }
.uploadbox { display: flex; flex-direction: column; gap: 12px; align-items: flex-start; }
.picker { position: relative; overflow: hidden; display: inline-block; }
.picker input[type="file"] { position: absolute; left: -9999px; }
.picker span {
  display: inline-block; padding: 10px 16px; border-radius: 8px;
  background: var(--surface-2); border: 1px solid var(--border); cursor: pointer; font-size: 13.5px;
}
.picker span:hover { border-color: var(--accent); }
.picked { list-style: none; margin: 0; padding: 0; width: 100%; }
.picked li {
  display: flex; justify-content: space-between; gap: 10px; padding: 7px 0;
  border-bottom: 1px solid var(--border); font-size: 12.5px;
}
.picked .size { color: var(--text-3); }
.uploaderr { color: var(--warn); font-size: 12.5px; margin: 0; line-height: 1.5; }
.uploaddone h2 { font-size: 1.2rem; margin: 0 0 6px; }
.uploaddone p { color: var(--text-2); margin: 0 0 16px; }

/* ---- run progress under the status pill (#39) ---- */
/* Row layout so it fits inside .sitecard-meta beside the timestamp without adding
   height. Was column (bar over label) as its own block, which grew the card. */
.runprog { display: flex; flex-direction: row; align-items: center; gap: 6px; }
.runbar { height: 3px; width: 56px; border-radius: 2px; background: var(--surface-2); overflow: hidden; flex: none; }
.runbar span {
  display: block; height: 100%; background: var(--accent);
  /* Eases toward the new width each tick instead of stepping - a bar that jumps looks
     like it's guessing, which it is, but it needn't advertise it. */
  transition: width 900ms linear;
}
/* Past the estimate: stop implying the bar means anything. */
.runbar span.over { background: var(--text-3); }
.runprog a { font-size: 11px; color: var(--text-3); text-decoration: none; white-space: nowrap; }
.runprog a:hover { color: var(--text-2); text-decoration: underline; }

/* ---- row overflow menu (#38: Edit · Fix · ⋯) ---- */
.rowmenu { position: relative; display: inline-block; }
/* Catches the click that dismisses the menu. Fixed + full-viewport so a click anywhere
   closes it; sits under the menu itself, above everything else. */
.rowmenu-backdrop { position: fixed; inset: 0; z-index: 40; }
/* position:fixed, with top/right supplied by the component from a live measurement - see
   RowMenu. Absolute inside .rowmenu meant .sitecard's and .card's overflow:hidden (both of
   which clip rounded corners, both of which are wanted) ate the menu whole. */
.rowmenu-items {
  position: fixed; z-index: 41;
  display: flex; flex-direction: column; min-width: 148px; padding: 4px;
  background: var(--surface); border: 1px solid var(--border); border-radius: 8px;
  box-shadow: var(--shadow-menu);
}
.rowmenu-items button {
  background: none; border: none; border-radius: 6px; text-align: left;
  padding: 7px 10px; font-size: 12.5px; color: var(--text); white-space: nowrap;
}
.rowmenu-items button:hover:not(:disabled) { background: var(--surface-2); }
.rowmenu-items button.warn { color: var(--warn); }

/* ---- create chooser ---- */
.modal-backdrop {
  /* Above the Live Edit view (z-index 80): confirm/publish dialogs can now be launched from
     the Live Edit side panel (approve, re-clone, SEO run) and must sit on top of it. */
  position: fixed; inset: 0; z-index: 90; display: grid; place-items: center;
  background: var(--scrim);
}
.modal {
  width: min(460px, calc(100vw - 32px));
  background: var(--surface); border: 1px solid var(--border); border-radius: 12px;
  padding: 22px; box-shadow: var(--shadow-modal);
}
.modal h2 { margin: 0 0 16px; font-size: 17px; }
.modal .choice {
  display: flex; flex-direction: column; gap: 3px; align-items: flex-start;
  width: 100%; text-align: left; padding: 13px 14px; margin-bottom: 10px;
  border-radius: 10px;
}
.modal .choice strong { font-size: 13.5px; font-weight: 600; }
.modal .choice span { font-size: 12px; color: var(--text-3); line-height: 1.45; white-space: normal; }
.modal .choice:hover { border-color: var(--accent); }
.modal-actions { display: flex; justify-content: flex-end; gap: 8px; margin-top: 4px; }

/* ---- batch fix (#40) ---- */
.modal.wide { width: min(560px, calc(100vw - 32px)); }
/* The modal's textarea sits in a .field, so it inherits width:100% - but .field textarea's
   76px min-height is short for a sentence you're about to apply to eight sites. */
.modal .field textarea { min-height: 92px; }
.selcell { width: 34px; padding-right: 0; }
/* Table cells don't want the .field input rules; these are bare checkboxes. */
.selcell input[type="checkbox"] { width: auto; margin: 0; accent-color: var(--accent); cursor: pointer; }
.selcell input[type="checkbox"]:disabled { cursor: not-allowed; opacity: 0.35; }
.targets {
  list-style: none; margin: 0; padding: 0; max-height: 168px; overflow-y: auto;
  border: 1px solid var(--border); border-radius: 8px;
}
.targets li {
  display: flex; align-items: center; gap: 8px; padding: 7px 10px; font-size: 12.5px;
  border-bottom: 1px solid var(--border);
}
.targets li:last-child { border-bottom: none; }
.targets li > span:first-child { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.targets .detail { color: var(--text-3); font-size: 11.5px; max-width: 46%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tag.ok { color: var(--ok, #4ade80); }
.tag.bad { color: var(--warn); }

/* ---- blog manager ---- */
.segmented { display: inline-flex; gap: 2px; background: var(--surface-2); border: 1px solid var(--border); border-radius: 8px; padding: 2px; margin-bottom: 18px; }
.segmented button { background: none; border: none; border-radius: 6px; padding: 5px 14px; font-size: 12.5px; color: var(--text-3); }
.segmented button[aria-selected="true"] { background: var(--surface); color: var(--text); }
.postlist { list-style: none; margin: 0; padding: 0; }
.postlist li { display: flex; align-items: center; gap: 10px; padding: 10px 0; border-bottom: 1px solid var(--border); }
.postlist li:last-child { border-bottom: none; }
.postlist .sm { padding: 4px 9px; font-size: 12.5px; }
.blogedit .field { margin-bottom: 12px; }
.blogmgr, .blogedit { margin-top: 4px; }

/* ---- delete (danger zone) ---- */
button.danger {
  background: transparent; color: var(--err);
  border-color: color-mix(in srgb, var(--err) 35%, transparent);
}
button.danger:hover:not(:disabled) {
  background: color-mix(in srgb, var(--err) 14%, transparent);
  border-color: var(--err);
}
.danger-zone {
  margin-top: 26px; padding: 16px; border-radius: 8px;
  border: 1px solid color-mix(in srgb, var(--err) 28%, transparent);
  background: color-mix(in srgb, var(--err) 6%, transparent);
}
.danger-zone h3 { color: var(--err) !important; margin-top: 0 !important; }
.danger-zone .help { margin-top: 0; margin-bottom: 12px; }
.danger-zone code {
  font-family: var(--mono); font-size: 12px; padding: 1px 6px; border-radius: 4px;
  background: var(--surface-2); color: var(--text-2); border: 1px solid var(--border);
}
.delconfirm {
  width: 100%; padding: 8px 10px; border-radius: 8px; margin-bottom: 12px;
  background: var(--bg); border: 1px solid var(--border); color: var(--text);
  font-family: var(--mono); font-size: 13px;
}
.delconfirm:focus { border-color: var(--err); outline: none; }
.danger-actions { display: flex; gap: 8px; align-items: center; }

/* ---- reset (stuck-record recovery) ---- */
button.warn {
  background: transparent; color: var(--warn);
  border-color: color-mix(in srgb, var(--warn) 35%, transparent);
}
button.warn:hover:not(:disabled) {
  background: color-mix(in srgb, var(--warn) 14%, transparent);
  border-color: var(--warn);
}

/* ---- Usage (#75) ----
   Spend, budget and per-site AI cost. The rail's Usage badge is a money figure,
   not a count, so it gets the mono treatment rather than the pill styling. */
.rail-nav .count.money { font-variant-numeric: tabular-nums; }

.usage h3 { margin: 22px 0 10px; font-size: 14px; }
.usage .footnote { margin-top: 18px; font-size: 11.5px; }

.usage-cards { display: grid; gap: 14px; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); }
.usage-stat { padding: 14px 16px; display: flex; flex-direction: column; gap: 4px; }
.usage-stat .label { font-size: 12px; color: var(--text-3); }
.usage-stat .figure { font-size: 26px; font-family: var(--mono); font-variant-numeric: tabular-nums; }
.usage-stat.warn .figure { color: var(--warn); }
.usage-stat.over .figure { color: var(--err); }

/* Budget meter. Colour is driven by the same thresholds as budgetState() so the
   bar and the banner can never disagree. */
.usage-stat .meter { height: 5px; border-radius: 3px; background: var(--surface-2); overflow: hidden; margin-top: 6px; }
.usage-stat .meter .fill { height: 100%; background: var(--ok); transition: width 240ms var(--ease); }
.usage-stat.warn .meter .fill { background: var(--warn); }
.usage-stat.over .meter .fill { background: var(--err); }

/* Deliberately NOT .grid - that's the card grid. */
.usagetable { width: 100%; border-collapse: collapse; font-size: 13px; }
.usagetable th, .usagetable td { text-align: left; padding: 8px 10px; border-bottom: 1px solid var(--border); }
.usagetable th { font-size: 11.5px; color: var(--text-3); font-weight: 500; }
.usagetable .num { text-align: right; font-family: var(--mono); font-variant-numeric: tabular-nums; }
.usage-setup { padding: 18px 20px; }
.usage-setup ol { margin: 10px 0 0 18px; line-height: 1.7; }
.usage-setup code { font-family: var(--mono); font-size: 12px; background: var(--surface-2); padding: 1px 5px; border-radius: 4px; }

/* ---- Login (#77) ----
   Standalone page outside the app shell: no rail, no nav - someone who isn't
   signed in has nothing to navigate to. */
.loginwrap { min-height: 100dvh; display: grid; place-items: center; padding: 24px; }
.logincard {
  width: 100%; max-width: 360px; text-align: center;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: 14px; padding: 32px 28px;
}
.logincard h1 { font-size: 18px; margin: 14px 0 4px; }
.logincard .muted { font-size: 13px; margin-bottom: 20px; }
.logincard .banner { text-align: left; }
/* The login card renders BOTH wordmarks (blue for light, white for dark) and hides
   one, exactly like .brandmark in the rail. Without the three show/hide rules below
   the page ships with the logo drawn twice, side by side - which is what it did on
   the first real sign-in, on the one screen every user sees before anything else.
   The sizing rule alone was here; the visibility rules were never copied across. */
.loginmark { height: 34px; width: auto; }
.loginmark.dark { display: none; }
:root[data-theme="dark"] .loginmark.light { display: none; }
:root[data-theme="dark"] .loginmark.dark { display: block; }
.loginbtn { width: 100%; justify-content: center; padding: 10px 14px; font-size: 14px; }

/* ---- editable status pill (#80) ---- */
.pill-btn {
  cursor: pointer; font: inherit; border: 1px solid transparent;
}
.pill-btn .caret { font-size: 9px; opacity: 0.55; margin-left: 4px; }
.pill-btn:hover {
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--accent) 30%, transparent);
}
/* position:fixed so the card's overflow:hidden can't clip it - coordinates come
   from the button rect (see StatusPill). Explicit colours: an inherited colour
   rendered the options white-on-white in one theme. */
.pillmenu {
  position: fixed; z-index: 200; margin: 0; padding: 4px; list-style: none;
  min-width: 150px; background: var(--surface);
  border: 1px solid var(--border); border-radius: 8px;
  box-shadow: 0 12px 34px -10px rgba(0, 0, 0, 0.45);
}
.pillmenu li button {
  width: 100%; text-align: left; border: 0; background: none;
  padding: 6px 10px; border-radius: 6px; font-size: 13px; cursor: pointer;
  color: var(--text-1);
}
.pillmenu li button:hover { background: var(--surface-hover); }
.pillmenu li button[aria-current="true"] { color: var(--accent); font-weight: 500; }
.pillmenu li.sep { border-top: 1px solid var(--border); margin-top: 4px; padding-top: 4px; }
.pillmenu li.sep button { color: var(--text-3); }

/* ---- open with Claude (#79) ---- */
.warnlist {
  margin: 0 0 16px; padding: 12px 14px 12px 30px;
  border: 1px solid var(--border); border-left: 3px solid var(--warn, #d08b2c);
  border-radius: 8px; background: var(--surface-2, rgba(0,0,0,0.03));
  font-size: 13px; line-height: 1.5; color: var(--text-2);
}
.warnlist li + li { margin-top: 8px; }
.cmd {
  margin: 0; padding: 12px 14px; border: 1px solid var(--border); border-radius: 8px;
  background: var(--surface-2, rgba(0,0,0,0.04)); font-size: 12.5px; line-height: 1.6;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  white-space: pre; overflow-x: auto; user-select: all;
}
.cmd-actions { display: flex; gap: 8px; margin-top: 10px; flex-wrap: wrap; align-items: center; }

/* ---- admin area (#76) ---- */
.admin { display: flex; flex-direction: column; gap: 16px; }
.admintabs { display: flex; gap: 4px; border-bottom: 1px solid var(--border); }
.admintabs button {
  background: none; border: 0; border-bottom: 2px solid transparent;
  padding: 8px 12px; font-size: 13.5px; color: var(--text-3); cursor: pointer;
}
.admintabs button.on { color: var(--text-1); border-bottom-color: var(--accent); }
.adminpane { display: flex; flex-direction: column; gap: 14px; max-width: 900px; }
.adduser { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.adduser input[type="email"] { flex: 1 1 260px; }
.usertable { width: 100%; border-collapse: collapse; font-size: 13.5px; }
.usertable th {
  text-align: left; font-weight: 500; color: var(--text-3);
  padding: 6px 8px; border-bottom: 1px solid var(--border);
}
.usertable td { padding: 8px; border-bottom: 1px solid var(--border); vertical-align: middle; }
.usertable tr.inactive td { opacity: 0.55; }
.usertable td .tag { margin-left: 6px; }

/* ---- Live Edit image picker ---- */
.le-media {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 6px;
  margin: 6px 0; max-height: 220px; overflow-y: auto;
}
.le-thumb {
  padding: 0; border: 2px solid var(--border); border-radius: 6px; overflow: hidden;
  cursor: pointer; background: var(--surface-2); aspect-ratio: 1;
}
.le-thumb.on { border-color: var(--accent); }
.le-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.le-uploadbtn {
  display: inline-block; margin-top: 6px; padding: 5px 10px;
  border: 1px dashed var(--border); border-radius: 6px; cursor: pointer;
  font-size: 12px; color: var(--text-3);
}
.le-uploadbtn:hover { color: var(--text-1); border-color: var(--accent); }

/* ---- roles (#74) ---- */
.rail-me {
  display: flex; flex-direction: column; align-items: stretch; gap: 6px;
  padding: 6px 8px; margin-top: auto; margin-bottom: 0;
  border-top: 1px solid var(--border); font-size: 11.5px;
}
.rail-me-id { display: flex; align-items: center; justify-content: space-between; gap: 6px; }
.rail-me-email { color: var(--text-3); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rail-signout {
  width: 100%; text-align: center; cursor: pointer;
  padding: 5px 8px; border-radius: 6px; font-size: 11.5px;
  color: var(--text-3); background: transparent; border: 1px solid var(--border);
}
.rail-signout:hover { color: var(--text-1); background: var(--surface-2); }
.rolechip {
  flex: none; text-transform: uppercase; letter-spacing: 0.04em; font-size: 10px;
  font-weight: 600; padding: 2px 6px; border-radius: 5px; font-family: var(--mono);
}
.rolechip.role-admin    { color: var(--accent); background: color-mix(in srgb, var(--accent) 14%, transparent); }
.rolechip.role-operator { color: var(--ok); background: color-mix(in srgb, var(--ok) 14%, transparent); }
.rolechip.role-viewer   { color: var(--text-3); background: var(--surface-2); }
/* When rail-me is present it owns the margin-top:auto, so the foot shouldn't also
   push. Belt-and-braces: the foot's own margin-top:auto still works when rail-me is
   absent (basic mode). */
.rail-me + .rail-foot { margin-top: 0; }
