/* Fatmira — this app's own layer.
 *
 * Everything here is *arrangement*: page frames, the rail, grids, the screens'
 * own compositions. Every component it arranges (.panel .pill .btn .entry
 * .steps .step .gate .rows .empty .eyebrow .mono .dim .rule .mark) comes from
 * `fatmira.css`, which is vendored from the design pack by
 * `bin/sync_fatmira.py` and must not be edited here.
 *
 * The same rule as the pack: semantic tokens only. A ramp step used directly
 * (`--fm-silver-400`) will not follow a retune, so there are none below. If a
 * colour is needed that the semantic layer does not name, that is a missing
 * token in the pack, not a licence to reach past it.
 *
 * Light and dark both come free: every colour below is a token, and the pack
 * redefines the tokens under `prefers-color-scheme` *and* under
 * `:root[data-theme]` in both directions. Nothing here may hard-code a colour,
 * because a hard-coded one is exactly what survives the theme switch.
 */

/* ---- utilities ---------------------------------------------------------- */

.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* Off-screen until focused, then a real, visible control. A skip link that
   cannot be seen once you have tabbed to it is decoration. */
.skip {
  position: absolute;
  left: var(--fm-space-4);
  top: -4rem;
  z-index: 10;
  background: var(--fm-panel);
  border: var(--fm-border-wire) solid var(--fm-brass);
  color: var(--fm-brass);
  padding: var(--fm-space-2) var(--fm-space-4);
  font-size: var(--fm-size-sm);
  transition: top var(--fm-motion-enter) var(--fm-motion-ease-out);
}
.skip:focus { top: var(--fm-space-4); }

.wrap { white-space: normal; overflow-wrap: anywhere; }

/* The connection dot. It is never alone — every place it appears, a word
   appears with it, because a coloured dot on its own asks the reader to have
   memorised a legend. */
.dot {
  width: 0.5rem; height: 0.5rem;
  border-radius: var(--fm-radius-circle);
  display: inline-block;
  flex: none;
}
.dot.live { background: var(--fm-granted); }
.dot.displaced { background: var(--fm-refused); }
.dot.quiet { background: var(--fm-pending); }
.dot.revoked { background: var(--fm-answered-empty); }

/* ======================================================================== */
/* the landing page                                                          */
/* ======================================================================== */

.landing {
  --gutter: var(--fm-space-6);
}

.site {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--fm-space-5);
  flex-wrap: wrap;
  max-width: var(--fm-measure-wide);
  margin: 0 auto;
  padding: var(--fm-space-5) var(--gutter);
}
.site-mark,
.rail-mark {
  display: flex;
  align-items: center;
  gap: var(--fm-space-3);
  color: var(--fm-ink-strong);
  text-decoration: none;
  font-family: var(--fm-font-head);
  font-size: var(--fm-size-lg);
  letter-spacing: var(--fm-tracking-tight);
}
.site-mark .mark,
.rail-mark .mark { width: 1.75rem; flex: none; }

.site nav {
  display: flex;
  align-items: center;
  gap: var(--fm-space-5);
  font-size: var(--fm-size-sm);
}
.site nav a { color: var(--fm-ink-dim); text-decoration: none; }
.site nav a:hover { color: var(--fm-ink-strong); }
.site nav a.btn { color: var(--fm-brass); }

/* ---- hero ---------------------------------------------------------------
   The wire cameo is the page's one large gesture and it is given real room. It
   is the `full` cut because it is *seen* at 240px, and the pack assigns the
   wire to everything at 96px and up — the relief cuts exist for sizes where the
   strands would close up. */
.hero {
  display: grid;
  grid-template-columns: minmax(0, 22rem) minmax(0, 1fr);
  gap: var(--fm-space-9);
  align-items: center;
  max-width: var(--fm-measure-wide);
  margin: 0 auto;
  padding: var(--fm-space-9) var(--gutter) var(--fm-space-10);
}
.hero-mark .mark { width: 100%; max-width: 20rem; }
.hero-say { display: flex; flex-direction: column; gap: var(--fm-space-5); align-items: flex-start; }

