/* ==========================================================================
   COMPONENTS
   ========================================================================== */

/* ------------------------------------------------------------- SIDEBAR -- */
.sidebar {
  background: var(--bg-nav);
  border-right: 1px solid var(--border);
  display: flex; flex-direction: column;
  position: sticky; top: 0; height: 100vh;
  z-index: var(--z-sticky);
}
.sidebar__brand {
  height: var(--h-topbar);
  display: flex; align-items: center; gap: var(--sp-3);
  padding: 0 var(--sp-5);
  border-bottom: 1px solid var(--border);
  flex: none;
}
.sidebar__brand-name { font-size: 15px; font-weight: var(--fw-bold); letter-spacing: -.01em; line-height: 1.1; }
.sidebar__brand-sub { font-size: var(--fs-micro); color: var(--text-muted); font-weight: var(--fw-medium); letter-spacing: var(--tracking-label); text-transform: uppercase; }
.sidebar__nav { flex: 1; overflow-y: auto; padding: var(--sp-4) var(--sp-3); display: flex; flex-direction: column; gap: var(--sp-5); }
.sidebar__foot { flex: none; border-top: 1px solid var(--border); padding: var(--sp-3); }

.navgroup { display: flex; flex-direction: column; gap: 2px; }
.navgroup__title {
  font-size: var(--fs-micro); font-weight: var(--fw-semi);
  letter-spacing: var(--tracking-label); text-transform: uppercase;
  color: var(--text-muted); padding: 0 var(--sp-3) var(--sp-2);
}
.navlink {
  position: relative;
  display: flex; align-items: center; gap: var(--sp-3);
  padding: 9px var(--sp-3); border-radius: var(--r-md);
  color: var(--text-secondary); font-size: var(--fs-body); font-weight: var(--fw-medium);
  transition: background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
  cursor: pointer; border: none; background: none; width: 100%; text-align: left;
}
/* Hover was a 4%-alpha tint and nothing else — on a dark surface that reads as
   no feedback at all. The row now also grows a brand accent on its left edge
   and the icon warms up, so pointing at an item is visibly different from
   standing on the selected one. */
.navlink::before {
  content: ""; position: absolute; left: 0; top: 50%;
  width: 3px; height: 0; border-radius: 0 var(--r-xs) var(--r-xs) 0;
  background: var(--brand); transform: translateY(-50%);
  transition: height var(--dur) var(--ease);
}
.navlink:hover::before { height: 40%; }
.navlink:hover { background: var(--bg-hover); color: var(--text-primary); }
.navlink .i { transition: color var(--dur-fast) var(--ease); }
.navlink:hover .i { color: var(--brand); }
.navlink:focus-visible { outline: none; box-shadow: var(--sh-focus); }
.navlink[aria-current="page"], .navlink.is-active {
  background: var(--brand-soft); color: var(--brand); font-weight: var(--fw-semi);
}
.navlink[aria-current="page"]::before, .navlink.is-active::before { height: 62%; }
.navlink[aria-current="page"] .i, .navlink.is-active .i { color: var(--brand); }
.navlink__badge { margin-left: auto; }
.navlink[disabled] { color: var(--text-muted); pointer-events: none; opacity: .65; }
.app[data-sidebar="collapsed"] .navlink { justify-content: center; padding: 10px; }
.app[data-sidebar="collapsed"] .navlink span,
.app[data-sidebar="collapsed"] .navgroup__title,
.app[data-sidebar="collapsed"] .sidebar__brand-text,
.app[data-sidebar="collapsed"] .navlink__badge { display: none; }
.app[data-sidebar="collapsed"] .sidebar__brand { justify-content: center; padding: 0; }
/* The account block is the way into Settings, so on the collapsed rail it must
   still be something you can aim at: the generic rule hides every span inside a
   navlink, the avatar included, which left an empty clickable strip. */
.app[data-sidebar="collapsed"] .sidebar__foot .navlink .avatar { display: grid; }

/* Collapsed the rail is 68px wide, so the sign-out label has nowhere to go:
   keep the icon, drop the word. The label was a bare text node in the button,
   which no selector could reach — it is a <span> now. */
.sidebar__signout { width: 100%; justify-content: center; }
.app[data-sidebar="collapsed"] .sidebar__signout span { display: none; }
.app[data-sidebar="collapsed"] .sidebar__signout { padding: 0; gap: 0; }

/* -------------------------------------------------------------- TOPBAR -- */
.topbar {
  height: var(--h-topbar); flex: none;
  background: var(--bg-nav);
  border-bottom: 1px solid var(--border);
  display: flex; align-items: center; gap: var(--sp-4);
  padding: 0 var(--page-pad-x);
  position: sticky; top: 0; z-index: var(--z-sticky);
}
.topbar__actions { display: flex; align-items: center; gap: var(--sp-2); margin-left: auto; }
/* The bell: the unread count rides on the icon's shoulder, in the same badge
   the sidebar uses so a number reads the same everywhere. */
.bell { position: relative; }
.bell__count { position: absolute; top: -4px; right: -6px; min-width: 16px; height: 16px;
               padding: 0 4px; font-size: var(--fs-micro); line-height: 16px; pointer-events: none; }
/* One notification in the drawer: direction pill, then title and move. */
.ntf { display: flex; align-items: flex-start; gap: var(--sp-3); padding: var(--sp-3) 0;
       border-bottom: 1px solid var(--border); }
.ntf:last-child { border-bottom: 0; }
.ntf__body { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1; }
.ntf__body a { color: var(--text-primary); text-decoration: none; font-weight: var(--fw-medium); }
.ntf__body a:hover { color: var(--brand); }
.ntf.is-read .ntf__body a { color: var(--text-secondary); font-weight: var(--fw-regular); }

/* -------------------------------------------------------------- SEARCH -- */
.search {
  position: relative; display: flex; align-items: center;
  width: min(460px, 42vw);
}
/* Any svg, not just .i: the markup uses .i-sm, so this rule never matched and
   the magnifier sat as a flex item beside the field instead of inside it. */
.search > svg { position: absolute; left: 12px; width: 16px; height: 16px;
                color: var(--text-muted); pointer-events: none; }
.search input {
  width: 100%; height: var(--h-control);
  padding: 0 76px 0 38px;
  background: var(--bg-app); border: 1px solid var(--border);
  border-radius: var(--r-md); color: var(--text-primary);
  font-size: var(--fs-body); outline: none;
  transition: border-color var(--dur-fast) var(--ease), box-shadow var(--dur-fast) var(--ease), background var(--dur-fast) var(--ease);
}
.search input::placeholder { color: var(--text-muted); }
.search input:hover { border-color: var(--border-strong); }
.search input:focus { background: var(--bg-surface); border-color: var(--border-focus); box-shadow: var(--sh-focus); }
.kbd {
  font-family: var(--font-sans); font-size: var(--fs-micro); font-weight: var(--fw-semi);
  color: var(--text-muted); background: var(--bg-surface);
  border: 1px solid var(--border); border-radius: var(--r-xs);
  padding: 2px 6px; line-height: 1.4;
}
.search .kbd { position: absolute; right: 10px; }

/* ------------------------------------------------------------- BUTTONS -- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--sp-2);
  height: var(--h-control); padding: 0 var(--sp-4);
  border-radius: var(--r-md); border: 1px solid transparent;
  font-size: var(--fs-body); font-weight: var(--fw-semi);
  cursor: pointer; white-space: nowrap;
  transition: background var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease),
              color var(--dur-fast) var(--ease), box-shadow var(--dur-fast) var(--ease);
}
.btn--primary { background: var(--brand); color: var(--brand-on); }
.btn--primary:hover { background: var(--brand-hover); }
.btn--primary:active { background: var(--brand-active); }
.btn--secondary { background: var(--bg-surface); color: var(--text-primary); border-color: var(--border); }
.btn--secondary:hover { background: var(--bg-hover); border-color: var(--border-strong); }
.btn--soft { background: var(--brand-soft); color: var(--brand); }
.btn--soft:hover { background: var(--brand-soft); filter: brightness(.97); }
.btn--ghost { background: transparent; color: var(--text-secondary); }
.btn--ghost:hover { background: var(--bg-hover); color: var(--text-primary); }
.btn--danger { background: var(--negative); color: #fff; }
.btn--danger:hover { filter: brightness(.94); }
.btn--sm { height: var(--h-control-sm); padding: 0 var(--sp-3); font-size: var(--fs-sm); }
.btn--icon { width: var(--h-control); padding: 0; }
.btn--icon.btn--sm { width: var(--h-control-sm); }
.btn[disabled], .btn.is-disabled { opacity: .5; pointer-events: none; }
.btn.is-loading { color: transparent; position: relative; pointer-events: none; }
.btn.is-loading::after {
  content: ""; position: absolute; width: 15px; height: 15px; border-radius: 50%;
  border: 2px solid currentColor; border-top-color: transparent; color: var(--brand-on);
  animation: spin .7s linear infinite;
}
.btn--secondary.is-loading::after, .btn--ghost.is-loading::after { color: var(--text-secondary); }
@keyframes spin { to { transform: rotate(360deg); } }

/* --------------------------------------------------------------- CARDS -- */
.card {
  background: var(--bg-surface);
  border: 1px solid var(--border-soft);
  border-radius: var(--r-lg);
  box-shadow: var(--sh-xs);
  padding: var(--card-pad);
  display: flex; flex-direction: column; gap: var(--sp-4);
  min-width: 0;
}
.card--flush { padding: 0; gap: 0; overflow: hidden; }
.card--tight { padding: var(--card-pad-sm); gap: var(--sp-3); }
/* A card you can click. One definition for the whole product: the niche picks,
   the product opportunities and anything added later must react the same way,
   or the grid reads as half-alive. */
.card--interactive {
  cursor: pointer; position: relative;
  transition: border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease),
              transform var(--dur) var(--ease);
}
.card--interactive:hover {
  border-color: var(--brand); box-shadow: var(--sh-md); transform: translateY(-2px);
}
.card--interactive:focus-visible { outline: none; box-shadow: var(--sh-focus); }
.card--interactive:active { transform: translateY(0); }
@media (prefers-reduced-motion: reduce) {
  .card--interactive:hover { transform: none; }
}
.card__head { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--sp-4); }
.card__head--pad { padding: var(--card-pad) var(--card-pad) 0; }
.card__title { font-family: var(--font-display); font-size: var(--fs-card); font-weight: var(--fw-bold); line-height: var(--lh-card); }
.card__sub { font-size: var(--fs-sm); color: var(--text-secondary); }
.card__foot { border-top: 1px solid var(--border); padding: var(--sp-3) var(--card-pad); display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3); }

/* ----------------------------------------------------------- KPI CARDS -- */
.kpi { display: flex; flex-direction: column; gap: var(--sp-3); }
.kpi__top { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--sp-3); }
.kpi__icon {
  width: 40px; height: 40px; border-radius: var(--r-md); flex: none;
  display: grid; place-items: center;
  background: var(--brand-soft); color: var(--brand);
}
.kpi__icon[data-tone="growth"]      { background: var(--positive-soft); color: var(--positive); }
.kpi__icon[data-tone="units"]       { background: var(--info-soft);     color: var(--info); }
.kpi__icon[data-tone="competition"] { background: var(--warning-soft);  color: var(--warning); }
.kpi__icon[data-tone="forecast"]    { background: var(--data-forecast-soft); color: var(--data-forecast); }
.kpi__value {
  font-family: var(--font-display); font-size: var(--fs-kpi); line-height: var(--lh-kpi);
  font-weight: var(--fw-black); letter-spacing: -.025em;
  font-variant-numeric: tabular-nums;
}
.kpi__meta { display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap; }
.kpi__context { font-size: var(--fs-sm); color: var(--text-muted); }
.kpi__spark { height: 40px; margin-top: -4px; overflow: hidden; }
/* no history yet: the slot carries a caption, not a chart — let it collapse */
.kpi__spark--note { height: auto; margin-top: -6px; }

/* --------------------------------------------------------------- DELTA -- */
.delta {
  display: inline-flex; align-items: center; gap: 3px;
  font-family: var(--font-num); font-size: var(--fs-sm); font-weight: var(--fw-semi);
  font-variant-numeric: tabular-nums; letter-spacing: var(--tracking-num);
}
/* Colour states MEANING, the arrow states DIRECTION. For most metrics up is
   good, so --up/--down are the shorthand. For inverse metrics (cost, blocks,
   latency, churn) use --good/--bad and pick the arrow yourself. */
.delta--up,   .delta--good { color: var(--positive); }
.delta--down, .delta--bad  { color: var(--negative); }
.delta--flat { color: var(--text-muted); }
.delta__arrow { font-size: 11px; line-height: 1; }

/* -------------------------------------------------------------- BADGES -- */
.badge {
  display: inline-flex; align-items: center; gap: 5px;
  height: 22px; padding: 0 9px; border-radius: var(--r-pill);
  font-size: var(--fs-micro); font-weight: var(--fw-black);
  letter-spacing: .02em; white-space: nowrap;
  background: var(--neutral-soft); color: var(--text-secondary);
}
/* Good / attention / bad read from ONE palette (--st-*), the same one the
   table pills and the competition bars use. They used to carry their own
   shades here, so the identical state looked different in a badge and in a
   table cell. --positive/--warning/--negative stay for charts and text. */
.badge--brand    { background: var(--brand-soft);    color: var(--brand); }
.badge--positive { background: var(--st-pos-bg);  color: var(--st-pos-fg); }
.badge--warning  { background: var(--st-warn-bg); color: var(--st-warn-fg); }
.badge--negative { background: var(--st-neg-bg);  color: var(--st-neg-fg); }
.badge--neutral  { background: var(--st-flat-bg); color: var(--st-flat-fg); }
.badge--info     { background: var(--info-soft);     color: var(--info); }
.badge--forecast { background: var(--data-forecast-soft); color: var(--data-forecast); }
.badge--dot::before { content: ""; width: 6px; height: 6px; border-radius: 50%; background: currentColor; }

/* ------------------------------------------------------------- AVATARS -- */
.avatar {
  width: 40px; height: 40px; border-radius: var(--r-pill); flex: none;
  display: grid; place-items: center; overflow: hidden;
  font-size: var(--fs-sm); font-weight: var(--fw-semi);
  background: var(--brand-soft); color: var(--brand);
  letter-spacing: .01em;
}
.avatar--sq { border-radius: var(--r-md); }
.avatar--32 { width: 32px; height: 32px; font-size: var(--fs-caption); }
.avatar--24 { width: 24px; height: 24px; font-size: var(--fs-micro); border-radius: var(--r-pill); }
.avatar--48 { width: 48px; height: 48px; font-size: var(--fs-card); }
.avatar img { width: 100%; height: 100%; object-fit: cover; }
.avatar-stack { display: flex; }
.avatar-stack .avatar { margin-left: -8px; border: 2px solid var(--bg-surface); }
.avatar-stack .avatar:first-child { margin-left: 0; }

