/* ==========================================================================
   Company design system
   - The first block mirrors docs/brand/tokens.css, the single source of truth.
     Change a value there first, then copy it here: this file is served to the
     browser and cannot import from docs/.
   - The second block keeps the names the app was already written against and
     maps them onto the brand tokens, plus the app's own greys and sizes
     (docs/onboarding-ui.md, «Simplificación (Fase 12)»).
   - Two appearances of the same tokens: light (white, greys by tone, black as
     the only accent) and, after :root, the dark set (Fase 15a), where the one
     accent is #f5f4f0 on #141416.
   ========================================================================== */

:root {
  /* Brand tokens — mirror of docs/brand/tokens.css ------------------------ */
  --font-heading: "Bricolage Grotesque", -apple-system, BlinkMacSystemFont, "Helvetica Neue", Arial, sans-serif;
  --font-body: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --font-mono: "SFMono-Regular", Menlo, Consolas, "Liberation Mono", monospace;

  --h1: 700 52px/1 var(--font-heading);
  --h2: 700 35px/1 var(--font-heading);
  --h3: 700 22px/1.15 var(--font-heading);
  --lead: 400 18px/1.5 var(--font-body);
  --body: 400 16px/1.5 var(--font-body);
  --small: 400 15px/1.45 var(--font-body);
  --caption: 400 13px/1.4 var(--font-body);
  --button: 600 15px/1 var(--font-body);
  --code: 400 13px/1.5 var(--font-mono);

  --bg: #ffffff;
  --bg-panel: #f5f5f5;
  --bg-soft: #fcfcfc;
  --ink: #000000;
  --text: #1d1d1f;
  --text-weak: #7a7a7a;
  --border: #dbdbdb;
  --border-strong: #b5b5b5;

  --primary: #111111;
  --primary-hover: #2a2a2a;
  --on-primary: #ffffff;
  --primary-soft: #f2f2f2;

  --glow: #fff7cc;
  --glow-strong: #ffe58a;
  --danger: #ff5555;
  --info-soft: #e5f2ff;

  --dark-bg: #141416;
  --dark-panel: #282a36;
  --dark-text: #f8f8f2;

  --radius: 6px;
  --radius-md: 8px;
  --radius-lg: 12px;
  --radius-pill: 999px;
  --shadow: 0 0.5em 1em -0.125em rgba(10, 10, 10, 0.1), 0 0 0 1px rgba(10, 10, 10, 0.02);
  --shadow-glow: 0 0 48px 12px rgba(255, 247, 204, 0.9);

  --s1: 8px;
  --s2: 16px;
  --s3: 24px;
  --s4: 32px;
  --s5: 40px;
  --s6: 48px;
  --s8: 64px;
  --s10: 80px;
  --s12: 96px;

  --max-w: 1200px;
  --nav-h: 60px;
  --hero-min-h: 700px;
  --panel-pad: 28px;
  --control-h: 40px;
  --control-h-lg: 48px;
  --icon: 20px;

  --ease: cubic-bezier(0.23, 1, 0.32, 1);
  --t-fast: 160ms;
  --t-base: 220ms;
  --glow-period: 6s;

  /* App names, mapped onto the brand ------------------------------------- */
  --surface: var(--bg);
  --surface-2: var(--bg-panel);
  /* One grey per tone (Linear Inbox, Fase 12): text, secondary, tertiary, lines. */
  --label: #141414;
  --label-2: #707070;
  --label-3: #adadad;
  --line: #ededed;
  --separator: var(--line);
  --fill: var(--bg-panel);
  --selected: #efefef;
  /* What floats over the page: menus, popovers and dialogs. The page itself on the light theme. */
  --raised: var(--surface);
  --tint: var(--ink);
  --mark: var(--glow-strong);
  --backdrop: rgba(10, 10, 10, 0.32);

  /* Bricolage for H1 and H2 only; everything else is the body font. */
  --title: var(--h3);
  --title-app: 700 24px/1.25 var(--font-heading);
  --subtitle-app: 700 20px/1.3 var(--font-heading);
  --reading: 400 15px/1.6 var(--font-body);
  /* The title of a row on lines of 20px (Fase 69): what the icon of its source, its hour and its faces are set on. */
  --row-lh: 20px;
  --row-title: 500 14px/var(--row-lh) var(--font-body);
  --row-line: 400 13px/18px var(--font-body);
  /* A row of the list of entries (Fase 67): its hour, and the icon of its source and the faces under the hour. */
  --row-time: 400 11px/16px var(--font-body);
  --row-icon: 18px;
  --meta: 400 13px/1.4 var(--font-body);
  --small-label: 500 12px/16px var(--font-body);
  --callout: var(--small);
  --footnote: var(--caption);

  --control: var(--control-h);
  --control-lg: var(--control-h-lg);
  --control-sm: 32px;
  --inset: var(--s3);
  --rail-w: 296px;
  --content-w: 720px;
  --ask-w: 600px;
  --row-h: 56px;

  /* Motion (Fase 144, emil-design-eng): what comes in or goes out eases out; what moves from one place on screen to another
     eases in and out; the sheet of a phone has the drawer's curve. Never an ease-in alone — what starts slow feels late —, and
     every transition and animation of this file names one of the three (or linear, steps() for what turns or types). Nothing
     lasts over 300ms but what explains — a demo of what to press or type, or that something is still going on —, which says
     so in its rule: «motion: explains». */
  --ease-out: var(--ease);
  --ease-in-out: cubic-bezier(0.77, 0, 0.175, 1);
  --ease-drawer: cubic-bezier(0.32, 0.72, 0, 1);
  --t-sheet: 300ms;

  /* The green dot of a connected source (docs/onboarding-ui.md): app-only, not in the brand tokens. */
  --connected: #34c759;
  /* What is the person's own in a terminal drawn on the dark tiles (Fase 141c, «Company, in your terminal.»): the name Company goes
     by and the token, in the gold of docs/terminal-guide/mock.html. App-only, as --connected; the tiles are dark in both themes, so
     it is one value for both, as --dark-text is. */
  --dark-key: #f0c56a;
  /* The tone of a person and the AI's (Fase 125, docs/sops.md §5): the chips of the roles of a SOP and the steps of its
     diagram, on the brand's soft blue and its glow — never a face's tint, which is .person-avatar's alone. The dark set
     gives the blue a value of its own; the glow has one already. */
  --tone-person: var(--info-soft);
  --tone-ai: var(--glow);

  /* The faces of people (Fase 52, personAvatar() in app.js): eight soft tints, a member's by their user id and a
     number's by a hash of its digits — the same person on the same tint on every screen, in both themes —, with the
     text colour on them. The dark set below, in the same order. */
  --avatar-1: #f2d4cf;
  --avatar-2: #f5e3c3;
  --avatar-3: #e6eec6;
  --avatar-4: #cfe8d8;
  --avatar-5: #cfe3ef;
  --avatar-6: #d8d6f2;
  --avatar-7: #efd3e6;
  --avatar-8: #e0e0e0;

  /* Safe areas */
  --safe-t: env(safe-area-inset-top, 0px);
  --safe-r: env(safe-area-inset-right, 0px);
  --safe-b: env(safe-area-inset-bottom, 0px);
  --safe-l: env(safe-area-inset-left, 0px);
}

/* Dark: the same tokens, second set (Fase 15a) ---------------------------
   «Oscuro» in «Ajustes» is data-theme="dark" on <html>, set by public/theme.js
   before the first paint. «Sistema» sets no data-theme and the system decides,
   but only on the pages that declare both appearances with
   <meta name="color-scheme" content="light dark"> — the app, the login and the
   onboarding. The landing and the legal pages load this file too and stay light.
   The two blocks are the same list: change one, change the other. */
:root[data-theme="dark"] {
  color-scheme: dark;
  --bg: #141416;
  --bg-panel: #1d1d20;
  --ink: #f5f4f0;
  --text: #f5f4f0;
  --text-weak: #9a9993;
  --border: #2c2c30;
  --primary: #f5f4f0;
  --primary-hover: #e0dfda;
  --on-primary: #141416;
  --primary-soft: #26262a;
  --glow: #2e2a1c;
  --glow-strong: #4a3d10;
  --info-soft: #1f2b38;
  /* The dark tiles (the logo, the avatars, the selection bar): one step above the page. */
  --dark-bg: #2c2c30;
  --shadow: 0 0.5em 1em -0.125em rgba(0, 0, 0, 0.5), 0 0 0 1px rgba(0, 0, 0, 0.2);
  --label: #f5f4f0;
  --label-2: #9a9993;
  /* 5:1 on the page, so the hours and the placeholders pass AA (Fase 16b; it was #6a6a70, 3.4:1). */
  --label-3: #86858b;
  --line: #2c2c30;
  --fill: #26262a;
  --selected: #26262a;
  /* A shadow does not show on a dark page: what floats is one step lighter than it instead. */
  --raised: #1d1d20;
  --backdrop: rgba(0, 0, 0, 0.55);
  --avatar-1: #5a3a36;
  --avatar-2: #5c4a2c;
  --avatar-3: #4a5330;
  --avatar-4: #2f4f3d;
  --avatar-5: #2f4658;
  --avatar-6: #3c3a5e;
  --avatar-7: #56364a;
  --avatar-8: #3a3a3e;
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]):has(meta[name="color-scheme"][content~="dark"]) {
    color-scheme: dark;
    --bg: #141416;
    --bg-panel: #1d1d20;
    --ink: #f5f4f0;
    --text: #f5f4f0;
    --text-weak: #9a9993;
    --border: #2c2c30;
    --primary: #f5f4f0;
    --primary-hover: #e0dfda;
    --on-primary: #141416;
    --primary-soft: #26262a;
    --glow: #2e2a1c;
    --glow-strong: #4a3d10;
    --info-soft: #1f2b38;
    --dark-bg: #2c2c30;
    --shadow: 0 0.5em 1em -0.125em rgba(0, 0, 0, 0.5), 0 0 0 1px rgba(0, 0, 0, 0.2);
    --label: #f5f4f0;
    --label-2: #9a9993;
    --label-3: #86858b;
    --line: #2c2c30;
    --fill: #26262a;
    --selected: #26262a;
    --raised: #1d1d20;
    --backdrop: rgba(0, 0, 0, 0.55);
    --avatar-1: #5a3a36;
    --avatar-2: #5c4a2c;
    --avatar-3: #4a5330;
    --avatar-4: #2f4f3d;
    --avatar-5: #2f4658;
    --avatar-6: #3c3a5e;
    --avatar-7: #56364a;
    --avatar-8: #3a3a3e;
  }
}
/* The one logo that is a PNG (Fireflies) brings its own white square, a white box on a dark row: a light
   disc of 24px instead. The file stays as it is. Not the iPhone app's icon, a PNG too, which keeps its
   corners (.app-icon). */
:root[data-theme="dark"] .source-logo img[src$=".png"]:not(.app-icon) { width: 24px; height: 24px; margin: -2px; border-radius: 50%; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]):has(meta[name="color-scheme"][content~="dark"]) .source-logo img[src$=".png"]:not(.app-icon) { width: 24px; height: 24px; margin: -2px; border-radius: 50%; }
}
/* The logo that stands for an entry (entryIcon() in app.js, Fase 67) on the dark theme: Fireflies' white square a
   light disc in its row, its head and wherever else, and ChatGPT's mark, black on its own, drawn light — and Cursor's,
   near black, too (Fase 95). */
:root[data-theme="dark"] .entry-logo[src$=".png"] { border-radius: 50%; }
:root[data-theme="dark"] .entry-logo[src$="/chatgpt.svg"] { filter: invert(1); }
:root[data-theme="dark"] .entry-logo[src$="/cursor.svg"] { filter: invert(1); }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]):has(meta[name="color-scheme"][content~="dark"]) .entry-logo[src$=".png"] { border-radius: 50%; }
  :root:not([data-theme="light"]):has(meta[name="color-scheme"][content~="dark"]) .entry-logo[src$="/chatgpt.svg"] { filter: invert(1); }
  :root:not([data-theme="light"]):has(meta[name="color-scheme"][content~="dark"]) .entry-logo[src$="/cursor.svg"] { filter: invert(1); }
}

/* Base ------------------------------------------------------------------ */
* { box-sizing: border-box; }
html { color-scheme: light; }
html, body { height: 100%; }
body {
  margin: 0;
  background: var(--bg);
  color: var(--label);
  font: var(--body);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}
a { color: var(--tint); text-decoration: none; }
/* Only with a pointer (Fase 144): a finger leaves the underline of a link it tapped behind it. */
@media (hover: hover) and (pointer: fine) {
  a:hover { text-decoration: underline; }
}
button { font: inherit; color: inherit; }
:focus-visible { outline: 2px solid var(--tint); outline-offset: 2px; }
[hidden] { display: none !important; }
/* The text colour and not the grey of the line it is in: grey on the highlight is under AA on either theme. */
mark { background: var(--mark); color: var(--label); border-radius: 3px; padding: 0 2px; }
.icon { flex: none; width: var(--icon); height: var(--icon); stroke: currentColor; stroke-width: 1.5; }
.err { color: var(--danger); }
/* What is said to whoever reads the page aloud and shown to nobody — how many rows the search of «Fuentes» finds (Fase 149) —:
   out of sight, and still in the page. */
.visually-hidden { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }

/* App shell -------------------------------------------------------------- */
.app {
  display: grid;
  grid-template-columns: var(--rail-w) minmax(0, 1fr);
  height: 100vh;
  height: 100dvh;
}
.rail {
  position: relative;
  display: flex;
  flex-direction: column;
  min-height: 0;
  background: var(--surface);
  border-right: 1px solid var(--line);
  padding-left: var(--safe-l);
}
.pane {
  min-height: 0;
  overflow-y: auto;
  background: var(--surface);
  padding-right: var(--safe-r);
}
/* The right edge of the rail, dragged to change --rail-w between 240 and 480px (railResizer() in app.js, as
   Linear and Missive): a strip of 6px inside the edge — the rail clips what goes past it —, unseen until the
   pointer is on it, when a line of 1px in the grey of the hours takes the place of the border; darker while
   it is dragged. A double click puts the width back. The body keeps the cursor and lets no text be selected
   while the drag lasts (.resizing-rail). Not on a phone, where the rail is the whole screen. */
.rail-resizer {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  z-index: 2;
  width: 6px;
  cursor: col-resize;
  touch-action: none;
}
.rail-resizer::after {
  content: "";
  position: absolute;
  top: 0;
  bottom: 0;
  right: 0;
  width: 1px;
  background: transparent;
  transition: background-color var(--t-fast) var(--ease-out);
}
@media (hover: hover) and (pointer: fine) {
  .rail-resizer:hover::after { background: var(--label-3); }
}
.rail-resizer.is-dragging::after { background: var(--label); }
body.resizing-rail { cursor: col-resize; user-select: none; -webkit-user-select: none; }

/* The scrollbars of the list and of the pane (Fase 52, as Linear's): a bar of 6px with no arrows and no
   track, its thumb rounded in the grey of the hours at 40%, seen only while the pointer is on the box or it
   is scrolling (`is-scrolling`, on from the first scroll event to 600ms after the last one, watchScrolling()
   in app.js), and fading in and out over 150ms — the colour is a registered property of the box, which its
   thumb reads, so that the transition reaches it. The same on either theme: the tokens. Chrome and Safari
   draw it through ::-webkit-scrollbar, which takes only its 6px and keeps the layout where it was; Firefox,
   which has no such selector, through scrollbar-width and scrollbar-color — Chrome ignores
   ::-webkit-scrollbar as soon as those are set, so each browser gets only its own. */
@property --scrollbar-thumb {
  syntax: "<color>";
  inherits: true;
  initial-value: transparent;
}
.timeline, .pane { --scrollbar-thumb: transparent; transition: --scrollbar-thumb 150ms var(--ease-out); }
.timeline:hover, .timeline.is-scrolling, .pane:hover, .pane.is-scrolling { --scrollbar-thumb: color-mix(in srgb, var(--label-3) 40%, transparent); }
@supports selector(::-webkit-scrollbar) {
  .timeline::-webkit-scrollbar, .pane::-webkit-scrollbar { width: 6px; height: 6px; background: transparent; }
  .timeline::-webkit-scrollbar-track, .pane::-webkit-scrollbar-track { background: transparent; }
  .timeline::-webkit-scrollbar-thumb, .pane::-webkit-scrollbar-thumb { border-radius: 3px; background-color: var(--scrollbar-thumb); }
  .timeline::-webkit-scrollbar-button, .pane::-webkit-scrollbar-button { display: none; width: 0; height: 0; }
  .timeline::-webkit-scrollbar-corner, .pane::-webkit-scrollbar-corner { background: transparent; }
}
@supports not selector(::-webkit-scrollbar) {
  .timeline, .pane { scrollbar-width: thin; scrollbar-color: var(--scrollbar-thumb) transparent; }
}

/* The wordmark as the landing and the legal pages size it; the rail makes it smaller. */
.wordmark {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font: var(--title);
  color: var(--label);
  letter-spacing: -0.045em;
  text-decoration: none;
}
.wordmark:hover { text-decoration: none; }
.wordmark .mark { width: var(--s4); height: var(--s4); padding: 3px; border-radius: var(--radius-md); background: var(--dark-bg); }

/* Rail, top to bottom (Fase 17): where — the space, or the wordmark without spaces —, what — «Nueva
   entrada», the sections, and the list with the search as its heading (Fase 44) — and who — the account
   at the foot. The icons of the rows, the space's flower and the account's avatar share one column, 16px in. */
.rail-head {
  display: flex;
  align-items: center;
  /* As tall with the space as with the wordmark, or with neither before /api/me answers: nothing
     under it moves when one of them comes in. */
  min-height: calc(60px + var(--safe-t));
  padding: calc(12px + var(--safe-t)) var(--s1) var(--s1);
}
.rail-head .wordmark { padding: 0 var(--s1); font: 700 20px/1 var(--font-heading); }
.rail-head .wordmark .mark { width: 24px; height: 24px; padding: 2px; border-radius: var(--radius); }
/* The space: the flower as its avatar, its name and a grey chevron, a row as wide as the rail like the
   account at the foot. Its menu (a .popover) switches it. */
