/* ---------------------------------------------------------------------------
   Peltify demo — application shell, onboarding, and the four surfaces.
   Written fresh for Peltify. No CORESYSTEM CSS is copied.
   --------------------------------------------------------------------------- */

/* ===========================================================================
   0. Shared primitives
   =========================================================================== */

.eyebrow {
  margin: 0;
  color: var(--ink-faint);
  font-size: 10px;
  font-weight: 800;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

h1,
h2,
h3,
h4 {
  margin: 0;
  letter-spacing: -0.03em;
  font-weight: 800;
  line-height: 1.14;
}

h1 { font-size: clamp(28px, 4.4vw, 42px); }
h2 { font-size: clamp(21px, 2.6vw, 27px); }
h3 { font-size: 17px; }
h4 { font-size: 14px; }

p { margin: 0; }

.lede {
  color: var(--ink-soft);
  font-size: 15px;
  line-height: 1.62;
}

.muted { color: var(--ink-soft); }
.faint { color: var(--ink-faint); }
.mono { font-family: var(--font-mono); font-size: 12px; }

.card {
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  background: var(--white);
  box-shadow: var(--shadow-sm);
}

.btn,
.btn-primary,
.btn-ghost {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  min-height: 44px;
  padding: 0 20px;
  border: 1px solid transparent;
  border-radius: var(--r-box);
  background: var(--ink);
  color: var(--white);
  font-size: 14px;
  font-weight: 750;
  letter-spacing: -0.01em;
  transition: transform var(--fast) var(--ease), background var(--fast) var(--ease),
    border-color var(--fast) var(--ease), box-shadow var(--fast) var(--ease);
}

.btn:hover:not(:disabled),
.btn-primary:hover:not(:disabled),
.btn-ghost:hover:not(:disabled) { transform: translateY(-1px); box-shadow: var(--shadow-md); }

.btn:active:not(:disabled),
.btn-primary:active:not(:disabled),
.btn-ghost:active:not(:disabled) { transform: translateY(0); }

.btn:disabled,
.btn-primary:disabled,
.btn-ghost:disabled { opacity: 0.42; cursor: not-allowed; }

.btn-primary { background: var(--violet); }
.btn-primary:hover:not(:disabled) { background: var(--spine); }

.btn-ghost {
  background: transparent;
  border-color: var(--line);
  color: var(--ink);
}
.btn-ghost:hover:not(:disabled) { border-color: var(--ink); background: var(--white); }

/* The variants are used standalone (`button.btn-ghost`), so they must carry
   the base box themselves rather than depend on .btn also being present. */
.btn-quiet {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 7px;
  min-height: 36px;
  padding: 0 14px;
  border: 1px solid transparent;
  border-radius: var(--r-box);
  background: transparent;
  color: var(--ink-soft);
  font-size: 13px;
  font-weight: 700;
  transition: background var(--fast) var(--ease), color var(--fast) var(--ease);
}
.btn-quiet:hover:not(:disabled) { color: var(--ink); background: var(--violet-wash); transform: none; box-shadow: none; }

.btn-sm { min-height: 34px; padding: 0 14px; font-size: 13px; }

.field { display: grid; gap: 7px; }

.field label {
  font-size: 12px;
  font-weight: 800;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--ink-soft);
}

.field input {
  min-height: 50px;
  padding: 0 16px;
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--white);
  font-size: 16px;
  transition: border-color var(--fast) var(--ease), box-shadow var(--fast) var(--ease);
}

.field input:focus {
  outline: none;
  border-color: var(--violet);
  box-shadow: 0 0 0 4px var(--violet-wash);
}

.field .hint { font-size: 12.5px; color: var(--ink-faint); }
.field .err { font-size: 12.5px; color: var(--coral-dark); font-weight: 700; }

/* ONE FOCUS RING, THE APP'S OWN (2026-08-31, UI-2). Chrome draws its native
   focus ring on a focused input unless a rule says otherwise, and this app
   already draws its own — a violet outline or pill border on the FIELD BOX
   (`:focus-within` on .stg-search, .brain-qbox, .ep-searchbar and friends) or
   on the input itself. Both at once is the "incredibly ugly select box" Nick
   screenshotted: the browser's ring drawn INSIDE the app's pill. The native
   ring goes; every text input keeps a visible indicator because the app's own
   rules supply it, and any input those rules miss still shows its wrapper's. */
input:focus, input:focus-visible,
textarea:focus, textarea:focus-visible,
select:focus, select:focus-visible {
  outline: none;
}
/* And no native search-box chrome either — Safari rounds it, Chrome adds its
   own cancel blob; the app draws both itself. */
input[type="search"] { -webkit-appearance: none; appearance: none; }
input[type="search"]::-webkit-search-decoration { -webkit-appearance: none; }

/* Guardrail / status pills ------------------------------------------------- */

.pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 5px 11px 5px 8px;
  border: 1px solid var(--line);
  border-radius: var(--r-box);
  background: var(--white);
  font-size: 11.5px;
  font-weight: 750;
  letter-spacing: -0.005em;
  white-space: nowrap;
}

.pill i {
  display: block; /* an inline <i> would ignore the size */
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--ink-faint);
  flex: none;
}

.pill.on {
  border-color: rgba(47, 125, 79, 0.34);
  background: var(--ok-wash);
  color: #235f3c;
}
.pill.on i { background: var(--ok); box-shadow: 0 0 0 3px rgba(47, 125, 79, 0.16); }

.pill.off { color: var(--ink-faint); background: var(--paper-deep); }

.pill.live { border-color: var(--violet-wash-strong); background: var(--violet-wash); color: var(--spine); }
.pill.live i { background: var(--violet); animation: pulse 1.6s var(--ease) infinite; }

.pill.warn { border-color: rgba(154, 100, 7, 0.32); background: var(--warn-wash); color: var(--warn); }
.pill.warn i { background: var(--warn); }

@keyframes pulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(139, 31, 209, 0.4); }
  50% { box-shadow: 0 0 0 5px rgba(139, 31, 209, 0); }
}

/* ===========================================================================
   1. Onboarding — three steps, skippable
   =========================================================================== */

.onb {
  min-height: 100vh;
  display: grid;
  grid-template-rows: auto 1fr auto;
  background:
    radial-gradient(1100px 620px at 12% -8%, rgba(139, 31, 209, 0.11), transparent 62%),
    radial-gradient(820px 520px at 96% 8%, rgba(158, 216, 244, 0.3), transparent 60%),
    var(--paper);
}

@keyframes rise {
  from { opacity: 0; transform: translateY(14px); }
  to { opacity: 1; transform: none; }
}

/* Step 2 — auth */

.auth-list { display: grid; gap: 10px; }

.auth-btn {
  display: flex;
  align-items: center;
  gap: 13px;
  width: 100%;
  min-height: 56px;
  padding: 0 18px;
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--white);
  text-align: left;
  font-size: 14.5px;
  font-weight: 700;
  transition: border-color var(--fast) var(--ease), transform var(--fast) var(--ease),
    box-shadow var(--fast) var(--ease);
}

.auth-btn:hover { border-color: var(--ink); transform: translateY(-1px); box-shadow: var(--shadow-sm); }
.auth-btn svg { width: 20px; height: 20px; flex: none; }
.auth-btn .tail { margin-left: auto; font-size: 11.5px; font-weight: 750; color: var(--ink-faint); }

.auth-sep {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: 12px;
  margin: 20px 0;
  color: var(--ink-faint);
  font-size: 11px;
  font-weight: 800;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}
.auth-sep::before,
.auth-sep::after { content: ""; height: 1px; background: var(--line); }

.auth-state {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-top: 18px;
  padding: 13px 15px;
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--paper);
  font-size: 13px;
}

/* Step 3 — API / connector showcase */

.api-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(148px, 1fr));
  gap: 10px;
}

.api-tile {
  position: relative;
  display: grid;
  gap: 7px;
  padding: 14px;
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--white);
  text-align: left;
  transition: border-color var(--fast) var(--ease), transform var(--fast) var(--ease),
    box-shadow var(--fast) var(--ease), background var(--fast) var(--ease);
}

.api-tile:hover:not(:disabled) { transform: translateY(-2px); border-color: var(--violet); box-shadow: var(--shadow-sm); }
.api-tile[aria-pressed="true"] { border-color: var(--violet); background: var(--violet-wash); }
.api-tile:disabled { opacity: 0.5; cursor: not-allowed; }

.api-tile img { width: 22px; height: 22px; }
.api-tile b { font-size: 13.5px; font-weight: 780; }
.api-tile span { font-size: 11.5px; color: var(--ink-faint); line-height: 1.35; }
.api-tile .pill { justify-self: start; margin-top: 2px; }

.api-tile .tick {
  position: absolute;
  top: 11px;
  right: 11px;
  width: 17px;
  height: 17px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  background: var(--violet);
  color: white;
  font-size: 10px;
  font-weight: 900;
  opacity: 0;
  transform: scale(0.6);
  transition: all var(--fast) var(--ease);
}
.api-tile[aria-pressed="true"] .tick { opacity: 1; transform: scale(1); }

.route-note {
  display: flex;
  gap: 10px;
  margin-top: 18px;
  padding: 13px 15px;
  border: 1px solid var(--violet-wash-strong);
  border-radius: var(--r-md);
  background: var(--violet-wash);
  font-size: 12.5px;
  line-height: 1.5;
  color: var(--spine);
}
.route-note b { font-weight: 800; }

/* ===========================================================================
   2. App shell
   =========================================================================== */

/* minmax(0, 1fr) rather than 1fr: a bare 1fr track takes its automatic minimum
   from the content's min-content size, which lets a wide child push the whole
   shell past the viewport instead of being made to wrap. */
.app {
  display: grid;
  /* [UI-3] 2026-09-01: the rail narrows — icon+label at 200px, icons only
     under 1100px (the phone layout below 900px is unchanged). */
  grid-template-columns: 200px minmax(0, 1fr);
  min-height: 100vh;
}
@media (max-width: 1100px) and (min-width: 901px) {
  .app { grid-template-columns: 72px minmax(0, 1fr); }
  .rail { padding: 18px 10px; }
  .rail-brand img { height: 26px; width: 26px; object-fit: cover; object-position: left; }
  .rail-nav button span:not(.count):not(.run-live) { display: none; }
  .rail-nav button { justify-content: center; padding: 10px 0; }
  .rail-user { justify-content: center; }
  .rail-user > :not(.avatar):not(img):not(.rail-user-pic) { display: none; }
}
/* [DASH-17] the page never scrolls sideways: rows scroll inside their own
   containers (overflow-x on the row), never the document. */
.app { overflow-x: clip; max-width: 100vw; }
.surface { overflow-x: clip; }

.rail {
  position: sticky;
  top: 0;
  align-self: start;
  height: 100vh;
  display: grid;
  grid-template-rows: auto 1fr auto;
  gap: var(--gap-4);
  padding: 22px 16px;
  border-right: 1px solid var(--line);
  background: var(--white);
}

/* The wordmark is a real button now (it goes home), so it has to shed the
   browser's button chrome and gain a real hover and focus state. */
.rail-brand {
  display: block; padding: 4px 6px; margin: -4px -6px;
  border: 0; background: none; cursor: pointer;
  border-radius: var(--r-sm);
  transition: background .16s cubic-bezier(.16,1,.3,1), opacity .16s;
}
.rail-brand:hover { background: color-mix(in srgb, var(--violet) 8%, transparent); }
.rail-brand:active { opacity: .78; }
.rail-brand img { height: 30px; width: auto; display: block; }

.rail-nav { display: grid; gap: 3px; align-content: start; }

.rail-nav button {
  display: flex;
  align-items: center;
  gap: 11px;
  width: 100%;
  min-height: 42px;
  padding: 0 12px;
  border: 0;
  border-radius: var(--r-sm);
  background: transparent;
  color: var(--ink-soft);
  font-size: 14px;
  font-weight: 720;
  text-align: left;
  transition: background var(--fast) var(--ease), color var(--fast) var(--ease);
}

.rail-nav button:hover { background: var(--paper); color: var(--ink); }

.rail-nav button[aria-current="page"] {
  background: var(--violet-wash);
  color: var(--spine);
  font-weight: 800;
}

.rail-nav svg { width: 17px; height: 17px; flex: none; }

/* 14.7 (library entry 9) — THE DIRECT ADD DOOR. Library carries a `+` of its
   own: the row goes to Your things, the `+` opens the picker where you stand.
   The pair is one grid row, so the active pill still measures the row. */
.rail-pair { display: flex; align-items: center; gap: 2px; }
.rail-pair > button:first-child { flex: 1 1 auto; min-width: 0; }
/* 17.7: no border, and the row's own glyph size — it was a bordered 30px box
   sitting beside a borderless 24px glyph, which is what read as "strange". */
.rail-nav .rail-plus { flex: none; width: 34px; min-height: 0; height: 34px; padding: 0; display: grid; place-items: center;
  border: 0; border-radius: var(--r-sm); background: transparent;
  color: var(--ink-soft); cursor: pointer; transition: background var(--fast) var(--ease), color var(--fast) var(--ease); }
.rail-nav .rail-plus:hover { background: var(--paper); color: var(--ink); }
@media (max-width: 1100px) and (min-width: 901px) {
  /* the narrow rail is icons only, and two icons on one row is a squeeze —
     the `+` sits under the row rather than beside it */
  .rail-pair { flex-direction: column; gap: 2px; }
  .rail-nav .rail-plus { width: 100%; height: 28px; }
}