/* -------------------------------------------------------------- ENTITY -- */
.entity { display: flex; align-items: center; gap: var(--sp-3); min-width: 0; }
.entity__body { display: flex; flex-direction: column; min-width: 0; gap: 1px; }
.entity__name { font-size: var(--fs-body); font-weight: var(--fw-semi); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.entity__meta { font-size: var(--fs-caption); color: var(--text-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.thumb {
  width: 40px; height: 40px; border-radius: var(--r-sm); flex: none;
  background: var(--bg-surface-alt); border: 1px solid var(--border);
  object-fit: contain; padding: 3px;
}
.thumb--48 { width: 48px; height: 48px; }

/* -------------------------------------------------------------- TABLES -- */
.table-wrap { width: 100%; overflow-x: auto; }
/* cells are separated, not glued: vertical gap between rows (owner ask 24.08),
   rows read as soft strips on the sunken surface */
.table { width: 100%; border-collapse: separate; border-spacing: 0 var(--sp-2); font-size: var(--fs-body); }
.table th, .table td { padding: 0 var(--sp-4); vertical-align: middle; }
.table th:first-child, .table td:first-child { padding-left: var(--card-pad); }
.table th:last-child,  .table td:last-child  { padding-right: var(--card-pad); }
.table thead th {
  position: sticky; top: 0; z-index: 2;
  height: 40px; background: var(--bg-surface);
  border-bottom: 1px solid var(--border);
  font-size: var(--fs-micro); font-weight: var(--fw-black);
  letter-spacing: var(--tracking-label); text-transform: uppercase;
  color: var(--text-faint); text-align: left; white-space: nowrap;
}
.table thead th.is-sortable { cursor: pointer; user-select: none; }
.table thead th.is-sortable:hover { color: var(--text-secondary); }
.table thead th .sort { display: inline-flex; align-items: center; gap: 4px; }
.table thead th[aria-sort] { color: var(--brand); }
.table tbody tr { height: var(--h-row); }
.table tbody td {
  background: var(--bg-row);
  transition: background var(--dur-fast) var(--ease);
}
.table tbody td:first-child { border-radius: var(--r-row) 0 0 var(--r-row); }
.table tbody td:last-child  { border-radius: 0 var(--r-row) var(--r-row) 0; }
/* hover/selected tint layers over the strip background (both are translucent) */
.table tbody tr:hover td { background: linear-gradient(var(--bg-hover), var(--bg-hover)), var(--bg-row); }
.table tbody tr.is-selected td { background: var(--bg-selected); }
.table--tight tbody tr { height: var(--h-row-tight); }
.table .num {
  text-align: right; font-family: var(--font-num);
  font-variant-numeric: tabular-nums; letter-spacing: var(--tracking-num);
  white-space: nowrap;
}
.table .num--key { font-weight: var(--fw-semi); }
.table .rank {
  text-align: center; width: 52px;
  font-family: var(--font-num); font-variant-numeric: tabular-nums;
  color: var(--text-muted); font-size: var(--fs-sm);
}
.table .col-actions { width: 44px; text-align: right; }

/* --------------------------------------------------------- PROGRESS/BAR */
.progress { height: 6px; border-radius: var(--r-pill); background: var(--track); overflow: hidden; width: 100%; }
/* Gradient bars are the handoff's, and they carry the same meaning as the flat
   fills did: violet for money, green for room to grow. */
.progress__fill { height: 100%; border-radius: var(--r-pill); background: var(--bar-earn); transition: width var(--dur-slow) var(--ease); }
.progress__fill[data-tone="growth"]      { background: var(--bar-room); }
.progress__fill[data-tone="competition"] { background: var(--st-warn-fg); }
.progress__fill[data-tone="risk"]        { background: var(--st-neg-fg); }
.progress__fill[data-tone="units"]       { background: var(--info); }
.progress--sm { height: 4px; }
.progress-row { display: flex; align-items: center; gap: var(--sp-3); }
.progress-row .progress { flex: 1; min-width: 60px; }
.progress-row__val { font-family: var(--font-num); font-size: var(--fs-sm); font-variant-numeric: tabular-nums; color: var(--text-secondary); width: 44px; text-align: right; flex: none; }

/* barlist — horizontal ranking */
.barlist { display: flex; flex-direction: column; gap: var(--sp-3); }
.barlist__item { display: grid; grid-template-columns: minmax(90px, 148px) 1fr auto; align-items: center; gap: var(--sp-3); }
.barlist__label { font-size: var(--fs-body); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.barlist__track { height: 10px; background: var(--track); border-radius: var(--r-pill); overflow: hidden; }
.barlist__fill { height: 100%; border-radius: var(--r-pill); background: var(--bar-earn); transition: width var(--dur-slow) var(--ease); }
.barlist__val { font-family: var(--font-num); font-size: var(--fs-sm); font-weight: var(--fw-semi); font-variant-numeric: tabular-nums; min-width: 62px; text-align: right; }

/* ------------------------------------------------------------- CONTROLS */
.field { display: flex; flex-direction: column; gap: 6px; }
.field__label { font-size: var(--fs-sm); font-weight: var(--fw-medium); color: var(--text-secondary); }
.field__hint  { font-size: var(--fs-caption); color: var(--text-muted); }
.field__error { font-size: var(--fs-caption); color: var(--negative); }

.input, .select, .textarea {
  height: var(--h-control); width: 100%;
  padding: 0 var(--sp-3);
  background: var(--bg-surface); color: var(--text-primary);
  border: 1px solid var(--border); border-radius: var(--r-sm);
  font-size: var(--fs-body); outline: none;
  transition: border-color var(--dur-fast) var(--ease), box-shadow var(--dur-fast) var(--ease);
}
.textarea { height: auto; padding: 10px var(--sp-3); resize: vertical; min-height: 88px; line-height: var(--lh-body); }
.input::placeholder, .textarea::placeholder { color: var(--text-muted); }
.input:hover, .select:hover, .textarea:hover { border-color: var(--border-strong); }
.input:focus, .select:focus, .textarea:focus { border-color: var(--border-focus); box-shadow: var(--sh-focus); }
.input[disabled], .select[disabled] { background: var(--bg-sunken); color: var(--text-muted); pointer-events: none; }
.input.is-invalid { border-color: var(--negative); }
/* A file input in the same frame as a text one: the browser's own button and
   the file name sit on the control's centre line instead of its top edge, and
   the button wears the secondary-button look rather than the platform grey. */
.input.is-invalid:focus { box-shadow: 0 0 0 3px var(--negative-soft); }
.select {
  appearance: none; padding-right: 34px; cursor: pointer;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%23A3AED0' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 10px center;
}
/* A data-URI cannot read a CSS variable, so the chevron is the one asset that
   needs an explicit per-theme copy. Colours match --text-muted in each theme. */
:root[data-theme="dark"] .select {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%237A88AC' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .select {
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%237A88AC' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
  }
}

/* segmented control */
.segmented {
  display: inline-flex; padding: 3px; gap: 2px;
  background: var(--bg-sunken); border-radius: var(--r-md);
  border: 1px solid var(--border);
}
.segmented__btn {
  height: 30px; padding: 0 var(--sp-3); border: none; background: transparent;
  border-radius: var(--r-xs); cursor: pointer;
  font-size: var(--fs-sm); font-weight: var(--fw-medium); color: var(--text-secondary);
  transition: background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}
.segmented__btn:hover { color: var(--text-primary); }
.segmented__btn[aria-pressed="true"], .segmented__btn.is-active {
  background: var(--bg-surface); color: var(--text-primary);
  font-weight: var(--fw-semi); box-shadow: var(--sh-xs);
}

/* filter chip */
.chip {
  display: inline-flex; align-items: center; gap: 6px;
  height: var(--h-control-sm); padding: 0 10px;
  border: 1px solid var(--border); border-radius: var(--r-pill);
  background: var(--bg-surface); color: var(--text-secondary);
  font-size: var(--fs-sm); font-weight: var(--fw-medium); cursor: pointer;
  transition: all var(--dur-fast) var(--ease);
}
.chip:hover { border-color: var(--border-strong); color: var(--text-primary); }
.chip.is-active { background: var(--brand-soft); border-color: transparent; color: var(--brand); font-weight: var(--fw-semi); }
.chip__x { display: grid; place-items: center; opacity: .6; }
.chip__x:hover { opacity: 1; }

.toolbar { display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap; }

/* switch */
.switch { position: relative; display: inline-flex; align-items: center; gap: var(--sp-3); cursor: pointer; }
.switch input { position: absolute; opacity: 0; width: 0; height: 0; }
.switch__track { width: 38px; height: 22px; border-radius: var(--r-pill); background: var(--bg-sunken); border: 1px solid var(--border); transition: background var(--dur) var(--ease), border-color var(--dur) var(--ease); flex: none; }
.switch__track::after { content: ""; display: block; width: 16px; height: 16px; border-radius: 50%; background: var(--bg-surface); box-shadow: var(--sh-xs); margin: 2px; transition: transform var(--dur) var(--ease); }
.switch input:checked + .switch__track { background: var(--brand); border-color: var(--brand); }
.switch input:checked + .switch__track::after { transform: translateX(16px); }
.switch input:focus-visible + .switch__track { box-shadow: var(--sh-focus); }

/* ---------------------------------------------------------------- TABS -- */
.tabs { display: flex; gap: var(--sp-5); border-bottom: 1px solid var(--border); }
.tab {
  position: relative; padding: 0 0 11px; border: none; background: none; cursor: pointer;
  font-size: var(--fs-body); font-weight: var(--fw-medium); color: var(--text-secondary);
  transition: color var(--dur-fast) var(--ease);
}
.tab:hover { color: var(--text-primary); }
.tab[aria-selected="true"] { color: var(--brand); font-weight: var(--fw-semi); }
.tab[aria-selected="true"]::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: -1px;
  height: 2px; background: var(--brand); border-radius: 2px 2px 0 0;
}

/* --------------------------------------------------------- BREADCRUMBS -- */
.crumbs { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; font-size: var(--fs-sm); }
.crumbs a { color: var(--text-muted); font-weight: var(--fw-medium); }
.crumbs a:hover { color: var(--text-secondary); }
.crumbs__sep { color: var(--text-muted); opacity: .55; display: grid; place-items: center; }
.crumbs__current { color: var(--text-primary); font-weight: var(--fw-semi); }

/* ---------------------------------------------------------------- TREE -- */
/* --------------------------------------------------------- EMPTY STATE -- */
.empty {
  display: flex; flex-direction: column; align-items: center; text-align: center;
  gap: var(--sp-3); padding: var(--sp-12) var(--sp-6);
}
.empty img { width: 148px; height: auto; opacity: .95; margin-bottom: var(--sp-2); }
.empty__title { font-size: var(--fs-card); font-weight: var(--fw-semi); }
.empty__text { font-size: var(--fs-body); color: var(--text-secondary); max-width: 380px; }
.empty__actions { margin-top: var(--sp-3); display: flex; gap: var(--sp-2); }

/* ----------------------------------------------------------- SKELETONS -- */
.skel {
  background: linear-gradient(90deg, var(--bg-skeleton) 25%, var(--bg-skeleton-hi) 37%, var(--bg-skeleton) 63%);
  background-size: 400% 100%;
  animation: skel 1.4s ease infinite;
  border-radius: var(--r-xs);
}
@keyframes skel { 0% { background-position: 100% 50%; } 100% { background-position: 0 50%; } }
.skel--text { height: 12px; }
.skel--title { height: 18px; width: 45%; }
.skel--kpi { height: 34px; width: 62%; }
.skel--circle { border-radius: 50%; }

/* -------------------------------------------------------------- ALERTS -- */
.alert {
  display: flex; gap: var(--sp-3); padding: var(--sp-3) var(--sp-4);
  border-radius: var(--r-md); font-size: var(--fs-sm);
  background: var(--info-soft); color: var(--text-primary);
  border: 1px solid transparent;
}
.alert .i { color: var(--info); margin-top: 2px; }
.alert--positive { background: var(--positive-soft); } .alert--positive .i { color: var(--positive); }
.alert--warning  { background: var(--warning-soft); }  .alert--warning  .i { color: var(--warning); }
.alert--negative { background: var(--negative-soft); } .alert--negative .i { color: var(--negative); }
.alert__title { font-weight: var(--fw-semi); display: block; margin-bottom: 2px; }

/* -------------------------------------------------------------- INSIGHT */
.insight {
  border: 1px solid var(--border); border-radius: var(--r-md);
  background: var(--data-forecast-soft);
  padding: var(--sp-3) var(--sp-4); display: flex; gap: var(--sp-3);
  border-color: transparent;
}
.insight .i { color: var(--data-forecast); flex: none; margin-top: 2px; }
.insight__text { font-size: var(--fs-sm); color: var(--text-primary); }

/* --------------------------------------------------------------- MISC --- */
.divider { height: 1px; background: var(--border); border: none; margin: 0; }
.dot-sep { color: var(--text-muted); opacity: .6; }
.legend { display: flex; align-items: center; gap: var(--sp-4); flex-wrap: wrap; }
.legend__item { display: inline-flex; align-items: center; gap: 6px; font-size: var(--fs-sm); color: var(--text-secondary); }
.legend__swatch { width: 9px; height: 9px; border-radius: 3px; flex: none; }
.legend__swatch--line { width: 14px; height: 3px; border-radius: 2px; }
.legend__swatch--dashed { width: 14px; height: 0; border-top: 2px dashed currentColor; border-radius: 0; }

.pagination { display: flex; align-items: center; gap: var(--sp-2); }
.pagination__info { font-size: var(--fs-sm); color: var(--text-muted); }

.dropdown { position: relative; }
.menu {
  position: absolute; right: 0; top: calc(100% + 6px); min-width: 200px;
  background: var(--bg-surface); border: 1px solid var(--border);
  border-radius: var(--r-md); box-shadow: var(--sh-md);
  padding: 6px; z-index: var(--z-dropdown);
}
.menu__item {
  display: flex; align-items: center; gap: var(--sp-3);
  width: 100%; padding: 8px 10px; border: none; background: none;
  border-radius: var(--r-xs); cursor: pointer; text-align: left;
  font-size: var(--fs-body); color: var(--text-primary);
}
.menu__item:hover { background: var(--bg-hover); }
.menu__item--danger { color: var(--negative); }
.menu__sep { height: 1px; background: var(--border); margin: 6px 0; }

/* ==========================================================================
   HIGHLIGHT CARDS — REPORT ONLY.
   The app no longer uses these: the niche picks and the product
   opportunities are both built by entityCard() on the .nf-card family, so
   the two grids cannot drift apart. What is left here is consumed by the
   standalone finder report (radar/crawler/templates/finder_report.html),
   which inlines this stylesheet and still ships its own markup. Do not
   reach for .top3/.meter/.fig in the cabinet or the admin console. */
.top3-wrap { display: flex; flex-direction: column; gap: var(--sp-4); }
.top3-head { display: flex; align-items: baseline; justify-content: space-between;
             gap: var(--sp-4); flex-wrap: wrap; }

.top3__top { display: flex; align-items: flex-start; gap: var(--sp-4); }
.top3__rank { font-family: var(--font-display); font-weight: var(--fw-black); font-size: 34px; line-height: 1;
              font-weight: var(--fw-bold); color: var(--border-strong);
              flex: none; letter-spacing: var(--tracking-num); }
.meters { display: flex; flex-direction: column; gap: var(--sp-2); }
.meter { display: grid; grid-template-columns: 104px 1fr 34px;
         align-items: center; gap: var(--sp-3); }
.meter__k { font-size: var(--fs-caption); color: var(--text-secondary); }
.meter__v { font-family: var(--font-num); font-size: var(--fs-sm);
            font-variant-numeric: tabular-nums; text-align: right;
            color: var(--text-secondary); }
.figs { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--sp-3);
        border-top: 1px solid var(--border); padding-top: var(--sp-4); }
.fig__k { font-size: var(--fs-micro); letter-spacing: var(--tracking-label);
          text-transform: uppercase; color: var(--text-muted); display: block; }
.fig__v { font-family: var(--font-display); font-size: var(--fs-card);
          font-weight: var(--fw-black); font-variant-numeric: tabular-nums; }

/* -------------------------------------------------------------- MODAL */
.modal { position: fixed; inset: 0; z-index: var(--z-modal);
         display: grid; place-items: center; padding: var(--sp-6); }
.modal__scrim { position: absolute; inset: 0; background: var(--bg-overlay); }
.modal__panel { position: relative; width: min(1080px, 100%); max-height: 92vh;
                display: flex; flex-direction: column;
                background: var(--bg-surface); border: 1px solid var(--border);
                border-radius: var(--r-xl); box-shadow: var(--sh-lg); overflow: hidden; }
.modal__head { flex: none; display: flex; align-items: flex-start; gap: var(--sp-4);
               padding: var(--card-pad); border-bottom: 1px solid var(--border); }
/* min-height:0 is required: a flex item's default min-height is its content,
   so a scrolling body refuses to shrink and spills past the panel instead. */
.modal__body { flex: 1 1 auto; min-height: 0;
               overflow-y: auto; overscroll-behavior: contain;
               padding: var(--card-pad);
               display: flex; flex-direction: column; gap: var(--section-gap); }
/* A flex item may shrink below its content, and in a scrolling column the last
   sections did exactly that — the products table collapsed to zero height and
   read as "squeezed", not as "scroll down". Children keep their own height;
   the body is what scrolls. */
.modal__body > * { flex: none; }


@keyframes rise { from { opacity: 0; transform: translateY(10px) } to { opacity: 1; transform: none } }
@keyframes fade { from { opacity: 0 } to { opacity: 1 } }
.top3 .card { animation: rise .4s var(--ease) backwards; }
.top3 .card:nth-child(1) { animation-delay: .05s }
.top3 .card:nth-child(2) { animation-delay: .12s }
.top3 .card:nth-child(3) { animation-delay: .19s }
.modal__scrim { animation: fade .18s var(--ease) }
.modal__panel { animation: rise .26s var(--ease) }
@media (prefers-reduced-motion: reduce) {
  .top3 .card, .modal__scrim, .modal__panel { animation: none }
}

/* --------------------------------------------------------------- chat -- */
/* PARKED 04.09.2026 with the assistant view (see cabinet.js RENDER.assistant):
   kept, not dead - design/ is not versioned and the section comes back. */
/* Marzi Assistant (design handoff 09/2026): warm chat on the app cream —
   mascot header, violet user bubbles, white answer bubbles with KPI cards
   and follow-up chips, rounded composer. Tokens first, so dark mode holds. */
.chat { display: flex; flex-direction: column; gap: var(--sp-4);
  width: 100%; max-width: 960px; margin: 0 auto; }
/* No inner scroll (owner ask 01.09): the thread grows the page. A box that
   scrolled inside the card hid the answer behind its own edge while the
   composer stayed pinned under it. */
.chat__log { display: flex; flex-direction: column; gap: 20px; padding: 16px 4px 24px; }
/* One reading column for the thread, the same 640px the composer uses, so the
   bubbles line up with the input under them. Without it the answer ran the
   full width of the page card, its lines got unreadably long, and the section
   looked misaligned against the bar. Applied to the log, not to its children:
   a width on the children would override the bubbles' own alignment. */
.chat__log { width: min(640px, 100%); margin-inline: auto; }
.chat__msg--user { align-self: flex-end; max-width: 78%; background: var(--brand);
  color: var(--brand-on); border-radius: 20px 20px 6px 20px; padding: 14px 20px;
  font-size: 15px; font-weight: 600; line-height: 1.5;
  box-shadow: 0 4px 14px rgba(91, 69, 224, .25);
  white-space: pre-wrap; overflow-wrap: break-word; }
.chat__group { align-self: flex-start; display: flex; gap: 12px; min-width: 0; }
.chat__avatar { flex: none; margin-top: 4px; }
.chat__col { display: flex; flex-direction: column; gap: 12px; min-width: 0; }
.chat__msg--bot { background: var(--bg-surface); border: 1px solid var(--border);
  border-radius: 6px 20px 20px 20px; padding: 18px 22px; font-size: 15px;
  color: var(--text-primary); line-height: 1.6;
  box-shadow: 0 2px 10px rgba(90, 61, 43, .05);
  overflow-wrap: break-word; }
/* the answer arrives as blocks, not one pre-wrapped run — space them so a
   lead-in, a list of niches and a closing line read as three things */
.chat__msg--bot > * { margin: 0; }
.chat__msg--bot > * + * { margin-top: 14px; }
.chat__msg--bot ul { padding-left: 20px; display: flex; flex-direction: column; gap: 10px; }
.chat__msg--bot li::marker { color: var(--text-faint); }
/* --- markdown inside an answer (js/md.js) ---------------------------------
   A model writes a table when it has rows to line up, a numbered list for
   steps, a fence for a log line. Nothing here styles the chat: it styles what
   the model wrote inside one bubble, which is why every rule is scoped to it.
   The bubble's own rhythm (14px between blocks) already comes from the rules
   above. */
.chat__msg--bot ol { padding-left: 22px; display: flex; flex-direction: column;
                     gap: 10px; }
/* A nested list belongs to the line above it, so it sits closer than two
   siblings do. */
.chat__msg--bot li > ul, .chat__msg--bot li > ol { margin-top: 10px; gap: 8px; }
.chat__msg--bot h4 { font-family: var(--font-display); font-weight: var(--fw-bold);
                     font-size: var(--fs-card); line-height: var(--lh-card);
                     color: var(--text-primary); }
.chat__msg--bot h5 { font-size: var(--fs-sm); line-height: var(--lh-sm);
                     font-weight: var(--fw-bold); color: var(--text-secondary); }
/* Its own scroller: a table wider than the bubble scrolls inside itself
   instead of pushing the page sideways. */
.md__scroll { overflow-x: auto; }
.chat__msg--bot table { border-collapse: collapse; width: 100%;
                        font-size: var(--fs-sm); line-height: var(--lh-sm); }
.chat__msg--bot th, .chat__msg--bot td {
  border-bottom: 1px solid var(--border); padding: var(--sp-2) var(--sp-3);
  text-align: left; vertical-align: top; }
.chat__msg--bot th { color: var(--text-secondary); font-weight: var(--fw-bold);
                     white-space: nowrap; }
/* Figures line up across rows only if their digits are the same width. */
.chat__msg--bot td { font-variant-numeric: tabular-nums; }
.chat__msg--bot tbody tr:last-child td { border-bottom: 0; }
.chat__msg--bot code { font-family: var(--font-mono); font-size: var(--fs-sm);
                       background: var(--bg-sunken); border-radius: var(--r-sm);
                       padding: 1px 5px; }
.chat__msg--bot .md__code { background: var(--bg-sunken);
                            border: 1px solid var(--border);
                            border-radius: var(--r-md); padding: var(--sp-3) var(--sp-4);
                            overflow-x: auto; }
.chat__msg--bot .md__code code { background: none; padding: 0;
                                 font-size: var(--fs-caption); line-height: var(--lh-sm); }
.chat__msg--bot blockquote { border-left: 3px solid var(--border);
                             padding-left: var(--sp-4); color: var(--text-secondary); }
.chat__msg--bot hr { border: 0; border-top: 1px solid var(--border); }
.chat__msg--bot a { color: var(--text-brand); }
.chat__msg--bot del { color: var(--text-muted); }
/* --- a wider thread for the console ---------------------------------------
   The cabinet's 640px column is right for what it holds: sentences, and a
   sentence wants a short line. The Index agent answers with dashboards — a
   card of five figures in that column stacks into a ladder nobody reads at a
   glance — and the console page has the width to spare. So the console asks
   for a wider column, and the figures grow with it. */
.chat--wide .chat__log,
.chat--wide .entry__form { width: min(1200px, 100%); }
.chat--wide .chat__msg--user { max-width: 70%; }
.chat--wide .md__tile { flex: 1 1 160px; padding: var(--sp-4) var(--sp-5); }
.chat--wide .md__tile-v { font-size: var(--fs-kpi); line-height: var(--lh-kpi); }
.chat--wide .md__tile-l { font-size: var(--fs-sm); }
.chat--wide .md__tile-u { font-size: var(--fs-sm); }
.chat--wide .chat__msg--bot { font-size: var(--fs-card); line-height: var(--lh-card); }
@media (max-width: 1100px) {
  .chat--wide .md__tile-v { font-size: var(--fs-section); line-height: var(--lh-section); }
}

/* --- the answer card (js/md.js, mm-card) --------------------------------
   A status answer is a dashboard, not a paragraph. The pill, the badges and
   the bar are the console's own components; what is new is the strip of
   figures, because a row of read-at-a-glance numbers inside a chat bubble did
   not exist before. Sizes and colours are tokens, as everywhere else. */
.md__card { border: 1px solid var(--border); border-radius: var(--r-lg);
            padding: var(--sp-4); display: flex; flex-direction: column;
            gap: var(--sp-4); background: var(--bg-surface); }
.md__card[data-tone="bad"]  { background: var(--negative-soft); border-color: transparent; }
.md__card[data-tone="warn"] { background: var(--warning-soft);  border-color: transparent; }
.md__card-head { display: flex; align-items: center; gap: var(--sp-3);
                 flex-wrap: wrap; }
.md__card-i { color: var(--text-secondary); flex: none; }
.md__card[data-tone="bad"] .md__card-i  { color: var(--negative); }
.md__card[data-tone="warn"] .md__card-i { color: var(--warning); }
.md__card-t { font-weight: var(--fw-bold); color: var(--text-primary); }
.md__card-sum { color: var(--text-secondary); font-size: var(--fs-sm);
                line-height: var(--lh-sm); flex: 1 1 200px; min-width: 0; }
.md__card-tags { display: flex; gap: var(--sp-2); flex-wrap: wrap; margin-left: auto; }
/* The figures. One strip, hairlines between, wrapping rather than shrinking:
   a number squeezed to two digits per line is worse than a second row. */
.md__tiles { display: flex; flex-wrap: wrap; border-radius: var(--r-md);
             background: var(--bg-sunken); overflow: hidden; }
.md__tile { flex: 1 1 120px; min-width: 0; padding: var(--sp-3) var(--sp-4);
            display: flex; flex-direction: column; gap: 2px;
            border-left: 1px solid var(--border); }
.md__tile:first-child { border-left: 0; }
.md__tile-l { font-size: var(--fs-caption); font-weight: var(--fw-bold);
              letter-spacing: .06em; text-transform: uppercase;
              color: var(--text-muted); }
.md__tile-v { font-family: var(--font-display); font-weight: var(--fw-black);
              font-size: var(--fs-card); color: var(--text-primary);
              font-variant-numeric: tabular-nums; }
.md__tile-v[data-tone="bad"]  { color: var(--negative); }
.md__tile-v[data-tone="warn"] { color: var(--warning); }
.md__tile-v[data-tone="ok"]   { color: var(--positive); }
.md__tile-u { font-size: var(--fs-caption); color: var(--text-muted); }
.md__bar { border: 1px solid var(--border); border-radius: var(--r-md);
           padding: var(--sp-3) var(--sp-4); display: flex;
           flex-direction: column; gap: var(--sp-3); }
.md__bar-head { display: flex; align-items: baseline; justify-content: space-between;
                gap: var(--sp-3); }
.md__bar-l { font-weight: var(--fw-bold); }
.md__bar-r { font-size: var(--fs-sm); color: var(--text-secondary); }
.md__bar-v { font-size: var(--fs-sm); font-variant-numeric: tabular-nums;
             white-space: nowrap; color: var(--text-secondary); }
.md__note { font-size: var(--fs-sm); line-height: var(--lh-sm);
            color: var(--text-secondary); }
/* A footnote marker rides the line it explains; the notes themselves close
   the answer, quieter than it. */
.md__fnref { font-size: var(--fs-caption); font-weight: var(--fw-bold);
             color: var(--text-brand); vertical-align: super; line-height: 0;
             margin-left: 2px; }
.chat__msg--bot .md__fn { padding-left: 20px; gap: 6px;
                          font-size: var(--fs-caption); line-height: var(--lh-sm);
                          color: var(--text-muted); }
.chat__kpis { display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px; }
.chat__kpi { background: var(--bg-surface); border: 1px solid var(--border);
  border-radius: 16px; padding: 14px 18px; display: flex;
  flex-direction: column; gap: 4px; min-width: 0; }
.chat__kpi-label { font-size: 11px; font-weight: 800; color: var(--text-secondary);
  letter-spacing: .08em; text-transform: uppercase; }
.chat__kpi-value { font-family: var(--font-display); font-weight: 800;
  font-size: 24px; color: var(--text-primary); }
.chat__kpi-note { font-size: 12px; font-weight: 800; color: var(--text-secondary); }
.chat__chips { display: flex; gap: 8px; flex-wrap: wrap; }
.chat__chip { border: 0; background: var(--brand-soft); color: var(--brand);
  border-radius: 99px; padding: 8px 16px; font-size: 13px; font-weight: 800;
  cursor: pointer; font-family: inherit; }
.chat__chip:hover { filter: brightness(.955); }
/* The assistant sits in the same cream page card as the Niche finder, so the
   log and the composer take the card's padding and the 640px bar centres in
   it exactly like the finder's search. */
.chat__composer { display: flex; flex-direction: column; align-items: center;
  gap: 12px; padding: 0 var(--sp-8) var(--sp-10); }
/* No side padding — the log is already a centred 640 column, and the inset made
   the bubbles sit 32px narrower than the bar under them. The top padding stays:
   without it the first message is glued to the edge of the page card. */
.chat__log { padding: var(--sp-8) 0 var(--sp-4); }
.chat__composer .entry__ex { width: 100%; }
.chat__note { align-self: flex-start; display: flex; align-items: center;
  gap: 10px; color: var(--text-secondary); font-size: 13px; font-weight: 700; }
.chat__note--warn { color: var(--warning); }
/* the "usually about 30s" / elapsed tail sits quieter than the step itself */
.chat__note-eta { color: var(--text-faint); font-weight: var(--fw-semi); }
/* The waiting indicator. noteSay() has always emitted three spans and the
   keyframe existed, but nothing styled them — they rendered as zero-sized
   inline boxes, so the status line was a bare piece of text with no sign that
   anything was happening. */
.chat__dots { display: inline-flex; align-items: center; gap: 5px; flex: none; }
.chat__dots span {
  width: 7px; height: 7px; border-radius: var(--r-pill); background: var(--brand);
  animation: chat-blink 1.2s var(--ease) infinite;
}
.chat__dots span:nth-child(2) { animation-delay: .18s; }
.chat__dots span:nth-child(3) { animation-delay: .36s; }
/* the label breathes with the dots, so the whole line reads as "working" */
.chat__note:not(.chat__note--warn) { animation: chat-pulse 2.4s var(--ease) infinite; }
@keyframes chat-blink { 0%, 100% { opacity: 1; transform: translateY(0); }
                        50% { opacity: .25; transform: translateY(-2px); } }
@keyframes chat-pulse { 0%, 100% { opacity: 1; } 50% { opacity: .72; } }
@media (prefers-reduced-motion: reduce) {
  .chat__dots span, .chat__note { animation: none; }
  .chat__dots span:nth-child(2) { opacity: .6; }
  .chat__dots span:nth-child(3) { opacity: .3; }
}
.chat__disclaimer { font-size: 12px; color: var(--text-muted);
  text-align: center; margin: 0; }
.chat__warn { align-self: stretch; }
@media (max-width: 760px) {
  .chat__kpis { grid-template-columns: 1fr; }
  .chat__group { max-width: 100%; }
  .chat__msg--user { max-width: 86%; }
}

/* ==========================================================================
   BUSY PROGRESS — a wait long enough that a static label reads as a hang.
   The bar advances on measured stage durations and stops short of the end:
   it must never show 100% before the answer is actually there.
   ========================================================================== */
.busy { display: flex; flex-direction: column; gap: var(--sp-3); }
.busy__row { display: flex; align-items: baseline; justify-content: space-between;
             gap: var(--sp-4); }
.busy__stage { font-size: var(--fs-body); font-weight: var(--fw-medium); }
.busy__time { font-family: var(--font-num); font-size: var(--fs-sm);
              font-variant-numeric: tabular-nums; color: var(--text-muted); }
.busy__steps { display: flex; gap: var(--sp-2); flex-wrap: wrap; }
.busy__step { font-size: var(--fs-caption); color: var(--text-muted); }
.busy__step[data-state="done"] { color: var(--positive); }
.busy__step[data-state="now"] { color: var(--brand); font-weight: var(--fw-semi); }

.progress__fill--busy {
  background-image: linear-gradient(90deg,
    transparent 0%, rgba(255, 255, 255, .35) 50%, transparent 100%);
  background-size: 200% 100%;
  background-repeat: no-repeat;
  animation: busy-sheen 1.4s linear infinite;
}
@keyframes busy-sheen { from { background-position: -100% 0 } to { background-position: 200% 0 } }
@media (prefers-reduced-motion: reduce) { .progress__fill--busy { animation: none } }

/* 14px chevron used inside breadcrumbs */
.i-xs { width: 14px; height: 14px; }

/* ==========================================================================
   SHARED SMALL PIECES — used by more than one section, so they live here
   rather than being re-invented inline in each renderer.
   ========================================================================== */
.chips { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); }
.note  { font-size: var(--fs-caption); line-height: var(--lh-sm); color: var(--text-muted); }
.note b { color: var(--text-secondary); font-weight: var(--fw-semi); }
.sep-v { width: 1px; height: 20px; background: var(--border);
         margin: 0 var(--sp-2); flex: none; }

/* An entry screen's intro: the finder illustrates it, the assistant leads with
   an icon, but the type scale and rhythm are the same in both. */
.intro { margin: auto; text-align: center; max-width: 560px; padding: var(--sp-8) 0;
         display: flex; flex-direction: column; align-items: center; gap: var(--sp-4); }
.intro__icon { color: var(--brand); }

/* The question input is the primary control on an entry screen, in the finder
   and in the assistant alike: same height, same type size. */
.search--lead { width: 100%; max-width: none; }
.search--lead input { height: 60px; font-size: 18px;
                      padding: 0 var(--sp-5) 0 54px;
                      border-radius: var(--r-lg); border-width: 2px;
                      background: var(--bg-surface); }
.search--lead .i-sm { left: var(--sp-5); width: 21px; height: 21px; }

/* Global search results, anchored under the topbar input. */
.search { position: relative; }
.search__results {
  position: absolute; left: 0; right: 0; top: calc(100% + 6px);
  background: var(--bg-surface); border: 1px solid var(--border);
  border-radius: var(--r-md); box-shadow: var(--sh-lg);
  padding: var(--sp-2); z-index: var(--z-dropdown);
  max-height: 62vh; overflow-y: auto;
}
.search__group { font-size: var(--fs-micro); letter-spacing: var(--tracking-label);
  text-transform: uppercase; color: var(--text-muted);
  padding: var(--sp-2) var(--sp-2) var(--sp-1); }
.search__hit {
  display: flex; align-items: center; gap: var(--sp-3); width: 100%;
  padding: var(--sp-2) var(--sp-2); border: none; background: none;
  border-radius: var(--r-xs); cursor: pointer; text-align: left;
  color: var(--text-primary); font-size: var(--fs-body);
}
.search__hit:hover, .search__hit:focus-visible { background: var(--bg-hover); outline: none; }
.search__hit .entity__body { flex: 1; min-width: 0; }
.search__val { font-family: var(--font-num); font-size: var(--fs-sm);
  font-variant-numeric: tabular-nums; color: var(--text-secondary); flex: none; }
.search__empty { padding: var(--sp-4) var(--sp-2); color: var(--text-muted);
  font-size: var(--fs-sm); text-align: center; }
/* The letters the query matched, inside a suggestion's name: the eye checks
   why a row is offered without reading the whole line. */
.search__hit mark { background: var(--brand-soft); color: inherit;
  border-radius: var(--r-xs); padding: 0 1px; margin: 0 -1px; }
/* The row a search landed on: marked until the next search or an emptied
   field, and it arrives with a pulse so the eye follows the scroll to it. */
@keyframes hit-in { from { background: var(--brand-soft); } to { background: var(--brand-tint); } }
.dt__row.is-hit { background: var(--brand-tint); box-shadow: inset 3px 0 0 var(--brand);
  animation: hit-in .9s var(--ease); }
.dt__row.is-hit .dt__name-t { color: var(--brand); }

/* Product-opportunity thumbnails (27.08): hotlinked from Allegro's CDN, the
   markup is emitted only when a URL exists, so no broken-image placeholders. */

/* ==========================================================================
   MARKETPLACE PICKER — which marketplace the numbers on screen belong to.
   Only Allegro is connected; the menu says so rather than offering a choice
   that does not exist.
   ========================================================================== */
.mp {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  height: var(--h-control-sm); padding: 0 10px 0 12px;
  background: var(--bg-surface); border: 1px solid var(--border);
  border-radius: var(--r-pill); cursor: pointer;
  transition: border-color var(--dur) var(--ease), background var(--dur) var(--ease);
}
.mp:hover { border-color: var(--border-strong); background: var(--bg-hover); }
.mp[aria-expanded="true"] { border-color: var(--border-focus); box-shadow: var(--sh-focus); }
.mp__logo { height: 15px; width: auto; display: block; }
.mp__caret { color: var(--text-muted); width: 14px; height: 14px; }
.mp__menu { min-width: 232px; }
.mp__menu .menu__item[aria-checked="true"] { background: var(--bg-selected); }
.mp__menu .menu__item img { height: 14px; width: auto; }
.mp__check { margin-left: auto; color: var(--brand); width: 15px; height: 15px; }
/* the language menu offers two entries; the tick marks the one in force */
.mp__menu .menu__item[aria-checked="false"] .mp__check { visibility: hidden; }
.mp__note {
  padding: 8px 10px 4px; font-size: var(--fs-caption);
  color: var(--text-muted); line-height: var(--lh-caption);
}