.hero h1 {
  font-family: var(--fm-font-display);
  font-size: var(--fm-size-5xl);
  line-height: 1.04;
  letter-spacing: var(--fm-tracking-tight);
  margin: var(--fm-space-2) 0 0;
}
.lede {
  font-size: var(--fm-size-lg);
  line-height: var(--fm-leading-relaxed);
  color: var(--fm-ink-dim);
  max-width: var(--fm-measure-prose);
}
.hero-do { display: flex; gap: var(--fm-space-4); flex-wrap: wrap; }
.hero-do .btn { text-decoration: none; display: inline-block; }

/* ---- bands -------------------------------------------------------------- */

.band {
  max-width: var(--fm-measure-wide);
  margin: 0 auto;
  padding: var(--fm-space-9) var(--gutter);
  display: flex;
  flex-direction: column;
  gap: var(--fm-space-7);
}
.band-head { display: flex; flex-direction: column; gap: var(--fm-space-3); }
.band-head h2 { font-size: var(--fm-size-3xl); max-width: var(--fm-measure-prose); }

.landing .rule { max-width: var(--fm-measure-wide); margin: 0 auto; }

.specimen { padding: var(--fm-space-6); }

.verbs {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
  gap: var(--fm-space-6) var(--fm-space-7);
}
.verbs li { display: flex; flex-direction: column; gap: var(--fm-space-2); }
.verbs h3 {
  font-family: var(--fm-font-mono);
  font-size: var(--fm-size-sm);
  color: var(--fm-ink-strong);
  letter-spacing: var(--fm-tracking-normal);
}
.verbs p { color: var(--fm-ink-dim); font-size: var(--fm-size-sm); }
.verb-icon { width: 1.5rem; height: 1.5rem; color: var(--fm-brass); }

.gates { display: grid; grid-template-columns: repeat(auto-fit, minmax(18rem, 1fr)); gap: var(--fm-space-5); }
.gate-card {
  padding: var(--fm-space-6);
  display: flex;
  flex-direction: column;
  gap: var(--fm-space-3);
  align-items: flex-start;
}
.gate-icon { width: 1.75rem; height: 1.75rem; color: var(--fm-brass); }
/* Not `.gate .code` — this is a card, not the refusal component, and borrowing
   the component's selector would drag its oxide rule and ground in with it. */
.gate-card .gate-code { color: var(--fm-refused); }
.gates-note { max-width: var(--fm-measure-prose); }

.site-foot {
  border-top: var(--fm-border-hair) solid var(--fm-line);
  max-width: var(--fm-measure-wide);
  margin: var(--fm-space-9) auto 0;
  padding: var(--fm-space-7) var(--gutter) var(--fm-space-9);
  display: grid;
  grid-template-columns: auto 1fr auto;
  gap: var(--fm-space-7);
  align-items: start;
}
.site-foot .mark { width: 2.5rem; }
.foot-nav ul { list-style: none; margin: var(--fm-space-3) 0 0; padding: 0; display: flex; gap: var(--fm-space-5); flex-wrap: wrap; }
.foot-nav a { font-size: var(--fm-size-sm); text-decoration: none; }
.foot-note { font-size: var(--fm-size-xs); max-width: 16rem; text-align: right; }

/* ======================================================================== */
/* the console shell                                                         */
/* ======================================================================== */

.shell {
  /* One place, because the column width and the stripe that paints it have to
     agree exactly -- a half-rem of drift shows up as a seam. */
  --rail-w: 15.5rem;
  display: grid;
  grid-template-columns: var(--rail-w) minmax(0, 1fr);
  min-height: 100vh;
  /* The rail's ground and hairline are painted here, on the grid container,
     rather than on `.rail` itself. `.rail` is sticky, so its box is only as
     tall as its own contents -- on any screen longer than the viewport the
     sunken column would stop a third of the way down and the layout would read
     as unfinished. The container spans the whole document, so a stripe on it
     runs the full height whatever the rail happens to hold. */
  background: linear-gradient(
    to right,
    var(--fm-ground-sunken) 0 var(--rail-w),
    var(--fm-line) var(--rail-w) calc(var(--rail-w) + var(--fm-border-hair)),
    transparent calc(var(--rail-w) + var(--fm-border-hair))
  );
}

.rail {
  padding: var(--fm-space-5) var(--fm-space-5) var(--fm-space-6);
  display: flex;
  flex-direction: column;
  gap: var(--fm-space-7);
  position: sticky;
  top: 0;
  align-self: start;
  max-height: 100vh;
  overflow-y: auto;
}

