/* Concorde design system, as the hub wears it.
   Grey paper, neutral charcoal ink, a single vermilion accent.
   Elongated serif display, wide-tracked technical labels, hairline rules,
   and a faint film-grain. Class names are stable so the app markup just gets
   dressed up.

   This is a copy of the agent console's sheet, not an import of it. The two are
   separate images built from separate contexts, and a stylesheet fetched across
   them would make the hub's front page depend on an agent being up. The bottom
   section is the part that is only the hub's: a web app installed to a home
   screen has to survive a notch, a keyboard and no network, none of which a
   console served inside a browser tab ever had to. */

:root {
  color-scheme: light dark;
  --paper: #f4f4f5;          /* light grey */
  --surface: #fcfcfd;        /* near-white */
  --surface-2: #ededef;
  --surface-3: #e3e3e6;
  --border: #dcdce0;         /* hairline */
  --border-strong: #c3c3c9;
  --ink: #1f2023;            /* neutral charcoal */
  --ink-2: #494b50;
  --muted: #74767c;
  --red: #c1121f;            /* vermilion (the one accent) */
  --red-soft: #f6e2e0;
  --accent: var(--red);
  --accent-ink: #fcfcfd;
  --ok: #2f7d4f;  --ok-soft: #e6f0ea;
  --bad: #c1121f; --bad-soft: #f6e2e0;
  --warn: #8a6d1a; --warn-soft: #efeadb;
  --radius: 3px; --radius-sm: 2px; --radius-lg: 5px;
  --shadow: 0 1px 0 var(--border), 0 12px 30px rgba(20,20,24,.07);
  --shadow-lg: 0 24px 70px rgba(20,20,24,.20);
  --maxw: 1080px;
  --serif: "Hoefler Text", "Iowan Old Style", "Palatino Linotype", Palatino,
           Garamond, Georgia, "Times New Roman", serif;
  --label: "Helvetica Neue", "Arial Narrow", Arial, sans-serif;
  --mono: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  --grain: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}
@media (prefers-color-scheme: dark) {
  :root {
    --paper: #161719; --surface: #1e1f22; --surface-2: #26272b; --surface-3: #2f3035;
    --border: #34363b; --border-strong: #474a50;
    --ink: #f2f3f5; --ink-2: #c4c7cd; --muted: #8b8e95;
    --red: #ff5d52; --red-soft: #351b1a;
    --ok: #67c98a; --ok-soft: #14231a; --bad: #ff6b6b; --bad-soft: #351b1a;
    --warn: #e9c46a; --warn-soft: #2a2510; --accent-ink: #161719;
    --shadow: 0 1px 0 var(--border), 0 16px 40px rgba(0,0,0,.5);
    --shadow-lg: 0 28px 80px rgba(0,0,0,.7);
  }
}

* { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
/*
 * Touch, as against a mouse. The same three rules as the console's, for the same reason and word
 * for word: this is one product and the two pages are the halves of it a person moves between.
 *
 * A tap must not select the label of what it tapped, a double tap must not zoom, and the grey flash
 * a mobile browser paints over a tapped control is the browser saying "web page" out loud.
 */
button, .tab, a.btn-sm, .brand {
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
  user-select: none;
}
/* Except an invitation link, which exists to be copied out of the page: a one-time link nobody can
   select is a link nobody can send. */
.code { user-select: text; -webkit-user-select: text; }
.tabs { overscroll-behavior: contain; }
body {
  margin: 0; color: var(--ink); font-family: var(--serif);
  font-size: 17px; line-height: 1.62; letter-spacing: .003em;
  background: var(--paper);
  background-attachment: fixed;
  -webkit-font-smoothing: antialiased; text-rendering: optimizeLegibility;
}
/* film grain */
body::after {
  content: ""; position: fixed; inset: 0; z-index: 1; pointer-events: none;
  background-image: var(--grain); background-size: 160px 160px; opacity: .05;
  mix-blend-mode: multiply;
}
@media (prefers-color-scheme: dark) { body::after { mix-blend-mode: screen; opacity: .07; } }
body > * { position: relative; z-index: 2; }

::selection { background: var(--red); color: #fff; }
a { color: var(--red); text-decoration: none; }
a:hover { text-decoration: underline; text-underline-offset: 3px; text-decoration-thickness: 1px; }
.wrap { max-width: var(--maxw); margin: 0 auto; padding: 0 1.6rem; }

/* ---- red hairline strip + top bar ---- */
.topbar { position: sticky; top: 0; z-index: 30; background: color-mix(in srgb, var(--surface) 88%, transparent);
  backdrop-filter: saturate(130%) blur(10px); border-bottom: 1px solid var(--ink); }
.topbar::before { content: ""; display: block; height: 3px; background: var(--red); }
.topbar .wrap { display: flex; align-items: center; gap: .9rem; height: 60px; }
.brand { color: inherit; text-decoration: none; font-family: var(--serif); font-weight: 600; font-size: 1.32rem; letter-spacing: .02em; display: flex; align-items: center; gap: .6rem; }
.brand .dot { width: 12px; height: 12px; border-radius: 50%; background: var(--red);
  box-shadow: 0 0 0 3px var(--surface), 0 0 0 4px var(--border); }
.spacer, .grow { flex: 1; }
.who { color: var(--muted); font-size: .82rem; font-style: italic; }
/* The screen's own name in the app bar, which is a phone's arrangement: on a wide screen the tabs
   are on the page and already say which screen this is. */
.screen-title { display: none; }
/* And the way back out of an agent's page, which on a wide screen is a link at the top of it. */
.bar-back { display: none; }
/* A tab's picture belongs to the bottom bar on a phone. The wide screen's tabs are lettered on
   purpose, and an icon in front of each word is a second alphabet in the same row. */
.tab-icon { display: none; }
/* How many people are waiting for an answer. On the tab on every screen size, because it is the
   only thing in this deployment that tells an admin somebody registered: there is no mail here. */
.tab-badge { display: inline-block; min-width: 18px; height: 18px; padding: 0 5px;
  margin-left: .35rem; border-radius: 9px; background: var(--red); color: #fff;
  font-family: var(--label); font-size: .62rem; font-weight: 700; line-height: 18px;
  letter-spacing: 0; text-align: center; vertical-align: text-bottom; }

/* ---- type: elongated serif display + tracked technical labels ---- */
h1 { font-family: var(--serif); font-weight: 600; font-size: 2.7rem; line-height: 1.06;
  letter-spacing: -.01em; margin: 1.3rem 0 .5rem; }
h2 { font-family: var(--serif); font-weight: 600; font-size: 1.5rem; letter-spacing: -.005em; margin: 1.6rem 0 .7rem; }
h3 { font-family: var(--serif); font-weight: 600; font-size: 1.12rem; margin: 0 0 .25rem; }
p { margin: .5rem 0; }
.muted { color: var(--muted); }
.small { font-size: .84rem; }
.center { text-align: center; }
.hidden { display: none !important; }
.row { display: flex; gap: .7rem; align-items: flex-start; }
.row > * { flex: 1; }
/* the technical-label look: use on eyebrows, meta, table headers */
.eyebrow, .label { font-family: var(--label); text-transform: uppercase; letter-spacing: .28em;
  font-size: .68rem; font-weight: 700; color: var(--red); }

/* ---- cards: hairline plates ---- */
.card { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
  box-shadow: var(--shadow); padding: 1.4rem 1.5rem; }
.cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(265px, 1fr)); gap: 1.1rem; }
.agent-card { cursor: pointer; position: relative; transition: transform .16s ease, box-shadow .16s ease, border-color .16s ease; }
.agent-card::before { content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 3px; background: var(--red); opacity: 0; transition: opacity .16s; }
.agent-card:hover { transform: translateY(-2px); border-color: var(--border-strong); box-shadow: 0 18px 44px rgba(20,20,24,.12); }
.agent-card:hover::before { opacity: 1; }
.agent-card .name { font-family: var(--serif); font-weight: 600; font-size: 1.18rem; letter-spacing: -.005em; }
.clickable { cursor: pointer; transition: background .12s; }
.clickable:hover { background: var(--surface-2); }