/* ==========================================================================
   NICHE FINDER — composition from the design handoff. The palette was already
   the brand's, so this file adds structure, not colour: the hero with the
   mascot, the wide search bar with its own submit, the rank-tile pick cards
   with two gradient bars, the progress card and the detail panel.
   ========================================================================== */
/* the page rhythm, same as every other section stack */
.nf { display: flex; flex-direction: column; gap: var(--section-gap); }
.nf-pill { background: var(--bg-surface); border: 1px solid var(--border);
           border-radius: var(--r-pill); padding: 6px 14px;
           font-size: var(--fs-caption); font-weight: 800; color: var(--text-muted);
           font-family: var(--font-sans); }
/* an actionable pill in the page head — the assistant's New chat */
button.nf-pill { cursor: pointer; }
.nf-pill--action { color: var(--brand); }
.nf-pill--action:hover { border-color: var(--brand); }

/* ==========================================================================
   ENTRY BLOCK — the screen a section opens on when it is built around one
   input: Niche finder, Assistant, Spy. Defined once, on purpose. Three copies
   of "a mascot, a headline and a search bar" is how the finder ended up with a
   40px headline while the same headline elsewhere used the display token.

   The block owns its surface, so a caller never wraps it in a .card — that is
   what made Spy read as a white sheet while the other two sat on the app
   background.
   ========================================================================== */
.entry { background: var(--bg-surface); border: 1px solid var(--border);
         border-radius: var(--r-xl); box-shadow: var(--sh-sm);
         padding: var(--sp-10) var(--sp-8);
         display: flex; flex-direction: column; align-items: center;
         gap: var(--sp-6); }
/* Headline and lead come from the type scale, never from a literal size. */
.entry__h { font-family: var(--font-display); font-weight: var(--fw-black);
            font-size: var(--fs-display); line-height: var(--lh-display);
            color: var(--text-primary); text-align: center; margin: 0; }
.entry__p { font-size: var(--fs-card); line-height: var(--lh-card);
            color: var(--text-muted); max-width: 520px; text-align: center;
            margin: 0; }

/* The bar owns its submit, so the action is never a guess. */
.entry__form { width: min(640px, 100%); background: var(--bg-surface);
               border: 2px solid var(--border); border-radius: var(--r-xl);
               padding: 8px 8px 8px var(--sp-6); display: flex; align-items: center;
               gap: var(--sp-4); box-shadow: 0 8px 24px rgba(90, 61, 43, .07);
               transition: border-color var(--dur) var(--ease),
                           box-shadow var(--dur) var(--ease); }
.entry__form:focus-within { border-color: var(--brand);
                            box-shadow: 0 8px 24px rgba(91, 69, 224, .12); }
.entry__form input { flex: 1; border: none; outline: none; background: transparent;
                     font-family: var(--font-sans); font-size: 16px;
                     font-weight: 600; color: var(--text-primary); min-width: 0; }
.entry__form input::placeholder { color: var(--text-muted); font-weight: 600; }
/* the frame already shows focus on the wrapper — the global focus ring on the
   input drew a second rounded rectangle inside it */
.entry__form input:focus-visible { box-shadow: none; }
.entry__form .i-sm, .entry__form > svg { color: var(--text-muted); flex: none;
                                         width: 18px; height: 18px; }

/* flex:none — the bar is a flex row, so without it the button shrinks below
   its content and an icon+label pair (the assistant's "✦ Ask") wraps.
   inline-flex + gap places that icon the same way in every section. */
.entry__go { background: var(--brand); color: var(--brand-on); border: none;
             border-radius: 18px; padding: 12px 26px; font-size: 15px;
             font-weight: 800; cursor: pointer; font-family: var(--font-sans);
             white-space: nowrap; flex: none; display: inline-flex;
             align-items: center; gap: var(--sp-2);
             transition: background var(--dur-fast) var(--ease); }
.entry__go:hover { background: var(--brand-hover); }
.entry__go:disabled { opacity: .6; cursor: default; }
/* while a reply streams the same button becomes Stop */
.entry__go--stop { background: var(--bg-surface); color: var(--brand);
                   border: 1px solid var(--border); }
.entry__go--stop:hover { background: var(--bg-surface-alt); }
.entry__clear { width: 28px; height: 28px; border-radius: var(--r-pill);
                border: none; background: var(--track); color: var(--text-muted);
                font-weight: 800; cursor: pointer; flex: none; }

/* A verdict on what was typed, inside the bar. Hidden until there is something
   to say: an empty pill would read as a state of its own. */
.entry__state { flex: none; display: inline-flex; align-items: center; gap: 6px;
                border-radius: var(--r-pill); padding: 5px 12px;
                font-size: var(--fs-caption); font-weight: var(--fw-bold);
                white-space: nowrap; }
.entry__state[hidden] { display: none; }
.entry__state[data-st="ok"]   { background: var(--positive-soft); color: var(--positive); }
.entry__state[data-st="bad"]  { background: var(--negative-soft); color: var(--negative); }
.entry__state[data-st="busy"] { background: var(--brand-soft);    color: var(--brand); }

/* A first check is a live crawl of three pages and takes most of a minute. The
   frame borrows the niche finder's travelling segment so the wait looks the
   same everywhere in the cabinet, and the pill carries a spinner and the real
   elapsed seconds — a percentage would be invented, the clock is measured. */
.entry__form.is-busy { position: relative; overflow: hidden; border-color: var(--brand);
                       box-shadow: 0 8px 24px rgba(91, 69, 224, .12); }
.entry__form.is-busy::after { content: ""; position: absolute; left: 0; bottom: 0;
                              width: 30%; height: 3px; background: var(--brand);
                              border-radius: var(--r-pill);
                              animation: nf-slide 1.6s ease-in-out infinite; }
.entry__spin { width: 11px; height: 11px; flex: none; border-radius: var(--r-pill);
               border: 2px solid currentColor; border-top-color: transparent;
               animation: spin .7s linear infinite; }
.entry__clock { font-variant-numeric: tabular-nums; opacity: .75; margin-left: 2px; }
@media (prefers-reduced-motion: reduce) {
  .entry__form.is-busy::after { animation: none; width: 100%; }
  .entry__spin { animation: none; }
}

/* Suggestions and controls sit BELOW the bar in every section. Above it they
   read as filters applied to the input rather than as ways to fill it. */
.entry__ex { display: flex; gap: var(--sp-2); flex-wrap: wrap; justify-content: center; }
.entry__ex button { background: var(--bg-surface); border: 1px solid var(--border);
                    color: var(--text-primary); border-radius: var(--r-pill);
                    padding: 8px 16px; font-size: var(--fs-sm); font-weight: 700;
                    cursor: pointer; font-family: var(--font-sans);
                    transition: border-color var(--dur-fast) var(--ease),
                                color var(--dur-fast) var(--ease); }
.entry__ex button:hover { border-color: var(--brand); color: var(--brand); }
/* One line under the controls saying what the choice above actually buys. */
.entry__note { font-size: var(--fs-caption); color: var(--text-muted);
               text-align: center; max-width: 640px; margin: 0; }
.entry__msgs { width: min(640px, 100%); display: flex; flex-direction: column;
               gap: var(--sp-2); }
.entry__msgs:empty { display: none; }

/* The picks are a page section now, not the inside of a card: the side and
   bottom padding belonged to the page card that used to wrap them, and it
   pushed this block out of line with every other section on the page. */
.nf-picks { display: flex; flex-direction: column; gap: var(--sp-4); }
.nf-picks__head { display: flex; align-items: baseline; justify-content: space-between;
                  gap: var(--sp-4); flex-wrap: wrap; }
.nf-picks__h { font-family: var(--font-display); font-weight: 800; font-size: 22px;
               color: var(--text-primary); }
/* minmax(0,1fr), not 1fr: a bare 1fr is minmax(auto,1fr), so a track refuses to
   shrink below its content and a long product title pushes the whole grid past
   the page. The niche picks have short names, which is why it only showed once
   the opportunities moved onto this grid. */
.nf-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--sp-4); }
@media (max-width: 1180px) { .nf-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 720px)  { .nf-grid { grid-template-columns: minmax(0, 1fr); } }
@media (max-width: 1100px) { .nf-grid { grid-template-columns: 1fr; } }

/* Inner card = 20px (--r-lg); 24px (--r-xl) is the page-card radius. */
.nf-card { background: var(--bg-surface); border: 1px solid var(--border-soft);
           border-radius: var(--r-lg); padding: var(--sp-6); min-width: 0;
           display: flex; flex-direction: column; gap: var(--sp-4); cursor: pointer;
           transition: box-shadow var(--dur) var(--ease), transform var(--dur) var(--ease); }
.nf-card:hover { box-shadow: 0 8px 24px rgba(90, 61, 43, .1); transform: translateY(-2px); }
.nf-card:focus-visible { outline: none; box-shadow: var(--sh-focus); }
.nf-card__top { display: flex; align-items: center; gap: var(--sp-3); min-width: 0; }
.nf-rank { width: 36px; height: 36px; border-radius: var(--r-md); flex: none;
           background: var(--marzipan); display: grid; place-items: center;
           font-family: var(--font-display); font-weight: 800; font-size: 18px;
           color: var(--text-primary); }
.nf-card__name { font-family: var(--font-display); font-weight: 700; font-size: 17px;
                 color: var(--text-primary); line-height: 1.2; }
.nf-card__path { font-size: var(--fs-caption); color: var(--text-muted); }

.nf-bar { display: flex; align-items: center; gap: 10px; }
.nf-bar__k { font-size: var(--fs-caption); font-weight: 700; color: var(--text-muted);
             width: 80px; flex: none; }
/* Inside a detail panel the axis labels carry their weight ("Buyers per offer
   · 20%"), which does not fit the 80px the card uses — they wrapped to two
   lines and pushed every bar out of alignment. */
.nd-box .nf-bar__k { width: 168px; }
/* display:block matters: these are spans, and an inline box ignores width
   and height — the bars rendered as empty tracks. */
.nf-bar__track { display: block; flex: 1; height: 8px; border-radius: var(--r-pill);
                 background: var(--track); overflow: hidden; }
.nf-bar__fill { display: block; height: 100%; border-radius: var(--r-pill);
                background: var(--bar-earn); transition: width .4s var(--ease); }
.nf-bar__fill--room { background: var(--bar-room); }
.nf-bar__v { font-size: var(--fs-sm); font-weight: 800; color: var(--text-primary);
             width: 28px; text-align: right; flex: none; }

.nf-stats { display: flex; justify-content: space-between; gap: var(--sp-3); min-width: 0;
            border-top: 1px solid var(--border-soft); padding-top: var(--sp-4); }
.nf-stat__k { font-size: 10px; font-weight: 800; color: var(--text-faint);
              letter-spacing: .08em; text-transform: uppercase; display: block; }
.nf-stat__v { font-family: var(--font-display); font-weight: 800; font-size: 18px;
              color: var(--text-primary); }

/* Card thumbnail and the product-panel thumb. The card family is shared by the
   niche picks and the product opportunities — see entityCard() in cabinet.js. */
.nf-card__thumb { width: 40px; height: 40px; flex: none; border-radius: var(--r-md);
                  background: var(--bg-app); border: 1px solid var(--border-soft);
                  object-fit: contain; padding: 3px; }
.nd-thumb { width: 96px; height: 96px; flex: none; border-radius: var(--r-md);
            background: var(--bg-app); border: 1px solid var(--border-soft);
            object-fit: contain; padding: 6px; }

/* progress ---------------------------------------------------------------- */
.nf-progress { width: min(640px, 100%); background: var(--bg-surface);
               border: 1px solid var(--border-soft); border-radius: var(--r-xl);
               padding: var(--sp-6) var(--sp-8); display: flex; flex-direction: column;
               gap: 18px; box-shadow: 0 2px 10px rgba(90, 61, 43, .05); }
.nf-progress__head { display: flex; align-items: center; gap: 14px; }
.nf-progress__title { font-family: var(--font-display); font-weight: 700; font-size: 17px;
                      color: var(--text-primary); }
.nf-progress__step { font-size: var(--fs-sm); color: var(--text-muted); }
.nf-progress__time { background: var(--brand-tint); color: var(--brand);
                     border-radius: var(--r-pill); padding: 5px 12px;
                     font-size: var(--fs-caption); font-weight: 800; flex: none; }
.nf-track { height: 8px; border-radius: var(--r-pill); background: var(--track);
            overflow: hidden; position: relative; }
.nf-track__seg { position: absolute; inset: 0 auto 0 0; width: 30%; height: 8px;
                 border-radius: var(--r-pill); background: var(--bar-earn);
                 animation: nf-slide 1.6s ease-in-out infinite; }
@keyframes nf-slide { from { transform: translateX(-100%) } to { transform: translateX(340%) } }
@media (prefers-reduced-motion: reduce) { .nf-track__seg { animation: none; width: 100% } }
.nf-steps { display: flex; flex-direction: column; gap: var(--sp-2); }
.nf-step { display: flex; align-items: center; gap: 10px;
           font-size: var(--fs-body); font-weight: 700; color: var(--text-muted); }
.nf-step__dot { width: 18px; height: 18px; border-radius: var(--r-pill); flex: none;
                border: 2px solid var(--border-strong); box-sizing: border-box;
                display: grid; place-items: center; font-size: 10px; font-weight: 900;
                line-height: 1; }
/* The strike goes on the label, not on the row: a decoration set on the row
   propagates into the dot and drew a line through the tick, which read as a
   tick sitting off-centre. */
.nf-step[data-s="done"] { color: var(--text-faint); }
.nf-step[data-s="done"] > span:last-child { text-decoration: line-through; }
.nf-step[data-s="done"] .nf-step__dot { border-color: transparent;
                background: var(--positive-soft); color: var(--positive); }
.nf-step[data-s="now"] { color: var(--brand); font-weight: 800; }
.nf-step[data-s="now"] .nf-step__dot { border-color: var(--brand); }

/* Niche detail panel (handoff view 3), rendered in the shared modal. */
.nd-head { background: var(--bg-app); padding: var(--sp-6) var(--sp-8);
           border-bottom: 1px solid var(--border-soft);
           display: flex; align-items: flex-start; justify-content: space-between;
           gap: var(--sp-6); }
.nd-title { font-family: var(--font-display); font-weight: 800; font-size: 30px;
            line-height: 1; color: var(--text-primary); }
.nd-tag { border-radius: var(--r-pill); padding: 5px 14px;
          font-size: var(--fs-caption); font-weight: 800; }
.nd-tag--cat  { background: var(--brand-tint); color: var(--brand); }
.nd-tag--acc  { background: var(--warning-soft); color: var(--warning); }
.nd-tag--win  { background: var(--bg-surface); border: 1px solid var(--border);
                color: var(--text-primary); }
.nd-score { display: flex; flex-direction: column; align-items: center; gap: 4px;
            background: var(--bg-surface); border: 1px solid var(--border-soft);
            border-radius: var(--r-lg); padding: 14px 22px; flex: none; }
.nd-score__k { font-size: 10px; font-weight: 800; color: var(--text-faint);
               letter-spacing: .08em; text-transform: uppercase; }
.nd-score__v { font-family: var(--font-display); font-weight: 800; font-size: 32px;
               line-height: 1; color: var(--brand); }
.nd-ai { background: var(--brand-tint); border-radius: var(--r-lg);
         padding: 20px 24px; display: flex; gap: 14px; align-items: flex-start; }
/* the mascot is a flex item and shrank to a dot beside a long paragraph */
.nd-ai > svg { flex: none; }
/* the product card fills the score slot only on the market card */
.nd-score:empty { display: none; }
.nd-ai p { font-size: var(--fs-body); color: var(--brand-ink); line-height: 1.65; margin: 0; }
.nd-kpi { background: var(--bg-app); border-radius: var(--r-lg); padding: 22px 24px;
          display: flex; flex-direction: column; gap: 6px; }
.nd-kpi__k { font-size: 11px; font-weight: 800; color: var(--text-muted);
             letter-spacing: .08em; text-transform: uppercase; }
.nd-kpi__v { font-family: var(--font-display); font-weight: 800; font-size: 32px;
             line-height: 1; color: var(--text-primary); }
.nd-kpi__sub { font-size: var(--fs-sm); color: var(--text-muted); }
.nd-box { border: 1px solid var(--border-soft); border-radius: var(--r-lg);
          padding: 26px 28px; display: flex; flex-direction: column; gap: 18px; }
.nd-box__h { font-family: var(--font-display); font-weight: 700; font-size: 19px;
             color: var(--text-primary); }
.nd-ladder { display: flex; align-items: center; gap: 14px; }
.nd-ladder__n { width: 34px; font-size: var(--fs-sm); font-weight: 800;
                color: var(--text-primary); flex: none; }
.nd-ladder__track { display: block; flex: 1; height: 12px; border-radius: var(--r-pill);
                    background: var(--track-soft); overflow: hidden; }
.nd-ladder__fill { display: block; height: 100%; border-radius: var(--r-pill);
                   background: var(--bar-earn); }
.nd-ladder__v { width: 74px; text-align: right; font-size: var(--fs-body);
                font-weight: 800; color: var(--text-primary); flex: none; }
.nd-row { display: grid; grid-template-columns: 1fr 90px 110px 120px 90px 90px;
          align-items: center; padding: 14px 16px; font-size: var(--fs-body);
          color: var(--text-primary); }
.nd-row--head { font-size: 11px; font-weight: 800; color: var(--text-faint);
                letter-spacing: .08em; text-transform: uppercase;
                padding: 0 16px 10px; border-bottom: 1px solid var(--border-soft); }
.nd-row + .nd-row { margin-top: 6px; }
.nd-row:not(.nd-row--head) { background: var(--bg-app); border-radius: var(--r-row); }
.nd-row > *:not(:first-child) { text-align: right; }
/* Market panel (design_handoff_similar_market, 09.09.2026): the finder's
   answer is the market of similar products. Header, KPI tiles, ladder and
   the product table reuse .nd-* and the data-table components; the rules
   below add only what the handoff draws that those do not have — the
   understanding block's inner cards, the three tinted assessment columns,
   the ladder's stat strip and the methodology note. Help sentences sit in
   title attributes on the labels, not as visible glyphs. */
.modal__panel--market { width: min(1280px, 100%); }
.nd-score__row { display: flex; align-items: baseline; gap: 4px; }
.nd-score__den { font-size: var(--fs-body); font-weight: var(--fw-black); color: var(--text-faint); }
.nd-kpi__den { font-size: var(--fs-section); color: var(--text-faint); }
.nd-kpi__row { display: flex; align-items: baseline; gap: var(--sp-2); }
.nd-kpi__k[title], .nd-score__k[title], .nd-box__h[title], .nd-ladder__stat-k[title] { cursor: help; }
.nd-box__head { display: flex; align-items: flex-start; justify-content: space-between;
                gap: var(--sp-4); flex-wrap: wrap; }
.nd-understand { background: var(--bg-app); border-color: transparent; }
.nd-understand__top { display: flex; align-items: center; gap: var(--sp-3); flex-wrap: wrap; }
.nd-understand__name { font-family: var(--font-display); font-weight: var(--fw-black); font-size: 24px;
                       line-height: 1; color: var(--text-primary); }
.nd-understand__grid { display: grid; grid-template-columns: 1fr 1fr 1.6fr; gap: var(--sp-3); }
.nd-mini { background: var(--bg-surface); border: 1px solid var(--border-soft); border-radius: var(--r-md);
           padding: var(--sp-4) var(--sp-5); display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.nd-mini__v { font-family: var(--font-display); font-weight: var(--fw-black); font-size: 26px;
              line-height: 1; color: var(--text-primary); }
.nd-mini__name { font-size: 15px; font-weight: var(--fw-black); line-height: 1.25; color: var(--text-primary); }
.nd-mini__s { font-size: var(--fs-caption); color: var(--text-muted); }
.nd-tag--muted { color: var(--text-muted); }

/* ---- opportunity read (owner brief 11.09.2026) ----------------------------
   The seven figures the verdict is built from, in one strip, and the "Why
   this opportunity?" box under them. Built from the panel's own vocabulary:
   nd-fig is nd-mini with a tone dot, the barrier rows reuse nf-bar. */
.nd-strip { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); gap: var(--sp-2); }
.nd-fig { background: var(--bg-surface); border: 1px solid var(--border-soft); border-radius: var(--r-md);
          padding: var(--sp-3) var(--sp-4); display: flex; flex-direction: column; gap: var(--sp-1);
          min-width: 0; position: relative; }
.nd-fig__k { font-size: var(--fs-micro); font-weight: var(--fw-black); color: var(--text-faint);
             letter-spacing: .06em; text-transform: uppercase; white-space: nowrap;
             overflow: hidden; text-overflow: ellipsis; }
.nd-fig__v { font-family: var(--font-display); font-weight: var(--fw-black); font-size: var(--fs-section);
             line-height: 1.1; color: var(--text-primary); white-space: nowrap; }
.nd-fig__v .nd-kpi__den { font-size: var(--fs-sm); }
/* the tone dot says which way the figure leans without recolouring the number */
.nd-fig[data-tone]::after { content: ""; position: absolute; top: var(--sp-3); right: var(--sp-3);
                            width: 8px; height: 8px; border-radius: var(--r-pill); }
.nd-fig[data-tone="pos"]::after  { background: var(--st-pos-fg); }
.nd-fig[data-tone="warn"]::after { background: var(--st-warn-fg); }
.nd-fig[data-tone="neg"]::after  { background: var(--st-neg-fg); }
.nd-fig:first-child { background: var(--brand-tint); border-color: transparent; }
.nd-fig:first-child .nd-fig__v { color: var(--brand); }
@media (max-width: 1180px) { .nd-strip { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
/* the headline strip: three tiles, the number a size up, a band word under
   it — Opportunity, Market accessibility and Competition answer the first
   three questions before anything else is read (owner brief 11.09.2026) */
.nd-strip--head { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--sp-3); }
.nd-strip--head .nd-fig { padding: var(--sp-4) var(--sp-5); }
.nd-strip--head .nd-fig__v { font-size: var(--fs-display); }
.nd-fig__s { display: block; font-family: var(--font-sans); font-size: var(--fs-caption); font-weight: var(--fw-semi);
             color: var(--text-muted); line-height: 1.35; white-space: normal; margin-top: var(--sp-1); }
.nd-strip--head .nd-fig__s { font-size: var(--fs-sm); font-weight: var(--fw-bold); color: var(--text-primary); }
/* why enter / why not: one column each, the final verdict on its own line */
.nd-why__col { display: flex; flex-direction: column; gap: var(--sp-2); min-width: 0; }
.nd-why__final { display: flex; align-items: center; gap: var(--sp-3); flex-wrap: wrap;
                 padding-top: var(--sp-3); border-top: 1px solid var(--border-soft); }
/* confidence rides on the Opportunity tile as a pill: a word about the
   data, never a fourth score card */
.nd-fig__pill { align-self: flex-start; margin-top: var(--sp-1); }
/* a fact's strength: the strong tier gets the full sign colour, the plain
   one a quieter ring — the words under the fact say which */
.nd-why__tier { font-size: var(--fs-micro); font-weight: var(--fw-black); letter-spacing: .06em;
                text-transform: uppercase; color: var(--text-faint); }
.nd-why__r[data-tier="strong"][data-tone="pos"] .nd-why__sign { background: var(--st-pos-fg); color: var(--bg-surface); }
.nd-why__r[data-tier="strong"][data-tone="neg"] .nd-why__sign { background: var(--st-neg-fg); color: var(--bg-surface); }
.nd-why__r[data-tier="strong"][data-tone="pos"] .nd-why__tier { color: var(--st-pos-fg); }
.nd-why__r[data-tier="strong"][data-tone="neg"] .nd-why__tier { color: var(--st-neg-fg); }
/* market size × accessibility: a two-by-two with one dot, beside its words.
   The halves are named on the axes, not inside the cells: the dot lands
   wherever the market's two figures put it, and a label inside a 100x60
   cell was under it more often than not (owner 13.09.2026). */
.nd-quad { display: flex; align-items: center; gap: var(--sp-5); }
.nd-quad__plot { flex: none; display: grid; grid-template-columns: auto 200px; grid-template-rows: 120px auto;
                 column-gap: var(--sp-2); row-gap: var(--sp-1); }
.nd-quad__ax { display: flex; justify-content: space-between; font-size: var(--fs-micro);
               font-weight: var(--fw-black); letter-spacing: .04em; line-height: var(--lh-micro);
               text-transform: uppercase; color: var(--text-faint); }
.nd-quad__ax--y { grid-row: 1; grid-column: 1; flex-direction: column; align-items: flex-end; }
.nd-quad__ax--x { grid-row: 2; grid-column: 2; }
.nd-quad__grid { grid-row: 1; grid-column: 2; position: relative; display: grid;
                 grid-template-columns: 1fr 1fr; grid-template-rows: 1fr 1fr; gap: 2px;
                 border-radius: var(--r-md); overflow: hidden; }
.nd-quad__cell { background: var(--bg-sunken); }
.nd-quad__cell[data-on] { background: var(--brand-tint); }
.nd-quad__dot { position: absolute; width: 14px; height: 14px; margin: 0 0 -7px -7px; border-radius: var(--r-pill);
                background: var(--brand); border: 2px solid var(--bg-surface); box-shadow: var(--sh-sm); }
.nd-quad__txt { display: flex; flex-direction: column; gap: var(--sp-1); min-width: 0; }
.nd-quad__zone { font-family: var(--font-display); font-weight: var(--fw-black); font-size: var(--fs-card); color: var(--text-primary); }

.nd-why__list { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--sp-2) var(--sp-4); }
.nd-why__r { display: flex; gap: var(--sp-2); align-items: flex-start; font-size: var(--fs-body);
             line-height: 1.45; color: var(--text-primary); }