.rail-nav { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--fm-space-1); }
.rail-nav a {
  display: block;
  padding: var(--fm-space-3) var(--fm-space-3) var(--fm-space-3) var(--fm-space-4);
  color: var(--fm-ink);
  text-decoration: none;
  font-family: var(--fm-font-head);
  font-size: var(--fm-size-md);
  /* The current screen is marked by a brass bezel on the leading edge. The
     inactive items reserve the same width in the neutral, so nothing shifts
     sideways as you move between screens. */
  border-left: var(--fm-border-bezel) solid transparent;
}
.rail-nav a:hover { background: var(--fm-panel); color: var(--fm-ink-strong); }
.rail-nav a[aria-current="page"] {
  border-left-color: var(--fm-brass);
  background: var(--fm-panel);
  color: var(--fm-ink-strong);
}
.rail-blurb {
  display: block;
  font-family: var(--fm-font-text);
  font-size: var(--fm-size-xs);
  color: var(--fm-ink-dim);
  line-height: var(--fm-leading-snug);
  margin-top: 0.15rem;
}

/* A labelled group in the rail. `.rail` is a flex column with a large gap, so
   without its own wrapper the "Live" label floats halfway between the two lists
   instead of sitting on the one it names. */
.rail-section { display: flex; flex-direction: column; gap: var(--fm-space-2); }

.rail-foot { margin-top: auto; display: flex; flex-direction: column; gap: var(--fm-space-2); }
.rail-client { display: flex; align-items: center; gap: var(--fm-space-2); color: var(--fm-ink-strong); }
.rail-version { font-size: var(--fm-size-3xs); }

.screen {
  padding: var(--fm-space-7) var(--fm-space-8) var(--fm-space-9);
  max-width: var(--fm-measure-wide);
  display: flex;
  flex-direction: column;
  gap: var(--fm-space-6);
  min-width: 0;
}

.masthead {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--fm-space-6);
  flex-wrap: wrap;
  padding-bottom: var(--fm-space-5);
  border-bottom: var(--fm-border-hair) solid var(--fm-line);
}
.masthead h1 { font-size: var(--fm-size-4xl); margin: var(--fm-space-2) 0 var(--fm-space-3); }
.masthead .lede { font-size: var(--fm-size-md); }

/* A short row of figures, aligned on their own baseline. `dl` because they are
   genuinely name/value pairs; the wrapping div per pair is what keeps a dt with
   its dd under flex. */
.meta { display: flex; gap: var(--fm-space-6); margin: 0; }
.meta div { display: flex; flex-direction: column; gap: var(--fm-space-1); }
.meta dt {
  font-family: var(--fm-font-mono);
  font-size: var(--fm-size-3xs);
  letter-spacing: var(--fm-tracking-eyebrow);
  text-transform: uppercase;
  color: var(--fm-ink-dim);
}
.meta dd { margin: 0; font-size: var(--fm-size-lg); color: var(--fm-ink-strong); }

/* ---- the ask screen ----------------------------------------------------- */

/* Real message text, unlike the sample transcript's one-liners: it arrives with
   the model's own newlines in it, and collapsing them turns a list of five
   flights into one paragraph. `pre-wrap` keeps the breaks and still wraps at the
   measure. `overflow-wrap` is for the URL that has no break in it at all. */
.chat-text { white-space: pre-wrap; overflow-wrap: anywhere; }

.transcript { max-width: var(--fm-measure-prose); padding-bottom: var(--fm-space-6); }
.transcript .gate { width: 100%; }
.gate-glyph { width: 1.5rem; height: 1.5rem; color: var(--fm-refused); }

/* Pinned to the bottom of the viewport, not to the end of the transcript: it is
   the single control on this screen and it should not walk off-screen as the
   conversation grows. */
.composer {
  position: sticky;
  bottom: 0;
  display: flex;
  gap: var(--fm-space-3);
  max-width: var(--fm-measure-prose);
  padding: var(--fm-space-4) 0;
  background: var(--fm-ground);
  border-top: var(--fm-border-hair) solid var(--fm-line);
}
/* Both text fields on these screens, together, so they cannot drift apart. A
   field the user types into is `--fm-panel` with a strong hairline; sunken
   ground on one of them and panel on the other made the sunken one read as
   disabled. */