.rail-nav .count {
  margin-left: auto;
  padding: 1px 7px;
  border-radius: var(--r-box);
  background: var(--paper-deep);
  font-size: 11px;
  font-weight: 800;
}
.rail-nav button[aria-current="page"] .count { background: var(--violet); color: white; }
/* [PELT-12] the social badge: Instagram's red disc on the paper-plane icon. */
.rail-nav button { position: relative; }
.rail-nav .count.is-alert {
  position: absolute; left: 24px; top: 4px; margin: 0; min-width: 18px; height: 18px; padding: 0 5px;
  border-radius: 999px; background: #ff3040; color: #fff; font-size: 10.5px; line-height: 18px;
  text-align: center; box-shadow: 0 0 0 2px var(--paper, #fbf7f2);
}
.rail-nav button[aria-current="page"] .count.is-alert { background: #ff3040; }

.rail-foot { display: grid; gap: 10px; font-size: 12px; }

/* THE ACCOUNT CHIP (rebuilt 2026-08-27). Nick: "@nick is not good enough."
   A 36px picture, the display name, the username with its pinned four digits
   under it, and a chevron. It lifts on hover because it is a control. */
.rail-user {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: 8px 10px;
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  background: var(--white);
  color: inherit;
  font: inherit;
  text-align: left;
  cursor: pointer;
  transition: transform 180ms var(--ease), box-shadow 180ms var(--ease),
              border-color 180ms var(--ease);
}
.rail-user:hover { transform: translateY(-2px); box-shadow: var(--raise); border-color: var(--line-strong); }
.rail-user:active { transform: translateY(0); box-shadow: var(--lift); }
.rail-user:focus-visible { outline: 2px solid var(--violet); outline-offset: 2px; }

.avatar {
  display: grid;
  place-items: center;
  width: 30px;
  height: 30px;
  flex: none;
  border-radius: 50%;
  background: var(--violet);
  color: white;
  font-size: 12px;
  font-weight: 800;
}

.rail-user-av { flex: none; }
.rail-user-t { flex: 1 1 auto; min-width: 0; display: grid; gap: 1px; }
.rail-user-name {
  display: block;
  font-size: 13px;
  font-weight: 800;
  letter-spacing: -0.01em;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.rail-user-tag {
  display: block;
  font-size: 11.5px;
  color: var(--ink-faint);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* The four digits are pinned to the username and cannot be edited, so they
   sit a shade back from it rather than reading as part of the name. */
.rail-user-id { opacity: 0.72; }
.rail-user-chev {
  flex: none;
  display: inline-flex;
  color: var(--ink-faint);
  transition: transform 180ms var(--ease), color 180ms var(--ease);
}
.rail-user:hover .rail-user-chev { transform: translateY(1px); color: var(--ink-soft); }

.main { display: grid; grid-template-rows: auto 1fr; min-width: 0; }

.topbar {
  /* [DASH-17] 2026-09-01: NOT sticky. A sticky header covered the top of the
     genre field at 2560px ("the treemap top hides under the sticky header");
     a header that scrolls away with the page can cover nothing. */
  position: static;
  top: 0;
  z-index: 20;
  display: flex;
  align-items: center;
  gap: var(--gap-3);
  padding: 13px clamp(18px, 3vw, 32px);
  border-bottom: 1px solid var(--line);
  background: rgba(245, 240, 232, 0.88);
  backdrop-filter: blur(12px);
}

.topbar-title { display: grid; gap: 1px; margin-right: auto; min-width: 0; }
.topbar-title b { font-size: 15px; font-weight: 800; letter-spacing: -0.02em; }
.topbar-title span { font-size: 12px; color: var(--ink-faint); }

.guardrails {
  display: flex;
  align-items: center;
  gap: 6px;
  flex-wrap: wrap;
  justify-content: flex-end;
}

.guardrails .more {
  display: inline-flex;
  align-items: center;
  min-height: 34px;
  border: 1px dashed var(--line-strong);
  background: transparent;
  color: var(--ink-soft);
  border-radius: var(--r-box);
  padding: 0 13px;
  font-size: 11.5px;
  font-weight: 750;
}
.guardrails .more:hover { border-color: var(--violet); color: var(--spine); }

/* min-width: 0 because .surface is a GRID ITEM, and a grid item's automatic
   minimum size is its min-content width — so one wide child does not wrap, it
   widens the whole shell. Measured 2026-08-19 at a 430px viewport: a suggestion
   poster gave the card a 1,284px minimum and the document went to 1,394px, so
   every page scrolled sideways and the bottom nav ran off the screen. */
.surface { padding: clamp(20px, 3vw, 34px) clamp(18px, 3vw, 32px) 64px; min-width: 0; }
.surface-inner { width: min(940px, 100%); margin-inline: auto; }
.surface-wide { width: min(1180px, 100%); margin-inline: auto; }

/* ===========================================================================
   3. Talk — the browser agent
   =========================================================================== */

.talk { display: grid; gap: var(--gap-4); }

.talk-hero { display: grid; gap: 8px; }
.talk-hero h1 { font-size: clamp(24px, 3.4vw, 34px); }

@keyframes sweep {
  0% { transform: scaleX(0.1); }
  50% { transform: scaleX(1); }
  100% { transform: scaleX(0.1); }
}

/* Thread ------------------------------------------------------------------- */

.thread { display: grid; grid-template-columns: minmax(0, 1fr); gap: 14px; }

.msg { display: grid; gap: 8px; max-width: 100%; }

/* A percentage max-width inside min() against a content-sized track is cyclic,
   so the browser drops the percentage and the 560px floor widens the column.
   Plain percentages resolve fine now that the track above is definite. */
.msg-user {
  justify-self: end;
  max-width: 88%;
  padding: 12px 17px;
  border-radius: var(--r-lg) var(--r-lg) 6px var(--r-lg);
  background: var(--ink);
  color: var(--white);
  font-size: 14.5px;
  line-height: 1.5;
  animation: rise var(--med) var(--ease) both;
}

.msg-agent {
  min-width: 0;
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  background: var(--white);
  box-shadow: var(--shadow-sm);
  overflow: hidden;
  animation: rise var(--med) var(--ease) both;
}

.msg-head {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 13px 16px;
  border-bottom: 1px solid var(--line-soft);
  background: linear-gradient(var(--white), var(--paper));
}

.msg-head img { width: 19px; height: 19px; }
.msg-head b { font-size: 13.5px; font-weight: 800; letter-spacing: -0.015em; }
.msg-head .spacer { margin-left: auto; }

.msg-body { padding: 15px 16px 17px; display: grid; grid-template-columns: minmax(0, 1fr); gap: 14px; }

/* Run log — the agent narrating what the browser is doing */

.runlog {
  display: grid;
  gap: 0;
  border: 1px solid var(--line-soft);
  border-radius: var(--r-md);
  background: var(--paper);
  overflow: hidden;
}

.runlog-head {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 9px 13px;
  border-bottom: 1px solid var(--line-soft);
  font-size: 10.5px;
  font-weight: 820;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

.runlog-head .tail { margin-left: auto; text-transform: none; letter-spacing: 0; font-weight: 700; font-size: 11px; }

.runlog ol { margin: 0; padding: 6px 0; list-style: none; }

.runlog li {
  display: grid;
  grid-template-columns: 20px minmax(0, 1fr) auto;
  align-items: center;
  gap: 9px;
  padding: 6px 13px;
  font-size: 12.5px;
  color: var(--ink-soft);
  animation: rise var(--fast) var(--ease) both;
}

.runlog li .dot {
  display: grid;
  place-items: center;
  width: 15px;
  height: 15px;
  border-radius: 50%;
  border: 1.5px solid var(--line-strong);
  font-size: 9px;
  color: var(--ink-faint);
}

.runlog li.done .dot { border-color: var(--ok); background: var(--ok); color: white; }
.runlog li.active { color: var(--ink); font-weight: 700; }
.runlog li.active .dot { border-color: var(--violet); border-right-color: transparent; animation: spin 0.7s linear infinite; }
.runlog li.blocked .dot { border-color: var(--warn); background: var(--warn); color: white; }
.runlog li .t { font-family: var(--font-mono); font-size: 10.5px; color: var(--ink-faint); }

@keyframes spin { to { transform: rotate(360deg); } }

/* Findings — grouped bullet answers */


.stat-row {
  display: flex;
  flex-wrap: wrap;
  gap: 7px;
}

.stat {
  display: grid;
  gap: 1px;
  padding: 8px 13px;
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--paper);
  min-width: 92px;
}

.stat b { font-size: 18px; font-weight: 820; letter-spacing: -0.03em; }
.stat span { font-size: 10.5px; font-weight: 750; letter-spacing: 0.05em; text-transform: uppercase; color: var(--ink-faint); }

.tag-cloud { display: flex; flex-wrap: wrap; gap: 6px; }

.tag {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  min-height: 34px;
  padding: 0 13px;
  border: 1px solid var(--line);
  border-radius: var(--r-box);
  background: var(--white);
  font-size: 12px;
  font-weight: 700;
  transition: border-color var(--fast) var(--ease), background var(--fast) var(--ease);
}
.tag:hover { border-color: var(--violet); background: var(--violet-wash); color: var(--spine); }
.tag b { font-weight: 800; }
.tag span { color: var(--ink-faint); font-weight: 700; }

.saved-note {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 10px 13px;
  border: 1px solid var(--line-soft);
  border-radius: var(--r-md);
  background: var(--lime-wash);
  font-size: 12.4px;
  font-weight: 700;
  color: #4a5b21;
}

.blocked-note {
  display: grid;
  gap: 5px;
  padding: 12px 14px;
  border: 1px solid rgba(154, 100, 7, 0.3);
  border-radius: var(--r-md);
  background: var(--warn-wash);
  font-size: 12.8px;
  line-height: 1.5;
  color: #6f4905;
}
.blocked-note b { font-weight: 820; }

.msg-foot {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  padding: 11px 16px;
  border-top: 1px solid var(--line-soft);
  background: var(--paper);
  font-size: 12px;
  color: var(--ink-faint);
}

/* Composer ----------------------------------------------------------------- */

.composer-wrap {
  position: sticky;
  bottom: 0;
  padding: 14px 0 0;
  background: linear-gradient(transparent, var(--paper) 26%);
}

.composer {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 9px;
  align-items: end;
  padding: 9px 9px 9px 17px;
  border: 1px solid var(--line);
  border-radius: var(--r-xl);
  background: var(--white);
  box-shadow: var(--shadow-md);
  transition: border-color var(--fast) var(--ease), box-shadow var(--fast) var(--ease);
}

.composer:focus-within { border-color: var(--violet); box-shadow: 0 0 0 4px var(--violet-wash), var(--shadow-md); }

.composer textarea {
  border: 0;
  background: transparent;
  resize: none;
  padding: 12px 0;
  min-height: 46px;
  max-height: 160px;
  font-size: 15px;
  line-height: 1.5;
  outline: none;
}

.composer-send {
  display: grid;
  place-items: center;
  width: 46px;
  height: 46px;
  border: 0;
  border-radius: 50%;
  background: var(--violet);
  color: white;
  transition: background var(--fast) var(--ease), transform var(--fast) var(--ease);
}
.composer-send:hover:not(:disabled) { background: var(--spine); transform: scale(1.05); }
.composer-send:disabled { background: var(--line-strong); cursor: not-allowed; }

.composer-hint {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  padding: 9px 6px 0;
  font-size: 11.5px;
  color: var(--ink-faint);
}

/* ===========================================================================
   4. Sources
   =========================================================================== */

.src-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(268px, 1fr));
  gap: 13px;
}

.src {
  display: flex; /* so .src-foot can be pushed to the bottom of every card */
  flex-direction: column;
  gap: 12px;
  padding: 17px;
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  background: var(--white);
  box-shadow: var(--shadow-sm);
}

.src-top { display: flex; align-items: flex-start; gap: 11px; }
.src-top img { width: 26px; height: 26px; margin-top: 1px; }
.src-top div { min-width: 0; margin-right: auto; }
.src-top b { display: block; font-size: 15px; font-weight: 800; letter-spacing: -0.02em; }
.src-top span { display: block; font-size: 12px; color: var(--ink-faint); }

.src-what { font-size: 12.8px; line-height: 1.5; color: var(--ink-soft); }

.src-what ul { margin: 6px 0 0; padding-left: 16px; display: grid; gap: 3px; }

.src-foot { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-top: auto; }

.src-route {
  padding: 9px 12px;
  border-radius: var(--r-sm);
  background: var(--violet-wash);
  font-size: 11.8px;
  line-height: 1.45;
  color: var(--spine);
}

/* ===========================================================================
   5. Brain

   MOSTLY MOVED OUT, 2026-08-27. The Brain became one surface — a graph that
   fills the page with a sidebar attached to it — and its rules now live in
   `styles/brain.css`. What was deleted from here: `.brain-head`,
   `.brain-search*`, `.brain-bar`, `.brain-graph-wrap`, `.brain-stage`,
   `.brain-canvas`, `.brain-zoom`, and every `.brain-panel*` rule (the floating
   overlay panel the sidebar replaces).

   What STAYED, and why: `.seg` (Profile's tabs use it), `.fact*` / `.sub-*`
   (Live and Talk use them), and `.brain-settings` / `.brain-setting` /
   `.brain-activity` / the `.bsrc` list-card block further down — those belong
   to the ARCHIVED List and Activity views, whose code is kept intact in
   brain.js and would need its CSS back with it.
   =========================================================================== */

/* Multi-column rather than grid: clusters are wildly uneven in height, and a
   grid leaves a hole under every short one. Columns pack them. */

.facts { display: grid; gap: 6px; }

.fact {
  display: grid;
  gap: 3px;
  padding: 9px 11px;
  border: 1px solid var(--line-soft);
  border-radius: var(--r-sm);
  background: var(--paper);
  font-size: 13px;
  line-height: 1.45;
  transition: border-color var(--fast) var(--ease), background var(--fast) var(--ease);
}
.fact:hover { border-color: var(--line); background: var(--white); }

.fact-meta {
  display: flex;
  align-items: center;
  gap: 7px;
  font-size: 10.5px;
  color: var(--ink-faint);
  font-weight: 700;
}

.fact-meta .kind {
  padding: 1px 6px;
  border-radius: var(--r-box);
  background: var(--white);
  border: 1px solid var(--line-soft);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  font-size: 9.5px;
  font-weight: 800;
}

.fact.is-new { animation: flash 1.6s var(--ease) both; }

@keyframes flash {
  0% { background: var(--lime-wash); border-color: rgba(215, 240, 143, 0.9); }
  100% { background: var(--paper); }
}

.empty {
  padding: 46px 22px;
  text-align: center;
  border: 1px dashed var(--line-strong);
  border-radius: var(--r-lg);
  color: var(--ink-faint);
  font-size: 13.5px;
  display: grid;
  gap: 9px;
  justify-items: center;
}

/* ===========================================================================
   6. Activity
   =========================================================================== */

.act-list { display: grid; gap: 9px; }

.act {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: 13px;
  padding: 13px 16px;
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--white);
}

.act-icon {
  display: grid;
  place-items: center;
  width: 32px;
  height: 32px;
  border-radius: var(--r-sm);
  background: var(--paper);
}
.act-icon img { width: 17px; height: 17px; }

.act div { min-width: 0; }
.act b { display: block; font-size: 13.5px; font-weight: 780; }
.act span { display: block; font-size: 12px; color: var(--ink-faint); }
.act time { font-size: 11.5px; color: var(--ink-faint); font-family: var(--font-mono); white-space: nowrap; }

/* ===========================================================================
   7. Sheet (guardrails / account)
   =========================================================================== */

.sheet-scrim {
  position: fixed;
  inset: 0;
  z-index: 60;
  display: grid;
  place-items: center;
  padding: 22px;
  background: rgba(36, 20, 46, 0.34);
  backdrop-filter: blur(3px);
  animation: fade var(--fast) var(--ease) both;
}

@keyframes fade { from { opacity: 0; } to { opacity: 1; } }

.sheet {
  width: min(520px, 100%);
  max-height: min(84vh, 720px);
  overflow: auto;
  padding: 26px;
  border-radius: var(--r-xl);
  background: var(--white);
  box-shadow: var(--shadow);
  animation: rise var(--med) var(--ease) both;
}

.sheet-h { display: flex; align-items: flex-start; gap: 12px; margin-bottom: 6px; }
.sheet-h h2 { margin-right: auto; }

.icon-btn {
  display: grid;
  place-items: center;
  width: 32px;
  height: 32px;
  border: 1px solid var(--line);
  border-radius: 50%;
  background: transparent;
  color: var(--ink-soft);
  flex: none;
}
.icon-btn:hover { border-color: var(--ink); color: var(--ink); }

.rail-list { display: grid; gap: 8px; margin-top: 20px; }

.rail-row {
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: center;
  gap: 13px;
  padding: 13px 15px;
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--paper);
}

.rail-row b { display: block; font-size: 13.5px; font-weight: 780; }
.rail-row span { display: block; font-size: 12px; color: var(--ink-faint); line-height: 1.4; margin-top: 2px; }

.rail-row.locked { background: var(--ok-wash); border-color: rgba(47, 125, 79, 0.26); }

/* ===========================================================================
   8. Responsive
   =========================================================================== */

@media (max-width: 900px) {
  /* 14.8: the phone tab bar's height, named once. The account strip sits
     above it, and the surface leaves room for both. */
  :root { --tabbar-h: calc(64px + env(safe-area-inset-bottom)); }
  .app { grid-template-columns: minmax(0, 1fr); }

  .rail {
    position: fixed;
    bottom: 0;
    top: auto;
    z-index: 40;
    height: auto;
    width: 100%;
    grid-template-rows: auto;
    gap: 0;
    padding: 6px 8px calc(6px + env(safe-area-inset-bottom));
    border-right: 0;
    border-top: 1px solid var(--line);
  }

  .rail-brand,
  .rail-foot { display: none; }

  .rail-nav { grid-auto-flow: column; grid-auto-columns: 1fr; gap: 2px; }

  .rail-nav button {
    flex-direction: column;
    gap: 3px;
    min-height: 52px;
    padding: 6px 2px;
    font-size: 10.5px;
    font-weight: 780;
  }

  .rail-nav .count { display: none; }

  .surface { padding-bottom: 96px; }
  .composer-wrap { bottom: 62px; }
  /* 14.8: the anonymous account strip stands above the tab bar, so whatever
     runs to the bottom of the page leaves room for both. `data-gate` is set
     by main.js on every render, so this follows the gate exactly. */
  [data-gate="bar"] .surface { padding-bottom: calc(96px + 46px); }
  [data-gate="bar"] .composer-wrap { bottom: calc(62px + 46px); }

  /* ONE SLIM ROW (2026-08-30, infrastructure shell/RAW.md entry 1: "why is
     this so big and fat on mobile?"). The subtitle is desktop furniture; the
     engine pill shrinks to fit beside the title instead of wrapping into a
     row of its own. */
  .topbar { flex-wrap: nowrap; padding: 8px 14px; gap: 8px; }
  .topbar-title span { display: none; }
  .topbar-title b { font-size: 14.5px; white-space: nowrap; }
  .topbar-status { min-width: 0; }
  .topbar .pill { font-size: 10.5px; padding: 3px 8px; white-space: nowrap; }
  .guardrails { width: 100%; justify-content: flex-start; }
}

@media (max-width: 560px) {
  .msg-user { max-width: 94%; }
}

/* ===========================================================================
   PELTIFY — Live surface, sliding nav pill, and the run carousel.
   New Peltify code, 2026-08-15.

   The carousel and the sliding nav pill are PORTED BEHAVIOURS from CORESYSTEM
   (app/app/demo/views/TalkView.js §5 and AppShell.js). CORESYSTEM gets them
   from framer-motion; these are the dependency-free equivalents. Do not
   "simplify" them back into a vertical stack or a blinking background — the
   side-by-side reachability of finished runs and the travelling pill are
   deliberate, and were called out as work not to erase.
   =========================================================================== */

/* --- the travelling active pill (framer-motion layoutId, in CSS) ---------- */

.rail-nav { position: relative; }

.rail-pill {
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  height: 42px;
  border-radius: var(--r-sm);
  background: var(--violet-wash);
  opacity: 0;
  pointer-events: none;
  /* Approximates the spring CORESYSTEM uses (stiffness 420, damping 36)
     without an animation library. Exponential ease-out, NOT the overshoot
     curve this used to carry: at damping 36 that spring barely overshoots,
     so cubic-bezier(0.34, 1.4, …) was bouncing well past what it claimed to
     emulate — and a visible bounce on a nav indicator reads as dated. */
  transition: transform 340ms cubic-bezier(0.16, 1, 0.3, 1),
              height 340ms cubic-bezier(0.16, 1, 0.3, 1),
              opacity 160ms ease;
}

/* The pill now draws the active background, so the button must not repaint it
   underneath — that was the blink this replaces. */
.rail-nav button { position: relative; z-index: 1; }
.rail-nav button[aria-current="page"] { background: transparent; }

@media (prefers-reduced-motion: reduce) {
  .rail-pill { transition: opacity 160ms ease; }
}

/* --- live surface --------------------------------------------------------- */

.live-head h1 { margin: 0 0 6px; font-size: 25px; letter-spacing: -0.02em; }

.gate {
  display: flex;
  align-items: flex-start;
  gap: 9px;
  margin: 16px 0 0;
  padding: 12px 14px;
  border-radius: var(--r-md);
  font-size: 13.5px;
  line-height: 1.5;
}
.gate svg { flex: none; margin-top: 2px; }
.gate-ok { background: color-mix(in srgb, var(--violet) 8%, transparent); color: var(--ink); }
.gate-blocked { background: var(--paper-deep); color: var(--ink-soft); }
/* Partly available: something works, something does not, and the copy says
   which. Coral rather than violet, so it does not read as a green light. */
.gate-warn {
  background: color-mix(in srgb, var(--coral) 10%, transparent);
  color: var(--ink);
  box-shadow: inset 2px 0 0 var(--coral);
}
.gate-warn svg { color: var(--coral); }

.live-actions { display: flex; align-items: center; gap: 12px; margin: 16px 0 0; flex-wrap: wrap; }
.live-busy { font-size: 12.5px; color: var(--ink-soft); }
.live-empty { margin-top: 22px; font-size: 13.5px; color: var(--ink-soft); max-width: 60ch; }

.step-list { list-style: none; margin: 16px 0 0; padding: 0; display: grid; gap: 6px; }
.step-list li {
  display: flex; align-items: center; gap: 8px;
  font-size: 13px; color: var(--ink-soft);
}
.step-list svg { color: var(--violet); flex: none; }

/* --- the horizontal run carousel ----------------------------------------- */

.carousel { margin-top: 26px; }

.carousel-head {
  display: flex; align-items: center; gap: 10px;
  margin-bottom: 10px; flex-wrap: wrap;
}
.carousel-title {
  font-size: 11px; letter-spacing: 0.16em; text-transform: uppercase;
  font-weight: 800; color: var(--violet);
}
.carousel-count { font-size: 12px; color: var(--ink-soft); }
.carousel-navs { margin-left: auto; display: inline-flex; gap: 6px; }

.carousel-nav {
  width: 30px; height: 30px; border-radius: var(--r-box);
  border: 1px solid var(--line); background: var(--paper);
  color: var(--ink); font-size: 16px; line-height: 1; cursor: pointer;
  display: grid; place-items: center;
}
.carousel-nav:disabled { opacity: 0.35; cursor: default; }

/* THE horizontal scroll. One card per view, snapping, swipeable. */
.carousel-track {
  display: flex;
  gap: 12px;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scrollbar-width: none;
  -ms-overflow-style: none;
  -webkit-overflow-scrolling: touch;
  padding-bottom: 2px;
  align-items: stretch;
}
.carousel-track::-webkit-scrollbar { display: none; }