.nd-why__sign { flex: none; width: 18px; height: 18px; border-radius: var(--r-pill); display: grid;
                place-items: center; font-weight: var(--fw-black); font-size: var(--fs-sm); margin-top: 1px; }
.nd-why__r[data-tone="pos"] .nd-why__sign { background: var(--st-pos-bg); color: var(--st-pos-fg); }
.nd-why__r[data-tone="neg"] .nd-why__sign { background: var(--st-neg-bg); color: var(--st-neg-fg); }
.nd-why__sub { font-size: var(--fs-micro); font-weight: var(--fw-black); color: var(--text-faint);
               letter-spacing: .06em; text-transform: uppercase; }
.nd-why__bar { display: flex; align-items: center; gap: var(--sp-3); }
.nd-why__k { width: 220px; flex: none; font-size: var(--fs-sm); font-weight: var(--fw-bold); color: var(--text-muted); }
.nd-why__v { width: 200px; flex: none; text-align: right; font-size: var(--fs-sm); font-weight: var(--fw-black);
             color: var(--text-primary); }
.nd-why__v .nd-kpi__den { font-size: var(--fs-caption); font-weight: var(--fw-semi); }
/* a barrier bar is filled by how much of the index sits below it, so the
   colour follows the difficulty band, not the metric */
.nf-bar__fill[data-tone="pos"]  { background: var(--st-pos-fg); }
.nf-bar__fill[data-tone="warn"] { background: var(--st-warn-fg); }
.nf-bar__fill[data-tone="neg"]  { background: var(--st-neg-fg); }

/* threshold inputs beside the sort select in a table's tool row */
.nd-assess { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--sp-4); }
.nd-assess__col { border-radius: var(--r-lg); padding: var(--sp-5) 22px; display: flex;
                  flex-direction: column; gap: var(--sp-3); min-width: 0; }
.nd-assess__col[data-tone="neg"]   { background: var(--tone-neg-bg); color: var(--tone-neg-fg);
                                     --tone: var(--st-neg-fg); --tone-h: var(--st-neg-fg); }
.nd-assess__col[data-tone="pos"]   { background: var(--tone-pos-bg); color: var(--tone-pos-fg);
                                     --tone: var(--tone-pos-icon); --tone-h: var(--st-pos-fg); }
.nd-assess__col[data-tone="brand"] { background: var(--brand-tint); color: var(--brand-ink);
                                     --tone: var(--brand); --tone-h: var(--brand); }
.nd-assess__head { display: flex; align-items: center; gap: var(--sp-2); }
.nd-assess__icon { width: 20px; height: 20px; border-radius: var(--r-pill); background: var(--tone);
                   color: var(--text-inverse); display: grid; place-items: center; flex: none;
                   font-size: var(--fs-caption); font-weight: var(--fw-black); line-height: 1; }
.nd-assess__h { font-size: var(--fs-caption); font-weight: var(--fw-black); letter-spacing: .08em;
                text-transform: uppercase; color: var(--tone-h); }
.nd-assess__item { display: flex; gap: var(--sp-2); align-items: flex-start;
                   font-size: var(--fs-sm); line-height: 1.5; }
.nd-assess__dot { width: 5px; height: 5px; border-radius: var(--r-pill); background: var(--tone);
                  flex: none; margin-top: 7px; }
.nd-assess__none { font-size: var(--fs-sm); opacity: .7; }
.nd-ladder__stats { border-top: 1px solid var(--border-soft); padding-top: var(--sp-4);
                    display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--sp-3); }
.nd-ladder__stat { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.nd-ladder__stat-k { font-size: var(--fs-micro); font-weight: var(--fw-black); letter-spacing: .08em;
                     text-transform: uppercase; color: var(--text-faint); }
.nd-ladder__stat-v { font-size: 16px; font-weight: var(--fw-black); color: var(--text-primary); }
.nd-ladder__stat-v[data-st="neg"] { color: var(--st-neg-fg); }
/* The product table is the shared data table inside the panel: it keeps
   the panel's card line instead of the page card's shadow. */
.nd-products > .dt { box-shadow: none; border: 1px solid var(--border-soft); border-radius: var(--r-lg); }
.nd-note { background: var(--bg-app); border-radius: var(--r-lg); padding: var(--sp-4) var(--sp-6);
           font-size: var(--fs-caption); color: var(--text-muted); line-height: 1.6; }
.nd-note b { color: var(--text-primary); }
@media (max-width: 860px) {
  .nd-assess, .nd-understand__grid { grid-template-columns: 1fr; }
  .nd-ladder__stats { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 860px) {
  .nd-head { flex-direction: column; }
  .nd-row { grid-template-columns: 1fr 90px; }
  .nd-row > *:nth-child(n+3) { display: none; }
}

/* ====================================================== DATA TABLE (.dt) ==
   Grid-row table from TABLE-GUIDELINES.md. No <table>: header and rows share
   one grid-template-columns set per instance, so a cell can hold a bar, a
   pill or a tree toggle and every column still lines up.
   Every data screen in the product renders through this one. The old .table
   (separated <tr> strips) is still live: the standalone finder report
   (radar/crawler/templates/finder_report.html) inlines this stylesheet and
   builds its tables with it. */
.dt { background: var(--bg-surface); border-radius: var(--r-xl); box-shadow: var(--sh-card); overflow: hidden; }

.dt__head { display: flex; align-items: flex-end; justify-content: space-between;
            gap: var(--sp-4); padding: 24px 32px 16px; }
.dt__title { font-family: var(--font-display); font-weight: var(--fw-black);
             font-size: 24px; line-height: 1.2; color: var(--text-primary); }
.dt__sub { font-size: var(--fs-sm); color: var(--text-muted); margin-top: 2px; }
.dt__tools { display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap; }
/* the category picker sits with the other table controls */
.dt-scope { display: inline-flex; align-items: center; gap: var(--sp-2); }
.dt-scope > span { font-size: var(--fs-micro); font-weight: var(--fw-black);
                   text-transform: uppercase; letter-spacing: .08em; color: var(--text-faint); }
.dt-scope .select { height: 32px; max-width: 240px; font-size: var(--fs-sm);
                    font-weight: var(--fw-bold); }

/* Sort / filter pills */
.dt-pill { display: inline-flex; align-items: center; gap: 5px; height: 30px; padding: 0 12px;
           border-radius: var(--r-pill); border: 1px solid var(--border);
           background: var(--bg-surface); color: var(--text-primary);
           font-size: var(--fs-sm); font-weight: var(--fw-bold); cursor: pointer;
           transition: border-color var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease); }
.dt-pill:hover { border-color: var(--brand); color: var(--brand); }
/* an action pill in a table head — "Rebuild now" in the admin */
.dt-pill--action { background: var(--brand); border-color: transparent; color: var(--brand-on); }
.dt-pill--action:hover { background: var(--brand-hover); border-color: transparent; color: var(--brand-on); }
.dt-pill[disabled] { opacity: .55; pointer-events: none; }

.dt-pill[aria-pressed="true"], .dt-pill.is-active {
  background: var(--brand-tint); border-color: transparent; color: var(--brand);
  font-weight: var(--fw-black);
}

/* Column headers and rows share the grid, which is set inline per instance */
.dt__cols, .dt__row { display: grid; align-items: center; gap: var(--sp-3); padding: 14px 32px; }
.dt__cols { padding-top: 0; padding-bottom: 10px; border-bottom: 1px solid var(--border-soft); }
/* max-width: a grid item with justify-self:end sizes to its content and spills
   OUTSIDE its track, so a long header ran over its neighbour instead of being
   clipped. Capping it at the track makes the ellipsis do its job. */
.dt__cols span {
  font-size: var(--fs-micro); font-weight: var(--fw-black); text-transform: uppercase;
  letter-spacing: .08em; color: var(--text-faint); white-space: nowrap;
  min-width: 0; max-width: 100%; overflow: hidden; text-overflow: ellipsis;
}
.dt__row .num { max-width: 100%; overflow: hidden; text-overflow: ellipsis; }
/* the row grid is inherited from the wrapper, so one string defines the whole
   table instead of being repeated on every row */
.dt__row { grid-template-columns: var(--dt-cols); border-bottom: 1px solid var(--track-soft); }
/* A Spy row whose offer Allegro has closed. The tint is the negative status
   ground, the same one the pills use, so the row reads as one alarm rather
   than a normal row with a red badge on it; the figures are left as they were,
   because they are the last the offer ever had. */
.dt__row[data-ended] { background: var(--st-neg-bg); }
.dt__row[data-ended] .dt__name-t { color: var(--st-neg-fg); }
.dt__row:last-child { border-bottom: 0; }
.dt__row[data-click] { cursor: pointer; }
.dt__row[data-click]:hover { background: var(--bg-row); }
.dt__row[hidden] { display: none; }

/* Scoped to rows. As `.dt .num` it also hit the header cells and beat
   `.dt__cols span` on specificity, so a numeric header rendered in the value
   colour and size — the reason CARDS / NICHES / STORE looked unlike REVENUE
   and MOMENTUM next to them. */
.dt__row .num { justify-self: end; text-align: right; font-variant-numeric: tabular-nums;
           font-size: var(--fs-body); font-weight: var(--fw-bold); color: var(--text-primary);
           white-space: nowrap; }
.dt__cols .num { justify-self: end; }
/* A column that needs explaining says so with a mark you can aim at, not just
   a cursor change on hover. */
.dt__cols .has-tip { cursor: help; }
.dt__q {
  display: inline-grid; place-items: center; margin-left: 5px;
  vertical-align: middle; position: relative; top: -1px;
  width: 13px; height: 13px; line-height: 1; border-radius: var(--r-pill);
  background: var(--track); color: var(--text-muted);
  font-style: normal; font-size: 9px; font-weight: var(--fw-black); letter-spacing: 0;
}
.dt__cols .has-tip:hover .dt__q { background: var(--brand-tint); color: var(--brand); }

/* Product preview in place of the rank number. Fixed box, contained image: the
   thumbnails come from Allegro at whatever aspect they were uploaded in. */
.dt__thumb { width: 40px; height: 40px; flex: none; border-radius: var(--r-md);
             background: var(--bg-app); border: 1px solid var(--border-soft);
             object-fit: contain; padding: 2px; display: block; }
/* keeps the action column's width when a row has no link */
.dt__go--void { display: block; }

/* Rank tile — and its spacer, so child rows keep the name column aligned */
.dt__rank, .dt__rank--void { width: 26px; height: 26px; flex: none; border-radius: 9px; }
.dt__rank { display: grid; place-items: center; background: var(--marzipan);
            font-family: var(--font-display); font-weight: var(--fw-black);
            font-size: var(--fs-sm); color: var(--text-primary); }

/* Name cell: title, optional meta line, trailing chevron */
.dt__name { display: flex; align-items: center; gap: var(--sp-3); min-width: 0; }
.dt__name-body { display: flex; flex-direction: column; min-width: 0; gap: 1px; }
.dt__name-t { font-size: var(--fs-card); font-weight: var(--fw-black); color: var(--text-primary);
              overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.dt__name-m { font-size: var(--fs-caption); font-weight: var(--fw-semi); color: var(--text-faint);
              overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* the title line can carry a mark beside the name; min-width:0 keeps the name
   itself the part that truncates, not the badge */
.dt__name-row { display: flex; align-items: center; gap: var(--sp-2); min-width: 0; }
.dt__name-row .dt__name-t { min-width: 0; }
.dt__ss {
  flex: none; display: inline-flex; align-items: center; gap: 3px;
  height: 20px; padding: 0 8px; border-radius: var(--r-pill);
  background: var(--st-pos-bg); color: var(--st-pos-fg);
  font-size: var(--fs-micro); font-weight: var(--fw-black); letter-spacing: .02em;
}
.dt__ss svg { width: 11px; height: 11px; }
.dt__chev { margin-left: auto; flex: none; color: var(--text-faint); display: inline-flex;
            transition: transform var(--dur-fast) var(--ease); }
.dt__chev svg { width: 14px; height: 14px; }
.dt__row.is-open > .dt__name .dt__chev { transform: rotate(90deg); }
.dt__chev--void { visibility: hidden; }

/* Primary metric bar: value right of the track, width relative to the column max */
.dt__bar { display: flex; align-items: center; gap: var(--sp-3); min-width: 0; }
.dt__bar-track { flex: 1 1 auto; min-width: 40px; height: 8px; border-radius: var(--r-pill);
                 background: var(--track); overflow: hidden; }
.dt__bar-fill { display: block; height: 100%; border-radius: var(--r-pill); background: var(--bar-earn); }
.dt__bar-v { flex: none; font-size: var(--fs-body); font-weight: var(--fw-black);
             font-variant-numeric: tabular-nums; color: var(--text-primary); text-align: right; }

/* Status pills (momentum) and the competition bar + label */
/* The status pill named by the table guide. It is .badge in another skin:
   both read --st-*, so a "Medium" in a table cell and a "Medium" badge in the
   admin are the same colour by construction.
   justify-self: a grid item stretches across its column whatever its display
   is, so without this the pill renders as a full-width capsule. */
.dt-pill--st { justify-self: start; display: inline-flex; align-items: center; gap: 4px;
               padding: 3px 10px; border-radius: var(--r-pill); font-size: var(--fs-caption);
               font-weight: var(--fw-black); white-space: nowrap; }
.dt-pill--st[data-st="pos"]  { background: var(--st-pos-bg);  color: var(--st-pos-fg); }
.dt-pill--st[data-st="warn"] { background: var(--st-warn-bg); color: var(--st-warn-fg); }
.dt-pill--st[data-st="neg"]  { background: var(--st-neg-bg);  color: var(--st-neg-fg); }
.dt-pill--st[data-st="flat"] { background: var(--st-flat-bg); color: var(--st-flat-fg); }

.dt__score { justify-self: start; display: flex; align-items: center; gap: var(--sp-2); }
.dt__score-track { width: 44px; height: 6px; flex: none; border-radius: var(--r-pill);
                   background: var(--track); overflow: hidden; }
.dt__score-fill { display: block; height: 100%; border-radius: var(--r-pill); background: currentColor; }
.dt__score-v { font-size: var(--fs-caption); font-weight: var(--fw-black); white-space: nowrap; }
.dt__score[data-st="pos"]  { color: var(--st-pos-fg); }
.dt__score[data-st="warn"] { color: var(--st-warn-fg); }
.dt__score[data-st="neg"]  { color: var(--st-neg-fg); }
.dt__score[data-st="flat"] { color: var(--st-flat-fg); }

/* an action button in a cell sizes to itself and sits at the right edge of its
   column, like the numbers it follows */
.dt__go { justify-self: end; }

.dt__foot { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-4);
            padding: 14px 32px 18px; }
.dt__count { font-size: var(--fs-caption); color: var(--text-faint); }
.dt__note { padding: 0 32px 18px; font-size: var(--fs-sm); color: var(--text-muted); }

/* A table whose figures are real but whose comparison is not measured yet.
   Blurred rather than hidden: the reader sees the shape of what is filling in,
   and the reason sits on top of it instead of in a footnote. The rows keep
   their place in the layout, so nothing jumps when the veil comes off. */
.dt-veil { position: relative; }
/* Only the figures go out of focus. The head keeps its title, its subtitle and
   the period switch sharp, because the switch is the way out of this state —
   blurring the control that fixes it would be a joke at the reader's expense. */
.dt-veil > .dt .dt__scroll,
.dt-veil > .dt .dt__foot { filter: blur(var(--blur-veil)); pointer-events: none;
                           user-select: none; }
.dt-veil__note { position: absolute; inset: 0; display: flex; flex-direction: column;
                 align-items: center; justify-content: center; gap: var(--sp-2);
                 padding: var(--sp-6); text-align: center; pointer-events: none; }
.dt-veil__t { font-family: var(--font-display); font-size: var(--fs-section);
              line-height: var(--lh-section); font-weight: 700;
              color: var(--text-primary); }
/* The note itself lets clicks through to nothing (the rows are inert), but a
   way in placed on it — a button for a section with no field above — must
   take them. */
.dt-veil__act { pointer-events: auto; margin-top: var(--sp-2); display: flex; gap: var(--sp-2); }
.dt-veil__s { font-size: var(--fs-sm); color: var(--text-secondary);
              max-width: 46ch; }

/* Tree rows indent the name cell only, so every other column stays on the grid */
.dt__row[data-depth="1"] .dt__name { padding-left: 24px; }
.dt__row[data-depth="2"] .dt__name { padding-left: 48px; }
.dt__row[data-depth="3"] .dt__name { padding-left: 72px; }
.dt__row[data-depth="4"] .dt__name { padding-left: 96px; }
.dt__row[data-depth="5"] .dt__name { padding-left: 120px; }

/* A cell whose content sits at the column's right edge: a figure over its
   pill, or a figure beside its refresh button. A class rather than an inline
   flex-end, so the phone layout can turn it around. */
.stack.dt__end { align-items: flex-end; }
.row.dt__end { justify-content: flex-end; }

/* Narrow screens: the grid keeps its columns and the card scrolls sideways */
.dt__scroll { overflow-x: auto; }
.dt__scroll > * { min-width: var(--dt-min, 940px); }

/* ==========================================================================
   SPY — competitor watchlist and one competitor's dossier.
   Nothing here restates the system: rows are .dt, tiles are .kpi, the dossier
   is .modal, the frequency picker is .segmented, warnings are .alert. What
   follows is only what the section genuinely adds — the entry block, the
   review columns, the image verdict and the change log.
   ========================================================================== */

/* Dossier header: thumbnail, title, the seller and delivery facts as badges. */
.spy-head { display: flex; align-items: flex-start; justify-content: space-between;
            gap: var(--sp-5); width: 100%; }
.spy-head__id { display: flex; gap: var(--sp-4); min-width: 0; }
.spy-head__tags { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); }
.spy-head__act { flex: none; display: flex; align-items: center; gap: var(--sp-2); }
/* The checking frequency is a fact about this target, not a control here —
   it reads as a small labelled value, like a KPI, and is changed from the row. */
.spy-freq-tag { display: flex; flex-direction: column; align-items: center; gap: 2px;
                border: 1px solid var(--border); border-radius: var(--r-lg);
                padding: 8px 16px; }
.spy-freq-tag b { font-family: var(--font-display); font-size: var(--fs-section);
                  font-weight: var(--fw-bold); color: var(--brand); }

/* Six compact facts across the top of the dossier. Not .kpi: these carry no
   sparkline and sit six to a row, so the padding and value size are smaller. */
/* auto-fit, not a fixed six: the rows carry six, seven or eight facts
   depending on what the card actually knows, and a fixed track leaves the last
   row ragged the moment the count changes. */
/* Tiles are read as a row of figures, so they are sized to the figures: the
   explanation moved onto the label's "?" and the tile lost the paragraph that
   made every one of them a different height. */
.spy-facts { display: grid; gap: var(--sp-2);
             grid-template-columns: repeat(auto-fit, minmax(132px, 1fr)); }
.spy-fact { background: var(--bg-app); border-radius: var(--r-md);
            padding: var(--sp-3); display: flex;
            flex-direction: column; gap: var(--sp-1); min-width: 0; }
.spy-fact__h { display: flex; align-items: center; }
.spy-fact__h.has-tip { cursor: help; }
/* The pill that explains a missing figure carries the full reason on hover,
   so it has to look askable. */
.spy-cell .dt-pill--st.has-tip { cursor: help; }
.spy-fact__h.has-tip:hover .dt__q { background: var(--brand-tint); color: var(--brand); }
.spy-fact__v { font-family: var(--font-display); font-size: var(--fs-section);
               font-weight: var(--fw-bold); color: var(--text-primary);
               line-height: var(--lh-section); }
/* The offer's own numbers are what the card is opened for; everything else is
   context around them. They get the larger step and a surface of their own so
   the eye lands there first instead of on whichever tile happens to be top left. */
.spy-facts--lead { background: var(--bg-surface); border: 1px solid var(--border);
                   border-radius: var(--r-lg); padding: var(--sp-3); }
.spy-facts--lead .spy-fact { background: var(--bg-app); }
/* Smart Pricing (handoff "Marzi Smart Pricing", 19.09.2026). What the
   handoff adds that no component had: one dominant number in a tinted,
   brand-bordered card with the current price and the median beside it; a
   distribution scale; reason tiles; a dashed simulation frame; the
   recommended column as the only display-face figure in the table. Every
   other surface of the section is .card, .segmented, .alert, .badge, .chip,
   .field, .input, .btn and the data table. Colours and sizes are tokens
   (tokens.css: --fs-hero, --brand-tint-line, --sim-line). */
.pricing-rec { font-family: var(--font-display); font-weight: var(--fw-black);
               font-size: var(--fs-section); line-height: 1; color: var(--text-primary);
               white-space: nowrap; font-variant-numeric: tabular-nums; }
.pricing-rec__d { display: block; font-family: var(--font-num); font-size: var(--fs-micro);
                  font-weight: var(--fw-black); margin-top: 2px; }
.pricing-rec__d[data-st="pos"] { color: var(--positive); }
.pricing-rec__d[data-st="neg"] { color: var(--negative); }
.pricing-rec__d[data-st="warn"] { color: var(--warning); }
/* the recommended column is the only tinted header of the table */
.dt__cols .sp-hdr-rec { color: var(--brand); }
/* the recommended card */
.sp-rec { background: var(--brand-tint); border: 2px solid var(--brand); border-radius: var(--r-lg);
          padding: var(--sp-6) var(--sp-8); display: flex; gap: var(--sp-8); align-items: center; }
.sp-rec__main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: var(--sp-2); }
.sp-rec__k { font-size: var(--fs-micro); font-weight: var(--fw-black); color: var(--brand);
             letter-spacing: var(--tracking-label); text-transform: uppercase; }
.sp-rec__v { font-family: var(--font-display); font-weight: var(--fw-black); font-size: var(--fs-hero);
             line-height: var(--lh-hero); color: var(--text-primary); letter-spacing: var(--tracking-num); }
.sp-rec__sep { width: 1px; align-self: stretch; background: var(--brand-tint-line); flex: none; }
.sp-rec__aside { width: 190px; flex: none; display: flex; flex-direction: column; gap: var(--sp-3); }
.sp-rec__mk { font-size: var(--fs-micro); font-weight: var(--fw-black); color: var(--text-secondary);
              letter-spacing: var(--tracking-label); text-transform: uppercase; }
.sp-rec__mv { font-family: var(--font-display); font-weight: var(--fw-black); font-size: var(--fs-section);
              line-height: var(--lh-section); color: var(--text-primary); }
.sp-rec__delta { background: var(--bg-surface); border: 1px solid var(--brand-tint-line); border-radius: var(--r-sm);
                 padding: var(--sp-2) var(--sp-3); font-size: var(--fs-caption); font-weight: var(--fw-black);
                 color: var(--positive); }
.sp-rec__delta[data-st="warn"] { color: var(--warning); }
.sp-rec__delta[data-st="neg"]  { color: var(--negative); }
/* a chip on the tint: white with the tint border (the strategy name) */
.badge--tint { background: var(--bg-surface); border: 1px solid var(--brand-tint-line); color: var(--brand); }
/* the reason tiles of "Why" */
.sp-why { background: var(--bg-app); border: 1px solid var(--border-soft); border-radius: var(--r-md);
          padding: var(--sp-3) var(--sp-4); display: flex; gap: var(--sp-3); align-items: flex-start;
          font-size: var(--fs-sm); line-height: 1.5; color: var(--text-primary); }
.sp-why::before { content: ""; width: 6px; height: 6px; border-radius: var(--r-pill); background: var(--brand);
                  margin-top: 7px; flex: none; }
/* the secondary rows of Market and of the simulation */
.sp-row { display: flex; align-items: baseline; justify-content: space-between; gap: var(--sp-3);
          padding: var(--sp-2) 0; border-bottom: 1px solid var(--track-soft); }
.sp-row:last-child { border-bottom: none; }
.sp-row__k { font-size: var(--fs-sm); color: var(--text-secondary); }
.sp-row__v { font-size: var(--fs-sm); font-weight: var(--fw-black); color: var(--text-primary); }
.sp-row__v[data-st="pos"] { color: var(--positive); }
.sp-row__v[data-st="neg"] { color: var(--negative); }
.sp-row__v[data-st="brand"] { color: var(--brand); }
/* a simulation is not a result: dashed frame, a badge, a line saying so */
.card.sp-sim { border: 1px dashed var(--sim-line); }
.sp-sim__note { font-size: var(--fs-caption); line-height: 1.55; font-weight: var(--fw-bold); color: var(--st-warn-fg); }
.sp-sim__price { border: 1px solid var(--border); border-radius: var(--r-md); padding: var(--sp-3) var(--sp-4);
                 display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3); }
.sp-sim__price input { font-family: var(--font-display); font-weight: var(--fw-black); font-size: var(--fs-section);
                       color: var(--text-primary); border: none; outline: none; background: transparent;
                       text-align: right; width: 150px; }