.composer input,
.add-origin input {
  color: var(--fm-ink);
  background: var(--fm-panel);
  border: var(--fm-border-hair) solid var(--fm-line-strong);
  border-radius: var(--fm-radius-none);
}
.composer input::placeholder,
.add-origin input::placeholder { color: var(--fm-ink-dim); }

.composer input {
  flex: 1;
  min-width: 0;
  font-family: var(--fm-font-text);
  font-size: var(--fm-size-md);
  padding: var(--fm-space-3) var(--fm-space-4);
}

/* ---- browsers ----------------------------------------------------------- */

.clients { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--fm-space-4); }
.client {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: var(--fm-space-3) var(--fm-space-5);
  padding: var(--fm-space-5);
  align-items: start;
}
.client-id { display: flex; flex-direction: column; gap: var(--fm-space-1); }
.client-id h2 { font-size: var(--fm-size-md); display: flex; align-items: center; gap: var(--fm-space-2); }
.client-id .dot { margin-right: var(--fm-space-1); }
.client-id .dim { font-size: var(--fm-size-xs); }
.client-state { justify-self: end; }

.client-facts { grid-column: 1 / -1; display: flex; gap: var(--fm-space-6); margin: 0; flex-wrap: wrap; }
.client-facts div { display: flex; gap: var(--fm-space-2); align-items: baseline; }
.client-facts dt { font-size: var(--fm-size-xs); color: var(--fm-ink-dim); }
.client-facts dd { margin: 0; color: var(--fm-ink-strong); }

/* The note is the whole point of the screen for any row that has one, so it is
   set in the text face at full size — not as fine print under the figures. */
.client-note {
  grid-column: 1 / -1;
  border-left: var(--fm-border-bezel) solid var(--fm-line-strong);
  padding-left: var(--fm-space-4);
  font-size: var(--fm-size-sm);
  color: var(--fm-ink-dim);
  max-width: var(--fm-measure-prose);
}
.client.displaced .client-note { border-left-color: var(--fm-refused); }
.client.quiet .client-note { border-left-color: var(--fm-pending); }

.aside {
  padding: var(--fm-space-5) var(--fm-space-6);
  display: flex;
  flex-direction: column;
  gap: var(--fm-space-3);
  max-width: var(--fm-measure-prose);
}
.aside h2 { font-size: var(--fm-size-lg); }
.aside p { font-size: var(--fm-size-sm); }
.aside .pill { margin-right: var(--fm-space-1); }

/* ---- sessions ----------------------------------------------------------- */

/* `.rows` already scrolls inside its own box, so the page body never scrolls
   sideways however long a question is. These add only what a ledger needs on
   top of it: right-aligned figures, and one column allowed to wrap. */
.sessions td.num, .sessions th.num { text-align: right; }
.sessions td.said { white-space: normal; min-width: 18rem; color: var(--fm-ink-strong); }
.sessions tfoot td {
  border-top: var(--fm-border-wire) solid var(--fm-line-strong);
  border-bottom: 0;
  color: var(--fm-ink-dim);
}
.sessions .pill { font-size: var(--fm-size-3xs); }

/* ---- adapters ----------------------------------------------------------- */

.adapter { padding: var(--fm-space-5) var(--fm-space-6) var(--fm-space-6); display: flex; flex-direction: column; gap: var(--fm-space-5); }
.adapter-head { display: flex; align-items: baseline; gap: var(--fm-space-3); }
.adapter-head h2 { font-size: var(--fm-size-xl); }

.command {
  border-top: var(--fm-border-hair) solid var(--fm-line-soft);
  padding-top: var(--fm-space-4);
  display: flex;
  flex-direction: column;
  gap: var(--fm-space-3);
}
.command-id { display: flex; align-items: center; gap: var(--fm-space-3); flex-wrap: wrap; }
.command-id h3 { font-size: var(--fm-size-sm); color: var(--fm-ink-strong); letter-spacing: var(--fm-tracking-normal); }
.command > p { font-size: var(--fm-size-sm); color: var(--fm-ink-dim); }