.carousel-slide { flex: 0 0 100%; min-width: 0; scroll-snap-align: start; }

.carousel-dots { display: flex; justify-content: center; gap: 6px; margin-top: 10px; }
.carousel-dot {
  width: 7px; height: 7px; padding: 0; border: 0; border-radius: var(--r-pill);
  background: var(--line); cursor: pointer;
  transition: width 200ms var(--ease), background 200ms var(--ease);
}
.carousel-dot.on { width: 22px; background: var(--violet); }

/* --- a run card ----------------------------------------------------------- */

.run-card {
  display: flex; flex-direction: column; gap: 16px;
  padding: 18px 20px;
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--paper);
  height: 100%;
}
.run-card-fail { border-color: color-mix(in srgb, #c0392b 35%, var(--line)); }

.run-head { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; }
.run-head b { font-size: 17px; }
.run-when { font-size: 12px; color: var(--ink-soft); margin-left: auto; }

.run-reason { margin: 0; font-family: var(--mono, monospace); font-size: 13px; color: #c0392b; }
.run-detail { margin: 0; font-size: 13.5px; color: var(--ink-soft); line-height: 1.5; }
.run-emph { font-weight: 700; color: var(--ink); }
.run-prov { margin: 0; font-size: 12px; color: var(--ink-soft); line-height: 1.5; }

.run-karma { display: flex; gap: 26px; flex-wrap: wrap; }
.run-karma div { display: grid; gap: 2px; }
.run-karma b { font-size: 20px; letter-spacing: -0.02em; }
.run-karma span { font-size: 11.5px; color: var(--ink-soft); }

/* --- expandable facts: every number opens to its exact points -------------- */

.fact-stack { display: grid; gap: 8px; }

.fact {
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  background: var(--paper-deep);
}
.fact[open] { background: var(--paper); }

.fact-head {
  display: flex; align-items: baseline; gap: 9px;
  padding: 11px 13px; cursor: pointer; list-style: none;
  font-size: 14px;
}
.fact-head::-webkit-details-marker { display: none; }
.fact-head::after {
  content: "›"; margin-left: auto; color: var(--ink-soft);
  transition: transform 200ms var(--ease); font-size: 16px;
}
.fact[open] > .fact-head::after { transform: rotate(90deg); }

.fact-n { font-size: 18px; font-weight: 800; letter-spacing: -0.02em; }
.fact-n.partial { color: #b26a00; }
.fact-label { color: var(--ink-soft); }
.fact-warn {
  font-size: 11px; color: #b26a00;
  background: color-mix(in srgb, #b26a00 12%, transparent);
  padding: 2px 7px; border-radius: var(--r-box);
}

.fact-body { padding: 0 13px 13px; }
.fact-note { margin: 0 0 8px; font-size: 12.5px; color: var(--ink-soft); }

.fact-list {
  list-style: none; margin: 0; padding: 0;
  display: grid; gap: 7px;
  max-height: 320px; overflow-y: auto;
}
.fact-list li {
  display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap;
  font-size: 13px; padding-bottom: 6px;
  border-bottom: 1px solid color-mix(in srgb, var(--line) 55%, transparent);
}
.sub-name { font-weight: 700; color: var(--ink); text-decoration: none; }
.sub-name:hover { color: var(--violet); text-decoration: underline; }
.sub-meta { font-size: 11.5px; color: var(--ink-soft); }
.sub-tag {
  font-size: 10px; font-weight: 800; padding: 1px 6px;
  border-radius: var(--r-box); background: var(--paper-deep); color: var(--ink-soft);
}
.sub-body { flex-basis: 100%; margin: 3px 0 0; font-size: 12.5px; color: var(--ink-soft); line-height: 1.5; }
.fact-empty { margin: 0; padding: 0 13px 13px; font-size: 12.5px; color: var(--ink-soft); }

/* --- scripted-data banner -------------------------------------------------
   Shown on every surface that still renders src/data.js fixtures. It is
   deliberately not subtle: an unlabelled invented number is the exact defect
   this build was written to correct. Remove a surface's fixtures, and remove
   its banner in shell.js at the same time — never one without the other. */

.mock-banner {
  margin: 0 0 18px;
  padding: 10px 14px;
  border: 1px dashed color-mix(in srgb, #b26a00 45%, var(--line));
  border-radius: var(--r-sm);
  background: color-mix(in srgb, #b26a00 7%, transparent);
  color: var(--ink-soft);
  font-size: 12.5px;
  line-height: 1.5;
}
.mock-banner b { color: #b26a00; }

.mock-link {
  padding: 0;
  border: 0;
  background: none;
  color: var(--violet);
  font: inherit;
  font-weight: 700;
  text-decoration: underline;
  cursor: pointer;
}

/* --- derived signals: inference must not look like fact --------------------
   A signal is Peltify's claim ABOUT the user, not something a source returned.
   It gets its own chrome so the difference survives a glance, and its
   provenance ("worked out from: saved + upvoted") renders on the card itself. */

.sec-label {
  margin: 4px 0 -4px;
  font-size: 11px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  font-weight: 800;
  color: var(--ink-soft);
}
.sec-label-derived { color: var(--violet); }
.sec-note {
  display: block;
  margin-top: 3px;
  font-size: 11px;
  letter-spacing: 0;
  text-transform: none;
  font-weight: 500;
  color: var(--ink-soft);
}

.fact-signal {
  border-style: dashed;
  border-color: color-mix(in srgb, var(--violet) 40%, var(--line));
  background: color-mix(in srgb, var(--violet) 4%, transparent);
}
.fact-signal[open] { background: color-mix(in srgb, var(--violet) 6%, transparent); }

.fact-derived {
  font-size: 10px;
  font-weight: 800;
  letter-spacing: 0.04em;
  padding: 2px 7px;
  border-radius: var(--r-box);
  background: color-mix(in srgb, var(--violet) 14%, transparent);
  color: var(--violet);
}
.fact-n.unknown { color: var(--ink-soft); }

.fact-caveat {
  margin: 0 0 8px;
  padding: 7px 10px;
  border-radius: var(--r-sm);
  background: color-mix(in srgb, #b26a00 10%, transparent);
  font-size: 12px;
  color: #8a5200;
}

/* A stored read must never pass as a fresh one. */
.run-tag {
  font-size: 10px; font-weight: 800; letter-spacing: 0.04em;
  padding: 2px 8px; border-radius: var(--r-box);
  background: var(--paper-deep); color: var(--ink-soft);
}

/* --- the memory graph ------------------------------------------------------
   Ported shape from CORESYSTEM MemoryGraph.js: clustered hubs, curved links,
   a Graph/List toggle. Sectioned by SOURCE, then intertwined with media hubs. */

.seg { display: inline-flex; padding: 2px; border: 1px solid var(--line);
       border-radius: var(--r-pill); background: var(--paper); }
.seg button { border: 0; background: transparent; padding: 5px 14px; font: inherit;
              font-size: 12.5px; font-weight: 700; border-radius: var(--r-pill);
              cursor: pointer; color: var(--ink-soft); }
.seg button.on { background: var(--violet); color: #fff; }

/* The graph is a CANVAS now, not SVG. SVG gave one DOM node per dot, which is
   why the old version capped itself at 22 dots and had neither zoom nor pan —
   a real read is 1,027 subreddits. The stage owns its own height because the
   canvas measures its host to size the backing store. Rewritten 2026-08-17. */
.fact-stack { display: grid; gap: 14px; }

/* ---- list view: one collapsible section per source ----------------------
   The source is the unit you scan by, so it is the unit that opens and
   closes. A closed section still carries its totals, so collapsing hides
   detail without hiding what is there. */
.src-sections { display: grid; gap: 10px; }

.src-section {
  border-radius: var(--r-md);
  background: var(--paper-deep);
  overflow: hidden;
}
.src-section-head {
  display: flex; align-items: center; gap: 11px;
  padding: 14px 16px; cursor: pointer;
  list-style: none;
  transition: background .16s cubic-bezier(.16,1,.3,1);
}
.src-section-head::-webkit-details-marker { display: none; }
.src-section-head:hover { background: color-mix(in srgb, var(--violet) 6%, transparent); }
.src-section[open] .src-section-head {
  background: color-mix(in srgb, var(--violet) 8%, transparent);
  box-shadow: inset 0 -1px 0 var(--line);
}
.src-section-name { font: 700 17px/1.2 var(--font-sans); color: var(--ink); }
.src-section-count {
  margin-left: auto; font-size: 12px; color: var(--ink-soft);
  font-variant-numeric: tabular-nums;
}
.src-section-count.faint { color: var(--ink-mut); font-style: italic; }
.src-section-caret {
  flex: none; color: var(--ink-mut); font-size: 12px;
  transition: transform .18s cubic-bezier(.16,1,.3,1);
}
.src-section[open] .src-section-caret { transform: rotate(90deg); }
.src-section-body { padding: 12px 16px 16px; display: grid; gap: 8px; }

/* --- talk surface ---------------------------------------------------------- */

.talk-compose { margin: 16px 0 0; display: grid; gap: 10px; }
.talk-input { width: 100%; padding: 12px 14px; border: 1px solid var(--line);
              border-radius: var(--r-md); background: var(--paper); color: var(--ink);
              font: inherit; font-size: 14px; resize: vertical; }
.talk-input:disabled { opacity: 0.55; }
.talk-actions { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.talk-hint { font-size: 12px; color: var(--ink-soft); }

.live-run { margin-top: 22px; padding: 16px 18px; border: 1px solid var(--line);
            border-radius: var(--r-md); background: var(--paper); }
.run-status { margin: 6px 0 10px; font-size: 13px; font-weight: 700; }
.run-status.ok { color: var(--violet); }
.run-status.bad { color: #c0392b; }
.run-status.running { color: var(--ink-soft); display: flex; align-items: center; gap: 8px; }
.run-answer { margin: 0 0 10px; font-size: 14px; line-height: 1.6; }

/* 18.5 (`_global/design-language/SPEC.md` entry 5) — THE ONE LOADING MARK.
   Nick: "any loading instance shows a green dot with a message. I want a
   neater, claude.ai style actual animating neat loading icon." The green
   pulsing dot is gone from every surface; `src/ui/loading.js` builds this.

   currentColor, so it is right in both themes and on a dark button. 1em, so
   it scales with the words beside it. Reduced motion stops the turn and keeps
   the mark, because a still dot still says "not finished". */
.ldg { display: inline-flex; align-items: center; gap: 8px; min-width: 0; }
.ldg-t { min-width: 0; }
/* The rail's "a run is live" badge is the same mark, at the rail's size — it
   was the other green dot, and its pulse went with the first one. */
.ldg-mark, .rail-nav button .run-live {
  flex: none; width: 1em; height: 1em; display: inline-block;
  background: currentColor;
  clip-path: polygon(50% 0%, 63% 37%, 100% 50%, 63% 63%, 50% 100%, 37% 63%, 0% 50%, 37% 37%);
  animation: ldg-turn 1.15s cubic-bezier(0.4, 0, 0.2, 1) infinite;
}
.rail-nav button .run-live { font-size: 12px; margin-left: auto; }
@keyframes ldg-turn {
  0%   { transform: rotate(0deg)   scale(0.78); opacity: 0.65; }
  50%  { transform: rotate(180deg) scale(1);    opacity: 1; }
  100% { transform: rotate(360deg) scale(0.78); opacity: 0.65; }
}
@media (prefers-reduced-motion: reduce) {
  .ldg-mark { animation: none; opacity: 0.85; }
}

.step-dot { width: 5px; height: 5px; border-radius: 50%; background: var(--violet); flex: none; }
.step-text { flex: 1; min-width: 0; }
.step-at { font-size: 11px; color: var(--ink-soft); }
.step-list li { display: flex; align-items: baseline; gap: 8px; }

.btn-clear { border: 1px solid var(--line); background: var(--paper); color: var(--ink-soft);
             border-radius: var(--r-box); padding: 5px 12px; font: inherit; font-size: 11.5px;
             font-weight: 700; cursor: pointer; }

/* the nav item flashes while a run is live — 18.5: the same mark as everywhere
   else, sized and placed a few rules above with `.ldg-mark`. */

/* --- Last.fm block --------------------------------------------------------- */
.lfm { margin-top: 26px; padding-top: 20px; border-top: 1px solid var(--line); }
.lfm .run-detail { max-width: 68ch; margin-bottom: 12px; }
.lfm-input { flex: 0 1 260px; padding: 9px 12px; border: 1px solid var(--line);
             border-radius: var(--r-sm); background: var(--paper); color: var(--ink);
             font: inherit; font-size: 14px; }

/* Sources — a failed read is reported in the coral, not the body ink, so a
   failure never reads as a result. Added 2026-08-17 with the login check. */
.run-detail.bad { color: var(--coral); }
.run-detail.bad svg { vertical-align: -2px; }
.src-meta .sub-meta.faint { color: var(--ink-faint); }

/* --- Sources: one compact row per source ---------------------------------
   Three columns — mark, body, actions. The body carries the name and tagline
   on one line and every piece of evidence on the next, so a source is two
   lines instead of four and the list fits on one screen. Nothing was removed
   to get there; the honesty labelling is all still on the row. */
.src-row {
  grid-template-columns: auto minmax(0, 1fr) auto;
  gap: 12px;
  padding: 10px 14px;
  align-items: center;
}
.src-row > img { align-self: center; }
.src-body { min-width: 0; }
.src-line { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; }
.src-row .src-line b { display: inline; font-size: 14px; line-height: 1.3; }
.src-row .src-tag {
  display: inline; margin: 0; font-size: 12px; color: var(--ink-mut); line-height: 1.3;
}
.src-meta {
  display: flex; align-items: baseline; flex-wrap: wrap;
  column-gap: 6px; row-gap: 1px; margin-top: 2px;
}
/* A middot between meta items, drawn rather than typed into every string. */
.src-row .src-meta .sub-meta { display: inline; margin: 0; font-size: 11.5px; line-height: 1.45; }
.src-row .src-meta .sub-meta + .sub-meta::before { content: "· "; color: var(--ink-faint); }
.src-actions { display: flex; align-items: center; gap: 9px; flex: none; }
.src-row .run-detail { margin: 3px 0 0; font-size: 11.5px; line-height: 1.45; }

@media (max-width: 620px) {
  /* The actions drop under the body rather than squeezing the evidence text. */
  .src-row { grid-template-columns: auto minmax(0, 1fr); row-gap: 8px; }
  .src-actions { grid-column: 1 / -1; justify-content: flex-start; }
}

/* --- Talk: media chips ---------------------------------------------------
   A row of source icons under the composer. Clicking one FILLS the box and
   stops — the chip never launches a run, so a stray click cannot send the
   agent to a real site. Added 2026-08-17. */
.media-chips {
  display: flex; align-items: center; gap: 7px; flex-wrap: wrap;
  padding: 10px 2px 2px;
}
.media-chips-label {
  font-size: 12px; color: var(--ink-faint); font-weight: 650;
  letter-spacing: .01em; margin-right: 2px;
}
.media-chip {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 5px 11px 5px 7px; border-radius: var(--r-box);
  border: 1px solid var(--line); background: var(--white);
  color: var(--ink-soft); font: 650 12.5px/1 var(--font-sans);
  cursor: pointer; transition: border-color .14s, color .14s, background .14s, transform .14s;
}
.media-chip:hover:not(:disabled) {
  border-color: var(--violet); color: var(--ink);
  background: var(--violet-wash); transform: translateY(-1px);
}
.media-chip:disabled { opacity: .42; cursor: default; }
.media-chip img, .media-chip svg { display: block; flex: none; }

/* A chip that RUNS on click looks different from one that only fills the box.
   The two do different things to your Chrome, so they must not look alike. */
.media-chip-run {
  border-color: var(--violet); color: var(--ink);
  box-shadow: 0 1px 0 var(--violet-wash);
}
.media-chip-run:hover:not(:disabled) { background: var(--violet); color: var(--white); }
.media-chip-run:hover:not(:disabled) .chip-route { background: rgba(255,255,255,.22); color: var(--white); }
.chip-route {
  margin-left: 2px; padding: 1px 5px; border-radius: var(--r-box);
  background: var(--violet-wash); color: var(--violet);
  font: 700 9.5px/1.5 var(--font-sans); letter-spacing: .04em;
}

/* The recalled-memory menu sits under the steps menu on a run card. */
.fact-memory .fact-n { background: var(--violet-wash-strong); color: var(--plum); }
.run-detail.faint { color: var(--ink-faint); font-size: 12.5px; }
.run-detail.faint svg { vertical-align: -2px; margin-right: 3px; }
.talk-hint.bad { color: var(--coral); font-weight: 600; }

/* ===========================================================================
   PELTIFY — Profile and Suggestions
   Added 2026-08-18 with the profiler and the recommendation deck.

   The one idea running through all of it: A CLAIM LOOKS LIKE WHAT IT IS.
   Read facts sit on paper. Counted facts sit on paper with a number. Model
   inferences sit in violet with an `inferred` badge. Nothing borrows another
   kind's styling, because on this page the styling is part of the claim.
   =========================================================================== */

/* --- provenance badges ---------------------------------------------------- */

.prov {
  display: inline-flex; align-items: center;
  font-size: 10px; font-weight: 700; letter-spacing: 0.08em;
  text-transform: uppercase;
  padding: 3px 8px; border-radius: var(--r-box);
  border: 1px solid var(--line); background: var(--white); color: var(--ink-soft);
  white-space: nowrap;
}
.prov-read { border-color: var(--line); }
.prov-counted { border-color: rgba(94, 21, 128, 0.28); color: var(--spine); }
.prov-inferred {
  border-color: rgba(139, 31, 209, 0.4);
  background: var(--violet-wash); color: var(--violet);
}

/* --- profile -------------------------------------------------------------- */

.prof-first {
  margin-top: 22px; padding: 28px; border-radius: var(--r-lg);
  border: 1px dashed var(--line-strong); background: var(--white);
  display: grid; gap: 16px; justify-items: start;
}

/* observations — openable, because the citation IS the point */
.prof-obs { display: grid; gap: 10px; }
.prof-ob {
  border: 1px solid var(--line); border-radius: var(--r-md);
  background: var(--white); overflow: hidden;
}
.prof-ob > summary {
  cursor: pointer; padding: 14px 16px; display: flex; gap: 12px;
  align-items: baseline; list-style: none;
}
.prof-ob > summary::-webkit-details-marker { display: none; }
.prof-ob-text { flex: 1; font-size: 14.5px; line-height: 1.5; }
.prof-ob-n { font-size: 11px; color: var(--ink-faint); white-space: nowrap; }
.prof-ob[open] > summary { border-bottom: 1px solid var(--line-soft); }
.prof-ob-body { padding: 14px 16px; background: var(--paper); }

/* lately */
.prof-recent { list-style: none; margin: 0; padding: 0; display: grid; gap: 2px; }
.prof-recent li {
  display: flex; gap: 10px; align-items: baseline; padding: 9px 12px;
  border-radius: var(--r-sm); font-size: 13px;
}
.prof-recent li:nth-child(odd) { background: var(--white); }
.prof-recent-kind {
  font-size: 10px; text-transform: uppercase; letter-spacing: 0.06em;
  color: var(--ink-faint); width: 62px; flex: none;
}
.prof-recent-text { flex: 1; min-width: 0; }
.prof-recent-where { font-size: 11px; color: var(--ink-soft); }
.prof-recent-at { font-size: 11px; color: var(--ink-faint); white-space: nowrap; }

/* built from */
.prof-counts {
  display: flex; flex-wrap: wrap; gap: 10px; margin-top: 14px;
}
.prof-count {
  padding: 10px 14px; border-radius: var(--r-sm);
  border: 1px solid var(--line-soft); background: var(--white); min-width: 92px;
}
.prof-count b { display: block; font-size: 19px; font-variant-numeric: tabular-nums; }
.prof-count span { font-size: 11px; color: var(--ink-soft); }

.prof-suggest { margin-top: 30px; }

/* --- the suggestions deck ------------------------------------------------- */

.talk-suggest { margin-top: 26px; }
.sg-deck-body { min-height: 40px; }
.sg-deck-actions { margin-top: 14px; }

.sg-card {
  /* Defaults, replaced at runtime by colours sampled from the real artwork. */
  --sg-avg: var(--violet);
  --sg-dark: var(--spine);
  --sg-vivid: var(--violet);
  --sg-wash: var(--violet-wash);

  border: 1px solid var(--line); border-radius: var(--r-lg);
  background: var(--white); overflow: hidden; box-shadow: var(--shadow-sm);
  display: flex; flex-direction: column;
}

/* THE HERO IS A FIXED BAND, so every card in the deck is the same shape and
   swiping does not make the page jump. Inside it the poster is `contain` —
   shown WHOLE, because a poster's title and billing are part of the artwork
   and `cover` would crop them off — over a blurred, enlarged copy of the same
   image. The gradient behind both IS the artwork's own colour, sampled from
   its pixels in suggestions.js. Nothing here is a colour or a texture Peltify
   invented: it all comes out of the real image. */
.sg-hero {
  position: relative; aspect-ratio: 3 / 2; overflow: hidden;
  display: grid; place-items: center;
  background: linear-gradient(160deg, var(--paper-deep), var(--paper));
  transition: background 400ms ease;
}
.sg-card.has-colour .sg-hero {
  background:
    radial-gradient(120% 90% at 50% 0%, var(--sg-wash), transparent 70%),
    linear-gradient(160deg, var(--sg-avg), var(--sg-dark));
}
/* The same artwork, enlarged and blurred, filling the band behind the poster
   so a portrait cover never sits in an empty rectangle. */
.sg-art-bg {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; transform: scale(1.18);
  filter: blur(26px) saturate(1.25) brightness(0.92);
  opacity: 0.55; pointer-events: none;
}
/* THE HEIGHT IS THE DEFINITE ONE, not the width. A replaced element with only
   PERCENTAGE limits still reports its full intrinsic width as its minimum
   contribution, so a 1,000px poster made the card 1,000px wide at every
   viewport — which is what pushed the whole shell sideways on a phone. Sizing
   from the band height (definite, via the hero aspect-ratio) and letting the
   width follow keeps the poster whole AND keeps the minimum small. */
.sg-art {
  position: relative; z-index: 1;
  height: 84%; width: auto; max-width: 74%; object-fit: contain;
  border-radius: var(--r-art);
  box-shadow: 0 16px 40px rgba(20, 10, 26, 0.42), 0 2px 6px rgba(20, 10, 26, 0.24);
}
.sg-art-none {
  position: relative; z-index: 1;
  display: grid; place-items: center; align-content: center; gap: 4px;
  width: 148px; height: 76%; border-radius: var(--r-art);
  border: 1px dashed var(--line-strong);
  background: color-mix(in srgb, var(--white) 82%, transparent);
  font-size: 12px; color: var(--ink-soft); text-align: center; padding: 10px;
}
.sg-art-none small { font-size: 10px; color: var(--ink-faint); }

.sg-body { padding: 20px 22px 22px; display: grid; gap: 15px; }
.sg-kind {
  font-size: 10px; text-transform: uppercase; letter-spacing: 0.12em;
  font-weight: 700; color: var(--violet);
}
.sg-title {
  font-family: var(--font-serif); font-size: 25px; margin: 5px 0 3px;
  line-height: 1.18; letter-spacing: -0.012em; text-wrap: balance;
}
.sg-creator {
  font-size: 12.5px; color: var(--ink-soft); margin: 0;
  letter-spacing: 0.015em;
}

.sg-tags { display: flex; flex-wrap: wrap; gap: 6px; }
.sg-tag {
  font-size: 11px; padding: 3px 9px; border-radius: var(--r-box);
  background: var(--paper); border: 1px solid var(--line-soft); color: var(--ink-soft);
}
.sg-tag-from { border-color: rgba(94, 21, 128, 0.3); color: var(--spine); }

/* FACT: what it is, from a catalogue — SOMEBODY ELSE'S WORDS, so they are set
   in the serif. The typeface is doing the same work as the violet box below
   does for the inference: telling you, before you have read a syllable, which
   of the two kinds of statement you are looking at. */
/* No coloured rail. The synopsis is already marked as somebody else's words
   by being set in the serif -- which was the original argument for the rail --
   so the border was adding an edge nothing else on the card has. */
.sg-fact { padding: 2px 0; }
.sg-fact p {
  margin: 0; font-family: var(--font-serif); font-size: 15.5px;
  line-height: 1.62; color: var(--ink); letter-spacing: 0.004em;
}
.sg-prov {
  display: flex; align-items: center; gap: 4px;
  margin-top: 9px !important; font-family: var(--font-sans);
  font-size: 11px !important; color: var(--ink-faint); letter-spacing: 0.02em;
}

/* INFERENCE: why you. Unmistakably a different kind of statement — the
   product's own voice, so it keeps the interface sans. */
.sg-why {
  border-radius: var(--r-md); padding: 15px 17px;
  background: var(--violet-wash); border: 1px solid rgba(139, 31, 209, 0.22);
}
.sg-why-h {
  display: flex; align-items: center; gap: 7px; margin-bottom: 8px;
  font-size: 11px; text-transform: uppercase; letter-spacing: 0.08em;
  color: var(--violet); font-weight: 700;
}
.sg-why-h .prov { margin-left: auto; }
.sg-why > p {
  margin: 0; font-family: var(--font-sans); font-size: 14.5px;
  line-height: 1.62; color: var(--ink); letter-spacing: 0.002em;
}
.sg-because { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 11px; }
.sg-chip {
  font-size: 11px; line-height: 1.4; padding: 4px 9px; border-radius: var(--r-sm);
  background: var(--white); border: 1px solid var(--line); color: var(--ink-soft);
}
.sg-nocite { margin: 10px 0 0; font-size: 11.5px; line-height: 1.5; color: var(--coral-dark); }
.sg-model { margin: 9px 0 0 !important; font-size: 10.5px !important; color: var(--ink-faint); }

.sg-actions { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }
.sg-actions .btn-quiet.is-on {
  border-color: var(--violet); background: var(--violet-wash); color: var(--spine);
}
.sg-actions .btn-quiet.is-off { opacity: 0.55; text-decoration: line-through; }
.sg-where { margin-left: auto; text-decoration: none; }

/* Beside the agent history the deck is narrower, so the band gets shallower
   rather than the poster getting cropped. */
.sg-compact .sg-hero { aspect-ratio: 16 / 9; }
.sg-compact .sg-title { font-size: 21px; }
.sg-compact .sg-fact p { font-size: 14.5px; }

@media (max-width: 700px) {
  .sg-hero { aspect-ratio: 4 / 3; }
  .sg-title { font-size: 22px; }
  .sg-fact p { font-size: 15px; }
  .prof-recent li { flex-wrap: wrap; }
  .prof-recent-kind { width: auto; }
}

/* ===========================================================================
   THE SUGGESTION CARD, TWO COLUMNS.  phase3, 2026-08-19.

   Left is the WORK (somebody else's fact), right is PELTIFY (our inference).
   The split is load-bearing, not layout taste: a reader can see which half is
   sourced and which half is inferred before reading a word. Under 860px the
   columns stack, work first, because the artwork is what you recognise.
   =========================================================================== */

.sg-split {
  display: grid;
  grid-template-columns: minmax(0, 0.82fr) minmax(0, 1.18fr);
  gap: 0;
  align-items: stretch;
}
/* Both children need this or a long unbroken title/URL sets the column's
   minimum to its own width and pushes the whole shell sideways. */
.sg-col-work, .sg-col-why { min-width: 0; }

.sg-col-work {
  display: flex; flex-direction: column; gap: 12px;
  padding: 0 0 20px;
  border-right: 1px solid var(--line);
  background: linear-gradient(180deg, transparent 62%, var(--paper) 100%);
}
.sg-col-work > *:not(.sg-hero) { padding-inline: 20px; }

/* NO SIDE PADDING ON THE ARTWORK. The poster runs the full width of its own
   column and the panel is squarer than the old wide band, which is what "the
   image is too big and it has padding on the side" was about. It is still
   `contain`, so a poster's own title and billing are never cropped off — a
   portrait cover sits full-height against a blurred copy of its own pixels
   rather than against invented colour. */
.sg-col-work .sg-hero { aspect-ratio: 4 / 3; border-radius: 0; }
.sg-col-work .sg-art {
  height: 100%; width: auto; max-width: 100%;
  border-radius: var(--r-art); box-shadow: none;
}
.sg-col-work .sg-titles { margin-top: 2px; }
.sg-col-work .sg-title { font-size: 22px; margin: 4px 0 2px; }
.sg-col-work .sg-fact { margin-top: 2px; }
.sg-col-work .sg-fact p { font-size: 14px; line-height: 1.6; }

.sg-col-why {
  display: flex; flex-direction: column; gap: 12px;
  padding: 20px 22px 20px;
  background:
    radial-gradient(120% 80% at 100% 0%, var(--violet-wash), transparent 62%),
    var(--white);
}

.sg-why-head { display: flex; align-items: center; gap: 8px; }
.sg-why-head h4 {
  margin: 0; font-size: 16.5px; font-weight: 700; color: var(--spine);
  letter-spacing: -0.01em;
}
.sg-why-head .prov { margin-left: auto; }
.sg-why-mark {
  display: grid; place-items: center; width: 26px; height: 26px;
  border-radius: 50%; background: var(--violet-wash); color: var(--violet);
  flex: 0 0 auto;
}
/* The product's own voice: sans, never the serif the sourced synopsis uses. */
.sg-why-lead {
  margin: 0; font-family: var(--font-sans);
  font-size: 15px; line-height: 1.62; color: var(--ink);
}

.sg-because { display: flex; flex-wrap: wrap; gap: 6px; margin: 0; }
.sg-because-h {
  flex: 1 0 100%; margin: 2px 0 0;
  font-size: 9.5px; text-transform: uppercase; letter-spacing: 0.11em;
  font-weight: 700; color: var(--ink-faint);
}

/* --- how this lines up with you ---------------------------------------------
   Every bar is one arithmetic fact. Deliberately NOT a percentage match score:
   the number at the end is the item count, and the caption says the bar is
   that count against the largest here and nothing else. */
.sg-align {
  border-top: 1px solid var(--line-soft); padding-top: 13px; margin-top: 2px;
}
.sg-align-h {
  margin: 0 0 9px; font-size: 9.5px; text-transform: uppercase;
  letter-spacing: 0.11em; font-weight: 700; color: var(--ink-faint);
}
.sg-bars { list-style: none; margin: 0; padding: 0; display: grid; gap: 7px; }
.sg-bar-row {
  display: grid; grid-template-columns: minmax(72px, 0.42fr) 1fr auto;
  align-items: center; gap: 10px;
}
.sg-bar-label {
  font-size: 12.5px; color: var(--ink-soft);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.sg-bar-track {
  height: 7px; border-radius: 99px; background: var(--paper-deep);
  overflow: hidden; min-width: 0;
}
.sg-bar-fill {
  display: block; height: 100%; border-radius: 99px;
  background: linear-gradient(90deg, var(--violet), var(--sg-vivid, var(--violet)));
}
.sg-bar-n {
  font-size: 11.5px; font-variant-numeric: tabular-nums;
  color: var(--ink-faint); min-width: 22px; text-align: right;
}
.sg-align-foot, .sg-align-none {
  margin: 9px 0 0; font-size: 11px; line-height: 1.5; color: var(--ink-faint);
}
.sg-align-none {
  border-top: 1px solid var(--line-soft); padding-top: 12px; margin-top: 2px;
}

/* --- keep / not for me / pelt ------------------------------------------------
   Three states, three weights. Pelt is the emphatic one because it is the only
   action that leaves Peltify, so it should never be the one clicked by
   accident. */
.sg-actions {
  display: flex; gap: 8px; flex-wrap: wrap; align-items: center;
  margin-top: auto; padding-top: 13px;
  border-top: 1px solid var(--line-soft);
}
.sg-verdict {
  flex: 1 1 0; min-width: 96px;
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  padding: 9px 12px; border-radius: var(--r-sm);
  border: 1px solid var(--line-strong); background: var(--white);
  font: inherit; font-size: 13px; font-weight: 600; color: var(--ink-soft);
  cursor: pointer;
  transition: background 130ms ease, border-color 130ms ease, color 130ms ease;
}
.sg-verdict:hover { border-color: var(--violet); color: var(--spine); }
.sg-keep.is-on {
  background: var(--violet-wash); border-color: var(--violet);
  color: var(--spine);
}
.sg-no.is-on {
  background: var(--paper-deep); border-color: var(--line-strong);
  color: var(--ink-faint); text-decoration: line-through;
}
.sg-pelt {
  background: var(--coral, #c8462f); border-color: var(--coral, #c8462f);
  color: #fff;
}
.sg-pelt:hover { filter: brightness(1.06); border-color: var(--coral, #c8462f); color: #fff; }
.sg-pelt.is-on { filter: brightness(0.92); }

/* Did the verdict actually reach durable memory? Never a tick that appears
   regardless of what the server said. */
.sg-mem { margin: 0; font-size: 11px; line-height: 1.5; }
.sg-mem.is-saving { color: var(--ink-faint); }
.sg-mem.is-ok { color: var(--violet); }
.sg-mem.is-warn { color: var(--coral-dark); }

.sg-col-why .sg-model { margin: 0 !important; }
.sg-col-why .sg-where {
  display: inline-flex; align-items: center; gap: 5px;
  margin: 0; font-size: 12.5px; font-weight: 600;
  color: var(--violet); text-decoration: none;
}
.sg-col-why .sg-where:hover { text-decoration: underline; }

@media (max-width: 860px) {
  .sg-split { grid-template-columns: minmax(0, 1fr); }
  .sg-col-work {
    border-right: 0; border-bottom: 1px solid var(--line);
    padding-bottom: 16px;
  }
  .sg-col-work .sg-hero { aspect-ratio: 16 / 9; }
  .sg-col-why { padding: 17px 18px 18px; }
  .sg-verdict { flex: 1 1 30%; }
}
@media (max-width: 520px) {
  .sg-col-work .sg-hero { aspect-ratio: 4 / 3; }
  .sg-col-work > *:not(.sg-hero) { padding-inline: 16px; }
  .sg-verdict { flex: 1 1 100%; }
}

/* ===========================================================================
   SCAN — the first screen.  phase3, 2026-08-19.

   A logo grid and a short list of rows. Deliberately plain: this is the screen
   that has to be obvious to somebody who has never heard of a browser agent,
   so nothing on it competes with the tiles and the one button per row.
   =========================================================================== */

.scan { display: grid; gap: 18px; }

.scan-grid {
  display: grid; gap: 10px;
  grid-template-columns: repeat(auto-fill, minmax(158px, 1fr));
}
.scan-tile {
  display: flex; align-items: center; gap: 10px;
  padding: 13px 14px; border-radius: var(--r-md);
  border: 1.5px solid var(--line); background: var(--white);
  font: inherit; font-size: 14.5px; font-weight: 600; color: var(--ink);
  cursor: pointer; text-align: left; min-width: 0;
  transition: border-color 130ms ease, box-shadow 130ms ease, transform 130ms ease;
}
.scan-tile:hover { border-color: var(--tile-accent); transform: translateY(-1px); }
.scan-tile.is-on {
  border-color: var(--tile-accent);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--tile-accent) 16%, transparent);
}
.scan-tile.is-done { border-color: var(--ok, #17864a); }
.scan-tile-name {
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0;
}
.scan-tile-tag {
  margin-left: auto; flex: 0 0 auto;
  font-size: 9px; font-weight: 700; letter-spacing: 0.1em; text-transform: uppercase;
  padding: 2px 6px; border-radius: var(--r-box);
  background: var(--violet-wash); color: var(--violet);
}
.scan-go {
  margin-left: auto; flex: 0 0 auto;
  display: inline-flex; align-items: center; gap: 7px;
  padding: 9px 16px; border-radius: var(--r-sm);
  border: 1px solid var(--violet); background: var(--violet); color: #fff;
  font: inherit; font-size: 13.5px; font-weight: 700; cursor: pointer;
  transition: filter 130ms ease;
}
.scan-go:hover:not(:disabled) { filter: brightness(1.08); }
.scan-go:disabled { opacity: 0.6; cursor: default; }
.scan-go.is-quiet {
  background: var(--white); color: var(--ink-soft); border-color: var(--line-strong);
}
.scan-go.is-running { background: var(--coral); border-color: var(--coral); }
.scan-go.is-done {
  background: transparent; border-color: transparent;
  color: var(--ok, #17864a); cursor: default; padding-inline: 4px;
}
.scan-go.is-off {
  background: var(--paper-deep); border-color: var(--line-strong);
  color: var(--ink-faint); cursor: default;
}

/* Why the button says what it says. Never a tooltip — the difference between
   "verified signed in" and "there is a cookie and we are guessing" is the
   thing this page most needs to communicate. */
.scan-why {
  margin: 0; font-size: 11.5px; line-height: 1.5; color: var(--ink-faint);
}
.scan-why.is-warn { color: var(--coral-dark); }

.scan-steps { font-size: 12px; }
.scan-steps > summary { cursor: pointer; color: var(--ink-soft); }
.scan-steplist {
  list-style: none; margin: 7px 0 0; padding: 0 0 0 12px;
  display: grid; gap: 3px; border-left: 2px solid var(--line-soft);
}
.scan-steplist li { font-size: 11.5px; color: var(--ink-faint); line-height: 1.45; }

.scan-answer { margin-top: 4px; font-size: 12.5px; }
.scan-answer > summary { cursor: pointer; color: var(--violet); font-weight: 600; }
@media (max-width: 560px) {
  .scan-grid { grid-template-columns: repeat(auto-fill, minmax(132px, 1fr)); }
  .scan-go { margin-left: 0; width: 100%; justify-content: center; }
}

/* The deck now sits directly under the headline, so it needs a little room to
   read as the page's answer rather than as another block. */
.prof-suggest { margin: 4px 0 6px; }

/* Quota. A limit is only honest if it is counted server-side and stated on the
   surface that spends it. */
.sg-quota {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  margin: 0 0 10px; padding: 9px 13px; border-radius: var(--r-sm);
  background: var(--paper-deep); font-size: 12px; color: var(--ink-soft);
}
.sg-quota b { color: var(--ink); }
.sg-quota.is-out { background: color-mix(in srgb, var(--coral) 9%, transparent); }
.sg-quota-cta {
  margin-left: auto; border: 0; background: none; padding: 0; font: inherit;
  font-size: 12px; font-weight: 700; color: var(--violet); cursor: pointer;
}
.sg-quota-cta:hover { text-decoration: underline; }

/* ===========================================================================
   phase4 — the user-facing half.  2026-08-22.

   Everything below is new surface: the two onboarding doors, the confirm
   dialogs, the login portal, the charts that replaced the counted-row dumps,
   the account panel, and the one Scan button.

   Three things hold this together and are worth stating once rather than
   repeating in twenty rules:

     PROVENANCE HAS A COLOUR AND IT IS ONLY EVER ONE THING. Violet fills mean
     Peltify counted your own material. Outlines mean somebody else's
     catalogue. That mapping is used in the charts, the web and the badges,
     and nothing decorative is allowed to borrow it.

     DESTRUCTIVE IS CORAL AND NOTHING ELSE IS. Reset, delete, remove. If a
     control is coral it removes something; if it removes something it is
     coral. No exceptions, so the colour keeps meaning what it means.

     MOTION IS SHORT AND ONLY ON REAL TRANSITIONS. Cards advancing, panels
     opening. Nothing loops, nothing pulses except a genuinely live run.
   =========================================================================== */

/* ---------------------------------------------------------- onboarding ----- */

.onb-doors {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 12px;
  margin: 22px 0 4px;
}

/* THE WAY PAST ALL OF IT, UNDER THE BOX. Peltify works with no account, and
   the one control that says so is not allowed to be a grey link in a corner. */
.onb-skip {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  width: 100%;
  margin: 18px auto 0;
  padding: 14px 18px;
  border: 1px dashed var(--line-strong);
  border-radius: var(--r-md);
  background: transparent;
  color: var(--ink-soft);
  font-size: 14px;
  font-weight: 600;
  transition: border-color var(--fast) var(--ease), color var(--fast) var(--ease),
              background var(--fast) var(--ease);
}

/* The Terms / Privacy line under the doors and above "Create account". Quiet,
   but a real sentence with real links — it is the moment the contract forms. */
.onb-legal {
  margin: 14px 0 0;
  font-size: 12.5px;
  line-height: 1.5;
  color: var(--ink-faint);
}

/* ------------------------------------------------------------- dialogs ----- */

.ask-scrim {
  position: fixed;
  inset: 0;
  z-index: 90;
  display: grid;
  place-items: center;
  padding: 20px;
  background: rgba(36, 20, 46, 0.4);
  backdrop-filter: blur(3px);
  opacity: 0;
  transition: opacity var(--fast) var(--ease);
}

.ask-scrim.is-in { opacity: 1; }
.ask-scrim.is-out { opacity: 0; }

.ask {
  width: min(440px, 100%);
  padding: 24px;
  border-radius: var(--r-lg);
  background: var(--white);
  box-shadow: var(--shadow);
  transform: translateY(8px) scale(0.98);
  transition: transform var(--med) var(--ease);
}

.ask-scrim.is-in .ask { transform: none; }

.ask-title { margin: 0 0 8px; font-size: 19px; line-height: 1.3; }
.ask-body { margin: 0 0 10px; font-size: 14px; color: var(--ink-soft); line-height: 1.55; }
.ask-phrase { color: var(--ink); }
.ask-phrase b { font-family: var(--font-mono); background: var(--paper-deep);
                padding: 1px 6px; border-radius: var(--r-box); }

.ask-input {
  width: 100%;
  padding: 11px 13px;
  border: 1px solid var(--line-strong);
  border-radius: var(--r-sm);
  background: var(--paper);
  font-family: var(--font-mono);
}

.ask-note {
  display: flex;
  gap: 6px;
  align-items: center;
  margin: 10px 0 0;
  font-size: 12px;
  color: var(--ink-faint);
}

.ask-actions {
  display: flex;
  justify-content: flex-end;
  gap: 10px;
  margin-top: 20px;
}

.ask-btn {
  padding: 10px 18px;
  border-radius: var(--r-box);
  border: 1px solid var(--line-strong);
  background: var(--white);
  font-weight: 600;
  font-size: 14px;
}

.ask-btn.ask-yes { background: var(--ink); border-color: var(--ink); color: var(--paper); }
/* Coral means it removes something. It never means anything else. */
.ask-btn.ask-yes.is-danger { background: var(--coral-dark); border-color: var(--coral-dark); }
.ask-btn:disabled { opacity: 0.4; cursor: default; }

.credential-card {
  position: relative; width: min(430px, calc(100vw - 28px));
  transition: width 160ms ease;
}
.credential-card.has-challenge { width: min(520px, calc(100vw - 28px)); }
.credential-title {
  display: grid; grid-template-columns: auto 1fr auto; align-items: center;
  gap: 11px; margin-bottom: 20px;
}
.credential-title .ask-title { margin: 1px 0 0; }
.credential-source {
  display: block; color: var(--ink-faint); font-size: 10px; font-weight: 800;
  letter-spacing: 0.1em; text-transform: uppercase;
}
.credential-close {
  width: 34px; height: 34px; display: grid; place-items: center;
  border: 0; border-radius: 50%; background: transparent; color: var(--ink-soft);
}
.credential-close:hover { background: var(--paper-deep); color: var(--ink); }
.credential-form { display: grid; gap: 14px; }
.credential-privacy {
  display: flex; align-items: center; gap: 7px; margin: 0;
  color: var(--ink-soft); font-size: 12.5px; line-height: 1.45;
}
.credential-privacy svg { flex: 0 0 auto; color: var(--violet); }
.credential-status {
  margin: 0; padding: 11px 12px; border-radius: var(--r-sm);
  background: var(--paper-deep); color: var(--ink-soft); font-size: 13px;
  line-height: 1.45;
}
.credential-status[hidden] { display: none; }
.credential-status.is-bad { background: var(--stop-wash); color: var(--coral-dark); }
.credential-status.is-ok { background: var(--ok-wash); color: var(--ok); }
.credential-submit { width: 100%; justify-content: center; margin-top: 2px; }
.credential-challenge-copy {
  margin: -6px 0 12px; color: var(--ink-soft); font-size: 13px; line-height: 1.45;
}
.credential-challenge { display: grid; gap: 10px; outline: none; }
.credential-challenge:focus-visible {
  border-radius: var(--r-sm); box-shadow: 0 0 0 3px var(--violet-wash);
}
.credential-challenge-screen {
  position: relative; overflow: hidden; min-height: 260px; border: 1px solid var(--line);
  border-radius: var(--r-sm); background: var(--paper-deep);
}
.credential-challenge-frame {
  display: none; width: 100%; max-height: min(56vh, 520px); object-fit: contain;
  background: white; cursor: default; user-select: none;
}
.credential-challenge-loading {
  position: absolute; inset: 0; display: grid; place-items: center;
  padding: 24px; color: var(--ink-soft); font-size: 13px; text-align: center;
}

.companion-card { width: min(680px, calc(100vw - 28px)); }
.companion-title { display: flex; align-items: center; gap: 10px; }
.companion-title .ask-title { margin-bottom: 0; }
.companion-status {
  margin: 14px 0; padding: 11px 12px; border-radius: var(--r-box);
  background: var(--paper-deep); color: var(--ink-soft); line-height: 1.45;
}
.companion-status.is-ok { color: var(--ok); }
.companion-status.is-warn { color: var(--warn); }
.companion-setup { margin: 10px 0; padding: 12px; border: 1px solid var(--line); border-radius: var(--r-box); }
.companion-setup[hidden] { display: none; }
.companion-fallback-note { margin: 13px 0; color: var(--warn); font-size: 13px; line-height: 1.45; }
.companion-actions { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: 8px; }
.companion-fallback { flex-basis: 100%; color: var(--warn); }

/* -------------------------------------------------------------- portal ----- */

.portal-scrim {
  position: fixed;
  inset: 0;
  z-index: 95;
  display: grid;
  place-items: center;
  padding: 18px;
  background: rgba(36, 20, 46, 0.55);
  backdrop-filter: blur(4px);
  opacity: 0;
  transition: opacity var(--med) var(--ease);
}

.portal-scrim.is-in { opacity: 1; }
.portal-scrim.is-out { opacity: 0; }

.portal {
  display: flex;
  flex-direction: column;
  width: min(1080px, 100%);
  max-height: min(92vh, 900px);
  border-radius: var(--r-lg);
  background: var(--white);
  box-shadow: var(--shadow);
  overflow: hidden;
}

.portal-head {
  display: flex;
  align-items: center;
  gap: 11px;
  padding: 14px 16px;
  border-bottom: 1px solid var(--line-soft);
}

.portal-head-t { flex: 1; min-width: 0; display: grid; gap: 2px; }
.portal-head-t b { font-size: 15px; }
.portal-head-t > span {
  display: flex;
  align-items: center;
  gap: 7px;
  font-size: 12px;
  color: var(--ink-faint);
  min-width: 0;
}

.portal-url { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.portal-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--line-strong);
  flex: none;
}

.portal-dot.is-on { background: var(--ok); box-shadow: 0 0 7px var(--ok); }

.portal-stage {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 12px 16px;
  background: var(--paper);
}

.portal-hint {
  display: flex;
  gap: 8px;
  align-items: flex-start;
  padding: 9px 12px;
  border-radius: var(--r-sm);
  background: var(--violet-wash);
  color: var(--plum);
  font-size: 12.5px;
  line-height: 1.45;
}

.portal-screen {
  position: relative;
  flex: 1;
  min-height: 0;
  display: grid;
  place-items: center;
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: #111;
  overflow: hidden;
}

.portal-frame {
  display: none;
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
}

.portal-wait {
  display: flex;
  gap: 8px;
  align-items: center;
  color: rgba(255, 253, 250, 0.7);
  font-size: 13px;
}

.portal-status { margin: 0; padding: 0 16px; font-size: 13px; color: var(--ink-soft); }
.portal-status:empty { display: none; }
.portal-status.is-warn { color: var(--warn); }
.portal-status.is-bad { color: var(--stop); }

.portal-foot {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 14px;
  padding: 13px 16px 16px;
  border-top: 1px solid var(--line-soft);
}

.portal-legal {
  flex: 1 1 300px;
  margin: 0;
  font-size: 12px;
  line-height: 1.5;
  color: var(--ink-faint);
}

.portal-actions { display: flex; gap: 9px; align-items: center; margin-left: auto; }
.portal-actions .btn-ghost.is-on { color: var(--ok); border-color: var(--ok); }

/* -------------------------------------------------------------- charts ----- */

.chart { display: grid; gap: 4px; }

.chart-bars { list-style: none; margin: 0; padding: 0; display: grid; gap: 5px; }

.chart-row {
  display: grid;
  grid-template-columns: minmax(80px, 34%) 1fr auto;
  align-items: center;
  gap: 10px;
}

.chart-label {
  border: 0;
  background: none;
  padding: 0;
  text-align: left;
  font-size: 12.5px;
  color: var(--ink);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

button.chart-label { text-decoration: underline; text-decoration-color: var(--line-strong);
                     text-underline-offset: 3px; }
button.chart-label:hover { color: var(--plum); text-decoration-color: var(--violet); }

.chart-track {
  height: 9px;
  border-radius: var(--r-pill);
  background: var(--paper-deep);
  overflow: hidden;
}

/* A violet fill is Peltify counting your own material. Nothing decorative
   uses this colour, so a filled bar always means the same thing. */
.chart-fill {
  display: block;
  height: 100%;
  border-radius: inherit;
  background: linear-gradient(90deg, var(--violet), var(--plum));
}

.chart-n {
  font-family: var(--font-mono);
  font-size: 11.5px;
  color: var(--ink-soft);
  min-width: 2.4em;
  text-align: right;
}

.chart-n.is-partial { color: var(--warn); }

.chart-foot { margin: 6px 0 0; font-size: 11.5px; color: var(--ink-faint); line-height: 1.5; }

/* --------------------------------------------------------------- strip ----- */

.strip { display: grid; gap: 9px; }

.strip-band {
  display: flex;
  height: 16px;
  border-radius: var(--r-pill);
  overflow: hidden;
  background: var(--paper-deep);
}

.strip-seg { display: block; height: 100%; }
.strip-seg.seg-0, .strip-dot.seg-0 { background: var(--violet); }
.strip-seg.seg-1, .strip-dot.seg-1 { background: var(--plum); }
.strip-seg.seg-2, .strip-dot.seg-2 { background: var(--coral); }
.strip-seg.seg-3, .strip-dot.seg-3 { background: #2f7d4f; }
.strip-seg.seg-4, .strip-dot.seg-4 { background: var(--ink-soft); }

.strip-key {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 8px 16px;
}

.strip-key li { display: flex; align-items: center; gap: 6px; font-size: 12px; }
.strip-dot { width: 9px; height: 9px; border-radius: 3px; flex: none; }
.strip-name { color: var(--ink); }
.strip-n { font-family: var(--font-mono); color: var(--ink-faint); font-size: 11px; }

/* ------------------------------------------------------------ timeline ----- */

.tl { display: grid; gap: 5px; margin-bottom: 14px; }

.tl-bars {
  display: flex;
  align-items: flex-end;
  gap: 2px;
  height: 54px;
  padding: 0 1px;
}

.tl-bar {
  flex: 1;
  min-width: 2px;
  border-radius: 2px 2px 0 0;
  background: var(--violet);
}

.tl-bar.is-empty { background: var(--line); }

.tl-axis {
  display: flex;
  justify-content: space-between;
  font-size: 10.5px;
  color: var(--ink-faint);
}

/* ------------------------------------------------------------- account ----- */

.acct { display: grid; gap: 8px; margin-top: 6px; }

.acct-who {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 14px;
  border-radius: var(--r-md);
  background: var(--paper);
}

.avatar-lg { width: 44px; height: 44px; font-size: 18px; }
.acct-who > div { flex: 1; min-width: 0; display: grid; gap: 1px; }
.acct-mail { font-size: 12.5px; color: var(--ink-soft); overflow: hidden;
             text-overflow: ellipsis; }

.acct-row {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  padding: 13px 14px;
  text-align: left;
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--white);
  transition: border-color var(--fast) var(--ease), background var(--fast) var(--ease);
}

.acct-row:hover { border-color: var(--line-strong); background: var(--paper); }
.acct-row > div { display: grid; gap: 1px; }
.acct-row b { font-size: 14px; }
.acct-row span { font-size: 12px; color: var(--ink-soft); line-height: 1.45; }

.acct-row.acct-signin { border-color: var(--violet); color: var(--plum); }
.acct-row.acct-signin:hover { background: var(--violet-wash); }

/* Coral means it removes something. */
.acct-row.is-danger { color: var(--stop); border-color: rgba(191, 62, 47, 0.35); }
.acct-row.is-danger span { color: var(--stop); opacity: 0.8; }
.acct-row.is-danger:hover { background: var(--stop-wash); border-color: var(--coral-dark); }

/* -------------------------------------------------------------- switch ----- */

.switch {
  width: 46px;
  height: 27px;
  flex: none;
  padding: 3px;
  border: 1px solid var(--line-strong);
  border-radius: var(--r-pill);
  background: var(--paper-deep);
  transition: background var(--fast) var(--ease), border-color var(--fast) var(--ease);
}

.switch[aria-checked="true"] { background: var(--violet); border-color: var(--violet); }

.switch-knob {
  display: block;
  width: 19px;
  height: 19px;
  border-radius: 50%;
  background: var(--white);
  box-shadow: var(--shadow-sm);
  transition: transform var(--fast) var(--ease);
}

.switch[aria-checked="true"] .switch-knob { transform: translateX(19px); }

.brain-settings { margin: 14px 0 4px; }

.brain-setting {
  display: flex;
  align-items: center;
  gap: 16px;
  padding: 13px 15px;
  border: 1px solid var(--line-soft);
  border-radius: var(--r-md);
  background: var(--white);
}

.brain-setting > div { flex: 1; min-width: 0; display: grid; gap: 2px; }
.brain-setting b { font-size: 14px; }
.brain-setting span { font-size: 12.5px; color: var(--ink-soft); line-height: 1.45; }

.brain-activity { margin-top: 8px; }

/* ---------------------------------------------------------------- scan ----- */

.scan-grid-sm { grid-template-columns: repeat(auto-fill, minmax(96px, 1fr)); }
.scan-tile-sm { padding: 10px 8px; }

.scan-public {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  margin: 9px 0 2px;
}

.scan-public-k { font-family: var(--font-mono); color: var(--ink-faint); font-size: 13px; }

.scan-username {
  width: 170px;
  padding: 7px 11px;
  border: 1px solid var(--line-strong);
  border-radius: var(--r-sm);
  background: var(--white);
  font-size: 13px;
}

.scan-public-note { flex: 1 1 220px; font-size: 11.5px; color: var(--ink-faint); line-height: 1.45; }


.talk-chip-note { margin: 8px 0 0; font-size: 12px; color: var(--ink-faint); }

.btn-link {
  border: 0;
  background: none;
  padding: 0;
  font: inherit;
  font-weight: 700;
  color: var(--plum);
  text-decoration: underline;
  text-underline-offset: 3px;
}

/* ------------------------------------------------------------- profile ----- */


.prof-first-actions { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 16px; }

.prof-sources { list-style: none; margin: 14px 0 0; padding: 0; display: grid; gap: 6px; }
.prof-sources li { display: flex; flex-wrap: wrap; gap: 8px; align-items: baseline;
                   font-size: 12.5px; }
.prof-sources span { color: var(--ink-soft); }

/* The cited sentences, under the picture rather than instead of it. */
.sg-because {
  display: grid;
  gap: 5px;
  margin: 12px 0 0;
  padding: 0 0 0 15px;
  list-style: none;
}

.sg-because li {
  position: relative;
  font-size: 12px;
  line-height: 1.5;
  color: var(--ink-soft);
}

.sg-because li::before {
  content: "";
  position: absolute;
  left: -13px;
  top: 8px;
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--violet);
}

.sg-mem.is-warn { color: var(--warn); font-size: 11.5px; margin: 8px 0 0; }

@media (max-width: 720px) {
  .chart-row { grid-template-columns: minmax(64px, 40%) 1fr auto; }
  .portal { max-height: 96vh; }
  .portal-legal { flex-basis: 100%; }
}

/* The tile becomes a card rather than a row (2026-08-22). It is a grid of
   LOGOS now — the thing you scan by is the app's mark, and a row of small icons
   beside text read as a list of settings. A card also gives the "linked" badge
   and the running ring somewhere to sit that is not the label's space. */
.scan-tile {
  position: relative;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 7px;
  padding: 16px 10px 13px;
  text-align: center;
  font-size: 13px;
}
.scan-tile .scan-tile-name { max-width: 100%; }
.scan-tile-tag { margin-left: 0; }
.scan-tile.is-done { border-color: var(--ok); }
.scan-grid { grid-template-columns: repeat(auto-fill, minmax(112px, 1fr)); }

/* ---------------------------------------------------- the sign-in window ----
   Its own popup, at login-dialog size. Four things on screen: which site, where
   the page is, Cancel, and a confirm button that is dead until the site itself
   says the sign-in worked. Everything else that used to be here — the paragraph
   about encryption at rest, a Typing toggle, a hint about clicking a field
   first — was true and was not what anybody needs while looking at a password
   box. */

.pw-body {
  margin: 0;
  height: 100vh;
  overflow: hidden;
  background: var(--paper);
}

#pw {
  display: grid;
  grid-template-rows: auto 1fr auto;
  height: 100vh;
}

.pw-head {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 11px 16px;
  border-bottom: 1px solid var(--line-soft);
  background: var(--white);
  min-width: 0;
}

.pw-title { font-size: 15px; flex: none; }

.pw-loc {
  display: flex;
  align-items: center;
  gap: 7px;
  min-width: 0;
  margin-left: auto;
  font-size: 12px;
  color: var(--ink-faint);
}

.pw-url {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-family: var(--font-mono);
  font-size: 11.5px;
}

.pw-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--line-strong);
  flex: none;
}

.pw-dot.is-on { background: var(--ok); box-shadow: 0 0 7px var(--ok); }

.pw-screen {
  position: relative;
  min-height: 0;
  display: grid;
  place-items: center;
  background: #111;
  overflow: hidden;
}

.pw-frame {
  display: none;
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
  /* A POINTER, NOT A CROSSHAIR. The crosshair was left over from the panel,
     where a toggle meant clicks sometimes did nothing and the cursor had to say
     which mode you were in. There is no mode here — every click goes through —
     so the cursor should say what a clickable page says. */
  cursor: default;
}

.pw-wait {
  position: absolute;
  display: flex;
  gap: 8px;
  align-items: center;
  color: rgba(255, 253, 250, 0.7);
  font-size: 13px;
}

.pw-foot {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 12px;
  padding: 12px 16px;
  border-top: 1px solid var(--line-soft);
  background: var(--white);
}

.pw-status {
  flex: 1 1 260px;
  margin: 0;
  font-size: 12.5px;
  line-height: 1.45;
  color: var(--ink-soft);
}

.pw-status.is-ok { color: var(--ok); font-weight: 600; }
.pw-status.is-warn { color: var(--warn); }
.pw-status.is-bad { color: var(--stop); }

.pw-actions { display: flex; gap: 9px; align-items: center; margin-left: auto; }

/* THE GATE, MADE VISIBLE. Disabled is genuinely inert here, not styled to look
   pressable — the button is the claim "the site recognised you", and it must
   not look available before that is true. */
.pw-confirm { min-width: 200px; justify-content: center; }
.pw-confirm:disabled { opacity: 0.45; cursor: not-allowed; }
.pw-confirm.is-ready { background: var(--ok); border-color: var(--ok); }

/* The one-line command that reads a log-delivered sign-in code. */
.onb-code-hint {
  margin: 10px 0 0;
  font-size: 12px;
  color: var(--ink-soft);
  line-height: 1.6;
}

/* One line under the whole field, instead of a qualifier on every card. */
.prof-basis-row {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 14px;
  margin: 12px 0 0;
  font-size: 12px;
  color: var(--ink-soft);
}
.basis-chip { display: inline-flex; align-items: center; gap: 4px; }
.basis-chip[data-tone="inferred"] { color: var(--ink-faint); }

/* The loading state carries its own escape hatch — see prof-waiting in
   profile.js. A spinner with no button was a dead end for real users. */
.prof-waiting {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 10px;
  margin: 18px 0;
}


/* ===========================================================================
   PROFILE.  Rewritten 2026-08-24, and this is now the ONLY place it is styled.

   WHY A REWRITE RATHER THAN ANOTHER PASS. `.prof-hero` had three separate
   definitions in this file, 1,900 lines apart, each from a different restyle
   and each partly overriding the last. `.prof-block` had two. The page was not
   badly designed so much as designed three times on top of itself, and the
   result reads exactly like that: nothing sits at a consistent height, radius
   or weight, which is what "clunky" and "not popping out" were describing.
   Those blocks are deleted. This one replaces all of them.

   THE FOUR RULES EVERYTHING BELOW OBEYS:

     RADIUS  12 controls, 16 inner, 20 cards, 22 hero, 999 pills. Nothing else.
             Timid, mixed radii were most of the clunky feeling.

     HEIGHT  Two shadows, `--lift` and `--raise`. A card gets a hairline border
             OR a real shadow, never both at full strength.

     COLOUR  One hue per medium, from tokens.css, reached through `--m`. The
             same violet is Music in its chip, its bar, its donut wedge and its
             sheet. Colour means one thing on this page or it means nothing.

     NUMBER  Every figure is mono and tabular, so a count changing from 9 to 10
             does not shift the column it sits in.

   AND THE ONE RULE THAT IS NOT A STYLE RULE: counted and inferred must stay
   told apart at a glance. Counted tiles are solid-edged and their donut wedge
   is the full stroke. Inferred tiles are dashed and their wedge is drawn thin
   -- the ANGLE still carries the count exactly, because the angle is the
   number; the thickness carries how well evidenced it is. A hollow wedge that
   also shrank would be a lie about arithmetic told in a friendlier shape.
   =========================================================================== */

.prof-suggest { margin: 2px 0 22px; }

/* ------------------------------------------------------------- the hero --- */

.prof-hero {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 26px;
  align-items: center;
  margin: 22px 0;
  padding: 26px 28px;
  border-radius: var(--r-box);
  color: var(--hero-ink);
  background:
    radial-gradient(84% 120% at 88% -10%, rgba(139, 31, 209, 0.55) 0%, transparent 58%),
    radial-gradient(60% 90% at 8% 108%, rgba(191, 62, 47, 0.22) 0%, transparent 62%),
    linear-gradient(128deg, #2a0f45 0%, #45146d 52%, #5e1580 100%);
  box-shadow: var(--raise);
  overflow: hidden;
}

/* A quiet field of light behind the numbers -- the same idea as the concept's
   constellation, drawn in CSS so it costs no request and scales cleanly. It is
   decoration and it is masked to fade, so it can never compete with a figure. */
.prof-hero::after {
  content: "";
  position: absolute;
  inset: 0;
  background-image: radial-gradient(rgba(255, 255, 255, 0.5) 1px, transparent 1.4px);
  background-size: 26px 26px;
  opacity: 0.14;
  -webkit-mask-image: radial-gradient(70% 100% at 88% 0%, #000 0%, transparent 70%);
  mask-image: radial-gradient(70% 100% at 88% 0%, #000 0%, transparent 70%);
  pointer-events: none;
}
.prof-hero > * { position: relative; z-index: 1; }

.prof-hero-main {
  display: flex;
  flex-direction: column;
  gap: 10px;
  min-width: 0;
}
.prof-hero-top {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 14px; flex-wrap: wrap;
}
.prof-hero-title {
  margin: 0;
  font-family: var(--font-serif);
  font-size: clamp(26px, 3.4vw, 34px);
  line-height: 1.1;
  letter-spacing: -0.015em;
  color: var(--hero-ink);
  text-wrap: balance;
}
.prof-hero-when {
  font-size: 12.5px;
  color: var(--hero-ink-faint);
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
  margin: 4px 0 0;
}
.prof-hero .prof-headline {
  margin: 0;
  font-size: 16px; line-height: 1.55; max-width: 58ch;
  color: var(--hero-ink-soft);
}
.prof-hero .prof-headline.faint { font-size: 14.5px; }

/* The badge rides ON the hero's own edge, so the very first thing read about
   that sentence is that Peltify inferred it. On this ground the light-violet
   version would vanish, so it gets its own treatment rather than its own
   opacity -- a faded badge is a badge somebody can miss. */
.prof-hero-badge { position: absolute; top: 14px; right: 16px; z-index: 2; }
.prof-hero-badge .prov-inferred {
  background: rgba(251, 247, 255, 0.14);
  border-color: rgba(251, 247, 255, 0.34);
  color: var(--hero-ink);
  backdrop-filter: blur(4px);
}

/* The numbers. Three, not four -- see headSection() for why the fourth went. */
.prof-stats {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 10px;
  width: 236px;
}
.pstat {
  display: flex;
  align-items: baseline;
  gap: 12px;
  padding: 11px 16px;
  border-radius: var(--r-box);
  background: rgba(251, 247, 255, 0.09);
  border: 1px solid var(--hero-rule);
}
.pstat-n {
  font-family: var(--font-mono);
  font-size: 25px;
  line-height: 1;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.02em;
  color: var(--hero-ink);
  min-width: 1.6ch;
}
.pstat-l { font-size: 13px; color: var(--hero-ink-soft); }

/* ------------------------------------------------------------- a block --- */

.prof-block {
  margin: 0 0 22px;
  padding: 22px 24px;
  border-radius: var(--r-box);
  background: var(--white);
  border: 1px solid var(--line-soft);
  box-shadow: var(--lift);
}
.prof-block-h {
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: baseline;
  gap: 6px 14px;
  margin: 0 0 18px;
}
/* A real heading, not a small-caps eyebrow. This page is read by somebody who
   has never seen it before; 10px letterspaced grey is a label for people who
   already know what the panel is. */
.prof-block-h h2 {
  margin: 0; grid-column: 1;
  font-size: 18px; font-weight: 700; letter-spacing: -0.012em; color: var(--ink);
}
.prof-block-h .prov { grid-column: 2; grid-row: 1; }
.prof-block-sub {
  grid-column: 1 / -1;
  margin: 0;
  font-size: 13px; line-height: 1.5; color: var(--ink-soft); max-width: 62ch;
}

/* -------------------------------------------------- what you're into ------ */

.taste-grid {
  display: grid;
  grid-template-columns: 188px minmax(0, 1fr);
  gap: 26px;
  align-items: center;
}

.taste-ring { margin: 0; display: grid; gap: 12px; justify-items: center; }
.taste-ring-svg { position: relative; width: 168px; height: 168px; }
.donut-svg {
  width: 100%; height: 100%; display: block;
  transform: rotate(-90deg);            /* start the first wedge at 12 o'clock */
}
.donut-track {
  fill: none;
  stroke: color-mix(in srgb, var(--paper-deep) 62%, var(--white));
}
.donut-seg {
  fill: none;
  stroke: var(--seg, var(--violet));
  stroke-linecap: butt;                 /* see donut() -- a round cap overstates */
}
/* Worked out, not read: same angle, thinner stroke. */
.donut-seg.is-inferred { stroke-width: 9; }

.taste-ring-mid {
  position: absolute; inset: 0;
  display: grid; place-content: center; justify-items: center; gap: 1px;
  text-align: center; pointer-events: none;
}
.taste-ring-mid b {
  font-family: var(--font-mono);
  font-size: 27px; font-weight: 600; line-height: 1;
  font-variant-numeric: tabular-nums; letter-spacing: -0.02em;
  color: var(--ink);
}
.taste-ring-mid span { font-size: 11.5px; color: var(--ink-soft); }
.taste-ring-cap {
  margin: 0;
  max-width: 26ch;
  text-align: center;
  font-size: 11.5px;
  line-height: 1.45;
  color: var(--ink-soft);
}

/* --- the medium tiles ------------------------------------------------------
   The icon chip is the element carrying most of the "solid" feeling: a tinted
   rounded square with the glyph at full strength. It is also the only place
   the medium's hue appears at size, which is what makes the same hue readable
   later as a thin bar or a donut wedge. */
.mtiles {
  list-style: none; margin: 0; padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(132px, 1fr));
  gap: 12px;
}
.mtiles.is-wide { grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); }

.mtile { min-width: 0; }
.mtile-hit {
  display: grid; gap: 7px; width: 100%;
  padding: 15px 15px 14px;
  border-radius: var(--r-box);
  border: 1px solid var(--line-soft);
  background: var(--white);
  box-shadow: var(--lift);
  text-align: left; font: inherit; color: inherit; cursor: pointer;
  transition: transform 140ms var(--ease), box-shadow 140ms var(--ease),
              border-color 140ms var(--ease);
}
.mtile-hit:hover {
  transform: translateY(-2px);
  box-shadow: var(--raise);
  border-color: color-mix(in srgb, var(--m) 34%, var(--line-soft));
}
.mtile-hit:active { transform: translateY(0); box-shadow: var(--lift); }
.mtile-hit:focus-visible { outline: 3px solid var(--m); outline-offset: 2px; }

/* Worked out from communities rather than read from a history. Two channels
   for one claim: the dashed edge, and the words in `.mtile-sub`. */
.mtile[data-tone="inferred"] .mtile-hit {
  border-style: dashed;
  border-color: color-mix(in srgb, var(--m) 30%, var(--line));
  box-shadow: none;
  background: var(--paper);
}

.mtile-top { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.mtile-chip {
  display: grid; place-items: center;
  width: 36px; height: 36px;
  border-radius: var(--r-box);
  background: var(--m-wash);
  color: var(--m);
  flex: none;
}
.mtile[data-tone="inferred"] .mtile-chip {
  background: color-mix(in srgb, var(--m) 6%, transparent);
  box-shadow: inset 0 0 0 1.6px color-mix(in srgb, var(--m) 34%, transparent);
}
.mtile-n {
  font-family: var(--font-mono);
  font-size: 21px; font-weight: 600; line-height: 1;
  font-variant-numeric: tabular-nums; letter-spacing: -0.02em;
  color: var(--ink);
}
.mtile-name {
  font-size: 14.5px; font-weight: 650; color: var(--ink);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.mtile-track {
  display: block; height: 6px; border-radius: 999px;
  background: var(--paper-deep); overflow: hidden;
}
.mtile-fill {
  display: block; height: 100%; border-radius: 999px;
  background: var(--m);
}
.mtile[data-tone="inferred"] .mtile-fill { opacity: 0.55; }
.mtile-sub {
  font-size: 11.5px;
  line-height: 1.4;
  color: var(--ink-soft);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: normal;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  min-height: 2.8em;
}

/* One line under the whole panel, rather than a qualifier on every tile. */
.prof-basis-row {
  display: flex; flex-wrap: wrap; gap: 8px 20px;
  margin: 18px 0 0; padding-top: 15px;
  border-top: 1px solid var(--line-soft);
  font-size: 12.5px; line-height: 1.5; color: var(--ink-soft);
}
.basis-chip { display: flex; align-items: flex-start; gap: 7px; max-width: 46ch; }
.basis-chip svg { margin-top: 3px; }
.basis-chip[data-tone="counted"] svg { color: var(--ok); }
.basis-chip[data-tone="inferred"] svg { color: var(--warn); }

.prof-empty {
  margin: 12px 0 0;
  padding: 12px 15px;
  border-radius: var(--r-box);
  background: var(--paper);
  font-size: 12.5px; line-height: 1.55; color: var(--ink-soft);
}
.prof-empty b { color: var(--ink); font-weight: 650; }

/* ------------------------------------------------ everything you're into --- */

.prof-everything .chart { gap: 0; }
.chart-bars { gap: 2px; }
.chart-row {
  display: grid;
  grid-template-columns: minmax(96px, 30%) 1fr auto;
  align-items: center;
  gap: 14px;
  padding: 7px 10px;
  margin: 0 -10px;
  border-radius: var(--r-box);
  transition: background 140ms var(--ease);
}
.chart-row:hover { background: var(--paper); }
.chart-label {
  border: 0; background: none; padding: 0; margin: 0; font: inherit;
  text-align: left; min-width: 0; cursor: pointer;
  font-size: 14px; color: var(--ink);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.chart-label:hover { color: var(--violet); }
.chart-label:focus-visible { outline: 3px solid var(--violet); outline-offset: 3px; border-radius: 4px; }
.chart-track {
  height: 9px; border-radius: 999px;
  background: var(--paper-deep); overflow: hidden; min-width: 0;
}
.chart-fill {
  display: block; height: 100%; border-radius: 999px;
  background: var(--m, var(--violet));
}
.chart-n {
  font-family: var(--font-mono);
  font-size: 13px; font-variant-numeric: tabular-nums;
  color: var(--ink-soft); min-width: 3ch; text-align: right;
}
.chart-n.is-partial { color: var(--warn); font-weight: 600; }
.chart-foot { color: var(--ink-soft); }

/* The long tail. Down here a count no longer ranks anything, so it stops
   being a bar and becomes a pill -- the honest shape for "this is also true". */
.tail { margin-top: 20px; padding-top: 16px; border-top: 1px solid var(--line-soft); }
.tail-h {
  margin: 0 0 11px;
  font-size: 13px; font-weight: 650; color: var(--ink-soft);
}
.tail-pills { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: 7px; }
.tail-pill {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 6px 12px;
  border-radius: 999px;
  border: 1px solid var(--line-soft);
  background: var(--paper);
  font: inherit; font-size: 12.5px; color: var(--ink);
  cursor: pointer;
  transition: background 140ms var(--ease), border-color 140ms var(--ease),
              color 140ms var(--ease);
}
.tail-pill:hover { background: var(--violet-wash); border-color: var(--violet); color: var(--spine); }
.tail-pill:focus-visible { outline: 3px solid var(--violet); outline-offset: 2px; }
.tail-pill-n {
  font-family: var(--font-mono); font-size: 11px;
  font-variant-numeric: tabular-nums; color: var(--ink-soft);
}
.tail-pill:hover .tail-pill-n { color: var(--spine); }

.prof-seeall {
  display: flex; align-items: center; justify-content: center; gap: 8px;
  width: 100%; margin-top: 18px;
  padding: 12px 16px;
  border-radius: var(--r-box);
  border: 1px solid var(--line);
  background: var(--paper);
  font: inherit; font-size: 13.5px; font-weight: 650; color: var(--ink);
  cursor: pointer;
  transition: background 140ms var(--ease), border-color 140ms var(--ease),
              color 140ms var(--ease);
}
.prof-seeall:hover { background: var(--violet-wash); border-color: var(--violet); color: var(--spine); }
.prof-seeall:focus-visible { outline: 3px solid var(--violet); outline-offset: 2px; }

/* --------------------------------------------------------------- sheet --- */

.sheet-body { margin-top: 14px; }
.sheet-h .lede { margin: 6px 0 0; font-size: 13px; line-height: 1.5; color: var(--ink-soft); }

/* --------------------------------------------------------- first run ----- */

.prof-first {
  margin: 22px 0;
  padding: 34px 30px;
  border-radius: var(--r-box);
  border: 1px dashed var(--line-strong);
  background: var(--white);
  display: grid; gap: 14px; justify-items: start;
  box-shadow: var(--lift);
}
.prof-first h1 { margin: 0; font-family: var(--font-serif); font-size: 27px; line-height: 1.15; }

/* ------------------------------------------------------------ responsive --- */

@media (max-width: 900px) {
  .taste-grid { grid-template-columns: 154px minmax(0, 1fr); gap: 20px; }
  .taste-ring-svg { width: 144px; height: 144px; }
}
@media (max-width: 760px) {
  .prof-hero { grid-template-columns: 1fr; gap: 20px; padding: 22px 20px; }
  .prof-hero-badge { position: static; justify-self: start; order: -1; }
  .prof-stats { grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); }
  .taste-grid { grid-template-columns: 1fr; }
  .taste-ring { justify-self: center; }
  .prof-block { padding: 18px; border-radius: var(--r-box); }
  .chart-row { grid-template-columns: minmax(80px, 40%) 1fr auto; gap: 10px; }
}
@media (max-width: 520px) {
  .mtiles, .mtiles.is-wide { grid-template-columns: repeat(auto-fit, minmax(118px, 1fr)); }
  .prof-hero-title { font-size: 25px; }
}

@media (prefers-reduced-motion: reduce) {
  .mtile-hit:hover { transform: none; }
}

/* ===========================================================================
   THE SUGGESTION CARD, brought onto the same scale.  2026-08-24.

   The card's structure was already right -- the work on the left, Peltify's
   inference on the right, and the split doing real work. What it lacked was
   presence: a 22px radius fighting a 10px one inside it, a 4px shadow that
   read as a smudge rather than as height, and three verdict buttons at 9px
   padding that looked like form controls rather than like the decision the
   whole card exists to ask for.

   Nothing here changes what the card SAYS. Only how solidly it says it.
   =========================================================================== */

.sg-card {
  border-radius: var(--r-box);
  border-color: var(--line-soft);
  box-shadow: var(--raise);
}

.sg-col-work { border-right-color: var(--line-soft); }

.sg-kind {
  display: inline-block;
  letter-spacing: 0.1em;
  color: var(--spine);
}
.sg-col-work .sg-title { font-size: 24px; letter-spacing: -0.015em; }

/* Tags become real pills on the page's one pill radius. */
.sg-tag {
  padding: 5px 11px;
  font-size: 11.5px;
  border-color: var(--line-soft);
}

.sg-why-mark {
  width: 30px; height: 30px;
  border-radius: var(--r-box);
  background: var(--violet-wash);
}
.sg-why-head h4 { font-size: 17px; }

/* --- the decision row ------------------------------------------------------
   Three states, three weights, and now three real buttons: 12px radius to
   match every other control on the page, 44px tall so a thumb can hit one,
   and a press that actually moves. Pelt stays the emphatic one because it is
   the only action that leaves Peltify. */
.sg-actions { gap: 10px; padding-top: 16px; }
.sg-verdict {
  min-height: 44px;
  padding: 11px 14px;
  border-radius: var(--r-box);
  border-color: var(--line);
  font-size: 13.5px; font-weight: 650;
  color: var(--ink);
  transition: background 140ms var(--ease), border-color 140ms var(--ease),
              color 140ms var(--ease), transform 140ms var(--ease),
              box-shadow 140ms var(--ease);
}
.sg-verdict:hover {
  border-color: var(--violet); color: var(--spine);
  background: var(--violet-wash);
}
.sg-verdict:active { transform: translateY(1px); }

.sg-keep.is-on {
  background: var(--violet-wash); border-color: var(--violet); color: var(--spine);
}
.sg-no:hover {
  border-color: var(--line-strong); background: var(--paper-deep); color: var(--ink-soft);
}
.sg-no.is-on { background: var(--paper-deep); border-color: var(--line-strong); }

.sg-pelt {
  background: var(--violet);
  border-color: var(--violet);
  color: var(--white);
  box-shadow: 0 6px 16px -8px rgba(139, 31, 209, 0.8);
}
.sg-pelt:hover {
  background: var(--spine); border-color: var(--spine); color: var(--white);
  box-shadow: 0 10px 22px -10px rgba(94, 21, 128, 0.9);
}
.sg-pelt.is-on { background: var(--spine); border-color: var(--spine); box-shadow: none; }

@media (prefers-reduced-motion: reduce) {
  .sg-verdict:active { transform: none; }
}

/* --- profile, second pass ---------------------------------------------------
   Everything here is a defect the first render actually showed, fixed in the
   same file rather than in a fourth stacked block somewhere else.
   -------------------------------------------------------------------------- */

/* The stat rail was taking 0.85fr of a 1,070px column, so "24 topics" sat in a
   390px pill with a void in the middle. The rail is content-sized now. */


/* --- the tiles -------------------------------------------------------------
   "worked out from your c…" on all four inferred tiles: the provenance line is
   the thing that makes the tile explain itself, so it is the last thing that
   may be truncated. Two lines, reserved whether used or not, so a row of tiles
   stays a row of the same shape. */


/* At 12% the ring round an inferred chip was invisible, which cost the tile
   the icon-chip weight that carries the whole "solid" feeling. */


/* --- the ranked bars -------------------------------------------------------
   The label column was 30% of a very wide card, which left a canyon between a
   six-letter topic and its bar. And `button.chart-label` out-specified the new
   rule, so every topic rendered permanently underlined and the panel read as a
   list of links. The row highlight already says the row is live. */
.prof-everything .chart-row {
  grid-template-columns: minmax(88px, 34%) 1fr auto;
}
button.chart-label { text-decoration: none; }
button.chart-label:hover,
button.chart-label:focus-visible {
  text-decoration: underline;
  text-decoration-color: var(--violet);
  text-underline-offset: 3px;
}

/* --- the deck's own empty state --------------------------------------------
   The first thing on this page was a violet micro-caption, a grey sentence and
   a button, floating on the paper with no card under any of it — directly
   above a hero with a gradient and a shadow. It is the same kind of panel as
   everything below it, so it gets the same box. */
.prof-suggest .sg-deck {
  padding: 22px 24px;
  border-radius: var(--r-box);
  background: var(--white);
  border: 1px solid var(--line-soft);
  box-shadow: var(--lift);
}
.prof-suggest .carousel-head { margin-bottom: 12px; }
.prof-suggest .carousel-title {
  font-size: 18px; font-weight: 700; letter-spacing: -0.012em;
  text-transform: none; color: var(--ink);
}
.prof-suggest .live-empty {
  margin: 0; font-size: 13.5px; line-height: 1.55; color: var(--ink-soft); max-width: 62ch;
}
.prof-suggest .sg-deck-actions { margin-top: 16px; }

/* The deck holding a real card should not put a card inside a card. */
.prof-suggest .sg-deck:has(.sg-card) {
  padding: 0; background: none; border: 0; box-shadow: none;
}

@media (max-width: 760px) {
  .prof-hero { grid-template-columns: 1fr; }
  .prof-stats { width: auto; }
}

/* --- profile, third pass ----------------------------------------------------
   Measured off the rendered page, not guessed at.
   -------------------------------------------------------------------------- */

/* The label column computed to 208px for six-letter topics, leaving a canyon
   before every bar. */


/* COUNTED SHOULD LOOK MORE SUBSTANTIAL THAN INFERRED, and it did not: the
   inferred tiles carried a tinted dashed edge while the one counted tile was
   plain white, so the weaker claim was the better-dressed one. Counted now
   sits on white with a lift; inferred sits flat on the page's own paper and
   is outlined rather than filled. */

.mtile[data-tone="inferred"] .mtile-hit:hover {
  background: var(--white);
}

/* The thin inferred wedges read better against a paler track. */


/* The head and the tail, side by side. See interests() for why. */
.ev-grid {
  display: grid;
  grid-template-columns: minmax(0, 1.05fr) minmax(0, 0.95fr);
  gap: 30px;
  align-items: start;
}
.ev-grid.is-single { grid-template-columns: minmax(0, 1fr); max-width: 620px; }
.ev-ranked, .ev-tail { min-width: 0; }
.ev-tail {
  padding-left: 30px;
  border-left: 1px solid var(--line-soft);
}
.ev-tail .tail { margin: 0; padding: 0; border-top: 0; }


@media (max-width: 900px) {
  .ev-grid { grid-template-columns: minmax(0, 1fr); gap: 20px; }
  .ev-tail {
    padding-left: 0; padding-top: 18px;
    border-left: 0; border-top: 1px solid var(--line-soft);
  }
}

/* ===========================================================================
   THE SUGGESTION CARD, COMPARTMENTED.  2026-08-24, second round.

   Nick: "It just isnt neat enough. It should have cool neat boxed borders.
   Look cool. All text on the page feels bland and small ish. Doesnt feel
   incapsulating. This suggestion should feel sophisticated."

   Three things were wrong and only one of them was type size.

   1. NOTHING WAS CONTAINED. The right-hand column was five blocks of content
      stacked on one flat wash with no edges between them -- a synopsis, a
      paragraph, a chart, a bulleted list, three buttons. The card had an outer
      border and no interior, so the eye had nowhere to rest and everything
      read as one undifferentiated column. Every block is now a box with its
      own edge, its own ground and its own label.

   2. THE TYPE WAS SET FOR A SIDEBAR, not for the thing the whole page exists
      to deliver. This is the one surface an outsider judges. The title, the
      synopsis and the reasoning all step up a size, and the small print stops
      being 10px.

   3. THE LINE-UP WAS THE WEAKEST ELEMENT ON THE STRONGEST CARD. See lineUp()
      in charts.js for what it is now and why the old one was wrong.
   =========================================================================== */

.sg-card {
  border-radius: var(--r-box);
  border: 1px solid var(--line);
  box-shadow: var(--raise-hi);
  overflow: hidden;
}

/* --- the work side ---------------------------------------------------------
   The artwork keeps its own hard edge against the panel rather than bleeding
   into it, so the poster reads as a held object instead of a background. */
.sg-col-work {
  gap: 16px;
  padding-bottom: 22px;
  border-right: 1px solid var(--line);
  background: linear-gradient(180deg, transparent 58%, var(--paper) 100%);
}
.sg-col-work .sg-hero { border-bottom: 1px solid var(--line); }

.sg-kind {
  display: inline-flex; align-items: center;
  padding: 4px 10px;
  border-radius: var(--r-box);
  background: var(--violet-wash);
  font-size: 10.5px; font-weight: 700; letter-spacing: 0.1em;
  color: var(--spine);
}
.sg-col-work .sg-title {
  font-size: 27px; line-height: 1.14; letter-spacing: -0.018em; margin: 10px 0 4px;
}
.sg-creator { font-size: 13.5px; }

.sg-tag {
  padding: 6px 12px;
  border-radius: var(--r-box);
  border: 1px solid var(--line);
  background: var(--white);
  font-size: 12.5px; color: var(--ink-soft);
}

/* The synopsis in its own box. It is somebody else's writing, and the box says
   so as plainly as the serif does. */
.sg-fact {
  padding: 16px 18px;
  border-radius: var(--r-box);
  border: 1px solid var(--line-soft);
  background: var(--white);
}
.sg-col-work .sg-fact p { font-size: 15.5px; line-height: 1.62; }
.sg-prov { font-size: 11.5px !important; }

/* --- the Peltify side ----------------------------------------------------- */

.sg-col-why {
  gap: 16px;
  padding: 22px 24px;
  background:
    radial-gradient(130% 90% at 100% 0%, var(--violet-wash), transparent 58%),
    var(--white);
}
.sg-why-head h4 { font-size: 18px; }
.sg-why-mark { width: 32px; height: 32px; border-radius: var(--r-box); }

/* The inference, boxed and tinted -- the product's own voice, unmistakably a
   different kind of statement from the sourced synopsis opposite. */
.sg-why-lead {
  padding: 16px 18px;
  border-radius: var(--r-box);
  border: 1px solid rgba(139, 31, 209, 0.18);
  background: rgba(255, 255, 255, 0.72);
  font-size: 16px; line-height: 1.6;
}

/* The citations, boxed under the reasoning they support. */
.sg-because {
  gap: 8px;
  margin: 0;
  padding: 14px 16px 14px 32px;
  border-radius: var(--r-box);
  border: 1px solid var(--line-soft);
  background: var(--paper);
}
.sg-because li { font-size: 12.5px; line-height: 1.55; color: var(--ink-soft); }
.sg-because li::before { left: -15px; top: 8px; width: 5px; height: 5px; }

.sg-nocite {
  margin: 0;
  padding: 13px 16px;
  border-radius: var(--r-box);
  border: 1px dashed rgba(154, 100, 7, 0.4);
  background: var(--warn-wash);
  font-size: 12.5px; line-height: 1.55; color: var(--warn);
}

.sg-align-none {
  margin: 0; padding: 14px 16px;
  border-radius: var(--r-box); border: 1px dashed var(--line-strong);
  background: var(--paper);
  font-size: 13px; line-height: 1.55; color: var(--ink-soft);
}

/* --- the line-up -----------------------------------------------------------
   One boxed panel: a header, a ranked list where every row states its own
   footing, and a footing line that says what the list adds up to. */
.lineup {
  border-radius: var(--r-box);
  border: 1px solid var(--line-soft);
  background: var(--white);
  overflow: hidden;
}
.lu-h {
  margin: 0;
  padding: 13px 18px;
  border-bottom: 1px solid var(--line-soft);
  background: var(--paper);
  font-size: 11px; font-weight: 700; letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--ink-soft);
}
.lu-rows { list-style: none; margin: 0; padding: 8px 0; }
.lu-row {
  display: grid;
  grid-template-columns: 12px minmax(0, 1fr) minmax(64px, 0.72fr) auto;
  align-items: center;
  gap: 12px;
  padding: 9px 18px;
}
.lu-row + .lu-row { box-shadow: inset 0 1px 0 var(--line-soft); }

.lu-dot {
  width: 9px; height: 9px; border-radius: 50%;
  border: 1.6px solid var(--line-strong);
  background: transparent;
}
.lu-row[data-side="both"] .lu-dot { background: var(--violet); border-color: var(--violet); }
.lu-row[data-side="yours"] .lu-dot { border-color: var(--violet); }

.lu-label {
  font-size: 14px; color: var(--ink);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.lu-row[data-side="both"] .lu-label { font-weight: 650; color: var(--spine); }
.lu-row[data-side="theirs"] .lu-label { color: var(--ink-soft); }

.lu-track {
  height: 9px; border-radius: 999px;
  background: var(--paper-deep); overflow: hidden; min-width: 0;
}
.lu-fill { display: block; height: 100%; border-radius: 999px; background: var(--violet); }
.lu-row[data-side="yours"] .lu-fill {
  background: repeating-linear-gradient(115deg,
    var(--violet) 0 6px, rgba(139, 31, 209, 0.55) 6px 11px);
}
/* No track where there is no quantity. Absent and zero are different claims. */
.lu-none { font-size: 12px; color: var(--ink-faint); white-space: nowrap; }
.lu-n {
  font-family: var(--font-mono);
  font-size: 13.5px; font-variant-numeric: tabular-nums;
  color: var(--ink-soft); min-width: 3ch; text-align: right;
}
.lu-row[data-side="both"] .lu-n { color: var(--spine); font-weight: 600; }

.lu-foot {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 6px;
  margin: 0;
  padding: 13px 18px;
  border-top: 1px solid var(--line-soft);
  background: var(--paper);
  font-size: 12.5px; line-height: 1.5; color: var(--ink-soft);
}
.lu-foot b { color: var(--spine); }
.lu-foot b.is-none { color: var(--warn); }
.lu-key {
  flex-basis: 100%;
  display: flex; flex-wrap: wrap; align-items: center; gap: 5px 14px;
  margin-top: 4px;
  font-size: 11.5px; color: var(--ink-faint);
}
.lu-key-i {
  width: 9px; height: 9px; border-radius: 50%; flex: none;
  border: 1.6px solid var(--line-strong);
}
.lu-key-i[data-side="both"] { background: var(--violet); border-color: var(--violet); }
.lu-key-i[data-side="yours"] { border-color: var(--violet); }

/* --- the decision row ------------------------------------------------------
   Its own footer strip with a ground of its own, so the card ends on a
   deliberate edge rather than trailing off into whitespace. */
.sg-actions {
  gap: 10px;
  margin: 4px -24px -22px;
  padding: 18px 24px;
  border-top: 1px solid var(--line-soft);
  background: var(--paper);
}
.sg-verdict { min-height: 46px; font-size: 14px; }

.sg-col-why .sg-where { font-size: 13.5px; margin-top: 4px; }

@media (max-width: 860px) {
  .sg-col-work { border-right: 0; border-bottom: 1px solid var(--line); }
  .sg-actions { margin: 4px -18px -18px; padding: 16px 18px; }
}
@media (max-width: 520px) {
  .lu-row { grid-template-columns: 12px minmax(0, 1fr) auto; gap: 10px; }
  .lu-track { display: none; }
  .sg-col-work .sg-title { font-size: 23px; }
}

/* --- type, up one step ------------------------------------------------------
   "All text on the page feels bland and small ish." It was: a dashboard read
   at arm's length was set at sidebar sizes. Nothing below changes a layout —
   each is the same role one step larger, and the small print stops being 10px.
   -------------------------------------------------------------------------- */

.prof-block-h h2 { font-size: 19px; }
.prof-block-sub { font-size: 14px; }
.pstat-l { font-size: 14px; }
.prof-hero .prof-headline { font-size: 17px; }
.prof-hero-when { font-size: 13px; }
.mtile-name { font-size: 15px; }
.mtile-sub { font-size: 12px; }
.mtile-n { font-size: 22px; }
.taste-ring-mid span { font-size: 12.5px; }
.taste-ring-cap { font-size: 12.5px; max-width: 28ch; }
.prof-basis-row { font-size: 13.5px; }
.prof-empty { font-size: 13.5px; }
.prof-everything .chart-label { font-size: 15px; }
.chart-n { font-size: 14px; }
.tail-h { font-size: 14px; }
.tail-pill { font-size: 13.5px; padding: 7px 13px; }
.tail-pill-n { font-size: 12px; }
.prof-seeall { font-size: 14.5px; padding: 14px 16px; }
.prof-suggest .carousel-title { font-size: 19px; }
.prof-suggest .live-empty { font-size: 14.5px; }

/* --- two things the render showed ------------------------------------------ */

/* The work column is as tall as the Peltify column beside it, and its content
   is shorter, so the synopsis box floated with a field of empty paper beneath
   it. The box takes the slack; the text still sits at its top. */
.sg-col-work .sg-fact { flex: 1 1 auto; }
.sg-col-work { background: var(--white); }

/* The deck's own provenance sat bare on the paper directly beneath a card that
   is now all edges, so it read as something that had fallen off. It is deck
   metadata, not card content, so it gets a quieter box of its own rather than
   the card's. */
.prof-suggest .run-prov,
.talk-suggest .run-prov {
  display: flex; align-items: flex-start; gap: 7px;
  margin: 12px 0 0;
  padding: 12px 16px;
  border-radius: var(--r-box);
  border: 1px solid var(--line-soft);
  background: var(--white);
  font-size: 12px; line-height: 1.55; color: var(--ink-soft);
}
.prof-suggest .run-prov + .run-prov,
.talk-suggest .run-prov + .run-prov { margin-top: 8px; }
.prof-suggest .run-prov svg,
.talk-suggest .run-prov svg { margin-top: 3px; color: var(--warn); }

/* The account-created screen. Shown once, on the sign-in that creates the
   account, so a person is told plainly what now exists rather than being
   dropped into the app to infer it. */
.onb-facts {
  list-style: none;
  margin: 4px 0 26px;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 14px;
}

/* Three dots that actually move, for a label describing work in progress.
   The word beside them is real text, so the button still reads correctly when
   animation is off — the dots are decoration and are hidden from screen
   readers. Reduced motion gets a static ellipsis rather than nothing, so the
   label does not silently change shape. */
.scan-dots::after {
  content: "";
  animation: scan-dots 1.4s steps(1, end) infinite;
}

@keyframes scan-dots {
  0%   { content: ""; }
  25%  { content: "."; }
  50%  { content: ".."; }
  75%  { content: "..."; }
  100% { content: ""; }
}

@media (prefers-reduced-motion: reduce) {
  .scan-dots::after { content: "…"; animation: none; }
}

/* Scanning is work in progress, so it reads as progress rather than as an
   action you could take: quieter than the solid Scan button, still clearly
   live, and still clickable to stop. */
.scan-go.is-running {
  background: var(--violet-wash, #f5edfc);
  color: var(--violet-deep, #6d17a8);
  border-color: transparent;
}

/* Settings. Deliberately plain: this page is a list of facts about the
   account, not a surface that needs its own personality. */
.set { display: flex; flex-direction: column; gap: 26px; max-width: 640px; }
.set-head h2 { margin: 0 0 4px; }
.set-who { margin: 0; color: var(--ink-2, #5f5a6b); font-size: 14px; }
.set-block { display: flex; flex-direction: column; gap: 12px; }
.set-block h3 {
  margin: 0; font-size: 11px; font-weight: 700; letter-spacing: .08em;
  text-transform: uppercase; color: var(--ink-3, #928c9e);
}
.set-note {
  margin: 0; font-size: 13px; line-height: 1.5; color: var(--ink-2, #5f5a6b);
  display: flex; align-items: flex-start; gap: 6px;
}
.set-row { display: flex; gap: 13px; align-items: flex-start; }
.set-copy { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.set-copy strong { font-size: 14.5px; font-weight: 600; }
.set-copy span { font-size: 13.5px; line-height: 1.5; color: var(--ink-2, #5f5a6b); }

.set-switch { flex: none; cursor: pointer; margin-top: 2px; }
.set-switch input { position: absolute; opacity: 0; pointer-events: none; }
.set-track {
  display: block; width: 34px; height: 20px; border-radius: 999px;
  background: #d9d5e2; position: relative; transition: background .15s ease;
}
.set-track::after {
  content: ""; position: absolute; top: 2px; left: 2px;
  width: 16px; height: 16px; border-radius: 50%; background: #fff;
  box-shadow: 0 1px 3px rgba(26,21,35,.22); transition: transform .15s ease;
}
.set-switch input:checked + .set-track { background: var(--violet, #8b1fd1); }
.set-switch input:checked + .set-track::after { transform: translateX(14px); }
.set-switch input:focus-visible + .set-track { outline: 2px solid var(--violet, #8b1fd1); outline-offset: 2px; }

/* Not built yet: readable, and visibly not interactive. */
.set-soon { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 12px; }
.set-soon li {
  display: flex; flex-direction: column; gap: 2px;
  padding: 12px 14px; border: 1px dashed var(--line, #e9e7ef);
  border-radius: var(--r-box); opacity: .75;
}
.set-soon strong { font-size: 14px; font-weight: 600; }
.set-soon span { font-size: 13px; line-height: 1.5; color: var(--ink-2, #5f5a6b); }

/* Why an action is withheld, where the action would have been. */
.gate-why {
  margin: 0; font-size: 13px; line-height: 1.5; color: var(--ink-2, #5f5a6b);
  display: flex; align-items: flex-start; gap: 6px;
}

/* The quieter third answer in a confirmation. Underlined and plain: it is a
   real choice, but a rarer and more destructive one than the two buttons, so
   it should not compete with them for the eye. */
.ask-actions-wrap { display: flex; flex-direction: column; gap: 10px; }

.ask-link {
  align-self: center;
  background: none;
  border: 0;
  padding: 2px 4px;
  font: inherit;
  font-size: 13px;
  color: var(--danger, #b3261e);
  text-decoration: underline;
  text-underline-offset: 3px;
  cursor: pointer;
}
.ask-link:hover { color: #8c1d18; }
.ask-link:focus-visible { outline: 2px solid var(--violet, #8b1fd1); outline-offset: 2px; border-radius: 4px; }

/* Today's allowance. A bar rather than a bare number, because "2 of 5 left"
   is a fact and the bar is the feeling — you can see at a glance whether you
   are near the wall. */
.use-row { display: flex; flex-direction: column; gap: 6px; }
.use-top { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; }
.use-top strong { font-size: 14.5px; font-weight: 600; }
.use-count { font-size: 13px; color: var(--ink-2, #5f5a6b); font-variant-numeric: tabular-nums; }
.use-count.is-out { color: var(--danger, #b3261e); font-weight: 600; }
.use-bar {
  height: 6px; border-radius: 999px; background: var(--line-soft, #f1eff5);
  overflow: hidden;
}
.use-bar span {
  display: block; height: 100%; border-radius: 999px;
  background: var(--violet, #8b1fd1); transition: width .25s ease;
}
.use-note { font-size: 12.5px; line-height: 1.5; color: var(--ink-3, #928c9e); }


/* Removals, said once and then gone.
   A stack of plain lines between the app grid and the scan bar — no Undo, no
   Delete, no dismiss. The person already decided; a notice that needs
   dismissing is a second task created by the first. */
.scan-removed {
  display: flex;
  flex-direction: column;
  gap: 4px;
  margin: 10px 0 2px;
}

.scan-removed-line {
  margin: 0;
  font-size: 13px;
  line-height: 1.5;
  color: var(--ink-2, #5f5a6b);
  animation: removed-fade 6s ease forwards;
}

.scan-removed-line b { color: var(--ink, #1a1523); font-weight: 600; }

@keyframes removed-fade {
  0%   { opacity: 0; transform: translateY(-3px); }
  8%   { opacity: 1; transform: none; }
  75%  { opacity: 1; }
  100% { opacity: 0; }
}

@media (prefers-reduced-motion: reduce) {
  .scan-removed-line { animation: none; opacity: 1; }
}

/* @username, with the server's verdict beside it and never ahead of it. */
.onb-handle {
  display: flex; align-items: center; gap: 0;
  border: 1.5px solid var(--line); border-radius: var(--r-md);
  background: var(--white); overflow: hidden;
  transition: border-color 140ms var(--ease), box-shadow 140ms var(--ease);
}

/* Eight characters typed blind is how a typo becomes a support request. */
.onb-pw { position: relative; display: flex; align-items: center; }

/* The 30-day undo, offered rather than performed. */
.onb-restore {
  margin-top: 18px; padding: 16px; border-radius: var(--r-lg);
  border: 1px solid color-mix(in srgb, var(--warn) 45%, var(--line));
  background: var(--warn-wash);
  animation: rise-in 420ms var(--bounce) both;
}

/* ---------------------------------------------------------------------------
   SHELL — the pristine top bar and the account popover (2026-08-26).

   The guardrail pills left the top bar for Settings, so the right-hand slot
   holds one thing: the engine pill. `.guardrails` above is untouched, because
   Settings is where those pills now live and it still draws them.
   --------------------------------------------------------------------------- */

.topbar-status { display: flex; align-items: center; gap: 8px; justify-content: flex-end; }

/* The avatar itself is drawn by src/ui/avatar.js (class `.av`), which owns
   both the stock pictures and the initials fallback. Nothing is restyled here;
   the rail and the account panel only need it to sit still in a flex row. */
.rail-user .av, .acct-who .av { flex: none; }

.sheet-acct .acct-who { padding: 18px; gap: 16px; align-items: center; }
.acct-who-t { flex: 1; min-width: 0; display: grid; gap: 3px; }
.acct-who-t b { font-size: 17px; letter-spacing: -0.02em; }
.acct-verified {
  display: inline-flex; align-items: center; gap: 4px; width: fit-content;
  font-size: 11px; font-weight: 700; letter-spacing: 0.02em;
  color: var(--ok); text-transform: lowercase;
}

/* 19.9 (`shell/SPEC.md` entry 2) — THE PUBLIC ID ROW IS GONE. Nick: "Remove
   'copy public ID'." Its five rules went with it; the handle on the line
   above is the address people actually use. */

/* ===========================================================================
   BRAIN · List view cards, and ACTIVITY · the timeline           (2026-08-26)

   Appended rather than placed in a stylesheet of their own: brain.js and
   activity.js have always drawn from app.css, and neither has a named sheet in
   the phase5 split (dashboard/scan/social/settings). If a `brain.css` is ever
   added, this whole block moves there unchanged.
   =========================================================================== */

/* ---- one card per source, in Brain's List view ---- */

.bsrc {
  border-radius: var(--r-lg);
  background: var(--white);
  border: 1px solid var(--line-soft);
  box-shadow: var(--raise);
  overflow: hidden;
}
.src-sections { display: grid; gap: 16px; }

.bsrc-head {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 14px 18px;
  border-bottom: 1px solid var(--line-soft);
  background: linear-gradient(180deg, var(--white), var(--paper));
}
.bsrc-logo { display: inline-flex; flex: none; }
.bsrc-who { flex: 1 1 auto; min-width: 0; display: grid; gap: 1px; }
.bsrc-who b { font-size: 16px; letter-spacing: -0.01em; }
.bsrc-who span { font-size: 12.5px; color: var(--ink-faint); }
.bsrc-count {
  flex: none;
  display: grid;
  justify-items: end;
  font: 800 19px var(--font-sans);
  letter-spacing: -0.02em;
  color: var(--ink);
}
.bsrc-count small { font-size: 10.5px; font-weight: 700; color: var(--ink-faint); letter-spacing: 0.05em; text-transform: uppercase; }
.bsrc-count.partial { color: var(--warn); }
.bsrc-count.faint { font-size: 12.5px; font-weight: 700; color: var(--ink-faint); }

.bgroups { padding: 14px 18px 18px; display: grid; gap: 14px; }
.bpills { display: flex; flex-wrap: wrap; gap: 8px; }
.bpill {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 6px 13px;
  border-radius: var(--r-box);
  border: 1px solid var(--line);
  background: var(--paper);
  color: var(--ink-soft);
  font: 700 13px var(--font-sans);
  cursor: pointer;
  transition: background var(--fast) var(--ease), color var(--fast) var(--ease),
              border-color var(--fast) var(--ease);
}
.bpill:hover { border-color: var(--violet); color: var(--violet); }
.bpill.on { background: var(--violet); border-color: transparent; color: var(--white); }
.bpill-n { font: 800 12px var(--font-mono); opacity: 0.85; }
.bpill-n.partial { color: var(--warn); }
.bpill.on .bpill-n.partial { color: var(--peach); }
.bpill-tag { font-size: 10.5px; font-weight: 700; opacity: 0.7; text-transform: uppercase; letter-spacing: 0.05em; }

.bgroup-body { display: grid; gap: 10px; }
.bchips { display: flex; flex-wrap: wrap; gap: 8px; }
.bchip {
  display: inline-flex;
  align-items: baseline;
  gap: 8px;
  max-width: 100%;
  padding: 7px 13px;
  border-radius: var(--r-box);
  border: 1px solid var(--line-soft);
  background: var(--paper);
  color: var(--ink);
  font: 600 13px var(--font-sans);
  text-align: left;
  cursor: pointer;
  animation: pop-in 300ms var(--bounce) both;
  animation-delay: calc(var(--i, 0) * 22ms);
}
.bchip:hover { border-color: var(--violet); background: var(--violet-wash); }
.bchip.is-flat { cursor: default; background: transparent; }
.bchip.is-flat:hover { border-color: var(--line-soft); background: transparent; }
.bchip-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 46ch; }
.bchip-meta { font-size: 11px; color: var(--ink-faint); white-space: nowrap; }

/* ---- the memories panel ---- */

.bmems { display: grid; gap: 10px; }
.bmem {
  padding: 12px 14px;
  border-radius: var(--r-md);
  background: var(--paper);
  border: 1px solid var(--line-soft);
}
.bmem-top { display: flex; align-items: center; gap: 10px; margin-bottom: 5px; }
.bmem-kind {
  padding: 2px 9px;
  border-radius: var(--r-box);
  background: var(--violet-wash);
  color: var(--spine);
  font: 800 10.5px var(--font-sans);
  letter-spacing: 0.06em;
  text-transform: uppercase;
}
.bmem-when { font-size: 11.5px; color: var(--ink-faint); }
.bmem-text { margin: 0; font-size: 13.5px; line-height: 1.55; color: var(--ink-soft); }

/* ---- Activity: one rail, one dot per entry ---- */

.act-rail { display: grid; gap: 10px; position: relative; }
.act-rail::before {
  content: "";
  position: absolute;
  left: 6px;
  top: 12px;
  bottom: 12px;
  width: 2px;
  border-radius: 1px;
  background: var(--line-soft);
}
.act-item { display: flex; gap: 14px; align-items: flex-start; position: relative; }
.act-dot {
  flex: none;
  width: 14px;
  height: 14px;
  margin-top: 14px;
  border-radius: 50%;
  background: var(--white);
  border: 3px solid var(--line-strong);
  position: relative;
  z-index: 1;
}
.act-dot.ok { border-color: var(--ok); }
.act-dot.warn { border-color: var(--warn); }
.act-dot.bad { border-color: var(--coral-dark); }

.act-card {
  flex: 1 1 auto;
  min-width: 0;
  border-radius: var(--r-md);
  border: 1px solid var(--line-soft);
  background: var(--white);
  box-shadow: var(--lift);
  overflow: hidden;
}
.act-line {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 12px 14px;
  cursor: pointer;
  list-style: none;
  flex-wrap: wrap;
}
.act-line::-webkit-details-marker { display: none; }
.act-n {
  flex: none;
  min-width: 40px;
  font: 800 15px var(--font-mono);
  letter-spacing: -0.02em;
}
.act-n.partial { color: var(--warn); }
.act-what {
  flex: 1 1 160px;
  min-width: 0;
  font-weight: 700;
  font-size: 14px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.act-tag {
  padding: 2px 9px;
  border-radius: var(--r-box);
  background: var(--paper-deep);
  color: var(--ink-soft);
  font: 700 11px var(--font-sans);
}
.act-cost { font: 600 11.5px var(--font-mono); color: var(--ink-faint); white-space: nowrap; }
.act-when { font-size: 11.5px; color: var(--ink-faint); white-space: nowrap; }
.act-when.faint { font-style: italic; }
.act-body { padding: 0 14px 14px; display: grid; gap: 8px; }

@media (max-width: 640px) {
  .bchip-name { max-width: 26ch; }
  .act-cost { display: none; }
}

/* "N reads came with you" — the one-time note that replaced the welcome screen. */
.topbar-carried { gap: 8px; }
.topbar-carried-x { border: 0; background: none; padding: 0 0 0 2px; font: inherit; font-size: 14px; line-height: 1; color: inherit; cursor: pointer; opacity: 0.7; }
.topbar-carried-x:hover { opacity: 1; }
.topbar-carried-link { border: 0; background: none; padding: 0; font: inherit; font-weight: 700; color: inherit; text-decoration: underline; cursor: pointer; }

/* 27.2 — the not-found page (src/ui/not-found.js) */
.nf { max-width: 520px; margin: 12vh auto 0; padding-inline: 16px; text-align: center; }
.nf-title { margin: 0 0 8px; font-size: 32px; letter-spacing: -.02em; color: var(--ink); }
.nf-line { margin: 0 0 20px; color: var(--ink-soft); overflow-wrap: anywhere; }
/* 2026-09-15 — the box is the Search page's bar (search.css owns its look);
   here it sits in the flow, unpinned, and its rows read left-aligned */
.nf .srch-bar { position: static; padding: 0; margin-bottom: 14px; background: none; border: 0; text-align: left; }