/* the two charts: scale of the market, history */
.sp-chart { width: 100%; height: auto; display: block; }   /* the viewBox sets the ratio; no letterbox on a narrow screen */
.sp-chart text { font-family: var(--font-num); font-size: 11px; font-weight: var(--fw-bold); fill: var(--text-secondary); }
.sp-chart text.brand { fill: var(--brand); font-weight: var(--fw-black); }
.sp-chart text.strong { fill: var(--text-primary); font-weight: var(--fw-black); }
.sp-chart .axis { fill: var(--track); }
.sp-chart .band { fill: var(--brand-tint-line); }
.sp-chart .band-soft { fill: var(--track-soft); }
.sp-chart .tick { stroke: var(--text-faint); stroke-width: 2; }
.sp-chart .mark { stroke: var(--text-primary); stroke-width: 2.4; }
.sp-chart .mark-muted { stroke: var(--text-secondary); stroke-width: 2.4; }
.sp-chart .mark-dash { stroke: var(--text-faint); stroke-width: 2; stroke-dasharray: 4 4; }
.sp-chart .rec { fill: var(--brand); }
.sp-chart .rec-halo { fill: none; stroke: var(--brand); stroke-width: 1.6; opacity: .4; }
.sp-chart .rec-line { stroke: var(--brand); stroke-width: 2.4; fill: none; }
.sp-chart .grid { stroke: var(--track-soft); stroke-width: 1; }
.sp-chart .grid-mid { stroke: var(--border-soft); }
.sp-chart .grid-low { stroke: var(--border); }
.sp-chart .median { stroke: var(--text-secondary); stroke-width: 2.4; fill: none; stroke-linecap: round; stroke-linejoin: round; }
.sp-chart .own { stroke: var(--text-faint); stroke-width: 2; stroke-dasharray: 6 5; fill: none; }
.sp-chart .dot-median { fill: var(--text-secondary); }
.sp-chart .dot-own { fill: var(--text-faint); }
/* the two-column detail */
.sp-grid { display: grid; grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr); gap: var(--sp-4); align-items: start; }
.sp-col { display: flex; flex-direction: column; gap: var(--sp-4); }
.sp-def { background: var(--bg-app); }
@media (max-width: 860px) {
  .sp-grid { grid-template-columns: 1fr; }
  /* the input card's head stacks: the Single / Multiple switch under the title */
  .sp-input__head { flex-direction: column; align-items: stretch; }
  .sp-input__head .segmented__btn { flex: 1; white-space: nowrap; }
  /* the charts are drawn in a 700-unit box: at 375 px their 11-unit type
     would be 6 px, so the phone sets the type in box units */
  .sp-chart text { font-size: 20px; }
  .sp-sim__price input { width: 100px; }
  .sp-rec__v { font-size: var(--fs-hero); }
  .sp-rec { flex-direction: column; align-items: stretch; gap: var(--sp-4); }
  .sp-rec__sep { width: auto; height: 1px; }
  .sp-rec__aside { width: auto; }
}
/* The lead row keeps a surface of its own, not a bigger type step: at 30px a
   four-digit price wrapped onto two lines and the tile grew to fit it. */
.spy-facts--lead .spy-fact__v { font-size: var(--fs-section); line-height: var(--lh-section); }
/* One line naming what a group of tiles is about. Without it two rows of
   numbers about two different subjects read as one long row. */
.spy-group { display: flex; align-items: baseline; gap: var(--sp-2);
             margin-bottom: var(--sp-2); }
.spy-group__h { font-family: var(--font-display); font-size: var(--fs-section);
                font-weight: var(--fw-bold); color: var(--text-primary); }
.spy-group__s { font-size: var(--fs-sm); color: var(--text-muted); }
.spy-fact__n { font-size: var(--fs-caption); font-weight: var(--fw-bold);
               color: var(--text-muted); }
.spy-fact__n[data-st="pos"]  { color: var(--positive); }
.spy-fact__n[data-st="neg"]  { color: var(--negative); }
.spy-fact__n[data-st="warn"] { color: var(--warning); }
/* How a number was arrived at, next to the number. EXACT is Allegro's own
   count; everything else was derived here and says so, because a figure whose
   provenance is invisible gets read as measured. */
.spy-fact__st { align-self: flex-start; border-radius: var(--r-pill);
                padding: 1px 7px; font-size: 10px; font-weight: var(--fw-black);
                letter-spacing: .04em; }
.spy-fact__st[data-st="EXACT"]     { background: var(--positive-soft); color: var(--positive); }
.spy-fact__st[data-st="ESTIMATED"] { background: var(--warning-soft);  color: var(--warning); }
.spy-fact__st[data-st="ANOMALY"]   { background: var(--negative-soft); color: var(--negative); }
/* An average is not a reading, and the badge says so in its own colour rather
   than borrowing the one that means "derived from what we saw". */
.spy-fact__st[data-st="AVERAGE"]   { background: var(--info-soft); color: var(--info); }
.spy-fact__st[data-st="UNAVAILABLE"],
.spy-fact__st[data-st="INSUFFICIENT_DATA"] { background: var(--bg-sunken); color: var(--text-muted); }
@media (max-width: 620px) {
  .spy-facts { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* History beside the image verdict; they stack before they squeeze. */
.spy-split { display: grid; grid-template-columns: 1.4fr 1fr; gap: var(--sp-4); }
@media (max-width: 1000px) { .spy-split { grid-template-columns: 1fr; } }
.spy-figs { display: flex; gap: var(--sp-3); border-top: 1px solid var(--border);
            padding-top: var(--sp-3); }
.spy-figs > div { flex: 1; display: flex; flex-direction: column; gap: 2px; min-width: 0; }

/* Image verdict. The score is the headline; the lines under it are what the
   analysis actually observed, each one either a fault or a confirmation. */
.spy-img { display: flex; gap: var(--sp-4); }
.spy-img__pic { width: 120px; height: 120px; flex: none; border-radius: var(--r-lg);
                background: var(--bg-sunken); object-fit: contain; }
.spy-img__list { flex: 1; display: flex; flex-direction: column; gap: var(--sp-2);
                 min-width: 0; }
.spy-check { display: flex; align-items: flex-start; gap: var(--sp-2);
             font-size: var(--fs-sm); color: var(--text-primary); line-height: 1.45; }
.spy-check__i { flex: none; width: 16px; height: 16px; margin-top: 2px;
                border-radius: var(--r-pill); display: grid; place-items: center;
                font-size: 10px; font-weight: var(--fw-black); }
.spy-check__i[data-st="warn"] { background: var(--warning-soft);  color: var(--warning); }
.spy-check__i[data-st="bad"]  { background: var(--negative-soft); color: var(--negative); }
.spy-check__i[data-st="ok"]   { background: var(--positive-soft); color: var(--positive); }
/* The one thing to do about it. Same violet as .insight, one step calmer. */
.spy-move { background: var(--brand-soft); border-radius: var(--r-md);
            padding: var(--sp-3) var(--sp-4); font-size: var(--fs-sm);
            color: var(--text-primary); line-height: 1.5; }

/* What buyers say: strengths left, weaknesses right, tinted so the two sides
   are separable at a glance without reading the headings. */
.spy-say { display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-4); }
@media (max-width: 900px) { .spy-say { grid-template-columns: 1fr; } }
.spy-side { border-radius: var(--r-lg); padding: var(--sp-5);
            display: flex; flex-direction: column; gap: var(--sp-4); }
.spy-side[data-side="pos"] { background: var(--positive-soft); }
.spy-side[data-side="neg"] { background: var(--negative-soft); }
.spy-side__h { font-size: var(--fs-caption); font-weight: var(--fw-bold);
               letter-spacing: .08em; text-transform: uppercase; }
.spy-side[data-side="pos"] .spy-side__h { color: var(--positive); }
.spy-side[data-side="neg"] .spy-side__h { color: var(--negative); }
.spy-find { display: flex; flex-direction: column; gap: 6px; }
.spy-find__top { display: flex; align-items: center; justify-content: space-between;
                 gap: var(--sp-3); }
.spy-find__t { font-size: var(--fs-body); font-weight: var(--fw-bold);
               color: var(--text-primary); }
.spy-find__n { font-size: var(--fs-caption); font-weight: var(--fw-bold);
               color: var(--text-secondary); white-space: nowrap; }
.spy-find__track { height: 6px; border-radius: var(--r-pill); overflow: hidden;
                   background: rgba(90, 61, 43, .10); }
.spy-find__fill { height: 100%; border-radius: var(--r-pill); }
.spy-side[data-side="pos"] .spy-find__fill { background: var(--positive); }
.spy-side[data-side="neg"] .spy-find__fill { background: var(--negative); }
.spy-find__q { font-size: var(--fs-caption); color: var(--text-secondary); line-height: 1.45; }
/* Impact is a computed level, so it is labelled as one and carries its basis
   in the title attribute rather than shouting it on the row. */
.spy-impact { display: inline-flex; align-items: center; border-radius: var(--r-pill);
              padding: 2px 8px; font-size: 11px; font-weight: var(--fw-black);
              letter-spacing: .04em; text-transform: uppercase; cursor: help; }
.spy-impact[data-lvl="high"]   { background: var(--text-primary); color: var(--text-inverse); }
.spy-impact[data-lvl="medium"] { background: rgba(90, 61, 43, .14); color: var(--text-primary); }
.spy-impact[data-lvl="low"]    { background: transparent; color: var(--text-muted);
                                 box-shadow: inset 0 0 0 1px var(--border); }

/* Change log: only the checks where something moved. */
.spy-log { display: flex; flex-direction: column; }
.spy-log__row { display: grid; grid-template-columns: 116px 24px 1fr 130px;
                align-items: center; gap: var(--sp-3);
                padding: var(--sp-3) 0; border-bottom: 1px solid var(--border); }
.spy-log__row:last-child { border-bottom: none; }
.spy-log__d { font-size: var(--fs-sm); font-weight: var(--fw-bold); color: var(--text-muted); }
.spy-log__i { width: 22px; height: 22px; border-radius: var(--r-pill);
              display: grid; place-items: center; font-size: 11px; font-weight: var(--fw-black); }
.spy-log__i[data-st="pos"]  { background: var(--positive-soft); color: var(--positive); }
.spy-log__i[data-st="neg"]  { background: var(--negative-soft); color: var(--negative); }
.spy-log__i[data-st="warn"] { background: var(--warning-soft);  color: var(--warning); }
.spy-log__t { font-size: var(--fs-body); color: var(--text-primary); }
.spy-log__v { text-align: right; font-size: var(--fs-sm); font-weight: var(--fw-bold);
              font-variant-numeric: tabular-nums; }
@media (max-width: 700px) {
  .spy-log__row { grid-template-columns: 24px 1fr auto; }
  .spy-log__d { display: none; }
}

/* --- watchlist row: photo, value, and what moved ------------------------- */
/* The first column is the product's own photo. A watchlist is scanned by
   recognition long before the title is read, and the row number it replaced
   ranked nothing — the rows are ordered by sales, not by that digit. */
.spy-thumb { display: block; width: 40px; height: 40px; border-radius: var(--r-sm);
             overflow: hidden; background: var(--bg-app);
             border: 1px solid var(--border); }
.spy-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.spy-thumb--void { background: var(--bg-hover); }

/* Every tracked number carries its move underneath: the level answers "where
   is it", the pill answers "what changed since the previous check", and the
   two together are what a monitoring table is for. */
.spy-cell { display: flex; flex-direction: column; gap: var(--sp-1); min-width: 0; }
.spy-cell--num { align-items: flex-end; }
.spy-cell__v { font-variant-numeric: tabular-nums; color: var(--text-primary);
               font-size: var(--fs-body); line-height: var(--lh-body); }
/* Inside the cell the pill is a label under a number, not a grid item: without
   an explicit self-alignment it stretches to the column width and reads as a
   filled bar. */
.spy-cell .dt-pill--st { justify-self: start; align-self: flex-start; }
.spy-cell--num .dt-pill--st { align-self: flex-end; }

/* The analysis of reviews and of the photo outlives the save by about a
   minute. This is what the two cards say meanwhile — a working line, not an
   empty state, because nothing has been decided yet. */

/* The photo on the bench: the real image, dimmed, with a beam travelling down
   it and a frame drawn around it. It says which picture is being looked at,
   which a spinner cannot. */
.spy-scan { position: relative; overflow: hidden; border-radius: var(--r-md);
            background: var(--bg-app); margin-bottom: var(--sp-3);
            aspect-ratio: 4 / 3; }
.spy-scan img { width: 100%; height: 100%; object-fit: contain; display: block;
                filter: saturate(.7) brightness(.96); }
.spy-scan__beam { position: absolute; left: 0; right: 0; top: 0; height: 34%;
                  background: linear-gradient(180deg,
                    transparent 0%, var(--brand-tint) 62%, var(--brand) 100%);
                  opacity: .5; animation: spy-beam 2.1s ease-in-out infinite; }
.spy-scan__frame { position: absolute; inset: var(--sp-2);
                   border: 2px solid var(--brand); border-radius: var(--r-sm);
                   opacity: .35; }
@keyframes spy-beam { 0% { transform: translateY(-100%) }
                      100% { transform: translateY(300%) } }

/* Reviews land in blocks, so the wait shows blocks landing. */
.spy-read { display: flex; flex-direction: column; gap: var(--sp-3);
            margin-bottom: var(--sp-3); }
.spy-read__row { display: flex; align-items: flex-start; gap: var(--sp-3); }
.spy-read__row .skel--circle { width: 28px; height: 28px; flex: none; }

@media (prefers-reduced-motion: reduce) {
  .spy-scan__beam { animation: none; opacity: .25; }
  .spy-read .skel { animation: none; }
}
.spy-working { display: flex; align-items: center; gap: var(--sp-2);
               color: var(--brand); font-size: var(--fs-sm);
               line-height: var(--lh-sm); font-weight: 700; }

/* Removing a target is destructive, so the control is quiet until the row is
   hovered — visible enough to find, not so loud it competes with the numbers. */
.dt__x { display: inline-flex; align-items: center; justify-content: center;
         width: 28px; height: 28px; padding: 0; border: 0; border-radius: var(--r-sm);
         background: transparent; color: var(--text-muted); cursor: pointer;
         opacity: .45; transition: opacity .15s var(--ease), background .15s var(--ease); }
.dt__row:hover .dt__x, .dt__x:focus-visible { opacity: 1; }
.dt__x:hover { background: var(--st-neg-bg); color: var(--st-neg-fg); }
.dt__x svg { width: 16px; height: 16px; fill: none; stroke: currentColor;
             stroke-width: 2; stroke-linecap: round; }
/* A pinned last column. A table wider than its card scrolls, and the drop
   control at the row's end was the first thing to leave the screen; the
   cell sticks to the scrollport's right edge and carries the row's own
   background so it never floats over the figures sliding under it. The
   negative margins let that background cover the row's padding. */
.dt__row > .dt__pin, .dt__cols > .dt__pin {
  position: sticky; right: 0; z-index: 1; display: flex; justify-content: flex-end;
  align-self: stretch; align-items: center; background: var(--bg-surface);
  margin: -14px -32px -14px calc(-1 * var(--sp-3)); padding: 0 32px 0 var(--sp-3); }
.dt__cols > .dt__pin { margin: 0 -32px -10px calc(-1 * var(--sp-3)); padding-bottom: 10px; }
.dt__row[data-click]:hover > .dt__pin { background: var(--bg-row); }

/* Pricer: a row wears the direction of its last price move (owner 11.09) —
   the status tints the whole line, the pill in the price cell says by how
   much. Same two tokens as the pills so the row and its pill agree. */
.dt__row[data-move="up"]   { background: var(--st-pos-bg); }
.dt__row[data-move="down"] { background: var(--st-neg-bg); }
/* withdrawn from sale: the amber of a warning, not the red of a price drop,
   and the thumbnail steps back so the live rows read first */
.dt__row[data-move="ended"] { background: var(--st-warn-bg); }
.dt__row[data-move="ended"] .dt__thumb { opacity: .55; }

/* Row actions on the Spy watchlist: the row itself no longer opens anything
   (owner 11.09), so the two ways in — the dossier and the day-by-day table —
   stand as buttons at the end of the row. Same geometry as the remove button
   so the three sit on one line, but always visible: a control that is the only
   way to a screen cannot wait for a hover to be found. */
.dt__acts { display: inline-flex; align-items: center; gap: var(--sp-1);
            justify-content: flex-end; }
.dt__act { display: inline-flex; align-items: center; justify-content: center;
           width: 28px; height: 28px; padding: 0; border: 0; border-radius: var(--r-sm);
           background: transparent; color: var(--text-secondary); cursor: pointer;
           transition: background .15s var(--ease), color .15s var(--ease); }
.dt__act:hover, .dt__act:focus-visible { background: var(--brand-tint); color: var(--brand); }
.dt__act svg { width: 16px; height: 16px; fill: none; stroke: currentColor;
               stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }

/* A confirmation is not a dossier: it holds two sentences and two buttons, so
   it takes a narrow panel and an action bar instead of the wide scrolling one. */
.modal__panel--ask { width: min(440px, 100%); }
/* A form dialog (Pricer's add list): wider than a question, narrower than a
   market table — a textarea of links wants room, a 1080px panel is a wall. */
.modal__panel--form { width: min(640px, 100%); }
.modal__foot { flex: none; display: flex; justify-content: flex-end; gap: var(--sp-2);
               padding: var(--sp-4) var(--sp-5) var(--sp-5); }
.spy-drop__err { margin-top: var(--sp-3); color: var(--st-neg-fg);
                 font-size: var(--fs-sm); line-height: var(--lh-sm); }

/* Department pictogram in the Categories tree (04.09): only depth-0 rows get
   one, so the icon column indents nothing on deeper levels. */
.dt__name-i { flex: none; color: var(--text-secondary); }


/* ------------------------------------------------------- ADMIN CONSOLE -- */
/* What the admin sections need that the cabinet never draws: a log viewer,
   a settings form grid, a key/value list, stage chips for a run, and the
   card an AI reading of a log or an event list comes back in. Everything
   else on those pages is the cabinet's own components. */
.logbox {
  margin: 0; padding: var(--sp-4); max-height: 560px; overflow: auto;
  background: var(--bg-sunken); color: var(--text-primary);
  border: 1px solid var(--border); border-radius: var(--r-md);
  font-family: var(--font-mono); font-size: var(--fs-caption); line-height: var(--lh-sm);
  white-space: pre-wrap; word-break: break-word; tab-size: 4;
}
.logbox--tall { max-height: 72vh; }
.logbox .is-err  { color: var(--negative); }
.logbox .is-warn { color: var(--warning); }
.logbox .is-runner { color: var(--text-brand); }
.form-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
  gap: var(--sp-4) var(--sp-5);
}
.form-grid--wide { grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); }
.form-grid .field--span { grid-column: 1 / -1; }
.kv { display: grid; grid-template-columns: max-content 1fr; gap: var(--sp-2) var(--sp-5); align-items: baseline; }
.kv__k { font-size: var(--fs-sm); color: var(--text-secondary); white-space: nowrap; }
.kv__v { font-size: var(--fs-sm); font-variant-numeric: tabular-nums; min-width: 0; word-break: break-word; }
.stages { display: flex; flex-wrap: wrap; gap: var(--sp-2); }
.stage {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  padding: 0 var(--sp-3); height: var(--h-control-sm); border-radius: var(--r-pill);
  font-size: var(--fs-sm); background: var(--bg-sunken); color: var(--text-secondary);
  border: 1px solid var(--border);
}
.stage[data-st="done"]    { background: var(--positive-soft); color: var(--positive); border-color: transparent; }
.stage[data-st="running"] { background: var(--info-soft); color: var(--info); border-color: transparent; }
.stage[data-st="failed"]  { background: var(--negative-soft); color: var(--negative); border-color: transparent; }
.stage[data-st="stopped"] { background: var(--warning-soft); color: var(--warning); border-color: transparent; }
.ai { display: flex; flex-direction: column; gap: var(--sp-4); }
.ai__summary { font-size: var(--fs-body); line-height: var(--lh-body); }
.ai__list { display: flex; flex-direction: column; gap: var(--sp-3); }
.ai__item {
  display: grid; grid-template-columns: max-content 1fr; gap: var(--sp-2) var(--sp-3);
  padding: var(--sp-3) var(--sp-4); border-radius: var(--r-md);
  background: var(--bg-sunken); border: 1px solid var(--border);
}
.ai__item-t { font-weight: var(--fw-semi); }
.ai__item-d { grid-column: 2; font-size: var(--fs-sm); color: var(--text-secondary); line-height: var(--lh-sm); }
.ai__foot { font-size: var(--fs-caption); color: var(--text-muted); }
.ev { display: flex; flex-direction: column; gap: var(--sp-1); }
.ev__row {
  display: grid; grid-template-columns: 118px 68px 80px 1fr; gap: var(--sp-3); align-items: baseline;
  padding: var(--sp-2) var(--sp-3); border-radius: var(--r-sm); font-size: var(--fs-sm);
}
.ev__row:hover { background: var(--bg-hover); }
.ev__t { font-family: var(--font-num); color: var(--text-muted); font-variant-numeric: tabular-nums; white-space: nowrap; }
.ev__d { color: var(--text-secondary); font-family: var(--font-mono); font-size: var(--fs-caption); word-break: break-word; }
.ev__row[data-level="error"] .ev__e { color: var(--negative); font-weight: var(--fw-semi); }
.ev__row[data-level="warn"]  .ev__e { color: var(--warning); font-weight: var(--fw-semi); }
.unit { display: inline-flex; align-items: center; gap: var(--sp-2); font-size: var(--fs-sm); }
.unit__dot { width: 8px; height: 8px; border-radius: 50%; background: var(--neutral); flex: none; }
.unit[data-st="active"] .unit__dot, .unit[data-st="waiting"] .unit__dot { background: var(--positive); }
.unit[data-st="activating"] .unit__dot { background: var(--info); }
.unit[data-st="failed"] .unit__dot { background: var(--negative); }
.unit[data-st="inactive"] .unit__dot { background: var(--warning); }
.toast {
  position: fixed; right: var(--sp-5); bottom: var(--sp-5); z-index: var(--z-toast);
  padding: var(--sp-3) var(--sp-4); border-radius: var(--r-md); box-shadow: var(--sh-lg);
  background: var(--bg-surface); border: 1px solid var(--border); font-size: var(--fs-sm);
  max-width: 420px;
}
.toast[data-tone="error"] { border-color: var(--negative); }
.toast[data-tone="ok"] { border-color: var(--positive); }

/* ============================================================ tooltips ==
   The `?` next to a figure used to carry a native `title`, which the browser
   shows after about a second, in its own font, wherever it likes. Two things
   replace it: a bubble that follows the mark on hover, and — when the mark is
   clicked — a glossary of every explained figure on the page.

   The bubble sits above the modal layer: a table inside a modal has explained
   columns too, and a tooltip hidden behind the panel explains nothing. */
.tip {
  position: fixed; z-index: var(--z-toast); max-width: 320px;
  padding: var(--sp-3) var(--sp-4);
  background: var(--bg-surface); color: var(--text-secondary);
  border: 1px solid var(--border); border-radius: var(--r-md);
  box-shadow: var(--sh-lg);
  font-size: var(--fs-sm); line-height: var(--lh-sm); font-weight: var(--fw-medium);
  opacity: 0; transform: translateY(4px);
  transition: opacity var(--dur-fast) var(--ease), transform var(--dur-fast) var(--ease);
  pointer-events: none;
}
.tip.is-on { opacity: 1; transform: none; }
.tip__t { display: block; margin-bottom: 4px;
          color: var(--text-primary); font-weight: var(--fw-bold); }
.tip__more { display: block; margin-top: var(--sp-2);
             color: var(--brand); font-size: var(--fs-micro);
             font-weight: var(--fw-semi); }

/* The side drawer: full height, slides in from the left. Born as the glossary
   (read against the table it explains — a centred modal would cover the very
   figures in question) and shared by the topbar bell's notifications, which
   take the --right variant since the bell sits at the right end of the topbar
   (owner 13.09: bell and theme toggle swapped places). */
.gloss { position: fixed; inset: 0; z-index: var(--z-modal); display: flex; }
.gloss__scrim { position: absolute; inset: 0; background: var(--bg-overlay);
                opacity: 0; transition: opacity var(--dur) var(--ease); }
.gloss__panel {
  position: relative; width: min(460px, 92vw); height: 100vh;
  display: flex; flex-direction: column;
  background: var(--bg-surface); border-right: 1px solid var(--border);
  box-shadow: var(--sh-lg);
  transform: translateX(-100%); transition: transform var(--dur) var(--ease);
}
.gloss--right { justify-content: flex-end; }
.gloss--right .gloss__panel { border-right: 0; border-left: 1px solid var(--border);
                              transform: translateX(100%); }
.gloss.is-on .gloss__scrim { opacity: 1; }
.gloss.is-on .gloss__panel { transform: none; }
.gloss__head { flex: none; display: flex; align-items: flex-start;
               justify-content: space-between; gap: var(--sp-4);
               padding: var(--sp-5); border-bottom: 1px solid var(--border); }
.gloss__body { flex: 1 1 auto; min-height: 0; overflow-y: auto; padding: var(--sp-5);
               display: flex; flex-direction: column; gap: var(--sp-5); }
.gloss__item { display: flex; flex-direction: column; gap: 6px; }
.gloss__term { color: var(--text-primary); font-size: var(--fs-body);
               font-weight: var(--fw-bold); }
.gloss__def  { color: var(--text-secondary); font-size: var(--fs-sm);
               line-height: var(--lh-sm); }


/* ==========================================================================
   MY PRODUCTS (owner 13.09.2026) — organic search-rank monitoring.
   Built from what exists: headBlock, tableCard, .modal, ndFig tiles, .badge,
   .segmented, .dt-pill--st for the move. What follows is only what the
   section genuinely adds: the position figure in a row, the recommendation
   checklist, the stage line of the add dialog, the tile strip that fits six.
   ========================================================================== */

/* The position in a table row: the display face, large enough to be read
   down a column; a dash in the muted colour when the offer is outside. */
.rank-pos { font-family: var(--font-display); font-size: var(--fs-card);
            font-weight: var(--fw-black); font-variant-numeric: tabular-nums;
            color: var(--text-primary); justify-self: end; }
.rank-pos--void { color: var(--text-muted); cursor: help; }
/* the card-position line under a dash: the product's card ranks, another
   seller's offer represents it */
.rank-pos__m { grid-column: 2; font-size: var(--fs-caption); color: var(--text-muted);
               justify-self: end; cursor: help; white-space: nowrap; }
.rank-busy { display: inline-flex; align-items: center; gap: var(--sp-2);
             font-size: var(--fs-sm); color: var(--brand); justify-self: end; }
.rank-fail { color: var(--negative); cursor: help; }

/* Six figures across the product page; auto-fit so a narrow window wraps
   them instead of squeezing the numbers (nd-strip is fixed at seven). */