.space-switcher {
  display: flex;
  align-items: center;
  gap: var(--s1);
  width: 100%;
  height: var(--control);
  padding: 0 var(--s1);
  border: 0;
  border-radius: var(--radius);
  background: transparent;
  color: var(--label);
  font: 500 14px/20px var(--font-body);
  text-align: left;
  cursor: pointer;
}
.space-switcher .mark { flex: none; width: 24px; height: 24px; padding: 2px; border-radius: var(--radius); background: var(--dark-bg); }
.space-switcher-name { flex: 1; min-width: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
.space-switcher .icon { width: 16px; height: 16px; color: var(--label-2); }
.space-switcher[aria-expanded="true"] { background: var(--fill); }

/* «Nueva entrada»: the one black button of the rail, as wide as it, with its key on the right like the
   search over the list. Two classes, so that .btn and .btn-primary, further down, do not size it again. */
.rail .btn-new {
  flex: none;
  justify-content: flex-start;
  height: 36px;
  margin: 0 var(--s2) var(--s1);
  padding: 0 12px;
  font: 500 14px/1 var(--font-body);
}
.btn-new .icon { width: 16px; height: 16px; }
.btn-new kbd {
  margin-left: auto;
  padding: 2px 6px;
  font: 500 11px/1.4 var(--font-body);
  color: color-mix(in srgb, var(--on-primary) 64%, transparent);
  border: 1px solid color-mix(in srgb, var(--on-primary) 24%, transparent);
  border-radius: 4px;
}
@media (hover: none) { .btn-new kbd { display: none; } }

/* The search, the heading of the list (Fase 44), where the label «Entradas» was: 8px under the hairline that parts it
   from the sections (Fase 60) and 8px over the list, which runs under it as it scrolls — the filter on its list, as in
   Linear. */
.search { padding: var(--s1) var(--s2); }
.search-box { position: relative; }
.search input {
  width: 100%;
  height: 36px;
  padding: 0 52px 0 12px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  color: var(--label);
  font: 400 14px/1 var(--font-body);
  -webkit-appearance: none;
  appearance: none;
}
.search input::placeholder { color: var(--label-3); }
.search input:focus { outline: 2px solid var(--tint); outline-offset: 0; }
.search kbd {
  position: absolute;
  right: var(--s1);
  top: 50%;
  transform: translateY(-50%);
  padding: 2px 6px;
  font: 500 11px/1.4 var(--font-body);
  color: var(--label-3);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 4px;
  pointer-events: none;
}
.search input:focus + kbd { display: none; }
@media (hover: none) { .search kbd { display: none; } }

/* The chips over the list (Fase 45), under the search: one line of 28px, a chip per type of entry the space has
   and «All», each only the 16px icon its rows wear, in a pill of its own (Fase 50) — a line of --separator
   around it, 6px from the next, the row centred under the search — so that they read as buttons and not as the
   icons of the rows under them, as Apple Mail's categories and Linear's filters. Grey like the icons of the rows;
   the one on filled like the section on screen (--fill, --label), its line darker (--label-3). More chips than
   the rail is wide for scroll sideways, and from the first: the row is at least as wide as its chips (min-width)
   inside the box that scrolls, and centres them only when the box is wider than they are. The box goes with the
   row app.js hides (:has). The 8px under the row are the ones the search leaves over the list without it; its 4px
   on top, taken from the 8px under the search, are the room the focus ring needs inside the box that scrolls. */
.type-filter-scroll {
  flex: none;
  margin-top: -4px;
  overflow-x: auto;
  scrollbar-width: none;
}
.type-filter-scroll::-webkit-scrollbar { display: none; }
.type-filter-scroll:has(> [hidden]) { display: none; }
.type-filter {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  min-width: max-content;
  padding: 4px var(--s2) var(--s1);
}
.type-chip {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: 28px;
  padding: 0 10px;
  border: 1px solid var(--separator);
  border-radius: var(--radius-pill);
  background: transparent;
  color: var(--label-2);
  cursor: pointer;
}
.type-chip .icon { width: 16px; height: 16px; }
.type-chip[aria-checked="true"] { background: var(--fill); border-color: var(--label-3); color: var(--label); }
/* The ring the page gives what has the focus, said here for the 4px the row keeps for it. */
.type-chip:focus-visible { outline: 2px solid var(--tint); outline-offset: 2px; }
@media (hover: hover) and (pointer: fine) {
  .type-chip:hover { background: var(--fill); color: var(--label); }
}

/* The sections: a row each, its icon and its name, and the one on screen marked (aria-current). Under them a hairline
   across the rail, in the grey of the rail's other lines (the one over the account), with 8px of the grid over it —
   the padding of the sections — and 8px under it, the padding of the search (Fase 60). */
.rail-nav { display: grid; padding: 4px var(--s1) var(--s1); border-bottom: 1px solid var(--line); }
.nav-row {
  display: flex;
  align-items: center;
  gap: var(--s1);
  height: var(--control-sm);
  padding: 0 var(--s1);
  border-radius: var(--radius);
  color: var(--label);
  font: 500 14px/20px var(--font-body);
  text-decoration: none;
}
.nav-row:hover { text-decoration: none; }
.nav-row .icon { width: 16px; height: 16px; color: var(--label-2); }
.nav-row[aria-current="page"] { background: var(--fill); }
.nav-row[aria-current="page"] .icon { color: var(--label); }
/* «Conectar →», on the right of «Fuentes» until the first source is connected: the accent. */
.nav-hint { margin-left: auto; font: 500 13px/20px var(--font-body); color: var(--tint); white-space: nowrap; }
/* The access requests waiting for an answer, on the right of «Equipo»: the accent too, as a pill. And the number of my
   open tasks on the right of «Tasks» (Fase 86, .nav-count), in the same box — so that its digits line up under those of
   What's new — in the lightest grey, with no pill: the black one is What's new's. */
.nav-badge, .nav-count {
  margin-left: auto;
  min-width: 20px;
  height: 20px;
  padding: 0 6px;
  font: 600 11px/20px var(--font-body);
  font-variant-numeric: tabular-nums;
  text-align: center;
}
.nav-badge { border-radius: var(--radius-pill); background: var(--primary); color: var(--on-primary); }
.nav-count { color: var(--label-3); }
/* A number beside a name or a switch (Fase 94, countChip() in app.js, docs/onboarding-ui.md): the box of the number of
   What's new, in grey — the quiet fill and the middle grey —, and never a «·» before it. */
.count-chip {
  flex: none;
  display: inline-block;
  min-width: 20px;
  height: 20px;
  padding: 0 6px;
  border-radius: var(--radius-pill);
  background: var(--fill);
  color: var(--label-2);
  font: 600 11px/20px var(--font-body);
  font-variant-numeric: tabular-nums;
  text-align: center;
}
/* A count said in words with its number in that chip (countWords() in app.js): «Following [2] ad accounts». */
.count-words .count-chip { vertical-align: middle; }
/* Things of different kinds on one line (Fase 94, apart() in app.js): each its own element, 8px apart, and no «·» between
   them. */
.apart + .apart { margin-left: var(--s1); }
/* A number that changes (Fase 70, rollNumber() in app.js), as a scoreboard: for as long as it rolls, each digit in a box
   of its own as tall as its line, which clips the old one going up and out and the new one coming in from below. */
.digit { position: relative; display: inline-block; overflow: hidden; vertical-align: top; }
.digit > span { display: block; }
.digit > .digit-out { position: absolute; inset: 0; }
@media (hover: hover) and (pointer: fine) {
  .space-switcher:hover, .nav-row:hover { background: var(--fill); }
}

/* Timeline: a day heading, then rows of the icon of their source and a line or two --
   Its rows are denser than those of «Fuentes», «Ajustes» and «Equipo», which keep the --row-h of :root: a line of 20px,
   6px above and under it and 10px at either side, 32px — 52px, two lines, for a title that does not fit the first beside
   the faces and the hour (Fase 106; until then two lines whatever the title, a title of one line keeping the second for
   the faces: Fase 67, Fase 69). What keeps the first row in view when rows come in above it is app.js's
   (keepingScroll()), and not the browser's: at the top, what comes in pushes the rest down (Fase 70). */
.timeline { flex: 1; min-height: 0; overflow-y: auto; overflow-anchor: none; --row-h: 32px; --row-pad: 6px 10px; }
.timeline-inner { padding: 0 var(--s1) var(--s4); }
/* «3 new entries» (newEntriesLine() in app.js): rows that came in while the list was scrolled down, said in a
   small pill that stays at the top of the list — in a box of no height, so that nothing under it moves — and
   scrolls back up when tapped. The accent, like a toast, so that it reads over the rows. */
.new-entries-holder { position: sticky; top: 0; z-index: 2; display: flex; justify-content: center; height: 0; }
.new-entries {
  margin-top: var(--s1);
  height: 26px;
  padding: 0 12px;
  border: 0;
  border-radius: var(--radius-pill);
  background: var(--primary);
  color: var(--on-primary);
  font: 500 12px/26px var(--font-body);
  box-shadow: var(--shadow);
  cursor: pointer;
}
/* A day heading opens the rows under it: 12px of air above it and 4px under it (Fase 95; 16px until then, which with the
   room a title of one line keeps under it in the last row of the day left a day twice as far from the next as two rows
   are), tight to its first row and apart from the group before, as in Linear's inbox, Things and Superhuman (Fase 44).
   The first one has no group before it and no air of its own: the 8px under the search, the heading of the list, are all
   there is between the two. */
.day { padding: 12px var(--s1) 4px; font: var(--small-label); color: var(--label-2); background: var(--surface); }
.timeline-inner > .day:first-child { padding-top: 0; }
.group { display: grid; }
/* The icon of where the entry came from, 18px (entryIcon() in app.js: a logo in its colours, or a grey icon), then a
   line of 20px — two when the title takes them — (Fase 67; Fase 69; Fase 106), each thing set on a line of the title's
   and not on the whole row: the icon — and the checkbox in its place — on the axis of its first line, the hour on its
   baseline, and the faces beside the hour on that axis, or on the axis of the second line when the title takes two. Every
   row keeps no more room than it uses, the last of a day as the others (Fase 95 kept 44px for that one alone). */
.row {
  /* The ring that cuts each face out of the one before (.avatar-stack): the background the row is on at the time. */
  --ring: var(--surface);
  position: relative;
  display: grid;
  grid-template-columns: var(--row-icon) minmax(0, 1fr);
  column-gap: 10px;
  align-items: start;
  min-height: var(--row-h);
  padding: var(--row-pad);
  border-radius: var(--radius);
  /* The rail's own, as a day heading's: a row sliding to its new place covers the rows that came in under it until it is
     clear of them (Fase 70, playLive() in app.js), and its flash fades to it. */
  background: var(--surface);
  cursor: pointer;
}
.row[aria-selected="true"] { --ring: var(--selected); background: var(--selected); }
.row-icon { display: grid; place-items: center; height: var(--row-lh); color: var(--label-2); }
.row-icon .icon { width: var(--row-icon); height: var(--row-icon); }
/* The checkbox of a row, in the place of its icon while rows are selected (Fase 68) — and only then: never under the
   pointer (Fase 95) —: the input takes the clicks and the keyboard over the box that shows (.check-box, checkBox() in
   app.js), which it checks. */
.row-check { display: none; position: relative; align-items: center; justify-content: center; height: var(--row-lh); }
.row-check input { position: absolute; inset: 0; width: 100%; height: 100%; margin: 0; opacity: 0; cursor: pointer; }
.row-check input:focus-visible + .check-box { outline: 2px solid var(--tint); outline-offset: 2px; }
.app.selecting .row-icon { display: none; }
.app.selecting .row-check { display: flex; }
/* The title of a row, and the name of a page a search found: what gives way, never the hour. */
.row-title, .row-line { min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.row-title { flex: 1 1 auto; font: var(--row-title); color: var(--label); }
/* The line or two of a row (rowBody() in app.js), as in Linear's inbox and in Mail. A title that fits the line beside who
   the row is about and the hour is that line — the title, then on the right the faces, 6px and the hour — and the row is
   the line and its padding, 32px (Fase 106; Manu, 2026-10-05: «mucho aire debajo del título»); one that does not goes on
   to a second line, cut at the end of it, with the hour on the right of the first and the faces under it, 52px. Nothing in
   app.js measures it: the title (1 1 auto) and what is on its right (.row-side, 0 1 auto) start as wide as their words on
   one line and, when both do not fit, give way together, by the same overflow — the title onto its second line, and
   .row-side, narrower than its one line, onto two: its items run from the right (row-reverse), the hour first, so that
   the hour stays on the first and the faces go under it. Never one without the other; what is on the right is never cut. */
.row-body { display: flex; align-items: flex-start; gap: var(--s1); min-width: 0; }
.row-body .row-title { display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; line-clamp: 2; white-space: normal; overflow-wrap: anywhere; }
.row-side { flex: 0 1 auto; display: flex; flex-flow: row-reverse wrap; align-items: center; column-gap: 6px; }
/* The faces, 18px, on a line as tall as the title's: 1px over and under them. */
.row-side > :not(.row-when) { margin-block: 1px; }
/* The hour's line, from its top: a line of the title's own type, so that the hour — and «Ask» — sit on the baseline of
   the title's first line, as words of different sizes sit on one line. */
.row-when { font: var(--row-title); white-space: nowrap; }
.row-when > .row-ask { margin-right: 6px; }
/* Who a row is about, as faces of 18px and never names (Fase 60, faceStack() in app.js), by the hour: on the axis of the
   line they are on, and nothing clips their ring. For an entry that is not everyone's, who reads it, with the lock glued
   to them (Fase 68, lockedFaces()): one group, the lock 3px from the faces, as tall as they are and on their axis. */
.row-who { display: flex; align-self: center; align-items: center; gap: 3px; height: var(--row-icon); }
.row-lock { flex: none; display: grid; place-items: center; height: var(--row-icon); color: var(--label-3); }
.row-lock .icon { width: 11px; height: 11px; }
/* Who sees an entry this person says, from its row (Fase 95, rowWho() in app.js): its faces and its lock, as they are, in a
   button that takes 3px either side of them back with its margin, so that nothing moves; under the pointer of the row,
   on the fill of a selection, 6px round, with the cursor of a link. Its click opens «Visible to» under it. */
.row-visibility { display: flex; align-self: center; height: var(--row-icon); margin: 0 -3px; padding: 0 3px; border: 0; border-radius: 6px; background: transparent; color: inherit; font: inherit; cursor: pointer; }
.row-visibility[aria-expanded="true"] { --ring: var(--selected); background: var(--selected); }
/* A page a search found (foundPages() in app.js), drawn as a row is: its name and its day on the first line
   (rowHead()), and what it is on the one under it, the whole width. */
.row-main { min-width: 0; display: grid; }
.row-head { display: flex; align-items: baseline; gap: 6px; min-width: 0; }
.row-line { font: var(--row-line); color: var(--label-2); }
/* The hour, in the lightest grey of the theme: a line of 16px, set on the title's baseline inside the 20px of the line
   it is on (.row-when), which it never makes taller. */
.row-time { flex: none; font: var(--row-time); font-variant-numeric: tabular-nums; color: var(--label-3); white-space: nowrap; }
/* Somebody else's entry this person may not read (Fase 68, renderLockedRow() in app.js): no checkbox, so its icon stays
   while selecting; dimmed to 0.45 — its icon, its title, its hour and its author's face after the lock — but for «Ask»,
   which a tap brings up on the right by the hour: the primary button of the theme, as tall as the line, and «Asked»,
   switched off (.btn:disabled), once it has gone. */
.app.selecting .row.locked .row-icon { display: grid; }
.row.locked > .row-icon, .row.locked .row-title, .row.locked .row-time, .row.locked .row-who { opacity: 0.45; }
/* A call nobody talked in (Fase 148e, unanswered() in app.js): a voicemail, a call nobody answered, one that failed. The same
   row, the logo of its source and all, dimmed as a closed one is — its icon, its title, its hour and its faces —, to 0.6: it
   is there to be read, and nothing new is in it. How it went is in the head of its entry (.outcome-chip). */
.row.unanswered > .row-icon, .row.unanswered .row-title, .row.unanswered .row-time, .row.unanswered .row-who { opacity: 0.6; }
/* What an entry of a phone line is (Fase 154, rowGlyph() in app.js; option C of the canvas «Quo rail icons»): a glyph of 14px,
   Lucide's stroke as every icon of the page, that opens the title of its row, on the line of its words and 6px before them —
   a bubble for a day of texts, a handset for a call somebody talked in, the handset with its mark for one nobody did —, in the
   grey of the secondary text of either theme. Never a colour of its own (Manu: «no en rojo»): what a call nobody talked in is,
   its mark says, and its row is dimmed with its title, the glyph in it. The logo of the source stays where every row has it. */
.row-glyph { display: inline-block; width: 14px; height: 14px; margin-right: 6px; vertical-align: -2px; color: var(--label-2); }
.row-glyph .icon { display: block; width: 14px; height: 14px; }
.btn.row-ask { height: 18px; padding: 0 8px; border-radius: var(--radius-pill); font: 500 11px/1 var(--font-body); }
/* Under the pointer a row only changes its background (Fase 95): its icon, its hour and its faces stay where they are,
   and its faces — or its lock — are the control of who sees it, on the fill of a selection. Its copy and its delete are
   in its right click and in the head of the entry; a selection starts with ⌘-click or ⇧-click. */
@media (hover: hover) and (pointer: fine) {
  .row:hover { --ring: var(--fill); background: var(--fill); }
  .row:hover .row-visibility { --ring: var(--selected); background: var(--selected); }
}
/* A finger resting on a row selects it (pressRow() in app.js): no callout of the system, and no word selected on the way. */
@media (hover: none) {
  .row { -webkit-touch-callout: none; -webkit-user-select: none; user-select: none; }
}
/* What is still to come (Fase 152, upcomingRows() in app.js), over «Today»: one strip as wide as the rows and as tall as one,
   on the quiet fill, 6px round — the row of «Previous» of What's new (.news-previous), at the height of a row of the rail —,
   its word in 500 13px/20px of the colour of the text with how many in a grey chip on the page's colour, and the chevron on
   the right, turned up while what it unfolds is open under it: its days, headed as the rail's are, and a hairline under
   them, over «Today». */
.upcoming { display: flex; align-items: center; justify-content: space-between; gap: var(--s1); width: 100%; height: var(--row-h); padding: 0 10px; border: 0; border-radius: var(--radius); background: var(--fill); font: 500 13px/20px var(--font-body); color: var(--label); cursor: pointer; }
.upcoming-label { display: flex; align-items: center; gap: var(--s1); min-width: 0; }
.upcoming .count-chip { background: var(--surface); }
.upcoming .icon { width: 16px; height: 16px; color: var(--label-2); transition: transform var(--t-fast) var(--ease-out); }
.upcoming[aria-expanded="true"] .icon { transform: rotate(180deg); }
.upcoming-list { padding-bottom: var(--s1); border-bottom: 1px solid var(--separator); }
/* What came in together (Fase 152, burstRows() in app.js): a row of the rail that is a button — the icon of its source, what
   its entries are called with how many in a grey chip 6px after it, on the line of the title, the hour of the newest and the
   faces of who brought them —, which keeps its icon while rows are selected: it has no checkbox. What it unfolds goes under
   it, a step of 20px in. */
button.row { width: 100%; border: 0; font: inherit; color: inherit; text-align: left; }
.row-title > .count-chip { margin-left: 6px; vertical-align: top; }
.app.selecting .row.burst .row-icon { display: grid; }
.burst-list { display: grid; padding-left: 20px; }
@media (hover: hover) and (pointer: fine) {
  .upcoming:hover { background: color-mix(in srgb, var(--label) 6%, var(--fill)); }
}

.empty { display: grid; gap: var(--s1); justify-items: start; padding: var(--s2) var(--s1); font: var(--meta); color: var(--label-2); }
.empty p { margin: 0; }

/* The account at the foot of the rail: avatar and name; its menu is a .popover. */
.rail-foot {
  padding: var(--s1) var(--s1) calc(var(--s1) + var(--safe-b));
  border-top: 1px solid var(--line);
}
.me {
  display: flex;
  align-items: center;
  gap: var(--s1);
  width: 100%;
  height: var(--control);
  padding: 0 var(--s1);
  border: 0;
  border-radius: var(--radius);
  background: transparent;
  color: var(--label);
  font: 500 14px/1 var(--font-body);
  text-align: left;
  cursor: pointer;
}
.me[aria-expanded="true"] { background: var(--fill); }
/* The circle of an invitation nobody has accepted in «Equipo» (pendingAvatar() in app.js, and .avatar.pending there):
   no tint of its own — the face of a person is .person-avatar's alone, on the tint of who they are (Fase 69). */
.avatar {
  flex: none;
  display: grid;
  place-items: center;
  width: 24px;
  height: 24px;
  border-radius: var(--radius-pill);
  font: 600 11px/1 var(--font-body);
}
.avatar .icon { width: 14px; height: 14px; }
.me-name { min-width: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
@media (hover: hover) and (pointer: fine) {
  .me:hover { background: var(--fill); }
}

/* The iPhone app over the account (iosAppCard() in app.js) until its × closes it: a quiet card with the
   app's icon as the App Store shows it, 40px and 16px in like the icons of the rows, its name and one line
   beside it, and on the right «Instalar» in the accent, like «Conectar →», or «Pronto» in grey, like
   «Próximamente». With a link the whole card but the × is one, and the pointer on it fills the card. */
.ios-banner { flex: none; padding: var(--s1); }
.ios-card {
  display: flex;
  align-items: center;
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
}
.ios-card-body {
  flex: 1;
  min-width: 0;
  display: grid;
  grid-template-columns: 40px minmax(0, 1fr) auto;
  column-gap: 12px;
  align-items: center;
  padding: 8px 4px 8px 7px;
  border-radius: var(--radius-md);
  color: var(--label);
  text-decoration: none;
}
.ios-card-body:hover { text-decoration: none; }
/* The app's own icon (IOS_APP_ICON in app.js), on the card and on its row of «Fuentes»: whole — a square in a
   square, never cut or stretched —, in the corners the App Store gives it (22% of its side), with a hairline of
   the separator so that its dark square does not melt into the page of the dark theme. */
.app-icon { display: block; flex: none; object-fit: contain; border: 1px solid var(--separator); border-radius: 22%; }
.ios-card .app-icon { width: 40px; height: 40px; }
.ios-card-text { min-width: 0; display: grid; }
.ios-card-name, .ios-card-line { min-width: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
.ios-card-name { font: 500 13px/18px var(--font-body); color: var(--label); }
.ios-card-line { font: 400 12px/16px var(--font-body); color: var(--label-2); }
.ios-card-action { font: 500 12px/16px var(--font-body); color: var(--label-2); white-space: nowrap; }
a.ios-card-body .ios-card-action { color: var(--tint); }
.ios-card .icon-btn { width: 24px; height: 24px; margin-right: 4px; }
.ios-card .icon-btn .icon { width: 14px; height: 14px; }
@media (hover: hover) and (pointer: fine) {
  .ios-card:has(a.ios-card-body:hover) { background: var(--fill); }
}

/* «Add Company to any iMessage group» over «Entradas» (lineCard() in app.js), until the space's number hears
   its first conversation or the × closes it: the hairline card of the iPhone app, the logo in the rows'
   16px column, its words — on two lines when they need them — and the ×, and under the words the number,
   grey, with «Copiar» on the right. */
.line-banner { flex: none; padding: 4px var(--s1) 0; }
.line-card {
  display: grid;
  grid-template-columns: 16px minmax(0, 1fr) auto;
  grid-template-areas: "logo name close" ". number copy";
  column-gap: 12px;
  row-gap: 2px;
  align-items: center;
  padding: 8px 4px 8px 7px;
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
}
.line-card-logo { grid-area: logo; width: 16px; height: 16px; }
.line-card-name { grid-area: name; min-width: 0; font: 500 13px/18px var(--font-body); color: var(--label); }
.line-card-number { grid-area: number; min-width: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; font: 400 12px/16px var(--font-body); font-variant-numeric: tabular-nums; color: var(--label-2); }
.line-card .btn-sm { grid-area: copy; height: 26px; padding: 0 10px; font-size: 12px; }
.line-card .icon-btn { grid-area: close; justify-self: end; width: 24px; height: 24px; }
.line-card .icon-btn .icon { width: 14px; height: 14px; }
/* «Connect a source and Company fills itself» (connectCard() in app.js), the same card while nothing is
   connected: the plug of «Fuentes» where the logo goes, the words on two lines when they need them, and
   «Connect» where «Copiar» is, which opens «Fuentes». */
.line-card .line-card-logo.icon { color: var(--label-2); }
.line-card a.btn-sm { grid-area: number; justify-self: start; margin-top: 4px; }

/* Popovers: menus, the «?» of «Ajustes», and the boxes that ask for one thing.
   Fixed and hung from <body> by app.js, which sets top and left. */
.popover {
  opacity: 1;
  transform: scale(1);
  transform-origin: top left;
  transition: opacity var(--t-fast) var(--ease-out), transform var(--t-fast) var(--ease-out);
  position: fixed;
  top: 0;
  left: 0;
  z-index: 25;
  background: var(--raised);
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow);
}
.menu { display: grid; min-width: 184px; max-width: min(280px, calc(100vw - 16px)); padding: 4px; }
.menu-item {
  display: block;
  width: 100%;
  padding: 6px 10px;
  border: 0;
  border-radius: 4px;
  background: transparent;
  color: var(--label);
  font: 400 14px/20px var(--font-body);
  text-align: left;
  cursor: pointer;
}
.menu-item:focus-visible { outline: none; background: var(--fill); }
.menu-item.danger { color: var(--danger); }
/* One of a set with one chosen (the spaces of the rail's head): the name, and a check on the one in use. */
.menu-item { display: flex; align-items: center; gap: 10px; min-width: 0; }
.menu-item .menu-label { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.menu-item .icon { flex: none; width: 16px; height: 16px; }
.menu-icon { display: grid; place-items: center; width: 16px; height: 16px; color: var(--label-2); }
.menu-item.danger .menu-icon { color: var(--danger); }
.menu-label { min-width: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
/* What an item says on its right, apart from its name (Fase 94): the price of a plan in «Upgrade». */
.menu-detail { flex: none; font: 400 13px/20px var(--font-body); color: var(--label-2); white-space: nowrap; }
.menu-separator { height: 1px; margin: 4px 0; background: var(--line); }
@media (hover: hover) and (pointer: fine) {
  .menu-item:hover { background: var(--fill); }
}
/* «Visible to» (Fase 68): under «Only some people» — and under «Some…» of the bar of a selection — the other
   members, each their checkbox, their face and their name (memberCheck() in app.js), scrolling past a handful so the
   popover stays on screen, and the line that stands in for them while they load or when they did not. */
.access-people { display: grid; max-height: 240px; overflow-y: auto; }
.member-check { gap: 8px; }
.menu-note { margin: 0; padding: 6px 10px; font: var(--meta); color: var(--label-2); }
/* That the members of a popover are loading (Fase 95, loadingLine() in app.js), where its items go. */
.menu > .loading-line { padding: 6px 10px; }
/* An option that is not there to choose (in the personal space, «Everyone» and «Only some people»):
   still reached by the arrows, in the grey of what is off. */
.menu-item[aria-disabled="true"],
.menu-item[aria-disabled="true"] .menu-icon { color: var(--label-3); cursor: default; }
@media (hover: hover) and (pointer: fine) {
  .menu-item[aria-disabled="true"]:hover { background: transparent; }
}
/* One of the people of a chat under «Only some people» (Fase 78b): in it for good, checked in that grey. */
.menu-item[aria-disabled="true"] .check-box.on { background: var(--label-3); border-color: var(--label-3); }
/* A grey line under the options that leads somewhere else («Crea un equipo para compartir»): it wraps
   instead of being cut, and it is underlined because it is a way out. */
.menu-item.menu-link { color: var(--label-2); font: var(--meta); }
.menu-item.menu-link .menu-label { white-space: normal; text-decoration: underline; text-underline-offset: 2px; }
/* A checkbox that is a real one (Fase 68, checkBox() in app.js), in the list of «Only some people» and in the rows:
   16px with corners of 5px, a hairline of the tertiary grey while it is empty and, checked, filled with the colour of
   the text with its ✓ drawn in it in the colour of the page — never a box of one colour and nothing in it —, by the
   tokens of either theme. Checked by its class, or by the input of a row just before it. */
.check-box {
  flex: none;
  display: grid;
  place-items: center;
  width: 16px;
  height: 16px;
  border: 1px solid var(--label-3);
  border-radius: 5px;
  background: transparent;
  color: var(--surface);
}
.check-box .icon, .menu-item .check-box .icon { width: 12px; height: 12px; stroke-width: 2.5; opacity: 0; }
.check-box.on, input:checked + .check-box { background: var(--label); border-color: var(--label); }
.check-box.on .icon, input:checked + .check-box .icon { opacity: 1; }
.popover-form { display: grid; gap: var(--s1); width: min(320px, calc(100vw - 16px)); padding: 12px; }
.popover-form .btn { justify-self: end; }
.popover-text { margin: 0; max-width: min(288px, calc(100vw - 16px)); padding: 10px 12px; font: var(--meta); color: var(--label); }

/* Controls --------------------------------------------------------------- */
.btn {
  height: var(--control);
  padding: 0 var(--s2);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  color: var(--label);
  font: var(--button);
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--s1);
  white-space: nowrap;
  text-decoration: none;
  transition: transform var(--t-fast) var(--ease-out), opacity var(--t-fast) var(--ease-out), background-color var(--t-fast) var(--ease-out);
}
.btn:hover { text-decoration: none; }
@media (hover: hover) and (pointer: fine) {
  .btn:hover { background: var(--fill); }
  .btn-primary:hover { background: var(--primary-hover); border-color: var(--primary-hover); }
  .btn-ghost:hover { background: var(--fill); }
}
.btn:active { transform: scale(0.97); }
/* Every other control a finger presses gives under it as .btn does (Fase 144, emil-design-eng: 0.97 on :active, from its centre,
   in --t-fast): the icons alone, the chips, the small round ones and the rows of the rail that are buttons. Not a row of the
   list, which j/k and a click move through tens of times a day, nor words that are a link. The arrows of a result keep the
   half of their height they are lifted by. Under prefers-reduced-motion nothing gives (at the end of this file). */
.icon-btn, .close, .type-chip, .chip, .name-btn, .new-entries, .ask-send, .audio-toggle, .help, .sop-thumb, .sop-file-remove, .nav-row, .space-switcher, .me { transition: transform var(--t-fast) var(--ease-out); }
.icon-btn:active, .close:active, .type-chip:active, .chip:active, .name-btn:active, .new-entries:active, .ask-send:active, .audio-toggle:active, .help:active, .sop-thumb:active, .sop-file-remove:active, .nav-row:active, .space-switcher:active, .me:active { transform: scale(0.97); }
.sop-arrow:active { transform: translateY(-50%) scale(0.97); }
.btn:disabled { opacity: 0.4; cursor: default; transform: none; }
.btn-primary { background: var(--primary); border-color: var(--primary); color: var(--on-primary); font: var(--button); }
.btn-ghost { background: transparent; border-color: transparent; color: var(--label-2); }
.btn-danger { color: var(--danger); }
.btn-lg { height: var(--control-lg); }
.btn-sm { height: var(--control-sm); padding: 0 12px; font: 500 13px/1 var(--font-body); }
/* Icons alone, for the actions that are not the one a screen is for. */
.icon-btn {
  flex: none;
  display: inline-grid;
  place-items: center;
  width: var(--control-sm);
  height: var(--control-sm);
  padding: 0;
  border: 0;
  border-radius: var(--radius);
  background: transparent;
  color: var(--label-2);
  text-decoration: none;
  cursor: pointer;
}
.icon-btn .icon { width: 16px; height: 16px; }
/* A tint of the text colour, so it shows on either theme (on white: rgba(20, 20, 20, 0.06)). */
.icon-btn[aria-expanded="true"] { background: color-mix(in srgb, var(--label) 6%, transparent); color: var(--label); }
.icon-btn:disabled { opacity: 0.4; cursor: default; }
@media (hover: hover) and (pointer: fine) {
  .icon-btn:hover:not(:disabled) { background: color-mix(in srgb, var(--label) 6%, transparent); color: var(--label); text-decoration: none; }
}
.link {
  background: none;
  border: 0;
  padding: 0;
  color: var(--label);
  font: inherit;
  font-weight: 500;
  text-decoration: underline;
  text-underline-offset: 2px;
  cursor: pointer;
}
.link:hover { text-decoration: underline; }
.field {
  width: 100%;
  height: 36px;
  padding: 0 12px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  color: var(--label);
  font: 400 14px/1 var(--font-body);
}
.field::placeholder { color: var(--label-3); }
.field:focus { outline: 2px solid var(--tint); outline-offset: 0; }
.hint { margin: 0; font: var(--footnote); color: var(--label-2); }
/* What went wrong, under a box that asks for something (Fase 95): calm, the dot of --danger and then the words in the grey
   of a hint, as the line of a row says it (.error-line) — never red words. */
.hint.err { color: var(--label-2); }
.hint.err::before { content: ""; display: inline-block; width: 6px; height: 6px; margin-right: 6px; border-radius: var(--radius-pill); background: var(--danger); vertical-align: 1px; }
/* «Dónde está: …», in the key boxes: grey like any hint, and underlined because it is a link. */
a.hint { text-decoration: underline; text-underline-offset: 2px; }
.tag {
  display: inline-flex;
  align-items: center;
  height: 20px;
  padding: 0 6px;
  border-radius: 4px;
  background: var(--fill);
  color: var(--label-2);
  font: var(--small-label);
  white-space: nowrap;
}

/* Detail: icon, title and one line; the body reads like a document ------ */
/* Positioned: the bar of its head lies over it (.head-bar-holder, Fase 139). */
.detail, .page {
  position: relative;
  max-width: var(--content-w);
  margin: 0 auto;
  padding: var(--s5) var(--inset) 96px;
}
.back { display: none; margin-bottom: var(--s2); gap: 6px; padding-left: var(--s1); }
.back .icon { width: 16px; height: 16px; }
.detail-head { display: grid; grid-template-columns: 20px minmax(0, 1fr) auto; column-gap: 12px; align-items: start; }
.detail-icon { display: grid; place-items: center; height: 30px; color: var(--label-2); }
.detail-icon .icon { width: 20px; height: 20px; }
.detail-heading { min-width: 0; }
.detail-title { display: flex; align-items: center; flex-wrap: wrap; gap: var(--s1); }
.detail-title h1 {
  margin: 0;
  font: var(--title-app);
  letter-spacing: -0.02em;
  color: var(--label);
  cursor: text;
  overflow-wrap: anywhere;
}
.title-input {
  flex: 1;
  min-width: 0;
  font: var(--title-app);
  letter-spacing: -0.02em;
  border: 0;
  border-bottom: 2px solid var(--primary);
  background: transparent;
  color: var(--label);
  padding: 0;
  margin: 0;
}
.detail-meta { margin: 4px 0 0; font: var(--meta); color: var(--label-2); overflow-wrap: anywhere; }
/* Who a note is for (Fase 115, addresseesLine() in app.js): right under its title, in the type and the grey of the line under
   it — their faces of 16px, then «For Daniel». */
.detail-for { display: flex; align-items: center; gap: 6px; margin: 4px 0 0; font: var(--meta); color: var(--label-2); }
.detail-for-faces { display: flex; }
/* What a day of a repository's activity counts, on the right of its title in its row and in its head (Fase 94,
   activityCounts() in app.js): a grey chip each, its icon of 14px and the number. */
.activity-counts { display: inline-flex; flex-wrap: wrap; gap: 6px; vertical-align: top; }
.row-title .activity-counts { margin-left: var(--s1); }
.count-chip.activity-count { display: inline-flex; align-items: center; gap: 4px; }
.activity-count .icon { width: 14px; height: 14px; }
/* The title the source gave an entry Company titled again (Fase 60, sourceTitleOf() in app.js): at the end of the meta
   line, in its grey and size. */
.source-title { color: var(--label-3); }
/* The third line of the head of an entry, and its last (Fase 60, detailPeople() in app.js): who it is about on the
   left, «Visible para» on the right, under the title and the tools alike. One line whatever the width: the people
   take what «Visible para» leaves and give way to «+N» (watchChips()). */
.detail-people { grid-column: 2 / -1; display: flex; align-items: center; gap: var(--s1); min-width: 0; margin-top: var(--s1); }
/* «Visible para» (Fase 21), the landing card's «Visible to»: its words, then the faces of who reads it, and in its
   tooltip who they are in words — one pill since Fase 133 (Manu: «que el highlight lo haga todo»). On an entry of mine,
   a dashboard or a page the pill is a button (Fase 68), whose popover is a .menu under it, and its grey under the
   pointer, with the focus or with its popover open is all of it, the words and the faces, 32px tall and round as the
   grey of the faces alone was; on somebody else's, the same pill and nothing to press. On the right of the third line
   of the head. */
.visible-row {
  /* The ring that cuts each face out of the one before: the background the row is on at the time. */
  --ring: var(--surface);
  flex: none;
  display: flex;
  align-items: center;
  gap: var(--s1);
  max-width: 100%;
  min-height: 32px;
  margin: 0 0 0 auto;
  padding: 4px 8px;
  border: 0;
  border-radius: var(--radius-pill);
  background: transparent;
  color: var(--label);
  font: var(--meta);
  text-align: left;
}
.visible-faces { display: flex; align-items: center; min-width: 0; }
button.visible-row { cursor: pointer; }
button.visible-row[aria-expanded="true"], button.visible-row:focus-visible { --ring: var(--fill); background: var(--fill); }
@media (hover: hover) and (pointer: fine) {
  button.visible-row:hover { --ring: var(--fill); background: var(--fill); }
}
.visible-label { flex: none; color: var(--label-2); }
/* The line on screen and, while they cross, the one that goes (swapAudience()): one cell, one over the other. */
.visible-audiences { display: grid; min-width: 0; }
.visible-audience { grid-area: 1 / 1; display: flex; align-items: center; gap: var(--s1); min-width: 0; }
.visible-who { min-width: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; font-weight: 500; }
.avatar-stack { flex: none; display: flex; }
.detail-tools { display: flex; gap: 2px; }
/* Who an entry is about, on the left of the third line of its head (Fase 60, personChips() and, for an iMessage
   entry, peopleRow() in app.js): each person a chip of their face of 24px and their name — their first name, or the
   whole of it in a space that names people so —, and for iMessage a button that opens the box that names them. The
   room the line leaves beside «Visible para», in one line: what does not fit is «+N» (.person-more). Pulled 6px left so
   that the faces line up with the meta line, with 4px all round for the ring of a chip with the focus. */
.people-row { flex: 1 1 0; min-width: 0; display: flex; flex-wrap: nowrap; gap: 4px; overflow: hidden; padding: 4px; margin: -4px 0 -4px -6px; }
.person {
  flex: none;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: 28px;
  padding: 0 8px 0 2px;
  border: 0;
  border-radius: var(--radius-pill);
  background: transparent;
  color: var(--label);
  font: var(--meta);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
button.person { cursor: pointer; }
/* The lead a call or a day of texts of Quo is with (Fase 148d, personChips() in app.js): the chip a link to its page, face and
   name, the name an inline link (.link) and the face never underlined. */
a.person { text-decoration: none; }
.person-more { padding: 0 6px; color: var(--label-2); }
/* How a call nobody talked in went, after the people of the last line of the head of its entry (Fase 148e, outcomeChip() in
   app.js): «Voicemail», «No answer»… in a grey chip — the quiet fill and the middle grey of a number's (.count-chip) —, as
   tall as a face of the line and in its type, on its axis. It never gives way to «+N» (watchChips()). */
.outcome-chip { flex: none; align-self: center; display: inline-flex; align-items: center; height: 24px; padding: 0 8px; border-radius: var(--radius-pill); background: var(--fill); color: var(--label-2); font: var(--meta); white-space: nowrap; }
@media (hover: hover) and (pointer: fine) {
  button.person:hover { background: var(--fill); }
}
/* A face (personAvatar() in app.js): their photo, or their initials — or the last two digits of a number nobody
   named — on one of the eight tints (--avatar-1…8), the same tint for the same number, or the same member by their
   user id, on every screen (Fase 69). 18px in a row of the list (Fase 67); 24px in the head of an entry, «Visible para», «Equipo» and the rail;
   26px beside a group of messages of a chat (Fase 74); 48px at the head of «Ajustes» (Fase 71b); 20px where no size is
   said. A photo fills its circle (object-fit: cover). One over the other in a stack (.avatar-stack), each cut out of the
   one before by a ring of the colour under them (--ring), and «+N» after three. Beside the messages of a number nobody
   named, the outline of a person on the grey of «+N» (.face-unknown): never its digits, nor a tint somebody has. */
.person-avatar {
  flex: none;
  display: inline-grid;
  place-items: center;
  width: 20px;
  height: 20px;
  border-radius: var(--radius-pill);
  background: var(--avatar-8);
  color: var(--label);
  font: 600 9px/1 var(--font-body);
  letter-spacing: 0.02em;
  object-fit: cover;
}
.person-avatar.face-24 { width: 24px; height: 24px; font-size: 10px; }
.person-avatar.face-26 { width: 26px; height: 26px; font-size: 11px; }
.person-avatar.face-18 { width: 18px; height: 18px; font-size: 8px; }
.person-avatar.face-48 { width: 48px; height: 48px; font-size: 18px; }
.person-avatar .icon { width: 60%; height: 60%; }
.person-avatar.face-more { background: var(--fill); color: var(--label-2); }
/* On the web (Fase 133, audienceLine() in app.js): the globe after the faces of «Visible to», one more of them in the
   grey of «+N». */
.person-avatar.face-web { background: var(--fill); color: var(--label-2); }
.person-avatar.face-unknown { background: var(--fill); color: var(--label-2); }
/* Beside what Company says in a chat (Fase 79, contextFace() in app.js): its flower in the circle, white on the dark of the
   mark of the rail in both themes — no tint of the palette, which is for people. */
.person-avatar.context-face { padding: 3px; background: var(--dark-bg); object-fit: contain; }
.avatar-stack .person-avatar { box-shadow: 0 0 0 2px var(--ring, var(--surface)); }
.avatar-stack .person-avatar + .person-avatar { margin-left: -5px; }
/* In the head of a turn, who said it wears the number in its tooltip; the chips of «Which one is you?» wear the avatar. */
.chip .person-avatar { margin-left: -4px; }
.detail-body { display: grid; gap: var(--s4); margin-top: var(--s4); }
/* The bar of a head (Fase 139, headBar() and watchHead() in app.js): once the head of an entry, a conversation, the page of an
   entity, of a SOP or a dashboard has scrolled out of the pane, the head made compact in a bar stuck to the top of the pane, as
   wide as the view and its things where the head has them — the icon of its source; its title on one line, cut with an ellipsis;
   its source and its date in grey beside it when they fit, else on a second line the bar's 20px hide —, and on its right the
   head's own «Visible to» and tools. On the page's surface, a hairline under it. Over the view, in a layer as big as it that
   the pointer goes through (.head-bar-holder): nothing under it moves when it shows. It comes down 6px into its place as it
   fades in, in 160ms, and goes the same way; under prefers-reduced-motion it only fades, where it rests (Fase 144; at once
   until then), and at once when a view painted again comes with it shown (.is-instant). The tools it has leave in the head a
   hole as big as each (.head-hole). */
.head-bar-holder { position: absolute; inset: 0; z-index: 2; pointer-events: none; }
.head-bar {
  position: sticky;
  top: 0;
  display: flex;
  align-items: center;
  gap: var(--s1);
  min-height: var(--s6);
  padding: 4px var(--inset);
  background: var(--surface);
  border-bottom: 1px solid var(--line);
  pointer-events: auto;
  opacity: 0;
  transform: translateY(-6px);
  visibility: hidden;
  transition: opacity var(--t-fast) var(--ease-out), transform var(--t-fast) var(--ease-out), visibility 0s linear var(--t-fast);
}
.head-bar.is-shown { opacity: 1; transform: none; visibility: visible; transition-delay: 0s; }
.head-bar.is-instant { transition: none; }
.head-bar-back { display: none; }
.head-bar-icon { flex: none; display: grid; place-items: center; width: 20px; height: 20px; color: var(--label-2); }
.head-bar-icon .icon { width: 16px; height: 16px; }
.head-bar-text { flex: 1 1 0; min-width: 0; display: flex; flex-wrap: wrap; align-items: baseline; column-gap: var(--s1); height: 20px; overflow: hidden; }
.head-bar-title { min-width: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; font: 600 14px/20px var(--font-body); color: var(--label); }
.head-bar-meta { flex: none; font: var(--meta); line-height: 20px; color: var(--label-2); white-space: nowrap; }
.head-bar-actions { flex: 0 1 auto; min-width: 0; display: flex; align-items: center; justify-content: flex-end; gap: var(--s1); }
.head-hole { flex: none; }
/* Somebody else's private entry (renderLocked()): whose it is, one line and «Pedir acceso». Its title
   is not one to edit. An entry older than what a space on Free remembers (Fase 73, renderPlanLocked()) is drawn the
   same, with «Upgrade to remember everything» where «Pedir acceso» goes. */
.detail.locked .detail-title h1 { cursor: default; }
.locked-request, .locked-upgrade { margin-top: var(--s2); }
/* «Ana pide ver esta entrada», over the content of an entry of mine, with «Permitir» and «Rechazar». */
.entry-requests { display: grid; gap: var(--s1); margin-top: var(--s3); }
.entry-requests:empty { display: none; }
.access-request {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 12px;
  padding: 10px 12px;
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
}
.access-request-text { flex: 1; min-width: 12em; font: var(--row-title); color: var(--label); overflow-wrap: anywhere; }
/* «Which one is you?» over an iMessage entry (whichOneLine() in app.js): one quiet line — the question in
   grey, the numbers nobody named as chips, «Not here» as a grey link — and what was refused under it. */
.which-one { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; margin-bottom: var(--s3); font: var(--meta); }
.which-one-text { margin-right: 4px; color: var(--label-2); }
.chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: 28px;
  padding: 0 10px;
  border: 1px solid var(--line);
  border-radius: var(--radius-pill);
  background: var(--surface);
  color: var(--label);
  font: 500 13px/1 var(--font-body);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  cursor: pointer;
}
.which-one-skip {
  padding: 0 4px;
  border: 0;
  background: none;
  color: var(--label-2);
  font: 400 13px/28px var(--font-body);
  text-decoration: underline;
  text-underline-offset: 2px;
  cursor: pointer;
}
.chip:disabled, .which-one-skip:disabled { opacity: 0.4; cursor: default; }
.which-one .hint { flex-basis: 100%; }
/* «Name» beside a number nobody named, after who said a turn and on its line: small, grey and outlined, like
   a tag one can press. */
.name-btn {
  padding: 0 7px;
  border: 1px solid var(--line);
  border-radius: var(--radius-pill);
  background: transparent;
  color: var(--label-2);
  font: 500 12px/18px var(--font-body);
  cursor: pointer;
}
@media (hover: hover) and (pointer: fine) {
  .chip:hover:not(:disabled), .name-btn:hover { background: var(--fill); color: var(--label); }
  .which-one-skip:hover:not(:disabled) { color: var(--label); }
}
/* The box «Name» opens (openNameBox() in app.js, Fase 58): in a team, «This is…» in small grey words (Fase 81) over the
   members of the space, over the box to write a name in, each their face of 20px — the one they have everywhere (Fase
   69) — and their name, a row to tap like the items of a menu, scrolling past a handful. */
.name-members-title { margin: 0; padding: 0 4px; font: var(--small-label); color: var(--label-2); }
.name-members { display: grid; max-height: 216px; margin: -4px -4px 0; overflow-y: auto; }
.name-member {
  display: flex;
  align-items: center;
  gap: 10px;
  min-width: 0;
  padding: 6px 8px;
  border: 0;
  border-radius: 4px;
  background: transparent;
  color: var(--label);
  font: 400 14px/20px var(--font-body);
  text-align: left;
  cursor: pointer;
}
.name-member-label { min-width: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
.name-member:focus-visible { outline: none; background: var(--fill); }
.name-member:disabled { opacity: 0.4; cursor: default; }
@media (hover: hover) and (pointer: fine) {
  .name-member:hover:not(:disabled) { background: var(--fill); }
}
/* A conversation (paintConversation() in app.js, Fase 58): its days one after the other, each after a hairline
   with its day in the middle, as Messages and Slack part days; the summary of a day that is over under that line,
   quieter than the messages; and at either end the edge that brings more days as the reader gets there, «Loading…»
   while it does. Its title is who is in it, not one to edit. */
.chat-view .detail-title h1 { cursor: default; }
.chat-days { display: grid; gap: var(--s4); margin-top: var(--s4); }
.chat-day { display: grid; gap: var(--s2); }
.chat-day-line { display: flex; align-items: center; gap: 12px; font: var(--small-label); color: var(--label-2); }
.chat-day-line::before, .chat-day-line::after { content: ""; flex: 1; height: 1px; background: var(--line); }
.chat-day-summary { padding: 10px 12px; border-radius: var(--radius-md); background: var(--fill); }
.chat-day-summary .rich { font: var(--meta); color: var(--label-2); }
.chat-edge { min-height: 1px; font: var(--meta); color: var(--label-3); text-align: center; }
/* The messages of a day of a chat (Fase 74, renderMessages() in app.js), as Slack reads them and with no bubbles: what one
   person sent one after the other in a group, their circle of 26px on the left and, on its first line, their name in 600
   and the hour of its first message in light grey; under it each message on its line, 14px on 1.5. Where there is a
   pointer, the hour of a message on the right in the same grey while the pointer is on it — or the focus is on a link in
   it —, in the room kept for it; a phone shows the hour of each group. */
.messages { display: grid; gap: var(--s2); }
.message-group { display: grid; grid-template-columns: 26px minmax(0, 1fr); column-gap: 10px; align-items: start; }
.message-group-body { display: grid; gap: 2px; min-width: 0; }
.message-head { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--s1); min-width: 0; }
.message-author { font: 600 14px/21px var(--font-body); color: var(--label); overflow-wrap: anywhere; }
/* Who said a group when no member of the space is behind their number (Fase 81, authorButton() in app.js): the same
   words, a button that opens «This is…». */
button.message-author { padding: 0; border: 0; background: none; text-align: left; cursor: pointer; }
@media (hover: hover) and (pointer: fine) {
  button.message-author:hover { text-decoration: underline; text-underline-offset: 2px; }
}
/* The lead a day of texts of Quo is with (Fase 148d, renderMessages() in app.js): their name an inline link (.link) to their
   page, and their circle too, as it is and never underlined. */
a.message-face { display: grid; text-decoration: none; }
.message-time, .message-hover-time { font: 400 12px/21px var(--font-body); font-variant-numeric: tabular-nums; color: var(--label-3); white-space: nowrap; }
.message { position: relative; display: grid; gap: 6px; min-width: 0; font: 400 14px/1.5 var(--font-body); color: var(--label); }
.message-text { white-space: pre-wrap; overflow-wrap: anywhere; }
.message-text a { color: var(--label); text-decoration: underline; text-underline-offset: 2px; }
.message-hover-time { position: absolute; top: 0; right: 0; visibility: hidden; }
.message .turn-media { margin-top: 0; }
@media (hover: hover) and (pointer: fine) {
  .message { padding-right: 64px; }
  .message:hover .message-hover-time, .message:focus-within .message-hover-time { visibility: visible; }
}
/* The card under a message for an address in it (linkCard()): the globe, the domain and the address cut short to its
   line, read off the address alone — nothing is asked of the network —, with the hairline and the corners of a file's card. */
.link-card {
  justify-self: start;
  display: flex;
  align-items: center;
  gap: 10px;
  width: min(400px, 100%);
  padding: 8px 12px;
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
  color: var(--label);
  text-decoration: none;
}
.link-card:hover { text-decoration: none; }
.link-card > .icon { width: 16px; height: 16px; color: var(--label-2); }
.link-card-text { display: grid; min-width: 0; }
.link-card-domain { font: 500 13px/18px var(--font-body); color: var(--label); overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
.link-card-url { font: 400 12px/16px var(--font-body); color: var(--label-2); overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
@media (hover: hover) and (pointer: fine) {
  .link-card:hover { background: var(--fill); }
}
.doc-section { display: grid; gap: var(--s1); }
.doc-section h3 { margin: 0; font: 600 14px/20px var(--font-body); color: var(--label); }
.fold {
  justify-self: start;
  padding: 0;
  border: 0;
  background: none;
  color: var(--label-2);
  font: 500 13px/20px var(--font-body);
  text-decoration: underline;
  text-underline-offset: 2px;
  cursor: pointer;
}
.tasks { display: grid; gap: 6px; margin: 0; padding: 0; list-style: none; }
.tasks li { display: flex; gap: 10px; font: var(--reading); color: var(--label); }
.tasks li::before { content: ""; flex: none; width: 14px; height: 14px; margin-top: 5px; border: 1.5px solid var(--label-3); border-radius: 4px; }
/* Tasks with their boxes (Fase 86, taskList() in app.js), the «Tasks» of an entry and the ones of an answer of Ask: a line
   each, its box on the axis of its first line — the input, unseen, over the box it ticks, as in a row of the list —, what
   is to be done in the type of reading and after it, smaller, who it is for in the middle grey when that is not me and
   the entry it comes from in the lightest grey, the way to it; ticked, struck through in the lightest grey. */
.task-list { display: grid; gap: 6px; margin: 0; padding: 0; list-style: none; }
.task { display: flex; align-items: flex-start; gap: 10px; font: var(--reading); color: var(--label); }
.task-check { position: relative; flex: none; display: grid; place-items: center; width: 20px; height: 24px; }
.task-check input { position: absolute; inset: 0; width: 100%; height: 100%; margin: 0; opacity: 0; cursor: pointer; }
.task-check input:focus-visible + .check-box { outline: 2px solid var(--tint); outline-offset: 2px; }
.task-line { min-width: 0; overflow-wrap: anywhere; }
/* What is to be done is the way to the page of the task (Fase 114d), in the colour of the line. */
.task-line .task-text { color: inherit; }
.task-who, .task-entry { margin-left: var(--s1); font: var(--meta); }
.task-who { color: var(--label-2); }
.task-entry { color: var(--label-3); text-decoration: none; }
.task:has(input:checked) .task-text, .task-row:has(input:checked) .task-text { color: var(--label-3); text-decoration: line-through; }
@media (hover: hover) and (pointer: fine) {
  .task-entry:hover { color: var(--label-2); text-decoration: none; }
}

/* Raw transcript: speaker name in 600, everything else in the reading size. */
.turns { display: flex; flex-direction: column; gap: var(--s2); }
.turn { display: grid; gap: 2px; }
.turn-head { display: flex; align-items: baseline; gap: var(--s1); }
.turn-speaker { font: var(--reading); font-weight: 600; color: var(--label); }
.turn-ts { font: 400 12px/1 var(--font-body); font-variant-numeric: tabular-nums; color: var(--label-3); }
.turn-text { font: var(--reading); color: var(--label); white-space: pre-wrap; overflow-wrap: anywhere; }
/* What a message of a chat carried (Fase 64; turnBody() and messageBody() in app.js), under who said it: an audio as a
   compact player — play and pause in a circle of 32px, the bar of where it is, how long it lasts — with what it says
   under it, read as the turns are; a photo inside its line, 320px tall at most, which opens in a new tab (Fase 74) — an
   iPhone's, a HEIC, at the JPEG the server makes of it (Fase 138, .sk-photo while it is made) —; a video or a file as
   the card of an original. Colours from the tokens alone, which the dark theme sets again. */
.turn-media { display: grid; justify-items: start; gap: var(--s1); min-width: 0; margin-top: 6px; }
.audio-player {
  display: flex;
  align-items: center;
  gap: var(--s1);
  width: min(320px, 100%);
  padding: 4px 12px 4px 4px;
  border: 1px solid var(--line);
  border-radius: var(--radius-pill);
}
.audio-toggle {
  flex: none;
  display: grid;
  place-items: center;
  width: var(--control-sm);
  height: var(--control-sm);
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: var(--primary);
  color: var(--on-primary);
  cursor: pointer;
}
.audio-toggle .icon { width: 14px; height: 14px; fill: currentColor; }
.audio-toggle:focus-visible, .media-thumb:focus-visible { outline: 2px solid var(--tint); outline-offset: 2px; }
.audio-bar { flex: 1; min-width: 0; height: 16px; margin: 0; accent-color: var(--primary); cursor: pointer; }
.audio-time { flex: none; min-width: 32px; font: 400 12px/16px var(--font-body); font-variant-numeric: tabular-nums; color: var(--label-2); text-align: right; }
.audio-transcript { font: var(--reading); color: var(--label); white-space: pre-wrap; overflow-wrap: anywhere; }
.media-thumb { display: block; max-width: 100%; padding: 0; border: 0; border-radius: var(--radius-md); background: none; cursor: pointer; }
.media-thumb img { display: block; max-width: 100%; max-height: 320px; border: 1px solid var(--line); border-radius: var(--radius-md); }
.turn-media .original-file { width: min(400px, 100%); }
.prose { margin: 0; font: var(--reading); color: var(--label); white-space: pre-wrap; overflow-wrap: anywhere; }
/* Markdown rendered as a document (richText in app.js): the reading font, tight rhythm, no decoration. */
.rich { display: grid; gap: 10px; font: var(--reading); color: var(--label); overflow-wrap: anywhere; }
.rich p { margin: 0; }
.rich .rich-h { margin: 6px 0 0; font: 600 14px/20px var(--font-body); color: var(--label); }
.rich h5.rich-h { font-weight: 500; color: var(--label-2); }
.rich .rich-list { margin: 0; padding-left: 20px; display: grid; gap: 6px; }
.rich strong { font-weight: 600; }
.rich code { font: var(--code); background: var(--fill); border-radius: 4px; padding: 1px 4px; }
.rich a { color: var(--label); text-decoration: underline; text-underline-offset: 2px; }
.rich a.rich-moment { font: 500 12px/16px var(--font-body); color: var(--label-2); text-decoration: none; white-space: nowrap; background: var(--fill); border-radius: var(--radius-pill); padding: 2px 7px; vertical-align: 1px; }
@media (hover: hover) and (pointer: fine) {
  .rich a.rich-moment:hover { color: var(--label); }
}
/* A block of code (Fase 71c, codeBlock() in app.js): its lines as they were written, wrapped, on the grey of the code in
   a line, and «Copy» in its top right corner, above the first line, so that no line gives up its width to it. */
.rich-code { position: relative; min-width: 0; }
.rich-code pre { margin: 0; padding: 44px 12px 12px; border-radius: var(--radius-md); background: var(--fill); font: var(--code); white-space: pre-wrap; overflow-wrap: anywhere; }
.rich .rich-code code { padding: 0; border: 0; border-radius: 0; background: none; }
.rich-code .rich-copy { position: absolute; top: 6px; right: 6px; }
/* A key struck out of a text (Fase 84b, keyChip() in app.js) — a message of a chat, a transcript, a note, its code —: a
   chip of 22px in the line of the words, on the quiet fill, 6px round, the key of 12px in the lightest grey and its name in
   500 12px of the mono type in the middle grey. No blur, no value, nothing to press: the tokens of the theme alone, so
   it is the same piece in the light and in the dark. On the fill of code it takes the page's surface, to stand out. */
.key-chip { display: inline-flex; align-items: center; gap: 4px; height: 22px; padding: 0 6px; border-radius: var(--radius); background: var(--fill); color: var(--label-2); vertical-align: middle; white-space: nowrap; }
.key-chip .icon { flex: none; width: 12px; height: 12px; color: var(--label-3); }
.key-chip-name { font: 500 12px/1 var(--font-mono); color: var(--label-2); }
.rich code .key-chip, .rich-code .key-chip { background: var(--surface); }
/* The original of an entry that is an image (originalImage() in app.js): as wide as the column at most and
   never wider than itself, with the hairline of the cards so that a white screenshot keeps its edge. */
.original-image { margin: 0; min-width: 0; }
.original-image img { display: block; max-width: 100%; height: auto; border: 1px solid var(--line); border-radius: var(--radius-md); }
/* A document (Fase 40), as Fathom opens a call: «Resumen» on top (summaryBlock() in app.js), the H3 of every
   section with «Resumir de nuevo» at the end of its line, grey and small, its words lined up with the column's
   edge; then «Texto | Original» (documentViews()), the tabs as the segmented «Tema», each view under them. */
.doc-summary-head { display: flex; align-items: center; justify-content: space-between; gap: var(--s1); }
.doc-summary-head .btn { margin-right: -12px; gap: 6px; }
.doc-summary-head .btn .icon { width: 14px; height: 14px; }
.doc-views { display: grid; gap: var(--s2); }
.doc-views > .segmented { justify-self: start; }
/* A day of a repository's activity, opened (Fase 131, activitySection() in app.js): each section of its text under the
   summary, its heading in the type of «Summary» on a button as wide as the column and as tall as the head of «Summary»,
   with on its right what it counts in a grey chip (.count-chip) and the chevron, which turns while it is open. A line each
   (.activity-row), as the changes of an ad account's day: when in the lightest grey, what it says in the colour of the
   text, who in the middle grey and at the end its short sha — or number, or tag — in a grey chip of the mono type, as
   the code of a SOP; what the connector counted rather than listed («12 merges into fase-9») a line in grey. */
.activity-toggle { display: flex; align-items: center; gap: var(--s1); width: 100%; min-height: var(--control-sm); padding: 0; border: 0; background: none; font: inherit; color: inherit; text-align: left; cursor: pointer; }
.activity-title { flex: 1; min-width: 0; overflow-wrap: anywhere; }
.activity-toggle .icon { width: 16px; height: 16px; color: var(--label-2); transition: transform var(--t-fast) var(--ease-out); }
.activity-toggle[aria-expanded="true"] .icon { transform: rotate(180deg); }
.activity-rows { display: grid; margin: 0; padding: 0; list-style: none; }
.activity-row { display: flex; align-items: baseline; gap: 10px; padding: 6px 0; font: var(--row-line); color: var(--label); }
.activity-time { flex: none; min-width: 40px; font-variant-numeric: tabular-nums; color: var(--label-3); }
.activity-text { flex: 1; min-width: 0; overflow-wrap: anywhere; }
.activity-by { flex: none; color: var(--label-2); white-space: nowrap; }
.activity-ref { flex: none; height: 20px; padding: 0 6px; border-radius: 4px; background: var(--fill); color: var(--label-2); font: 500 12px/20px var(--font-mono); white-space: nowrap; }
.activity-note { padding: 6px 0; font: var(--row-line); color: var(--label-2); }
@media (hover: hover) and (pointer: fine) {
  .activity-toggle:hover .icon { color: var(--label); }
}
/* «Original» (originalView()): a PDF in a frame as tall as most of the screen, on the grey of a panel until it
   draws; a file the browser does not draw as a card with the hairline and the corners of .access-request, and
   the button that opens it (fileCard()). */
.original-view { display: grid; gap: var(--s1); min-width: 0; }
.original-frame { display: block; width: 100%; height: clamp(420px, 75vh, 1000px); border: 1px solid var(--line); border-radius: var(--radius-md); background: var(--fill); }
.original-file {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 12px;
  padding: 12px 16px;
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
}
.original-file > .icon { color: var(--label-2); }
.original-file-text { flex: 1; min-width: 12em; display: grid; gap: 2px; }
.original-file-name { font: var(--row-title); color: var(--label); overflow-wrap: anywhere; }
.original-file-size { font: var(--row-line); color: var(--label-2); }

/* Ask: the question box of the home pane (and of onboarding.html) -------- */
.ask {
  max-width: calc(var(--ask-w) + 2 * var(--inset));
  margin: 0 auto;
  padding: 18vh var(--inset) 96px;
  display: grid;
  gap: 12px;
  align-content: start;
}
/* Ask greets (Fase 82, askHello() in app.js), centred over the box: the flower of Company — public/mark.svg, as a mask,
   in the colour on the accent — on a disc of 40px of the accent; «Good evening, Manu» in the heading type, 44px; and one
   line of 15px in the middle grey, all of it the way to What's new — the faces of 18px of the others in what is new,
   then what is new since when —, filled under the pointer as a suggestion is. On a phone, 32px, and the line wraps. */
.ask-hello { display: grid; justify-items: center; gap: 12px; margin-bottom: var(--s3); text-align: center; }
.ask-mark { display: block; width: 40px; height: 40px; border-radius: var(--radius-pill); background: var(--primary); }
.ask-mark::before {
  content: "";
  display: block;
  width: 100%;
  height: 100%;
  background: var(--on-primary);
  -webkit-mask: url(/mark.svg) center / 30px no-repeat;
  mask: url(/mark.svg) center / 30px no-repeat;
}
.ask-greeting { margin: 0; font: 700 44px/1.05 var(--font-heading); letter-spacing: -0.025em; color: var(--label); overflow-wrap: anywhere; }
.ask-news { --ring: var(--surface); display: inline-flex; align-items: center; gap: var(--s1); max-width: 100%; padding: 4px var(--s1); border-radius: var(--radius); font: 400 15px/22px var(--font-body); color: var(--label-2); text-decoration: none; }
.ask-news:hover { text-decoration: none; }
.ask-news-faces { flex: none; display: flex; }
.ask-news-text { min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
@media (hover: hover) and (pointer: fine) {
  .ask-news:hover { --ring: var(--fill); background: var(--fill); color: var(--label); }
}
.ask-field { position: relative; }
.ask-input {
  display: block;
  width: 100%;
  min-height: 52px;
  max-height: 240px;
  padding: 14px 52px 14px 16px;
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  background: var(--surface);
  color: var(--label);
  font: 400 15px/22px var(--font-body);
  resize: none;
  overflow-y: auto;
  box-shadow: 0 1px 2px rgba(10, 10, 10, 0.04);
  -webkit-appearance: none;
  appearance: none;
}
.ask-input::placeholder { color: var(--label-3); }
.ask-input:focus { outline: none; border-color: var(--label-2); }
.ask-input:disabled { background: var(--fill); cursor: not-allowed; }
/* Switched off, the placeholder is the one line that says why: it has to read (AA) on the grey. */
.ask-input:disabled::placeholder { color: var(--label-2); }
.ask-send {
  position: absolute;
  right: 10px;
  bottom: 10px;
  display: grid;
  place-items: center;
  width: var(--control-sm);
  height: var(--control-sm);
  padding: 0;
  border: 0;
  border-radius: var(--radius-pill);
  background: var(--primary);
  color: var(--on-primary);
  cursor: pointer;
}
.ask-send .icon { width: 16px; height: 16px; stroke-width: 2; }
.ask-send:disabled { background: var(--line); color: var(--label-3); cursor: default; }
/* «New question» (Fase 86, newQuestion() in app.js): with an answer on screen, a × of 28px on the left of the button that
   sends, in the lightest grey — the colour of the text under the pointer, as any icon alone —, which takes Ask back to
   the start. What is typed keeps clear of it. */
.ask-new { position: absolute; right: 46px; bottom: 12px; width: 28px; height: 28px; color: var(--label-3); }
.ask-field:has(.ask-new:not([hidden])) .ask-input { padding-right: 80px; }
.ask-suggestions { display: grid; }
/* Under the suggestions (Fase 86, openTasksLine() in app.js): «You have 6 open tasks», one line in the lightest grey where
   the words of the suggestions are, which asks for them; the colour of the text under the pointer. */
.ask-tasks { justify-self: start; padding: var(--s1) var(--s2); border: 0; background: none; color: var(--label-3); font: 400 13px/20px var(--font-body); text-align: left; cursor: pointer; }
.suggestion {
  padding: var(--s1) var(--s2);
  border: 0;
  border-radius: var(--radius);
  background: transparent;
  color: var(--label-2);
  font: 400 14px/20px var(--font-body);
  text-align: left;
  cursor: pointer;
}
.suggestion:disabled { opacity: 0.5; cursor: default; }
.ask-answer { display: grid; gap: 12px; margin-top: var(--s2); }
.ask-answer:empty { display: none; }
/* «Conectar una fuente» under the answer to an empty inbox: at its own width, not across the column. */
.ask-answer > .btn { justify-self: start; }
.ask-question { margin: 0; font: var(--subtitle-app); letter-spacing: -0.01em; color: var(--label); overflow-wrap: anywhere; }
.ask-text { margin: 0; font: var(--reading); color: var(--label); white-space: pre-wrap; overflow-wrap: anywhere; }
.ask-sources { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; }
.ask-sources-label { margin-right: 2px; font: var(--small-label); color: var(--label-2); }
/* An entry an answer or an observation comes from: icon and title, and it opens it. */
.cite {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  max-width: 240px;
  height: 28px;
  padding: 0 10px;
  border: 1px solid var(--line);
  border-radius: var(--radius-pill);
  background: var(--surface);
  color: var(--label);
  font: 400 13px/1 var(--font-body);
  text-decoration: none;
  vertical-align: middle;
}
.cite .icon { width: 14px; height: 14px; color: var(--label-2); }
.cite span { min-width: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
.cite:hover { text-decoration: none; }
.answer-tools { display: flex; gap: 2px; margin-left: calc(var(--s1) * -1); }
@media (hover: hover) and (pointer: fine) {
  .suggestion:hover:not(:disabled) { background: var(--fill); color: var(--label); }
  .ask-tasks:hover:not(:disabled) { color: var(--label); }
  .fold:hover { color: var(--label); }
  .cite:hover { background: var(--fill); }
}
/* Today (Fase 105, todayBlock() in app.js): Ask's start when the day has anything, under its suggestions (Fase 135) — and
   the answer to «What do I have today?» under its line —: three flat blocks, no card, each under a heading of What's new's
   sections (an icon of 14px, then small capitals of 11px in the lightest grey, 16px over it and 4px under it), and its rows
   where the rows of «Tasks» have theirs, 20px in. «Meetings»: a row of 32px each — its hour in 13px of the middle grey in a
   column of 64px, its title in 500 14px of the colour of the text and on its right the faces of 18px of who else is in it,
   all of it the way to its entry —, and under it, where its title starts, what was last decided with them in 13px of the
   lightest grey, the way to where it was. «Tasks»: the rows of «Tasks» with their boxes, and «+N» in a grey chip, the way to
   «Tasks». «Waiting on»: a row of 32px each, the face of 20px of whose it is, their name in the middle grey and what is to
   be done in the colour of the text. Last, one line of 13px in the lightest grey: who is away. Out of sight while an answer
   is on screen, and nothing at all for a day with nothing in it. */
.ask-today { margin-top: var(--s1); }
.ask-today:empty { display: none; }
.today { display: grid; }
.today-heading { display: flex; align-items: center; gap: 6px; padding: var(--s2) 20px 4px; font: 500 11px/16px var(--font-body); letter-spacing: 0.06em; text-transform: uppercase; color: var(--label-3); }
.today-heading:first-child { padding-top: 0; }
.today-heading .icon { width: 14px; height: 14px; }
.today-meeting { display: grid; }
.today-meeting-main { --ring: var(--surface); display: flex; align-items: center; gap: 12px; min-height: 32px; padding: 0 10px 0 20px; border-radius: var(--radius); color: inherit; text-decoration: none; }
.today-time { flex: none; width: 64px; font: 400 13px/20px var(--font-body); font-variant-numeric: tabular-nums; color: var(--label-2); white-space: nowrap; }
.today-title { flex: 1; min-width: 0; font: 500 14px/20px var(--font-body); color: var(--label); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.today-faces { flex: none; display: flex; }
.today-note { justify-self: start; max-width: calc(100% - 106px); margin: -4px 0 4px 96px; font: 400 13px/18px var(--font-body); color: var(--label-3); text-decoration: none; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* «+3 more» under my tasks (Fase 164), as «+3 more» of a person of «Team»: where the words of the rows over it start — the
   20px of Today, one indent, the box and its 10px —, 500 13px in the lightest grey, the middle one under the pointer. */
.today-more { justify-self: start; margin: 2px 0 0 76px; font: 500 13px/20px var(--font-body); color: var(--label-3); text-decoration: none; }
.today-waiting { --ring: var(--surface); display: flex; align-items: center; gap: var(--s1); min-height: 32px; padding: 0 10px 0 20px; border-radius: var(--radius); color: inherit; text-decoration: none; }
.today-meeting-main:hover, .today-waiting:hover, .today-more:hover { text-decoration: none; }
.today-who { flex: none; font: 500 14px/20px var(--font-body); color: var(--label-2); }
.today-what { flex: 1; min-width: 0; font: 400 14px/20px var(--font-body); color: var(--label); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.today-away { margin: var(--s2) 0 0; padding: 0 10px 0 20px; font: 400 13px/20px var(--font-body); color: var(--label-3); }
.today-away:first-child { margin-top: 0; }
.today-away a { color: inherit; text-decoration: none; }
@media (hover: hover) and (pointer: fine) {
  .today-meeting-main:hover, .today-waiting:hover { --ring: var(--fill); background: var(--fill); }
  .today-note:hover, .today-away a:hover { color: var(--label-2); }
  .today-more:hover { color: var(--label-2); }
}

/* «Fuentes» and «Ajustes»: an H1 and lists of rows ----------------------- */
.page { display: grid; gap: var(--s3); align-content: start; }
.page h1 { margin: 0; font: var(--title-app); letter-spacing: -0.02em; color: var(--label); }
/* The tabs of «Fuentes» (Fase 52, sourcesTabs() in app.js): one row under the title — «All», «Connected» and
   a category each —, the segmented control of «Texto | Original», 8px closer to the title than the lists are
   to one another, and the one on screen under them (.sources-panel). On a narrow screen they take a second line.
   On their right, lined up with their first line, its search (Fase 149, sourcesSearch()): 240px wide and as tall as they are,
   the box of the rail's search — the field of the rail and its line, its words in the lightest grey while it is empty — with
   a magnifier of 16px in that grey in it, on the left. On a phone it has a line of its own over the tabs, a thumb tall. The
   list it narrows takes the focus back from it with no ring: the rows in it have theirs. */
.sources-head { display: flex; align-items: flex-start; gap: var(--s1) var(--s2); margin-top: calc(var(--s1) * -1); }
.sources-tabs { flex: 1; min-width: 0; }
.sources-search { flex: none; width: 240px; padding: 0; }
.sources-search .icon { position: absolute; left: 10px; top: 50%; width: 16px; height: 16px; transform: translateY(-50%); color: var(--label-3); pointer-events: none; }
.sources-search input { height: var(--control-sm); padding: 0 12px 0 32px; }
.sources-panel { display: grid; gap: var(--s3); }
.sources-panel:focus { outline: none; }
.sources-panel > .hint { padding: var(--s1) 0; }
@media (max-width: 880px) {
  .sources-head { flex-direction: column-reverse; align-items: stretch; }
  .sources-search { width: auto; }
  .sources-search input { height: 36px; }
}
.list { display: grid; border-top: 1px solid var(--line); }
/* The groups of «Ajustes» («Tú», «Este espacio») and of «Fuentes» («Conectadas» once one is, then the
   categories: «Reuniones», «Calendario»…, in the onboarding too): an H2 over its list, like the groups
   of «Equipo» (.team-section). */
.settings-section, .sources-section { display: grid; gap: var(--s1); }
.settings-section h2, .sources-section h2 { margin: 0; font: 600 14px/20px var(--font-body); color: var(--label); }
.source-row, .setting-row, .team-row {
  display: flex;
  align-items: center;
  gap: 12px;
  min-height: var(--row-h);
  padding: 10px 0;
  border-bottom: 1px solid var(--line);
}
.setting-row { flex-wrap: wrap; }
.source-logo { flex: none; display: grid; place-items: center; width: 20px; height: 20px; color: var(--label-2); }
.source-logo img { width: 20px; height: 20px; object-fit: contain; }
.source-logo .icon { width: 20px; height: 20px; }
.source-text { flex: 1; min-width: 0; display: grid; gap: 2px; }
.source-name { font: var(--row-title); color: var(--label); }
.source-line { font: var(--row-line); color: var(--label-2); overflow-wrap: anywhere; }
/* What went wrong, on the line of a row of the onboarding (a sync that failed, a file that could not go
   up): the red of .err, which the grey above would otherwise keep out. */
.source-line.err { color: var(--danger); }
.source-controls { flex: none; display: flex; align-items: center; gap: var(--s1); }
.connected { display: inline-flex; align-items: center; gap: 6px; font: 500 13px/1 var(--font-body); color: var(--label-2); white-space: nowrap; }
.connected::before { content: ""; width: 6px; height: 6px; border-radius: var(--radius-pill); background: var(--connected); }
/* «Importing…» while the first import of a connection runs (Fase 150, importingChip() in app.js): «Connected» with its dot in
   the lightest grey. */
.importing { display: inline-flex; align-items: center; gap: 6px; font: 500 13px/1 var(--font-body); color: var(--label-2); white-space: nowrap; }
.importing::before { content: ""; width: 6px; height: 6px; border-radius: var(--radius-pill); background: var(--label-3); }
/* «Not available here» — or «Coming soon», for what is not built (Fase 89) —, where the button of a source that cannot be
   connected here would go: grey, like «Conectada». */
.soon { font: 500 13px/1 var(--font-body); color: var(--label-2); white-space: nowrap; }
/* The one anatomy of a row of «Fuentes» (Fase 150, sourceRow() in app.js; docs/assets/screens/SourcesStates.dc.html): on the
   right one column, from the top as the name is — its slot, «Connected», «Importing…», a quiet word or the one button its
   state asks for, with the «···» beside it, and under them, lined up under the slot, when it last brought something, in the
   small type and the lightest grey of a loading line. Never a button beside a chip: one slot. */
.source-row:has(> .source-state) { align-items: flex-start; }
.source-state { flex: none; display: flex; flex-direction: column; align-items: flex-end; gap: 4px; }
.source-status { display: flex; align-items: center; gap: var(--s1); min-height: var(--control-sm); }
.source-when { font: 400 12px/16px var(--font-body); color: var(--label-3); white-space: nowrap; }
.source-status:has(> .icon-btn) + .source-when { padding-right: calc(var(--control-sm) + var(--s1)); }
/* A sub-row of a card of «Fuentes» (Fase 150, rule 5 of the board): an account among others, a list folded behind its row
   (subFold()), a setting — 32px, no fill and no hairline, its words in the type of a line —, with its control in the column
   of the card's controls, under the slot of its row and not under the «···»: the switch of a setting, the chevron of a list,
   the «Reconnect» or the grey «last read» of an account. One vertical to scan. */
.sub-row { display: flex; align-items: center; gap: var(--s1); min-height: var(--control-sm); font: var(--row-line); color: var(--label-2); }
/* The label of a sub-row is never on two lines (Fase 150d; the judge of screens after Fase 150c: Supabase's «Real time» as «Real»
   over «time», narrowed by the long line after it): on one line, as wide as its words whatever follows it, and the labels of a
   card as wide as each other — at least 120px, where the widest of one with a line after it fits, «URL del webhook»; on a phone
   a fifth of the sub-row, where iMessage's «Número», its number and «Copiar» still fit in 360px —, so that their grey lines
   start on one vertical and take the rest of it (.sub-line). */
.sub-label { display: flex; flex: none; align-items: center; gap: var(--s1); white-space: nowrap; color: var(--label); }
.sub-row > .sub-label { min-width: min(120px, 20%); }
.sub-row > .error-line { flex: 1 1 auto; }
.sub-control { flex: none; display: flex; align-items: center; justify-content: flex-end; gap: var(--s1); margin-left: auto; padding-right: calc(var(--control-sm) + var(--s1)); }
.sub-when { font: 400 12px/16px var(--font-body); color: var(--label-3); white-space: nowrap; }
button.sub-fold { width: 100%; padding: 0; border: 0; background: none; text-align: left; cursor: pointer; }
.sub-fold .sub-control .icon { width: 16px; height: 16px; color: var(--label-2); transition: transform var(--t-fast) var(--ease-out); }
.sub-fold[aria-expanded="true"] .sub-control .icon { transform: rotate(180deg); }
@media (hover: hover) and (pointer: fine) {
  .sub-fold:hover .sub-control .icon { color: var(--label); }
}
/* The grey line of a sub-row after its label (Fase 150c): what it reads — «[215] in Quo» —, or an instruction that stays with its
   link at its end — Supabase's «Real time», Calendly's «Webhook URL» —, wrapping before it reaches the column of the controls. */
.sub-line { flex: 1 1 auto; min-width: 0; overflow-wrap: anywhere; }
/* A state in the column of the card's controls, as the right of a row says one (Fase 150c, Supabase's «Real time»): «● Receiving»
   over when the last delivery came, in the small grey of .sub-when. */
.sub-state { display: flex; flex-direction: column; align-items: flex-end; gap: 4px; padding: 4px 0; }
/* A list folded behind a sub-row whose line holds a link (Fase 150c, Quo's «Properties to create»): a button holds no link, so its
   words are the button, whose layer covers the sub-row under the link — a click anywhere else on it folds or unfolds —, and the
   chevron on the right, drawn as .sub-fold's, turns with it. */
.sub-fold-row { position: relative; }
button.sub-fold-label { padding: 0; border: 0; background: none; color: inherit; font: inherit; text-align: left; cursor: pointer; }
button.sub-fold-label::after { content: ""; position: absolute; inset: 0; }
.sub-fold-row > .link { position: relative; z-index: 1; }
.sub-fold-row > .sub-control .icon { width: 16px; height: 16px; color: var(--label-2); transition: transform var(--t-fast) var(--ease-out); }
.sub-fold-row:has(> .sub-fold-label[aria-expanded="true"]) > .sub-control .icon { transform: rotate(180deg); }
@media (hover: hover) and (pointer: fine) {
  .sub-fold-row:hover > .sub-control .icon { color: var(--label); }
}
/* A source with no logo in /landing/logos/ yet: its icon on a light disc of 24 px, in the 20 px of a
   logo with the margin of the Fireflies disc on the dark theme. */
.source-disc { display: grid; place-items: center; width: 24px; height: 24px; margin: -2px; border-radius: 50%; background: var(--fill); }
.source-logo .source-disc .icon { width: 14px; height: 14px; }
/* The iPhone app's row: its own icon (.app-icon) in the room of a disc. */
.source-logo .app-icon { width: 24px; height: 24px; margin: -2px; }
.setting-label { flex: 1; min-width: 0; display: inline-flex; align-items: center; gap: 6px; font: var(--row-title); color: var(--label); }
.setting-value { font: var(--row-line); color: var(--label-2); overflow-wrap: anywhere; }
.help {
  flex: none;
  display: inline-grid;
  place-items: center;
  width: 16px;
  height: 16px;
  padding: 0;
  border: 1px solid var(--line);
  border-radius: var(--radius-pill);
  background: transparent;
  color: var(--label-2);
  font: 600 10px/1 var(--font-body);
  cursor: pointer;
}
.help[aria-expanded="true"] { border-color: var(--label-3); color: var(--label); }
@media (hover: hover) and (pointer: fine) {
  .help:hover { border-color: var(--label-3); color: var(--label); }
}
/* «Tema»: three .btn-sm in a row and the one in use checked (role="radiogroup" in app.js). «Reuniones
   nuevas» of «Equipo» too, whose two are long enough to take a second line on a narrow phone; and
   «Texto | Original» of a document, whose two are tabs (role="tablist"), the one shown selected. */
.segmented { display: flex; flex-wrap: wrap; gap: 4px; }
/* No wider than its row, so that a segmented control in it can take that second line. */
.setting-row > .source-controls { max-width: 100%; }
.segmented .btn { color: var(--label-2); }
.segmented .btn[aria-checked="true"], .segmented .btn[aria-selected="true"] { background: var(--selected); border-color: var(--label-3); color: var(--label); }
/* «Idioma» and «Zona horaria» (Fase 153): the app's .field, as tall as the buttons of the other rows and as wide as its words. */
.setting-row select.field { width: auto; height: var(--control-sm); }
/* You, at the head of «Ajustes» (Fase 71b, personSettings() in app.js): the first row of «Tú», your circle of 48px and
   beside it your name, which a click edits where it is written, over the buttons of your photo and the one line that
   says what went wrong. */
.settings-person { display: flex; align-items: center; gap: var(--s2); padding: var(--s2) 0; border-bottom: 1px solid var(--line); }
.settings-person-text { flex: 1; min-width: 0; display: grid; gap: var(--s1); justify-items: start; }
.settings-name { max-width: 100%; padding: 0; border: 0; background: none; font: 600 16px/24px var(--font-body); color: var(--label); text-align: left; overflow-wrap: anywhere; cursor: text; }
.settings-name-input { width: 100%; height: 24px; padding: 0; margin: 0; border: 0; border-bottom: 2px solid var(--primary); background: transparent; font: 600 16px/24px var(--font-body); color: var(--label); }
.settings-photo { display: flex; flex-wrap: wrap; gap: var(--s1); }
/* While a photo goes up or is taken off (Fase 71c), the circle is dimmed until the server answers. */
.settings-person[aria-busy="true"] > .person-avatar { opacity: 0.4; }
/* «Plan» (Fase 73, planSection() in app.js): a row as those of «Fuentes», without a logo — the plan, a line of what it
   includes and, on Free, how many of the people it is for the team has or, with more, how much of what it remembers the
   space has used (Fase 101): a bar of 4px in the grey of a fill, filled with the colour of the text, over its words.
   «Update card» of a payment that failed is as red as its line. */
.plan-meter { display: grid; gap: 6px; padding-top: 4px; }
.plan-meter-bar { display: block; width: 100%; max-width: 240px; height: 4px; border-radius: var(--radius-pill); background: var(--fill); overflow: hidden; }
.plan-meter-fill { display: block; height: 100%; border-radius: inherit; background: var(--label); }
.source-line.err .link { color: inherit; }
/* Why a team on Free does not remember everything, over the list and under an answer (Fase 73, Fase 101, planLine() in
   app.js), and who Free is for, under the box that invites: one line of footnote grey, whose «Upgrade» is a link apart
   from the words (Fase 94). */
.plan-line { margin: 0; font: var(--footnote); color: var(--label-2); }
.timeline-inner > .plan-line { padding: 0 var(--s1); }

/* «Equipo»: the members, the box that invites, the invitations waiting and «Salir del espacio».
   Each row is avatar · who · what, grey, and the «···» (.team-row shares .source-row's line). */
.page h1.editable { cursor: text; }
.team-section { display: grid; gap: var(--s1); }
.team-section h2 { margin: 0; font: 600 14px/20px var(--font-body); color: var(--label); }
.team-name { flex: 1; min-width: 0; font: var(--row-title); color: var(--label); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.team-role { font: var(--row-line); color: var(--label-2); white-space: nowrap; }
/* A number of the space's chats that is a member's (Fase 81, memberNumbers() in app.js): under their row and lined up
   with their name — past the 24px of their face and the 12px after it —, the number whole in grey, and «Remove». */
.team-number { min-height: 0; padding: 6px 0 6px 36px; }
.team-number-label { flex: 1; min-width: 0; font: var(--row-line); font-variant-numeric: tabular-nums; color: var(--label-2); }
/* An invitation nobody has accepted: the outline of an avatar. */
.avatar.pending { border: 1px dashed var(--label-3); color: var(--label-2); }
.invite-form { display: grid; gap: var(--s1); }
.invite-field { display: flex; gap: var(--s1); }
.invite-field .field { flex: 1; min-width: 0; }
.invite-field .btn { height: 36px; }
.leave { padding: 0; border: 0; background: none; color: var(--danger); font: var(--row-title); cursor: pointer; }
@media (hover: hover) and (pointer: fine) {
  .leave:hover { text-decoration: underline; text-underline-offset: 2px; }
}

/* What's new (Fase 59; as notifications since Fase 66, whatsNewPage() in app.js): a head as small as the toolbar of an
   inbox — its title in 15px of the body type and not the big title of a page, the number of what is new on it as the
   pill of its row in the rail, and its «···» on the right —, then what came in, in three sections, flat (Fase 69b):
   «Decisions», «New entries» and «Pages», each under a heading of its own — its icon of 14px, then its name in small
   capitals of 11px in the lightest grey, with the air of a day heading of the list, 16px over it and 4px under it —
   and its rows right under it: a row each as dense as a row of the list, 36px: the dot of the accent on the left while
   it is new, who by their faces of 20px in the tints the list paints them with, one over the other as there (Fase 69)
   — the icon of a page's kind on a quiet fill —, one line of 14px and no bold cut at its end — what was done in the
   middle grey of the theme, then what, in the colour of the text: no names, the faces say who —, and when on the right
   in the lightest grey. The decisions under the line of the conversation they come from (Fase 82, .news-conv below),
   each a row of 30px set in under its title — or by topic or by person, on the tabs under the head (Fase 87, .news-tabs
   below). No card, no big title, no row of settings. A request to see an entry of
   yours has «Allow» and «Decline» where the hour goes (Fase 68); a decision has its × «Not for me» on the right while
   the pointer is on its row, as the actions of a row of the list, and always on a screen without a pointer. */
.news-page { gap: var(--s2); }
.news-head { display: flex; align-items: center; gap: var(--s1); min-height: var(--control-sm); }
.news-head h1 { font: 600 15px/20px var(--font-body); letter-spacing: normal; }
.news-head .nav-badge { margin-left: 0; }
.news-menu { margin-left: auto; }
.news { display: grid; }
/* The heading of a section, a .day of the list for the live panel (newsSection() in app.js): the first has the gap of the
   page over it, which is its 16px. */
.news > .news-section { display: flex; align-items: center; gap: 6px; padding: var(--s2) 20px 4px; font: 500 11px/16px var(--font-body); letter-spacing: 0.06em; text-transform: uppercase; color: var(--label-3); }
.news > .news-section:first-child { padding-top: 0; }
.news-section .icon { width: 14px; height: 14px; }
/* The ring that cuts each face out of the one before (.avatar-stack): the background the row is on at the time. Which is
   the pane's, as a row of the list is on the rail's (Fase 70): one sliding to its new place covers what came in under it. */
.news-row { --ring: var(--surface); position: relative; display: flex; align-items: center; gap: var(--s1); border-radius: var(--radius); background: var(--surface); }
/* Its faces, its line and its hour on one line of 20px, each in a column of its own: the line takes what is left. */
.news-main {
  position: relative;
  flex: 1;
  min-width: 0;
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  align-items: center;
  column-gap: 10px;
  min-height: 36px;
  padding: 8px 10px 8px 20px;
  color: inherit;
  text-decoration: none;
}
.news-main:hover { text-decoration: none; }
/* On the axis of its line, 8px + 10px down. */
.news-new { position: absolute; top: 18px; left: 7px; width: 6px; height: 6px; margin-top: -3px; border-radius: var(--radius-pill); background: var(--tint); }
.news-face { flex: none; display: flex; align-items: center; justify-content: center; min-width: 20px; height: 20px; border-radius: var(--radius-pill); }
.news-face:has(> .icon) { background: var(--fill); color: var(--label-2); }
.news-face > .icon { width: 12px; height: 12px; }
.news-text { flex: 1; min-width: 0; font: 400 14px/20px var(--font-body); color: var(--label); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.news-verb { color: var(--label-2); }
/* The name of a key in a row of «Keys» (Fase 84b, keyNewsRow() in app.js): in mono, a size under the line it is in. */
.news-key { font: 500 13px/20px var(--font-mono); }
.news-time { flex: none; font: var(--row-time); font-variant-numeric: tabular-nums; color: var(--label-3); white-space: nowrap; grid-column: 3; }
/* On the right of its line, 28px centred on its 20px. */
.news-dismiss { position: absolute; top: 4px; right: 4px; width: 28px; height: 28px; background: var(--surface); opacity: 0; pointer-events: none; }
.news-dismiss:focus-visible { opacity: 1; pointer-events: auto; }
.request-row .news-main { padding-right: 0; }
.request-row .source-controls { padding-right: 4px; }
/* A conversation over its decisions (Fase 82, conversationLine() in app.js): a line, not a row — no fill, no box, no
   pointer —: its title alone since Fase 87, no icon of its source, in 500 13px/20px in the middle grey, and on the right
   the hour of its newest decision, lined up with the rows' hours. The first right under its heading; the others under a
   hairline, with 6px of air. On the background of the page, as a day heading is, so that it covers what came in under it
   while it slides (Fase 70). Its decisions under it, each a row of 30px set in 28px, as they were: their faces of 16px,
   and what was decided. */
.news-conv { display: flex; align-items: center; gap: var(--s1); margin: 0 10px 0 20px; padding-top: 6px; border-top: 1px solid var(--line); background: var(--surface); }
.news-section + .news-conv { padding-top: 0; border-top: 0; }
.news-conv-title { flex: 1; min-width: 0; font: 500 13px/20px var(--font-body); color: var(--label-2); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.news-decision { margin-left: 28px; }
.news-decision .news-main { column-gap: var(--s1); min-height: 30px; padding-top: 5px; padding-bottom: 5px; }
.news-decision .news-face { min-width: 16px; height: 16px; }
.news-decision .news-face > .icon { width: 10px; height: 10px; }
.news-decision .news-dismiss { top: 1px; }
/* A note for you (Fase 115, mentionRow() in app.js), «For you» on top of What's new and of Ask's Today: a row of What's new;
   while you have not seen it, the dot, its title in 600 and on its right its ✓ «Seen», an icon alone of 20px with its check
   of 14px, 10px from the edge — a thumb's 40px on a phone, as every icon alone. «Notes for Daniel» of a page has the title of
   one not seen in 600 too. */
.mention-unseen .news-main { padding-right: var(--s1); }
.mention-unseen .news-text, .mention-unseen .page-entry-title { font-weight: 600; }
.mention-seen { width: 20px; height: 20px; margin-right: 10px; }
.mention-seen .icon { width: 14px; height: 14px; }
@media (hover: hover) and (pointer: fine) {
  .news-row:hover { --ring: var(--fill); background: var(--fill); }
  .news-row:hover .news-dismiss { opacity: 1; pointer-events: auto; background: var(--fill); }
  .news-row:hover:has(.news-dismiss) .news-time, .news-row:has(.news-dismiss:focus-visible) .news-time { visibility: hidden; }
}
@media (hover: none) {
  .news-dismiss { position: static; align-self: flex-start; margin-top: 4px; background: transparent; opacity: 1; pointer-events: auto; }
  .news-decision .news-dismiss { margin-top: 1px; }
}
/* The brief of What's new (Fase 82b, newsBriefBox() in app.js), over its sections when three decisions or more are new:
   on the quiet fill of the theme, 10px round, the sentences the AI wrote of them, one a line, 8px apart — each on two
   columns, the faces of 18px of who took its decisions in a column of their own, on its right and on the axis of the
   first line of 24px (3px down), however many lines the sentence wraps to; the sentence in 15px of the colour of the
   text, its first words in 600 —; while they are on their way, the three lines of a skeleton, of the colour of the page
   so that they show on the fill. Under it, one line of 13px in the middle grey: how many, from how many conversations and
   since when, 12px apart and since when in the lightest grey (Fase 94), and «Ask about this» on its right. On a phone it
   runs from edge to edge, its words where the page's are. */
.news-brief-box { display: grid; gap: var(--s1); }
.news-brief { --ring: var(--fill); display: grid; gap: 8px; padding: 14px 16px; border-radius: 10px; background: var(--fill); }
.news-brief-line { display: grid; grid-template-columns: 44px 1fr; column-gap: 10px; }
.news-brief-faces { display: flex; justify-content: flex-end; align-self: start; padding-top: 3px; }
.news-brief-text { min-width: 0; margin: 0; font: 400 15px/24px var(--font-body); color: var(--label); overflow-wrap: anywhere; }
.news-brief-lead { font-weight: 600; }
.news-brief .sk-line { background-image: linear-gradient(90deg, var(--surface) 0%, var(--line) 40%, var(--surface) 80%); }
.news-brief-foot { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; column-gap: var(--s2); font: 500 13px/20px var(--font-body); color: var(--label-2); }
.news-brief-counts > .apart + .apart { margin-left: 12px; }
.news-brief-since { color: var(--label-3); }
.news-brief-ask { color: inherit; white-space: nowrap; }
@media (hover: hover) and (pointer: fine) {
  .news-brief-ask:hover { color: var(--label); }
}
/* The tabs of the views of its decisions (Fase 87, newsTabs() in app.js), right under the head of What's new: text as
   Linear's, 500 13px/20px, 24px tall, no fill — the one on in the colour of the text over a line of 2px of the accent,
   the others in the middle grey. Since Fase 94 in a row with «Expand all» on their right (.news-bar, newsExpand()), a
   button of text in 500 12px of the middle grey, the colour of the text under the pointer. */
.news-tabs { display: flex; gap: var(--s2); margin-top: calc(var(--s1) * -1); }
.news-tab { height: 24px; padding: 0; border: 0; background: none; font: 500 13px/20px var(--font-body); color: var(--label-2); box-shadow: inset 0 -2px 0 transparent; cursor: pointer; }
.news-tab[aria-selected="true"] { color: var(--label); box-shadow: inset 0 -2px 0 var(--tint); }
.news-bar { display: flex; align-items: center; justify-content: space-between; gap: var(--s2); margin-top: calc(var(--s1) * -1); }
.news-bar > .news-tabs { margin-top: 0; }
.news-expand { flex: none; height: 24px; padding: 0; border: 0; background: none; font: 500 12px/20px var(--font-body); color: var(--label-2); cursor: pointer; }
@media (hover: hover) and (pointer: fine) {
  .news-tab:hover { color: var(--label); }
  .news-expand:hover { color: var(--label); }
}
/* «Previous» (Fase 87, previousRows() in app.js), after what is new in «Conversations», the last of its section: one row
   as wide as the page, 36px, on the quiet fill, 8px round, its words in 500 13px/20px of the colour of the text with its
   number in a chip (Fase 94) — on the page's colour, as the row is on the quiet fill — and its chevron on the right,
   turned up while what came before is open under it — its lines and rows as the ones over it, the first with no hairline. */
.news-previous { display: flex; align-items: center; justify-content: space-between; gap: var(--s1); width: 100%; height: 36px; margin-top: var(--s1); padding: 0 12px; border: 0; border-radius: var(--radius-md); background: var(--fill); font: 500 13px/20px var(--font-body); color: var(--label); cursor: pointer; }
.news-previous-label { display: flex; align-items: center; gap: var(--s1); min-width: 0; }
.news-previous .count-chip { background: var(--surface); }
.news-previous .icon { width: 16px; height: 16px; color: var(--label-2); transition: transform var(--t-fast) var(--ease-out); }
.news-previous[aria-expanded="true"] .icon { transform: rotate(180deg); }
.news-previous-list { display: grid; padding-top: var(--s1); }
.news-previous-list > .news-conv:first-child { padding-top: 0; border-top: 0; }
@media (hover: hover) and (pointer: fine) {
  .news-previous:hover { background: color-mix(in srgb, var(--label) 6%, var(--fill)); }
}
/* What the others added together (Fase 152, entryBurstRows() in app.js): one line of «New entries», a button where the others
   have a link — its number in a grey chip on the line of its words —, and what it unfolds under it, a step of 20px in. */
button.news-main { width: 100%; border: 0; background: none; font: inherit; text-align: left; cursor: pointer; }
.news-burst .count-chip { vertical-align: top; }
.news-burst-list { display: grid; padding-left: 20px; }
/* «Topics» (Fase 87, topicsBlock() in app.js): a card each with no border, a hairline between two — its title in 600
   15px of the colour of the text with the faces of 18px of who took its decisions on the right, its sentences in 400
   14px/22px, and under them in the lightest grey how many decisions from how many conversations —, all of it a button
   that opens its decisions under it as plain lines of 30px, their faces of 16px, what was decided and when. Its words
   where the rows have theirs, 20px in; three grey lines while it is on its way. */
.news-topics { display: grid; }
.news-topics > :not(.news-topic) { margin: 0 10px 0 20px; }
/* Topics that did not come (Fase 95): the block of a view that did not load, centred where the cards would be; and the
   line of an answer with none, with its «Retry». */
.news-topics > .error-block { margin: var(--s4) auto; }
.news-topics > .error-row { margin-bottom: var(--s1); }
.news-topic + .news-topic { border-top: 1px solid var(--line); }
.news-topic-head { --ring: var(--surface); display: grid; gap: 4px; width: 100%; padding: 12px 10px 12px 20px; border: 0; border-radius: var(--radius); background: var(--surface); color: inherit; font: inherit; text-align: left; cursor: pointer; }
.news-topic-top { display: flex; align-items: center; gap: var(--s1); }
.news-topic-title { flex: 1; min-width: 0; font: 600 15px/20px var(--font-body); color: var(--label); }
.news-topic-faces { flex: none; display: flex; }
.news-topic-text { font: 400 14px/22px var(--font-body); color: var(--label); overflow-wrap: anywhere; }
.news-topic-counts { font: 400 12px/16px var(--font-body); color: var(--label-3); }
.news-topic-lines { display: grid; padding-bottom: var(--s1); }
.news-topic-line .news-main { column-gap: var(--s1); min-height: 30px; padding-top: 5px; padding-bottom: 5px; }
.news-topic-line .news-face { min-width: 16px; height: 16px; }
.news-topic-line .news-face > .icon { width: 10px; height: 10px; }
@media (hover: hover) and (pointer: fine) {
  .news-topic-head:hover { --ring: var(--fill); background: var(--fill); }
}
/* «People» (Fase 87, personBlock() in app.js): a block each, headed as a conversation is — a hairline and 10px of air
   over all but the first — by their face of 24px, their name in 600 14px and how many decisions in a grey chip (Fase 94,
   .count-chip); under it its decisions, lines of 30px set in under the name, what was decided and when, and «+7 more» in
   the lightest grey where the rest open. «Team», the decisions that name nobody, by the icon of a team on the quiet fill.
   Somebody no member is has «This is…» at the right end of their head (Fase 92), the tag of «Name» (.name-btn). */
.news-person { display: grid; }
.news-person-head { display: flex; align-items: center; gap: var(--s1); margin: 0 10px 0 20px; padding: 10px 0 4px; border-top: 1px solid var(--line); }
.news-section + .news-person > .news-person-head { padding-top: 0; border-top: 0; }
.news-person-face { flex: none; display: grid; place-items: center; width: 24px; height: 24px; border-radius: var(--radius-pill); background: var(--fill); color: var(--label-2); }
.news-person-face .icon { width: 14px; height: 14px; }
.news-person-name { min-width: 0; font: 600 14px/20px var(--font-body); color: var(--label); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.news-person-head > .name-btn { flex: none; margin-left: auto; }
.news-person-line { margin-left: 32px; }
.news-person-line .news-main { grid-template-columns: minmax(0, 1fr) auto; min-height: 30px; padding-top: 5px; padding-bottom: 5px; }
.news-person-line .news-time { grid-column: 2; }
.news-more { justify-self: start; height: 28px; margin-left: 52px; padding: 0; border: 0; background: none; font: 500 13px/20px var(--font-body); color: var(--label-3); cursor: pointer; }
@media (hover: hover) and (pointer: fine) {
  .news-more:hover { color: var(--label-2); }
}

/* «Tasks» (Fase 86, tasksPage() in app.js), with the pieces of What's new: its head — «Tasks» and how many in a grey chip
   (Fase 94, .count-chip) —, its tabs, and a row a task: its box and what is to be done, in the colour of the text; ticked,
   struck through in the lightest grey (.task-list above). «Team» by whom they are for: a face, the name and its chip, and
   the rows under the name, «+3 more». The rows are Today's too (todayTasks() in app.js), 20px in there, where its other
   rows are. */
.tasks-list { display: grid; --task-indent: 26px; }
.task-row { display: flex; align-items: center; min-height: 32px; padding-left: 20px; border-radius: var(--radius); }
.task-row .task-check { height: 32px; }
.task-main { flex: 1; min-width: 0; display: flex; align-items: center; gap: var(--s1); align-self: stretch; padding: 0 10px; color: inherit; text-decoration: none; }
.task-main:hover { text-decoration: none; }
.task-row .task-text { flex: 1; min-width: 0; font: 400 14px/20px var(--font-body); color: var(--label); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.tasks-team > .news-person:first-child > .news-person-head { padding-top: 0; border-top: 0; }
@media (hover: hover) and (pointer: fine) {
  .task-row:hover { background: var(--fill); }
}
/* A to-do (Fase 164, toDoRows() in app.js), as What's new has its decisions (.news-conv, .news-decision): the line of each
   conversation — What's new's own, its title in 500 13px of the middle grey and when it happened on its right, the first
   right under what heads it and the others under a hairline — and under it its tasks, rows of 30px set in by one indent:
   the box, the face of 16px of whose it is when it is not mine, the task in 400 14px of the colour of the text and, on the
   right, when it is due. No second line. Under a to-do, «Closed by Company today» and «Earlier», rows of «Previous», and
   what they open (.tasks-fold): a task Company closed today is a row of 30px too, a ✓ where the box goes, its words struck
   through and the sentence that closed it in 12px of the middle grey, cut at its end. One indent is --task-indent, 26px. */
.task-todo, .task-closed-today { min-height: 30px; }
.task-todo { margin-left: 26px; }
.task-todo .task-check { height: 30px; }
.task-face { flex: none; display: flex; }
.task-quote { flex: none; max-width: 45%; font: 400 12px/20px var(--font-body); color: var(--label-2); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.tasks-fold { display: grid; padding-top: var(--s1); }
.tasks-list > .news-conv:first-child, .tasks-fold > .news-conv:first-child, .news-person-head + .news-conv, .today-heading + .news-conv { padding-top: 0; border-top: 0; }
/* The column of «Tasks» is its title's and its tabs' (Fase 106; Manu, 2026-10-05: «la página empieza muy a la derecha»),
   by one indent, --task-indent of .tasks-list: the box of a row on the left edge of the page, under the T of «Tasks», and
   its words 10px from it — the box of 16px and the 10px, 26px —; under the pointer the fill of the row comes 8px out of
   the column, so that the box is not on its edge. A row with no box has its words there all the same («Waiting on»,
   .task-row.waiting below); one Company closed today has its ✓ where the box goes, as big as it. In «Team» a person is on
   the edge — their face of 18px and the 8px after it: their name where the words of a task are —. Since Fase 164 the rows of
   a to-do are one indent in from the line of their conversation (below); «Closed by Company today» and «Earlier» are rows
   of «Me», on the edge, and a person's «Earlier» starts where their name does, as wide as the rest of the column. */
.tasks-list .task-row { margin-left: calc(var(--s1) * -1); padding-left: var(--s1); }
.tasks-list .task-check, .tasks-list .task-mark { width: var(--task-indent); justify-items: start; }
.tasks-list .task-mark .icon { width: 16px; height: 16px; }
.tasks-list .task-main { padding-left: 0; }
.tasks-team .news-person-head { margin-left: 0; }
.tasks-team .news-person-face { width: 18px; height: 18px; }
.tasks-team .news-person-face .icon { width: 12px; height: 12px; }
.tasks-team .task-row { margin-left: calc(var(--task-indent) - var(--s1)); }
.tasks-team .news-previous { width: calc(100% - var(--task-indent)); margin-left: var(--task-indent); }
/* A to-do on «Tasks» (Fase 164): the line of a conversation on the edge of the column — in «Team», one indent in, under the
   name of its person — and its tasks one indent further in: the box under the first letter of its title, as a decision's
   faces are under it. */
.tasks-list .news-conv { margin-left: 0; }
.tasks-team .news-conv { margin-left: var(--task-indent); }
.tasks-list .task-todo { margin-left: calc(var(--task-indent) - var(--s1)); }
.tasks-team .task-todo { margin-left: calc(var(--task-indent) * 2 - var(--s1)); }
.tasks-team .news-more { margin-left: calc(var(--task-indent) * 3); }
/* The life of a task (Fase 97, toDoRow() in app.js since Fase 164). Closed — done or dismissed — it is struck through in the
   lightest grey by its data-status, as a box ticked strikes it (.task-list above), wherever it is. An open one has its ×
   «Dismiss» on its right, 24px in the lightest grey, while the pointer is on it — always on a screen without one —; one that
   waits on somebody no member is, no box — its words where the others have theirs — and «Done» and «Dismiss» on its right
   under the pointer: words of 12px in the middle grey (.task-action). */
.task:not([data-status="open"]) .task-text, .task-row:not([data-status="open"]) .task-text { color: var(--label-3); text-decoration: line-through; }
.task-dismiss { width: 24px; height: 24px; color: var(--label-3); visibility: hidden; }
.task-dismiss .icon { width: 14px; height: 14px; }
.task > .task-dismiss { margin-left: auto; }
.task-row > .task-dismiss { margin-right: 4px; }
.task:not([data-status="open"]) .task-dismiss, .task-row:not([data-status="open"]) .task-dismiss { display: none; }
.task-mark { flex: none; display: grid; place-items: center; width: 20px; color: var(--label-3); }
.task-mark .icon { width: 14px; height: 14px; }
.task-actions { flex: none; display: flex; gap: 12px; padding-right: 10px; visibility: hidden; }
.task-action { padding: 0; border: 0; background: none; font: 500 12px/20px var(--font-body); color: var(--label-2); cursor: pointer; }
.tasks-list .task-row.waiting { padding-left: calc(var(--s1) + var(--task-indent)); }
.task-row.waiting:not([data-status="open"]) .task-actions { display: none; }
.task-dismiss:focus-visible, .task-actions:focus-within { visibility: visible; }
@media (hover: hover) and (pointer: fine) {
  .task:hover .task-dismiss, .task-row:hover .task-dismiss, .task-row:hover .task-actions { visibility: visible; }
  .task-action:hover { color: var(--label); }
}
@media (hover: none) {
  .task-dismiss, .task-actions { visibility: visible; }
}
/* When a task is due (Fase 107, dueTag() in app.js), right of all on its row and always there: 12px in the middle grey —
   «Today», «Tonight», «Tomorrow», «Mon», «Oct 7» —, and in the lightest once it is over, «Was due Mon»: never red. Gone,
   with its ×, once the task is closed. Since Fase 164 only where somebody said when. */
.task-due { flex: none; font: 400 12px/20px var(--font-body); color: var(--label-2); white-space: nowrap; }
.task-due.past { color: var(--label-3); }
.task-row:not([data-status="open"]) .task-due { display: none; }
/* «Undo» of a task Company closed today (Fase 164, closedTodayRow() in app.js), on the right of its row: words of 12px in the
   middle grey (.task-action), always there while it may be undone. */
.task-undo { flex: none; padding-right: 10px; }
/* A small heading of «Tasks» (Fase 97, tasksHeading() in app.js), «Waiting on»: its words in 500 12px of the middle grey on
   the edge of the column, where the boxes are (Fase 106), and how many in a grey chip. In «Team» it parts what waits on
   others from the members with the hairline of a person, and the person right under it has none. */
.tasks-heading { display: flex; align-items: center; gap: var(--s1); padding: 12px 10px 4px 0; font: 500 12px/20px var(--font-body); color: var(--label-2); }
.tasks-team > .tasks-heading { margin-top: var(--s1); padding-top: 10px; border-top: 1px solid var(--line); }
.tasks-heading + .news-person > .news-person-head { padding-top: 0; border-top: 0; }

/* The page of a task (Fase 114d, taskPageView() in app.js), as Linear's issue and Things' to-do: the head of an entry — the icon
   of «Tasks», its words as the title, «Why?» on its right —, and under the title one line of what it is to, things apart: whose
   it is by their face of 16px, the leads and the projects it is linked to as the chips of an entry, and when it is due with
   where that comes from in the lightest grey. «Why?» opens a flat panel under the head, on the quiet fill, with what the pass
   of evidence read in mono. Its history is a list, a line of 32px an event: how long ago in the lightest grey on the left, in a
   column of its own, as the rows of the list say their hour; the face of 16px of whoever did it or the icon of what happened;
   and what happened — the entry it was said in, the sentence between quotes in the middle grey, and in the lightest grey where
   a date came from or the class of what was weighed —, cut at its end. The tokens of either theme. */
.task-view .detail-title h1 { cursor: default; }
.task-facts { display: flex; align-items: center; flex-wrap: wrap; margin-top: 6px; font: var(--meta); color: var(--label-2); }
.task-fact { display: inline-flex; align-items: center; gap: 6px; min-width: 0; }
.task-fact .icon { width: 14px; height: 14px; color: var(--label-3); }
.task-fact-source { color: var(--label-3); }
.task-facts .entity-chip { vertical-align: middle; }
.task-why { padding: 12px 14px; border-radius: var(--radius-md); background: var(--fill); }
.task-why-text { margin: 0; font: 400 12px/18px var(--font-mono); color: var(--label-2); white-space: pre-wrap; overflow-wrap: anywhere; }
.story { display: grid; margin: 0; padding: 0; list-style: none; }
.story-row { display: flex; align-items: center; gap: 10px; min-height: 32px; font: 400 14px/20px var(--font-body); color: var(--label); }
.story-when { flex: none; width: 88px; font: 400 12px/20px var(--font-body); font-variant-numeric: tabular-nums; color: var(--label-3); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.story-mark { flex: none; display: grid; place-items: center; width: 16px; height: 16px; color: var(--label-3); }
.story-mark .icon { width: 14px; height: 14px; }
.story-text { flex: 1; min-width: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
.story-text a { color: inherit; }
.story-quote { color: var(--label-2); }
.story-class { font-size: 12px; color: var(--label-3); }

/* Pages (Fase 61, «Pages» in app.js). What an entry names, as quiet chips under its head (entityChips()): a face of 16px
   for a member, the icon of its kind in the grey of the hours for anything else, and its name, in a pill with the
   hairline of the chips over the list; the pointer on one fills it. */
.entity-chips { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 12px; }
.entity-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  max-width: 240px;
  height: 24px;
  padding: 0 8px 0 6px;
  border: 1px solid var(--line);
  border-radius: var(--radius-pill);
  color: var(--label-2);
  font: 500 12px/1 var(--font-body);
  text-decoration: none;
}
.entity-chip:hover { text-decoration: none; }
.entity-chip .icon { width: 14px; height: 14px; color: var(--label-3); }
.entity-chip-name { min-width: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
.person-avatar.face-16 { width: 16px; height: 16px; font-size: 7px; }
/* «Pages» (pagesView()): an entity a row, in the line of the rows of «Fuentes» — its face or icon, its name, and under it
   what it is, how many entries name it and the day of the latest —, with the dot of the accent while its page changed
   since your last visit. The pages a search found go over its entries in the rail (foundPages()): links drawn as the rows
   of the list — the same box, the same two lines —, but none of them, and left as they are by a selection. */
.page-row { display: flex; align-items: center; gap: 12px; min-height: var(--row-h); padding: 10px 0; border-bottom: 1px solid var(--line); color: inherit; text-decoration: none; }
.page-row:hover { text-decoration: none; }
.page-row-icon { flex: none; display: grid; place-items: center; width: 20px; height: 20px; color: var(--label-2); }
.page-row-text { flex: 1; min-width: 0; display: grid; gap: 2px; }
.page-row-name, .page-row-line { min-width: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
.page-row-name { font: var(--row-title); color: var(--label); }
.page-row-line { font: var(--row-line); color: var(--label-2); }
.page-row-new { flex: none; width: 6px; height: 6px; border-radius: var(--radius-pill); background: var(--tint); }
/* A dashboard on the web (Fase 133, dashboardRow() in app.js): the globe of its «Visible to» on the right of its row,
   16px in the grey of its icon. */
.page-row-web { flex: none; display: grid; place-items: center; width: 16px; height: 16px; color: var(--label-2); }
.page-row-web .icon { width: 16px; height: 16px; }
.page-hit {
  display: grid;
  grid-template-columns: var(--row-icon) minmax(0, 1fr);
  column-gap: 10px;
  align-items: start;
  min-height: var(--row-h);
  padding: var(--row-pad);
  border-radius: var(--radius);
  color: inherit;
  text-decoration: none;
}
.page-hit:hover { text-decoration: none; }
.app.selecting .page-hit .row-icon { display: grid; }
/* The search and the chips of «Pages» (Fase 76, pagesView()): the box of the list's search and its pills, in the tokens of
   either theme, under the title — 8px closer to it than the list is, as the tabs of «Fuentes» — and the chips 8px under the
   box, lined up on the left with it and with the rows. No ⌘K in the box, and no room kept for it: the cursor goes in it.
   The 4px around the chips are the room their focus ring needs inside the box that scrolls, which its margin takes back.
   Under them the rows, or the one line, and 8px under those why the server's search failed (pagesListed()). */
.pages-filter { display: grid; gap: var(--s1); margin-top: calc(var(--s1) * -1); }
.pages-filter .search { padding: 0; }
.pages-filter .search input { padding-right: 12px; }
.pages-filter .type-filter-scroll { margin: -4px; }
.pages-filter .type-filter { justify-content: flex-start; padding: 4px; }
.pages-list { display: grid; gap: var(--s1); }
/* The page of an entity (entityPageView()): the head of an entry, whose name is not one to edit; the page; «What changed»
   with its tabs on the right of its title, or the one there is in grey; and the entries that name it, a line each. */
.entity-view .detail-title h1 { cursor: default; }
.what-changed-head { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: var(--s1); }
.what-changed-since { font: var(--meta); color: var(--label-2); }
.page-entry { display: flex; align-items: center; gap: 12px; min-height: 40px; padding: 8px 0; border-bottom: 1px solid var(--line); color: var(--label); text-decoration: none; }
.page-entry:hover { text-decoration: none; }
.page-entry-icon { flex: none; display: grid; place-items: center; width: 16px; height: 16px; color: var(--label-2); }
.page-entry-icon .icon { width: 16px; height: 16px; }
.page-entry-title { flex: 1; min-width: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; font: var(--row-title); }
.page-entry-day { flex: none; font: var(--row-line); color: var(--label-3); white-space: nowrap; }
/* What changed between two versions of a page (changesView()): what went struck through
   in soft grey, what came on a soft green — the green of a connected source faded into the page, which makes it soft on
   the light theme and on the dark one alike —, no red and no signs; a sentence that changed one word whole, with that
   word so. The label of a section, in grey. */
.diff .diff-label { margin: 6px 0 0; font: 600 13px/20px var(--font-body); color: var(--label-2); }
.diff-gone { color: var(--label-2); text-decoration: line-through; text-decoration-color: var(--label-3); }
.diff-new {
  padding: 0 2px;
  border-radius: 3px;
  background: color-mix(in srgb, var(--connected) 16%, var(--surface));
  color: var(--label);
  text-decoration: none;
  -webkit-box-decoration-break: clone;
  box-decoration-break: clone;
}
@media (hover: hover) and (pointer: fine) {
  .entity-chip:hover, .page-hit:hover { background: var(--fill); color: var(--label); }
  .page-row:hover .page-row-name, .page-entry:hover .page-entry-title { text-decoration: underline; text-underline-offset: 2px; text-decoration-color: var(--label-3); }
}
/* «Leads» (Fase 104, leadsPage() in app.js): the second tab of «Pages», under the tabs of What's new (.news-tabs) and the box
   of its search (.pages-filter): a table as wide as its columns need, which scrolls sideways where the page is narrower. Its
   columns named in 500 12px of the middle grey over a hairline; a group per stage, its name in 600 13px with how many and what
   they are worth in grey chips (.count-chip, Fase 94), 12px over it; a lead a row of 36px over a hairline — its name in the
   colour of the text, the way to its page; its company, its value and its days in 13px of the middle grey; its stage a grey
   chip, on the soft red of --danger for one lost or not a fit; the face of 18px of who has it; the next step and its day,
   cut at its end. The tokens of either theme, and no colour of its own. */
.leads-list { display: grid; gap: var(--s1); }
.leads-scroll { overflow-x: auto; }
.leads-table { width: 100%; min-width: 640px; border-collapse: collapse; }
.leads-table th, .leads-table td { padding: 0 12px 0 0; text-align: left; white-space: nowrap; vertical-align: middle; }
.leads-table thead th { height: 28px; border-bottom: 1px solid var(--line); font: 500 12px/16px var(--font-body); color: var(--label-2); }
.leads-group-head th { height: 44px; padding-top: 12px; font: 600 13px/20px var(--font-body); color: var(--label); }
.leads-group-head .count-chip { margin-left: var(--s1); vertical-align: top; }
.lead-row { height: 36px; border-bottom: 1px solid var(--line); }
.lead-row td { font: var(--row-line); color: var(--label-2); }
.lead-name, .lead-company, .lead-next { max-width: 200px; overflow: hidden; text-overflow: ellipsis; }
.lead-name a { font: var(--row-title); color: var(--label); text-decoration: none; }
.lead-owner .person-avatar { display: block; }
.lead-stage {
  display: inline-block;
  height: 20px;
  padding: 0 8px;
  border-radius: var(--radius-pill);
  background: var(--fill);
  color: var(--label-2);
  font: 500 12px/20px var(--font-body);
  white-space: nowrap;
}
.lead-stage[data-stage="lost"], .lead-stage[data-stage="not_fit"] { background: color-mix(in srgb, var(--danger) 12%, transparent); color: var(--danger); }
/* The card of a lead on top of the page of its entity (leadCard() in app.js): a hairline round it, 8px round, a field a line
   of 40px over a hairline — its name on the left in 13px of the middle grey, 120px wide, and on its right the stage as its
   chip, 24px, with a chevron that opens the stages; the value in a box of numbers of 32px, with no arrows, and its period
   beside it; who has it by their face of 18px and their name; the next step with its day. Its history under it is a
   section of the page, a line each change as the entries that name it are (.page-entry). */
.lead-card { padding: 0 16px; border: 1px solid var(--line); border-radius: var(--radius-md); }
.lead-fields { display: grid; margin: 0; }
.lead-field { display: grid; grid-template-columns: 120px minmax(0, 1fr); column-gap: var(--s2); align-items: center; min-height: 40px; }
.lead-field + .lead-field { border-top: 1px solid var(--line); }
.lead-field dt { font: var(--row-line); color: var(--label-2); }
.lead-field dd { display: flex; align-items: center; gap: var(--s1); min-width: 0; margin: 0; font: var(--row-line); color: var(--label); }
.lead-stage-pick { position: relative; display: inline-flex; align-items: center; }
.lead-stage-select { -webkit-appearance: none; appearance: none; height: 24px; padding: 0 24px 0 10px; border: 0; font: 500 12px/24px var(--font-body); cursor: pointer; }
.lead-stage-select:focus-visible { outline: 2px solid var(--tint); outline-offset: 2px; }
.lead-stage-pick .icon { position: absolute; right: 7px; width: 12px; height: 12px; color: var(--label-3); pointer-events: none; }
.lead-value-edit { display: flex; align-items: center; gap: var(--s1); }
.lead-amount { width: 140px; height: var(--control-sm); -moz-appearance: textfield; appearance: textfield; }
.lead-amount::-webkit-inner-spin-button, .lead-amount::-webkit-outer-spin-button { -webkit-appearance: none; margin: 0; }
.lead-period { width: auto; height: var(--control-sm); }
/* The title of the entry a change of the history says so in, apart after what it says: in the lightest grey, as a task's. */
.lead-event .apart + .apart { color: var(--label-3); }
@media (hover: hover) and (pointer: fine) {
  .lead-name a:hover { text-decoration: underline; text-underline-offset: 2px; text-decoration-color: var(--label-3); }
}
/* A lead is one person however the team names them (Fase 112). Its company on its card (companyEditor() in app.js): a box of
   text of 32px, as the box of its value, with the company pages of the space in the browser's list under it. «Same person
   as…» of the «···» of its page (openSamePerson()): the rows of «This is…» (.name-member), each the face or the icon of its
   page in 20px, its name, and on its right its stage in its chip or what it is in the middle grey. And what the page asks
   before it goes into the one chosen (mergeConfirm()), on top of its body: a hairline round it, 8px round, as a request to
   see an entry is (.access-request) — what merging does in 13px, «Cancel» and «Merge» on its right, and what the server
   refused under them. The tokens of either theme, and no colour of their own. */
.lead-company-edit { display: flex; min-width: 0; }
.lead-company-input { width: 240px; max-width: 100%; height: var(--control-sm); }
.merge-choice .name-member-label { flex: 1; }
.merge-choice > .icon { width: 16px; height: 16px; margin: 0 2px; color: var(--label-2); }
.merge-choice .lead-stage { flex: none; }
.merge-choice-kind { flex: none; font: var(--meta); color: var(--label-2); white-space: nowrap; }
.merge-choices > .hint, .merge-choices > .error-row { padding: 6px 8px; }
.lead-merge { display: flex; align-items: center; flex-wrap: wrap; gap: 12px; padding: 10px 12px; border: 1px solid var(--line); border-radius: var(--radius-md); }
.lead-merge-text { flex: 1; min-width: 12em; margin: 0; font: var(--meta); color: var(--label); overflow-wrap: anywhere; }
.lead-merge-actions { flex: none; display: flex; gap: var(--s1); }
.lead-merge .hint { flex-basis: 100%; }
/* Who has a lead and what comes next, on its card (Fase 117, ownerSelect() and nextStepEditor() in app.js): the face of 18px of
   who has it — none for nobody — beside a menu of the members of 32px, as the period of its value; and the next step in a box
   of text of 32px, as wide as the box of its company, with its day beside it in a box of dates of 32px, under it where the card
   is too narrow for both, 4px over and under them to keep off the hairlines. The tokens of either theme, and no colour of
   their own. */
.lead-owner-edit { display: flex; align-items: center; gap: var(--s1); min-width: 0; }
.lead-owner-face { display: flex; }
.lead-owner-face:empty { display: none; }
.lead-owner-select { width: auto; min-width: 0; max-width: 100%; height: var(--control-sm); }
.lead-next-edit { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s1); min-width: 0; padding: 4px 0; }
.lead-next-input { width: 240px; max-width: 100%; height: var(--control-sm); }
.lead-next-day { width: auto; height: var(--control-sm); }
/* The address of a lead on its card, after its company (Fase 148f, emailEditor() in app.js): a box of 32px as wide as the box of
   its company. The tokens of either theme, and no colour of its own. */
.lead-email-input { width: 240px; max-width: 100%; height: var(--control-sm); }
/* SOPs (Fase 125, docs/sops.md §7; sopsPage(), sopPageView() and sopFlow() in app.js): the list a row of the rail opens since
   Fase 129 — a tab of «Pages» before —, a row each as the rows of «Pages» (.page-row), and the page of one with the head of an
   entry, whose title is not one to edit: under its short name (Fase 140) one grey line — its title where it says more than the
   name, then its code in a grey chip of the mono type, its version, who made it by their face of 18px and the day it last
   changed, each its own and 8px apart, the line wrapping under the title where it does not fit beside it —; «Launch» on its
   right, which unfolds under the head, on the quiet fill, one line and the sentence that launches it in mono in a box of the
   page's colour with «Copy» — what goes after its colon in the lightest grey —, and under it the command of before in 12px of
   the mono type in the lightest grey. Then its tabs, What's new's with a Lucide icon of 14px each, in one row that scrolls
   sideways where it does not fit — 6px over and under them inside it, the room their thumb's worth of a target needs on a phone
   —, and under them the tab chosen, its sections 32px apart. The roles of a SOP and the steps of its diagram wear the tone of a
   person or the AI's (--tone-person, --tone-ai); a tool, the grey of a chip. The tokens of either theme, and no colour of their
   own. */
.sop-view .detail-title h1 { cursor: default; }
.sop-facts { display: flex; align-items: center; flex-wrap: wrap; row-gap: 4px; margin-top: 6px; font: var(--meta); color: var(--label-2); }
.sop-title { min-width: 0; overflow-wrap: anywhere; }
.sop-fact { display: inline-flex; align-items: center; gap: 6px; }
.sop-code { display: inline-block; height: 20px; padding: 0 6px; border-radius: 4px; background: var(--fill); color: var(--label-2); font: 500 12px/20px var(--font-mono); white-space: nowrap; }
/* The last line of the head of a SOP (Fase 140b, sopShareLine() in app.js), as the page of an entity has it: «Visible to» on its
   right and, while the SOP is on the web, on its left in the type and the grey of the line under its name, the globe of 14px,
   «Shared with the internet», its link in the mono type cut at its end, «Shared with Ariel, Daniel» cut at its end too, and «Stop
   sharing» in --danger (.share-stop); asked, the question in the colour of the text with «Cancel» and «Stop sharing». It wraps
   where it does not fit beside «Visible to». */
.sop-shared { flex: 1 1 0; min-width: 0; display: flex; align-items: center; flex-wrap: wrap; gap: 4px var(--s1); font: var(--meta); color: var(--label-2); }
.sop-shared > .icon { flex: none; width: 14px; height: 14px; }
.sop-shared-web { flex: none; }
.sop-shared-link, .sop-shared-to { min-width: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
.sop-shared-link { max-width: 28ch; font: var(--code); color: var(--label-2); }
.sop-launch { display: grid; gap: 10px; margin-top: var(--s2); padding: 12px 14px; border-radius: var(--radius-md); background: var(--fill); }
/* The launch on the person's Claude (Fase 142, sopClaudeForm() in app.js), first in what «Launch» unfolds: a box for each variable of
   a SOP of before — the sentence, of a SOP v2 — and «Launch on your Claude», in one row that wraps where it does not fit. Under it,
   folded, the way of Claude Code of Fase 140: its summary in the grey of a line, its chevron turning as it unfolds, and the sentence
   and the command under it as they were. */
.sop-claude-launch { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s1); }
.sop-claude-launch .field { flex: 1 1 160px; height: var(--control-sm); }
.sop-launch-other summary { list-style: none; display: inline-flex; align-items: center; gap: 6px; font: var(--meta); color: var(--label-2); cursor: pointer; }
.sop-launch-other summary::-webkit-details-marker { display: none; }
.sop-launch-other summary .icon { width: 14px; height: 14px; transition: transform var(--t-fast) var(--ease-out); }
.sop-launch-other[open] summary .icon { transform: rotate(90deg); }
.sop-launch-other .sop-command { margin-top: 10px; }
.sop-command { display: flex; align-items: center; gap: var(--s1); padding: 4px 4px 4px 12px; border: 1px solid var(--line); border-radius: var(--radius); background: var(--surface); }
.sop-command-text { flex: 1; min-width: 0; font: var(--code); color: var(--label); overflow-wrap: anywhere; }
.sop-command-hint { color: var(--label-3); }
.sop-slash { margin: 6px 0 0; font: 500 12px/16px var(--font-mono); color: var(--label-3); overflow-wrap: anywhere; }
.sop-tabs { margin-top: 18px; padding: 6px 0; overflow-x: auto; overflow-y: hidden; scrollbar-width: none; }
.sop-tabs::-webkit-scrollbar { display: none; }
.sop-tab { flex: none; display: inline-flex; align-items: center; gap: 6px; white-space: nowrap; }
.sop-tab .icon { width: 14px; height: 14px; }
.sop-panel { display: grid; gap: var(--s4); margin-top: 18px; min-width: 0; }
.sop-text { margin: 0; font: var(--reading); color: var(--label); overflow-wrap: anywhere; }
/* «Summary»: since Fase 140 its result first, as «Result» shows it; the objective on the quiet fill, 8px round, its target in
   the middle grey on the axis of its first line and its name in 600 13px over it; the scope as a list, each part's name in
   600; and «Who does what», rows of two columns over hairlines, each role in the chip of its tone. Of a SOP v2, its style
   whole under its result, every line as it was written. */
.sop-objective { display: grid; grid-template-columns: 18px minmax(0, 1fr); gap: 12px; padding: 14px 16px; border-radius: var(--radius-md); background: var(--fill); }
.sop-objective > .icon { width: 18px; height: 18px; margin-top: 2px; color: var(--label-2); }
.sop-objective-label { margin: 0 0 2px; font: 600 13px/20px var(--font-body); color: var(--label-2); }
.sop-style-whole { white-space: pre-wrap; }
.sop-scope { display: grid; gap: 6px; margin: 0; padding-left: 20px; font: var(--reading); color: var(--label); }
.sop-scope strong { font-weight: 600; }
.sop-roles { width: 100%; border-collapse: collapse; font: var(--meta); color: var(--label); }
.sop-roles td { padding: 8px 12px 8px 0; border-bottom: 1px solid var(--line); vertical-align: top; overflow-wrap: anywhere; }
.sop-roles tr:first-child td { border-top: 1px solid var(--line); }
.sop-roles-name { width: 1%; white-space: nowrap; }
.sop-role { display: inline-block; height: 20px; padding: 0 8px; border-radius: var(--radius-pill); background: var(--tone-person); color: var(--label); font: 500 12px/20px var(--font-body); white-space: nowrap; }
.sop-role[data-who="ai"] { background: var(--tone-ai); }
/* «Result»: its caption in 13px of the middle grey over the preview. Its page (Fase 140), framed as wide as the column in the
   hairline and the corners of the app, 70vh tall with its own scroll, on the colour a page has where it sets none (Canvas in
   the light scheme), whatever the theme. One image as wide as the column in the hairline and the corners of the app, a window
   of 70vh with its own scroll for one taller than wide; several, the one chosen contained, 70vh at most, on the quiet fill,
   round arrows of the raised surface on its sides, and under it a strip of thumbnails of 56px, the one chosen ringed with the
   accent. Until an image has come, its frame is a picture's shape on the quiet fill. Its bar: «3 of 10» in a grey chip on the
   left, «Full size» and «Open the real one» on the right. Nothing to show: a calm box of a dashed hairline, the icon of an image
   in the lightest grey and its words in the middle grey. */
.sop-result { display: grid; gap: 12px; min-width: 0; }
.sop-caption { margin: 0; font: var(--meta); color: var(--label-2); overflow-wrap: anywhere; }
.sop-viewer { display: grid; gap: 12px; min-width: 0; }
.sop-html { display: block; width: 100%; height: 70vh; border: 1px solid var(--line); border-radius: var(--radius-md); color-scheme: light; background: Canvas; }
.sop-gallery:focus-visible { outline: 2px solid var(--tint); outline-offset: 4px; border-radius: var(--radius-md); }
.sop-shot { overflow: hidden; border: 1px solid var(--line); border-radius: var(--radius-md); background: var(--surface); }
.sop-shot img { display: block; width: 100%; height: auto; cursor: zoom-in; }
.sop-shot[data-state="tall"] { max-height: 70vh; overflow-y: auto; }
.sop-stage-frame { position: relative; min-width: 0; }
.sop-stage { display: grid; place-items: center; overflow: hidden; border: 1px solid var(--line); border-radius: var(--radius-md); background: var(--fill); }
.sop-stage img { display: block; max-width: 100%; max-height: 70vh; object-fit: contain; cursor: zoom-in; }
.sop-shot[data-state="loading"], .sop-stage[data-state="loading"] { aspect-ratio: 16 / 10; background: var(--fill); }
.sop-shot[data-state="loading"] img, .sop-stage[data-state="loading"] img { opacity: 0; }
.sop-arrow { position: absolute; top: 50%; transform: translateY(-50%); border-radius: var(--radius-pill); background: var(--raised); box-shadow: var(--shadow); color: var(--label); }
.sop-arrow-previous { left: var(--s1); }
.sop-arrow-next { right: var(--s1); }
.sop-thumbs { display: flex; gap: var(--s1); margin: -4px; padding: 4px; overflow-x: auto; }
.sop-thumb { flex: none; width: 56px; height: 56px; padding: 0; overflow: hidden; border: 1px solid var(--line); border-radius: var(--radius); background: var(--fill); cursor: pointer; }
.sop-thumb img { display: block; width: 100%; height: 100%; object-fit: cover; }
.sop-thumb[aria-current="true"] { outline: 2px solid var(--tint); outline-offset: 1px; }
.sop-result-bar { display: flex; align-items: center; flex-wrap: wrap; gap: var(--s1); }
.sop-result-actions { display: flex; flex-wrap: wrap; gap: var(--s1); margin-left: auto; }
.sop-empty { display: grid; justify-items: center; gap: var(--s1); padding: var(--s6) var(--s2); border: 1px dashed var(--line); border-radius: var(--radius-md); color: var(--label-3); text-align: center; }
.sop-empty .icon { width: 20px; height: 20px; }
.sop-empty p { margin: 0; font: var(--meta); color: var(--label-2); }
/* An image of a result at its own size (openSopLayer() in app.js): a dialog over the whole screen, the app darkened twice
   under it — the backdrop of the dialogs (--backdrop), and the dialog itself of the same —, the image in the middle where it is
   smaller than the screen and scrolling where it is larger; the × and «3 of 10» in the top corner and the arrows on the sides,
   on the raised surface. Its page (Fase 140, openSopPage()) fills the dialog and scrolls in itself, on the colour of its frame
   on the page of the SOP. */
.sop-layer { width: 100vw; height: 100vh; height: 100dvh; max-width: none; max-height: none; margin: 0; padding: 0; border: 0; background: var(--backdrop); }
.sop-layer::backdrop { background: var(--backdrop); }
.sop-layer-stage { display: flex; width: 100%; height: 100%; overflow: auto; }
.sop-layer-stage img { flex: none; margin: auto; max-width: none; }
.sop-layer-page { display: block; width: 100%; height: 100%; border: 0; color-scheme: light; background: Canvas; }
.sop-layer-bar { position: fixed; top: calc(12px + var(--safe-t)); right: calc(12px + var(--safe-r)); display: flex; align-items: center; gap: var(--s1); }
.sop-layer-bar .close { border-radius: var(--radius-pill); background: var(--raised); box-shadow: var(--shadow); color: var(--label); }
.sop-layer .sop-arrow { position: fixed; }
.sop-layer .sop-arrow-previous { left: calc(12px + var(--safe-l)); }
.sop-layer .sop-arrow-next { right: calc(12px + var(--safe-r)); }
/* «Steps»: the requirements a box each — the box of a task (.task-check) on the axis of the first line of its words, in the type
   of reading, the middle grey once ticked —; and the procedure, a table as wide as its columns need, which scrolls sideways
   where the page is narrower: its columns named in 500 12px of the middle grey over a hairline, a step a row over a hairline —
   its number in the lightest grey, its action in 500 14px with «The AI waits here» under it in 500 12px of --danger where it
   stops, its role in the chip of its tone, its tool in a grey chip and its check with its box, in 13px. */
.sop-checks { display: grid; gap: 4px; }
.sop-check { display: flex; align-items: flex-start; gap: 10px; font: var(--reading); color: var(--label); cursor: pointer; }
.sop-check-text { min-width: 0; overflow-wrap: anywhere; }
.sop-check:has(input:checked) .sop-check-text { color: var(--label-2); }
.sop-table-scroll { overflow-x: auto; }
.sop-table { width: 100%; min-width: 600px; border-collapse: collapse; }
.sop-table th { height: 28px; padding: 0 12px 0 0; border-bottom: 1px solid var(--line); text-align: left; font: 500 12px/16px var(--font-body); color: var(--label-2); white-space: nowrap; }
.sop-table td { padding: 10px 12px 10px 0; border-bottom: 1px solid var(--line); vertical-align: top; font: var(--meta); color: var(--label); }
.sop-step-n { width: 24px; font-variant-numeric: tabular-nums; color: var(--label-3); }
.sop-step-action { min-width: 140px; }
.sop-step-name { display: block; font: var(--row-title); color: var(--label); }
.sop-waits { display: block; margin-top: 2px; font: 500 12px/16px var(--font-body); color: var(--danger); }
.sop-tool { display: inline-block; height: 20px; padding: 0 8px; border-radius: var(--radius-pill); background: var(--fill); color: var(--label-2); font: 500 12px/20px var(--font-body); white-space: nowrap; }
.sop-step-check .sop-check { font: var(--meta); }
.sop-step-check .task-check { height: 20px; }
/* «Diagram» (sopFlow() in app.js): the drawing in a hairline box, 8px round, shrunk whole where the column is narrower than it.
   A step on the tone of who does it, its number in 600 and its action in 13px of the colour of the text; a decision a rhombus
   of the page's colour with a hairline of the lightest grey and its question in 500 12px; the start and the end pills of the
   colour of the text with their words in the page's; the arrows in the lightest grey, «Yes» in 11px of the middle grey; each
   «No» dashed, its head and its word in --danger. Under it the legend, in 13px of the middle grey: the roles in the chips of
   their tones, then the rhombus and the dashed line, drawn as in the diagram, with their words. */
.sop-diagram { display: grid; gap: 12px; min-width: 0; }
.sop-flow-frame { padding: var(--s3) var(--s2); border: 1px solid var(--line); border-radius: var(--radius-md); }
.sop-flow { display: block; max-width: 100%; height: auto; margin: 0 auto; }
.sop-flow text { dominant-baseline: central; font-family: var(--font-body); }
.sop-flow-step { fill: var(--tone-person); }
.sop-flow-step[data-who="ai"] { fill: var(--tone-ai); }
.sop-flow-action { text-anchor: middle; font-size: 13px; fill: var(--label); }
.sop-flow-n { font-weight: 600; font-variant-numeric: tabular-nums; }
.sop-flow-decision { fill: var(--surface); stroke: var(--label-3); stroke-width: 1.5; }
.sop-flow-question { text-anchor: middle; font-size: 12px; font-weight: 500; fill: var(--label); }
.sop-flow-term { fill: var(--label); }
.sop-flow-word { text-anchor: middle; font-size: 12px; font-weight: 600; fill: var(--surface); }
.sop-flow-arrow { fill: none; stroke: var(--label-3); stroke-width: 1.5; }
.sop-flow-head { fill: var(--label-3); }
.sop-flow-yes { font-size: 11px; fill: var(--label-2); }
.sop-flow-back { fill: none; stroke: var(--danger); stroke-width: 1.5; stroke-dasharray: 4 3; }
.sop-flow-back-head { fill: var(--danger); }
.sop-flow-no { font-size: 11px; font-weight: 500; fill: var(--danger); }
.sop-legend { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s1) 12px; font: var(--meta); color: var(--label-2); }
.sop-legend-item { display: inline-flex; align-items: center; gap: 6px; }
.sop-legend-mark { flex: none; display: block; }
/* «Rules»: a card a rule, two to a row where there is room, a hairline round each, 8px round — the icon of its level in a tile
   of 28px and its chip over its words in 13px —: «Never» on the soft red of --danger, «Always» on the soft green of
   «Connected» with its icon in that green, «Should» on the mark, «May» on the quiet fill. Under them «If something fails», rows
   over hairlines in one box: the icon of a warning in the middle grey, the problem in 500 14px and what to do in 13px of the
   middle grey. */
.sop-rules { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: var(--s1); margin: 0; padding: 0; list-style: none; }
.sop-rule { display: grid; grid-template-columns: 28px minmax(0, 1fr); gap: 12px; align-items: start; padding: 12px; border: 1px solid var(--line); border-radius: var(--radius-md); }
.sop-rule-icon { display: grid; place-items: center; width: 28px; height: 28px; border-radius: var(--radius); background: var(--fill); color: var(--label-2); }
.sop-rule-icon .icon { width: 16px; height: 16px; }
.sop-rule-body { display: grid; gap: 4px; justify-items: start; min-width: 0; }
.sop-rule-level { display: inline-block; height: 20px; padding: 0 8px; border-radius: var(--radius-pill); background: var(--fill); color: var(--label-2); font: 500 12px/20px var(--font-body); }
.sop-rule-text { margin: 0; font: var(--meta); color: var(--label); overflow-wrap: anywhere; }
.sop-rule[data-level="never"] .sop-rule-icon, .sop-rule[data-level="never"] .sop-rule-level { background: color-mix(in srgb, var(--danger) 12%, transparent); color: var(--danger); }
.sop-rule[data-level="always"] .sop-rule-icon, .sop-rule[data-level="always"] .sop-rule-level { background: color-mix(in srgb, var(--connected) 16%, transparent); color: var(--label); }
.sop-rule[data-level="always"] .sop-rule-icon { color: var(--connected); }
.sop-rule[data-level="should"] .sop-rule-icon, .sop-rule[data-level="should"] .sop-rule-level { background: var(--mark); color: var(--label); }
.sop-failures { display: grid; margin: 0; padding: 0; list-style: none; border: 1px solid var(--line); border-radius: var(--radius-md); }
.sop-failure { display: grid; grid-template-columns: 16px minmax(0, 1fr); gap: 10px; padding: 10px 12px; }
.sop-failure + .sop-failure { border-top: 1px solid var(--line); }
.sop-failure > .icon { width: 16px; height: 16px; margin-top: 2px; color: var(--label-2); }
.sop-failure-body { display: grid; gap: 2px; min-width: 0; }
.sop-failure-problem { font: var(--row-title); color: var(--label); }
.sop-failure-fix { font: var(--meta); color: var(--label-2); overflow-wrap: anywhere; }
/* «For the AI»: the text as the server writes it, in the mono type on the quiet fill, 8px round, every line as it comes, and
   «Copy» in its corner. «History»: a line of 32px a version, the newest on top — «v3» and its day in 12px of the lightest grey,
   the face of 16px and the first name, what changed in the middle grey —; and where each step comes from, numbered as its step,
   its action in 500 of the colour of the text and its source apart, then the references, in 13px of the middle grey. */
.sop-ai { position: relative; min-width: 0; }
.sop-ai-text { margin: 0; padding: 48px 14px 14px; border-radius: var(--radius-md); background: var(--fill); font: var(--code); color: var(--label); white-space: pre-wrap; overflow-wrap: anywhere; }
.sop-ai > .btn { position: absolute; top: var(--s1); right: var(--s1); }
.sop-versions { display: grid; margin: 0; padding: 0; list-style: none; }
.sop-version { display: flex; align-items: center; flex-wrap: wrap; column-gap: 10px; min-height: 32px; font: 400 14px/20px var(--font-body); color: var(--label); }
.sop-version-n { flex: none; width: 28px; font: 500 12px/20px var(--font-body); font-variant-numeric: tabular-nums; color: var(--label-3); }
.sop-version-day { flex: none; min-width: 56px; font: 400 12px/20px var(--font-body); color: var(--label-3); white-space: nowrap; }
.sop-version-who { flex: none; display: inline-flex; align-items: center; gap: 6px; }
.sop-version-note { flex: 1; min-width: 12em; color: var(--label-2); overflow-wrap: anywhere; }
.sop-sources, .sop-references { display: grid; gap: 4px; margin: 0; padding-left: 24px; font: var(--meta); color: var(--label-2); overflow-wrap: anywhere; }
.sop-source-step { font-weight: 500; color: var(--label); }
/* «Runs» (Fase 125b, sopRuns() in app.js): a line of 36px a run over a hairline, the newest on top, the way to its entry — the
   face of 18px of whoever started it; the values that tell it from the others in 500 14px of the colour of the text, cut at
   their end; its day in 12px of the lightest grey; where it stands in a chip; and how many of its steps are done in a grey
   chip (.count-chip) —. Where a run stands wears the colours of the weights of the rules: the mark while it runs, the soft
   green of «Connected» once done, the soft red of --danger once it failed, the quiet fill once abandoned. Under the command
   of «Launch», the last run in 13px of the middle grey. The tokens of either theme, and no colour of their own. */
.sop-runs { display: grid; margin: 0; padding: 0; list-style: none; }
.sop-run { display: flex; align-items: center; gap: 10px; min-height: 36px; border-bottom: 1px solid var(--line); color: inherit; text-decoration: none; }
.sop-run:hover { text-decoration: none; }
.sop-run .person-avatar { flex: none; }
.sop-run-values { flex: 1; min-width: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; font: var(--row-title); color: var(--label); }
.sop-run-day { flex: none; font: 400 12px/20px var(--font-body); color: var(--label-3); white-space: nowrap; }
.sop-run-status { flex: none; display: inline-block; height: 20px; padding: 0 8px; border-radius: var(--radius-pill); background: var(--fill); color: var(--label-2); font: 500 12px/20px var(--font-body); white-space: nowrap; }
.sop-run-status[data-status="running"] { background: var(--mark); color: var(--label); }
.sop-run-status[data-status="done"] { background: color-mix(in srgb, var(--connected) 16%, transparent); color: var(--label); }
.sop-run-status[data-status="failed"] { background: color-mix(in srgb, var(--danger) 12%, transparent); color: var(--danger); }
.sop-last-run { display: flex; align-items: center; flex-wrap: wrap; row-gap: 4px; margin: 0; font: var(--meta); color: var(--label-2); text-decoration: none; }
.sop-last-run:hover { text-decoration: none; }
@media (hover: hover) and (pointer: fine) {
  a.sop-last-run:hover { color: var(--label); }
}
/* The tools of the head of a SOP (sopHead() in app.js): «Launch» and «Edit», «Cancel» and «Save» of its editor, 8px apart on the
   right of the head. «New SOP» on the right of the title of «SOPs» since Fase 140, on its axis, as «Launch» and «Edit» are on the
   right of the name of a SOP. «Your Claude» under it since Fase 149b (yourClaudeStrip()), a list of one row, with why 8px over it
   while a launch waits for a Claude. A row of «SOPs»: under its short name, its title takes what its code, its version, who and the
   day leave, cut at its end. */
.sop-tools { gap: var(--s1); }
.sops-head { display: flex; align-items: center; justify-content: space-between; gap: var(--s2); min-width: 0; }
.sops-claude { display: grid; gap: var(--s1); }
.sop-row-line { display: flex; gap: var(--s1); }
.sop-row-title { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.sop-row-facts { flex: none; }
/* SOPs v2 (Fase 130; docs/sops/v2/mock.html, whose mk-* rules these are, and sopEditorView(), sopLaunchView() and sopRunPage() in
   app.js). The editor: the short name written in the title (Fase 140), its placeholder in the lightest grey while it is empty;
   «Materials», «Style» and «Result», each its name in the small label over its part, 24px under what is over it — «Result» a
   frame as the materials' for its page —; the materials, chips of 30px in a hairline
   pill — the icon of their type in grey, their name cut at its end, their type in a chip of the mono type on the quiet fill, and
   in the editor their × in the lightest grey —, in a dashed frame that fills while files are over it, «Drop files here» last in the
   lightest grey; why a file did not go, a line under it; the style, a box of 15px on lines of 1.5 a person makes taller. The page
   of a SOP: the same chips, its style folded to one line in the middle grey, which unfolds whole; Ask's box in 16px with its
   suggestions under it; and the last run in the lightest grey. A run: beside its title, a chip of where it stands — a dot of the
   green of «Connected» that breathes while it runs, --danger once it failed, grey once abandoned, the ✓ once done —; the sentence
   under it in 15px of the middle grey; what was found in a hairline card, its line in 600 14px with the loader turning, then the ✓;
   the steps, a line of time — a mark of 22px on a hairline that joins them: empty while pending, the colour of the text round the
   loader while it runs, filled with it under its ✓ once done, on the glow while it waits for the person —, their words in 600 15px
   (500 in the lightest grey while pending), their note in 14px of the middle grey, the items in hairline cards — the one unticked
   in grey on «Your turn», whose two buttons are under it —. Done: what was found and the steps folded in one line of 14px of the
   middle grey with a chevron that turns as it unfolds; the result, cards that open, «Open in Pages» and «Copy all». An item: the
   way back in 14px of the middle grey, its text in 17px, its call to action in 15px of the middle grey, «Previous» and «Next».
   Nothing turns nor breathes under prefers-reduced-motion. The tokens of either theme, and no colour of their own. */
.sop-view .detail-title h1.sop-name { cursor: text; }
/* Written in place, it shows the focus as every title written in place does (.title-input), with a line of 2px under it, and
   not the ring of the page (Fase 144: until then nothing showed it). */
.sop-name:focus { outline: none; box-shadow: 0 2px 0 var(--primary); }
.sop-name:empty::before { content: attr(data-placeholder); color: var(--label-3); }
/* The title under the short name in the editor (Fase 140): written in place as the name is, in the type and the grey of the line
   it is part of on the page of the SOP, its placeholder in the lightest grey while it is empty. */
.sop-title-box { margin: 6px 0 0; font: var(--meta); color: var(--label-2); overflow-wrap: anywhere; cursor: text; }
.sop-title-box:focus { outline: none; box-shadow: 0 2px 0 var(--primary); }
.sop-title-box:empty::before { content: attr(data-placeholder); color: var(--label-3); }
.sop-section { display: grid; gap: 6px; margin-top: var(--s3); }
.sop-label { font: var(--small-label); color: var(--label-2); }
.sop-drop { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; padding: 10px; border: 1px dashed var(--line); border-radius: var(--radius-md); }
.sop-drop[data-over] { border-color: var(--label-3); background: var(--fill); }
.sop-file { display: inline-flex; align-items: center; gap: 7px; height: 30px; max-width: 100%; padding: 0 9px; border: 1px solid var(--line); border-radius: var(--radius-pill); background: var(--surface); font: 400 13px/1 var(--font-body); color: var(--label); white-space: nowrap; }
.sop-file .icon { flex: none; width: 14px; height: 14px; color: var(--label-2); }
.sop-file-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.sop-kind { flex: none; height: 16px; padding: 0 5px; border-radius: 4px; background: var(--fill); color: var(--label-2); font: 500 10px/16px var(--font-mono); letter-spacing: 0.03em; }
.sop-file-remove { flex: none; display: grid; place-items: center; width: 18px; height: 18px; margin-right: -4px; padding: 0; border: 0; border-radius: var(--radius-pill); background: none; color: var(--label-3); cursor: pointer; }
.sop-file-remove .icon { width: 12px; height: 12px; color: inherit; }
.sop-drop-hint { display: inline-flex; align-items: center; gap: 6px; height: 30px; padding: 0 8px; border: 0; background: none; font: 400 13px/1 var(--font-body); color: var(--label-3); cursor: pointer; }
.sop-drop-hint .icon { width: 14px; height: 14px; }
.sop-upload-error { margin: 0; }
.sop-style { width: 100%; resize: vertical; padding: 12px 14px; border: 1px solid var(--line); border-radius: var(--radius-md); background: var(--surface); color: var(--label); font: 400 15px/1.5 var(--font-body); }
.sop-style::placeholder { color: var(--label-3); }
.sop-style:focus { outline: none; border-color: var(--label-2); }
.sop-materials { display: flex; flex-wrap: wrap; gap: 8px; margin-top: var(--s2); }
.sop-style-line { display: flex; align-items: baseline; gap: 8px; width: 100%; margin-top: var(--s2); padding: 0; border: 0; background: none; text-align: left; font: var(--meta); color: var(--label-2); cursor: pointer; }
.sop-style-text { flex: 1; min-width: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
.sop-style-line[aria-expanded="true"] .sop-style-text { white-space: pre-wrap; overflow-wrap: anywhere; }
.sop-ask { margin-top: var(--s3); }
/* Its box as tall as its lines (fitSopAsk() in app.js): no scroll of its own up to six lines — 1.4em each, over 14px of padding and
   a hairline on either side —, and past them one. */
.sop-ask .ask-input { font: 400 16px/1.4 var(--font-body); max-height: calc(6 * 1.4em + 30px); overflow-y: hidden; }
.sop-view .ask-suggestions { margin-top: 4px; }
.sop-last { display: flex; flex-wrap: wrap; row-gap: 4px; margin: var(--s2) 0 0; font: var(--meta); color: var(--label-3); text-decoration: none; }
.sop-last:hover { text-decoration: none; }
.sop-live { display: inline-flex; align-items: center; gap: 6px; height: 20px; padding: 0 8px; border-radius: var(--radius-pill); background: var(--fill); font: 500 12px/20px var(--font-body); color: var(--label-2); white-space: nowrap; }
.sop-live .icon { width: 12px; height: 12px; }
.sop-dot { width: 7px; height: 7px; border-radius: 50%; background: var(--connected); }
.sop-live[data-state="running"] .sop-dot { /* motion: explains — the run is still going */ animation: sop-pulse 1.4s var(--ease-in-out) infinite; }
.sop-live[data-state="failed"] .sop-dot { background: var(--danger); }
.sop-live[data-state="abandoned"] .sop-dot { background: var(--label-3); }
@keyframes sop-pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.3; } }
.sop-ask-line { margin: 10px 0 0; font: 400 15px/1.45 var(--font-body); color: var(--label-2); overflow-wrap: anywhere; }
.sop-finding { margin-top: var(--s2); padding: 12px 14px; border: 1px solid var(--line); border-radius: var(--radius-md); background: var(--surface); }
.sop-finding-line { display: flex; align-items: center; gap: 8px; min-height: 22px; font: 600 14px/20px var(--font-body); color: var(--label); }
.sop-finding-line .icon { flex: none; width: 16px; height: 16px; color: var(--label-2); }
.sop-finding .sources-line { margin-top: 10px; }
.sop-finding.sop-compact { margin-top: 10px; }
.sop-finding.sop-compact .sources-line { margin-top: 0; }
/* Where a run launched on somebody's Claude runs (Fase 142, sopClaudeLine() in app.js), in the box of what Company found: Claude's mark
   of 16px and «Running on your Claude» in the type of that line, and on its right «Open in claude.ai» with its arrow, in grey. What
   its session said when it closed it, under its steps, as the note of a step. */
.sop-claude { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; margin-top: var(--s2); padding: 12px 14px; border: 1px solid var(--line); border-radius: var(--radius-md); background: var(--surface); font: 600 14px/20px var(--font-body); color: var(--label); }
.sop-claude .entry-logo { flex: none; width: 16px; height: 16px; }
.sop-claude-open { display: inline-flex; align-items: center; gap: 4px; margin-left: auto; font: 500 14px/20px var(--font-body); color: var(--label-2); text-decoration: none; }
.sop-claude-open .icon { width: 14px; height: 14px; }
.sop-claude-result { margin-top: var(--s2); }
.sop-spin { /* motion: explains — still at work */ animation: sop-spin 1s linear infinite; transform-origin: center; }
@keyframes sop-spin { to { transform: rotate(360deg); } }
.sop-timeline { display: grid; margin-top: var(--s3); }
.sop-tl-step { position: relative; display: grid; grid-template-columns: 22px minmax(0, 1fr); column-gap: 12px; padding-bottom: 16px; }
.sop-tl-step::before { content: ""; position: absolute; left: 10px; top: 24px; bottom: 0; width: 1px; background: var(--line); }
.sop-tl-step:last-child::before { display: none; }
.sop-tl-step:last-child { padding-bottom: 0; }
.sop-mark { display: inline-grid; place-items: center; width: 22px; height: 22px; border: 1px solid var(--line); border-radius: 50%; background: var(--surface); color: var(--label-3); }
.sop-mark .icon { width: 13px; height: 13px; }
.sop-tl-step[data-state="pending"] .sop-mark .icon { display: none; }
.sop-tl-step[data-state="running"] .sop-mark { border-color: var(--label); color: var(--label); }
.sop-tl-step[data-state="done"] .sop-mark { background: var(--label); border-color: var(--label); color: var(--surface); }
.sop-tl-step[data-state="waiting"] .sop-mark { background: var(--glow); border-color: var(--glow-strong); color: var(--label); }
.sop-tl-step[data-state="failed"] .sop-mark { border-color: var(--danger); color: var(--danger); }
.sop-ttl { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; font: 600 15px/22px var(--font-body); color: var(--label); }
.sop-tl-step[data-state="pending"] .sop-ttl { font-weight: 500; color: var(--label-3); }
.sop-note { margin: 4px 0 0; max-width: 62ch; font: 400 14px/1.45 var(--font-body); color: var(--label-2); }
.sop-items { display: grid; gap: 8px; margin-top: 10px; }
.sop-item { display: grid; gap: 3px; padding: 10px 12px; border: 1px solid var(--line); border-radius: var(--radius-md); background: var(--surface); font: 400 14px/1.45 var(--font-body); color: var(--label); text-align: left; overflow-wrap: anywhere; }
button.sop-item { width: 100%; cursor: pointer; }
.sop-item-choice { position: relative; padding-right: 44px; cursor: pointer; }
.sop-item-check { position: absolute; top: 10px; right: 12px; }
.sop-item-choice:has(input:not(:checked)) { color: var(--label-3); }
.sop-item-k { font: 500 12px/1 var(--font-body); color: var(--label-3); font-variant-numeric: tabular-nums; }
.sop-item-title { font-weight: 600; }
.sop-item-cta { color: var(--label-2); }
.sop-turn { display: grid; gap: 10px; margin-top: 8px; }
.sop-turn-actions { display: flex; flex-wrap: wrap; gap: 8px; }
.sop-outcome { margin-top: var(--s3); }
.sop-outcome .sop-label { margin-bottom: 8px; }
.sop-actions { display: flex; flex-wrap: wrap; gap: 8px; margin-top: var(--s2); }
.sop-details { margin-top: var(--s2); }
.sop-details summary { list-style: none; display: inline-flex; align-items: center; gap: 6px; font: 400 14px/20px var(--font-body); color: var(--label-2); cursor: pointer; }
.sop-details summary::-webkit-details-marker { display: none; }
.sop-details summary .icon { width: 14px; height: 14px; transition: transform var(--t-fast) var(--ease-out); }
.sop-details[open] summary .icon { transform: rotate(90deg); }
.sop-timeline.sop-compact { margin-top: 12px; }
.sop-timeline.sop-compact .sop-tl-step { padding-bottom: 8px; }
.sop-timeline.sop-compact .sop-tl-step:last-child { padding-bottom: 0; }
.sop-back { display: inline-flex; align-items: center; gap: 6px; margin-bottom: var(--s2); padding: 0; border: 0; background: none; font: 400 14px/20px var(--font-body); color: var(--label-2); cursor: pointer; }
.sop-back .icon { width: 14px; height: 14px; }
.sop-item-body { margin: var(--s3) 0 0; max-width: 60ch; font: 400 17px/1.5 var(--font-body); color: var(--label); white-space: pre-wrap; overflow-wrap: anywhere; }
.sop-item-action { margin: 8px 0 0; font: 400 15px/1.5 var(--font-body); color: var(--label-2); overflow-wrap: anywhere; }
.sop-item-nav { display: flex; gap: 8px; margin-top: var(--s3); }
@media (hover: hover) and (pointer: fine) {
  .sop-drop-hint:hover, .sop-file-remove:hover, .sop-back:hover, .sop-details summary:hover, .sop-launch-other summary:hover, .sop-style-line:hover, a.sop-last:hover, .sop-claude-open:hover { color: var(--label); }
  .sop-claude-open:hover { text-decoration: none; }
  button.sop-item:hover { background: var(--fill); }
}
button.sop-item:focus-visible { background: var(--fill); }
@media (prefers-reduced-motion: reduce) {
  .sop-spin, .sop-live[data-state="running"] .sop-dot { animation: none; }
  .sop-details summary .icon, .sop-launch-other summary .icon { transition: none; }
}
/* Who is who (Fase 113, identityCard() in app.js): a card for each question of whether two names are one person — on top of
   What's new, on the page of each of the two and first in Ask's Today —, 8px apart, a hairline round each, 8px round, as a
   request to see an entry is (.access-request): the question in 500 14px of the colour of the text; under it a line of 13px in
   the middle grey for each of the two, the sentence that names them, cut at the end of its line — the colour of the text under
   the pointer, the way to its entry —; and on its right, on the middle of the card, «Yes», «No» and «Not sure» (Fase 121),
   buttons of 28px — a thumb's 36px on a phone, as every small button (.btn-sm there) —, under the text where the card is too
   narrow for both, as a request's are. The tokens of either theme, and no colour of their own. */
.identity-cards { display: grid; gap: var(--s1); }
.identity-card { display: flex; align-items: center; flex-wrap: wrap; gap: 12px; padding: 10px 12px; border: 1px solid var(--line); border-radius: var(--radius-md); background: var(--surface); }
.identity-text { flex: 1; min-width: 12em; display: grid; gap: 2px; }
.identity-question { margin: 0; font: var(--row-title); color: var(--label); overflow-wrap: anywhere; }
.identity-quote { min-width: 0; font: var(--row-line); color: var(--label-2); text-decoration: none; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
a.identity-quote:hover { text-decoration: none; }
.identity-answers { flex: none; display: flex; gap: var(--s1); }
.identity-answer { height: 28px; padding: 0 10px; }
@media (hover: hover) and (pointer: fine) {
  a.identity-quote:hover { color: var(--label); }
}

/* «Keys» (Fase 84b, public/keys.js): the keys of a team space's repos, a section each, 32px apart — its head, the icon of
   git of 16px in the middle grey, the repo in 600 15px and how many keys in 13px of the middle grey, each its own —; under
   it, for whoever gives access, «Who can see these keys» in the middle grey, the faces of 24px of the list a little apart,
   each with its × of 16px over its corner while the pointer is on it (always, on a screen without a pointer), and «+»;
   then the keys, a row of 36px each over a hairline — the name in 500 13px of the mono type, and on its right who changed
   it and when, «pulled by» and the faces of who read it, in 13px of the middle grey, then «Reveal» —, or for whoever does
   not read them one line of 13px with «Ask». A value revealed takes the place of who and when, in mono, cut at its end,
   with «Copy». The tokens of either theme, and no colour of its own. */
.keys-page { gap: var(--s4); }
.keys-body { display: grid; gap: var(--s4); }
.keys-repo { display: grid; gap: var(--s1); min-width: 0; }
.keys-repo-head { display: flex; align-items: center; gap: var(--s1); margin: 0; font: 600 15px/20px var(--font-body); color: var(--label); }
.keys-repo-head .icon { flex: none; width: 16px; height: 16px; color: var(--label-2); }
.keys-repo-name { min-width: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
.keys-repo-count { flex: none; font: 400 13px/20px var(--font-body); color: var(--label-2); }
.keys-who { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s1); min-height: var(--control-sm); }
.keys-who-label { font: var(--row-line); color: var(--label-2); }
.keys-who-faces { display: flex; align-items: center; gap: 6px; }
.keys-who-face { position: relative; display: inline-flex; }
.keys-who-remove { position: absolute; top: -5px; right: -5px; display: grid; place-items: center; width: 16px; height: 16px; padding: 0; border: 0; border-radius: var(--radius-pill); background: var(--label); color: var(--surface); cursor: pointer; opacity: 0; }
.keys-who-remove .icon { width: 10px; height: 10px; stroke-width: 2.5; }
.keys-who-remove:focus-visible { opacity: 1; }
.keys-list { display: grid; }
.keys-row { display: flex; align-items: center; gap: var(--s2); min-height: 36px; border-bottom: 1px solid var(--line); }
.keys-name { flex: 1; min-width: 0; font: 500 13px/20px var(--font-mono); color: var(--label); overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
.keys-changed, .keys-pulled { flex: none; display: flex; align-items: center; gap: 6px; font: var(--row-line); color: var(--label-2); white-space: nowrap; }
.keys-value { flex: 2; min-width: 0; font: 500 13px/20px var(--font-mono); color: var(--label); overflow: hidden; white-space: nowrap; text-overflow: ellipsis; user-select: all; }
.keys-locked { display: flex; align-items: center; gap: var(--s2); min-height: 36px; font: var(--row-line); color: var(--label-2); }
.keys-locked-text { flex: 1; min-width: 0; }
@media (hover: hover) and (pointer: fine) {
  .keys-who-face:hover .keys-who-remove { opacity: 1; }
}
@media (hover: none) {
  .keys-who-remove { opacity: 1; }
}

/* «Configuración técnica»: what the operator of the instance set up, folded at the end. */
.instance > summary { padding: var(--s1) 0; font: 500 13px/20px var(--font-body); color: var(--label-2); cursor: pointer; }
.instance-body { display: grid; gap: var(--s4); padding-top: var(--s2); }
.instance-body > p { margin: 0; font: var(--meta); color: var(--label-2); }
.tech { display: grid; gap: var(--s1); min-width: 0; }
.tech h3 { margin: 0; font: 600 14px/20px var(--font-body); color: var(--label); }
.tech p { margin: 0; font: var(--meta); color: var(--label-2); }
.status {
  display: inline-flex;
  align-items: center;
  height: 24px;
  padding: 0 var(--s1);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  color: var(--label-2);
  font: var(--small-label);
  white-space: nowrap;
}
.status.ok { background: var(--primary-soft); border-color: transparent; color: var(--label); }
/* The pill is an inline-flex, so ::before is a flex item of its own: the space
   after the check has to be a margin or it collapses away. */
.status.ok::before { content: "✓"; margin-right: 4px; }
.status.err { background: color-mix(in srgb, var(--danger) 10%, transparent); border-color: transparent; color: var(--danger); }
code, .code {
  font: var(--code);
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 0 var(--s1);
  overflow-wrap: anywhere;
}
pre.code {
  margin: 0;
  padding: var(--s2);
  border: 0;
  border-radius: var(--radius-md);
  background: var(--dark-panel);
  color: var(--dark-text);
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}
.log { display: grid; gap: var(--s1); }
/* A delivery: when, where it came from, how it went and what it said, each in its column (Fase 94: no «·» between the
   source and how it went). */
.log-row {
  display: grid;
  grid-template-columns: 120px 80px 88px minmax(0, 1fr);
  gap: var(--s2);
  align-items: center;
  font: var(--footnote);
  color: var(--label-2);
  padding: var(--s1) 0;
  border-top: 1px solid var(--separator);
}
.tokens { display: grid; gap: var(--s1); }
.token-row {
  display: flex;
  align-items: center;
  gap: var(--s2);
  flex-wrap: wrap;
  padding: var(--s1) var(--s2);
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
  font: var(--footnote);
  color: var(--label-2);
}
.token-row .token-when { flex: 1; min-width: 0; }

/* iMessage in «Fuentes» (Fase 42): its row, and under it, in line with its name, the space's number to
   copy and the groups and chats it has heard, folded behind «Groups and chats» and its chip (Fase 89, .fold-list). The number is
   a sub-row of 32px since Fase 150c (numberRow() in app.js): «Number», the number to copy plain in the grey of its line since
   Fase 150e, where it was a grey chip (docs/assets/screens/SourcesConnected.dc.html, note 7: «A number is plain text in its
   sub-row»; a grey chip is a count's) — on one line, cut short where it does not fit, as Email Company's address is —, and the
   small «Copy» in the column of the card's controls. The whole card closes with one line, like a row. */
.imessage-card { border-bottom: 1px solid var(--line); }
.imessage-card > .source-row { border-bottom: 0; }
.imessage-body { display: grid; padding: 0 0 var(--s1) 32px; }
.imessage-number > .sub-line { overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
.imessage-conversations { display: grid; }
/* A group or a chat: its name, which reads as text and is edited in place (a hairline on hover, the ring
   on focus), who is in it and when it last spoke, and its «···». */
.imessage-conversations .conversation-row { min-height: 48px; padding: 6px 0; border-bottom: 0; border-top: 1px solid var(--line); }
/* Under the name: the faces of who is in it (avatarStack()), then the words — who, how many messages, when. */
.conversation-row .source-line { display: flex; align-items: center; gap: 8px; min-width: 0; }
.conversation-row .conversation-words { min-width: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
.conversation-name {
  width: 100%;
  min-width: 0;
  height: 28px;
  margin-left: -6px;
  padding: 0 6px;
  border: 1px solid transparent;
  border-radius: var(--radius);
  background: transparent;
  color: var(--label);
  font: var(--row-title);
  text-overflow: ellipsis;
}
.conversation-name::placeholder { color: var(--label); opacity: 1; }
.conversation-name:focus { outline: 2px solid var(--tint); outline-offset: 0; background: var(--surface); }
@media (hover: hover) and (pointer: fine) {
  .conversation-name:hover:not(:focus) { border-color: var(--line); }
}

/* A list folded behind its row (Fase 89): in «Fuentes» a sub-row (Fase 150, subFold() in app.js, .sub-fold), and in what
   Meta Ads files the row of «Previous» (foldedList(), .news-previous); and what it unfolds. */
.fold-list { display: grid; }

/* GitHub in «Fuentes» (Fase 63, Fase 89, Fase 150): its row, in the anatomy of every row — «[6] repositories» on its line,
   «Importing…» and «3 of 6 repositories» on its right while some are importing —, and under it, in line with its name,
   «Repositories» and its chip on a sub-row (.sub-fold), which unfolds what «Milestones & activity» means, once, and then by
   account — its photo of 16px and its name in capitals of 11px — each repository on a line of 36px: its name, where it
   stands and its «···». The whole card closes with one line, like a row. */
.github-card { border-bottom: 1px solid var(--line); }
.github-card > .source-row { border-bottom: 0; }
.github-body { display: grid; gap: var(--s1); padding: 0 0 var(--s2) 32px; }
.github-body:empty { display: none; }
.github-explain { margin: 0; padding: var(--s1) 0 4px; font: var(--row-line); color: var(--label-2); }
.github-installation, .github-repos { display: grid; }
.github-account { display: flex; align-items: center; gap: 6px; min-height: 28px; padding-top: var(--s1); font: 600 11px/16px var(--font-body); letter-spacing: 0.04em; text-transform: uppercase; color: var(--label-2); }
.github-login { flex: 1; min-width: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
.github-repo { display: flex; align-items: center; gap: var(--s1); min-height: 36px; }
.github-repo-name { flex: none; max-width: 45%; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; font: var(--row-title); color: var(--label); text-decoration: none; }
.github-repo-line { flex: 1; min-width: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; font: var(--row-line); color: var(--label-2); }
@media (hover: hover) and (pointer: fine) {
  a.github-repo-name:hover { text-decoration: underline; }
}
.github-choice input { flex: none; width: 16px; height: 16px; margin: 0; accent-color: var(--primary); cursor: pointer; }
/* «Docs» of a repository: its folders and files at the top of its branch, a box each, then «Cancel» and «Save». */
.github-choices { display: grid; border-top: 1px solid var(--line); }
.github-choice { display: flex; align-items: center; gap: 10px; min-height: 40px; border-bottom: 1px solid var(--line); font: var(--row-title); color: var(--label); cursor: pointer; }
.github-choice .icon { flex: none; width: 16px; height: 16px; color: var(--label-2); }
.github-choice span { min-width: 0; overflow-wrap: anywhere; }
.github-docs-foot { display: flex; justify-content: flex-end; gap: var(--s1); }
/* Who each login is (Fase 131b, githubPeople() in app.js), on top of the card's body: a sub-row of 32px for each, stacked with no
   gap — «@Ariel6974 is» its label, cut short where a long login does not fit —, and in the column of the card's controls the
   member chosen for it, a round button of 28px as who answers a number of Quo's is (.quo-answerer): their face of 18px and their
   first name, or «Choose a member» in grey while nobody is, and a chevron in the lightest grey; its grey under the pointer, with
   the focus or with its menu open is all of it. Its menu, the members of the space, each their face of 20px and their whole name. */
.github-people { display: grid; }
.github-person > .sub-label { display: block; flex: 0 1 auto; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
.github-person-choice {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-width: 0;
  height: 28px;
  padding: 0 6px 0 2px;
  border: 0;
  border-radius: var(--radius-pill);
  background: transparent;
  color: var(--label);
  font: var(--row-line);
  cursor: pointer;
}
.github-person-name, .github-person-unset { min-width: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
.github-person-unset { color: var(--label-2); }
.github-person-choice > .icon { flex: none; width: 14px; height: 14px; color: var(--label-3); }
.github-person-choice[aria-expanded="true"], .github-person-choice:focus-visible { background: var(--fill); }
@media (hover: hover) and (pointer: fine) {
  .github-person-choice:hover { background: var(--fill); }
}
.github-person-item { gap: 8px; }

/* Meta Ads in «Fuentes» (Fase 122, metaAdsCard() in app.js), as GitHub's: its row, whose one line says what is going on —
   «Following [2] ad accounts», the number in its grey chip inside the words —, and under it, in line with its name, «Ad
   accounts» and its chip, which unfolds a line of 36px for each ad account the grant sees: its box, its name — in grey
   for one a status stops —, and in the grey of a line its business, its currency, that status and the last day it ran;
   under them, set in under its name and wrapping as the card narrows, what it spent in its life and over the last 30
   and 7 days, each amount in a chip, how many campaigns run and how far back its history is read (Fase 122f), a second
   line only where there is any. The whole card closes with one line, like a row. */
.meta-ads-card { border-bottom: 1px solid var(--line); }
.meta-ads-card > .source-row { border-bottom: 0; }
.meta-ads-body { display: grid; gap: var(--s1); padding: 0 0 var(--s2) 32px; }
.meta-ads-body:empty { display: none; }
.meta-ads-account { display: flex; flex-wrap: wrap; align-items: center; gap: 0 var(--s1); min-height: 36px; }
label.meta-ads-account { cursor: pointer; }
.meta-ads-account input { flex: none; width: 16px; height: 16px; margin: 0; accent-color: var(--primary); cursor: pointer; }
.meta-ads-account-name { flex: none; max-width: 45%; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; font: var(--row-title); color: var(--label); }
.meta-ads-account.off .meta-ads-account-name { color: var(--label-2); }
.meta-ads-account-line { flex: 1; min-width: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; font: var(--row-line); color: var(--label-2); }
.meta-ads-account-figures { flex-basis: 100%; min-width: 0; padding-bottom: var(--s1); font: var(--row-line); color: var(--label-2); }
.meta-ads-account-figures:empty { display: none; }
label.meta-ads-account .meta-ads-account-figures { padding-left: 24px; }

/* Shopify in «Fuentes» (Fase 143, shopifyCard() in app.js), as Meta Ads': its row, whose one line says how the store's week
   went — its name, «[12] orders this week» with the number in its grey chip inside the words, and what they brought in a
   chip of its own, sitting in the line as that one does —, and under it, in line with its name, the store on one line of
   36px: its name, and in the grey of a line its address, its currency and when the last pass ended. The whole card closes
   with one line, like a row. Its «Connect» asks for the store's address in the popover a key is asked in (.popover-form). */
.shopify-card { border-bottom: 1px solid var(--line); }
.shopify-card > .source-row { border-bottom: 0; }
.shopify-card .source-line .count-chip { vertical-align: middle; }
.shopify-body { display: grid; gap: var(--s1); padding: 0 0 var(--s2) 32px; }
.shopify-body:empty { display: none; }
.shopify-store { display: flex; align-items: center; gap: var(--s1); min-height: 36px; }
.shopify-store-name { flex: none; max-width: 45%; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; font: var(--row-title); color: var(--label); }
.shopify-store-line { flex: 1; min-width: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; font: var(--row-line); color: var(--label-2); }

/* Supabase in «Fuentes» (Fase 146, supabaseCard() in app.js), as Meta Ads': its row, whose one line says what it reads —
   «Reading [3] tables and views» with the number in its grey chip inside the words, when it last imported on its right
   (Fase 150) —, and under it, in line with its name, its tables and views folded behind a sub-row (.sub-fold), each a line of 36px: its
   name, and in the grey of a line its dataset, its rows in a chip and its last row; under them, in grey, that Company reads the
   most recent of one with more rows than a pass reads. Then «Real time», a sub-row of 32px since Fase 150c (.sub-row,
   supabaseRealTime()): the webhook to make with its link at the end of its line, and in the column of the card's controls
   «● Receiving» over when the last delivery came (.sub-state), or «Copy URL». The whole card closes with one line, like a row.
   Its sheet (openSupabaseDialog()): the SQL and the example of a view in the dark block of a command (.dialog .code-block), the
   box of the connection string, and «Connect» on the right. Only the tokens of either theme. */
.supabase-card { border-bottom: 1px solid var(--line); }
.supabase-card > .source-row { border-bottom: 0; }
.supabase-card .source-line .count-chip { vertical-align: middle; }
.supabase-body { display: grid; padding: 0 0 var(--s1) 32px; }
.supabase-body:empty { display: none; }
.supabase-relations { display: grid; }
.supabase-relation { display: flex; flex-wrap: wrap; align-items: center; gap: 0 var(--s1); min-height: 36px; }
.supabase-relation-name { flex: none; max-width: 45%; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; font: var(--row-title); color: var(--label); }
.supabase-relation-line { flex: 1; min-width: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; font: var(--row-line); color: var(--label-2); }
.supabase-relation-line .count-chip { vertical-align: middle; }
.supabase-relation-capped { flex-basis: 100%; min-width: 0; padding-bottom: var(--s1); font: var(--row-line); color: var(--label-2); }
.supabase-form > .btn { justify-self: end; }
/* «Set it up with your AI» (Fase 146b, supabaseWithAi() in app.js), as a row of «Fuentes»: its words over the grey line of
   where the prompt goes, and «Copy prompt» on the right. First in the sheet, with a hairline under it before the SQL by hand. */
.supabase-ai { display: flex; align-items: center; gap: 12px; }
.supabase-ai-text { flex: 1; min-width: 0; display: grid; gap: 2px; }
.supabase-ai-title { font: var(--row-title); color: var(--label); }
.supabase-ai-line { font: var(--row-line); color: var(--label-2); }
.supabase-ai > .btn { flex: none; }
.supabase-form > .supabase-ai { padding-bottom: var(--s2); border-bottom: 1px solid var(--line); }

/* Quo in «Fuentes» (Fase 148, quoCard() in app.js), as Shopify's: its row, whose one line says how the line stands — the
   workspace, «[3] calls and [12] texts in 30 days» with each number in its grey chip inside the words, and when the last call
   was —, and under it, in line with its name, sub-rows of 32px with no gap between them (Fase 150d, docs/assets/screens/
   SourcesConnected.dc.html, note 7: «A number is plain text in its sub-row, its label («Sales») in grey, never a filled
   pill»): «Line» for each number of the workspace, the number plain in the grey of its line and its name in the lightest
   grey; while Company's webhook is not at Quo, «Webhook missing» in the grey of a line with «Register again» on its right;
   and its «Contacts». The whole card closes with one line, like a row. Only the tokens of either theme. */
.quo-card { border-bottom: 1px solid var(--line); }
.quo-card > .source-row { border-bottom: 0; }
.quo-card .source-line .count-chip { vertical-align: middle; }
.quo-body { display: grid; padding: 0 0 var(--s1) 32px; }
.quo-body:empty { display: none; }
.quo-numbers { display: grid; }
.quo-number-name { color: var(--label-3); }
/* Who answers each number in a team (Fase 148d, quoAnswered() in app.js): a sub-row of 32px under its «Line» since Fase 150d
   (note 7 of the board: «A setting of a line (who answers it) is a sub-row too») — «Answered by» its label, and in the column
   of the card's controls, as the switch of a setting is, the member as a person of the head of an entry is, their face of
   18px and their first name, with a chevron in the lightest grey: a button whose grey under the pointer, with the focus or
   with its menu open is all of it. Its menu, the members of the space, each their face of 20px and their whole name. */
.quo-answerer {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-width: 0;
  height: 28px;
  padding: 0 6px 0 2px;
  border: 0;
  border-radius: var(--radius-pill);
  background: transparent;
  color: var(--label);
  font: var(--row-line);
  cursor: pointer;
}
.quo-answerer-name { min-width: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
.quo-answerer > .icon { flex: none; width: 14px; height: 14px; color: var(--label-3); }
.quo-answerer[aria-expanded="true"], .quo-answerer:focus-visible { background: var(--fill); }
@media (hover: hover) and (pointer: fine) {
  .quo-answerer:hover { background: var(--fill); }
}
.quo-answerer-item { gap: 8px; }
/* «Register again» in the column of the card's controls, under the slot of its row (Fase 150). */
.quo-webhook { display: flex; align-items: center; gap: var(--s1); min-height: 32px; padding-right: calc(var(--control-sm) + var(--s1)); }
.quo-webhook-line { flex: 1; min-width: 0; font: var(--row-line); color: var(--label-2); }
.quo-webhook > .btn { flex: none; }
/* «Contacts» under Quo's row (Fase 148c; Fase 150c, quoContacts() in app.js): a sub-row of 32px (.sub-row) — «Contacts», «[219] in
   Quo» with the number in its grey chip, and «last sync» in the column of the card's controls (.sub-when) —; under it, where
   fields have no property in the workspace, «Properties to create» and its chip folded behind a sub-row whose line closes with
   «Open Quo ↗» (.sub-fold-row), which unfolds them, each in a grey chip, wrapping. */
.quo-contacts { display: grid; }
.quo-properties { display: flex; flex-wrap: wrap; gap: 6px; padding: 4px 0 var(--s1); }
.quo-property { display: inline-flex; align-items: center; height: 24px; padding: 0 var(--s1); border-radius: var(--radius-pill); background: var(--fill); font: 500 12px/24px var(--font-body); color: var(--label-2); white-space: nowrap; }

/* What Meta Ads files, opened (Fase 122f, metaAdsSections() in app.js). Its figures in grey tiles that wrap as the page
   narrows — what each is in small grey words, its number, and under it what more it says: what each result cost, how it
   moved against the seven days before —, «The day is still going.» over them in grey. A day's campaigns and breakdowns
   folded behind the row of «Previous» (.news-previous), 8px apart: the campaigns a tree, a step of 20px each with what
   each spent in a chip on its right; a breakdown a short table of tabular numbers that scrolls sideways where the page is
   narrower. An overview's campaigns each a name over a line of grey things apart, a hairline between them, their ad sets
   folded under them and set in, each ad with its thumbnail of 48px and its creative. The changes of a day a line each,
   the important ones with their icon of 16px in grey and when, who and the two sides under them; the rest with when in
   the lightest grey first. Only the tokens of either theme. */
.meta-ads-figures { display: flex; flex-wrap: wrap; gap: var(--s1); }
.meta-ads-figure { display: grid; align-content: start; gap: 2px; min-width: 112px; padding: 10px 12px; border-radius: var(--radius-md); background: var(--fill); }
.meta-ads-figure-label { font: var(--small-label); color: var(--label-2); }
.meta-ads-figure-value { font: 600 16px/22px var(--font-body); font-variant-numeric: tabular-nums; color: var(--label); }
.meta-ads-figure-more { font: var(--caption); font-variant-numeric: tabular-nums; color: var(--label-2); }
.meta-ads-note { margin: 0; font: var(--meta); color: var(--label-2); }
.meta-ads-folds { display: grid; }
.meta-ads-folds > .news-previous:first-child { margin-top: 0; }
.meta-ads-folds .fold-list { padding-top: var(--s1); }
.meta-ads-tree-line { display: flex; align-items: center; gap: var(--s1); min-height: 32px; font: var(--row-line); color: var(--label); }
.meta-ads-tree-line.step-1 { padding-left: 20px; }
.meta-ads-tree-line.step-2 { padding-left: 40px; color: var(--label-2); }
.meta-ads-tree-name { flex: 1; min-width: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
.meta-ads-table-scroll { overflow-x: auto; }
.meta-ads-table { width: 100%; border-collapse: collapse; font: var(--row-line); color: var(--label); }
.meta-ads-table th { height: 28px; padding: 0 12px 0 0; border-bottom: 1px solid var(--line); text-align: left; font: 500 12px/16px var(--font-body); color: var(--label-2); white-space: nowrap; }
.meta-ads-table td { height: 32px; padding: 0 12px 0 0; border-bottom: 1px solid var(--line); white-space: nowrap; }
.meta-ads-table .num { text-align: right; font-variant-numeric: tabular-nums; }
.meta-ads-heading .count-chip { margin-left: var(--s1); vertical-align: top; }
.meta-ads-campaigns { display: grid; }
.meta-ads-campaign { display: grid; gap: 2px; padding: 12px 0; border-top: 1px solid var(--line); }
.meta-ads-campaign:first-child { padding-top: 0; border-top: 0; }
.meta-ads-name { display: flex; align-items: center; gap: var(--s1); min-width: 0; font: var(--row-title); color: var(--label); overflow-wrap: anywhere; }
.meta-ads-line { min-width: 0; font: var(--row-line); color: var(--label-2); overflow-wrap: anywhere; }
.meta-ads-line .count-chip { vertical-align: middle; }
.meta-ads-adset { display: grid; gap: 2px; padding: var(--s1) 0 var(--s1) 20px; }
.meta-ads-ad { display: flex; align-items: flex-start; gap: 12px; padding: var(--s1) 0 0 20px; }
.meta-ads-thumb { flex: none; width: 48px; height: 48px; border: 1px solid var(--line); border-radius: var(--radius-md); object-fit: cover; }
.meta-ads-ad-text { display: grid; gap: 2px; min-width: 0; }
.meta-ads-ad-title { font: 600 13px/18px var(--font-body); color: var(--label); overflow-wrap: anywhere; }
.meta-ads-ad-body { margin: 0; font: var(--row-line); color: var(--label); white-space: pre-line; overflow-wrap: anywhere; }
.meta-ads-cta { display: inline-block; padding: 0 8px; border: 1px solid var(--line); border-radius: var(--radius-pill); font: 500 12px/18px var(--font-body); color: var(--label); }
.meta-ads-line a { color: var(--label-2); }
.meta-ads-open { display: inline-flex; color: var(--label-2); }
.meta-ads-open .icon { width: 14px; height: 14px; }
.meta-ads-changes { display: grid; margin: 0; padding: 0; list-style: none; }
.meta-ads-change { display: flex; align-items: flex-start; gap: 10px; padding: 6px 0; font: var(--row-line); color: var(--label); }
.meta-ads-change > .icon { flex: none; width: 16px; height: 16px; margin-top: 1px; color: var(--label-2); }
.meta-ads-change-time { flex: none; min-width: 48px; font-variant-numeric: tabular-nums; color: var(--label-3); }
.meta-ads-change-body { display: grid; gap: 2px; min-width: 0; overflow-wrap: anywhere; }
.meta-ads-change-text { min-width: 0; overflow-wrap: anywhere; }
.meta-ads-change-what { font: var(--row-title); }
@media (hover: hover) and (pointer: fine) {
  .meta-ads-open:hover, .meta-ads-line a:hover { color: var(--label); }
}

/* A day of a store, opened (Fase 145, shopifyDaySections() in app.js), as a day of Meta Ads is: its figures in grey tiles that
   wrap as the page narrows — what each is in small grey words over its number —, «The day is still going.» over them in grey,
   and a day without orders that one grey line; its products that sold the most behind the heading that folds a section of a
   day of GitHub (.activity-toggle), a short table of tabular numbers that scrolls sideways where the page is narrower, a long
   product's name going on to a second line. Only the tokens of either theme. */
.shopify-figures { display: flex; flex-wrap: wrap; gap: var(--s1); }
.shopify-figure { display: grid; align-content: start; gap: 2px; min-width: 112px; padding: 10px 12px; border-radius: var(--radius-md); background: var(--fill); }
.shopify-figure-label { font: var(--small-label); color: var(--label-2); }
.shopify-figure-value { font: 600 16px/22px var(--font-body); font-variant-numeric: tabular-nums; color: var(--label); }
.shopify-note { margin: 0; font: var(--meta); color: var(--label-2); }
.shopify-table-scroll { overflow-x: auto; }
.shopify-table { width: 100%; border-collapse: collapse; font: var(--row-line); color: var(--label); }
.shopify-table th { height: 28px; padding: 0 12px 0 0; border-bottom: 1px solid var(--line); text-align: left; font: 500 12px/16px var(--font-body); color: var(--label-2); white-space: nowrap; }
.shopify-table td { height: 32px; padding: 0 12px 0 0; border-bottom: 1px solid var(--line); white-space: nowrap; }
.shopify-table td:first-child { white-space: normal; overflow-wrap: break-word; }
.shopify-table .num { text-align: right; font-variant-numeric: tabular-nums; }

/* A connector Company may write to in «Fuentes» (Fase 79, writeCard() in app.js: Google Calendar): its row, and in the
   same block, under its account and in line with its name, «Let Company create events», a sub-row of 32px (.sub-row, Fase
   150) with no hairline over it, its words in the colour of the label of a sub-row and its switch in the column of the
   card's controls, under the slot of the row. The card closes with one line, like a row. Company's other line (WhatsApp,
   contextLineRow()) is a row alone since Fase 150d: how Company is asked there is on its line, as on the iMessage card's. */
/* A switch (Linear's integration rows): 34 by 20, the track in the grey of a line while off and in the label's colour
   while on — the app's one accent —, and the knob the background's, which slides. A button with role="switch". */
.toggle { flex: none; position: relative; width: 34px; height: 20px; padding: 0; border: 0; border-radius: var(--radius-pill); background: var(--label-3); cursor: pointer; transition: background-color 140ms var(--ease-out); }
.toggle.on { background: var(--label); }
.toggle:disabled { cursor: default; opacity: 0.6; }
.toggle:focus-visible { outline: 2px solid var(--tint); outline-offset: 2px; }
.toggle-knob { position: absolute; top: 2px; left: 2px; width: 16px; height: 16px; border-radius: var(--radius-pill); background: var(--bg); transition: transform 140ms var(--ease-in-out); }
.toggle.on .toggle-knob { transform: translateX(14px); }
/* Under prefers-reduced-motion the knob is where it goes at once, and the track still fades to its colour (Fase 144). */
@media (prefers-reduced-motion: reduce) { .toggle-knob { transition: none; } }
.write-card { border-bottom: 1px solid var(--line); }
.write-card > .source-row { border-bottom: 0; padding-bottom: 0; }
.write-body { display: grid; padding: 0 0 4px 32px; }
.write-line { flex: 1; min-width: 0; font: var(--row-line); color: var(--label); }
.write-name { overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }

/* A connector a person connects several accounts of (Fase 89, accountsCard() in app.js: Gmail, Outlook, Drive, OneDrive):
   its row — with one account, a row as the others are (Fase 150) — and under it, in line with its name, with several, a
   sub-row of 32px for each account (.sub-row): its address, why its last pass did not work after the dot of --danger, and
   in the column of the card's controls «Reconnect» or, in grey, when it last read; and «Add another account», a quiet
   link on a sub-row of its own. The card closes with one line, like a row. Email Company's addresses are such sub-rows
   since Fase 150e (.email-senders); «Your Claude» is made as the accounts were before Fase 150 (.account-row). */
.accounts-card { border-bottom: 1px solid var(--line); }
.accounts-card > .source-row { border-bottom: 0; }
.accounts-body { display: grid; padding: 0 0 var(--s1) 32px; }
.accounts-body > .sub-row > .sub-label { display: block; flex: 0 1 auto; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
.account-row { display: flex; align-items: center; gap: var(--s1); min-height: 28px; }
.account-address { flex: none; max-width: 55%; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; font: 500 13px/18px var(--font-body); color: var(--label-2); }
.account-state { flex: 1; min-width: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; font: var(--row-line); color: var(--label-3); }
.account-row .icon-btn { width: 28px; height: 28px; }
.add-account { justify-self: start; display: inline-flex; align-items: center; min-height: 28px; font: var(--row-line); color: var(--label-2); text-decoration: none; }
@media (hover: hover) and (pointer: fine) {
  .add-account:hover { color: var(--label); text-decoration: underline; }
}
/* «Add address» of Email Company is a button that reads as that link. */
button.add-account { padding: 0; border: 0; background: none; cursor: pointer; }

/* «Your Claude» (Fase 142, yourClaudeRow() in app.js), over the list of «SOPs» since Fase 149b (yourClaudeStrip()) — under Claude Code's
   row of «Fuentes» until then — and made as the accounts of Gmail: a line of 28px for each routine — what its person calls it, «…1234»
   in the grey of a line, and of the person's own «Shared with the company» with its switch and its «···»; of one the space shares, who
   shares it —, and «Add another account». */
.routine-shared { flex: 0 1 auto; min-width: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; font: var(--row-line); color: var(--label-2); }
.routine-row .toggle { margin-left: 4px; }

/* «Connect your Claude» (Fase 142, renderConnectClaude() in app.js): docs/connect-claude/mock.html as it is. One column of 640px, its
   parts 32px apart: why on top when a launch sent the person here; the one line that is its title, in Bricolage; the steps across the
   top, a circle of 40px each joined by a hairline — the one on screen in the colour of the primary button, the ones done on the grey
   of a fill with a tick, the rest an outline —; and the step on screen: its caption in Bricolage with what to press in a grey chip, a
   real screen of claude.ai with a red frame breathing round the place to press, a note on the grey of a fill, and its buttons of
   44px apart at its foot. In the tokens of either theme; what is drawn on claude.ai's screens, in claude.ai's own colours, which
   are dark in both. */
.page.claude-connect { max-width: calc(640px + 2 * var(--inset)); gap: var(--s4); }
.claude-why { margin: 0; font: var(--small); color: var(--label-2); }
.page .claude-title { font: 700 35px/1.05 var(--font-heading); letter-spacing: normal; }
.claude-title span { display: block; }
.claude-steps { display: flex; align-items: center; }
.claude-pill { flex: none; display: inline-flex; align-items: center; justify-content: center; width: 40px; height: 40px; padding: 0; border: 1px solid var(--border); border-radius: var(--radius-pill); background: var(--surface); color: var(--label-2); font: 600 15px/1 var(--font-body); cursor: pointer; transition: transform var(--t-fast) var(--ease-out), background-color var(--t-fast) var(--ease-out), color var(--t-fast) var(--ease-out), border-color var(--t-fast) var(--ease-out); }
.claude-pill:active { transform: scale(0.97); }
.claude-pill.on { background: var(--primary); border-color: var(--primary); color: var(--on-primary); }
.claude-pill.ok { background: var(--fill); border-color: var(--border); color: var(--label); }
.claude-pill .icon { width: 16px; height: 16px; stroke-width: 2.5; }
.claude-bar { flex: 1; min-width: 16px; height: 1px; background: var(--border); }
.claude-bar.ok { background: var(--label); }
.claude-step { display: grid; gap: var(--s2); }
.claude-cap { margin: 0; font: 700 26px/1.2 var(--font-heading); color: var(--label); }
.claude-k { display: inline-block; padding: 0 8px; border-radius: var(--radius); background: var(--fill); font: 600 22px/1.5 var(--font-heading); }
.claude-step .btn { height: 44px; padding: 0 18px; border-color: var(--border); }
.claude-step .btn-primary { border-color: var(--primary); }
.claude-step .btn-sm { height: 34px; padding: 0 12px; }
.claude-step .btn .icon { width: 14px; height: 14px; }
.claude-foot { display: flex; justify-content: space-between; align-items: center; gap: 12px; }
.claude-note { display: flex; gap: 12px; align-items: flex-start; padding: 14px 16px; border-radius: var(--radius-md); background: var(--fill); font: 400 15px/1.45 var(--font-body); color: var(--label); }
.claude-copy { display: flex; gap: 10px; align-items: flex-start; padding: 14px 12px 14px 16px; border: 1px solid var(--border); border-radius: var(--radius-md); background: var(--surface); }
.claude-copy p { flex: 1; min-width: 0; margin: 0; font: 400 14px/1.55 var(--font-mono); color: var(--label); overflow-wrap: anywhere; }
.claude-fields { display: grid; gap: 12px; padding: 20px; border: 1px solid var(--border); border-radius: var(--radius-lg); background: var(--surface); }
.claude-fields .field { height: 48px; padding: 0 14px; border-color: var(--border); border-radius: var(--radius-md); font: 400 16px/1 var(--font-body); }
/* A screen of claude.ai, as it is (public/connect-claude/*.jpg), and what is drawn on it: the place to press framed in red, nothing on
   top of it; a word typed and a text pasted where its boxes are empty, over a patch of the colour under them. The type of what is
   drawn grows with the screen (cqw, of the screen as wide as the column). */
.claude-shot { position: relative; container-type: inline-size; border: 1px solid var(--border); border-radius: var(--radius-lg); overflow: hidden; background: #141416; box-shadow: var(--shadow); }
.claude-shot img { display: block; width: 100%; height: auto; }
.claude-ring { /* motion: explains — the place to press */ position: absolute; border: 3px solid var(--danger); border-radius: 10px; box-shadow: 0 0 0 0 rgba(255, 85, 85, 0.55); animation: claude-breathe 2s var(--ease-out) infinite; pointer-events: none; }
@keyframes claude-breathe { 0% { box-shadow: 0 0 0 0 rgba(255, 85, 85, 0.55); } 70% { box-shadow: 0 0 0 14px rgba(255, 85, 85, 0); } 100% { box-shadow: 0 0 0 14px rgba(255, 85, 85, 0); } }
.claude-hide { position: absolute; background: #2a2a2d; }
.claude-hide-name { background: #141416; }
.claude-over { position: absolute; color: #f5f4f0; font: 400 2.1cqw/1.3 var(--font-body); white-space: nowrap; }
.claude-typed { /* motion: explains — what to type */ display: inline-block; overflow: hidden; vertical-align: bottom; border-right: 2px solid #f5f4f0; animation: claude-typing 2.6s steps(14) infinite; }
@keyframes claude-typing { 0% { width: 0; } 55% { width: 100%; } 100% { width: 100%; } }
.claude-paste { /* motion: explains — what to paste */ position: absolute; color: #f5f4f0; font: 400 2cqw/1.45 var(--font-body); white-space: normal; animation: claude-reveal 2.6s var(--ease-out) infinite; }
@keyframes claude-reveal { 0%, 35% { opacity: 0; transform: translateY(4px); } 50%, 100% { opacity: 1; transform: translateY(0); } }
/* The window of the token (step 4), drawn: nobody captured it. */
.claude-modal { position: relative; container-type: inline-size; width: 100%; aspect-ratio: 1200 / 420; border: 1px solid var(--border); border-radius: var(--radius-lg); overflow: hidden; background: #141416; box-shadow: var(--shadow); }
.claude-win { position: absolute; left: 18%; top: 8%; width: 64%; height: 84%; border: 1px solid #3a3a3e; border-radius: 10px; background: #1d1d20; }
.claude-win-title { position: absolute; color: #f5f4f0; font: 500 2.3cqw/1 var(--font-body); white-space: nowrap; }
.claude-win-label { position: absolute; color: #9a9993; font: 400 1.9cqw/1 var(--font-body); white-space: nowrap; }
.claude-win-box { position: absolute; display: flex; align-items: center; padding: 0 2%; border: 1px solid #3a3a3e; border-radius: 6px; background: #141416; color: #f5f4f0; font: 400 1.8cqw/1 var(--font-mono); white-space: nowrap; overflow: hidden; }
.claude-win-copy { position: absolute; display: flex; align-items: center; justify-content: center; border-radius: 6px; background: #f5f4f0; color: #141416; font: 600 1.9cqw/1 var(--font-body); white-space: nowrap; }
@media (hover: hover) and (pointer: fine) {
  .claude-pill:hover { border-color: var(--border-strong); }
  .claude-pill.on:hover { border-color: var(--primary); }
}
@media (prefers-reduced-motion: reduce) {
  .claude-pill { transition: none; }
  .claude-ring, .claude-paste { animation: none; }
  .claude-typed { animation: none; border-right: 0; }
  .claude-pill:active { transform: none; }
}

/* «Company, in your terminal.» (Fase 141c, terminalGuide() in app.js): docs/terminal-guide/mock.html as it is, over the rows of the tab
   of Claude Code of «Fuentes». A column of parts 28px apart: its line in Bricolage at 40px and a grey one under it; the command in a
   dark block of mono — the dark of the tiles and their text in both themes, the gold of what is the person's own —, «Copy» on its
   right and a grey line under them; «Then just talk.» over a second dark block where three examples type themselves, and «Play
   again»; and three points, each its icon on a grey disc, its line in Bricolage and its words in grey, what is pasted or said in a grey
   chip of mono. Its motion is the README's: the parts arrive in 220 ms ease-out from 8px below, 50 ms apart; each example types in
   900 ms of steps — a block of the dark slides off it, so that only transform moves — and its answer arrives under it; «Copy» turns
   into «Copied» through a blur of 200 ms. Painted again in its place (.is-still), nothing moves; under prefers-reduced-motion, only
   fades, and the typing shows whole. */
/* No wider than the panel whatever its lines: what does not fit scrolls inside its dark block. */
.terminal-guide { display: flex; flex-direction: column; gap: 28px; min-width: 0; }
.terminal-in { opacity: 0; transform: translateY(8px); animation: terminal-arrive var(--t-base) var(--ease-out) forwards; }
.terminal-in.terminal-in-1 { animation-delay: 50ms; }
.terminal-in.terminal-in-2 { animation-delay: 100ms; }
.terminal-in.terminal-in-3 { animation-delay: 150ms; }
@keyframes terminal-arrive { to { opacity: 1; transform: translateY(0); } }
@keyframes terminal-fade { to { opacity: 1; } }
.terminal-head { display: flex; flex-direction: column; gap: 10px; }
.terminal-title { margin: 0; font: 700 40px/1.05 var(--font-heading); color: var(--text); }
.terminal-lead { margin: 0; font: 400 17px/1.5 var(--font-body); color: var(--label-2); }
.terminal { padding: 18px 20px; border-radius: var(--radius-lg); background: var(--dark-bg); color: var(--dark-text); font: 400 14px/1.7 var(--font-mono); overflow-x: auto; }
.terminal-prompt { color: color-mix(in srgb, var(--dark-text) 60%, transparent); }
.terminal-key { color: var(--dark-key); }
.terminal-dim { color: color-mix(in srgb, var(--dark-text) 52%, transparent); }
.terminal-ok { color: var(--connected); }
.terminal-install { display: flex; gap: 12px; align-items: flex-start; }
.terminal-install .terminal { flex: 1; min-width: 0; overflow-wrap: anywhere; }
.terminal-copy { flex: none; border-color: var(--border); transition: transform var(--t-fast) var(--ease-out), border-color var(--t-fast) var(--ease-out); }
.terminal-copy-label { display: inline-block; transition: filter 200ms var(--ease-out), opacity 200ms var(--ease-out); }
.terminal-copy[data-copy="swap"] .terminal-copy-label { filter: blur(2px); opacity: 0.6; }
.terminal-note { margin: -16px 0 0; font: 400 14px/1.5 var(--font-body); color: var(--label-2); }
.terminal-talk { display: flex; flex-direction: column; gap: 12px; }
.terminal-talk-title { margin: 0; font: 700 22px/1.2 var(--font-heading); color: var(--text); }
.terminal-examples { display: flex; flex-direction: column; gap: 14px; }
.terminal-typed { position: relative; display: inline-block; overflow: hidden; vertical-align: bottom; white-space: nowrap; }
.terminal-typed::after { /* motion: explains — what to say */ content: ""; position: absolute; inset: 0; background: var(--dark-bg); animation: terminal-type 900ms steps(32, end) forwards; }
@keyframes terminal-type { to { transform: translateX(100%); } }
.terminal-answer { margin-top: 6px; opacity: 0; transform: translateY(4px); animation: terminal-arrive var(--t-base) var(--ease-out) forwards; }
.terminal-todo { white-space: pre; }
.terminal-ex1 .terminal-typed::after { animation-delay: 400ms; }
.terminal-ex1 .terminal-answer { animation-delay: 1500ms; }
.terminal-ex2 .terminal-typed::after { animation-delay: 3200ms; }
.terminal-ex2 .terminal-answer { animation-delay: 4300ms; }
.terminal-ex3 .terminal-typed::after { animation-delay: 5600ms; }
.terminal-ex3 .terminal-answer { animation-delay: 6700ms; }
.terminal-again { align-self: flex-start; }
.terminal-again .icon { width: 14px; height: 14px; stroke-width: 2; }
.terminal-points { display: flex; flex-direction: column; }
.terminal-point { display: flex; gap: 16px; align-items: flex-start; padding: 16px 0; border-top: 1px solid var(--border); }
.terminal-point-icon { flex: none; display: grid; place-items: center; width: 28px; height: 28px; border-radius: var(--radius-pill); background: var(--fill); color: var(--text-weak); }
.terminal-point-icon .icon { width: 14px; height: 14px; stroke-width: 2; }
.terminal-point h3 { margin: 0; font: 700 18px/1.25 var(--font-heading); color: var(--text); }
.terminal-point p { margin: 4px 0 0; font: 400 15px/1.5 var(--font-body); color: var(--label-2); }
.terminal-chip { display: inline-block; padding: 0 7px; border-radius: 4px; background: var(--fill); color: var(--text); font: 500 13px/22px var(--font-mono); white-space: nowrap; }
.terminal-guide.is-still .terminal-in, .terminal-examples.is-still .terminal-answer { opacity: 1; transform: none; animation: none; }
.terminal-examples.is-still .terminal-typed::after { content: none; }
@media (hover: hover) and (pointer: fine) {
  .terminal-copy:hover { background: var(--surface); border-color: var(--border-strong); }
  .terminal-again:hover { background: transparent; color: var(--text); }
}
@media (prefers-reduced-motion: reduce) {
  .terminal-in, .terminal-answer { animation: terminal-fade 200ms var(--ease-out) forwards; transform: none; }
  .terminal-typed::after { content: none; }
  .terminal-copy-label { transition: opacity 200ms var(--ease-out); }
  .terminal-copy[data-copy="swap"] .terminal-copy-label { filter: none; }
}

/* Email Company in «Fuentes» (Fase 93, emailContextCard() in app.js): its row, with Company's flower on its dark square
   as the head of the rail has it, and under it, in line with its name, sub-rows of 32px since Fase 150d (.sub-row, where a box
   and paragraphs were): «Address», the address plain in the grey of its line since Fase 150e, as the number of iMessage is,
   where it was a grey chip — on one line, cut short where a phone is narrower than it: «Copy» copies it whole — and the small
   «Copy» in the column of the card's controls; «Email goes to» with its menu in that column; and «Addresses I send from», under
   it a sub-row for each since Fase 150e, as the accounts of Gmail are, where each was a line of 28px (.account-row): the
   address, cut short as theirs is, and where it stands in grey in the column of the card's controls; and «Add address» on a
   sub-row of its own. The whole card closes with one line, like a row. */
.email-card { border-bottom: 1px solid var(--line); }
.email-card > .source-row { border-bottom: 0; }
.email-body { display: grid; padding: 0 0 var(--s1) 32px; }
.source-logo .context-mark { padding: 2px; border-radius: var(--radius); background: var(--dark-bg); }
.email-address > .sub-line { overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
.email-space select.field { width: auto; min-width: 0; height: var(--control-sm); }
.email-senders { display: grid; }
.email-senders > .sub-row > .sub-label { display: block; flex: 0 1 auto; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }

/* Calendly in «Fuentes» (Fase 104b, calendlyCard() in app.js): its row, and under it, in line with its name, what to paste in
   a webhook of Calendly's on two sub-rows of 32px since Fase 150c (.sub-row): «Webhook URL», where it goes with its link at the
   end of its line and «Copy URL» in the column of the card's controls; and «Signing key», once in mono in a grey chip — cut
   short where the column is narrower than it — with «Copy», else that it is shown only once. The whole card closes with one
   line, like a row. */
.calendly-card { border-bottom: 1px solid var(--line); }
.calendly-card > .source-row { border-bottom: 0; }
.calendly-body { display: grid; padding: 0 0 var(--s1) 32px; }
.calendly-key-chip { flex: 0 1 auto; min-width: 0; height: 24px; padding: 0 var(--s1); border-radius: var(--radius-pill); background: var(--fill); font: 500 12px/24px var(--font-mono); color: var(--label-2); overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }

/* Your own data in «Fuentes» (Fase 127, dataCard() in app.js): its row, the database on a light disc, and under it, in line
   with its name — «Nothing sent yet.» in the grey of a hint while there is none (Fase 147) —, each dataset the team's code
   sends rows to on a line of 36px — its name, how many rows with the number in its grey chip and
   when the last came, in grey, and its «···» — over its columns folded behind a sub-row (.sub-fold, Fase 150), each a
   line of 28px, its name in mono and what it was read as in grey; a hairline between two datasets. The whole card closes with
   one line, like a row. Its sheet (openDataDialog()): the name and «Create»; then the URL whole in mono with «Copy», in a box
   of its own, and the examples in the dark block of a command with room for «Copy»; and what it asks before a
   key is rotated or a dataset deleted, «Cancel» and the button on the right. Only the tokens of either theme. */
.data-card { border-bottom: 1px solid var(--line); }
.data-card > .source-row { border-bottom: 0; }
.data-body { display: grid; gap: var(--s1); padding: 0 0 var(--s2) 32px; }
.data-body:empty { display: none; }
.data-set { display: grid; gap: 4px; }
.data-set + .data-set { padding-top: var(--s1); border-top: 1px solid var(--line); }
.data-set-head { display: flex; align-items: center; gap: var(--s1); min-height: 36px; }
.data-set-name { flex: none; max-width: 45%; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; font: var(--row-title); color: var(--label); }
.data-set-line { flex: 1; min-width: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; font: var(--row-line); color: var(--label-2); }
.data-columns { display: grid; padding: 4px 0 var(--s1); }
.data-column { display: flex; align-items: baseline; gap: 12px; min-height: 28px; }
.data-column-name { min-width: 0; overflow-wrap: anywhere; font: 500 13px/20px var(--font-mono); color: var(--label); }
.data-column-type { flex: none; font: var(--row-line); color: var(--label-2); }
.data-form .btn { justify-self: end; }
.data-field { display: grid; gap: 4px; }
.data-label { font: var(--row-line); color: var(--label-2); }
.data-url {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 8px 8px 8px var(--s2);
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
  background: var(--surface-2);
}
.data-url-text { flex: 1; min-width: 0; font: 500 13px/20px var(--font-mono); color: var(--label); overflow-wrap: anywhere; }
.dialog .data-sent .code-block .code { padding-right: 88px; }
.data-foot { display: flex; justify-content: flex-end; gap: var(--s1); }
/* The datasets a connector writes, on its card (Fase 147, withDatasets() in app.js): the card as it is, its own closing line
   taken away whatever card it is, and under it, in line with its name, «Datasets» and its chip on a sub-row (.sub-fold, Fase
   150) folded over a dataset each, drawn as one of «Your own data» without its «···» (.data-set). The whole
   block closes with one line, like a row. Only the tokens of either theme. */
.datasets-card { border-bottom: 1px solid var(--line); }
.datasets-card > :first-child { border-bottom: 0; }
.datasets-body { display: grid; gap: var(--s1); padding: 0 0 var(--s2) 32px; }
.datasets-list { display: grid; }

/* «Tu móvil» of «Ajustes»: the country, the rest of the number and «Guardar» on one line, and what was
   refused under them. */
.phone-form { display: flex; flex-wrap: wrap; align-items: center; justify-content: flex-end; gap: var(--s1); }
.phone-form select.field { width: auto; height: var(--control-sm); }
.phone-form input.field { width: 11em; height: var(--control-sm); }
.phone-form .hint { flex-basis: 100%; text-align: right; }

/* Dialog / sheet --------------------------------------------------------- */
.dialog {
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  padding: 0;
  width: min(720px, calc(100vw - var(--s6)));
  max-height: calc(100dvh - var(--s6));
  background: var(--raised);
  color: var(--label);
  box-shadow: var(--shadow);
  overflow: hidden;
}
.dialog-sm { width: min(560px, calc(100vw - var(--s6))); }
.dialog::backdrop { background: var(--backdrop); }
.dialog[open] {
  opacity: 1;
  transform: scale(1);
  transition: opacity var(--t-base) var(--ease-out), transform var(--t-base) var(--ease-out);
}
@starting-style {
  .dialog[open] { opacity: 0; transform: scale(0.95); }
}
.grabber { display: none; }
.dialog-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s2);
  padding: var(--inset) var(--inset) 0;
}
.dialog-head h2 { margin: 0; font: var(--subtitle-app); letter-spacing: -0.02em; }
.close {
  flex: none;
  width: var(--control-sm);
  height: var(--control-sm);
  border: 0;
  border-radius: var(--radius);
  background: transparent;
  color: var(--label-2);
  display: grid;
  place-items: center;
  cursor: pointer;
}
.close .icon { width: 18px; height: 18px; }
@media (hover: hover) and (pointer: fine) {
  .close:hover { background: var(--fill); color: var(--label); }
}
.dialog-body {
  padding: var(--inset);
  display: grid;
  gap: var(--s2);
  max-height: calc(100dvh - 240px);
  overflow: auto;
}
.dialog-body > p { margin: 0; font: var(--small); color: var(--label); }
.dialog-body > .hint { font: var(--footnote); color: var(--label-2); }
.dialog-body textarea {
  width: 100%;
  min-height: 200px;
  padding: var(--s2);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  color: var(--label);
  font: var(--body);
  line-height: 24px;
  resize: vertical;
  -webkit-appearance: none;
  appearance: none;
}
.dialog-body textarea:focus { outline: 2px solid var(--tint); outline-offset: 0; }
.dialog-body textarea::placeholder { color: var(--label-3); }
/* Como qué se va a guardar, y el único modo de llevarle la contraria. */
.detect { display: flex; align-items: center; flex-wrap: wrap; gap: var(--s1); margin: 0; font: var(--footnote); color: var(--label-2); }
.detect select {
  height: var(--control-sm);
  padding: 0 var(--s1);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  color: var(--label);
  font: var(--footnote);
}
/* «@» in the box (Fase 115, mentionPicker() in app.js): right under it, 8px from it, in a hairline box of its corners, the
   members a row each of 36px — 40px on a phone, as the rows of a menu —: their face of 20px and their whole name in 14px of
   the colour of the text; the one the arrows are on, and the one under the pointer, on the quiet fill. */
.mention-picker { display: grid; margin-top: calc(var(--s1) * -1); padding: 4px; border: 1px solid var(--line); border-radius: var(--radius); background: var(--surface); }
.mention-option { display: flex; align-items: center; gap: var(--s1); min-height: 36px; padding: 0 var(--s1); border-radius: var(--radius); font: 400 14px/20px var(--font-body); color: var(--label); cursor: pointer; }
.mention-option[aria-selected="true"] { background: var(--fill); }
.mention-name { min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
@media (hover: hover) and (pointer: fine) {
  .mention-option:hover { background: var(--fill); }
}
.dialog-foot {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: center;
  gap: var(--s2);
  padding: 0 var(--inset) var(--inset);
}
.dialog-foot .left, .dialog-foot .right { display: flex; align-items: center; gap: var(--s1); }
/* Claude Code's token in its dialog (Fase 144; the command of the skill's installer until then): the dark block of brand.md §7,
   «Copy» over it. Scoped to .dialog because landing.html styles a .code-block of its own. The padding is the room «Copy» needs. */
.dialog .code-block { position: relative; }
.dialog .code-block .code { padding-right: 88px; }
.dialog .code-copy {
  position: absolute;
  top: var(--s1);
  right: var(--s1);
  background: transparent;
  border-color: rgba(248, 248, 242, 0.24);
  color: var(--dark-text);
}
@media (hover: hover) and (pointer: fine) {
  .dialog .code-copy:hover { background: rgba(248, 248, 242, 0.12); }
}
/* «Nuevo espacio…»: the name, what went wrong with it — the dot of .hint.err before grey words (Fase 95) —, and «Crear»
   at the end. */
.space-form .btn { justify-self: end; }
/* «Reportar un fallo» (Fase 77b, openFeedback() in app.js): a small sheet — what happened, «Include what I was looking at»
   with the checkbox of Fase 68 drawn under a real input, «Send» on the right and, under it, the line of what went wrong —,
   by the tokens of both themes. */
.feedback-form textarea { min-height: 120px; }
.feedback-include { position: relative; display: flex; align-items: center; gap: var(--s1); justify-self: start; font: var(--small); color: var(--label); cursor: pointer; }
.feedback-include input { position: absolute; top: 0; left: 0; width: 16px; height: 100%; margin: 0; opacity: 0; cursor: pointer; }
.feedback-include input:focus-visible + .check-box { outline: 2px solid var(--tint); outline-offset: 2px; }
.feedback-form .btn { justify-self: end; }
.feedback-form > .hint.err { text-align: right; }
/* «Borrar cuenta» (Fase 80c, deleteAccountButton() and openDeleteAccount() in app.js): the last of «Ajustes», red words with
   no box, underlined under the pointer as «Salir del espacio»; and in its sheet, under the box DELETE is typed in and the
   line of what deleted nothing, «Cancel» and the red «Delete account» on the right — by the tokens of both themes. */
.delete-account { padding: 0; border: 0; background: none; color: var(--danger); font: var(--row-title); cursor: pointer; }
@media (hover: hover) and (pointer: fine) {
  .delete-account:hover { text-decoration: underline; text-underline-offset: 2px; }
}
.delete-account-foot { display: flex; justify-content: flex-end; gap: var(--s1); }

/* The bar over the list while rows are selected (Fase 68, renderSelectionBar() in app.js): in the rail, under the
   chips, as quiet as they are — the ✕, how many and the «···»; the three answers of «Visible to», each its icon and a
   word; and, once one was chosen, how many of the selected it changed, in one line —, in the tokens of both themes. */
.selection-bar {
  flex: none;
  display: grid;
  gap: 6px;
  margin: 0 var(--s1) var(--s1);
  padding: 4px 4px 8px;
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
  background: var(--surface);
}
.selection-head { display: flex; align-items: center; gap: 4px; }
.selection-head .icon-btn { width: 28px; height: 28px; }
.selection-count { flex: 1; min-width: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; font: var(--small-label); color: var(--label); }
.selection-share { display: flex; flex-wrap: wrap; gap: 4px; padding: 0 4px; }
.selection-share .btn { height: 28px; padding: 0 10px; gap: 6px; font: 500 12px/1 var(--font-body); }
.selection-share .icon { width: 14px; height: 14px; }
.selection-result { margin: 0; padding: 0 8px; font: var(--row-time); color: var(--label-2); }

/* Toasts ----------------------------------------------------------------- */
.toasts {
  position: fixed;
  top: calc(var(--s3) + var(--safe-t));
  right: calc(var(--s3) + var(--safe-r));
  display: grid;
  gap: var(--s1);
  z-index: 30;
  max-width: min(440px, calc(100vw - var(--s6)));
}
/* The accent, inverted with the theme: near-black on white, #f5f4f0 with dark text on the dark theme. */
.toast {
  padding: var(--s2);
  border-radius: var(--radius-md);
  background: var(--primary);
  color: var(--on-primary);
  font: var(--callout);
  box-shadow: var(--shadow);
  opacity: 1;
  transform: translateY(0);
  transition: opacity var(--t-base) var(--ease-out), transform var(--t-base) var(--ease-out);
}
@starting-style {
  .toast { opacity: 0; transform: translateY(-8px); }
}
/* A failure (Fase 95, toastNode() in app.js), calm: on the raised surface of the theme with a hairline, the dot of
   --danger before its words in the colour of the text, and its action — «Retry» — after them, a button that reads as the
   links of a toast. 6 s in the corner (ERROR_TOAST_MS). */
.toast.err { display: flex; align-items: baseline; gap: var(--s1); border: 1px solid var(--line); background: var(--raised); color: var(--label); }
.toast.err > .error-dot { align-self: center; }
.toast-text { flex: 1; min-width: 0; }
.toast-button { flex: none; padding: 0; border: 0; background: none; color: inherit; font: inherit; font-weight: 600; text-decoration: underline; text-underline-offset: 2px; cursor: pointer; }
/* A word in the corner that is there to be tapped (Fase 59, noticeDecisions() in app.js): a toast that is a button. */
.toast-action { border: 0; text-align: left; cursor: pointer; }
@media (hover: hover) and (pointer: fine) {
  .toast-action:hover { text-decoration: underline; text-underline-offset: 2px; }
}
/* «Open» after «Thanks, we got it» (Fase 77b, thankForReport() in app.js): a link in the colour of the toast's words. */
.toast a { color: inherit; font-weight: 600; text-decoration: underline; text-underline-offset: 2px; }
/* «Undo» after «+1 669 278 4158 is Ariel now» (Fase 81, assignNumber() in app.js): a button that reads as that link. */
.toast-undo { padding: 0; border: 0; background: none; color: inherit; font: inherit; font-weight: 600; text-decoration: underline; text-underline-offset: 2px; cursor: pointer; }
.toast-undo:disabled { opacity: 0.6; cursor: default; }

/* Files dragged over the page (Fase 36, dropLayer in app.js and onboarding.html): the backdrop of the
   dialogs over all of it, and in the middle a dashed card that says where they go. Nothing in the layer
   takes the pointer but the layer itself, so that it is left only when the files leave the window.
   Over the toasts; the dialogs, in the top layer, keep it away (app.js). */
.drop-layer {
  position: fixed;
  inset: 0;
  z-index: 40;
  display: grid;
  place-items: center;
  padding: var(--s3);
  background: var(--backdrop);
  opacity: 1;
  transition: opacity var(--t-fast) var(--ease-out);
}
@starting-style {
  .drop-layer { opacity: 0; }
}
.drop-layer * { pointer-events: none; }
.drop-card {
  display: grid;
  justify-items: center;
  gap: var(--s2);
  width: min(440px, 100%);
  padding: var(--s6) var(--s4);
  border: 2px dashed var(--border-strong);
  border-radius: var(--radius-lg);
  background: var(--raised);
  color: var(--label);
  box-shadow: var(--shadow);
  text-align: center;
}
.drop-card .icon { width: 32px; height: 32px; color: var(--label-2); }
.drop-text { margin: 0; font: var(--subtitle-app); letter-spacing: -0.02em; }

/* A popover grows from its control (Fase 144, emil-design-eng): from 0.95 and transparent, never from nothing, its
   transform-origin set by placePopover() in app.js to the side of the control it hangs from. */
@starting-style {
  .popover { opacity: 0; transform: scale(0.95); }
}

/* Loading (Fase 95, skeleton() and loadingLine() in app.js) ---------------
   What waits for data paints the shape of what it waits for, in grey: bars 6px round on the quiet fill, a shimmer of the
   colour of a line crossing them every 1.4 s, and rows as tall as the real ones — 52px a row of the list of two lines, 36
   one of What's new, 32 one of «Tasks», the --row-h of the rows of «Fuentes», «Pages», «Equipo» and «Ajustes» —, so that
   nothing jumps when they come. Under the head of its view, one line of 12px in the lightest grey says what is loading,
   with three dots that move. Both stay out of sight for their first 150 ms: what comes sooner never shows them. */
.sk, .loading-line { animation: sk-appear 0s linear 150ms both; }
@keyframes sk-appear {
  from { visibility: hidden; }
  to { visibility: visible; }
}
.sk { display: grid; gap: 10px; }
.sk-line, .sk-icon, .sk-avatar, .sk-face, .sk-logo, .sk-time {
  /* motion: explains — still loading */
  display: block;
  border-radius: 6px;
  background: linear-gradient(90deg, var(--fill) 0%, var(--line) 40%, var(--fill) 80%);
  background-size: 200% 100%;
  animation: shimmer 1.4s linear infinite;
}
@keyframes shimmer {
  from { background-position: 100% 0; }
  to { background-position: -100% 0; }
}
.sk-line { height: 12px; }
.sk-title { height: 20px; }
.sk-avatar, .sk-face, .sk-logo { flex: none; border-radius: var(--radius-pill); }
.sk-time { width: 32px; height: 10px; }
/* An empty box, and a ghost button: their lines alone. */
.sk-box { flex: none; width: 16px; height: 16px; border: 1px solid var(--line); border-radius: 5px; }
.sk-button { flex: none; width: 72px; height: var(--control-sm); border: 1px solid var(--line); border-radius: var(--radius); }
/* The head of an entry or a page, then its paragraphs, as far apart as the sections of an entry. */
.sk-head { gap: var(--s1); }
.sk-paragraphs { gap: var(--s3); }
.sk-paragraph { display: grid; gap: 10px; }
.detail > .loading-line { margin-top: var(--s2); }
.detail > .sk-paragraphs { margin-top: var(--s4); }
/* The list of the rail: a day heading, then rows of two lines, 52px — the square of an icon of 18px on the axis of the
   first line, a title, and on the right the hour and under it the circle of a face —, under the line that says it is
   loading. */
.sk-list { gap: 0; }
.sk-day { display: flex; align-items: center; height: 20px; padding: 0 var(--s1) 4px; }
.sk-row { display: grid; grid-template-columns: var(--row-icon) minmax(0, 1fr) auto; column-gap: 10px; align-items: start; min-height: var(--row-h); padding: var(--row-pad); }
.sk-row > .sk-icon { width: var(--row-icon); height: var(--row-icon); margin-top: 1px; border-radius: 4px; }
.sk-row > .sk-line { margin-top: 4px; }
.sk-side { display: grid; grid-template-rows: var(--row-lh) var(--row-lh); justify-items: end; align-items: center; }
.sk-side > .sk-avatar { width: var(--row-icon); height: var(--row-icon); }
.list-waiting > .loading-line { padding: 0 var(--s1) var(--s1); }
/* The topics of What's new, a card each as .news-topic-head is: a title, three lines and a foot, a hairline between two. */
.sk-cards { gap: 0; }
.sk-card { display: grid; gap: 10px; padding: 12px 10px 12px 20px; }
.sk-card + .sk-card { border-top: 1px solid var(--line); }
/* The rows of What's new, 36px as .news-main: a face, a line and the hour. */
.sk-news { gap: 0; }
.sk-news-row { display: grid; grid-template-columns: 20px minmax(0, 1fr) auto; align-items: center; column-gap: 10px; min-height: 36px; padding: 8px 10px 8px 20px; }
.sk-news-row > .sk-avatar { width: 20px; height: 20px; }
/* The members of a menu (Fase 148d, who answers a number of Quo's), as tall as its items: a face of 20px and a bar. */
.sk-people { gap: 0; }
.sk-person { display: flex; align-items: center; gap: 8px; min-height: 32px; padding: 6px 10px; }
.sk-person > .sk-avatar { width: 20px; height: 20px; }
/* The rows of «Tasks», 32px as .task-row: an empty box on the edge of the column and what is to be done 10px from it, where
   the rows of the page have theirs (Fase 106, --task-indent). */
.sk-tasks { gap: 0; }
.sk-task { display: flex; align-items: center; gap: 10px; min-height: 32px; padding-left: 0; }
/* The rows of «Fuentes», «Pages», «Equipo» and «Ajustes», as .source-row: a logo or a face, two bars, and on the right the
   state of a row of «Fuentes» or a ghost button. */
.sk-sources, .sk-pages, .sk-members, .sk-settings { gap: 0; border-top: 1px solid var(--line); }
.sk-item { display: flex; align-items: center; gap: 12px; min-height: var(--row-h); padding: 10px 0; border-bottom: 1px solid var(--line); }
.sk-item > .sk-logo { width: 20px; height: 20px; }
.sk-item > .sk-face { width: 24px; height: 24px; }
.sk-text { flex: 1; min-width: 0; display: grid; gap: 6px; }
/* The right of a row of «Fuentes» (Fase 150): its slot over when it last brought something, two bars on its right edge. */
.sk-state { flex: none; display: grid; justify-items: end; gap: 8px; width: 112px; }
/* The result of a SOP (Fase 125, sopResult()): the line of its caption, the picture as wide as the column in the shape of one,
   8px round, and its thumbnails of 56px. */
.sk-viewer { gap: 12px; }
.sk-viewer .sk-picture { height: auto; aspect-ratio: 16 / 10; border-radius: var(--radius-md); }
.sk-thumbs { display: flex; gap: var(--s1); }
.sk-viewer .sk-thumb { flex: none; width: 56px; height: 56px; border-radius: var(--radius); }
.detail > .sk-viewer { margin-top: var(--s4); }
/* An iPhone's photo in the line of its message while its JPEG is made (Fase 138, heifImage()): the shape of a photo taken
   standing, 8px round, as tall as a photo in its line is at most (.media-thumb img), so that nothing under it moves when it
   comes. */
.sk-photo .sk-picture { width: 240px; max-width: 100%; height: 320px; border-radius: var(--radius-md); }
.loading-line { margin: 0; font: 400 12px/16px var(--font-body); color: var(--label-3); }
.loading-line::after {
  /* motion: explains — still loading */
  content: "";
  display: inline-block;
  width: 1.2em;
  text-align: left;
  animation: ellipsis 1.2s steps(4, end) infinite;
}
@keyframes ellipsis {
  0% { content: ""; }
  25% { content: "."; }
  50% { content: ".."; }
  75% { content: "..."; }
}

/* Failing calmly (Fase 95, errorBlock(), errorLine() and toast() in app.js) ---------------
   A view that could not load says it in its place, centred, 360px at most: the icon of why in the lightest grey, what did
   not load in 600 14px, why in 13px of the middle grey — and that nothing was lost —, «Try again», and «Report this» in
   words for the server's trouble. A row says it on its line: a dot of 6px of --danger, the words in the grey of the line,
   and its action on its right. The red is that dot, and nothing else. */
.error-block { display: grid; justify-items: center; gap: 4px; width: 100%; max-width: 360px; margin: var(--s6) auto; padding: 0 var(--s2); text-align: center; }
.error-icon { display: grid; place-items: center; margin-bottom: var(--s1); color: var(--label-3); }
.error-icon .icon { width: 20px; height: 20px; }
.error-title { margin: 0; font: 600 14px/20px var(--font-body); color: var(--label); }
.error-why { margin: 0; font: 400 13px/18px var(--font-body); color: var(--label-2); overflow-wrap: anywhere; }
.error-actions { display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: var(--s2); margin-top: 12px; }
.error-actions:empty { display: none; }
.error-report { font: 500 13px/20px var(--font-body); color: var(--label-2); }
.error-dot { flex: none; display: inline-block; width: 6px; height: 6px; border-radius: var(--radius-pill); background: var(--danger); }
.error-line { display: inline-flex; align-items: baseline; gap: 6px; min-width: 0; }
.error-line > .error-dot { align-self: center; }
.error-line > .err { color: var(--label-2); }
.error-row { display: flex; align-items: center; justify-content: space-between; gap: var(--s2); font: var(--row-line); color: var(--label-2); }
.timeline-inner > .error-row { padding: 0 var(--s1) var(--s1); }

/* The band over the app while the browser has no network (Fase 95, #offline-band of index.html): thin and quiet, on the
   fill of the theme with a hairline under it; the app under it a band shorter, so that nothing of it goes under the band. */
.offline-band { display: flex; align-items: center; justify-content: center; gap: var(--s1); height: 28px; padding: 0 var(--s2); border-bottom: 1px solid var(--line); background: var(--fill); font: 500 12px/16px var(--font-body); color: var(--label-2); }
.offline-band .icon { width: 14px; height: 14px; }
body:has(> .offline-band:not([hidden])) .app { height: calc(100vh - 28px); height: calc(100dvh - 28px); }

/* Two logos in the room of one (Fase 95, mcpRow() in app.js): ChatGPT's, and Claude's over its corner, cut out of it by
   a ring of the page. */
.logo-pair { position: relative; display: block; width: 20px; height: 20px; }
.logo-pair img { position: absolute; width: 14px; height: 14px; }
.logo-pair img:first-child { top: 0; left: 0; }
.logo-pair img:last-child { right: 0; bottom: 0; border-radius: var(--radius-pill); background: var(--surface); box-shadow: 0 0 0 1.5px var(--surface); }

/* The gallery of the states of Fase 95, at '/?states' (paintStates() in app.js): its own layout, a sample of each piece
   in a box with its name over it. Every piece in it is styled by the rules above, as it is in the app. */
.states { display: grid; gap: var(--s5); max-width: 960px; margin: 0 auto; padding: var(--s4) var(--s3) var(--s8); }
.states-head { display: flex; align-items: center; justify-content: space-between; gap: var(--s2); }
.states-head h1 { margin: 0; font: var(--title-app); color: var(--label); }
.states-section { display: grid; gap: var(--s2); }
.states-section > h2 { margin: 0; font: var(--code); color: var(--label-2); }
.states-sample { display: grid; gap: var(--s1); padding: var(--s2); border: 1px solid var(--line); border-radius: var(--radius-md); }
.states-label { margin: 0; font: var(--code); color: var(--label-3); }
.states-rail { width: var(--rail-w); }
.states-logos { display: grid; gap: 4px; }
.states-logo-row { display: grid; grid-template-columns: 200px repeat(5, 32px); align-items: center; }
.states-logo { display: grid; place-items: center; color: var(--label-2); }
.states-logo > .icon { width: var(--size); height: var(--size); }

/* Under prefers-reduced-motion only fades are left (Fase 144, emil-design-eng: fewer and gentler, not none): a dialog, a menu,
   a toast and the bar of a head fade in their place, without growing, rising or sliding; a button still fades its fill; and
   nothing a finger presses gives under it. What only fades already — the layer of dropped files, the scrollbars, the edge of
   the rail — stays as it is. The sheet of a phone, in the block of narrow screens. */
@media (prefers-reduced-motion: reduce) {
  .dialog[open], .popover, .toast { transition: opacity var(--t-fast) var(--ease-out); }
  .head-bar { transform: none; transition: opacity var(--t-fast) var(--ease-out), visibility 0s linear var(--t-fast); }
  .btn { transition: opacity var(--t-fast) var(--ease-out), background-color var(--t-fast) var(--ease-out); }
  .btn:active, .icon-btn:active, .close:active, .type-chip:active, .chip:active, .name-btn:active, .new-entries:active, .ask-send:active, .audio-toggle:active, .help:active, .sop-thumb:active, .sop-file-remove:active, .nav-row:active, .space-switcher:active, .me:active { transform: none; }
  .sop-arrow:active { transform: translateY(-50%); }
  /* The grey of what is loading, without its shimmer or its dots (Fase 95). */
  .sk-line, .sk-icon, .sk-avatar, .sk-face, .sk-logo, .sk-time { animation: none; }
  .loading-line::after { animation: none; content: none; }
}

/* Narrow screens: sheet dialog, single pane ------------------------------- */
@media (max-width: 880px) {
  .app { grid-template-columns: 1fr; }
  .rail-resizer { display: none; }
  .pane { display: none; padding-left: var(--safe-l); }
  .app.show-pane .pane { display: block; }
  .app.show-pane .rail { display: none; }
  .back { display: inline-flex; }
  .detail, .page, .ask { padding: calc(var(--s3) + var(--safe-t)) var(--s2) 96px; }
  /* The back button sits in the grid of the ask panel: at its own width, not stretched across. */
  .ask .back { justify-self: start; margin-bottom: 0; }
  /* Its greeting smaller (Fase 82), and the line under it on as many lines as it takes. */
  .ask-greeting { font-size: 32px; }
  .ask-news-text { white-space: normal; }
  /* The brief of What's new from edge to edge (Fase 82b), its words where the page's are. */
  .news-brief { margin: 0 calc(var(--s2) * -1); padding-inline: var(--s2); border-radius: 0; }
  /* Its tabs keep their 24px and take a thumb's worth of room over and under them (Fase 87), and so does «Expand all» (Fase
     94); «+7 more» is as tall as a button. */
  .news-tab { position: relative; }
  .news-tab::after { content: ""; position: absolute; inset: -6px 0; }
  .news-expand { position: relative; }
  .news-expand::after { content: ""; position: absolute; inset: -6px 0; }
  .news-more { height: 36px; }
  /* A key of «Keys» (Fase 84b) on two lines when its row does not hold all of it: its name over who and when, and the
     faces of who pulled it without their words. */
  .keys-row { flex-wrap: wrap; row-gap: 4px; padding: 6px 0; }
  .keys-pulled-label { display: none; }
  .detail-head { grid-template-columns: minmax(0, 1fr) auto; }
  .detail-icon { display: none; }
  /* Without the icon's column, the third line of the head runs from the left edge. */
  .detail-people { grid-column: 1 / -1; }
  /* The bar of a head (Fase 139) under the status bar of a phone, and as the head without its icon: the way back first instead,
     the one that scrolled away with the head, and «Visible to» its faces alone, which leave the title its room. */
  .head-bar { min-height: calc(var(--s6) + var(--safe-t)); padding: calc(4px + var(--safe-t)) var(--s2) 4px; }
  .head-bar-back { display: inline-grid; }
  .head-bar-icon { display: none; }
  .head-bar .visible-label { display: none; }
  .log-row { grid-template-columns: 1fr; gap: 0; }
  .dialog {
    width: 100vw;
    max-width: 100vw;
    max-height: calc(100dvh - var(--s6));
    margin: auto 0 0;
    border: 0;
    border-radius: var(--radius-lg) var(--radius-lg) 0 0;
    box-shadow: none;
  }
  .dialog[open] {
    transform: translateY(0);
    transition: transform var(--t-sheet) var(--ease-drawer), opacity var(--t-sheet) var(--ease-drawer);
  }
  @starting-style {
    .dialog[open] { transform: translateY(100%); opacity: 1; }
  }
  /* Under prefers-reduced-motion the sheet fades in where it rests (Fase 144): this block comes after the one of reduced motion,
     and without these its slide came back. */
  @media (prefers-reduced-motion: reduce) {
    .dialog[open] { transition: opacity var(--t-sheet) var(--ease-out); }
    @starting-style {
      .dialog[open] { opacity: 0; }
    }
  }
  .grabber {
    display: block;
    width: var(--s5);
    height: 4px;
    border-radius: var(--radius-pill);
    background: var(--line);
    margin: var(--s1) auto 0;
  }
  .dialog-head { padding-top: var(--s2); }
  .dialog-body { max-height: calc(100dvh - 232px); }
  .dialog-foot { padding-bottom: calc(var(--inset) + var(--safe-b)); }
  /* The sheets without a foot (Claude Code, «Nuevo espacio») end above the home indicator too. */
  .dialog-body:last-child { padding-bottom: calc(var(--inset) + var(--safe-b)); }
  .toasts { left: var(--s3); right: var(--s3); max-width: none; }
  /* Thumb-sized (Fase 16b): 40 px for what is only an icon, for the way back and for the rail's space,
     «Nueva entrada» and sections (Fase 17), 36 px for the other buttons, 40 px rows in the menus. */
  .icon-btn, .close { width: 40px; height: 40px; }
  /* Play and pause of an audio of a chat too (Fase 64). */
  .audio-toggle { width: 40px; height: 40px; }
  /* The × of the iPhone app's card too: its icon stays small, and the card is tall enough for it. So is the
     one of the iMessage card, and its chips and «Name» take a thumb too. */
  .ios-card .icon-btn, .line-card .icon-btn { width: 40px; height: 40px; margin-right: 0; }
  .line-card .btn-sm, .chip { height: 36px; }
  .which-one-skip { line-height: 36px; }
  .name-btn { line-height: 26px; }
  /* «Borrar cuenta» at the end of «Ajustes» (Fase 80c): red words, as tall as a button. */
  .delete-account { line-height: 36px; }
  .btn-sm { height: 36px; }
  .visible-row { min-height: 36px; }
  /* The bar of a selection takes a thumb too (Fase 68). */
  .selection-head .icon-btn { width: 40px; height: 40px; }
  .selection-share .btn { height: 36px; }
  .back, .space-switcher, .rail .btn-new, .nav-row { height: 40px; }
  .setting-row select.field { height: 36px; }
  .menu-item { padding: 10px 12px; }
  /* Who answers a number of Quo's takes a thumb too (Fase 148d), and the rows in grey of its menu are as tall as its items. */
  .quo-answerer { height: 36px; }
  /* So does who a login of GitHub is (Fase 131b). */
  .github-person-choice { height: 36px; }
  .sk-person { min-height: 40px; padding: 10px 12px; }
  /* So are the members an @ offers in «New entry» (Fase 115). */
  .mention-option { min-height: 40px; }
  .ask-send { right: 8px; bottom: 8px; width: 36px; height: 36px; }
  /* «New question» (Fase 86), of 40px as every icon alone, on the left of it; and a row of «Tasks» as tall as a thumb. */
  .ask-new { right: 44px; bottom: 6px; }
  .ask-field:has(.ask-new:not([hidden])) .ask-input { padding-right: 88px; }
  .task-row { min-height: 40px; }
  .task-row .task-check { height: 40px; }
  /* Words that are buttons and the chips over the list take a thumb's worth of room around them without growing (Fase 144, Web
     Interface Guidelines: 44px on a phone), where nothing else is pressed beside them: «Leave the space», alone in its row, 44px;
     «Show transcript», 36px — the 8px between it and the transcript, no more —; the chips, up and down only, inside the box that
     scrolls them. Not what floats over rows («3 new entries») nor the words of a task, whose neighbours are pressed too. */
  .fold, .leave, .type-chip { position: relative; }
  .leave::after { content: ""; position: absolute; inset: -12px -4px; }
  .fold::after { content: ""; position: absolute; inset: -8px -4px; }
  .type-chip::after { content: ""; position: absolute; inset: -8px 0; }
  /* The history of a task (Fase 114d): a phone has no tooltip, so what happened wraps rather than being cut. */
  .story-text { white-space: normal; }
  /* The «?» of «Ajustes» keeps its size and takes a thumb's worth of room around it. */
  .help { position: relative; }
  .help::after { content: ""; position: absolute; inset: -12px; }
  /* 16 px in every box one types in: below that, Safari on the iPhone zooms the page on focus. */
  .search input, .field, .ask-input, .conversation-name, .detect select { font-size: 16px; }
  .phone-form select.field, .phone-form input.field { height: 36px; }
  /* «Email goes to» of Email Company (Fase 93), and its «Add address», take a thumb too. */
  .email-space select.field { height: 36px; }
  button.add-account { min-height: 36px; }
  /* The editor of a SOP v2 (Fase 130): its style — and since Fase 140 its title — in 16px as every box (.field), and the × of a
     material a thumb's 36px. */
  .sop-style, .sop-title-box { font-size: 16px; }
  .sop-file-remove { width: 36px; height: 36px; margin: 0 -12px 0 -8px; }
  /* Who has a lead and its next step take a thumb too (Fase 117), in 16px as every box (.field). */
  .lead-owner-select, .lead-next-input, .lead-next-day { height: 36px; }
  /* The company of a lead takes a thumb too (Fase 112), in 16px as every box (.field). */
  .lead-company-input { height: 36px; }
  /* And so does its address (Fase 148f). */
  .lead-email-input { height: 36px; }
  /* The stage of a lead (Fase 104), its value and its period take a thumb too, and its stage is in 16px as every box. */
  .lead-stage-select { height: 36px; font-size: 16px; }
  .lead-amount, .lead-period { height: 36px; }
}

/* Overflow guards: grid and flex children default to min-width:auto ------- */
.rail, .pane { overflow-x: hidden; }
.page > *, .detail > *, .ask > * { min-width: 0; }

.more { display: flex; justify-content: center; padding: var(--s2) 0 var(--s1); }
.timeline-inner > .hint { padding: 0 var(--s1); }

/* Legal pages ------------------------------------------------------------- */
/* privacy.html and terms.html: one screen of text with the landing's nav. They
   have no <style> of their own, so the rules live here instead of twice. */
.legal-page { height: auto; }
.legal-wrap { max-width: var(--max-w); margin: 0 auto; border-inline: 1px solid var(--border); }
.legal-nav {
  display: flex;
  align-items: center;
  justify-content: space-between;
  height: var(--nav-h);
  padding: 0 var(--s3);
  border-bottom: 1px solid var(--border);
}
.legal-nav .wordmark { font: var(--h3); color: var(--ink); gap: 5px; letter-spacing: -0.045em; }
.legal-nav .wordmark .mark { width: 28px; height: 28px; }
.legal-nav .sign-in { font: var(--small); color: var(--text); }
.legal {
  display: grid;
  gap: var(--s2);
  max-width: var(--content-w);
  margin: 0 auto;
  padding: var(--s8) var(--s3) var(--s12);
}
.legal h2 { margin: 0; font: var(--h2); color: var(--ink); letter-spacing: -0.02em; }
.legal p { margin: 0; font: var(--body); color: var(--text); }
.legal .updated { font: var(--caption); color: var(--text-weak); }
.legal-foot {
  display: flex;
  gap: var(--s2);
  padding: var(--s3) var(--s3) calc(var(--s3) + var(--safe-b));
  border-top: 1px solid var(--border);
  font: var(--caption);
  color: var(--text-weak);
}
.legal-foot a { color: var(--text); }
@media (max-width: 880px) {
  .legal h2 { font: 700 28px/1.1 var(--font-heading); }
  .legal { padding: var(--s6) var(--s3) var(--s8); }
}

/* /admin (Fase 83) ------------------------------------------------------------
   The internal page of Company's own people (public/admin.html and admin.js), which nothing in the app links to: no
   rail, one column of 1100px at most. «Company admin» in 600 15px with who you are on its right; four figures in
   --title-app under their --small-label; the chart of what the AI cost a day, its bars 1px apart, its axes in
   --label-3, and stacked in tones of the text colour (.admin-s1 to .admin-s9), dark and light by turns so that two
   neighbours of a stack stand apart — the ninth, of the pass of evidence of the tasks (Fase 107), 20 or more from the
   eighth under it, from «other» over it and from the first —, with the lightest (.admin-s0) for what is no team's or
   none of the nine functions — never the faces' tints, which are .person-avatar's alone —; tabs as What's new's; and
   tables of rows of 36px, their numbers tabular, the fill under the pointer. Only the tokens of either theme. Whoever
   ADMIN_EMAILS does not name reads «Nothing here.» in --label-3, and nothing else. */
.admin { display: grid; gap: var(--s4); max-width: 1100px; margin: 0 auto; padding: var(--s3); }
.admin-nothing { margin: 0; font: var(--meta); color: var(--label-3); }
.admin-head { display: flex; align-items: center; justify-content: space-between; gap: var(--s2); }
.admin-title { margin: 0; font: 600 15px/20px var(--font-body); color: var(--label); }
.admin-me { font: var(--meta); color: var(--label-2); }
.admin-view { display: grid; gap: var(--s4); min-width: 0; }
.admin-figures { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--s2); }
.admin-figure { display: grid; gap: 4px; min-width: 0; }
.admin-figure-label { font: var(--small-label); color: var(--label-2); }
.admin-figure-value { font: var(--title-app); font-variant-numeric: tabular-nums; color: var(--label); }
.admin-section { display: grid; gap: var(--s2); min-width: 0; }
.admin-section-head { display: flex; align-items: center; justify-content: space-between; gap: var(--s2); min-height: var(--control-sm); }
.admin-section-title { margin: 0; font: 600 13px/20px var(--font-body); color: var(--label); }
.admin-period { font: var(--meta); color: var(--label-3); }
.admin-chart { display: grid; gap: var(--s2); }
.admin-chart-svg { display: block; width: 100%; height: auto; }
.admin-chart-svg rect { shape-rendering: crispEdges; }
.admin-hit { fill: transparent; }
.admin-grid { stroke: var(--line); }
.admin-axis { stroke: var(--label-3); }
.admin-axis-label { fill: var(--label-3); font: 400 11px/1 var(--font-body); font-variant-numeric: tabular-nums; }
.admin-s0 { fill: color-mix(in srgb, var(--label) 12%, transparent); background: color-mix(in srgb, var(--label) 12%, transparent); }
.admin-s1 { fill: color-mix(in srgb, var(--label) 88%, transparent); background: color-mix(in srgb, var(--label) 88%, transparent); }
.admin-s2 { fill: color-mix(in srgb, var(--label) 40%, transparent); background: color-mix(in srgb, var(--label) 40%, transparent); }
.admin-s3 { fill: color-mix(in srgb, var(--label) 70%, transparent); background: color-mix(in srgb, var(--label) 70%, transparent); }
.admin-s4 { fill: color-mix(in srgb, var(--label) 22%, transparent); background: color-mix(in srgb, var(--label) 22%, transparent); }
.admin-s5 { fill: color-mix(in srgb, var(--label) 56%, transparent); background: color-mix(in srgb, var(--label) 56%, transparent); }
.admin-s6 { fill: color-mix(in srgb, var(--label) 30%, transparent); background: color-mix(in srgb, var(--label) 30%, transparent); }
.admin-s7 { fill: color-mix(in srgb, var(--label) 78%, transparent); background: color-mix(in srgb, var(--label) 78%, transparent); }
.admin-s8 { fill: color-mix(in srgb, var(--label) 48%, transparent); background: color-mix(in srgb, var(--label) 48%, transparent); }
.admin-s9 { fill: color-mix(in srgb, var(--label) 68%, transparent); background: color-mix(in srgb, var(--label) 68%, transparent); }
.admin-legend { display: flex; flex-wrap: wrap; gap: var(--s1) var(--s3); margin: 0; padding: 0; list-style: none; font: var(--meta); color: var(--label-2); }
.admin-legend li { display: flex; align-items: center; gap: 6px; }
.admin-swatch { width: 10px; height: 10px; border-radius: 2px; }
.admin-legend-cost { font-variant-numeric: tabular-nums; color: var(--label); }
.admin-empty { margin: 0; font: var(--meta); color: var(--label-2); }
.admin-tabs { display: flex; gap: var(--s2); }
.admin-tab { height: 24px; padding: 0; border: 0; background: none; font: 500 13px/20px var(--font-body); color: var(--label-2); box-shadow: inset 0 -2px 0 transparent; cursor: pointer; }
.admin-tab[aria-selected="true"] { color: var(--label); box-shadow: inset 0 -2px 0 var(--tint); }
.admin-table-wrap { overflow-x: auto; }
.admin-table { width: 100%; border-collapse: collapse; font: 400 13px/20px var(--font-body); color: var(--label); }
.admin-table th { height: 36px; padding: 0 var(--s1); border-bottom: 1px solid var(--line); text-align: left; font: var(--small-label); color: var(--label-2); white-space: nowrap; }
.admin-table td { height: 36px; padding: 0 var(--s1); border-bottom: 1px solid var(--line); white-space: nowrap; }
.admin-table .num { text-align: right; font-variant-numeric: tabular-nums; }
.admin-table a { color: inherit; }
.admin-link { cursor: pointer; }
.admin-clip { display: inline-block; max-width: 240px; overflow: hidden; text-overflow: ellipsis; vertical-align: bottom; }
.admin-person { display: grid; gap: 4px; justify-items: start; }
.admin-share { display: block; height: 4px; border-radius: var(--radius-pill); background: var(--fill); }
.admin-positive { color: var(--connected); }
.admin-negative { color: var(--danger); }
.admin-back { justify-self: start; font: 500 13px/20px var(--font-body); color: var(--label-2); }
.admin-team-head { display: grid; gap: 4px; }
.admin-team-name { margin: 0; font: var(--subtitle-app); color: var(--label); }
.admin-meta { display: flex; flex-wrap: wrap; gap: 4px 12px; margin: 0; font: var(--meta); color: var(--label-2); }
/* Connectors (Fase 91, connectorsTable() in admin.js), in the type of the other tables: a connector's logo as «Fuentes»
   draws it (.source-logo), 8px from its name; «Configured» with the green dot of «Connected», or «Not configured» in the
   lightest grey; how many times it failed in 24 hours in --danger (.admin-negative), a button that reads as the number;
   and its last entry with its time on the right, in the lightest grey. A row that failed opens under it its failures,
   set in under its name, the row and them one block: a line each, what it said as a row of the app says what went wrong
   (.error-line, Fase 95), how many times in a grey chip (.count-chip, Fase 94) and when the last was on the right. The
   red is that number and those dots, and nothing else. */
.admin-connector { display: inline-flex; align-items: center; gap: var(--s1); }
.admin-off { color: var(--label-3); }
.admin-at { color: var(--label-3); white-space: nowrap; }
.admin-entry { display: flex; align-items: baseline; justify-content: space-between; gap: var(--s1); }
.admin-opener { padding: 0; border: 0; background: none; font: inherit; cursor: pointer; }
.admin-table tr:has(+ .admin-errors-row:not([hidden])) > td { border-bottom-color: transparent; }
.admin-table .admin-errors-row > td { height: auto; padding: 0 var(--s1) var(--s1) 36px; white-space: normal; }
.admin-errors { display: grid; margin: 0; padding: 0; list-style: none; }
.admin-error { display: grid; grid-template-columns: minmax(0, 1fr) auto auto; align-items: center; gap: var(--s1); min-height: 28px; overflow-wrap: anywhere; }
/* Models (Fase 108, modelsView() in admin.js): its figures, its table and the line of the last benchmark, a block each,
   24px apart. After what every call would have cost on another model, how far that is from what they did cost, in --meta
   and the lightest grey: never green or red, because a model that costs less may answer worse. */
.admin-models { display: grid; gap: var(--s3); min-width: 0; }
.admin-change { font: var(--meta); color: var(--label-3); }
/* The AI's settings (Fase 111, settingsSection() in admin.js), over the figures of Models and 32px from them: «Default» and
   a row for each function in the rows of 36px of the other tables, each choice the app's .field, 32px tall and as wide as
   its words, 8px from the price of the model chosen in a grey chip (.count-chip) and from what the variables of Vercel say
   of it, in the lightest grey. */
.admin-models-tab { display: grid; gap: var(--s4); min-width: 0; }
.admin-choice { display: inline-flex; align-items: center; gap: var(--s1); }
.admin-choice select.field { width: auto; height: var(--control-sm); }
.admin-env { color: var(--label-3); }
/* Performance (Fase 166, performanceView() in admin.js): its tables 32px apart, in the rows of 36px of the others — the routes of
   24 hours and of 7 days, the statements, the connections —, a route's method in the lightest grey before its template, and a
   statement in the type of code, cut where its column ends. The red is how many took too long (.admin-negative), and nothing else. */
.admin-performance { display: grid; gap: var(--s4); min-width: 0; }
.admin-method { color: var(--label-3); }
.admin-query { max-width: 560px; font: 400 12px/20px var(--font-mono); color: var(--label-2); }
/* The bar of People is the fill too: under the pointer, on a row of that fill, it takes the grey of the axes. The failures
   of a connector are no row to point at, and their chips are that fill. */
@media (hover: hover) and (pointer: fine) {
  .admin-table tbody tr:hover { background: var(--fill); }
  .admin-table tbody tr:hover .admin-share { background: var(--label-3); }
  .admin-table tbody tr.admin-errors-row:hover { background: none; }
  .admin-tab:hover, .admin-back:hover { color: var(--label); }
}

/* Dashboards (Fase 128, and since Fase 134 the scene of the landing, docs/company-landing/mock-body.html; dashboardsPage(),
   composerView(), sourcesLine(), dashboardPage() and playScene() in app.js) ------------------------------------------------
   «Dashboards», the last tab of «Pages»: Ask's box (.ask-field) on top, 8px closer to the tabs than the list is, as «New SOP»'s
   button was, and under it, 12px down, the variables it offers — its suggestions (.suggestion), each with the logo or icon of
   where it comes from at 16px, and in the whole catalog, under the box or hanging from «Add» in a popover of 380px whose rows
   scroll, under the name of its source in the small capitals of Today's headings, with its dataset in a grey chip (.count-chip)
   of the mono type —; then a row each as the rows of «Pages» (.page-row). The line of what was found: a chip each as a cite
   (.cite), 28px, its logo of 14px, its name and how much in a grey chip, 6px apart. The page of one is wider than a page of text,
   1120px, and as tight as the landing's window, 12px between its parts: Ask's box as wide as the page, what the AI is doing under
   it; the sources it reads; its head — its title, which a click edits, and on its right the period, one segmented control of the
   hairline whose choice is on the quiet fill, «Add» and the «···» —; then a grid of three columns 16px apart, where a number beside
   a line is the landing's 1fr 2fr — one column on a phone —, the cards of a row as tall as each other, each a card of the hairline
   and the large radius, 16px inside, as wide as it says (data-w): its name in 600 13px of the colour of the text with its «···»,
   and under it its number in the heading type, 32px, with how it moved under it in a grey chip — green up, --danger down —; its
   line in tones of the colour of the text, the first the darkest, over the area under it in the faintest tone; its bars from the
   axis in the middle grey and the last in the colour of the text, their corners round, rising from the axis as they come in; the
   axis a hairline, and what the charts say — the days, the last value, the value over a bar — in 500 11px of the middle grey; its
   bars across in the colour of the text on the quiet fill; its table, rows of 28px. The tokens of either theme, and no colour of
   their own. */
.dash-ask { display: grid; }
.dashboards-page > .dash-ask { margin-top: calc(var(--s1) * -1); }
.dash-ask-state:not(:empty) { margin-top: var(--s1); }
.dash-offer { display: grid; gap: 12px; margin-top: 12px; }
.dash-offered { display: grid; }
.dash-offer > .dash-waiting { display: grid; gap: 12px; }
.dash-metric { display: flex; align-items: center; gap: 10px; min-width: 0; }
.dash-metric-icon { flex: none; display: grid; place-items: center; width: 16px; height: 16px; color: var(--label-2); }
.dash-metric-icon .icon { width: 16px; height: 16px; }
.dash-metric-label { flex: 1; min-width: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
.dash-metric-dataset { max-width: 40%; overflow: hidden; text-overflow: ellipsis; font: 500 11px/20px var(--font-mono); }
.dash-catalog { display: grid; gap: var(--s1); }
.dash-catalog-rows { display: grid; gap: var(--s1); }
.dash-catalog-group { display: grid; }
.dash-catalog-source { margin: 0; padding: var(--s1) var(--s2) 4px; font: 500 11px/16px var(--font-body); letter-spacing: 0.06em; text-transform: uppercase; color: var(--label-3); }
.dash-catalog-popover { width: min(380px, calc(100vw - 16px)); padding: var(--s1); }
.dash-catalog-popover .dash-catalog-rows { max-height: min(420px, 60vh); overflow-y: auto; }
.dash-none { display: grid; justify-items: start; gap: var(--s1); }
.sources-line { display: flex; flex-wrap: wrap; gap: 6px; }
.sources-chip { display: inline-flex; align-items: center; gap: 6px; height: 28px; padding: 0 4px 0 10px; border: 1px solid var(--line); border-radius: var(--radius-pill); background: var(--surface); font: 400 13px/1 var(--font-body); color: var(--label); }
.sources-chip-icon { flex: none; display: grid; place-items: center; width: 14px; height: 14px; color: var(--label-2); }
.sources-chip-icon .icon { width: 14px; height: 14px; }
.sources-chip-name { max-width: 240px; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
.page.dashboard-page { max-width: 1120px; gap: 12px; }
.dash-body { display: grid; gap: 12px; align-content: start; min-width: 0; }
.dash-found:empty { display: none; }
.dash-head { display: flex; align-items: center; flex-wrap: wrap; gap: var(--s1) var(--s2); }
.dash-head > h1 { flex: 1 1 240px; min-width: 0; overflow-wrap: anywhere; }
.dash-head > .title-input { flex: 1 1 240px; }
.dash-tools { display: flex; align-items: center; flex-wrap: wrap; gap: var(--s1); }
.dash-range { flex-wrap: nowrap; gap: 0; border: 1px solid var(--line); border-radius: var(--radius-md); overflow: hidden; }
.dash-range .btn { height: 30px; padding: 0 10px; border: 0; border-right: 1px solid var(--line); border-radius: 0; font-variant-numeric: tabular-nums; transform: none; }
.dash-range .btn:last-child { border-right: 0; }
.dash-range .btn[aria-checked="true"] { border-color: var(--line); background: var(--fill); color: var(--label); }
.dash-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 16px; }
.dash-grid > .hint { grid-column: 1 / -1; }
.dash-widget { grid-column: span 1; display: grid; gap: 12px; align-content: start; min-width: 0; padding: 16px; border: 1px solid var(--line); border-radius: var(--radius-lg); background: var(--surface); }
.dash-widget[data-w="2"] { grid-column: span 2; }
.dash-widget[data-w="3"] { grid-column: span 3; }
.dash-widget-head { display: flex; align-items: center; gap: var(--s1); min-height: var(--control-sm); margin: -8px -8px 0 0; }
.dash-widget-title { flex: 1; min-width: 0; margin: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; font: 600 13px/20px var(--font-body); color: var(--label); }
.dash-widget-body { min-width: 0; }
.sk-widget { gap: 12px; }
.sk-widget .sk-plot { height: 120px; }
.dash-widget[data-type="number"] .sk-plot { height: 36px; }
.dash-number { display: grid; justify-items: start; gap: var(--s1); }
.dash-number-value { font: 700 32px/1.1 var(--font-heading); letter-spacing: -0.02em; font-variant-numeric: tabular-nums; color: var(--label); overflow-wrap: anywhere; }
.dash-change[data-trend="up"] { color: color-mix(in srgb, var(--connected) 70%, var(--label)); }
.dash-change[data-trend="down"] { color: var(--danger); }
.dash-chart { display: grid; gap: var(--s1); }
.dash-chart-svg { display: block; width: 100%; height: auto; }
.dash-chart-svg rect { shape-rendering: crispEdges; }
.dash-chart-svg rect[rx] { shape-rendering: auto; }
.dash-hit { fill: transparent; }
/* The hairlines of the scale the page of a link still draws (public/share.js, Fase 132), until it copies Fase 134's charts. */
.dash-grid-line { stroke: var(--line); }
.dash-axis { stroke: var(--line); }
.dash-axis-label { fill: var(--label-2); font: 500 11px/1 var(--font-body); font-variant-numeric: tabular-nums; }
.dash-line { fill: none; stroke: var(--tone); stroke-width: 2; stroke-linejoin: round; stroke-linecap: round; }
.dash-area { fill: color-mix(in srgb, var(--label) 6%, transparent); }
.dash-dot, .dash-bar { fill: var(--tone); }
.dash-stack { transform-box: fill-box; transform-origin: 50% 100%; }
.dash-weak { --tone: var(--label-2); }
.dash-s1 { --tone: color-mix(in srgb, var(--label) 88%, transparent); }
.dash-s2 { --tone: color-mix(in srgb, var(--label) 40%, transparent); }
.dash-s3 { --tone: color-mix(in srgb, var(--label) 70%, transparent); }
.dash-s4 { --tone: color-mix(in srgb, var(--label) 22%, transparent); }
.dash-s5 { --tone: color-mix(in srgb, var(--label) 56%, transparent); }
.dash-s6 { --tone: color-mix(in srgb, var(--label) 30%, transparent); }
.dash-legend { display: flex; flex-wrap: wrap; gap: 4px var(--s2); margin: 0; padding: 0; list-style: none; font: var(--meta); color: var(--label-2); }
.dash-legend li { display: flex; align-items: center; gap: 6px; min-width: 0; }
.dash-swatch { flex: none; width: 10px; height: 10px; border-radius: 2px; background: var(--tone); }
.dash-legend-name { min-width: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
.dash-legend-value { font-variant-numeric: tabular-nums; color: var(--label); }
.dash-bars { display: grid; gap: 6px; margin: 0; padding: 0; list-style: none; }
.dash-bar-row { display: grid; grid-template-columns: minmax(0, 2fr) minmax(0, 3fr) auto auto; align-items: center; gap: var(--s1); font: var(--row-line); color: var(--label); }
.dash-bar-name { min-width: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; color: var(--label-2); }
.dash-bar-track { display: block; height: 8px; border-radius: var(--radius-pill); background: var(--fill); overflow: hidden; }
.dash-bar-fill { display: block; height: 100%; border-radius: inherit; background: color-mix(in srgb, var(--label) 70%, transparent); }
.dash-bar-value { font-variant-numeric: tabular-nums; text-align: right; }
.dash-table-wrap { overflow-x: auto; }
.dash-table { width: 100%; border-collapse: collapse; font: 400 13px/20px var(--font-body); color: var(--label); }
.dash-table th { height: 28px; padding: 0 var(--s1) 0 0; border-bottom: 1px solid var(--line); text-align: left; font: var(--small-label); color: var(--label-2); white-space: nowrap; }
.dash-table td { height: 28px; padding: 0 var(--s1) 0 0; border-bottom: 1px solid var(--line); white-space: nowrap; }
.dash-table .num { padding-right: 0; text-align: right; font-variant-numeric: tabular-nums; }
@media (max-width: 880px) {
  .dash-grid { grid-template-columns: minmax(0, 1fr); }
  .dash-widget[data-w] { grid-column: auto; }
}

/* Share (Fase 132; «Share with the internet» of «Visible to» since Fase 133 — webBlock() in app.js —, and public/share.html) ----
   A popover of «Visible to» with the web among its answers is 320px. Under the web, in its place: its question — who will see
   it in the type of the meta line, and «Cancel» and «Share» on the right under it —; on the web, the link in a box of the mono
   type that reads only and «Copy» on its right, and under them «Anyone with the link can view» in the grey of a hint with «Stop
   sharing» on its right, in --danger, which asks the same way, its «Stop sharing» a button in --danger; then, over a hairline,
   «Send to» in the small label, its box and «Send», what was refused in a hint with the red dot, and who it went to, a grey chip
   of 24px each, its address cut short and its day apart in the lightest grey. Lined up with the words of the answers.
   The page of a link: no rail, the app's own pieces in either theme — a dashboard as wide as in the app, its period on the right
   of its title and its widgets without their «···»; a document or a page in the app's column of text, its title in the type of
   an entry's —, and «Shared from Company» in the caption's grey at the foot, the way to the landing. A link that opens nothing
   says so in the block of a failure. The tokens of either theme, and no colour of their own. */
.menu:has(.menu-item[data-key="web"]) { width: min(320px, calc(100vw - 16px)); max-width: none; }
.share-block { display: grid; gap: var(--s1); min-width: 0; padding: 4px 10px 8px; }
.share-ask { display: grid; gap: var(--s1); min-width: 0; }
.share-ask-text { margin: 0; font: var(--meta); color: var(--label); overflow-wrap: anywhere; }
.share-ask-actions { display: flex; justify-content: flex-end; gap: var(--s1); }
.share-line { display: flex; align-items: center; gap: var(--s1); min-width: 0; }
.share-url { flex: 1; min-width: 0; font: var(--code); color: var(--label-2); text-overflow: ellipsis; }
.share-emails { flex: 1; min-width: 0; }
.share-anyone { justify-content: space-between; }
.share-stop { flex: none; padding: 0; border: 0; background: none; color: var(--danger); font: 500 13px/20px var(--font-body); cursor: pointer; }
.share-stop:disabled { opacity: 0.4; cursor: default; }
.share-send { padding-top: 12px; border-top: 1px solid var(--line); }
.share-label { font: var(--small-label); color: var(--label-2); }
.share-sent { display: flex; flex-wrap: wrap; gap: 6px; min-width: 0; margin: 0; padding: 0; list-style: none; }
.share-chip { display: inline-flex; align-items: center; gap: 6px; max-width: 100%; height: 24px; padding: 0 10px; border-radius: var(--radius-pill); background: var(--fill); color: var(--label-2); font: 400 12px/24px var(--font-body); }
.share-chip-email { min-width: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
.share-chip-day { flex: none; color: var(--label-3); }
.share-body { display: flex; flex-direction: column; height: auto; min-height: 100%; }
.share-main { flex: 1; }
.share-main > .detail, .share-main > .page { padding-bottom: var(--s5); }
.share-head h1 { margin: 0; font: var(--title-app); letter-spacing: -0.02em; color: var(--label); overflow-wrap: anywhere; }
.share-foot { padding: var(--s3) var(--s3) calc(var(--s3) + var(--safe-b)); font: var(--caption); text-align: center; }
.share-foot a { color: var(--label-2); }
@media (max-width: 880px) {
  .share-stop { line-height: 36px; }
  /* 16 px, as every box of a phone: below that, Safari on the iPhone zooms the page when the link is tapped to select it. */
  .share-url { font-size: 16px; }
}