.command-facts { display: grid; grid-template-columns: 8rem minmax(0, 1fr); gap: var(--fm-space-2) var(--fm-space-5); margin: 0; }
.command-facts div { display: contents; }
.command-facts dt { font-size: var(--fm-size-xs); color: var(--fm-ink-dim); }
.command-facts dd { margin: 0; color: var(--fm-ink); min-width: 0; }

/* ---- settings ----------------------------------------------------------- */

.block { padding: var(--fm-space-5) var(--fm-space-6) var(--fm-space-6); display: flex; flex-direction: column; gap: var(--fm-space-5); }
.block-head { display: flex; flex-direction: column; gap: var(--fm-space-2); }
.block-head h2 { font-size: var(--fm-size-xl); }
.block-head .dim { font-size: var(--fm-size-sm); }

.origins { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; }
.origins li {
  display: flex;
  align-items: center;
  gap: var(--fm-space-4);
  padding: var(--fm-space-3) 0;
  border-top: var(--fm-border-hair) solid var(--fm-line-soft);
  flex-wrap: wrap;
}
.origins li > .mono:first-child { min-width: 11rem; color: var(--fm-ink-strong); font-size: var(--fm-size-sm); }
.origin-when { margin-left: auto; }

.add-origin { display: flex; gap: var(--fm-space-3); flex-wrap: wrap; }
.add-origin input {
  font-family: var(--fm-font-mono);
  font-size: var(--fm-size-2xs);
  padding: var(--fm-space-2) var(--fm-space-3);
  min-width: 14rem;
}

.kv { display: grid; grid-template-columns: 12rem minmax(0, 1fr); gap: var(--fm-space-3) var(--fm-space-5); margin: 0; }
.kv div { display: contents; }
.kv dt { color: var(--fm-ink-dim); font-size: var(--fm-size-sm); }
.kv dd { margin: 0; color: var(--fm-ink-strong); }

.token { display: flex; align-items: center; gap: var(--fm-space-5); flex-wrap: wrap; }
.token > .mono { font-size: var(--fm-size-sm); color: var(--fm-ink-strong); }
.token-do { display: flex; gap: var(--fm-space-3); flex-wrap: wrap; }

.note { font-size: var(--fm-size-sm); max-width: var(--fm-measure-prose); }

/* ======================================================================== */
/* narrow                                                                    */
/* ======================================================================== */

@media (max-width: 60rem) {
  .hero { grid-template-columns: minmax(0, 1fr); gap: var(--fm-space-6); }
  .hero-mark { max-width: 12rem; }
  .hero h1 { font-size: var(--fm-size-4xl); }

  .site-foot { grid-template-columns: minmax(0, 1fr); }
  .foot-note { text-align: left; }

  /* The rail becomes a strip across the top. It stops being sticky at the same
     time -- a sticky horizontal bar on a short screen eats the content it is
     meant to navigate. */
  /* One column now, so the vertical stripe painted on `.shell` would run down
     the left of the whole page behind nothing. The rail takes its own ground
     back for this layout. */
  .shell { grid-template-columns: minmax(0, 1fr); background: none; }
  .rail {
    background: var(--fm-ground-sunken);
    position: static;
    max-height: none;
    border-bottom: var(--fm-border-hair) solid var(--fm-line);
    flex-direction: row;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--fm-space-4);
  }
  .rail-nav { flex-direction: row; flex-wrap: wrap; }
  .rail-nav a { border-left: 0; border-bottom: var(--fm-border-bezel) solid transparent; padding: var(--fm-space-2) var(--fm-space-3); }
  .rail-nav a[aria-current="page"] { border-left-color: transparent; border-bottom-color: var(--fm-brass); }
  .rail-blurb { display: none; }
  .rail-foot { margin-top: 0; margin-left: auto; }

  .screen { padding: var(--fm-space-5) var(--fm-space-5) var(--fm-space-8); }
  .masthead h1 { font-size: var(--fm-size-3xl); }
  .client { grid-template-columns: minmax(0, 1fr); }
  .client-state { justify-self: start; }
  .command-facts, .kv { grid-template-columns: minmax(0, 1fr); gap: var(--fm-space-1); }
  .command-facts div, .kv div { display: flex; flex-direction: column; gap: 0.1rem; margin-bottom: var(--fm-space-2); }
}