.rank-strip { display: grid; gap: var(--sp-2);
              grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); }
.rank-strip .nd-fig:first-child { background: var(--bg-surface); border-color: var(--border-soft); }
.rank-strip .nd-fig:first-child .nd-fig__v { color: var(--text-primary); }
.rank-strip .nd-fig__v .dt-pill--st { font-size: var(--fs-sm); }

.rank-img { width: 64px; height: 64px; border-radius: var(--r-md); object-fit: cover;
            background: var(--bg-sunken); flex: none; }
.rank-preview { display: flex; gap: var(--sp-3); align-items: center;
                padding: var(--sp-3); border-radius: var(--r-md); background: var(--bg-sunken); }

/* The stage line while the offer is read and the model works: a spinner and
   the sentence naming the step — no bar, there is no total to fill. */
.rank-stage { display: flex; align-items: center; gap: var(--sp-3);
              padding: var(--sp-3) 0; color: var(--text-secondary); font-size: var(--fs-sm); }

/* The recommendation checklist: one row per search, the checkbox first, the
   type and the model's reason under the query, the relevance at the right. */
.picks { display: flex; flex-direction: column; gap: var(--sp-1); }
/* the custom-search line under the picks: field and button stay on one
   line on the phone too (the generic .row wraps there), the field gives way */
.row.picks-own { flex-wrap: nowrap; }   /* outweighs the phone's .row { wrap } below */
.picks-own .input { flex: 1 1 auto; min-width: 0; }
.picks-own .btn { flex: none; }
.pick { display: flex; align-items: center; gap: var(--sp-3);
        padding: var(--sp-2) var(--sp-3); border: 1px solid var(--border-soft);
        border-radius: var(--r-md); cursor: pointer; background: var(--bg-surface); }
.pick:hover { border-color: var(--border-strong); }
.pick input { flex: none; width: 16px; height: 16px; accent-color: var(--brand); margin: 0; }
.pick--have { opacity: .6; cursor: default; }
.pick__body { display: flex; flex-direction: column; gap: 1px; min-width: 0; flex: 1; }
.pick__q { font-weight: var(--fw-bold); color: var(--text-primary); }
.pick__m { font-size: var(--fs-caption); color: var(--text-muted);
           overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pick__s { flex: none; font-family: var(--font-num); font-size: var(--fs-sm);
           font-variant-numeric: tabular-nums; color: var(--text-secondary); cursor: help; }

.rank-chart { width: 100%; }
/* the list row's pinned cell: the state badge and the remove cross */
.dt__pin .dt__x { margin-left: var(--sp-2); }
.rank-moves { display: inline-flex; gap: var(--sp-1); }

/* ======================================================================
   MCP server (design handoff 15.09.2026). What the section adds and why
   nothing existing covered it: a three-step wizard chrome (step pills and
   a progress rail), a category accordion with a tri-state box, function
   rows with a monospace name, a sticky summary, the client picker with its
   numbered guide, a code box, catalogue chips with a state dot, and the
   billing pair. Everything else on the screens is .card, .badge,
   .segmented, .progress, .chip, the data table and the buttons.
   ====================================================================== */
.mcp-mono { font-family: var(--font-mono); font-size: var(--fs-sm); font-weight: var(--fw-bold);
            color: var(--brand-ink); white-space: nowrap; }
.mcp-code { font-family: var(--font-mono); font-size: var(--fs-sm); line-height: var(--lh-sm);
            background: var(--bg-surface); border: 1px solid var(--border-soft);
            border-radius: var(--r-md); padding: var(--sp-3) var(--sp-4);
            white-space: pre; overflow-x: auto; margin: 0; color: var(--text-primary); }

/* wizard chrome */
.mcp-wiz { background: var(--bg-surface); border-radius: var(--r-xl); box-shadow: var(--sh-md); overflow: hidden; }
.mcp-wiz__head { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-4);
                 flex-wrap: wrap; background: var(--bg-app-alt); padding: var(--sp-5) var(--sp-8);
                 border-bottom: 1px solid var(--border-soft); }
.mcp-wiz__rail { height: 4px; background: var(--track); }
.mcp-wiz__rail span { display: block; height: 100%; background: var(--bar-earn); transition: width var(--dur-slow) var(--ease); }
.mcp-wiz__title { padding: var(--sp-6) var(--sp-8) 0; display: flex; flex-direction: column; gap: var(--sp-1); }
.mcp-wiz__body { display: grid; grid-template-columns: minmax(0, 1.85fr) minmax(250px, 1fr); gap: var(--sp-5);
                 align-items: start; padding: var(--sp-5) var(--sp-8) var(--sp-8); }
.mcp-wiz__foot { display: flex; justify-content: space-between; padding: var(--sp-4) var(--sp-8);
                 border-top: 1px solid var(--border-soft); }
.mcp-steps { display: flex; gap: var(--sp-2); flex-wrap: wrap; }
.mcp-step { display: inline-flex; align-items: center; gap: var(--sp-2); border-radius: var(--r-pill);
            padding: 6px 12px 6px 6px; font-size: var(--fs-sm); font-weight: var(--fw-black);
            background: var(--bg-surface); border: 1px solid var(--border-soft); color: var(--text-muted); cursor: pointer; }
.mcp-step__dot { width: 22px; height: 22px; border-radius: 50%; display: grid; place-items: center;
                 font-size: var(--fs-caption); background: var(--track); color: var(--text-muted); }
.mcp-step[data-st="cur"]  { background: var(--brand-tint); border-color: var(--brand-soft); color: var(--brand); }
.mcp-step[data-st="cur"] .mcp-step__dot  { background: var(--brand); color: var(--brand-on); }
.mcp-step[data-st="done"] { color: var(--st-pos-fg); }
.mcp-step[data-st="done"] .mcp-step__dot { background: var(--positive); color: var(--brand-on); }

/* the category accordion and its rows */
.mcp-search { margin-bottom: var(--sp-1); }
.mcp-cat { border: 1.5px solid var(--border-soft); border-radius: var(--r-lg); overflow: hidden; }
.mcp-cat[data-on="1"] { border-color: var(--brand-soft); }
.mcp-cat__h { display: flex; align-items: center; gap: var(--sp-3); padding: var(--sp-4) var(--sp-5);
              background: var(--bg-app-alt); cursor: pointer; }
.mcp-cat[data-on="1"] .mcp-cat__h { background: var(--brand-tint); }
.mcp-cat__t { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.mcp-cat__t b { font-weight: var(--fw-black); }
.mcp-cat__t span { font-size: var(--fs-sm); color: var(--text-muted); }
.mcp-cat__chev { color: var(--text-muted); transition: transform var(--dur) var(--ease); }
.mcp-cat[data-open="1"] .mcp-cat__chev { transform: rotate(90deg); }
.mcp-cat__b { background: var(--bg-surface); }
.mcp-box { width: 20px; height: 20px; border-radius: var(--r-xs); border: 1px solid var(--border-strong);
           background: var(--bg-surface); display: grid; place-items: center; flex: none;
           font-size: var(--fs-caption); font-weight: var(--fw-black); color: var(--brand-on); cursor: pointer; padding: 0; }
.mcp-box[data-st="all"]  { background: var(--brand); border-color: var(--brand); }
.mcp-box[data-st="some"] { background: var(--accent); border-color: var(--brand); }
.mcp-fn { display: flex; align-items: baseline; gap: var(--sp-3); padding: var(--sp-3) var(--sp-5);
          border-top: 1px solid var(--track-soft); cursor: pointer; flex-wrap: wrap; }
.mcp-fn:hover { background: var(--bg-app-alt); }
.mcp-fn input { position: absolute; opacity: 0; width: 0; height: 0; }
.mcp-fn .mcp-box { align-self: center; }
.mcp-fn[data-on="0"] .mcp-mono { color: var(--text-muted); }
.mcp-fn__d { font-size: var(--fs-sm); color: var(--text-muted); }

/* the summary column */
.mcp-sum { position: sticky; top: var(--sp-5); background: var(--brand-tint); border-radius: var(--r-lg);
           padding: var(--sp-5) var(--sp-6); display: flex; flex-direction: column; gap: var(--sp-4); }
.mcp-sum__strip { display: flex; justify-content: space-between; align-items: center; gap: var(--sp-3);
                  background: var(--bg-surface); border-radius: var(--r-md); padding: var(--sp-3) var(--sp-4); }
.mcp-sum__g { display: flex; flex-direction: column; gap: 3px; }
.mcp-sum__g b { font-size: var(--fs-sm); font-weight: var(--fw-black); color: var(--brand-ink); }
.mcp-sum__f { font-family: var(--font-sans); font-size: var(--fs-sm); font-weight: var(--fw-bold);
              color: var(--brand-ink); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mcp-sum__f::before { content: ""; display: inline-block; width: 5px; height: 5px; border-radius: 50%;
                      background: var(--brand); margin-right: 8px; vertical-align: middle; }
.mcp-sum__more { font-size: var(--fs-caption); font-weight: var(--fw-black); color: var(--accent); }
.mcp-sum__caps { border-top: 1px solid var(--brand-soft); padding-top: var(--sp-4); display: flex; flex-direction: column; gap: var(--sp-2); }

/* step 2: modes, endpoint, clients, guide */
.mcp-modes { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: var(--sp-4); }
.mcp-mode { display: flex; gap: var(--sp-3); align-items: flex-start; border-radius: var(--r-lg);
            padding: var(--sp-4) var(--sp-5); background: var(--bg-app-alt); border: 1.5px solid var(--border-soft); }
.mcp-mode b { font-family: var(--font-display); font-size: var(--fs-section); }
.mcp-mode p { font-size: var(--fs-sm); color: var(--text-muted); margin: 2px 0 var(--sp-2); }
.mcp-mode[data-sel="1"] { background: var(--brand-tint); border-color: var(--brand); }
.mcp-mode[data-sel="1"] b { color: var(--brand); }
.mcp-mode[aria-disabled="true"] { opacity: .7; }
.mcp-radio { width: 18px; height: 18px; border-radius: 50%; border: 2px solid var(--border-strong); flex: none; margin-top: 4px; }
.mcp-mode[data-sel="1"] .mcp-radio { border-color: var(--brand); background: radial-gradient(circle, var(--brand) 45%, transparent 50%); }
.mcp-endpoint { background: var(--bg-app-alt); border-radius: var(--r-lg); padding: var(--sp-5) var(--sp-6);
                display: flex; flex-direction: column; gap: var(--sp-3); }
.mcp-clients { display: grid; grid-template-columns: repeat(auto-fill, minmax(170px, 1fr)); gap: var(--sp-2); }
.mcp-client { display: flex; align-items: center; gap: var(--sp-3); border-radius: var(--r-md); padding: var(--sp-3) var(--sp-4);
              background: var(--bg-surface); border: 1.5px solid var(--border-soft); cursor: pointer; text-align: left; }
.mcp-client__tile { width: 26px; height: 26px; border-radius: var(--r-sm); display: grid; place-items: center; flex: none;
                    font-family: var(--font-display); font-weight: var(--fw-black); background: var(--marzipan); color: var(--text-primary); }
.mcp-client b { font-size: var(--fs-sm); font-weight: var(--fw-black); display: block; }
.mcp-client i { font-style: normal; font-size: var(--fs-micro); font-weight: var(--fw-bold); color: var(--text-muted); }
.mcp-client[aria-pressed="true"] { background: var(--brand-tint); border-color: var(--brand); }
.mcp-client[aria-pressed="true"] .mcp-client__tile { background: var(--brand); color: var(--brand-on); }
.mcp-guide { background: var(--bg-app-alt); border-radius: var(--r-lg); padding: var(--sp-4) var(--sp-5);
             display: flex; flex-direction: column; gap: var(--sp-3); }
.mcp-guide__steps { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--sp-2); }
.mcp-guide__steps li { display: flex; gap: var(--sp-3); align-items: center; font-size: var(--fs-body); }
.mcp-guide__steps li span { width: 22px; height: 22px; border-radius: 50%; background: var(--marzipan);
                            display: grid; place-items: center; font-family: var(--font-display); font-weight: var(--fw-black);
                            font-size: var(--fs-caption); flex: none; }

/* step 3 */
.mcp-ready { display: flex; flex-direction: column; align-items: center; gap: var(--sp-5); text-align: center;
             padding: var(--sp-12) var(--sp-8) var(--sp-16); }
.mcp-ready__ok { width: 56px; height: 56px; border-radius: 50%; background: var(--st-pos-bg); color: var(--st-pos-fg);
                 display: grid; place-items: center; font-size: var(--fs-section); font-weight: var(--fw-black); }
.mcp-ready__card { background: var(--bg-app-alt); border-radius: var(--r-lg); padding: var(--sp-4) var(--sp-5);
                   min-width: 200px; display: flex; flex-direction: column; gap: var(--sp-2); align-items: flex-start; }
.mcp-ready__card b { display: inline-flex; align-items: center; gap: var(--sp-2); }
.mcp-ready__n { font-family: var(--font-display); font-size: var(--fs-page); color: var(--brand); }
.mcp-dot { display: inline-block; width: 8px; height: 8px; border-radius: 50%; background: var(--border-strong); flex: none; }
.mcp-dot--live, .mcp-ready__card .mcp-dot { background: var(--positive); animation: mcp-pulse 1.6s ease-in-out infinite; }
@keyframes mcp-pulse { 0%, 100% { opacity: 1; } 50% { opacity: .35; } }

/* dashboard */
.mcp-conn { display: flex; align-items: center; gap: var(--sp-4); flex-wrap: wrap; background: var(--bg-app-alt);
            border-radius: var(--r-lg); padding: var(--sp-4) var(--sp-5); margin-bottom: var(--sp-4); }
.mcp-kpis { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: var(--sp-4); margin-bottom: var(--sp-4); }
.mcp-kpi { background: var(--bg-app-alt); border-radius: var(--r-lg); padding: var(--sp-5) var(--sp-5);
           display: flex; flex-direction: column; gap: var(--sp-2); }
.mcp-kpi > b { font-family: var(--font-display); font-size: var(--fs-page); line-height: var(--lh-page); }
.mcp-charts { display: grid; grid-template-columns: minmax(0, 1.6fr) minmax(280px, 1fr); gap: var(--sp-4); margin-bottom: var(--sp-4); }
.mcp-tr { display: grid; grid-template-columns: 1fr auto; gap: var(--sp-1) var(--sp-3); align-items: center; padding: var(--sp-2) 0; }
.mcp-tr .progress { grid-column: 1 / -1; }
.mcp-catgrid { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: var(--sp-3); }
.mcp-catpanel { background: var(--bg-app-alt); border-radius: var(--r-lg); padding: var(--sp-4); display: flex; flex-direction: column; gap: var(--sp-3); }
.mcp-chip { display: inline-flex; align-items: center; gap: 6px; border-radius: var(--r-pill); padding: 4px 10px;
            font-family: var(--font-mono); font-size: var(--fs-caption); font-weight: var(--fw-bold);
            background: var(--bg-surface); border: 1px solid var(--border-soft); color: var(--text-muted); cursor: pointer; }
.mcp-chip[data-on="1"] { background: var(--brand-tint); border-color: var(--brand-soft); color: var(--brand-ink); }
.mcp-chip[data-on="1"] .mcp-dot { background: var(--brand); }
.mcp-billing { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.3fr); gap: var(--sp-4); margin: var(--sp-4) 0; }
.mcp-bill { background: var(--brand-tint); border-radius: var(--r-lg); padding: var(--sp-5) var(--sp-6);
            display: flex; flex-direction: column; gap: var(--sp-3); }
.mcp-bill__v { font-family: var(--font-display); font-size: var(--fs-page); line-height: var(--lh-page); color: var(--brand); }
.mcp-hist { display: flex; flex-direction: column; }
.mcp-hist__h, .mcp-hist__r { display: grid; grid-template-columns: minmax(120px, 1fr) 76px 82px 82px; gap: var(--sp-3); align-items: center; }
.mcp-hist__h { font-size: var(--fs-micro); font-weight: var(--fw-black); text-transform: uppercase; letter-spacing: var(--tracking-label);
               color: var(--text-muted); padding: var(--sp-2) 0; border-bottom: 1px solid var(--border-soft); }
.mcp-hist__r { padding: var(--sp-3) 0; border-bottom: 1px solid var(--track-soft); font-size: var(--fs-sm); font-weight: var(--fw-bold); }
.mcp-hist__h span:not(:first-child), .mcp-hist__r span:not(:first-child) { text-align: right; justify-self: end; }
.mcp-note { background: var(--bg-app-alt); border-radius: var(--r-lg); padding: var(--sp-4) var(--sp-6);
            font-size: var(--fs-caption); color: var(--text-muted); line-height: 1.6; }
.mcp-note b { color: var(--text-primary); }
@media (max-width: 900px) {
  .mcp-wiz__body, .mcp-charts, .mcp-billing { grid-template-columns: 1fr; }
  .mcp-sum { position: static; }
}

/* the money strip of the MCP dashboard (0058): balance gauge and daily cap */
.mcp-money { display: grid; grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); gap: var(--sp-4); margin-bottom: var(--sp-4); }
.mcp-money__card { background: var(--brand-tint); border-radius: var(--r-lg); padding: var(--sp-5) var(--sp-6);
                   display: flex; flex-direction: column; gap: var(--sp-3); }
.mcp-notice:empty { display: none; }
.mcp-notice { margin-bottom: var(--sp-3); }

/* function rows read as abilities: the plain name, its one-line meaning,
   and the id in small type for whoever needs it */
.mcp-fn__t { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.mcp-fn__t b { font-weight: var(--fw-black); color: var(--brand-ink); }
.mcp-fn[data-on="0"] .mcp-fn__t b { color: var(--text-muted); }
.mcp-fn__id { font-family: var(--font-mono); font-size: var(--fs-micro); color: var(--text-muted); }
.mcp-chip { font-family: var(--font-sans); }
.mcp-sum__presets { display: flex; flex-direction: column; gap: var(--sp-2); }

/* the block's own explanation at the top of its expanded card */
.mcp-cat__about { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: var(--sp-4);
                  padding: var(--sp-4) var(--sp-5); border-top: 1px solid var(--track-soft); background: var(--bg-app-alt); }
.mcp-cat__about b { display: block; font-size: var(--fs-micro); font-weight: var(--fw-black); text-transform: uppercase;
                    letter-spacing: var(--tracking-label); color: var(--text-muted); margin-bottom: 4px; }
.mcp-cat__about p { margin: 0; font-size: var(--fs-sm); line-height: var(--lh-sm); color: var(--text-secondary); }
.mcp-fn__ex { font-size: var(--fs-caption); color: var(--text-muted); }
.mcp-fn__ex i { color: var(--brand-ink); font-style: normal; }

/* ------------------------------------------------------------ plans --
   Plans, the trial and billing — handoff "Marzi Plans and Billing"
   (17.09.2026, TZ_BILLING_UI.md). New here and nowhere else: the two gate
   panels (a tinted head with the mascot, a full-width CTA), the plan card
   as a component (.plan with accent / current variants and a limits list),
   the pill period toggle, the invoices grid and the sidebar plan line.
   Colours, radii, type and shadows are the cabinet's tokens; the
   handoff's hex values map onto them one to one. */

/* the gate: the .modal that cannot be dismissed. The plan gate leaves the
   sidebar out from under the scrim so "Sign out" stays reachable; the
   welcome gate covers the page. */
.modal--gate[data-side="expanded"] { left: var(--w-sidebar); }
.modal--gate[data-side="collapsed"] { left: var(--w-sidebar-collapsed); }
@media (max-width: 1024px) { .modal--gate[data-side] { left: 0; } }
.modal__panel--gate { width: min(960px, 100%); padding: 0; gap: 0; border-radius: var(--r-xl); box-shadow: var(--sh-lg); overflow: hidden; }
.modal__panel--welcome { width: min(720px, 100%); }
.gate__head { flex: none; display: flex; align-items: flex-start; gap: var(--sp-5);
  padding: var(--sp-8) var(--sp-8) var(--sp-6); background: var(--bg-app); border-bottom: 1px solid var(--border-soft); }
.gate__head--stack { flex-direction: column; gap: var(--sp-4); }
.gate__mascot { flex: none; width: calc(var(--sp-12) * 2); height: calc(var(--sp-12) * 2); }
.gate__t { font-family: var(--font-display); font-size: var(--fs-page); line-height: var(--lh-page); font-weight: var(--fw-black); }
.gate__p { font-size: var(--fs-card); line-height: var(--lh-card); color: var(--text-secondary); max-width: 72ch; margin-top: var(--sp-2); }
.gate__body { padding: var(--sp-6) var(--sp-8) 0; overflow: auto; }
.gate__foot { flex: none; display: flex; flex-direction: column; gap: var(--sp-3); padding: var(--sp-5) var(--sp-8) var(--sp-8); }
.gate__foot--row { flex-direction: row; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: var(--sp-4); padding-top: var(--sp-4); }
.gate__note { font-size: var(--fs-caption); color: var(--text-faint); text-align: center; }
.gate__line { font-size: var(--fs-sm); color: var(--text-secondary); }
.gate__line a { font-weight: var(--fw-black); text-decoration: none; }
.gate__by { font-size: var(--fs-caption); color: var(--text-faint); }
.gate__msg:empty { display: none; }
.gate__msg { margin-bottom: var(--sp-4); }
.btn--gate { width: 100%; height: auto; padding: var(--sp-4) var(--sp-6); border-radius: var(--r-lg); font-size: var(--fs-card); font-weight: var(--fw-black); }

/* the pill toggle of the period: the handoff's rounded variant of .segmented */
.segmented--pill { border-radius: var(--r-pill); padding: var(--sp-1); border: none; background: var(--bg-sunken); }
.segmented--pill .segmented__btn { border-radius: var(--r-pill); height: auto; padding: var(--sp-2) var(--sp-4); font-weight: var(--fw-bold); }
.segmented--pill .segmented__btn[aria-pressed="true"] { color: var(--brand); font-weight: var(--fw-black); box-shadow: var(--sh-sm); }

/* the trial card in the welcome gate: one card, limits in two columns */
.trialcard { border: 1px solid var(--border); border-radius: var(--r-lg); overflow: hidden; }
.trialcard__head { display: flex; align-items: baseline; justify-content: space-between; gap: var(--sp-4);
  padding: var(--sp-4) var(--card-pad); border-bottom: 1px solid var(--border-soft); }
.trialcard__price { font-family: var(--font-display); font-size: var(--fs-section); font-weight: var(--fw-black); color: var(--brand); white-space: nowrap; }
.trialcard .plan__list { padding: var(--sp-2) var(--card-pad) var(--sp-4); display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0 var(--sp-6); }
@media (max-width: 640px) { .trialcard .plan__list { grid-template-columns: 1fr; } }

/* the plan card */
.plans { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--sp-4); }
@media (max-width: 860px) { .plans { grid-template-columns: 1fr; } }
.plan { display: flex; flex-direction: column; gap: var(--sp-4); padding: var(--card-pad) var(--sp-5);
  background: var(--bg-surface); border: 1px solid var(--border); border-radius: var(--r-lg);
  transition: box-shadow var(--dur-fast) var(--ease); }
.plan:hover { box-shadow: var(--sh-md); }
.plan--accent { background: var(--brand-tint); border-color: var(--brand-soft); }
.plan--current { border: 2px solid var(--brand); background: var(--brand-tint); padding: calc(var(--card-pad) - 1px) calc(var(--sp-5) - 1px); }
.plan__top { display: flex; flex-direction: column; gap: 3px; }
.plan__name { display: flex; align-items: center; gap: var(--sp-2); font-family: var(--font-display); font-size: var(--fs-section); line-height: var(--lh-section); font-weight: var(--fw-black); }
.plan__tag { font-size: var(--fs-sm); color: var(--text-secondary); }
.plan__price { display: flex; flex-direction: column; gap: 2px; }
.plan__amount { font-family: var(--font-display); font-size: var(--fs-display); line-height: 1; font-weight: var(--fw-black); }
.plan__per { font-size: var(--fs-caption); font-weight: var(--fw-bold); color: var(--text-faint); }
.plan--accent .plan__per, .plan--current .plan__per { color: var(--text-secondary); }
.plan__list { display: flex; flex-direction: column; margin: 0; padding: 0; list-style: none; }
.plan__list li { display: flex; align-items: baseline; justify-content: space-between; gap: var(--sp-3);
  padding: 7px 0; border-bottom: 1px solid var(--border-soft); font-size: var(--fs-sm); }
.plan__list li span { font-weight: var(--fw-semi); color: var(--text-secondary); }
.plan__list li b { font-weight: var(--fw-black); color: var(--text-primary); text-align: right; }
.plan__cta { margin-top: auto; height: auto; padding: var(--sp-3) var(--sp-5); border-radius: var(--r-row); font-size: var(--fs-body); font-weight: var(--fw-black); }
.plan__cta.btn--secondary { color: var(--brand); }
.plan__cta.btn--secondary:hover { border-color: var(--brand); }
.plan__cta--own { margin-top: auto; padding: var(--sp-3) var(--sp-5); border-radius: var(--r-row); border: 1px dashed var(--brand-soft);
  background: var(--bg-surface); color: var(--brand); font-size: var(--fs-body); font-weight: var(--fw-black); text-align: center; }
.badge--solid { background: var(--brand); color: var(--brand-on); letter-spacing: var(--tracking-label); text-transform: uppercase; }
.badge--outline { background: var(--bg-surface); color: var(--brand); border: 1px solid var(--brand-soft); letter-spacing: var(--tracking-label); text-transform: uppercase; }

/* Settings → Plan and billing: the strip of what the plan gives and what is
   used of it. The first tile names the plan and its state (brand tint),
   the rest are meters — used of max with a thin bar that turns warm at
   80 % and warning when full; a limit without ceiling shows a dashed bar. */
.usage { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: var(--sp-3); }
.usage__tile { display: flex; flex-direction: column; gap: var(--sp-2); padding: var(--sp-4) var(--sp-4) var(--sp-3);
  background: var(--bg-surface); border: 1px solid var(--border-soft); border-radius: var(--r-lg); min-width: 0; }
