/* Only what a page without a framework needs to stand up. Nothing visual lives here:
   colours, type, radii, spacing all come from console.css — the old console's own. */
html, body { margin: 0; height: 100%; }
/* The shell is as tall as what is VISIBLE. 100dvh does not shrink for the phone's
   keyboard (iOS never; Android only with interactive-widget=resizes-content), so
   the shell was taller than the screen with the keyboard up and the top was pushed
   off (Mark, 2026-09-03). session.js publishes the visual viewport's height and
   offset; without them the dynamic viewport stands. */
#app { height: 100vh; height: 100dvh; height: var(--fm-vvh, 100dvh); position: relative; top: var(--fm-vvtop, 0px); padding-bottom: env(safe-area-inset-bottom, 0px); box-sizing: border-box; }   /* the frame ends above a phone's home indicator, so its bottom border and corners show whole (Mark, 2026-09-03) */
html.fm-booting #app { visibility: hidden; }   /* blank until the first content is ready; session.js lifts it */
#comb { display: grid; }
/* The dock's remembered width from the first paint (the head script sets the variable); session.js writes the same value inline once it runs. */
@media (min-width: 700px) { #dock { width: var(--fm-dock-w, 280px); } }
.fm-domrows { flex: 1 1 auto; }
[hidden] { display: none !important; }
.fm-disc-fallback { width: 86%; aspect-ratio: 1; border-radius: 50%; display: grid; place-items: center; font-weight: 700; font-size: 38cqw; color: #fff; background: var(--disc-ink, var(--bg-input)); filter: drop-shadow(0 3px 7px #0000008c); z-index: 2; position: relative; }
.tree-icon-fallback { width: 36px; height: 36px; border-radius: 50%; display: grid; place-items: center; font-weight: 700; font-size: 15px; color: #fff; background: var(--disc-ink, var(--bg-input)); }
.fm-dtab-fallback { width: 22px; height: 22px; border-radius: 50%; display: inline-grid; place-items: center; font-weight: 700; font-size: 11px; color: #fff; background: var(--disc-ink, var(--bg-input)); }
/* The console's own rule, minus the Vue scope it was compiled with: while a screen
   is open over the shell, the corner user button is hidden. */
:root.fm-popup-open .fm-corner-user { display: none; }
/* ON THE PHONE THE AVATAR IS ALWAYS THERE. console.css draws the corner user
   only while the dock overlay is open — but this button is the one door to
   Chat Settings and the pages menu, so with the dock closed there was no
   avatar at all (Mark, 2026-09-03: "meu avatar não está lá pra eu usar o chat
   settings"). Loaded after console.css, so this wins; an open popup still
   hides it. */
@media (max-width: 639px) {
  .fm-corner-user { display: block; }
  :root.fm-popup-open .fm-corner-user { display: none; }
}
/* A one-line word at the bottom of the viewer for what has no footer (a trigger's
   menu answered with a refusal). Tokens only; gone on its own. */
.fm-toast { position: absolute; left: 50%; bottom: 3.5rem; transform: translateX(-50%); z-index: 40; max-width: 80%; padding: 6px 12px; border-radius: 10px; font-size: 11.5px; color: var(--text-strong); background: var(--popup-bg); border: 1px solid var(--popup-border); box-shadow: var(--popup-shadow); }

/* Sending and recording animate the BUTTON, not a ring around it (Mark, 2026-09-02:
   "ao invés de ser círculo, pode fazer uma animação com um botão. A mesma coisa para
   quando estiver gravando"). The console's expanding ring is switched off here. */
/* Sending: the console's own animation — the disc pulses and a ring travels out of
   it (Mark, 2026-09-02: "o envio da mensagem tem uma animação lá no original que não
   está aqui"). Its keyframes lost their brightness value to the console's minifier
   (`filter:brightness()`, invalid), so they are restated here with it.
   Recording pulses the same way; THINKING breathes instead, slower and without the
   ring, so pressing stop visibly changes what the button is doing. */
.fm-mic-disc.is-busy::after, .fm-mic-disc.is-live::after { display: none; }
.fm-send-disc { position: relative; }   /* the ring is an ::after and has to sit on the disc */
.fm-send-disc.is-busy, .fm-mic-disc.is-live, .fm-bar-btn.is-busy { animation: fm-send-pulse .9s ease-in-out infinite; }
@keyframes fm-send-pulse { 0%, 100% { transform: scale(1); filter: brightness(1); } 50% { transform: scale(1.1); filter: brightness(1.35); } }
@keyframes fm-send-ring { 0% { transform: scale(1); opacity: .85; } 100% { transform: scale(1.85); opacity: 0; } }
.fm-mic-disc.is-busy { animation: fm-mic-think 1.7s ease-in-out infinite; }
@keyframes fm-mic-think { 0%, 100% { opacity: .5; transform: scale(.93); } 50% { opacity: 1; transform: scale(1.03); } }
@media (prefers-reduced-motion: reduce) {
  .fm-send-disc.is-busy, .fm-mic-disc.is-live, .fm-mic-disc.is-busy, .fm-bar-btn.is-busy { animation: fm-send-dim 1.4s ease-in-out infinite; }
  .fm-send-disc.is-busy::after { animation: none; opacity: .5; }
  @keyframes fm-send-dim { 0%, 100% { filter: brightness(1); } 50% { filter: brightness(1.4); } }
}

/* An emoji icon is the icon: flat, no coloured disc behind it (the console's own). */
.fm-icon-glyph { background: none !important; filter: none !important; color: inherit; font-weight: 400; }
.fm-disc-fallback.fm-icon-glyph { font-size: 56cqw; }
.tree-icon-fallback.fm-icon-glyph { font-size: 24px; }
.fm-dtab-fallback.fm-icon-glyph { font-size: 19px; }

/* The dock as an overlay (phones): out of the flow, in from the right, and a
   sliver at the edge to pull it back. Mirrors the console's DockPanel 'auto'. */
.fm-dock-float { position: absolute; top: 0; bottom: 0; right: 0; z-index: 40; transform: translateX(101%); transition: transform .22s ease; box-shadow: 0 25px 50px -12px #0009; }
.fm-dock-float.is-open { transform: none; }
.fm-dock-edge { position: absolute; top: 0; bottom: 0; right: 0; width: 14px; z-index: 30; cursor: pointer; background: linear-gradient(to left, color-mix(in srgb, var(--bg-active) 40%, transparent), transparent); }
.fm-dock-scrim { position: absolute; inset: 0; z-index: 35; background: #0006; }

/* The page saying it is out of date: above the composer, tap to load the new one. */
.fm-update-pill { position: absolute; left: 50%; transform: translateX(-50%); bottom: calc(var(--fm-composer-h, 64px) + 10px); z-index: 60; white-space: nowrap;   /* one line, and always just above the composer, whose height the page publishes (Mark, 2026-09-03: "always appear above the input text box") */
  padding: 7px 14px; border-radius: 999px; border: 1px solid var(--border-default); background: var(--bg-bubble); color: var(--text-strong);
  font-size: 12px; box-shadow: 0 6px 20px #0007; cursor: pointer; }
.fm-update-pill:hover { background: var(--bg-active); }

/* A markdown file reads the way the console's viewer reads it — coloured headings,
   inline code on a surface, tables that keep their columns, an HTML comment on its
   own dim line. Those rules live in the console's md-live theme, which is compiled
   into its bundle and never reaches console.css (ABBA, 2026-09-02), so they are
   restated here. Amber only in the dark themes: on white it is the one pairing Mark
   has ruled out. */
.fm-md-body h1, .fm-md-body h2, .fm-md-body h3, .fm-md-body h4, .fm-md-body h5, .fm-md-body h6,
.jsonl-viewer h1, .jsonl-viewer h2, .jsonl-viewer h3, .jsonl-viewer h4 { font-weight: 600; padding-top: .5em; padding-bottom: .12em; }
.fm-md-body h1, .jsonl-viewer h1 { font-size: 1.35em; }
.fm-md-body h2, .jsonl-viewer h2 { font-size: 1.18em; }
.fm-md-body h3, .jsonl-viewer h3 { font-size: 1.06em; }
.fm-md-body h4, .jsonl-viewer h4 { font-size: 1em; }
.fm-md-body h1, .fm-md-body h2 { color: var(--warning, #FBBF24); }
.fm-md-body h3 { color: var(--warning-strong, #F59E0B); }
.fm-md-body h4, .fm-md-body h5, .fm-md-body h6 { color: var(--text-muted, #94979C); }
.theme-light .fm-md-body h1, .theme-bluey .fm-md-body h1,
.theme-light .fm-md-body h2, .theme-bluey .fm-md-body h2 { color: var(--text-strong); }
.theme-light .fm-md-body h3, .theme-bluey .fm-md-body h3 { color: var(--text-secondary); }
.fm-md-body code, .jsonl-viewer code { font-family: var(--font-mono, ui-monospace, monospace); font-size: .92em; background: color-mix(in srgb, var(--text-muted, #94979C) 14%, transparent); border-radius: 4px; padding: .1em .35em; }
.fm-md-body code { color: var(--success); }              /* the console's teal in a file */
.jsonl-viewer code { color: var(--code-inline); }        /* and the chat's own ink in a bubble */
.jsonl-viewer pre code, .fm-md-body pre code { background: none; padding: 0; color: inherit; }
.fm-md-body pre { background: color-mix(in srgb, var(--text-muted, #94979C) 9%, transparent); border-radius: 6px; }
.fm-md-body pre code { background: none; padding: 0; }
.fm-md-scroll { overflow-x: auto; max-width: 100%; }
.fm-md-body table { border-collapse: collapse; width: max-content; min-width: 100%; }
.fm-md-body th { text-align: left; font-weight: 600; color: var(--text-muted, #94979C); padding: .4em .7em; border-bottom: 1px solid var(--border-strong, #565E6B); white-space: nowrap; }
.fm-md-body td { padding: .4em .7em; border-bottom: 1px solid var(--border-default, #22272F); vertical-align: top; overflow-wrap: normal; }
.fm-md-body td:not(:first-child) { overflow-wrap: anywhere; max-width: 70ch; }
.fm-md-note { display: block; color: var(--text-dim); font-family: var(--font-mono, ui-monospace, monospace); font-size: .9em; opacity: .8; }

/* An agent that cannot sign itself in says so where you would type to it. */
.fm-signin-wall { margin: 0 12px 6px 4px; padding: 6px 10px; border-radius: 10px; font-size: 12px;
  color: var(--text-secondary); background: color-mix(in srgb, var(--warning, #FBBF24) 12%, var(--bg-input));
  border: 1px solid color-mix(in srgb, var(--warning, #FBBF24) 45%, transparent); }
.fm-signin-wall a { color: var(--link); }
.fm-signin-lock { opacity: .8; }

/* Chat Settings — the two grids the original draws with Tailwind utilities the
   compiled console.css does not carry (grid-cols-4, the lg two-column split). */
.fm-cs-themes { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 8px; }
.fm-cs-grid { display: grid; gap: 0 20px; grid-template-columns: minmax(0, 1fr); }
/* Side by side from 760px — a tablet's width — not only from a desktop's 1024 (Mark, 2026-09-03: "they should be split vertically for this width"). */
@media (min-width: 760px) { .fm-cs-grid { grid-template-columns: minmax(0, 1fr) minmax(0, 380px); } }
/* The theme swatches, in plain classes — the compiled console.css lacks the
   arbitrary utilities (h-[9px], w-[82%], border-2) the original drew them with. */
.fm-cs-sw { display: block; border-radius: 12px; overflow: hidden; border: 2px solid var(--border-default); padding: 0; background: none; cursor: pointer; text-align: left; transition: border-color .15s; }
.fm-cs-sw:hover { border-color: var(--border-strong); }
.fm-cs-sw.is-sel { border-color: var(--accent); }
.fm-cs-sw-top { display: block; background: var(--bg-primary); padding: 8px 8px 10px; }
.fm-cs-pill1 { display: block; height: 9px; width: 82%; border-radius: 999px; background: var(--bg-bubble); margin-bottom: 5px; }
.fm-cs-pill2 { display: block; height: 9px; width: 58%; border-radius: 999px; background: var(--accent); margin-left: auto; }
.fm-cs-sw-name { display: block; background: var(--bg-well); padding: 6px 8px; font-size: 11px; color: var(--text-secondary); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.fm-cs-sw.is-sel .fm-cs-sw-name { color: var(--text-strong); font-weight: 600; }
/* The dialog HOLDS ITS HEIGHT (the original's rule, Mark 2026-08-23 'don't
   change the overall size of the popup, just add scroll' — re-asked 2026-09-03
   when this port grew with the type): fixed height, each column scrolls
   itself, the preview box scrolls its content. */
.fm-cs-modal { width: min(860px, 96vw); height: min(84vh, 780px); }   /* the console's 860px; the compiled sheet lacks w-[860px] */
.fm-cs-right > h3 { display: none; }
@media (min-width: 760px) { .fm-cs-right > h3 { display: block; } }
.fm-cs-body { flex: 1; min-height: 0; }
.fm-cs-left { min-width: 0; overflow-x: hidden; }
.fm-cs-preview { overflow-y: auto; height: 46vh; }
@media (min-width: 760px) {
  .fm-cs-body { overflow: hidden; }
  .fm-cs-left { height: 100%; overflow-y: auto; padding-right: 4px; }
  .fm-cs-right { height: 100%; display: flex; flex-direction: column; min-height: 0; padding-top: 0; }
  .fm-cs-preview { height: auto; flex: 1; min-height: 0; }
}
@media (max-width: 759px) { .fm-cs-body { overflow-y: auto; } }
.fm-cs-rows { display: flex; flex-direction: column; gap: 8px; }
.fm-cs-row { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
/* ONE hand on the scroll. The thread fills older bubbles in above the reader and
   compensates scrollTop itself; Chrome's own scroll anchoring did the same thing
   on top of it, so every prepend moved the view twice — the drift behind the
   jumps and behind a reload landing ~500px below its anchor (2026-09-03). */
#thread { overflow-anchor: none; }
/* Six section tabs on a phone-wide drawer: one more step down so 'New agent'
   stays whole — the rule is every word visible at one shared size (Mark,
   2026-09-01; seen truncated on his phone 2026-09-03). */
@container (max-width: 400px) { .fm-domtab-l { font-size: calc(var(--fm-tile-lb) - 2px); letter-spacing: -0.03em; } }
/* With the panel open on a phone the avatar sits on the bar's left end, so the
   tiles start after it (the console's 46px reservation, phone edition). */
@media (max-width: 639px) { :root.fm-dock-overlay-open #bandbar .fm-bandtiles { padding-left: 44px; } }

/* The chevron at the end of a folding bubble's header (concept B, Mark 2026-09-03). */
.fm-msg-chev{margin-left:.45em;opacity:.75;flex:none;display:inline-flex}
.fm-msg-chev svg{width:1.1em;height:1.1em}
.fm-msg-head:hover .fm-msg-chev{opacity:1}


/* The reasoning and auto-compact pills: the console named their fills with
   arbitrary Tailwind classes that its compiled stylesheet never emitted, so the
   pill was an invisible box whose padding read as a gap between bubbles (Mark,
   2026-09-03: "take a look at the spacing between bubbles"). */
.fm-cb-reasoning { background: color-mix(in srgb, var(--link) 14%, var(--bg-bubble)); }
.fm-cb-compact { background: color-mix(in srgb, var(--warning-strong) 14%, var(--bg-bubble)); }

/* THE SEND PAIR (Mark, 2026-09-03, concept G2 inside today's balloon): the
   sender's face behind, the recipient's in front, the blue arrow badge between.
   A row that arrives pops the badge once. */
.fm-send-pair { position: relative; width: 56px; height: 34px; flex: none; display: block; }
.fm-send-pair .fm-send-from, .fm-send-pair .fm-send-to { position: absolute; top: 0; }
.fm-send-pair .fm-send-from { left: 0; z-index: 1; filter: brightness(.82); }
.fm-send-pair .fm-send-to { left: 28px; top: 8px; z-index: 2; }
.fm-send-pair .fm-send-to > * { box-shadow: 0 0 0 2px var(--bg-primary); border-radius: 8px; }
.fm-send-badge { position: absolute; left: 20px; top: 19px; z-index: 3; display: grid; place-items: center; width: 16px; height: 16px; border-radius: 50%; color: #fff; background: linear-gradient(135deg, color-mix(in srgb, var(--link) 70%, white), var(--link)); box-shadow: 0 0 0 2px var(--bg-primary), 0 2px 6px color-mix(in srgb, var(--link) 55%, transparent); }
.fm-send-badge svg { width: 10px; height: 10px; }
.fm-arrive .fm-send-badge { animation: fm-send-land .35s ease-out .1s 1 backwards; }
@keyframes fm-send-land { from { transform: scale(.2); opacity: 0; } 60% { transform: scale(1.25); opacity: 1; } to { transform: scale(1); opacity: 1; } }
@media (prefers-reduced-motion: reduce) { .fm-arrive .fm-send-badge { animation: none; } }
/* GChat pills: the console's green variant, whose fill class the compiled sheet lacks. */
.fm-cb-gchat { background: color-mix(in srgb, var(--success) 14%, var(--bg-bubble)); color: var(--success-soft, var(--success)); --fm-bub: color-mix(in srgb, var(--success) 14%, var(--bg-bubble)); }   /* the tail beside a person's chat message takes the pill's fill */

/* The avatar field's drop-downs hang from the field. Their sizes are the console's
   (300px five-column tile grid; 400px describe panel), as own classes: the
   compiled sheet lacks the arbitrary utilities, and without a width the grid
   collapsed to 67px on a phone — "nada na lista?" (Mark, 2026-09-03). */
.fm-setavatar { position: relative; }
.fm-ava-drop { position: absolute; left: 0; z-index: 40; overflow-y: auto; }
.fm-ava-drop[hidden] { display: none; }
.fm-ava-gridbox { width: 300px; max-width: calc(100vw - 28px); padding: 8px; display: grid; grid-template-columns: repeat(5, 1fr); gap: 6px; }
.fm-ava-gridbox img { width: 48px; height: 48px; object-fit: cover; }
.fm-ava-genbox { width: 400px; max-width: calc(100vw - 28px); padding: 12px; display: flex; flex-direction: column; gap: 8px; }

/* The read-aloud button's two faces: the speaker, or the check while this bubble is being read. */
.fm-speak .fm-speak-on { display: none; }
.fm-speak.is-speaking .fm-speak-on { display: block; color: var(--success); }
.fm-speak.is-speaking .fm-speak-off { display: none; }

/* A switch row: the label at one end, the switch at the other (the compiled sheet lacks justify-between). */
.fm-cs-switchrow { display: flex; align-items: center; justify-content: space-between; gap: 12px; }

/* THE SEARCH SCREEN: list left, preview right from a tablet's width (Mark,
   2026-09-03: "o botão de Search antigamente mostrava do lado esquerdo a lista e
   do direito o preview — agora não"). The console stacked them under 900px, and
   in this page's markup the stacked list collapsed to 4px, so only the preview
   showed. Side by side from 760px; under it, the list keeps 40% of the height. */
@media (min-width: 760px) and (max-width: 900px) { .fm-searchcols { flex-direction: row; } .fm-searchleft { flex: 0 0 42%; max-height: none; overflow: hidden; } .fm-searchprev { flex: 58%; min-height: 0; } }
@media (max-width: 759px) { .fm-searchleft { flex: 0 0 40%; max-height: 40%; } .fm-searchprev { flex: 1 1 auto; min-height: 0; } }

/* The dock's own scrolling stays in the dock: on a phone, reaching the end of the
   roster or the drawer must not hand the gesture to the conversation behind the
   scrim (Mark, 2026-09-03: "a bit unstable when bringing up the side view"). */
.fm-dock-float #agents-pane, .fm-dock-float #drawer, .fm-dock-float .fm-dockpane { overscroll-behavior: contain; }

/* The opening indicator's dots sit inline before the words. */
.fm-load-dots { display: inline-flex; gap: 4px; align-items: center; margin-right: 6px; }

/* THE PERSON'S BUTTON RIDES THE DOCK. The console fixed it to the viewport at the
   band's published corner, re-published 320ms after the dock slid — on a phone
   it hung in the air while the dock left (Mark, 2026-09-04: "why can't that just
   be in there like the other buttons"). It sits in the dock now, absolute at the
   band's corner within it, and moves with the dock like every other button. */
#dock .fm-corner-user { position: absolute; display: block; left: var(--fm-band-left, 10px); top: calc(var(--fm-band-top, 10px) + (var(--fm-band-h, 44px) - var(--fm-ava)) / 2); z-index: 41; }
:root.fm-popup-open #dock .fm-corner-user { display: none; }

/* THE SELECTED AGENT, RAISED (Mark, 2026-09-04, concept S4): the selected domain's
   tile grows a little and casts a shadow under a ring in its own colour; the
   selected team row becomes an elevated card. The console marked both flat. */
.fm-disc-sel { transform: scale(1.12); z-index: 2; }
.fm-disc-sel .fm-disc-c { box-shadow: 0 10px 22px -8px #000c, 0 0 0 2px var(--bg-primary), 0 0 0 4px var(--disc-ink); }
.theme-light .fm-disc-sel .fm-disc-c { box-shadow: 0 10px 22px -10px #0007, 0 0 0 2px var(--bg-primary), 0 0 0 4px var(--disc-ink); }
.fm-disc-sel .fm-disc-nm { font-weight: 700; color: var(--text-strong); }
.tree-row.sel { background: var(--bg-elevated); border-radius: 14px; margin: 3px 6px; padding: 7px 10px; box-shadow: 0 8px 20px -10px #000e, inset 0 1px 0 #ffffff12, inset 0 0 0 1px color-mix(in srgb, var(--disc-ink) 35%, transparent); transform: translateX(2px); }
.theme-light .tree-row.sel { box-shadow: 0 8px 20px -12px #0007, inset 0 0 0 1px color-mix(in srgb, var(--disc-ink) 35%, transparent); }
.tree-row.sel .tree-name { color: var(--text-strong); }

/* HOVER REHEARSES THE SELECTION, a step short of it (Mark, 2026-09-04, concept H1):
   on a pointer device the tile under the cursor lifts a little with a soft shadow
   and a faint ring in its colour, and the row becomes a light card — the
   "meio caminho" of the raised selection. Touch screens have no hover. */
@media (hover: hover) {
  .fm-disc:not(.fm-disc-sel):hover { transform: scale(1.05); filter: none; }
  .fm-disc:not(.fm-disc-sel):hover .fm-disc-c { box-shadow: 0 8px 18px -10px #000c, 0 0 0 2px color-mix(in srgb, var(--disc-ink) 45%, transparent); }
  .theme-light .fm-disc:not(.fm-disc-sel):hover .fm-disc-c { box-shadow: 0 8px 18px -12px #0007, 0 0 0 2px color-mix(in srgb, var(--disc-ink) 45%, transparent); }
  .tree-row:not(.sel):hover { background: color-mix(in srgb, var(--bg-elevated) 70%, transparent); border-radius: 14px; margin: 3px 6px; padding: 7px 10px; box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--border-default) 60%, transparent); }
}

/* THE VIEWER'S RENDERERS (phase 2): the strip's tools, the pages of a PDF with a
   text layer, the picture box, the grid, the code gutter, the JSON tree. */
.fm-vw-tools { display: inline-flex; align-items: center; gap: 4px; font-size: 12px; color: var(--text-muted); white-space: nowrap; flex: none; }   /* "1 / 3" broke into three lines on a phone */
.fm-vw-tools button, .fm-vw-tools a.fm-vw-raw { border: 1px solid var(--border-default); background: var(--bg-input); color: var(--text-secondary); border-radius: 6px; padding: 1px 7px; line-height: 18px; font-size: 12px; cursor: pointer; text-decoration: none; }
.fm-vw-tools button:hover, .fm-vw-tools a.fm-vw-raw:hover { color: var(--text-strong); background: var(--bg-hover); }
.fm-vw-tools button.is-on { color: var(--accent); border-color: var(--accent); }
.fm-vw-sep { width: 1px; height: 14px; background: var(--border-default); margin: 0 3px; }
.fm-vw-filter { width: 12em; height: 22px; font-size: 12px; padding: 0 8px; }
.fm-vw-scroll { background: var(--bg-primary); outline: none; }
.fm-vw-pages { display: flex; flex-direction: column; align-items: center; gap: 12px; padding: 12px; }
.fm-vw-page { position: relative; background: #fff; box-shadow: 0 2px 12px #0006; }
.fm-vw-page canvas { display: block; }
.fm-vw-page .textLayer { position: absolute; inset: 0; overflow: hidden; line-height: 1; opacity: .25; }
.fm-vw-page .textLayer span, .fm-vw-page .textLayer br { color: transparent; position: absolute; white-space: pre; cursor: text; transform-origin: 0 0; }
.fm-vw-page .textLayer ::selection { background: rgba(0, 120, 255, .45); }
.fm-vw-imgbox { display: grid; place-items: start; padding: 8px; cursor: grab; }
.fm-vw-imgbox.is-fit { place-items: center; cursor: zoom-in; }
.fm-vw-img { display: block; max-width: none; image-rendering: auto; }
.fm-vw-table { border-collapse: collapse; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 12px; white-space: nowrap; }
.fm-vw-table th, .fm-vw-table td { padding: 0 10px; height: 24px; line-height: 24px; border-bottom: 1px solid color-mix(in srgb, var(--border-default) 50%, transparent); text-align: left; max-width: 40ch; overflow: hidden; text-overflow: ellipsis; }
.fm-vw-table thead th { position: sticky; top: 0; background: var(--bg-well); color: var(--text-strong); cursor: pointer; user-select: none; z-index: 1; }
.fm-vw-table th.is-asc .fm-vw-sort::after { content: ' ▲'; } .fm-vw-table th.is-desc .fm-vw-sort::after { content: ' ▼'; }
.fm-vw-table tbody { will-change: transform; }
.fm-cd { border-collapse: collapse; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 12.5px; line-height: 1.5; }
.fm-cd-ln { color: var(--text-dim); text-align: right; padding: 0 10px 0 12px; user-select: none; vertical-align: top; width: 1%; }
.fm-cd-l { white-space: pre; padding-right: 16px; color: var(--text-strong); }
.is-wrap .fm-cd-l { white-space: pre-wrap; word-break: break-word; }
.fm-cd-c { color: var(--text-dim); font-style: italic; } .fm-cd-s { color: var(--success); } .fm-cd-n { color: var(--warning); } .fm-cd-k { color: var(--link); font-weight: 600; }
.fm-js-node > summary { list-style: none; cursor: pointer; } .fm-js-node > summary::-webkit-details-marker { display: none; }
.fm-js-node > summary::before { content: '▸ '; color: var(--text-dim); } .fm-js-node[open] > summary::before { content: '▾ '; }
.fm-js-kids { padding-left: 18px; border-left: 1px solid color-mix(in srgb, var(--border-default) 50%, transparent); margin-left: 4px; }
.fm-js-row { white-space: pre-wrap; word-break: break-word; }
.fm-js-k { color: var(--link); } .fm-js-p { color: var(--text-dim); } .fm-js-n { color: var(--text-dim); font-size: 11px; margin: 0 2px; } .fm-js-s { color: var(--success); } .fm-js-num { color: var(--warning); } .fm-js-b { color: var(--purple, #a78bfa); } .fm-js-null { color: var(--text-dim); font-style: italic; }

/* THE VIEWER ON A PHONE (phase 4): the tab fills the screen, the way back is the
   button at the strip's left; pages get a slim bar for it. Pinch and pan are
   the renderer's (touch-action lets the browser pan and hands us the pinch). */
.fm-vw-back { display: none; border: 1px solid var(--border-default); background: var(--bg-input); color: var(--text-strong); border-radius: 8px; width: 28px; height: 24px; line-height: 22px; font-size: 18px; text-align: center; flex: none; cursor: pointer; }
.fm-vw-pagebar { display: none; }
@media (max-width: 699px) { .fm-vw-back { display: inline-flex; align-items: center; justify-content: center; } .fm-vw-pagebar { display: flex; } }
.fm-vw-imgbox, [data-pdf-scroll] { touch-action: pan-x pan-y; }

/* WINDOWS INSIDE THE CONVERSATION (web/win.js): a floating layer over the thread,
   never the composer. A window is dragged by its bar, maximized, or closed; on a
   phone it fills the layer. */
.fm-winlayer { position: absolute; inset: 0; overflow: hidden; pointer-events: none; z-index: 25; }
.fm-win { position: absolute; width: min(680px, 86%); height: min(64%, 460px); min-width: 260px; display: flex; flex-direction: column; pointer-events: auto; background: var(--bg-primary); border: 1px solid var(--border-default); border-radius: 12px; box-shadow: 0 18px 52px rgba(0,0,0,.5); overflow: hidden; }
.fm-win.is-max { left: 6px !important; top: 6px !important; width: calc(100% - 12px); height: calc(100% - 12px); }
.fm-win-bar { display: flex; align-items: center; gap: 8px; padding: 5px 6px 5px 11px; background: var(--bg-well); border-bottom: 1px solid var(--border-default); cursor: move; user-select: none; touch-action: none; flex: none; }
.fm-win-ico { font-size: 13px; line-height: 1; }
.fm-win-title { font-size: 12px; font-weight: 500; color: var(--text-strong); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 55%; }
.fm-win-state { font-size: 11px; color: var(--text-dim); white-space: nowrap; }
.fm-win-btn { width: 24px; height: 24px; flex: none; border: 0; background: none; color: var(--text-dim); border-radius: 6px; font-size: 12px; line-height: 1; display: grid; place-items: center; cursor: pointer; }
.fm-win-btn:hover { background: var(--bg-active); color: var(--text-strong); }
.fm-win-body { position: relative; flex: 1; min-height: 0; display: flex; flex-direction: column; }
@media (hover: none) and (pointer: coarse) { .fm-win-bar { cursor: default; } }

/* THE PROMPT (web/term.js), inside a window: the screen fills the body; on a touch
   screen a row of keys the soft keyboard lacks sits under it. */
.fm-term { background: var(--bg-primary); padding: 4px 0 0 6px; overflow: hidden; }
.fm-term .xterm { height: 100%; }
.fm-term-keys { display: flex; gap: 6px; padding: 6px 8px calc(6px + env(safe-area-inset-bottom)); border-top: 1px solid var(--border-default); background: var(--bg-well); overflow-x: auto; flex: none; }
.fm-term-keys button { flex: none; min-width: 44px; height: 32px; padding: 0 10px; border-radius: 8px; border: 1px solid var(--border-default); background: var(--bg-input); color: var(--text-secondary); font: 13px var(--font-mono, ui-monospace, monospace); }
.fm-term-keys button.is-on { background: var(--bg-active); color: var(--text-strong); }
.fm-term-again { position: absolute; left: 50%; bottom: 14px; transform: translateX(-50%); padding: 6px 14px; border-radius: 8px; border: 1px solid var(--border-default); background: var(--bg-input); color: var(--text-strong); font-size: 12px; cursor: pointer; z-index: 5; }

/* THE + is its own disc, to the LEFT of the bubble (Mark, 2026-09-04: "o + fica
   fora, como na foto"), and the row centers it against the field's height. It
   holds attach and prompt. */
.fm-plus { width: 40px; height: 40px; flex: none; display: grid; place-items: center; border-radius: 999px; border: 1px solid var(--border-default); background: var(--bg-elevated); color: var(--text-secondary); box-shadow: 0 3px 10px rgba(0,0,0,.4); cursor: pointer; }
.fm-plus:hover { color: var(--text-strong); border-color: var(--accent); }
@media (max-width: 560px) { .fm-plus { width: 36px; height: 36px; } }

/* THE PROMPT DIALOG (dialogs/prompt.js): labelled fields and a segmented ssh/mosh
   toggle instead of raw radios (Mark, 2026-09-04). */
.fm-field { display: flex; flex-direction: column; gap: 6px; }
.fm-field-label { font-size: 12px; font-weight: 500; color: var(--text-dim); }
.fm-field-hint { font-weight: 400; opacity: .85; }
.fm-mono { font-family: var(--font-mono, ui-monospace, Menlo, monospace); }
.fm-seg { display: inline-flex; width: fit-content; gap: 2px; padding: 2px; border: 1px solid var(--border-default); border-radius: 9px; background: var(--bg-well); }
.fm-seg button { padding: 5px 20px; border: 0; border-radius: 7px; background: none; color: var(--text-secondary); font: 500 13px var(--font-mono, ui-monospace, monospace); cursor: pointer; }
.fm-seg button:hover { color: var(--text-strong); }
.fm-seg button.is-on { background: var(--accent); color: #fff; }

/* THE + MENU (session.js): an icon tile, a gap, then the label — "much much
   better" and "more space between image and text" (Mark, 2026-09-04). */
.fm-plusmenu { position: fixed; z-index: 90; min-width: 224px; padding: 7px; border-radius: 15px; background: var(--popup-bg); border: 1px solid var(--popup-border); box-shadow: 0 18px 48px rgba(0,0,0,.5); animation: fm-pm-in .12s ease-out; }
@keyframes fm-pm-in { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }
.fm-plusmenu button { display: flex; align-items: center; gap: 13px; width: 100%; padding: 8px 10px; border: 0; border-radius: 11px; background: none; color: var(--text-strong); text-align: left; cursor: pointer; }
.fm-plusmenu button:hover { background: var(--bg-hover); }
.fm-pm-ico { width: 34px; height: 34px; flex: none; display: grid; place-items: center; font-size: 18px; line-height: 1; }   /* transparent, icon ~10% bigger (Mark, 2026-09-04) */
.fm-pm-label { font-size: 14px; font-weight: 500; line-height: 1.15; }
.fm-pm-sub { display: block; font-size: 11px; font-weight: 400; color: var(--text-dim); margin-top: 2px; }

/* THE AGENT TERMINAL (dialogs/terminal.js), in a window: the agent's screen as a
   monospace snapshot that fills the body, refreshed each second. */
.fm-pane { flex: 1; min-height: 0; margin: 0; padding: 8px 10px; overflow: auto; background: var(--bg-primary); color: var(--text-secondary); font: 12px/1.4 var(--font-mono, ui-monospace, monospace); white-space: pre-wrap; }