/* ---- buttons: crisp, lettered ---- */
button, .btn-primary, .btn-ghost, .btn-danger, .btn-sm {
  font-family: var(--label); font-size: .76rem; font-weight: 700; text-transform: uppercase; letter-spacing: .12em;
  border-radius: var(--radius-sm); padding: .6rem 1.15rem; cursor: pointer;
  border: 1px solid var(--ink); background: var(--surface); color: var(--ink);
  transition: transform .08s, background .14s, color .14s, border-color .14s, opacity .12s;
}
button:hover { background: var(--ink); color: var(--surface); }
button:active { transform: translateY(1px); }
button:disabled { opacity: .45; cursor: not-allowed; }
.btn-primary { background: var(--red); border-color: var(--red); color: #fff; }
.btn-primary:hover { background: #a50f1a; border-color: #a50f1a; color: #fff; }
.btn-ghost { background: transparent; border-color: var(--border-strong); color: var(--ink-2); }
.btn-ghost:hover { background: var(--ink); color: var(--surface); border-color: var(--ink); }
.btn-danger { background: transparent; color: var(--red); border-color: var(--red); }
.btn-danger:hover { background: var(--red); color: #fff; }
.btn-sm { padding: .35rem .7rem; font-size: .68rem; letter-spacing: .1em; }
/*
 * A tap target is 44px, which is what a thumb is.
 *
 * Measured on a 390px screen before this: every control was between 25 and 33 pixels tall, because
 * they were sized for a pointer. Apple's number is 44, Android's is 48dp, and a 25px control is one
 * somebody misses and then presses twice. A minimum height rather than padding, so the desktop
 * layout does not move, and keyed on a coarse pointer as well as on width: a tablet is not narrow.
 */
@media (pointer: coarse), (max-width: 620px) {
  button, .btn-primary, .btn-ghost, .btn-danger, .btn-sm, a.btn-sm, input, select {
    min-height: 44px;
  }
  .btn-sm { padding: .55rem .9rem; font-size: .72rem; }
  .btn-row { gap: .5rem; flex-wrap: wrap; }
  /*
   * A button says what it does, in the case those words are written in.
   *
   * The uppercase, letterspaced label face is right for a *label*, and this stylesheet put it on
   * `button`. On a wide screen at .76rem in a row of two that reads as a house style; on a phone,
   * where controls are full width and stacked, MANAGE and OPEN and APPROVE and MAKE ADMIN turn a
   * screen into a wall of shouting in which nothing is easier to read than anything else.
   */
  button, .btn-primary, .btn-ghost, .btn-danger, .btn-sm, a.btn-sm {
    text-transform: none; letter-spacing: .01em; font-size: .84rem;
  }
  /* And the press: a tap with no answer reads as a dead control. */
  button:active, .btn-sm:active, a.btn-sm:active, a.btn-primary:active { transform: scale(.97); }
}
.btn-row { display: flex; flex-wrap: wrap; gap: .55rem; align-items: center; }

/* ---- fields ---- */
label { display: block; font-family: var(--label); text-transform: uppercase; letter-spacing: .14em;
  font-size: .7rem; font-weight: 700; color: var(--muted); margin: .9rem 0 .35rem; }
input, textarea, select { width: 100%; font-family: var(--serif); font-size: 1rem; color: var(--ink);
  background: var(--surface); border: 1px solid var(--border-strong); border-radius: var(--radius-sm); padding: .6rem .8rem;
  transition: border-color .12s, box-shadow .12s; }
input::placeholder, textarea::placeholder { color: var(--muted); font-style: italic; }
input:focus, textarea:focus, select:focus { outline: none; border-color: var(--red); box-shadow: 0 0 0 2px var(--red-soft); }
textarea { min-height: 5rem; resize: vertical; line-height: 1.55; }
select { appearance: none; background-image:
  linear-gradient(45deg, transparent 50%, var(--muted) 50%), linear-gradient(135deg, var(--muted) 50%, transparent 50%);
  background-position: calc(100% - 18px) 55%, calc(100% - 13px) 55%; background-size: 5px 5px; background-repeat: no-repeat; padding-right: 2rem; }

/* ---- tabs: ruled, tracked ---- */
.tabs { display: flex; gap: .1rem; flex-wrap: wrap; border-bottom: 1px solid var(--ink); margin: 1.1rem 0 1.4rem; }
.tab { font-family: var(--label); text-transform: uppercase; letter-spacing: .14em; font-size: .72rem; font-weight: 700;
  border: none; background: none; color: var(--muted); padding: .65rem .9rem; border-bottom: 2px solid transparent; margin-bottom: -1px; }
.tab:hover { color: var(--ink); background: none; }
.tab.on { color: var(--red); border-bottom-color: var(--red); }

/* ---- pills ---- */
.pill { display: inline-flex; align-items: center; gap: .35rem; padding: .12rem .55rem; border-radius: 999px;
  font-family: var(--label); text-transform: uppercase; letter-spacing: .1em; font-size: .64rem; font-weight: 700;
  background: var(--surface); color: var(--muted); border: 1px solid var(--border-strong); }
.pill.active, .pill.approve, .pill.yes, .pill.include { color: var(--ok); border-color: var(--ok); background: var(--ok-soft); }
.pill.reject, .pill.no, .pill.exclude { color: var(--red); border-color: var(--red); background: var(--red-soft); }
.pill.paused, .pill.pending { color: var(--warn); border-color: var(--warn); background: var(--warn-soft); }
.pill.retired { color: var(--muted); }

/* ---- lists / stats ---- */
.list-item { display: flex; align-items: center; gap: .7rem; padding: .7rem 0; border-bottom: 1px solid var(--border); }
.list-item:last-child { border-bottom: none; }
.ok { color: var(--ok); font-weight: 600; } .bad { color: var(--bad); font-weight: 600; }
.stat { display: inline-block; margin-right: 1.8rem; }
.stat b { display: block; font-family: var(--serif); font-size: 1.55rem; font-weight: 600; letter-spacing: -.01em; }
.stat .muted, .stat span:not(:first-child) { font-family: var(--label); text-transform: uppercase; letter-spacing: .12em; font-size: .62rem; }
.empty { text-align: center; color: var(--muted); padding: 2.6rem 1rem; font-style: italic; }

/* ---- banner ---- */
.banner { display: flex; align-items: center; gap: .85rem; background: var(--surface-2);
  border: 1px solid var(--border); border-left: 3px solid var(--red); border-radius: var(--radius);
  padding: .9rem 1.15rem; margin: 1rem 0; color: var(--ink-2); font-size: .95rem; }

/* ---- code, toast, modal ---- */
.code { font-family: var(--mono); font-size: .8rem; background: var(--surface-2); border: 1px solid var(--border); border-radius: 3px; padding: .1rem .4rem; }
pre { font-family: var(--mono); font-size: .8rem; line-height: 1.5; background: var(--surface-2); border: 1px solid var(--border); border-radius: var(--radius); padding: .9rem 1rem; overflow: auto; white-space: pre-wrap; word-break: break-word; }
details > summary { cursor: pointer; padding: .35rem 0; font-weight: 600; }
.toast { position: fixed; bottom: 1.5rem; left: 50%; transform: translateX(-50%) translateY(12px); background: var(--ink); color: var(--surface);
  font-family: var(--label); text-transform: uppercase; letter-spacing: .1em; font-size: .74rem; font-weight: 700;
  padding: .75rem 1.15rem; border-radius: 999px; box-shadow: var(--shadow-lg); opacity: 0; pointer-events: none; transition: opacity .22s, transform .22s; z-index: 60; }
.toast.show { opacity: 1; transform: translateX(-50%) translateY(0); }
.modal-overlay { position: fixed; inset: 0; background: color-mix(in srgb, var(--ink) 55%, transparent); backdrop-filter: blur(3px); display: flex; align-items: flex-start; justify-content: center; padding: 5vh 1rem; z-index: 50; overflow: auto; }
.modal { background: var(--surface); border: 1px solid var(--ink); border-radius: var(--radius); box-shadow: var(--shadow-lg); max-width: 680px; width: 100%; padding: 1.7rem 1.8rem; max-height: 92vh; overflow: auto; }
.proposal-head { display: flex; align-items: flex-start; gap: .8rem; padding-bottom: .8rem; margin-bottom: .5rem; border-bottom: 1px solid var(--border); }
.proposal-head h2 { margin: .1rem 0 0; }
.actions { display: flex; flex-direction: column; margin: .3rem 0 .5rem; }
.action-item { display: flex; gap: .85rem; align-items: flex-start; padding: .7rem 0; border-bottom: 1px solid var(--border); }
.action-item:last-child { border-bottom: none; }
.ai-num { flex: none; width: 1.7rem; height: 1.7rem; border-radius: 50%; display: flex; align-items: center; justify-content: center; border: 1px solid var(--red); color: var(--red); font-family: var(--label); font-weight: 700; font-size: .72rem; }
.ai-title { font-weight: 600; }
.kv { display: flex; gap: .6rem; justify-content: space-between; padding: .2rem 0; }

/* Three numbered steps in a panel. Not .steps, which is the wizard's progress bar. */
.how-to { margin: .5rem 0 1.1rem; padding-left: 1.2rem; color: var(--muted); font-size: .84rem; line-height: 1.55; }
.how-to li { margin: .2rem 0; }

/* ---- wizard steps ---- */
.steps { display: flex; gap: .6rem; margin: 1rem 0 1.4rem; }
.step { height: 2px; flex: 1; background: var(--border-strong); }
.step.on { background: var(--red); }

/* ---- chat ---- */
.chat { display: flex; flex-direction: column; gap: .55rem; max-height: 52vh; overflow: auto; padding: .25rem; }
.chat-input { display: flex; gap: .5rem; margin-top: .8rem; }
.chat-input input { flex: 1; }
.msg { padding: .6rem .9rem; border-radius: var(--radius); max-width: 82%; font-size: .96rem; line-height: 1.5; }
.msg.me { align-self: flex-end; background: var(--ink); color: var(--surface); }
.msg.bot { align-self: flex-start; background: var(--surface); border: 1px solid var(--border); }

/* ---- plain paper backgrounds (no imagery) ---- */
.auth-bg { background: var(--paper); }
.cloud-band { display: none; }

/* a long hairline rule with a red tick, used as a section divider */
.rule { height: 1px; background: var(--border); margin: 1.4rem 0; position: relative; }
.rule::before { content: ""; position: absolute; left: 0; top: -1px; width: 42px; height: 3px; background: var(--red); }

/* ---- role signposts (home + console headers) ---- */
.kicker { font-family: var(--label); text-transform: uppercase; letter-spacing: .2em;
  font-size: .6rem; font-weight: 700; color: var(--red); display: block; margin-bottom: .5rem; }
.role-card .kicker { color: var(--red); }
.role-card.op .kicker { color: var(--red); }
.consolebar { display: flex; align-items: center; gap: .6rem; flex-wrap: wrap;
  background: var(--surface-2); border: 1px solid var(--border); border-left: 3px solid var(--red);
  border-radius: var(--radius); padding: .55rem .8rem; margin: 1.1rem 0; font-size: .9rem; }
.consolebar.op { border-left-color: var(--red); }
.consolebar .tag { font-family: var(--label); text-transform: uppercase; letter-spacing: .14em;
  font-size: .62rem; font-weight: 700; color: var(--ink); }
/* topbar nav links that wrap gracefully */
.navlinks { display: flex; align-items: center; gap: .55rem; flex-wrap: wrap; justify-content: flex-end; }
.navlinks a, .navlinks .who { white-space: nowrap; }

/* ---- responsive ---- */
@media (max-width: 900px) {
  .home-hero .wrap { padding: 3.6rem 1.3rem 2.6rem !important; }
  .home-hero h1 { font-size: 2.5rem !important; }
}
@media (max-width: 620px) {
  body { font-size: 16px; }
  h1 { font-size: 1.95rem; } h2 { font-size: 1.3rem; }
  /*
   * `clip`, so nothing inside can make the page scroll sideways. The tab strip reaches past this
   * padding to the edges of the screen, which is a negative margin, which is a child wider than its
   * parent. Measured in the console, whose strip is the same: with a negative margin and a scroll
   * position of its own, a sticky scroll container put 57 pixels of itself into the width of the
   * document about half the time at 320px, and a page that scrolls sideways is the most obvious way
   * a web app says it was never opened on a phone.
   *
   * `clip` rather than `hidden`: hidden makes this a scroll container, and a sticky child sticks to
   * its nearest scroll container, so hidden would silently unstick the tabs.
   */
  .wrap { padding: 0 1.05rem; overflow-x: clip; }
  .card { padding: 1.1rem 1.15rem; }
  .row { flex-direction: column; } .row > * { width: 100%; }
  /*
   * The app bar: one row, and the name of the screen you are on.
   *
   * The mark, the signed-in email and a bordered SIGN OUT box wrapped onto two rows and took 245
   * pixels off the top of an 844 pixel screen, on every screen. None of the three is what somebody
   * came for. So the mark keeps its dot as the way home, the screen's own name takes the space,
   * and who you are signed in as is on the Settings screen, which is the screen about that.
   */
  .topbar .wrap { height: auto; min-height: 52px; flex-wrap: nowrap; gap: .55rem;
    padding-top: calc(.3rem + env(safe-area-inset-top)); padding-bottom: .3rem; }
  .brand { min-height: 44px; min-width: 44px; }
  .brand-word { display: none; }
  .brand .dot { width: 13px; height: 13px; }
  .screen-title { display: block; font-family: var(--serif); font-size: 1.12rem; font-weight: 600;
    letter-spacing: -.01em; color: var(--ink); white-space: nowrap; overflow: hidden;
    text-overflow: ellipsis; }
  /* Drawn rather than typed, so it is a chevron and not a punctuation mark in the serif face. */
  .bar-back { display: flex; align-items: center; justify-content: center; border: none;
    background: none; min-width: 42px; min-height: 44px; padding: 0; font-size: 0;
    color: var(--red); }
  .bar-back span { display: block; width: 11px; height: 11px; margin-left: 4px;
    border-left: 2px solid currentColor; border-bottom: 2px solid currentColor;
    transform: rotate(45deg); }
  .bar-back:active { transform: none; opacity: .5; }
  /* With a back button in the bar the mark stands down: two ways out of one screen, side by side,
     is one too many, and the mark is the one that leaves the app entirely. */
  #barBack:not(.hidden) ~ .brand { display: none; }
  .who { display: none; }
  #signOut { display: none; }
  /* And the page ends above the home indicator rather than under it. */
  body { padding-bottom: env(safe-area-inset-bottom); }
  .spacer { flex: 1 1 auto; }
  .navlinks { justify-content: flex-end; width: auto; }
  /*
   * The tabs are a bar along the bottom, which is where a thumb is.
   *
   * They were a strip under the top bar, which is the part of a phone a hand holding it cannot
   * reach. Every application on the device puts its destinations along the bottom, so it needs no
   * explaining, and three of them across 390 pixels is roomy once each is an icon with a word.
   */
  .tabs { position: fixed; left: 0; right: 0; bottom: 0; z-index: 40; margin: 0;
    display: flex; flex-wrap: nowrap; align-items: stretch; justify-content: space-around;
    gap: 0; padding: 0 .2rem calc(env(safe-area-inset-bottom)); border-top: 1px solid var(--border);
    border-bottom: none; background: var(--surface); overflow: visible; }
  .tab { flex: 1 1 0; display: flex; flex-direction: column; align-items: center;
    justify-content: center; gap: .12rem; min-width: 0; min-height: 52px;
    padding: .4rem .1rem .3rem; border: none; background: none; position: relative;
    font-family: var(--label); font-size: .6rem; font-weight: 700; letter-spacing: .02em;
    text-transform: none; color: var(--muted); }
  .tab-icon { display: block; height: 23px; }
  .tab-label { display: block; max-width: 100%; overflow: hidden; text-overflow: ellipsis;
    white-space: nowrap; }
  /* The one you are on is the red one: on a bar this small a 1px underline is invisible at arm's
     length. */
  .tab.on, .tab.active { color: var(--red); border: none; }
  .tab:active { background: var(--surface-2); }
  /* How many are waiting, on the icon rather than in the label: "People (1)" does not fit a bar
     along the bottom, and the number is the whole of what tells an admin anybody is there. */
  .tab-badge { position: absolute; top: .3rem; left: 55%; min-width: 17px; height: 17px;
    padding: 0 4px; border-radius: 9px; background: var(--red); color: #fff;
    font-family: var(--label); font-size: .6rem; font-weight: 700; line-height: 17px;
    text-align: center; }
  /* Room for the bar, so the last line of every screen is readable rather than under it. */
  #pane { padding-bottom: 4.6rem; }
  /*
   * A field's own label, in the case its words are written in: PIN IT TO AN ADDRESS over a box is
   * an intranet form.
   *
   * Here rather than up with the other touch rules, because the base rule for `label` is declared
   * further down this file than that block and a media query does not raise specificity. Same
   * specificity, later wins, so the override written above it silently did nothing.
   */
  label { text-transform: none; letter-spacing: .01em; font-size: .84rem; font-weight: 600;
    color: var(--ink); }
  .home-hero h1 { font-size: 2.05rem !important; }
  .home-hero p { font-size: 1.02rem !important; }
  .btn-row { gap: .5rem; } .btn-row > * { flex: 1 1 auto; text-align: center; }
  .modal { padding: 1.2rem 1.15rem; }
  .msg { max-width: 92%; }
  .stat { margin-right: 1.1rem; }
  .consolebar { flex-direction: column; align-items: flex-start; gap: .3rem; }
  .consolebar .grow { flex-basis: auto; }
}

/* -- workspace browser (file tree + markdown preview) --------------------- */
.ws { display: grid; grid-template-columns: 260px 1fr; gap: 1rem; align-items: start;
  border: 1px solid var(--border); border-radius: var(--radius); overflow: hidden; }
.ws-tree { border-right: 1px solid var(--border); background: var(--surface-2);
  padding: .5rem; max-height: 520px; overflow: auto; }
.ws-folder > summary { cursor: pointer; font-family: var(--label); letter-spacing: .04em;
  font-size: .82rem; padding: .25rem .3rem; list-style: none; }
.ws-folder > summary::-webkit-details-marker { display: none; }
.ws-folder { margin-left: .2rem; border-left: 1px solid var(--border); padding-left: .5rem; }
.ws-file { display: block; width: 100%; text-align: left; background: none; border: none;
  font-family: var(--mono); font-size: .8rem; color: var(--ink-2); cursor: pointer;
  padding: .28rem .35rem; border-radius: var(--radius-sm); }
.ws-file:hover { background: var(--surface-3); }
.ws-file.on { background: var(--surface-3); color: var(--ink); font-weight: 600; }
.ws-preview { padding: .9rem 1.1rem; max-height: 520px; overflow: auto; min-width: 0; }
.ws-empty { padding: 2rem 0; text-align: center; }
.ws-path { display: flex; align-items: center; gap: .6rem; font-family: var(--mono);
  font-size: .72rem; color: var(--muted); border-bottom: 1px solid var(--border);
  padding-bottom: .45rem; margin-bottom: .7rem; word-break: break-all; }
.ws-raw { margin-left: auto; font-family: var(--label); text-transform: uppercase;
  letter-spacing: .1em; font-size: .58rem; border: 1px solid var(--border);
  background: var(--surface); border-radius: var(--radius-sm); padding: .12rem .4rem; cursor: pointer; }
.ws-raw.on { background: var(--ink); color: var(--surface); border-color: var(--ink); }
.ws-rawbody pre { white-space: pre-wrap; font-family: var(--mono); font-size: .78rem; margin: 0; }
@media (max-width: 620px) { .ws { grid-template-columns: 1fr; }
  .ws-tree { border-right: none; border-bottom: 1px solid var(--border); max-height: 220px; } }

/* rendered markdown */
.md { font-size: .93rem; line-height: 1.6; color: var(--ink-2); word-wrap: break-word; }
.md h1, .md h2, .md h3, .md h4 { font-family: var(--serif); color: var(--ink);
  line-height: 1.2; margin: 1.1rem 0 .5rem; }
.md h1 { font-size: 1.5rem; } .md h2 { font-size: 1.22rem; } .md h3 { font-size: 1.05rem; }
.md h1:first-child, .md h2:first-child { margin-top: 0; }
.md p { margin: .55rem 0; } .md ul, .md ol { margin: .5rem 0 .5rem 1.3rem; }
.md li { margin: .2rem 0; } .md a { color: var(--red); }
.md code { font-family: var(--mono); font-size: .85em; background: var(--surface-2);
  border: 1px solid var(--border); border-radius: var(--radius-sm); padding: .05rem .3rem; }
.md pre.md-code { background: var(--surface-2); border: 1px solid var(--border);
  border-radius: var(--radius); padding: .7rem .85rem; overflow: auto; margin: .7rem 0; }
.md pre.md-code code { background: none; border: none; padding: 0; font-size: .8rem; }
.md blockquote { border-left: 3px solid var(--border-strong); margin: .7rem 0;
  padding: .1rem 0 .1rem .9rem; color: var(--muted); font-style: italic; }
.md hr { border: none; border-top: 1px solid var(--border); margin: 1.1rem 0; }

/* ---- the hub's own additions ------------------------------------------------
   Everything above this line is the shared design system. Everything below is
   here because this app gets installed to a phone's home screen. */

/* Safe areas. Installed, this app is the whole screen, so the notch and the
   home indicator are its problem rather than the browser chrome's. */
.topbar { padding-top: env(safe-area-inset-top); }
.topbar .wrap,
.wrap { padding-left: max(1.05rem, env(safe-area-inset-left));
        padding-right: max(1.05rem, env(safe-area-inset-right)); }
body { padding-bottom: env(safe-area-inset-bottom); min-height: 100svh; }

/* Standing up an auth card in the middle of a phone screen. `svh` and not `vh`
   so the card does not jump the moment the address bar collapses. */
.gate { max-width: 30rem; margin: 0 auto; padding: 1.6rem 0 3rem; }
.gate .card { padding: 1.5rem 1.4rem; }
.gate h1 { font-size: 2.1rem; margin: .2rem 0 .3rem; }
.gate .lede { color: var(--ink-2); font-style: italic; margin-bottom: 1.2rem; }

/* Fields wide enough to hit with a thumb, and at a size iOS will not zoom into:
   anything under 16px makes Safari scale the whole page on focus, which reads
   as the app breaking. */
input, select, textarea { font-size: 16px; min-height: 44px; }
/* 44, not 40. Apple's own number and Android's 48dp are both above what this said, and the four
   pixels are the difference between a control a thumb lands on and one it lands beside. */
button, .btn-sm, a.btn-sm { min-height: 44px; }
.gate button { width: 100%; }
.field-note { color: var(--muted); font-size: .82rem; font-style: italic; margin: .35rem 0 0; }

/* A refusal or a confirmation, said in place rather than in a toast, because a
   toast that has already faded is a message somebody never read. */
.note { border: 1px solid var(--border); border-left: 3px solid var(--border-strong);
  border-radius: var(--radius); padding: .8rem 1rem; margin: 1rem 0; font-size: .95rem;
  background: var(--surface-2); color: var(--ink-2); }
.note.bad { border-left-color: var(--bad); background: var(--bad-soft); color: var(--ink); }
.note.good { border-left-color: var(--ok); background: var(--ok-soft); color: var(--ink); }
.note.wait { border-left-color: var(--warn); background: var(--warn-soft); color: var(--ink); }

/* The account rows an admin decides about. A row per account on a wide screen,
   a stacked block on a narrow one: the buttons must never end up off the edge,
   which is what a table would have done. */
.account { border: 1px solid var(--border); border-radius: var(--radius);
  background: var(--surface); padding: .85rem 1rem; margin-bottom: .7rem;
  display: flex; align-items: center; gap: .8rem; flex-wrap: wrap; }
.account .who-email { font-weight: 600; word-break: break-all; }
.account .meta { color: var(--muted); font-size: .8rem; }
.account .grow { flex: 1 1 12rem; min-width: 0; }
.account .btn-row { flex: 0 0 auto; }
@media (max-width: 620px) {
  /*
   * An agent, or a person, as a row of a list rather than as a card.
   *
   * Stacked and stretched, each card came out 300 pixels tall with a black full-width MANAGE bar
   * and a red full-width OPEN bar in it, so two agents filled the screen and the buttons carried
   * more weight than the names they belonged to. A row is the name, what it is doing, and the
   * controls at their own size on the end of it.
   */
  /*
   * A row that wraps, rather than a column that stretches.
   *
   * A column with `align-items: stretch` makes every direct child the width of the screen, and the
   * pill and the buttons are direct children: RUNNING came out as a full-width bordered bar and
   * Open as a full-width red one, so a state and a link outweighed the name of the agent they
   * belonged to. Wrapping instead, with the name block claiming a whole line, puts the state and
   * the controls side by side underneath it at their own size, which is what a list row looks
   * like. No markup moved: the same children in the same order simply flow.
   */
  .account { flex-direction: row; flex-wrap: wrap; align-items: center; gap: .5rem;
    border: none; border-bottom: 1px solid var(--border); border-radius: 0;
    margin: 0 -1.05rem; padding: .8rem 1.05rem; }
  .account .grow { flex: 1 1 100%; min-width: 0; }
  .account .btn-row { flex: 0 0 auto; gap: .45rem; }
  .account .btn-row > * { flex: 0 0 auto; }
  .account .who-email { font-size: 1.02rem; word-break: normal; overflow-wrap: anywhere; }
  /* A pill is a label beside a name, so it is quiet and it says its words in the case they are
     written in: WAITING TO BE BUILT across a phone is a headline for a footnote. */
  .account .pill { text-transform: none; letter-spacing: .01em; font-size: .72rem; }
  /*
   * The greeting goes.
   *
   * "Signed in as admin" over "Welcome, Lena" over a rule over "Your agents" is 240 pixels of an
   * 844 pixel screen spent before the first agent, and the app bar says which screen this is. It
   * stays on a wide screen, where a page has room to say hello.
   */
  .greeting { display: none; }
}

/* Install. Hidden until the browser says an install is possible, so it is never
   a button that does nothing. */
#install { margin-left: .3rem; }

/* Offline. Shown by the service worker's own fallback and by a failed fetch. */
.offline { position: fixed; left: 0; right: 0; bottom: 0; z-index: 40;
  background: var(--ink); color: var(--surface); text-align: center;
  font-family: var(--label); text-transform: uppercase; letter-spacing: .12em;
  font-size: .66rem; font-weight: 700; padding: .5rem .8rem calc(.5rem + env(safe-area-inset-bottom)); }

/* A tap that does nothing visible for 200ms reads as a dead button on a phone,
   so every button that talks to the hub says it is working. */
button.working { opacity: .6; pointer-events: none; }

/* The two access states the hub has that the console's pills never named. */
.pill.approved { color: var(--ok); border-color: var(--ok); background: var(--ok-soft); }
.pill.refused { color: var(--red); border-color: var(--red); background: var(--red-soft); }

/* Field labels in a spec-sheet row read as an accent everywhere at the shared
   sheet's red, so they are quietened here without touching the shared rule. */
.kv .label { color: var(--muted); letter-spacing: .14em; }
.kv { border-bottom: 1px solid var(--border); padding: .45rem 0; gap: 1rem; }
.kv:last-child { border-bottom: none; }

/* The brand is a link home. Underlined on hover rather than always, because a page title that is
   permanently underlined reads as a mistake, and a link nobody can tell is one is not a way out. */
.brand:hover { text-decoration: underline; text-underline-offset: .18em; }

/* Wide screens. The column is sized for reading, not for the window: 1080px is right for prose on
   a laptop and looks like a phone page marooned in grey on a 3200px monitor. So the column grows,
   once, and stops well before a line of text gets too long to track. Both apps carry the same rule
   because they are one product and this is exactly where the two drifted apart before. */
@media (min-width: 1500px) {
  :root { --maxw: 1320px; }
}