.usage__tile--plan { background: var(--brand-tint); border-color: transparent; }
.usage__k { font-size: var(--fs-micro); font-weight: var(--fw-black); letter-spacing: var(--tracking-label); text-transform: uppercase; color: var(--text-faint); }
.usage__v { font-family: var(--font-display); font-size: var(--fs-section); line-height: var(--lh-section); font-weight: var(--fw-black); font-variant-numeric: tabular-nums; }
.usage__v small { font-family: var(--font-sans); font-size: var(--fs-sm); font-weight: var(--fw-semi); color: var(--text-secondary); }
.usage__tile--plan .usage__v { color: var(--brand); }
.usage__s { font-size: var(--fs-caption); color: var(--text-secondary); min-height: var(--lh-caption); }
.usage__s--warn { color: var(--st-warn-fg); font-weight: var(--fw-bold); }
.usage .progress { margin-top: auto; }
.usage .progress--none { background: repeating-linear-gradient(90deg, var(--border) 0, var(--border) 6px, transparent 6px, transparent 10px); }
.usage .progress__fill[data-tone="warm"] { background: var(--st-warn-fg); }
.usage .progress__fill[data-tone="full"] { background: var(--st-neg-fg); }

/* Settings → Plan and billing */
.billing__head { display: flex; align-items: flex-end; justify-content: space-between; gap: var(--sp-5); flex-wrap: wrap; }
.billing__status { font-size: var(--fs-sm); font-weight: var(--fw-bold); color: var(--text-secondary); }
.billing__status--warn { color: var(--st-warn-fg); }
.billing__actions { display: flex; gap: var(--sp-2); flex-wrap: wrap; }
.billing__row { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-4); flex-wrap: wrap; }
.billing__hint { font-size: var(--fs-caption); color: var(--text-faint); }
.note { padding: var(--sp-3) var(--sp-4); border-radius: var(--r-row); font-size: var(--fs-sm); font-weight: var(--fw-black); border: 1px solid transparent; }
.note--positive { background: var(--st-pos-bg); color: var(--st-pos-fg); }
.note--warning { background: var(--st-warn-bg); color: var(--st-warn-fg); }
.note--neutral { background: var(--st-flat-bg); color: var(--st-flat-fg); }

.invoices { border: 1px solid var(--border-soft); border-radius: var(--r-lg); overflow: hidden; }
.invoices__head { padding: var(--sp-4) var(--card-pad) var(--sp-3); display: flex; flex-direction: column; gap: 3px; }
.invoices__t { font-family: var(--font-display); font-size: var(--fs-section); font-weight: var(--fw-black); }
.invoices__s { font-size: var(--fs-caption); color: var(--text-secondary); }
.invoices__row { display: grid; grid-template-columns: minmax(0, 1.4fr) minmax(0, 2fr) minmax(0, 1fr) minmax(0, 1fr); align-items: center; gap: var(--sp-3);
  padding: var(--sp-3) var(--card-pad); border-bottom: 1px solid var(--border-soft); font-size: var(--fs-sm); }
.invoices__row:last-child { border-bottom: 0; }
.invoices__row:hover { background: var(--bg-app); }
/* the month heading over its invoices: label left, what the month paid right */
.invoices__month { display: flex; align-items: baseline; justify-content: space-between; gap: var(--sp-3);
  padding: var(--sp-3) var(--card-pad) var(--sp-2); background: var(--bg-app); border-bottom: 1px solid var(--border-soft);
  font-family: var(--font-display); font-size: var(--fs-card); font-weight: var(--fw-black); }
.invoices__month-sum { font-family: var(--font-sans); font-size: var(--fs-caption); font-weight: var(--fw-bold); color: var(--text-secondary); }
.invoices__row--h { font-size: var(--fs-micro); font-weight: var(--fw-black); color: var(--text-faint); letter-spacing: var(--tracking-label); text-transform: uppercase; }
.invoices__row--h:hover { background: transparent; }
.invoices__row > :nth-child(3), .invoices__row > :nth-child(4) { text-align: right; }
.invoices__row > :nth-child(4) { display: flex; justify-content: flex-end; }
.invoices__n { font-weight: var(--fw-black); text-decoration: none; }
.invoices__period { font-weight: var(--fw-semi); color: var(--text-secondary); }
.invoices__amount { font-weight: var(--fw-black); }
.invoices__empty { padding: var(--sp-8) var(--card-pad); display: flex; flex-direction: column; align-items: center; gap: var(--sp-2); text-align: center; }
.invoices__empty-mark { width: var(--sp-12); height: var(--sp-12); border-radius: var(--r-row); border: 1px dashed var(--border); background: var(--bg-app); }
.invoices__empty-t { font-family: var(--font-display); font-size: var(--fs-card); font-weight: var(--fw-black); }
.invoices__empty-s { font-size: var(--fs-sm); color: var(--text-secondary); max-width: 40ch; }

/* the plan line under the e-mail in the sidebar foot, and the dot on the
   avatar when the rail is collapsed */
.entity__meta[data-plan="trial"] { color: var(--brand); font-weight: var(--fw-black); }
.entity__meta[data-plan="live"] { color: var(--st-pos-fg); font-weight: var(--fw-black); }
.entity__meta[data-plan="warn"] { color: var(--st-warn-fg); font-weight: var(--fw-black); }
.entity__meta[data-plan="none"] { color: var(--text-muted); font-weight: var(--fw-bold); }
.sidebar__foot .avatar { position: relative; }
.sidebar__foot .avatar[data-dot] { overflow: visible; }
.sidebar__foot .avatar[data-dot]::after { content: ""; position: absolute; right: -2px; bottom: -2px; width: var(--sp-3); height: var(--sp-3);
  border-radius: var(--r-pill); border: 2px solid var(--bg-nav); background: var(--st-pos-fg); display: none; }
.sidebar__foot .avatar[data-dot="warn"]::after { background: var(--st-warn-fg); }
.app[data-sidebar="collapsed"] .sidebar__foot .avatar[data-dot]::after { display: block; }

/* AI Integration without access, and the paused band in the trackers */
.lockcard { display: flex; align-items: flex-start; gap: var(--sp-4); padding: var(--sp-5) var(--card-pad); border-radius: var(--r-lg);
  background: var(--bg-app); border: 1px solid var(--border-soft); }
.lockcard__i { flex: none; width: var(--sp-10); height: var(--sp-10); border-radius: var(--r-md); display: grid; place-items: center;
  background: var(--brand-tint); color: var(--brand); }
.lockcard__body { display: flex; flex-direction: column; gap: var(--sp-4); align-items: flex-start; }
.lockcard__t { font-size: var(--fs-card); font-weight: var(--fw-black); line-height: var(--lh-card); }
.paused { padding: var(--sp-3) var(--sp-4); border-radius: var(--r-row); font-size: var(--fs-sm); font-weight: var(--fw-black);
  background: var(--st-warn-bg); color: var(--st-warn-fg); border: 1px solid transparent; margin-bottom: var(--sp-4); }

/* Support (17.09.2026). The thread is the assistant's chat (.chat__log,
   .chat__msg--user, .chat__group / .chat__msg--bot) and the composer is the
   same .entry__form; what this block adds is what a helpdesk thread has and
   a chat with a model does not: a line under each bubble saying who wrote
   it, through which door and when; the original text behind a translated
   answer; the files a message carries; and a multi-line field in the entry
   bar, since a support message is a paragraph, not a query. */
.sup-thread .chat__log { width: min(760px, 100%); margin-inline: 0; padding-top: var(--sp-2); }
.sup-thread .chat__group { max-width: 100%; }
.sup-thread .chat__msg--user { max-width: 86%; }
.sup-thread .chat__msg--bot { white-space: pre-wrap; }
.sup-thread .chat__msg--user { white-space: pre-wrap; }
.sup-meta { display: flex; align-items: center; gap: var(--sp-2); font-size: var(--fs-caption); color: var(--text-muted); flex-wrap: wrap; }
.sup-meta--user { align-self: flex-end; }
.sup-meta b { color: var(--text-secondary); font-weight: var(--fw-bold); }
.sup-orig { font-size: var(--fs-sm); color: var(--text-secondary); }
.sup-orig summary { cursor: pointer; color: var(--text-brand); font-weight: var(--fw-semi); list-style: none; }
.sup-orig summary::-webkit-details-marker { display: none; }
.sup-orig[open] summary { margin-bottom: var(--sp-2); }
.sup-orig p { white-space: pre-wrap; margin: 0; }
.sup-files { display: flex; flex-wrap: wrap; gap: var(--sp-2); }
.sup-files .chip { text-decoration: none; }
.sup-files .chip .i-sm { width: 14px; height: 14px; }
.sup-compose { width: min(760px, 100%); display: flex; flex-direction: column; gap: var(--sp-3); align-items: flex-start; }
.sup-compose .entry__form { width: 100%; align-items: center; }
.entry__form textarea { flex: 1; min-width: 0; border: none; outline: none; background: transparent; resize: none;
  font-family: var(--font-sans); font-size: var(--fs-body); font-weight: var(--fw-semi); color: var(--text-primary);
  line-height: var(--lh-body); padding: var(--sp-2) 0; max-height: 240px; }
.entry__form textarea::placeholder { color: var(--text-muted); font-weight: var(--fw-semi); }
.entry__form textarea:focus-visible { box-shadow: none; }
.sup-compose__row { display: flex; align-items: center; gap: var(--sp-3); flex-wrap: wrap; width: 100%; }
.sup-compose__row .btn { flex: none; }
.sup-compose__row input[type="file"] { display: none; }
/* the list: an unread thread reads like unread mail */
.dt__row[data-unread] .dt__name-t { font-weight: var(--fw-black); }
.sup-count { display: inline-flex; align-items: center; justify-content: center; min-width: var(--sp-5); height: var(--sp-5);
  padding: 0 var(--sp-2); border-radius: var(--r-pill); background: var(--brand); color: var(--brand-on);
  font-size: var(--fs-micro); font-weight: var(--fw-black); margin-left: var(--sp-2); }
.sup-status { display: inline-flex; align-items: center; gap: var(--sp-2); }

/* ==========================================================================
   PHONE — everything under 860px that is not a table row or the drawer
   (those sit with their components). One block, so the phone layout can
   be read in one place: the section head stacks and its field takes the
   width, the entry block and its bar lose the desktop air, KPI strips fold
   to two tiles, modals become sheets. No new colours or sizes: tokens only.
   ========================================================================== */
@media (max-width: 860px) {
  /* section head: crumb, title, lead, then the field or button full width */
  .page-head { flex-direction: column; gap: var(--sp-4); }
  .page-head__actions { width: 100%; flex-wrap: wrap; }
  .page-head__actions .search { width: 100%; }
  .search { width: 100%; max-width: none; }
  /* the topbar: the pills keep their labels, the gaps shrink */
  .topbar { gap: var(--sp-2); }
  .topbar__actions { gap: var(--sp-1); }
  /* the entry block (finder, spy, pricer, rank): the card loses its
     desktop air, the bar keeps input and button on one line but stops
     spending 24px on the left before the first letter */
  .entry { padding: var(--sp-6) var(--sp-4); gap: var(--sp-5); }
  .entry__form { padding: var(--sp-1); padding-left: var(--sp-3); gap: var(--sp-2); }
  .entry__go { padding: var(--sp-3) var(--sp-4); }
  /* row cells that right-align on the desktop grid read left on a card */
  .dt__row > .dt__end, .dt__row > .spy-cell--num { align-items: flex-start; }
  .dt__row .dt__end { align-items: flex-start; justify-content: flex-start; }
  .dt__row > .row.dt__end, .dt__row > .row { flex-direction: row; flex-wrap: wrap; align-items: center; }
  .dt__row > .row::before { flex: 1 0 100%; }
  .spy-cell--num .dt-pill--st { align-self: flex-start; }
  /* a pill that carries a sentence wraps instead of leaving the card */
  .dt__row .dt-pill--st { white-space: normal; max-width: 100%; }
  /* the title cell: two lines instead of an ellipsis after twelve letters,
     and the marks beside it wrap under it */
  .dt__row .dt__name-t { white-space: normal; display: -webkit-box; -webkit-line-clamp: 2;
                         -webkit-box-orient: vertical; }
  .dt__row .dt__name-row { flex-wrap: wrap; }
  /* a generic row of controls wraps rather than leaving the screen */
  .row { flex-wrap: wrap; }
  /* AI Integration: the wizard and the dashboard lose the wide padding; the
     billing history keeps four columns by letting the figures size themselves */
  .mcp-wiz__head, .mcp-wiz__title, .mcp-wiz__body, .mcp-wiz__foot {
    padding-left: var(--sp-4); padding-right: var(--sp-4); }
  .mcp-wiz__body { padding-bottom: var(--sp-5); }
  .mcp-conn { padding: var(--sp-4); }
  .mcp-money { grid-template-columns: minmax(0, 1fr); }
  .mcp-money__card, .mcp-bill { padding: var(--sp-4); }
  .mcp-hist__h, .mcp-hist__r { grid-template-columns: minmax(0, 1fr) auto auto auto; gap: var(--sp-2); }
  /* the dossier head (Spy target, Keyword Tracker product): identity first,
     the action buttons on their own line under it */
  .spy-head { flex-wrap: wrap; gap: var(--sp-4); }
  .spy-head__id { flex: 1 1 100%; }
  .spy-head__act { width: 100%; flex-wrap: wrap; }
  .spy-head__act .btn { flex: 1 1 auto; justify-content: center; }
  /* a dossier group's heading and its one-line explanation stack */
  .spy-group { flex-direction: column; align-items: flex-start; gap: var(--sp-1); }
  /* the niche dossier: the head loses the wide padding and the title the
     30px that wrapped to four lines; the seven-figure strip goes two a line,
     the three-figure head strip one a line */
  .nd-head { padding: var(--sp-5) var(--sp-4); }
  .nd-title { font-size: var(--fs-display); line-height: var(--lh-display); }
  .nd-strip { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .nd-strip--head { grid-template-columns: minmax(0, 1fr); }
  .gloss__panel { height: 100dvh; }
  /* the finder's market card: the quadrant map above its reading, why-enter
     and why-not one under the other, a barrier bar as label / track / value
     on two lines instead of three fixed columns */
  .nd-quad { flex-direction: column; align-items: flex-start; }
  .nd-quad__plot { grid-template-columns: auto minmax(0, 1fr); width: 100%; }
  .nd-why__list { grid-template-columns: minmax(0, 1fr); }
  .nd-why__bar { flex-wrap: wrap; row-gap: var(--sp-1); }
  .nd-why__k { width: auto; flex: 1 1 auto; }
  .nd-why__v { width: auto; flex: 0 1 auto; text-align: right; }
  .nd-why__bar .nf-bar__track { flex: 1 0 100%; order: 1; }
  .nd-kpi { padding: var(--sp-4); }
  .nd-fig__k { white-space: normal; }
  /* the veil shows the shape of the list; two stand-in cards are enough */
  .dt-veil .dt__row:nth-child(n+3) { display: none; }
  /* modals: a sheet from the bottom, full width, its own scroll */
  .modal { padding: 0; place-items: end center; }
  .modal__panel { width: 100%; max-width: none; max-height: 96dvh; border-radius: var(--r-xl) var(--r-xl) 0 0; }
}

/* --- the phone: a row is a card, not a line ------------------------------
   A 940px grid on a 375px screen is a strip that scrolls sideways past every
   figure; here the header row goes and each row wraps: the title cell (the
   free column, dt__rows--p<n> from cabinet.js) takes the first line beside a
   leading thumbnail, the figures follow two to a line, each captioned by its
   column name (--l<n> on .dt__rows, copied into --l per cell), and the row's
   action buttons close the card on the right. Bars, scores and status pills
   keep their skins; the pill only grows room for its caption. */
@media (max-width: 860px) {
  .dt__head { padding: var(--sp-5) var(--sp-4) var(--sp-3); flex-wrap: wrap; align-items: flex-start; }
  .dt__cols { display: none; }
  .dt__scroll > * { min-width: 0; }
  .dt__row { display: flex; flex-wrap: wrap; align-items: center;
             gap: var(--sp-3) var(--sp-4); padding: var(--sp-4); }
  .dt__row > * { --l: ""; flex: 1 1 calc(50% - var(--sp-4)); min-width: 0;
                 display: flex; flex-direction: column; align-items: flex-start; gap: 2px;
                 justify-self: auto; text-align: left; }
  .dt__row > *::before { content: var(--l); font-size: var(--fs-micro); line-height: var(--lh-micro);
                         font-weight: var(--fw-black); text-transform: uppercase; letter-spacing: .08em;
                         color: var(--text-faint); white-space: nowrap; }
  .dt__row > :nth-child(1)  { --l: var(--l1, ""); }
  .dt__row > :nth-child(2)  { --l: var(--l2, ""); }
  .dt__row > :nth-child(3)  { --l: var(--l3, ""); }
  .dt__row > :nth-child(4)  { --l: var(--l4, ""); }
  .dt__row > :nth-child(5)  { --l: var(--l5, ""); }
  .dt__row > :nth-child(6)  { --l: var(--l6, ""); }
  .dt__row > :nth-child(7)  { --l: var(--l7, ""); }
  .dt__row > :nth-child(8)  { --l: var(--l8, ""); }
  .dt__row > :nth-child(9)  { --l: var(--l9, ""); }
  .dt__row > :nth-child(10) { --l: var(--l10, ""); }
  .dt__row > :nth-child(11) { --l: var(--l11, ""); }
  .dt__row > :nth-child(12) { --l: var(--l12, ""); }
  /* the title cell: first line, no caption, its own row layout kept */
  .dt__rows--p1 .dt__row > :nth-child(1),
  .dt__rows--p2 .dt__row > :nth-child(2) { --l: ""; flex: 1 1 0; min-width: 60%;
                                           flex-direction: row; align-items: center; gap: var(--sp-3); }
  .dt__rows--p2 .dt__row > :nth-child(1) { flex: none; }
  /* a figure cell stays one line of text: "4 / 10" is a value and its
     denominator, not two items to stack */
  .dt__row > .num { display: block; font-size: var(--fs-body); white-space: nowrap; text-align: left;
                    justify-self: auto; max-width: none; }
  .dt__row > .num::before { display: block; }
  .dt__row > .dt__bar, .dt__row > .dt__score { flex-direction: row; flex-wrap: wrap;
                                               align-items: center; gap: var(--sp-2); }
  .dt__row > .dt__bar::before, .dt__row > .dt__score::before { flex: 1 0 100%; }
  .dt__row > .dt-pill--st { padding: var(--sp-2) var(--sp-3); border-radius: var(--r-md); }
  .dt__row > .dt-pill--st::before { color: inherit; opacity: .7; }
  /* action cells (a button, or a group of them): no caption, together at
     the right end of the card, no sticky. Only the first of a run takes the
     free space, so two neighbouring buttons stay on one line. */
  .dt__row > .dt__x, .dt__row > .dt__act, .dt__row > .dt__go, .dt__row > .btn,
  .dt__row > .dt__acts, .dt__row > .dt__pin {
    --l: ""; flex: 0 0 auto; flex-direction: row; align-items: center; gap: var(--sp-1);
    margin: 0; padding: 0; position: static; background: none; }
  .dt__row > :not(.dt__x, .dt__act, .dt__go, .btn, .dt__acts, .dt__pin) +
    :is(.dt__x, .dt__act, .dt__go, .btn, .dt__acts, .dt__pin) { margin-left: auto; }
  .dt__row > .dt__go--void { display: none; }
  /* tree depth: a quarter of the desktop indent, the screen has no room for more */
  .dt__row[data-depth="1"] .dt__name { padding-left: var(--sp-3); }
  .dt__row[data-depth="2"] .dt__name { padding-left: var(--sp-6); }
  .dt__row[data-depth="3"] .dt__name { padding-left: calc(3 * var(--sp-3)); }
  .dt__row[data-depth="4"] .dt__name { padding-left: var(--sp-12); }
  .dt__row[data-depth="5"] .dt__name { padding-left: calc(5 * var(--sp-3)); }
  .dt__foot, .dt__note { padding-left: var(--sp-4); padding-right: var(--sp-4); }
}

/* ==========================================================================
   PHONE SHELL (handoff "Marzi Mobile", 18.09.2026; js/mobile.js)
   The desktop's sidebar and topbar are gone under 860px: a tab bar at the
   bottom, a header per screen, one list row, one delta chip, fact tiles,
   object tabs, sheets, a toast. Everything sized from tokens.css (--*-m).
   ========================================================================== */
@media (max-width: 860px) {
  html[data-phone] .sidebar, html[data-phone] .topbar { display: none; }
  html[data-phone] .app { grid-template-columns: minmax(0, 1fr); }
  html[data-phone] .page { padding: 0 0 calc(var(--h-tabbar) + var(--safe-b) + var(--sp-6)); gap: 0; }
  html[data-phone] .view { gap: 0; }
  html[data-phone][data-deep] .mtab { display: none; }
  html[data-phone][data-deep] .page { padding-bottom: var(--sp-6); }
  html[data-sheet] { overflow: hidden; }

  /* --- tab bar --- */
  .mtab { position: fixed; left: 0; right: 0; bottom: 0; z-index: var(--z-sticky);
          display: grid; grid-template-columns: repeat(7, 1fr); height: calc(var(--h-tabbar) + var(--safe-b));
          padding-bottom: var(--safe-b); background: var(--bg-nav); border-top: 1px solid var(--border); }
  /* icons only, in the sidebar's order: seven names do not fit a phone's
     width, and More lists every section with its name */
  .mtab__i { display: flex; align-items: center; justify-content: center; color: var(--text-muted); }
  .mtab__i[aria-current="page"] { color: var(--brand); }
  .mtab__i[aria-current="page"] .mtab__ic::after { content: ""; position: absolute; left: 50%; bottom: calc(-1 * var(--sp-2)); width: var(--sp-1); height: var(--sp-1);
                                                   border-radius: var(--r-pill); background: var(--brand); transform: translateX(-50%); }
  .mtab__ic { position: relative; display: block; }
  .mtab__ic .i { width: var(--sp-6); height: var(--sp-6); }
  .mtab__badge { position: absolute; top: calc(-1 * var(--sp-2)); right: calc(-1 * var(--sp-4)); min-width: 18px; height: 18px;
                 padding: 0 var(--sp-1); border-radius: var(--r-pill); font-size: var(--fs-micro); line-height: 16px; text-align: center;
                 background: var(--st-warn-bg); color: var(--st-warn-fg); border: 1px solid var(--st-warn-bg); }
  .mtab__badge[data-st="neg"] { background: var(--st-neg-bg); color: var(--st-neg-fg); }

  /* --- screen header --- */
  .mhead { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--sp-2);
           padding: var(--sp-3) var(--sp-2) var(--sp-3) var(--sp-4); position: sticky; top: 0; z-index: var(--z-sticky);
           background: var(--bg-app); }
  .mhead__txt { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
  .mhead__t { font-family: var(--font-display); font-weight: var(--fw-black); font-size: var(--fs-m-title); line-height: var(--lh-m-title);
              color: var(--text-primary); margin: 0; }
  .mhead__s { font-size: var(--fs-caption); color: var(--text-muted); }
  .mhead__acts { display: flex; gap: 2px; flex: none; align-items: center; }
  .mhead__btn { width: var(--tap-m); height: var(--tap-m); border-radius: var(--r-md); border: 0; background: none; color: var(--text-primary);
                display: flex; align-items: center; justify-content: center; cursor: pointer; }
  .mhead__btn--accent { background: var(--brand-tint); color: var(--brand); }
  .mhead__btn .i { width: var(--sp-6); height: var(--sp-6); }
  .mhead--obj { align-items: center; padding: var(--sp-2) var(--sp-2); min-height: var(--h-mhead); }
  .mhead__t--one { font-size: var(--fs-m-obj); line-height: var(--lh-m-obj); flex: 1; min-width: 0;
                   white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  .mhead__pill { border: 1px solid var(--border); border-radius: var(--r-pill); padding: 2px var(--sp-3); background: var(--bg-surface);
                 font-size: var(--fs-caption); font-weight: var(--fw-black); color: var(--brand); }
  .mhead__bell { position: relative; }
  .mhead__bell .mtab__badge { top: 1px; right: calc(-1 * var(--sp-1)); }
  .mhead__link { border: 0; background: none; color: var(--brand); font-size: var(--fs-sm); font-weight: var(--fw-black); padding: 0 var(--sp-2); cursor: pointer; }
  .mcrumb { padding: 0 var(--sp-4) var(--sp-2); font-size: var(--fs-caption); color: var(--text-muted); }

  /* no field under 16px: iOS zooms into it and stays zoomed */
  html[data-phone] input:not([type="checkbox"]):not([type="radio"]):not([type="file"]), html[data-phone] textarea, html[data-phone] select { font-size: var(--fs-input-m); }

  /* --- the section entry card (fix handoff 19.09) --- */
  .mentry { margin: 0 var(--sp-4) var(--sp-3); background: var(--bg-surface); border: 1px solid var(--border); border-radius: var(--r-lg);
            padding: var(--sp-4); display: flex; flex-direction: column; gap: var(--sp-2); }
  .mentry__in { min-height: var(--tap-m); font-size: var(--fs-body); }
  .mentry__ex { display: flex; gap: var(--sp-2); flex-wrap: wrap; }
  .mentry__alt { border: 0; background: none; color: var(--brand); font-size: var(--fs-sm); font-weight: var(--fw-black); padding: 0; cursor: pointer; text-align: left; }
  .mentry .entry__msgs:empty { display: none; }
  .mgroup.mgroup--row { flex-direction: row; align-items: baseline; justify-content: space-between; padding: var(--sp-3) var(--sp-4) var(--sp-2); }
  .mtools { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-2); padding: 0 var(--sp-4) var(--sp-2); }
  .mtools .mseg { margin: 0; flex: none; }
  .mtools .mseg__b { padding: var(--sp-1) var(--sp-3); }

  /* --- list and row --- */
  .mlist { background: var(--bg-surface); border-top: 1px solid var(--border); }
  .mlist--card { margin: 0 var(--sp-4); border: 1px solid var(--border); border-radius: var(--r-lg); overflow: hidden; }
  .mrow { display: flex; gap: var(--sp-3); align-items: center; padding: var(--sp-3) var(--sp-4); min-height: var(--h-row-m);
          border-bottom: 1px solid var(--border-soft); color: inherit; text-decoration: none; }
  .mrow[data-mopen], a.mrow { cursor: pointer; }
  .mrow[data-mopen]:active, a.mrow:active { background: var(--bg-row); }
  .mrow[data-ended] { background: var(--st-neg-bg); }
  .mrow:last-child { border-bottom: 0; }
  .mrow__img { width: var(--w-thumb-m); height: var(--w-thumb-m); flex: none; border-radius: var(--r-sm); background: var(--bg-sunken); object-fit: contain; }
  .mrow__rank { width: var(--sp-6); flex: none; font-family: var(--font-display); font-weight: var(--fw-black); font-size: var(--fs-sm); color: var(--text-muted); }
  .mrow__q { width: var(--sp-10); height: var(--sp-10); flex: none; border-radius: var(--r-sm); background: var(--brand-tint); color: var(--brand);
             display: flex; align-items: center; justify-content: center; }
  .mrow__q--void { display: none; }
  .mrow__body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 3px; }
  .mrow__t { font-size: var(--fs-body); font-weight: var(--fw-bold); line-height: 1.3; color: var(--text-primary);
             display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
  .mrow__m { font-size: var(--fs-caption); color: var(--text-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  .mrow__m .badge { vertical-align: middle; }
  .mrow__end { display: flex; flex-direction: column; align-items: flex-end; gap: var(--sp-1); flex: none; max-width: 40%; }
  .mrow__hero { font-family: var(--font-display); font-weight: var(--fw-black); font-size: var(--fs-m-hero); line-height: 1; color: var(--text-primary); white-space: nowrap; }
  .mrow__hero[data-st="muted"] { color: var(--text-muted); }
  .mrow__den { font-size: var(--fs-sm); color: var(--text-muted); font-weight: var(--fw-bold); }
  .mrow__cap { display: block; font-size: var(--fs-micro); font-weight: var(--fw-black); letter-spacing: .08em; text-transform: uppercase; color: var(--text-faint); margin-bottom: 2px; }
  .mrow__dot { display: inline-block; width: var(--sp-2); height: var(--sp-2); border-radius: var(--r-pill); margin-right: var(--sp-1); vertical-align: middle; background: var(--st-flat-fg); }
  .mrow__dot[data-st="warn"] { background: var(--st-warn-fg); }
  .mrow__note { font-size: var(--fs-sm); color: var(--text-muted); }
  .mrow__t--one { display: block; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  .mrow__body > .mchip { align-self: flex-start; margin-top: 2px; }
  .mrow__end--score { width: 74px; max-width: none; }
  .mrow__hero--big { font-size: var(--fs-display); }
  .mrow__rank--tile { width: var(--sp-6); height: var(--sp-6); border-radius: var(--r-sm); background: var(--marzipan); color: var(--st-warn-fg);
                      display: flex; align-items: center; justify-content: center; font-size: var(--fs-micro); }
  .mrow__promo { display: inline-block; width: 6px; height: 6px; border-radius: var(--r-pill); background: var(--st-warn-fg); margin-left: var(--sp-1); vertical-align: middle; }
  .mbar--wide { width: 100%; margin: 0; }
  .mbar i[data-st="pos"] { background: var(--st-pos-fg); }
  .mbar i[data-st="warn"] { background: var(--st-warn-fg); }
  .mbar i[data-st="neg"] { background: var(--st-neg-fg); }
  .mrow--set { min-height: var(--h-control); padding-top: var(--sp-3); padding-bottom: var(--sp-3); }
  .mrow--set .mrow__end { flex-direction: row; align-items: center; gap: var(--sp-2); max-width: 60%; }
  .mbar { display: block; width: var(--sp-16); height: 6px; border-radius: var(--r-pill); background: var(--track); overflow: hidden; margin-bottom: var(--sp-1); margin-left: auto; }
  .mbar i { display: block; height: 100%; background: var(--bar-earn); border-radius: var(--r-pill); }

  /* --- delta chip --- */
  .mchip { display: inline-flex; align-items: center; height: var(--h-chip-m); padding: 0 var(--sp-2); border-radius: var(--r-pill);
           font-size: var(--fs-micro); font-weight: var(--fw-black); white-space: nowrap;
           background: var(--st-flat-bg); color: var(--st-flat-fg); }
  .mchip[data-st="pos"] { background: var(--st-pos-bg); color: var(--st-pos-fg); }
  .mchip[data-st="neg"] { background: var(--st-neg-bg); color: var(--st-neg-fg); }
  .mchip[data-st="warn"] { background: var(--st-warn-bg); color: var(--st-warn-fg); }
  .mchip[data-st="brand"] { background: var(--brand-tint); color: var(--brand); }

  /* --- segments, chips strip, tabs --- */
  .mseg { display: flex; padding: 3px; border-radius: var(--r-pill); background: var(--bg-sunken); margin: 0 var(--sp-4) var(--sp-3); }
  .mseg__b { flex: 1; border: 0; background: none; border-radius: var(--r-pill); padding: var(--sp-2) 0; font-size: var(--fs-caption);
             font-weight: var(--fw-bold); color: var(--text-muted); cursor: pointer; white-space: nowrap; }
  .mseg__b[aria-selected="true"] { background: var(--bg-surface); color: var(--brand); font-weight: var(--fw-black); box-shadow: var(--sh-xs); }
  .mchips { display: flex; gap: var(--sp-2); overflow-x: auto; padding: 0 var(--sp-4) var(--sp-3); scrollbar-width: none; }
  .mchips::-webkit-scrollbar { display: none; }
  .mchips .chip { flex: none; }
  .mtabs { display: flex; padding: 3px; border-radius: var(--r-pill); background: var(--bg-sunken); margin: 0 var(--sp-4) var(--sp-3);
           position: sticky; top: var(--h-mhead); z-index: var(--z-sticky); }
  .mtabs__b { flex: 1; text-align: center; border-radius: var(--r-pill); padding: var(--sp-2) 0; font-size: var(--fs-caption);
              font-weight: var(--fw-bold); color: var(--text-muted); text-decoration: none; }
  .mtabs__b[aria-selected="true"] { background: var(--bg-surface); color: var(--brand); font-weight: var(--fw-black); box-shadow: var(--sh-xs); }
  .msearch { padding: 0 var(--sp-4) var(--sp-3); }

  /* --- tiles --- */
  .mtiles { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--sp-2); padding: 0 var(--sp-4) var(--sp-3); }
  .mtile { background: var(--bg-surface); border: 1px solid var(--border-soft); border-radius: var(--r-md); padding: var(--sp-2) var(--sp-3);
           display: flex; flex-direction: column; gap: 2px; min-width: 0; position: relative; }
  .mtile[data-st]::after { content: ""; position: absolute; top: var(--sp-3); right: var(--sp-3); width: var(--sp-2); height: var(--sp-2); border-radius: var(--r-pill); }
  .mtile[data-st="pos"]::after { background: var(--st-pos-fg); }
  .mtile[data-st="warn"]::after { background: var(--st-warn-fg); }
  .mtile[data-st="neg"]::after { background: var(--st-neg-fg); }
  .mtile[data-st=""]::after { display: none; }
  .mtile__k { font-size: var(--fs-micro); font-weight: var(--fw-black); letter-spacing: .06em; text-transform: uppercase; color: var(--text-faint);
              display: flex; align-items: center; gap: var(--sp-1); }
  .mtile__badge { font-size: var(--fs-micro); padding: 1px var(--sp-1); border-radius: var(--r-xs); background: var(--bg-sunken); letter-spacing: .04em; }
  .mtile__v { font-family: var(--font-display); font-weight: var(--fw-black); font-size: var(--fs-m-tile); line-height: 1.15; color: var(--text-primary); }
  .mtile__s { font-size: var(--fs-micro); font-weight: var(--fw-bold); color: var(--text-muted); }

  /* --- key / value list, group heading, note --- */
  .mkv { display: flex; flex-direction: column; margin: 0 var(--sp-4) var(--sp-3); }
  .mkv__r { display: flex; justify-content: space-between; gap: var(--sp-3); padding: var(--sp-2) 0; border-bottom: 1px solid var(--border-soft); font-size: var(--fs-sm); }
  .mkv__k { color: var(--text-muted); }
  .mkv__v { font-weight: var(--fw-black); color: var(--text-primary); text-align: right; }
  .mgroup { display: flex; flex-direction: column; gap: 2px; padding: var(--sp-3) 0 var(--sp-2); }
  .mgroup__h { font-family: var(--font-display); font-weight: var(--fw-bold); font-size: var(--fs-card); color: var(--text-primary); }
  .mgroup__s { font-size: var(--fs-caption); color: var(--text-muted); }
  .mnote { padding: var(--sp-3) var(--sp-4); font-size: var(--fs-caption); color: var(--text-muted); }
  .mday { padding: var(--sp-3) var(--sp-4) var(--sp-1); font-size: var(--fs-micro); font-weight: var(--fw-black); letter-spacing: .06em; text-transform: uppercase; color: var(--text-faint); background: var(--bg-app); }

  /* --- home feed row --- */
  .mfeed { display: flex; gap: var(--sp-3); align-items: center; padding: var(--sp-3) var(--sp-4); border-bottom: 1px solid var(--border-soft);
           color: inherit; text-decoration: none; }
  .mfeed.is-unread { background: var(--bg-selected); }
  .mfeed__i { width: var(--sp-8); height: var(--sp-8); flex: none; border-radius: var(--r-sm); display: flex; align-items: center; justify-content: center;
              font-size: var(--fs-caption); font-weight: var(--fw-black); background: var(--st-flat-bg); color: var(--st-flat-fg); }
  .mfeed__i[data-st="pos"] { background: var(--st-pos-bg); color: var(--st-pos-fg); }
  .mfeed__i[data-st="neg"] { background: var(--st-neg-bg); color: var(--st-neg-fg); }
  .mfeed__i[data-st="warn"] { background: var(--st-warn-bg); color: var(--st-warn-fg); }
  .mfeed__body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
  .mfeed__t { font-size: var(--fs-sm); font-weight: var(--fw-bold); color: var(--text-primary); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  .mfeed__m { font-size: var(--fs-caption); color: var(--text-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  .mfeed__m b { color: var(--text-secondary); font-weight: var(--fw-bold); }
  .mfeed__dot { width: var(--sp-2); height: var(--sp-2); border-radius: var(--r-pill); background: var(--brand); flex: none; }

  /* --- object screen --- */
  .mobj { display: flex; flex-direction: column; gap: var(--sp-3); padding: 0 var(--sp-4) var(--sp-3); }
  .mobj__id { display: flex; gap: var(--sp-3); align-items: flex-start; }
  .mobj__img { width: var(--sp-16); height: var(--sp-16); flex: none; border-radius: var(--r-md); background: var(--bg-sunken); object-fit: contain; }
  .mobj__txt { min-width: 0; display: flex; flex-direction: column; gap: var(--sp-1); }
  .mobj__t { font-size: var(--fs-body); font-weight: var(--fw-bold); line-height: 1.3; color: var(--text-primary); }
  .mobj__m { font-size: var(--fs-caption); color: var(--text-muted); display: flex; flex-wrap: wrap; gap: var(--sp-1) var(--sp-2); align-items: center; }
  .mobj__body { padding: 0 var(--sp-4); display: flex; flex-direction: column; gap: var(--sp-3); }
  .mobj__body .mtiles, .mobj__body .mkv, .mobj__body .mseg, .mobj__body .mchips { padding-left: 0; padding-right: 0; margin-left: 0; margin-right: 0; }
  .mobj__body .mlist { margin: 0 calc(-1 * var(--sp-4)); }
  .mobj__body .spy-facts { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .mobj__body .card, .mobj__body .spy-side { padding: var(--sp-4); }
  .mobj__body .nd-box { padding: var(--sp-4); }
  .mobj--flat { padding-bottom: 0; }
  .mobj__body .spy-img { flex-direction: column; }
  .mobj__body .spy-img__pic { width: 100%; height: auto; max-height: 200px; }
  .mobj__body .mtiles { padding: 0; }
  .mmoves { display: flex; flex-direction: column; gap: var(--sp-2); font-size: var(--fs-sm); color: var(--text-secondary); }
  .mmarket__badges { display: flex; flex-wrap: wrap; gap: var(--sp-1); }
  .mmarket__score { display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: var(--sp-2) var(--sp-3);
                    padding: var(--sp-3); border: 1px solid var(--border-soft); border-radius: var(--r-md); background: var(--bg-surface); }
  .mmarket__score .nd-score__v { font-size: var(--fs-section); }
  .mbtn { width: 100%; justify-content: center; min-height: var(--tap-m); border-radius: var(--r-row); font-weight: var(--fw-black); }
  .mfoot { position: sticky; bottom: calc(var(--h-tabbar) + var(--safe-b)); padding: var(--sp-3) var(--sp-4) var(--sp-4); background: var(--bg-app);
           display: flex; gap: var(--sp-2); }
  .mfoot--2 .mbtn { flex: 1; }
  html[data-deep] .mfoot { bottom: 0; padding-bottom: calc(var(--sp-4) + var(--safe-b)); }

  /* --- sheet --- */
  .msheet { position: fixed; inset: 0; z-index: var(--z-modal); display: flex; align-items: flex-end; }
  .msheet__scrim { position: absolute; inset: 0; background: var(--bg-overlay); opacity: 0; transition: opacity var(--dur) var(--ease); }
  .msheet__panel { position: relative; width: 100%; max-height: 92dvh; overflow-y: auto; background: var(--bg-surface);
                   border-radius: var(--r-xl) var(--r-xl) 0 0; padding: var(--sp-2) var(--sp-4) calc(var(--sp-4) + var(--safe-b));
                   transform: translateY(100%); transition: transform var(--dur-slow) var(--ease); }
  .msheet.is-on .msheet__scrim { opacity: 1; }
  .msheet.is-on .msheet__panel { transform: none; }
  .msheet__handle { width: var(--sp-10); height: 4px; border-radius: var(--r-pill); background: var(--border); margin: 0 auto var(--sp-3); }
  .msheet__t { font-family: var(--font-display); font-weight: var(--fw-black); font-size: var(--fs-section); color: var(--text-primary); margin-bottom: var(--sp-3); }
  .msheet__body { display: flex; flex-direction: column; gap: var(--sp-3); }
  .msheet__p { font-size: var(--fs-sm); line-height: var(--lh-sm); color: var(--text-secondary); padding: var(--sp-3) var(--sp-4); }
  .mradio { display: flex; flex-direction: column; margin: 0 calc(-1 * var(--sp-4)); }
  .mradio__i { text-align: left; border: 0; background: none; padding: var(--sp-3) var(--sp-4); min-height: var(--tap-m); font-size: var(--fs-body);
               font-weight: var(--fw-bold); color: var(--text-primary); border-bottom: 1px solid var(--border-soft); cursor: pointer;
               display: flex; justify-content: space-between; align-items: center; }
  .mradio__i:last-child { border-bottom: 0; }
  .mradio__i[aria-checked="true"] { color: var(--brand); }
  .mradio__i[aria-checked="true"]::after { content: "\2713"; font-weight: var(--fw-black); }
  .mradio__i[data-st="neg"] { color: var(--negative); }

  /* --- the More sheet --- */
  .mmore__acct { display: flex; align-items: center; gap: var(--sp-3); padding: var(--sp-2) 0 var(--sp-3); border-bottom: 1px solid var(--border-soft); color: inherit; text-decoration: none; }
  .mmore__who { flex: 1; min-width: 0; display: flex; flex-direction: column; }
  .mmore__who b { font-size: var(--fs-body); color: var(--text-primary); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  .mmore__who span { font-size: var(--fs-caption); color: var(--text-muted); }
  .mmore__manage { font-size: var(--fs-sm); font-weight: var(--fw-black); color: var(--brand); }
  .mmore__list { display: flex; flex-direction: column; }
  .mmore__i { display: flex; align-items: center; gap: var(--sp-3); min-height: var(--tap-m); padding: var(--sp-2) 0; border-bottom: 1px solid var(--border-soft);
              color: var(--text-primary); font-size: var(--fs-body); font-weight: var(--fw-bold); text-decoration: none; }
  .mmore__i:last-child { border-bottom: 0; }
  .mmore__ic { width: var(--sp-8); height: var(--sp-8); border-radius: var(--r-sm); background: var(--brand-tint); color: var(--brand); display: flex; align-items: center; justify-content: center; }
  .mmore__chev { margin-left: auto; color: var(--text-faint); }
  .mmore__i .mchip { margin-left: auto; }
  .mmore__out { border: 0; background: none; color: var(--negative); font-weight: var(--fw-black); font-size: var(--fs-body); text-align: left; padding: var(--sp-3) var(--sp-4); cursor: pointer; }

  /* --- gestures: swipe actions, pull-to-refresh, push/pop --- */
  .mswipe { position: relative; overflow: hidden; }
  .mswipe .mrow { position: relative; z-index: 1; background: var(--bg-surface); transition: transform var(--dur) var(--ease); touch-action: pan-y; }
  .mswipe .mrow[data-ended] { background: var(--st-neg-bg); }
  .mswipe__acts { position: absolute; top: 0; bottom: 0; right: 0; display: flex; }
  .mswipe__a { width: var(--sp-16); border: 0; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: var(--sp-1);
               background: var(--bg-sunken); color: var(--text-secondary); font-size: var(--fs-micro); font-weight: var(--fw-black); cursor: pointer; }
  .mswipe__a[data-st="neg"] { background: var(--st-neg-bg); color: var(--st-neg-fg); }
  .mpull { position: fixed; top: var(--sp-2); left: 50%; z-index: var(--z-toast); width: var(--sp-10); height: var(--sp-10); border-radius: var(--r-pill);
           background: var(--bg-surface); box-shadow: var(--sh-md); display: flex; align-items: center; justify-content: center; color: var(--text-muted);
           transform: translate(-50%, 0); opacity: 0; pointer-events: none; }
  .mpull.is-ready { color: var(--brand); }
  .mpull.is-busy { animation: mspin .8s linear infinite; opacity: 1; transform: translate(-50%, 56px); }
  @keyframes mspin { to { transform: translate(-50%, 56px) rotate(360deg); } }
  .view.m-push { animation: mpush var(--dur-slow) var(--ease); }
  .view.m-pop { animation: mpop var(--dur-slow) var(--ease); }
  @keyframes mpush { from { opacity: 0; transform: translateX(var(--sp-6)); } to { opacity: 1; transform: none; } }
  @keyframes mpop { from { opacity: 0; transform: translateX(calc(-1 * var(--sp-6))); } to { opacity: 1; transform: none; } }
  .mform__note { font-size: var(--fs-caption); color: var(--text-muted); margin: 0; }

  /* --- toast, veil, states --- */
  .mtoast { position: fixed; left: var(--sp-4); right: var(--sp-4); bottom: calc(var(--h-tabbar) + var(--safe-b) + var(--sp-3)); z-index: var(--z-toast);
            background: var(--text-primary); color: var(--bg-app); border-radius: var(--r-row); padding: var(--sp-3) var(--sp-4);
            display: flex; justify-content: space-between; align-items: center; gap: var(--sp-3); font-size: var(--fs-sm); font-weight: var(--fw-bold);
            box-shadow: var(--sh-lg); transition: opacity var(--dur) var(--ease); }
  .mtoast.is-off { opacity: 0; }
  .mtoast__a { border: 0; background: none; color: var(--marzipan); font-weight: var(--fw-black); font-size: var(--fs-sm); cursor: pointer; }
  .mveil { position: relative; }
  .mveil__rows { filter: blur(var(--blur-veil)); opacity: .5; pointer-events: none; user-select: none; }
  .mveil__note { position: absolute; inset: 0; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: var(--sp-2);
                 padding: var(--sp-4); text-align: center; }
  .mveil__t { font-family: var(--font-display); font-weight: var(--fw-bold); font-size: var(--fs-section); color: var(--text-primary); }
  .mveil__s { font-size: var(--fs-sm); color: var(--text-secondary); max-width: 40ch; }
  .mveil__act { margin-top: var(--sp-2); }
  .mskel { padding: var(--sp-4); display: flex; flex-direction: column; gap: var(--sp-2); }
  .mfail { display: flex; flex-direction: column; gap: var(--sp-3); padding: var(--sp-4); align-items: center; }

  /* --- the desktop sections that stay (Finder entry, AI Integration,
         Market Intelligence, Support form/thread, Settings cards): their
         page head becomes the screen header, their body loses the page air --- */
  html[data-phone] .page-head { padding: var(--sp-3) var(--sp-4); position: sticky; top: 0; background: var(--bg-app); z-index: var(--z-sticky); }
  html[data-phone] .page-head .crumbs { display: none; }
  html[data-phone] .page-head .t-page { font-size: var(--fs-m-title); line-height: var(--lh-m-title); }
  html[data-phone] .page-head__titles > p { font-size: var(--fs-caption); line-height: var(--lh-caption); color: var(--text-muted); }
  html[data-phone] .view > .entry, html[data-phone] .view > .card, html[data-phone] .view > .nf, html[data-phone] .view > .stack,
  html[data-phone] .view > .dt, html[data-phone] .view > .paused, html[data-phone] .view > .alert, html[data-phone] .view > .mcp-conn,
  html[data-phone] .view > .mcp-wiz, html[data-phone] .view > .mcp-money, html[data-phone] .view > .mcp-kpis, html[data-phone] .view > .mcp-charts,
  html[data-phone] .view > .mcp-billing, html[data-phone] .view > .mcp-notice, html[data-phone] .view > div:not([class]) { margin: 0 var(--sp-4) var(--sp-3); }
  html[data-phone] .entry { padding: var(--sp-5) var(--sp-4); }
  html[data-phone] .entry__form { flex-wrap: wrap; padding: var(--sp-2); }
  html[data-phone] .entry__form input { flex: 1 1 100%; min-height: var(--tap-m); padding: 0 var(--sp-2); }
  html[data-phone] .entry__form .entry__go { flex: 1 1 100%; justify-content: center; }
  html[data-phone] .entry__form > svg { display: none; }
  /* the support thread: the log keeps the page margin, the composer sits on
     the bottom edge above the safe area */
  html[data-phone] .sup-thread { margin: 0 var(--sp-4); }
  html[data-phone] .sup-compose { position: sticky; bottom: 0; margin: 0; padding: var(--sp-2) var(--sp-4) calc(var(--sp-3) + var(--safe-b));
                                  background: var(--bg-app); border-top: 1px solid var(--border-soft); }
  html[data-phone] .sup-compose .entry__form { flex-wrap: nowrap; align-items: flex-end; }
  html[data-phone] .sup-compose .entry__form textarea { flex: 1 1 auto; }
  html[data-phone] .sup-compose .entry__form .entry__go { flex: none; padding: var(--sp-3); }
  html[data-phone] .sup-compose__row .t-sm { display: none; }
  html[data-phone] .sup-thread .chat__msg--user { max-width: 82%; }
  /* the ended row inside a swipe wrapper: its tint is translucent and let
     the action rail show through — paint it over an opaque surface */
  .mswipe .mrow[data-ended] { background-color: var(--bg-surface); background-image: linear-gradient(var(--st-neg-bg), var(--st-neg-bg)); }
  /* a finger leaves no hover; the current section is what reads purple */
  html[data-phone] a:hover { color: inherit; }
  .mmore__i[aria-current="page"], .mmore__i[aria-current="page"] .mmore__ic { color: var(--brand); }
  /* tap targets in the desktop-markup sections and the small text links */
  html[data-phone] .btn--sm, html[data-phone] .chip, html[data-phone] .segmented__btn { min-height: var(--h-control); }
  html[data-phone] .segmented { max-width: 100%; overflow-x: auto; flex-wrap: nowrap; scrollbar-width: none; }
  html[data-phone] .segmented::-webkit-scrollbar { display: none; }
  html[data-phone] .segmented__btn { white-space: nowrap; flex: none; }
  .mentry__alt, .mhead__link { min-height: var(--tap-m); display: inline-flex; align-items: center; }
  html[data-phone] textarea { resize: none; }
  html[data-phone] .btn--icon { min-width: var(--tap-m); }
  .mseg__b, .mtabs__b { min-height: var(--h-seg-m); }
  /* a desktop table head inside a sheet: its tools take the full width and
     scroll rather than push the panel wider */
  html[data-phone] .dt__head > .dt__tools { flex: 1 1 100%; min-width: 0; max-width: 100%; }
  /* a pasted link in a bubble breaks anywhere rather than leaving one
     character on its own line */
  html[data-phone] .chat__msg--user, html[data-phone] .chat__msg--bot { overflow-wrap: anywhere; }
  .mhead { padding-top: max(var(--sp-3), var(--safe-t)); }
  .mhead--obj { padding-top: max(var(--sp-2), var(--safe-t)); }
  /* the product card (#modal) as a sheet: the close button in the corner,
     the head stacked */
  html[data-phone] #modal .nd-head { position: relative; flex-direction: column; padding-right: var(--sp-12); }
  html[data-phone] #modal .nd-head > .row { position: absolute; top: var(--sp-3); right: var(--sp-3); }
  html[data-phone] #modal .nd-title { font-size: var(--fs-section); line-height: var(--lh-section); }
  /* the plan gate is the page, not a panel over it */
  html[data-phone] .modal__panel--gate { width: 100%; height: 100dvh; max-height: none; border-radius: 0; border: 0; }
  html[data-phone] .modal[data-gate] { padding: 0; place-items: stretch; }
  html[data-phone] .modal[data-gate] .modal__scrim { display: none; }
}

/* the Competitor Tracker's link form inside its add dialog (owner 19.09:
   the section takes Price Tracker's shape): the hero's shadow and width
   make no sense on a panel, the field itself is the same */
.modal .entry__form { width: 100%; box-shadow: none; }
.modal .entry__form:focus-within { box-shadow: none; }
