/* =========================================================================
   TEGO console · /app preview
   Sidebar console shared by the admin, insurer, client and partner views.
   Tokens come from css/tego.css; nothing here invents a colour.
   ========================================================================= */

/* ---- 1. Frame: grid, sidebar, topbar, main, footer, preview ribbon ---- */

.app-shell {
  /* Tone pairs for badges, stat tiles and pills. Every one of these is
     derived from a tego.css token, so a palette change lands here too. */
  --tone-brand-bg: var(--brand-soft);
  --tone-brand-ink: var(--brand);
  --tone-ok-bg: color-mix(in srgb, var(--ok) 12%, var(--surface));
  --tone-ok-ink: var(--ok);
  --tone-info-bg: color-mix(in srgb, var(--periwinkle) 16%, var(--surface));
  --tone-info-ink: color-mix(in srgb, var(--periwinkle) 55%, var(--ink));
  --tone-warn-bg: var(--warn-bg);
  --tone-warn-ink: color-mix(in srgb, var(--error) 62%, var(--warn-border));
  --tone-error-bg: var(--error-bg);
  --tone-error-ink: var(--error);
  --tone-muted-bg: var(--mist);
  --tone-muted-ink: var(--muted);

  /* Chart hues, one per file status. The badge tones only carry three
     shades of purple across submitted, with_insurer and withdrawn, which
     reads fine on a pill and not at all on a donut, so the chart gets six
     separable hues built from the same tego.css tokens. */
  --chart-submitted: var(--brand);
  --chart-documents-needed: var(--tone-warn-ink);
  --chart-with-insurer: color-mix(in srgb, var(--periwinkle) 55%, var(--ok));
  --chart-policy-issued: var(--ok);
  --chart-declined: var(--tone-error-ink);
  --chart-withdrawn: var(--muted-2);

  --side-w: 232px;
  --top-h: 68px;
  --ribbon-h: 34px;

  display: grid;
  grid-template-columns: var(--side-w) minmax(0, 1fr);
  min-height: 100vh;
  font-family: var(--font-body);
  font-size: 14px;
  line-height: 1.5;
  color: var(--ink);
  background: var(--bg);
}

.app-shell.ribbon-off { --ribbon-h: 0px; }

.app-shell h1,
.app-shell h2,
.app-shell h3,
.app-shell h4 {
  font-family: var(--font-display);
  letter-spacing: -0.02em;
  line-height: 1.15;
  margin: 0;
}

.app-shell p { margin: 0; }
.app-shell a { text-decoration: none; color: inherit; }
.app-shell button { font-family: inherit; font-size: inherit; cursor: pointer; }
.app-shell .ico { flex: none; }

.side {
  position: sticky;
  top: 0;
  align-self: start;
  height: 100vh;
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 20px 12px 16px;
  background: var(--brand-tint);
  border-right: 1px solid var(--border);
  overflow-y: auto;
  z-index: 40;
}

.main-col {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

/* Only ever a thing once the sidebar is off-canvas. Left displayed it would
   claim a grid cell of its own and push the main column off the row. */
.nav-scrim { display: none; }

.topbar {
  position: sticky;
  top: var(--ribbon-h);
  z-index: 35;
  display: flex;
  align-items: center;
  gap: 16px;
  height: var(--top-h);
  padding: 0 24px;
  background: var(--surface);
  border-bottom: 1px solid var(--border);
}

.app-main {
  flex: 1;
  padding: 28px;
  min-width: 0;
}

.main-inner {
  max-width: 1360px;
  margin: 0 auto;
}

.app-foot {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
  margin-top: 32px;
  padding-top: 18px;
  border-top: 1px solid var(--border);
  color: var(--muted);
  font-size: 13px;
}

.app-foot img { width: 46px; height: auto; opacity: 0.75; }
.app-foot .foot-links { margin-left: auto; display: flex; gap: 20px; }
.app-foot .foot-links a:hover { color: var(--brand); }

/* A strip at the top of the main column rather than a badge floating over
   the bottom-left corner. It holds a row of its own above the topbar and
   sticks with it, so at no scroll position can it come to rest over a card,
   a table row or a primary button. Dismissing it gives the row back. */
.preview-ribbon {
  position: sticky;
  top: 0;
  z-index: 36;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  height: var(--ribbon-h);
  padding: 0 44px;
  background: var(--ink);
  color: var(--surface);
  font-size: 12px;
  letter-spacing: 0.01em;
}

.preview-ribbon button {
  position: absolute;
  top: 50%;
  right: 12px;
  transform: translateY(-50%);
  display: grid;
  place-items: center;
  width: 22px;
  height: 22px;
  padding: 0;
  border: 0;
  border-radius: 999px;
  background: color-mix(in srgb, var(--surface) 18%, transparent);
  color: var(--surface);
}

.preview-ribbon button:hover { background: color-mix(in srgb, var(--surface) 30%, transparent); }
.preview-ribbon[hidden] { display: none; }

/* ---- 2. Sidebar nav: brand, items, active bar, count pill, help card --- */

.side-brand {
  padding: 4px 10px 18px;
}

.side-brand img { width: 108px; height: auto; }

.side-brand .tag {
  margin-top: 8px;
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted-2);
}

.side-nav { display: flex; flex-direction: column; gap: 4px; }

.side-nav .nav-item {
  position: relative;
  display: flex;
  align-items: center;
  gap: 12px;
  height: 44px;
  padding: 0 12px;
  border-radius: 12px;
  color: var(--ink-2);
  font-size: 14px;
  font-weight: 500;
  transition: background 0.16s var(--ease), color 0.16s var(--ease);
}

.side-nav .nav-item .ico { color: var(--muted); transition: color 0.16s var(--ease); }
.side-nav .nav-item:hover { background: color-mix(in srgb, var(--brand-soft) 55%, transparent); }

.side-nav .nav-item.is-active {
  background: var(--brand-soft);
  color: var(--brand);
  font-weight: 600;
}

.side-nav .nav-item.is-active .ico { color: var(--brand); }

.side-nav .nav-item.is-active::before {
  content: "";
  position: absolute;
  left: -12px;
  top: 6px;
  bottom: 6px;
  width: 3px;
  border-radius: 0 3px 3px 0;
  background: var(--brand);
}

.side-nav .nav-label { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.side-nav .count-pill {
  flex: none;
  min-width: 22px;
  height: 20px;
  padding: 0 7px;
  display: grid;
  place-items: center;
  border-radius: 999px;
  background: var(--surface);
  color: var(--brand);
  font-size: 12px;
  font-weight: 600;
}

.side-divider {
  height: 1px;
  margin: 16px 12px;
  background: var(--border);
}

.side-help {
  margin-top: auto;
  padding: 16px;
  border-radius: var(--radius);
  border: 1px solid var(--border);
  background: var(--surface);
}

.side-help.is-promo { background: var(--brand-soft); border-color: color-mix(in srgb, var(--brand) 18%, var(--border)); }

.side-help .help-tile {
  display: grid;
  place-items: center;
  width: 36px;
  height: 36px;
  border-radius: 999px;
  background: var(--brand-soft);
  color: var(--brand);
  margin-bottom: 10px;
}

.side-help.is-promo .help-tile { background: var(--surface); }
.side-help h4 { font-size: 14px; font-weight: 700; margin-bottom: 4px; }
.side-help p { font-size: 13px; color: var(--muted); line-height: 1.45; }

.btn-outline-full {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  width: 100%;
  margin-top: 12px;
  height: 38px;
  border-radius: 10px;
  border: 1px solid var(--border-strong);
  background: var(--surface);
  color: var(--brand);
  font-size: 13px;
  font-weight: 600;
}

.btn-outline-full:hover { border-color: var(--brand); background: var(--brand-tint); }

/* ---- 3. Topbar: search, bell + dropdown, persona chip + menu ----------- */

.top-search {
  position: relative;
  flex: 1;
  max-width: 600px;
  display: flex;
  align-items: center;
  gap: 10px;
  height: 40px;
  padding: 0 12px;
  border-radius: 10px;
  border: 1px solid var(--border);
  background: var(--brand-tint);
  color: var(--muted);
}

.top-search input {
  flex: 1;
  min-width: 0;
  border: 0;
  background: transparent;
  font-family: inherit;
  font-size: 14px;
  color: var(--ink);
}

.top-search input::placeholder { color: var(--muted-2); }
.top-search input:focus { outline: none; }
.top-search:focus-within { border-color: var(--brand); background: var(--surface); }

.kbd-chip { display: flex; gap: 4px; }

.kbd-chip span {
  display: grid;
  place-items: center;
  min-width: 22px;
  height: 22px;
  padding: 0 5px;
  border-radius: 6px;
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--muted);
  font-size: 11px;
  font-weight: 600;
}

.top-right { margin-left: auto; display: flex; align-items: center; gap: 8px; }

.icon-btn {
  position: relative;
  display: grid;
  place-items: center;
  width: 40px;
  height: 40px;
  border: 1px solid transparent;
  border-radius: 10px;
  background: transparent;
  color: var(--ink-2);
}

.icon-btn:hover { background: var(--mist); }
.icon-btn.has-dot::after {
  content: "";
  position: absolute;
  top: 9px;
  right: 10px;
  width: 8px;
  height: 8px;
  border-radius: 999px;
  background: var(--error);
  border: 2px solid var(--surface);
}

.persona-chip {
  display: flex;
  align-items: center;
  gap: 10px;
  height: 48px;
  padding: 0 10px 0 6px;
  border: 1px solid transparent;
  border-radius: 12px;
  background: transparent;
  text-align: left;
}

.persona-chip:hover { background: var(--mist); }

.avatar {
  display: grid;
  place-items: center;
  width: 36px;
  height: 36px;
  border-radius: 999px;
  background: var(--brand-soft);
  color: var(--brand);
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.02em;
}

.persona-chip .p-text { display: block; }
.persona-chip .p-name { display: block; font-size: 14px; font-weight: 600; line-height: 1.25; color: var(--ink); }
.persona-chip .p-sub { display: block; font-size: 12px; line-height: 1.25; color: var(--muted); }
.persona-chip .ico-chevron { color: var(--muted); }

.pop {
  position: absolute;
  top: calc(var(--top-h) - 6px);
  right: 24px;
  z-index: 50;
  width: 300px;
  padding: 8px;
  border-radius: var(--radius);
  border: 1px solid var(--border);
  background: var(--surface);
  box-shadow: var(--shadow-md);
}

.pop[hidden] { display: none; }
.pop .pop-title {
  padding: 8px 10px 6px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--muted-2);
}

.pop .pop-item {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 9px 10px;
  border-radius: 10px;
  font-size: 14px;
  color: var(--ink-2);
}

.pop .pop-item:hover { background: var(--mist); }
.pop .pop-item .ico { color: var(--muted); }
.pop .pop-item > span { display: block; min-width: 0; }
.pop .pop-item > span > span { display: block; }
.pop .pop-item .p-sub { display: block; font-size: 12px; color: var(--muted); }
.pop .pop-sep { height: 1px; margin: 6px 8px; background: var(--border); }

.pop .note-item { display: flex; gap: 10px; padding: 10px; border-radius: 10px; }
.pop .note-item:hover { background: var(--mist); }
.pop .note-item > span:not(.act-tile) { display: block; min-width: 0; }
.pop .note-item .note-title { display: block; font-size: 13px; font-weight: 600; }
.pop .note-item .note-sub { display: block; font-size: 12px; color: var(--muted); }
.pop .note-item .note-time { margin-left: auto; font-size: 12px; color: var(--muted-2); white-space: nowrap; }

.hamburger { display: none; }

/* ---- 4. Page header: title, lede, date chip, split button ------------- */

.page-head {
  display: flex;
  align-items: flex-start;
  gap: 20px;
  flex-wrap: wrap;
  margin-bottom: 22px;
}

.page-head .head-text { min-width: 0; flex: 1; }

.page-head h1 {
  font-size: 28px;
  font-weight: 700;
  letter-spacing: -0.03em;
  color: var(--ink);
}

.page-head .lede { margin-top: 6px; font-size: 15px; color: var(--muted); }

.page-head .head-side {
  display: flex;
  align-items: center;
  gap: 16px;
  padding-top: 4px;
}

.date-chip { display: flex; align-items: center; gap: 8px; font-size: 14px; color: var(--muted); }
.date-chip .ico { color: var(--muted-2); }

.head-quote {
  position: relative;
  font-family: var(--font-display);
  font-size: 15px;
  font-style: italic;
  color: var(--ink-2);
  padding-bottom: 8px;
}

/* The mockup underlines only the opening third of the line, not all of it. */
.head-quote::after {
  content: "";
  position: absolute;
  left: 0;
  bottom: 0;
  width: 36%;
  height: 2px;
  border-radius: 2px;
  background: var(--brand);
}

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  height: 44px;
  padding: 0 18px;
  border-radius: 10px;
  border: 1px solid transparent;
  font-size: 14px;
  font-weight: 600;
  white-space: nowrap;
}

.btn-primary { background: var(--brand); color: var(--surface); }
.btn-primary:hover { background: var(--brand-hover); }
.btn-dark { background: var(--ink); color: var(--surface); }
.btn-dark:hover { background: var(--ink-2); }
.btn-ghost { background: var(--surface); border-color: var(--border-strong); color: var(--ink-2); }
.btn-ghost:hover { border-color: var(--brand); color: var(--brand); }
.btn-sm { height: 34px; padding: 0 12px; font-size: 13px; border-radius: 8px; }

.btn-split {
  display: inline-flex;
  align-items: stretch;
  border-radius: 10px;
  overflow: hidden;
  background: var(--brand);
  color: var(--surface);
}

.btn-split > .btn-split-main {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  height: 44px;
  padding: 0 18px;
  border: 0;
  background: transparent;
  color: inherit;
  font-size: 14px;
  font-weight: 600;
}

.btn-split > .btn-split-more {
  display: grid;
  place-items: center;
  width: 44px;
  border: 0;
  border-left: 1px solid color-mix(in srgb, var(--surface) 25%, transparent);
  background: transparent;
  color: inherit;
}

.btn-split:hover { background: var(--brand-hover); }

/* ---- 5. Cards and grids: .card, .grid-4, .grid-main-rail, .grid-2 ----- */

.card {
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
  box-shadow: var(--shadow-sm);
}

.card > .card-head {
  display: flex;
  align-items: flex-start;
  flex-wrap: wrap;
  gap: 16px;
  padding: 18px 20px 14px;
}

/* No min-width: 0 here. The text block keeps its min-content width so that
   in a narrow card the action wraps to the next line instead of squeezing
   the title. */
.card > .card-head .ch-text { flex: 1 1 auto; }
/* A card title is a name, not a sentence: in a narrow card the View all
   action wraps under it rather than squeezing it onto two lines. */
.card > .card-head h3 { font-size: 17px; font-weight: 700; white-space: nowrap; }
.card > .card-head .ch-sub { margin-top: 3px; font-size: 13px; color: var(--muted); }
.card > .card-head .ch-actions { display: flex; align-items: center; gap: 10px; margin-left: auto; }
.card > .card-body { padding: 0 20px 20px; }
.card.is-tight > .card-body { padding: 0; }
.card.is-tight > .card-head { padding-bottom: 12px; }

.grid-4 { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 16px; }
.grid-3 { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 16px; }
.grid-2 { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 16px; }
.grid-main-rail { display: grid; grid-template-columns: minmax(0, 1fr) 340px; gap: 16px; align-items: start; }
/* An explicit track: without it the implicit `auto` column is sized to the
   widest child's min-content, and a wide table pushes the column past the
   rail instead of scrolling inside its own box. */
.stack { display: grid; grid-template-columns: minmax(0, 1fr); gap: 16px; }

@media (max-width: 1240px) {
  .grid-main-rail { grid-template-columns: minmax(0, 1fr); }
  .grid-4 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 720px) {
  .grid-4, .grid-3, .grid-2 { grid-template-columns: minmax(0, 1fr); }
}

/* ---- 6. Stat cards: icon tile tones, value, delta --------------------- */

.stat {
  padding: 20px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
  box-shadow: var(--shadow-sm);
}

.stat .stat-row { display: flex; align-items: center; gap: 14px; }

.stat .stat-tile {
  display: grid;
  place-items: center;
  width: 48px;
  height: 48px;
  border-radius: var(--radius);
  flex: none;
}

.stat .stat-row > span:last-child { display: block; min-width: 0; }

.stat .stat-value {
  display: block;
  font-family: var(--font-display);
  font-size: 28px;
  font-weight: 700;
  letter-spacing: -0.03em;
  line-height: 1.1;
  color: var(--ink);
}

.stat .stat-label { display: block; font-size: 14px; color: var(--muted); }
.stat .stat-delta { display: flex; align-items: center; gap: 6px; margin-top: 14px; font-size: 13px; font-weight: 500; }

.tone-brand .stat-tile, .tile-brand { background: var(--tone-brand-bg); color: var(--tone-brand-ink); }
.tone-ok .stat-tile, .tile-ok { background: var(--tone-ok-bg); color: var(--tone-ok-ink); }
.tone-warn .stat-tile, .tile-warn { background: var(--tone-warn-bg); color: var(--tone-warn-ink); }
.tone-info .stat-tile, .tile-info { background: var(--tone-info-bg); color: var(--tone-info-ink); }
.tone-error .stat-tile, .tile-error { background: var(--tone-error-bg); color: var(--tone-error-ink); }

.tone-brand .stat-delta { color: var(--tone-brand-ink); }
.tone-ok .stat-delta { color: var(--tone-ok-ink); }
.tone-warn .stat-delta { color: var(--tone-warn-ink); }
.tone-info .stat-delta { color: var(--tone-info-ink); }
.tone-error .stat-delta { color: var(--tone-error-ink); }

/* ---- 7. Tables: .tbl, sticky head, row hover, actions, pagination ----- */

.tbl-wrap { width: 100%; overflow-x: auto; }

.tbl { width: 100%; border-collapse: collapse; font-size: 14px; }

.tbl thead th {
  position: sticky;
  top: 0;
  z-index: 1;
  padding: 10px 16px;
  background: var(--surface);
  border-bottom: 1px solid var(--border);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--muted);
  text-align: left;
  white-space: nowrap;
}

.tbl tbody td {
  height: 56px;
  padding: 8px 16px;
  border-bottom: 1px solid var(--border);
  color: var(--ink-2);
  vertical-align: middle;
  white-space: nowrap;
}

/* Rows are a fixed 56px, so a cell wraps only when it asks to. */
.tbl .cell-wrap { white-space: normal; }

.tbl tbody tr:last-child td { border-bottom: 0; }
.tbl tbody tr:hover td { background: var(--mist); }
.tbl .ta-right { text-align: right; }
.tbl .ta-center { text-align: center; }
.tbl .cell-ref { color: var(--brand); font-weight: 600; white-space: nowrap; }
.tbl .cell-strong { display: block; font-weight: 600; line-height: 1.35; color: var(--ink); }
.tbl .cell-sub { display: block; font-size: 13px; line-height: 1.35; color: var(--muted); }
.tbl .cell-nowrap { white-space: nowrap; }
.tbl .tbl-empty td { height: 96px; text-align: center; color: var(--muted); }

.row-actions {
  display: grid;
  place-items: center;
  width: 32px;
  height: 32px;
  border: 0;
  border-radius: 8px;
  background: transparent;
  color: var(--muted);
}

.row-actions:hover { background: var(--brand-soft); color: var(--brand); }

.tbl-foot {
  display: flex;
  align-items: center;
  gap: 16px;
  flex-wrap: wrap;
  padding: 14px 20px;
  border-top: 1px solid var(--border);
  font-size: 13px;
  color: var(--muted);
}

.pager { margin-left: auto; display: flex; flex-wrap: wrap; gap: 6px; }

.pager button {
  display: grid;
  place-items: center;
  width: 32px;
  height: 32px;
  border-radius: 8px;
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--ink-2);
  font-size: 13px;
  font-weight: 600;
}

.pager button:hover { border-color: var(--brand); color: var(--brand); }
.pager button.is-active { background: var(--ink); border-color: var(--ink); color: var(--surface); }

/* ---- 8. Badges and insurer marks -------------------------------------- */

.badge {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: 24px;
  padding: 0 10px;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 600;
  white-space: nowrap;
}

.badge.t-brand { background: var(--tone-brand-bg); color: var(--tone-brand-ink); }
.badge.t-ok { background: var(--tone-ok-bg); color: var(--tone-ok-ink); }
.badge.t-info { background: var(--tone-info-bg); color: var(--tone-info-ink); }
.badge.t-warn { background: var(--tone-warn-bg); color: var(--tone-warn-ink); }
.badge.t-error { background: var(--tone-error-bg); color: var(--tone-error-ink); }
.badge.t-muted { background: var(--tone-muted-bg); color: var(--tone-muted-ink); }

/* The insurers' marks. .ins-logo itself -- the sizing, and the optical
   correction that stops Sicom reading large and Eagle small -- is described
   in css/tego.css, which every console page loads before this file. All a
   context here does is set --ins-h.

   The default is small on purpose: most of these sit in table cells. The
   width cap matters more than the height, because Sanlam Allianz is a
   two-name lockup at 8.6:1 and is the one mark that will shove a column
   wider than its share if left alone. */
.ins-mark {
  --ins-h: 20px;
  display: inline-flex;
  align-items: center;
  gap: 10px;
  min-width: 0;
  max-width: 132px;
}

/* Only reached when insurerOf() finds nothing -- a file pointing at an
   insurer that is no longer in the list. */
.ins-mark .mark-name { font-weight: 600; color: var(--ink); }

/* ---- 9. Charts: donut + legend, bar list ------------------------------ */

/* The ring and its legend sit side by side at every console width: stacked,
   the legend left a card's worth of dead space under the ring and dragged
   the chart card beside it to the same height. */
.donut { display: flex; align-items: center; gap: 16px; flex-wrap: nowrap; }
.donut .donut-svg { position: relative; flex: none; width: 136px; height: 136px; }
.donut .donut-svg svg { width: 136px; height: 136px; }

.donut .donut-centre {
  position: absolute;
  inset: 0;
  display: grid;
  place-content: center;
  text-align: center;
}

.donut .donut-total {
  font-family: var(--font-display);
  font-size: 26px;
  font-weight: 700;
  letter-spacing: -0.03em;
  color: var(--ink);
}

.donut .donut-caption { font-size: 12px; color: var(--muted); }
.donut .donut-legend { flex: 1; min-width: 0; display: grid; gap: 8px; }
.donut .legend-row { display: flex; align-items: center; gap: 8px; font-size: 13px; color: var(--ink-2); }
.donut .legend-row > span:nth-child(2) { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.donut .legend-dot { width: 8px; height: 8px; border-radius: 999px; flex: none; }
.donut .legend-count { margin-left: auto; font-weight: 600; }

.bar-list { display: grid; gap: 14px; }
.bar-list .bar-row { display: flex; align-items: center; gap: 12px; font-size: 14px; }
.bar-list .bar-label { width: 148px; flex: none; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.bar-list .bar-track {
  flex: 1;
  height: 10px;
  border-radius: 999px;
  background: var(--brand-tint);
  overflow: hidden;
}

.bar-list .bar-fill { display: block; height: 100%; border-radius: 999px; background: var(--brand); }
.bar-list .bar-count { width: 32px; text-align: right; font-weight: 600; color: var(--ink); }

/* ---- 10. Activity list, empty state, help/upload promo cards ---------- */

.act-list { display: grid; }
.act-list .act-row { display: flex; align-items: center; gap: 12px; padding: 12px 0; border-bottom: 1px solid var(--border); }
.act-list .act-row:last-child { border-bottom: 0; }

/* Not scoped to .act-list: the notification dropdown reuses the same tile. */
.act-tile {
  display: grid;
  place-items: center;
  width: 36px;
  height: 36px;
  border-radius: 999px;
  flex: none;
}

.act-list .act-text { min-width: 0; flex: 1; }
.act-list .act-text { display: block; }
.act-list .act-title { display: block; font-size: 14px; font-weight: 600; color: var(--ink); }
.act-list .act-sub { display: block; font-size: 13px; color: var(--muted); }
.act-list .act-time { font-size: 13px; color: var(--muted-2); white-space: nowrap; }

.empty {
  display: grid;
  justify-items: center;
  gap: 8px;
  padding: 56px 24px;
  border: 1px dashed var(--border-strong);
  border-radius: var(--radius);
  background: var(--surface);
  text-align: center;
}

.empty .empty-tile {
  display: grid;
  place-items: center;
  width: 48px;
  height: 48px;
  border-radius: var(--radius);
  background: var(--brand-soft);
  color: var(--brand);
  margin-bottom: 4px;
}

.empty h3 { font-size: 18px; font-weight: 700; }
.empty p { font-size: 14px; color: var(--muted); max-width: 46ch; }

.promo { padding: 20px; border-radius: var(--radius); background: var(--brand-tint); }

.promo .promo-tile {
  display: grid;
  place-items: center;
  width: 48px;
  height: 48px;
  border-radius: var(--radius);
  background: var(--surface);
  color: var(--brand);
  margin-bottom: 14px;
}

.promo h3 { font-size: 17px; font-weight: 700; margin-bottom: 6px; }
.promo p { font-size: 13px; color: var(--muted); line-height: 1.5; }
.promo .btn, .promo .btn-outline-full { margin-top: 14px; width: 100%; }

/* ---- 11. Forms, drawer, tabs, toast, offer cards ---------------------- */

/* align-content keeps a short field from stretching its input to match a
   taller neighbour in the same grid row. */
.field { display: grid; gap: 6px; align-content: start; margin-bottom: 14px; }
.field label { font-size: 13px; font-weight: 600; color: var(--ink-2); }

.field input,
.field select,
.field textarea {
  width: 100%;
  min-height: 42px;
  padding: 10px 12px;
  border: 1px solid var(--border-strong);
  border-radius: 10px;
  background: var(--surface);
  font-family: inherit;
  font-size: 14px;
  color: var(--ink);
}

.field textarea { min-height: 96px; resize: vertical; }
.field input:focus, .field select:focus, .field textarea:focus { outline: none; border-color: var(--brand); }
.field .hint { font-size: 12px; color: var(--muted); }

.drawer-scrim {
  position: fixed;
  inset: 0;
  z-index: 70;
  background: color-mix(in srgb, var(--ink) 38%, transparent);
}

.drawer {
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  z-index: 71;
  width: min(440px, 100%);
  display: flex;
  flex-direction: column;
  background: var(--surface);
  border-left: 1px solid var(--border);
  box-shadow: var(--shadow-lg);
  animation: drawer-in 0.22s var(--ease);
}

@keyframes drawer-in { from { transform: translateX(24px); opacity: 0; } to { transform: none; opacity: 1; } }

@media (prefers-reduced-motion: reduce) {
  .drawer { animation: none; }
}

.drawer .drawer-head {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 18px 20px;
  border-bottom: 1px solid var(--border);
}

.drawer .drawer-head h3 { flex: 1; font-size: 17px; font-weight: 700; }
.drawer .drawer-body { flex: 1; overflow-y: auto; padding: 20px; }
.drawer .drawer-foot { display: flex; gap: 10px; padding: 16px 20px; border-top: 1px solid var(--border); }
.drawer .drawer-foot .btn { flex: 1; }

.drawer .drawer-done {
  display: grid;
  justify-items: center;
  gap: 10px;
  padding: 40px 20px;
  text-align: center;
}

.drawer .drawer-done .done-tile {
  display: grid;
  place-items: center;
  width: 52px;
  height: 52px;
  border-radius: 999px;
  background: var(--tone-ok-bg);
  color: var(--tone-ok-ink);
}

.drawer .drawer-done p { font-size: 14px; color: var(--muted); }

.tabs {
  display: flex;
  gap: 6px;
  padding: 5px;
  border-radius: var(--radius);
  background: var(--brand-tint);
}

.tabs button {
  flex: 1;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  height: 44px;
  padding: 0 12px;
  border: 0;
  border-radius: 10px;
  background: transparent;
  color: var(--muted);
  font-size: 14px;
  font-weight: 500;
}

.tabs button:hover { color: var(--ink-2); }

.tabs button.is-active {
  background: var(--surface);
  color: var(--brand);
  font-weight: 600;
  box-shadow: var(--shadow-sm);
}

.toast-wrap {
  position: fixed;
  left: 50%;
  bottom: 28px;
  z-index: 90;
  transform: translateX(-50%);
  display: grid;
  gap: 8px;
  justify-items: center;
}

.toast {
  padding: 11px 18px;
  border-radius: 999px;
  background: var(--ink);
  color: var(--surface);
  font-size: 13px;
  font-weight: 500;
  box-shadow: var(--shadow-md);
  animation: toast-in 0.2s var(--ease);
}

@keyframes toast-in { from { transform: translateY(8px); opacity: 0; } to { transform: none; opacity: 1; } }

.offer {
  position: relative;
  display: flex;
  flex-direction: column;
  padding: 18px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
  box-shadow: var(--shadow-sm);
}

.offer.is-best { border: 2px solid var(--brand); }

.offer .offer-tag {
  position: absolute;
  top: -1px;
  right: -1px;
  padding: 5px 12px;
  border-radius: 0 var(--radius) 0 var(--radius);
  background: var(--ink);
  color: var(--surface);
  font-size: 12px;
  font-weight: 600;
}

.offer .offer-plan { margin-top: 12px; font-size: 15px; font-weight: 600; color: var(--ink); }
.offer .offer-price { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; margin: 8px 0 14px; }

.offer .offer-amount {
  font-family: var(--font-display);
  font-size: 28px;
  font-weight: 700;
  letter-spacing: -0.03em;
  color: var(--ink);
}

.offer .offer-per { font-size: 14px; color: var(--muted); }
.offer .offer-benefits { display: grid; gap: 9px; }
.offer .offer-benefits li { display: flex; align-items: flex-start; gap: 8px; font-size: 13px; color: var(--ink-2); }
.offer .offer-benefits .ico { color: var(--ok); margin-top: 1px; }
.offer .offer-sep { height: 1px; margin: 14px 0; background: var(--border); }
.offer .offer-excess { display: flex; align-items: center; gap: 12px; font-size: 13px; color: var(--muted); }
.offer .offer-excess strong { margin-left: auto; color: var(--ink); font-size: 14px; }
.offer .btn { margin-top: 14px; width: 100%; }

/* ---- 12. Responsive: 1100px icon rail, 800px off-canvas --------------- */

@media (max-width: 1100px) {
  .app-shell { --side-w: 64px; }
  .side { padding: 18px 8px 14px; align-items: stretch; }
  .side-brand { padding: 0 0 14px; display: grid; justify-items: center; }
  .side-brand img { width: 44px; object-fit: contain; }
  .side-brand .tag { display: none; }
  .side-nav .nav-item { justify-content: center; padding: 0; gap: 0; }
  .side-nav .nav-label { display: none; }
  .side-nav .nav-item.is-active::before { left: -8px; }
  .side-divider { margin: 14px 6px; }

  .side-nav .count-pill {
    position: absolute;
    top: 4px;
    right: 4px;
    min-width: 18px;
    height: 18px;
    padding: 0 5px;
    font-size: 11px;
    border: 1px solid var(--border);
  }

  .side-nav .nav-item[data-tip]:hover::after {
    content: attr(data-tip);
    position: absolute;
    left: calc(100% + 10px);
    top: 50%;
    transform: translateY(-50%);
    z-index: 60;
    padding: 6px 10px;
    border-radius: 8px;
    background: var(--ink);
    color: var(--surface);
    font-size: 12px;
    font-weight: 500;
    white-space: nowrap;
    pointer-events: none;
  }

  .side-help { display: none; }
}

@media (max-width: 800px) {
  .app-shell { grid-template-columns: minmax(0, 1fr); --side-w: 244px; }

  .side {
    position: fixed;
    left: 0;
    top: 0;
    width: var(--side-w);
    padding: 18px 12px 16px;
    transform: translateX(-100%);
    transition: transform 0.24s var(--ease);
  }

  /* The shadow only while the nav is out: parked off the screen, its 80px
     blur shaded the left edge of every page. */
  .app-shell.nav-open .side { transform: none; box-shadow: var(--shadow-lg); }
  .side-brand { display: block; padding: 4px 10px 18px; }
  .side-brand img { width: 108px; }
  .side-brand .tag { display: block; }
  .side-nav .nav-item { justify-content: flex-start; padding: 0 12px; gap: 12px; }
  .side-nav .nav-label { display: block; }
  .side-nav .count-pill { position: static; height: 20px; min-width: 22px; padding: 0 7px; font-size: 12px; border: 0; }
  .side-nav .nav-item[data-tip]:hover::after { content: none; }
  .side-help { display: block; }

  .hamburger { display: grid; }
  .top-search .kbd-chip { display: none; }
  .app-main { padding: 18px; }
  .persona-chip .p-text { display: none; }
  .persona-chip .ico-chevron { display: none; }
  .pop { right: 12px; width: min(300px, calc(100vw - 24px)); }

  .app-shell.nav-open .nav-scrim {
    display: block;
    position: fixed;
    inset: 0;
    z-index: 39;
    background: color-mix(in srgb, var(--ink) 38%, transparent);
  }

  /* On a phone the card is narrow enough that a long title has to wrap, and
     the ring has the room to keep its legend under it. */
  .card > .card-head h3 { white-space: normal; }
  .donut { flex-wrap: wrap; justify-content: center; }
  .donut .donut-legend { min-width: 200px; }
  .page-head .head-side { width: 100%; }
}

/* ---- Persona picker (/app) --------------------------------------------- */

.picker {
  min-height: 100vh;
  display: grid;
  place-items: center;
  padding: 48px 24px;
  background: var(--bg);
  font-family: var(--font-body);
  font-size: 14px;
  color: var(--ink);
}

.picker a { text-decoration: none; color: inherit; }
.picker .picker-inner { width: 100%; max-width: 880px; text-align: center; }
.picker img.picker-logo { width: 132px; height: auto; margin: 0 auto 22px; }

.picker h1 {
  font-family: var(--font-display);
  font-size: 34px;
  font-weight: 700;
  letter-spacing: -0.03em;
  line-height: 1.1;
  margin: 0;
  color: var(--ink);
}

.picker .picker-lede { margin: 10px auto 0; max-width: 54ch; font-size: 15px; color: var(--muted); }

.picker .picker-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 16px;
  margin-top: 32px;
  text-align: left;
}

.picker .picker-card {
  display: flex;
  flex-direction: column;
  padding: 22px;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--surface);
  box-shadow: var(--shadow-sm);
  transition: border-color 0.16s var(--ease), box-shadow 0.16s var(--ease), transform 0.16s var(--ease);
}

.picker .picker-card:hover { border-color: var(--brand); box-shadow: var(--shadow-md); transform: translateY(-2px); }
.picker .picker-card .pc-top { display: flex; align-items: center; gap: 12px; }

.picker .picker-card .avatar {
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  border-radius: 999px;
  background: var(--brand-soft);
  color: var(--brand);
  font-size: 15px;
  font-weight: 700;
}

.picker .picker-card h2 { font-family: var(--font-display); font-size: 18px; font-weight: 700; margin: 0; letter-spacing: -0.02em; }
.picker .picker-card .pc-top > span:not(.avatar) { display: block; min-width: 0; }
.picker .picker-card .pc-sub { display: block; font-size: 13px; color: var(--muted); }
.picker .picker-card .pc-desc { margin: 14px 0 18px; font-size: 14px; color: var(--muted); line-height: 1.5; }
.picker .picker-card .btn { margin-top: auto; align-self: flex-start; }
.picker .picker-note { margin-top: 26px; font-size: 13px; color: var(--muted-2); }

@media (max-width: 720px) {
  .picker .picker-grid { grid-template-columns: minmax(0, 1fr); }
}

/* ---- 13. Ops console: filters, data grid, timeline, docs, charts ------
   Components the ops pages need that the shell did not already carry.
   Every colour is still a tego.css token. */

.filters { display: grid; gap: 12px; }
.filter-row { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; }
.filter-pills { display: flex; flex-wrap: wrap; gap: 6px; }

.f-pill {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  height: 34px;
  padding: 0 13px;
  border-radius: 999px;
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--ink-2);
  font-size: 13px;
  font-weight: 500;
  transition: border-color 0.16s var(--ease), color 0.16s var(--ease);
}

.f-pill:hover { border-color: var(--brand); color: var(--brand); }
.f-pill.is-active { background: var(--brand); border-color: var(--brand); color: var(--surface); }
.f-pill .f-pill-n { font-weight: 700; opacity: 0.62; }

.inline-select {
  flex: none;
  width: auto;
  height: 40px;
  padding: 0 34px 0 12px;
  border-radius: 10px;
  border: 1px solid var(--border-strong);
  background: var(--surface);
  color: var(--ink);
  font-family: inherit;
  font-size: 14px;
}

.inline-select:focus { outline: none; border-color: var(--brand); }

.search-box {
  display: flex;
  align-items: center;
  gap: 8px;
  flex: 1;
  min-width: 220px;
  max-width: 380px;
  height: 40px;
  padding: 0 12px;
  border-radius: 10px;
  border: 1px solid var(--border);
  background: var(--mist);
}

.search-box .ico { color: var(--muted); }
.search-box input { flex: 1; min-width: 0; border: 0; background: transparent; font: inherit; color: var(--ink); }
.search-box input:focus { outline: none; }
.search-box:focus-within { border-color: var(--brand); background: var(--surface); }

.row-check { width: 16px; height: 16px; accent-color: var(--brand); }

.row-menu {
  position: fixed;
  z-index: 70;
  min-width: 186px;
  padding: 6px;
  display: grid;
  gap: 2px;
  border-radius: var(--radius);
  border: 1px solid var(--border);
  background: var(--surface);
  box-shadow: var(--shadow-md);
}

.row-menu button {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: 9px 10px;
  border: 0;
  border-radius: 8px;
  background: transparent;
  text-align: left;
  font-family: inherit;
  font-size: 14px;
  color: var(--ink-2);
}

.row-menu button:hover { background: var(--mist); }
.row-menu .ico { color: var(--muted); }

.cell-user { display: flex; align-items: center; gap: 11px; }

.cell-user .avatar-xs {
  display: grid;
  place-items: center;
  width: 34px;
  height: 34px;
  flex: none;
  border-radius: 999px;
  background: var(--brand-soft);
  color: var(--brand);
  font-size: 12px;
  font-weight: 700;
}

.mono { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 13px; color: var(--ink-2); }

.data-grid { display: grid; }
.data-grid > div { display: flex; align-items: baseline; gap: 16px; padding: 11px 0; border-bottom: 1px solid var(--border); }
.data-grid > div:last-child { border-bottom: 0; }
.data-grid dt { width: 116px; flex: none; font-size: 13px; color: var(--muted); }
.data-grid dd { flex: 1; min-width: 0; margin: 0; font-size: 14px; font-weight: 500; color: var(--ink); }
.data-grid dd a { color: var(--brand); font-weight: 600; }
.data-grid dd a:hover { text-decoration: underline; }

.timeline { display: grid; }
.timeline .tl-step { display: grid; grid-template-columns: 26px minmax(0, 1fr); gap: 14px; }
.timeline .tl-rail { display: grid; grid-template-rows: auto 1fr; justify-items: center; }

.timeline .tl-dot {
  display: grid;
  place-items: center;
  width: 26px;
  height: 26px;
  border-radius: 999px;
  border: 2px solid var(--border-strong);
  background: var(--surface);
  color: var(--muted-2);
}

.timeline .tl-line { width: 2px; min-height: 20px; background: var(--border); }
.timeline .tl-step:last-child .tl-line { background: transparent; min-height: 0; }
.timeline .tl-body { padding: 2px 0 20px; }
.timeline .tl-step:last-child .tl-body { padding-bottom: 0; }
.timeline .tl-title { display: block; font-size: 14px; font-weight: 600; color: var(--ink-2); }
.timeline .tl-date { display: block; margin-top: 2px; font-size: 13px; color: var(--muted); }
.timeline .is-done .tl-dot { border-color: var(--ok); background: var(--ok); color: var(--surface); }
.timeline .is-current .tl-dot { border-color: var(--brand); background: var(--brand); color: var(--surface); }
.timeline .is-current .tl-title { color: var(--brand); }
.timeline .is-terminal .tl-dot { border-color: var(--error); background: var(--error); color: var(--surface); }
.timeline .is-terminal .tl-title { color: var(--error); }
.timeline .is-pending .tl-title { color: var(--muted-2); }

.doc-list { display: grid; }
.doc-list .doc-row { display: flex; align-items: center; gap: 12px; padding: 12px 0; border-bottom: 1px solid var(--border); }
.doc-list .doc-row:last-child { border-bottom: 0; }

.doc-list .doc-tile {
  display: grid;
  place-items: center;
  width: 34px;
  height: 34px;
  flex: none;
  border-radius: 9px;
  background: var(--brand-soft);
  color: var(--brand);
}

.doc-list .doc-text { flex: 1; min-width: 0; }
.doc-list .doc-name { display: block; font-size: 14px; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.doc-list .doc-sub { display: block; font-size: 13px; color: var(--muted); }

.note-card {
  padding: 20px;
  border-radius: var(--radius);
  border: 1px solid var(--border);
  background: var(--surface);
  box-shadow: var(--shadow-sm);
}

.note-card .note-tile {
  display: grid;
  place-items: center;
  width: 36px;
  height: 36px;
  border-radius: 999px;
  background: var(--brand-soft);
  color: var(--brand);
  margin-bottom: 12px;
}

.note-card h3 { font-size: 15px; font-weight: 700; margin-bottom: 4px; }
.note-card p { font-size: 13px; color: var(--muted); line-height: 1.5; }
.note-card .btn, .note-card .btn-outline-full { margin-top: 14px; width: 100%; }

.card-actions { display: grid; gap: 10px; }
.card-actions .btn { width: 100%; }
.form-actions { display: flex; gap: 10px; margin-top: 4px; }
.btn[disabled] { opacity: 0.45; cursor: not-allowed; }
.btn[disabled]:hover { background: var(--surface); border-color: var(--border-strong); color: var(--ink-2); }

.ins-head { display: flex; align-items: center; gap: 12px; }
/* The insurer's own page. This is the one place the mark is the heading,
   so it gets the room to be read as a logo rather than a row label. */
.ins-head .ins-mark { --ins-h: 40px; max-width: 260px; }
.ins-head .ins-mark .mark-name { font-family: var(--font-display); font-size: 18px; font-weight: 700; }
.ins-mail { margin-top: 12px; font-size: 13px; color: var(--muted); }
.ins-stats { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 10px; margin: 16px 0 12px; }
.ins-stats .n { display: block; font-family: var(--font-display); font-size: 21px; font-weight: 700; color: var(--ink); white-space: nowrap; }
.ins-stats .n-sm { font-size: 16px; }
.ins-stats .l { display: block; font-size: 12px; color: var(--muted); }
.ins-note { font-size: 12px; color: var(--muted-2); }
.ins-actions { display: flex; gap: 10px; margin-top: 16px; }
.ins-actions .btn { flex: 1; justify-content: center; }

.chart svg { display: block; width: 100%; height: auto; }
.chart .c-bar { fill: var(--brand); }
.chart .c-value { fill: var(--ink); font-family: var(--font-display); font-size: 14px; font-weight: 700; text-anchor: middle; }
.chart .c-month { fill: var(--muted); font-size: 12px; text-anchor: middle; }
.chart .c-axis { stroke: var(--border); stroke-width: 1; }

.bar-list.is-wide .bar-count { width: 92px; }
.bar-list.is-wide .bar-label { width: 110px; }

.funnel { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }

.funnel .fn-stage {
  flex: 1;
  min-width: 130px;
  padding: 20px 12px;
  border-radius: var(--radius);
  background: var(--brand-tint);
  text-align: center;
}

.funnel .fn-n { display: block; font-family: var(--font-display); font-size: 30px; font-weight: 700; color: var(--ink); }
.funnel .fn-l { display: block; margin-top: 4px; font-size: 13px; color: var(--muted); }
.funnel .fn-conv { flex: none; display: grid; justify-items: center; gap: 2px; padding: 0 8px; font-size: 12px; color: var(--muted); }
.funnel .fn-pct { font-size: 15px; font-weight: 700; color: var(--brand); }
.funnel .fn-conv .ico { color: var(--muted-2); }

.share-bar { display: flex; align-items: center; gap: 10px; }
.share-bar .track { flex: 1; min-width: 56px; height: 6px; border-radius: 999px; background: var(--mist); }
.share-bar .fill { display: block; height: 100%; border-radius: 999px; background: var(--brand); }
.share-bar .pct { width: 40px; flex: none; text-align: right; font-size: 13px; color: var(--muted); }

.check-cell { display: grid; place-items: center; }
.check-cell input { width: 18px; height: 18px; accent-color: var(--brand); }

.note-log { display: grid; gap: 10px; margin-top: 14px; }
.note-log .nl-row { padding: 12px; border-radius: 10px; background: var(--mist); }
.note-log .nl-meta { display: block; margin-bottom: 4px; font-size: 12px; color: var(--muted); }
.note-log .nl-body { font-size: 14px; color: var(--ink-2); line-height: 1.5; }

/* .queue-wide is defined once, in section 13b, where its gutters and its
   client-cell width were measured together. Two blocks setting the same
   max-width at the same specificity only differed by source order. */

.tbl .cell-client { display: block; max-width: 178px; }
.tbl .cell-client .cell-strong,
.tbl .cell-client .cell-sub { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.queue-compact .tbl { font-size: 13px; }
.queue-compact .tbl thead th,
.queue-compact .tbl tbody td { padding-left: 6px; padding-right: 6px; }
.queue-compact .tbl thead th:first-child,
.queue-compact .tbl tbody td:first-child { padding-left: 16px; }
.queue-compact .tbl thead th:last-child,
.queue-compact .tbl tbody td:last-child { padding-right: 16px; }
.queue-compact .ins-mark { gap: 7px; --ins-h: 17px; max-width: 104px; }
.queue-compact .badge { padding: 0 8px; font-size: 11px; }
.queue-compact .tbl .cell-client { max-width: 112px; }
.queue-compact .cell-ref { font-size: 12px; }
.queue-compact .cell-sub { font-size: 12px; }

/* The ops dashboard rail is a touch narrower than the client one: the file
   queue beside it carries eight columns and needs the width. */
.grid-main-rail.is-tight { grid-template-columns: minmax(0, 1fr) 312px; }

@media (max-width: 1240px) {
  .grid-main-rail.is-tight { grid-template-columns: minmax(0, 1fr); }
}

/* ---- 14. Client portal: offer grid, product panel, stepper, pay options
   Additive. Every selector below is new to this file; nothing above is
   restructured. The first block exists because /app pages load css/tego.css
   as well, and the public site owns its own `.offer` card: these rules pin
   the console's version so the two cannot fight. -------------------------- */

.app-shell .offer {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 0;
  grid-template-columns: none;
  /* The top band is reserved on every card, not only the best one, so the
     corner tag never lands on an insurer name and the four cards still line
     up row for row. */
  padding: 30px 12px 12px;
  border-radius: var(--radius);
  background: var(--surface);
}

.app-shell .offer.is-best { background: var(--surface); box-shadow: var(--shadow-sm); }
.app-shell .offer .offer-price { flex-direction: row; align-items: baseline; text-align: left; gap: 3px; }
.app-shell .offer .offer-amount { font-size: 21px; }
.app-shell .offer .offer-per { font-size: 12px; }
.app-shell .offer .offer-excess strong { white-space: nowrap; }
.app-shell .offer .ins-mark { --ins-h: 26px; max-width: 170px; }
/* The benefit list takes the slack, so the excess row and the button sit on
   the same line across all four cards however long the benefits run. */
.app-shell .offer .offer-benefits { flex: 1; align-content: start; }

/* The client dashboard's policy table: the ops queue's compact gutters, at
   the console's normal type size. */
.queue-compact.is-client .tbl { font-size: 14px; }
.queue-compact.is-client .tbl .cell-sub { font-size: 13px; }

/* The shell caps the two-line cell at 178px, and the ops queue at 112px, so a
   long client name cannot run away with a column. The client tables have the
   room and every value in them has to be readable whole, so the cap is off. */
.tbl-roomy .tbl .cell-client { max-width: none; }

/* The offers rail is narrower than the shell default so the column beside it
   can hold three offer cards wide enough not to wrap their benefit lines. */
.grid-main-rail.is-offers { grid-template-columns: minmax(0, 1fr) 312px; }

/* And the card around the offer grid keeps a narrower gutter than the rest,
   for the same reason: the grid is the content here, not the frame. */
.app-shell .card.is-offers { padding-left: 10px; padding-right: 10px; }
.card.is-offers > .card-head { padding-left: 12px; padding-right: 12px; }
.card.is-offers > .card-body { padding-left: 10px; padding-right: 10px; }

.offer-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 10px; }
.offer-grid.is-five { grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 8px; }

/* Five across is 30px per card narrower than four, which is exactly enough
   to break `Third-party liability up to Rs 10M` onto a second line. The
   wording is fixed, so the card gives the line the width instead: tighter
   gutters, a tighter check, and one step down in benefit type. */
@media (min-width: 1241px) {
  .app-shell .offer-grid.is-five .offer { padding-left: 8px; padding-right: 8px; }
  .app-shell .offer-grid.is-five .offer-benefits li { gap: 7px; font-size: 12px; }
  .app-shell .offer-grid.is-five .offer-benefits .ico { width: 15px; height: 15px; }
}
.offer-panel { min-width: 0; }

.offer .offer-pill {
  padding: 2px 6px;
  border-radius: 999px;
  background: var(--tone-ok-bg);
  color: var(--tone-ok-ink);
  font-size: 11px;
  font-weight: 600;
  white-space: nowrap;
}

.offer .offer-benefits { list-style: none; margin: 0; padding: 0; }
.offer .btn { justify-content: center; }

/* A stat card that is also a link: the delta reads as the call to action. */
.stat-link { display: block; border-radius: var(--radius); }
.stat-link .stat { height: 100%; transition: border-color 0.16s var(--ease), box-shadow 0.16s var(--ease); }
.stat-link:hover .stat { border-color: var(--brand); box-shadow: var(--shadow-md); }

.stack.is-close { gap: 14px; }

/* A product row inside a table cell: small tinted tile, label over detail. */
.cell-policy { display: flex; align-items: center; gap: 10px; min-width: 0; }

.cell-tile {
  display: grid;
  place-items: center;
  width: 32px;
  height: 32px;
  flex: none;
  border-radius: 9px;
  background: var(--brand-soft);
  color: var(--brand);
}

.cell-offer { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.cell-offer .ins-mark { --ins-h: 18px; max-width: 112px; }
.cell-offer .ins-mark .mark-name { font-weight: 500; font-size: 13px; }

.help-actions { display: flex; gap: 10px; margin-top: 14px; }
.help-actions .btn { flex: 1; justify-content: center; margin-top: 0; }

/* Upcoming renewals, in the rail and on the renewals page. The rail is only
   300px wide, so the row is two explicit lines rather than a wrapping flex
   that leaves the product name broken over two. */
.ren-list { display: grid; }

.ren-row {
  display: grid;
  grid-template-columns: 32px minmax(0, 1fr);
  align-items: center;
  gap: 8px 10px;
  padding: 12px 0;
  border-bottom: 1px solid var(--border);
}

.ren-row:last-child { border-bottom: 0; }
.ren-row .cell-tile { grid-column: 1; grid-row: 1; }
.ren-text { grid-column: 2; grid-row: 1; min-width: 0; }
.ren-row .btn { grid-column: 2; grid-row: 3; justify-self: start; }
.ren-title,
.ren-sub { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ren-title { font-size: 14px; font-weight: 600; color: var(--ink); }
.ren-sub { font-size: 13px; color: var(--muted); }
.ren-when { grid-column: 2; grid-row: 2; display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.ren-date { font-size: 12px; color: var(--muted); white-space: nowrap; }
.ren-head { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-bottom: 4px; }

/* The two-line client cell is styled for tables only; these components reuse
   the same markup outside one. */
.ren-head .cell-client,
.due-row .cell-client { display: block; min-width: 0; flex: 1; }
.ren-head .cell-strong,
.due-row .cell-strong { display: block; font-weight: 600; line-height: 1.35; color: var(--ink); }
.ren-head .cell-sub,
.due-row .cell-sub { display: block; font-size: 13px; line-height: 1.35; color: var(--muted); }
.ren-head .ins-mark { margin-left: auto; }

.pill-days {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 3px 9px;
  border-radius: 999px;
  background: var(--tone-error-bg);
  color: var(--tone-error-ink);
  font-size: 12px;
  font-weight: 600;
  white-space: nowrap;
}

.countdown { display: flex; align-items: baseline; gap: 10px; margin-bottom: 10px; }

.countdown .cd-n {
  font-family: var(--font-display);
  font-size: 38px;
  font-weight: 700;
  line-height: 1;
  letter-spacing: -0.03em;
  color: var(--brand);
}

.countdown .cd-l { font-size: 13px; color: var(--muted); }

.btn-full { width: 100%; justify-content: center; margin-top: 14px; }

.link-danger {
  align-self: start;
  justify-self: start;
  padding: 0;
  border: 0;
  background: none;
  color: var(--error);
  font-size: 13px;
  font-weight: 600;
  opacity: 0.85;
}

.link-danger:hover { opacity: 1; text-decoration: underline; }

.link-brand {
  padding: 0;
  border: 0;
  background: none;
  color: var(--brand);
  font-size: inherit;
  font-weight: 600;
}

.link-brand:hover { text-decoration: underline; }

/* A claim row opens its own history in place, inside the same table. */
.tbl tbody tr.is-open td { background: var(--mist); }
.tbl tbody tr.row-detail td { padding: 16px 18px 18px; background: var(--brand-tint); }
.tbl tbody tr.row-detail:hover td { background: var(--brand-tint); }

.tbl .rd-title {
  display: block;
  margin-bottom: 12px;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--muted);
}

/* The claim wizard's step rail. */
.stepper {
  display: flex;
  gap: 8px;
  margin: 0;
  padding: 5px;
  list-style: none;
  border-radius: var(--radius);
  background: var(--brand-tint);
}

.stepper .step { flex: 1; min-width: 0; }

.stepper .step button {
  width: 100%;
  display: flex;
  align-items: center;
  gap: 10px;
  height: 46px;
  padding: 0 12px;
  border: 0;
  border-radius: 10px;
  background: transparent;
  color: var(--muted);
  font-size: 14px;
  font-weight: 500;
  text-align: left;
}

.stepper .step-n {
  display: grid;
  place-items: center;
  width: 26px;
  height: 26px;
  flex: none;
  border-radius: 999px;
  background: var(--surface);
  color: var(--muted);
  font-size: 13px;
  font-weight: 700;
}

.stepper .step-l { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.stepper .is-current button { background: var(--surface); color: var(--brand); font-weight: 600; box-shadow: var(--shadow-sm); }
.stepper .is-current .step-n { background: var(--brand); color: var(--surface); }
.stepper .is-done button { color: var(--ink-2); }
.stepper .is-done .step-n { background: var(--ok); color: var(--surface); }
.stepper .is-todo button[disabled] { cursor: not-allowed; opacity: 0.75; }

.step-nav { justify-content: flex-end; margin-top: 18px; }

.field-legend { font-size: 13px; font-weight: 600; color: var(--ink-2); }

.radio-row { display: flex; gap: 10px; flex-wrap: wrap; }

.radio-pill {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  height: 42px;
  padding: 0 16px;
  border: 1px solid var(--border-strong);
  border-radius: 10px;
  background: var(--surface);
  font-size: 14px;
  color: var(--ink-2);
  cursor: pointer;
}

/* A radio or a checkbox is an input too, and section 11's .field rule sizes
   text boxes. Controls that are not text boxes opt out here. */
.field .radio-pill input,
.field .check-row input,
.pay-option input {
  width: 17px;
  height: 17px;
  min-height: 0;
  margin: 0;
  padding: 0;
  border: 0;
  border-radius: 0;
  background: none;
}

.radio-pill input { accent-color: var(--brand); }
.radio-pill:has(input:checked) { border-color: var(--brand); background: var(--brand-tint); color: var(--brand); font-weight: 600; }

.check-list { display: grid; gap: 10px; }
.check-row { display: flex; align-items: center; gap: 10px; font-size: 14px; color: var(--ink-2); cursor: pointer; }
.check-row input { width: 17px; height: 17px; accent-color: var(--brand); }

.input-row { display: flex; gap: 10px; align-items: center; }
.input-row input { flex: 1; min-width: 0; }
.input-row .btn { flex: none; }

.inline-label { font-size: 13px; font-weight: 600; color: var(--ink-2); }

/* The claim wizard's upload step. Nothing is uploaded: the input is real so
   the picker opens, and the dashed zone is what a person aims at. */
.slot-list { display: grid; gap: 16px; }
.upload-slot { display: grid; gap: 8px; }
.slot-label { font-size: 13px; font-weight: 600; color: var(--ink-2); }

.dropzone {
  display: grid;
  justify-items: center;
  gap: 4px;
  padding: 22px 16px;
  border: 1.5px dashed var(--border-strong);
  border-radius: var(--radius);
  background: var(--brand-tint);
  text-align: center;
  cursor: pointer;
}

.dropzone:hover { border-color: var(--brand); }
.dropzone .ico { color: var(--brand); }
.dropzone .dz-title { font-size: 14px; font-weight: 600; color: var(--ink-2); }
.dropzone .dz-sub { font-size: 12px; color: var(--muted); }
.dz-input { font-size: 12px; color: var(--muted); max-width: 100%; }

/* The claim wizard's success state. */
.done-panel { display: grid; justify-items: center; gap: 10px; padding: 28px 20px; text-align: center; }

.done-panel .done-tile {
  display: grid;
  place-items: center;
  width: 56px;
  height: 56px;
  border-radius: 999px;
  background: var(--tone-ok-bg);
  color: var(--tone-ok-ink);
}

.done-panel h3 { font-family: var(--font-display); font-size: 21px; font-weight: 700; }
.done-panel p { max-width: 48ch; font-size: 14px; color: var(--muted); }
.done-actions { display: flex; gap: 10px; flex-wrap: wrap; justify-content: center; margin-top: 8px; }

.num-steps { display: grid; gap: 14px; margin: 0; padding: 0; list-style: none; }
.num-steps li { display: flex; align-items: flex-start; gap: 12px; font-size: 14px; color: var(--ink-2); line-height: 1.5; }

.num-steps .num {
  display: grid;
  place-items: center;
  width: 26px;
  height: 26px;
  flex: none;
  border-radius: 999px;
  background: var(--brand-soft);
  color: var(--brand);
  font-family: var(--font-display);
  font-size: 13px;
  font-weight: 700;
}

.due-row { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; }
.due-amount { display: grid; gap: 2px; margin-left: auto; text-align: right; }
.due-amount .da-n { font-family: var(--font-display); font-size: 24px; font-weight: 700; color: var(--ink); }
.due-amount .da-l { font-size: 13px; color: var(--muted); }

.pay-options { display: grid; gap: 12px; }

.pay-option {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  padding: 16px;
  border: 1.5px solid var(--border-strong);
  border-radius: var(--radius);
  background: var(--surface);
  cursor: pointer;
}

.pay-option:hover { border-color: var(--brand); }
.pay-option:has(input:checked) { border-color: var(--brand); background: var(--brand-tint); }
.pay-option input { margin-top: 3px; accent-color: var(--brand); }
.pay-option .po-text { display: block; min-width: 0; }
.pay-option .po-title { display: block; font-size: 15px; font-weight: 600; color: var(--ink); }
.pay-option .po-sub { display: block; margin-top: 3px; font-size: 13px; color: var(--muted); line-height: 1.45; }

.drawer-note { margin-bottom: 16px; font-size: 14px; color: var(--muted); line-height: 1.55; }

.faq { display: grid; }
.faq details { border-bottom: 1px solid var(--border); }
.faq details:last-child { border-bottom: 0; }

.faq summary {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 14px 0;
  font-size: 15px;
  font-weight: 600;
  color: var(--ink);
  cursor: pointer;
  list-style: none;
}

.faq summary::-webkit-details-marker { display: none; }
.faq summary .ico { margin-left: auto; color: var(--muted); transition: transform 0.18s var(--ease); }
.faq details[open] summary { color: var(--brand); }
.faq details[open] summary .ico { transform: rotate(180deg); }
.faq details p { padding: 0 0 16px; font-size: 14px; color: var(--muted); line-height: 1.6; max-width: 68ch; }

/* Client responsive: the offer grid loses a column before the frame does, and
   nothing is allowed to push the page sideways at phone width. */
@media (max-width: 1240px) {
  .grid-main-rail.is-offers { grid-template-columns: minmax(0, 1fr); }
  .offer-grid.is-five { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

@media (max-width: 1000px) {
  .offer-grid, .offer-grid.is-five { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* Phone-width corrections. Both are additive: no rule above is changed, and
   both apply only under the shell's own off-canvas breakpoint.
   The search pill is a flex item with the default min-width:auto, so at 390px
   it refuses to shrink and pushes the persona chip past the right edge. That
   is the only thing making a /app page scroll sideways on a phone. */
@media (max-width: 800px) {
  .top-search { min-width: 0; }
  .top-search input { min-width: 0; }
}

@media (max-width: 720px) {
  .offer-grid, .offer-grid.is-five { grid-template-columns: minmax(0, 1fr); }
  /* The header quote and the page action share one flex row. On a phone the
     quote is squeezed to four words a line, so give each its own row. */
  .page-head .head-side { flex-wrap: wrap; }
  .page-head .head-quote { flex: 1 1 100%; }
  /* A row of two buttons is wider than a phone; let it wrap. */
  .form-actions { flex-wrap: wrap; }
  /* A document row is a grid item, so its automatic minimum is the filename
     at full length. Releasing it lets the name ellipsise instead of pushing
     the page sideways. */
  .doc-list .doc-row { min-width: 0; }
  .tabs { flex-wrap: wrap; }
  .tabs button { flex: 1 1 44%; }
  .stepper { flex-wrap: wrap; }
  .stepper .step { flex: 1 1 44%; }
  .stepper .step button { padding: 0 8px; font-size: 13px; }
  .due-row .due-amount { margin-left: 0; text-align: left; }
  .due-row .btn { width: 100%; justify-content: center; }
  .ren-row .btn { width: 100%; justify-content: center; }
  .help-actions { flex-direction: column; }
  .countdown .cd-n { font-size: 32px; }
  .done-actions .btn { width: 100%; justify-content: center; }
}

/* ---- 13b. Ops file queue, full width: room for a whole email address ----
   Additive, and scoped to the ops queue tables only. The Client cell on the
   files page carries a name over an address; the longest address in the book
   is 31 characters, so the column is given the width to show it whole rather
   than cutting one off mid-domain. The gutters pay for it. */
.queue-wide .tbl thead th,
.queue-wide .tbl tbody td { padding-left: 6px; padding-right: 6px; }
.queue-wide .tbl thead th:first-child,
.queue-wide .tbl tbody td:first-child { padding-left: 16px; }
.queue-wide .tbl thead th:last-child,
.queue-wide .tbl tbody td:last-child { padding-right: 16px; }
.queue-wide .tbl .cell-client { max-width: 200px; }
.queue-wide .tbl .cell-sub { font-size: 12px; }

/* ---- 15. Live client portal (P1) ------------------------------------------
   The /app shell adopted by the live portal (master D2): the sign-in frame,
   the language toggle, the file uploader, tables that stack into cards on a
   phone, the Simulation pill, and the states the preview never needed: an
   error in a drawer, a track step still to come or stopped. P2 and P3 append
   their own blocks after this one. */

/* The sign-in page on the shell's ground: the mark home, the toggle, one
   card, the company line. */
.auth {
  min-height: 100vh;
  display: grid;
  grid-template-rows: auto 1fr auto;
  background: var(--bg);
  font-family: var(--font-body);
  color: var(--ink);
}
.auth-top { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 20px 24px; }
.auth-top img { display: block; height: 30px; }
.auth-main { display: grid; place-items: center; padding: 12px 16px 40px; }
.auth-card {
  width: 100%;
  max-width: 440px;
  padding: 28px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-md);
}
.auth-card h1 { font-family: var(--font-display); font-size: 24px; letter-spacing: -0.02em; line-height: 1.15; margin: 0 0 8px; }
.auth-foot { padding: 20px 24px; text-align: center; font-size: 12px; color: var(--muted); }

/* EN | FR. js/i18n.js lights the current one (is-on) and handles the click. */
.lang-toggle { display: inline-flex; border: 1px solid var(--border-strong); border-radius: 999px; overflow: hidden; }
.lang-toggle button {
  border: 0;
  background: var(--surface);
  color: var(--muted);
  font: 600 12px/1 var(--font-body);
  padding: 8px 11px;
  cursor: pointer;
}
.lang-toggle button.is-on { background: var(--brand); color: var(--surface); }

.top-spacer { flex: 1; }
.pop .pop-empty { margin: 0; padding: 10px; font-size: 13px; color: var(--muted); }
.pop button.pop-item { width: 100%; border: 0; background: none; font: inherit; color: inherit; text-align: left; cursor: pointer; }

/* A drawer hangs off <body>, outside .app-shell where the --tone-* pairs are
   declared, so it names the tego.css tokens the error pair stands for. */
.drawer .drawer-error {
  margin: 0 0 14px;
  padding: 10px 12px;
  border-radius: 10px;
  background: var(--error-bg);
  color: var(--error);
  font-size: 13px;
}

.uploader .up-list { list-style: none; margin: 10px 0 0; padding: 0; display: grid; gap: 6px; }
.uploader .up-item {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 10px;
  border: 1px solid var(--border);
  border-radius: 10px;
  font-size: 13px;
}
.uploader .up-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.uploader .up-size { color: var(--muted); white-space: nowrap; }
.uploader .up-error { margin: 8px 0 0; font-size: 12px; color: var(--error); }
.uploader.is-full .dropzone { opacity: .5; pointer-events: none; }
.uploader.is-dragging .dropzone { border-color: var(--brand); background: var(--brand-tint); }

.sim-pill {
  display: inline-flex;
  align-items: center;
  height: 22px;
  padding: 0 9px;
  border-radius: 999px;
  background: var(--tone-warn-bg);
  color: var(--tone-warn-ink);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .02em;
  white-space: nowrap;
}

/* Below 720px a stacked table prints each row as a card of label and value:
   six columns and a button never fit a phone, and a table that scrolls
   sideways hides the button. A stacked cell gives up the desktop row's fixed
   height and no-wrap, or a long address runs out of its card. */
@media (max-width: 720px) {
  .tbl-stack .tbl thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }
  .tbl-stack .tbl, .tbl-stack .tbl tbody, .tbl-stack .tbl tr, .tbl-stack .tbl td { display: block; width: 100%; }
  .tbl-stack .tbl tr { padding: 6px 12px; margin-bottom: 10px; border: 1px solid var(--border); border-radius: 12px; background: var(--surface); }
  .tbl-stack .tbl td { display: flex; justify-content: space-between; align-items: center; gap: 12px; height: auto; padding: 8px 0; border: 0; text-align: right; white-space: normal; overflow-wrap: anywhere; }
  .tbl-stack .tbl td::before { content: attr(data-label); flex: none; font-weight: 600; color: var(--muted); text-align: left; }
  .tbl-stack .tbl td[data-label=""] { justify-content: flex-end; }
  .tbl-stack .tbl td[data-label=""]::before, .tbl-stack .tbl .tbl-empty td::before { content: none; }
}

/* A track step still to come is a hollow ring with a quiet title; a stopped
   one (a claim rejected, a file withdrawn) is marked in the error tone. The
   note under a step is the person's own words, on its own line. */
.timeline .is-todo .tl-dot { border-color: var(--border-strong); background: var(--surface); }
.timeline .is-todo .tl-title { color: var(--muted); }
.timeline .is-stopped .tl-dot { border-color: var(--tone-error-bg); background: var(--tone-error-bg); color: var(--tone-error-ink); }
.timeline .tl-note { display: block; margin-top: 4px; font-size: 13px; line-height: 1.45; color: var(--ink-2); overflow-wrap: anywhere; }

/* The sign-in card's inner parts: the lede under each heading and the
   address repeated on the code step, in the same quiet tone; the address
   itself is long enough to wrap on a phone rather than push the card wide. */
.auth-card .signin-lede,
.auth-card .signin-sentto {
  margin: 0 0 20px;
  font-size: 14px;
  color: var(--muted);
}
.auth-card .signin-sentto strong { color: var(--ink); font-weight: 600; overflow-wrap: anywhere; }

/* "Use a different address" / "Send a new code": two text-buttons beside
   each other, wrapping onto their own lines rather than clipping on a
   phone. */
.signin-actions { display: flex; flex-wrap: wrap; gap: 8px 20px; margin-top: 16px; }
.auth-link { border: 0; background: none; padding: 0; font: 600 13px/1.3 var(--font-body); color: var(--brand); cursor: pointer; }
.auth-link:hover { text-decoration: underline; }

/* Where Delete my account lands: a calm notice, not an error. .auth sits
   outside .app-shell, same as .drawer above, so this names the tego.css
   tokens the --tone-ok pair stands for rather than reaching for a variable
   that is not in scope here. */
.auth-note {
  margin: 0 0 20px;
  padding: 10px 12px;
  border-radius: 10px;
  background: color-mix(in srgb, var(--ok) 12%, var(--surface));
  color: var(--ok);
  font-size: 13px;
}

/* Same tone pair as .drawer .drawer-error, for the card outside any drawer. */
.auth-error {
  margin: 16px 0 0;
  padding: 10px 12px;
  border-radius: 10px;
  background: var(--error-bg);
  color: var(--error);
  font-size: 13px;
}

.btn-block { width: 100%; }

/* The portal's pages (js/portal-pages.js): what the preview never drew.
   A link drawn as a primary button keeps its white label: section 1's
   `.app-shell a { color: inherit }` outweighs `.btn-primary` and paints the
   label ink on purple. The preview's anchor buttons show the same thing and
   are left as they are; the live portal is scoped by its body attribute. */
body[data-portal] .app-shell a.btn-primary { color: var(--surface); }

/* A line of plain text inside a card, in the page's quiet voice. */
.card-text { margin: 0; font-size: 14px; line-height: 1.5; color: var(--muted); }

/* In progress: one request a row, what it is over where it has got to. The
   track runs across the row, dot and line side by side, so three or four
   steps read at a glance instead of standing a column tall per request. */
.prog-list { display: grid; }
.prog-row { display: grid; gap: 14px; padding: 16px 0; border-bottom: 1px solid var(--border); }
.prog-row:first-child { padding-top: 0; }
.prog-row:last-child { padding-bottom: 0; border-bottom: 0; }
.prog-head { display: flex; align-items: center; gap: 8px 12px; flex-wrap: wrap; }
.prog-text { flex: 1 1 160px; min-width: 0; }
.prog-ref { display: block; font-size: 14px; font-weight: 600; color: var(--brand); }
.prog-sub { display: block; font-size: 13px; color: var(--muted); overflow-wrap: anywhere; }
.prog-head .ins-mark { --ins-h: 18px; max-width: 112px; }
.prog-meta { font-size: 14px; font-weight: 600; color: var(--ink); white-space: nowrap; }
.prog-link { justify-self: start; display: inline-flex; align-items: center; gap: 6px; font-size: 13px; font-weight: 600; color: var(--brand); }
.prog-row .timeline { grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr); }
.prog-row .timeline .tl-step { grid-template-columns: minmax(0, 1fr); gap: 8px; }
.prog-row .timeline .tl-rail { grid-template-rows: none; grid-template-columns: auto minmax(0, 1fr); align-items: center; justify-items: stretch; }
.prog-row .timeline .tl-line { width: auto; height: 2px; min-height: 0; margin: 0 6px; }
.prog-row .timeline .tl-body { padding: 0 8px 0 0; }
.prog-row .timeline .tl-title { font-size: 13px; line-height: 1.3; }

/* A request's checklist on the Documents page: the slot, the file chosen
   for it at checkout, and where that file is now. */
.slot-rows { display: grid; }
.slot-row { display: flex; align-items: center; gap: 12px; padding: 12px 0; border-bottom: 1px solid var(--border); }
.slot-row:first-child { padding-top: 0; }
.slot-row:last-child { padding-bottom: 0; border-bottom: 0; }
.slot-text { flex: 1; min-width: 0; }
.slot-kind { display: block; font-size: 14px; font-weight: 600; color: var(--ink); }
.slot-file { display: block; font-size: 13px; color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.slot-kept { font-size: 13px; color: var(--muted); text-align: right; }
/* On a phone "Conservé sur votre appareil" kept its one line and took the
   row from the slot's name (three lines) and the file name (ten letters):
   there it wraps in a narrow column of its own. */
@media (max-width: 480px) {
  .slot-kept { flex: none; max-width: 7.5em; line-height: 1.35; }
}

/* Two notes in the warn tone: where to send a document when uploads are off,
   and the answer under Re-compare and Renew when there is one to give (no
   answers behind the policy, or the request failing). */
.slot-send,
.renew-note {
  margin: 14px 0 0;
  padding: 10px 12px;
  border-radius: 10px;
  background: var(--tone-warn-bg);
  color: var(--tone-warn-ink);
  font-size: 13px;
  line-height: 1.45;
}
.renew-note a { color: inherit; font-weight: 600; text-decoration: underline; }

/* On a phone a policy's document keeps the row for its name, and Download
   moves under it: beside the French "Télécharger" the name was down to its
   first word. */
@media (max-width: 720px) {
  body[data-portal] .doc-list .doc-row { flex-wrap: wrap; }
  body[data-portal] .doc-list .doc-text { flex: 1 1 calc(100% - 46px); }
  body[data-portal] .doc-list .doc-row .btn { margin-left: 46px; }
}

/* Beside the rail a compact table's widest column can be its heading
   ("RENEWAL DATE" over "31 Aug 2027"): a heading may take two lines there
   so the row's last button stays inside the card. */
body[data-portal] .queue-compact .tbl thead th { white-space: normal; vertical-align: bottom; }
/* For the same reason the product tile goes (every policy is motor, and it
   is the row's one decoration), and the product and the car over it may
   wrap as a last resort: a policy number cannot, and a longer one is what
   would push the row out. */
body[data-portal] .queue-compact .cell-policy .cell-tile { display: none; }
body[data-portal] .queue-compact .cell-policy .cell-strong,
body[data-portal] .queue-compact .cell-policy .cell-sub { white-space: normal; }

/* A payment's status and the Simulation pill, side by side in one cell. */
.pay-state { display: inline-flex; align-items: center; gap: 6px; }

/* The uploader in a phone-width drawer. Its list's one track is held to the
   drawer, or a long file name widens it and pushes Remove past the edge. The
   native input speaks the browser's language ("No file chosen") whatever the
   page's: the dashed zone is its label and what a person aims at, so the
   input stays in the tab order unseen and the zone shows its focus. */
.uploader .up-list { grid-template-columns: minmax(0, 1fr); }
.uploader .dropzone { position: relative; }
.uploader .dz-input { position: absolute; width: 1px; height: 1px; opacity: 0; overflow: hidden; }
.uploader .dropzone:focus-within { outline: 2px solid var(--brand); outline-offset: 2px; }

/* Saved quotes that would not load: the reason and Try again, on one line
   while there is room. */
.load-error { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 10px 16px; font-size: 14px; color: var(--muted); }

/* Raise a claim with no cover to raise it on: the button stays, disabled,
   and says why under itself. */
.head-hold { display: grid; justify-items: end; gap: 6px; }
.head-hint { max-width: 240px; font-size: 12px; line-height: 1.4; color: var(--muted); text-align: right; }
@media (max-width: 720px) {
  .head-hold { justify-items: start; }
  .head-hint { max-width: none; text-align: left; }
}

/* A claim's row opens the claim wherever it is tapped. */
.claim-rows .tbl tbody tr:not(.tbl-empty) { cursor: pointer; }

/* The date over its count in one cell (renewalCell), however the row is
   laid out. */
.cell-when { display: inline-block; }

/* A form's answer that belongs to no one field: the claim that did not
   send, a profile that did not save, a message refused. */
.form-alert {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 8px 14px;
  margin: 14px 0 0;
  padding: 10px 12px;
  border-radius: 10px;
  background: var(--error-bg);
  color: var(--error);
  font-size: 13px;
  line-height: 1.45;
}
.form-alert[hidden] { display: none; }

/* Yes / No on the claim form. tego.css's `.field label` (display: block,
   bold, a bottom margin) outranks .radio-pill inside a .field, which stacks
   the dot over its word; the preview's claim wizard shows the same and is
   left as it is. */
body[data-portal] .field .radio-pill { display: inline-flex; margin-bottom: 0; font-size: 14px; }

/* The done panel: the new claim's reference kept whole, the photos that
   did not follow it, and a sent message's line in the page's ink. */
.done-panel .done-ref { white-space: nowrap; }
.done-fails { display: grid; gap: 6px; max-width: 48ch; margin: 0; padding: 10px 12px; list-style: none; border-radius: 10px; background: var(--tone-warn-bg); color: var(--tone-warn-ink); font-size: 13px; overflow-wrap: anywhere; }
.done-panel .done-lead { font-size: 15px; font-weight: 600; color: var(--ink); overflow-wrap: anywhere; }

/* A value a person typed can be one long word (a place, a description, a
   police report number): it wraps inside its column. On a phone the label
   column gives up 20px, so a policy number ("SW/MO/2026/30144") still fits
   whole on its line; a two-word label takes two lines instead. */
body[data-portal] .data-grid dd { overflow-wrap: anywhere; }
@media (max-width: 720px) {
  body[data-portal] .data-grid > div { gap: 12px; }
  body[data-portal] .data-grid dt { width: 96px; }
}

/* A renewal card: room under its head, and its two buttons wrap inside the
   card rather than run past it ("Renouveler avec Swan General"). */
.ren-card .countdown { margin-top: 14px; }
.ren-card .form-actions { flex-wrap: wrap; margin-top: 14px; }

.privacy-actions { margin-top: 12px; }

/* A field the page moves the focus to (the first one in error) stops below
   the sticky topbar with its label in view, not under the bar. */
body[data-portal] .app-shell :is(input, select, textarea) {
  scroll-margin-top: calc(var(--ribbon-h) + var(--top-h) + 44px);
}

/* Compare offers while the five rate files load: the card holds its place,
   with the brick build, and the rest of the dashboard is already drawn. */
.offer-wait { display: grid; place-items: center; min-height: 160px; }

/* A cover's last day: the countdown says Today, in a size that fits
   "Aujourd'hui" beside its line on a phone. */
.countdown .cd-n.is-word { font-size: 26px; letter-spacing: -0.02em; }

/* Raising a claim on a phone: "Retour" and "Envoyer la déclaration" do not
   share a line, and the wrap left Back alone above the submit. The step's
   buttons stack full width there, the way forward on top. */
@media (max-width: 480px) {
  body[data-portal] .step-nav { flex-direction: column-reverse; align-items: stretch; }
  body[data-portal] .step-nav .btn { justify-content: center; }
}

/* Four stat cards across at 1280 leave a label two lines: balanced, it
   breaks "Renewals due / (30 days)" rather than inside the brackets. */
body[data-portal] .stat .stat-label { text-wrap: balance; }

/* Support's one way to reach TEGO, over its hours. Scoped to the shell:
   its `a { color: inherit }` outweighs a single class. */
.app-shell .contact-mail { display: inline-flex; align-items: center; gap: 8px; margin-bottom: 8px; font-size: 15px; font-weight: 600; color: var(--brand); }
.app-shell .contact-mail:hover { text-decoration: underline; }

/* ---- 16. Ops console (P2) --------------------------------------------------
   The /staff pages (js/ops-app.js) wear this shell with is-ops. The sidebar
   goes dark: an ops screen holds other people's policies and must never pass
   for the shopfront or for a customer's own account (spec "Dark sidebar",
   review flag 1; portal.css "Admin chrome" says the same of the old bar).
   The customer portal wears this same shell light, so colour is the one cue
   left between the two, and the brick logo already reads on var(--ink) in
   the admin bar. The topbar and the content stay light. Everything here is
   scoped to .app-shell.is-ops unless it is a component of its own. */

.app-shell.is-ops .side {
  background: var(--ink);
  border-color: transparent;
  scrollbar-color: rgba(255, 255, 255, 0.22) transparent;
}

.app-shell.is-ops .side-brand .tag { color: rgba(255, 255, 255, 0.6); }

.app-shell.is-ops .side-nav .nav-item,
.app-shell.is-ops .side-nav .nav-item .ico { color: rgba(255, 255, 255, 0.72); }
.app-shell.is-ops .side-nav .nav-item:hover { background: rgba(255, 255, 255, 0.08); }
.app-shell.is-ops .side-nav .nav-item:hover .ico { color: #fff; }
.app-shell.is-ops .side-nav .nav-item.is-active { color: #fff; background: rgba(255, 255, 255, 0.12); }
.app-shell.is-ops .side-nav .nav-item.is-active .ico { color: #fff; }
.app-shell.is-ops .side a:focus-visible { outline: 2px solid #fff; outline-offset: 2px; }

.app-shell.is-ops .side-nav .count-pill { background: rgba(255, 255, 255, 0.16); color: #fff; }

/* Eleven items and the help card fill a 900px-tall side: a divider left to
   flex would shrink to nothing first, so it keeps its pixel, on less margin. */
.app-shell.is-ops .side-divider { flex: none; margin-block: 12px; background: rgba(255, 255, 255, 0.12); }

.app-shell.is-ops .side-help { background: var(--ink-2); border-color: transparent; color: #fff; }
.app-shell.is-ops .side-help h4 { color: #fff; }
.app-shell.is-ops .side-help .help-tile { background: rgba(255, 255, 255, 0.12); color: #fff; }
.app-shell.is-ops .side-help p { color: rgba(255, 255, 255, 0.72); }
.app-shell.is-ops .side-help .btn-outline-full { background: transparent; border-color: rgba(255, 255, 255, 0.5); color: #fff; }
.app-shell.is-ops .side-help .btn-outline-full:hover { background: rgba(255, 255, 255, 0.08); border-color: #fff; }

/* The 1100px icon rail (section 12): the open-files count sits on the icon's
   corner, so it is solid there, ringed in the rail's own ink. */
@media (max-width: 1100px) {
  .app-shell.is-ops .side-nav .count-pill { background: var(--brand); border-color: var(--ink); }
}

/* The rail's labels are its data-tip tooltips (section 12), drawn past the
   rail's 64px, where section 1's overflow-y: auto on .side clips them away
   (the preview's rail does the same, and is left as it is). Wherever the
   rail's ~650px fits the screen, the ops side lets them out over the page. */
@media (min-width: 801px) and (max-width: 1100px) and (min-height: 720px) {
  .app-shell.is-ops .side { overflow: visible; }
}

/* The 800px off-canvas nav (section 12) is the same .side, dark already; the
   count goes back to sitting beside its label. */
@media (max-width: 800px) {
  .app-shell.is-ops .side-nav .count-pill { background: rgba(255, 255, 255, 0.16); }
}

/* An anchor drawn as a primary button keeps its white label (section 1's
   `.app-shell a { color: inherit }` would paint it ink on purple; the portal
   fixes the same thing under body[data-portal]). */
.app-shell.is-ops a.btn-primary { color: var(--surface); }

/* A page's title and lede are often a client's or a partner's name as it
   was typed: a word longer than the line (an address for a name, a name
   typed as markup) breaks inside the head rather than push the page
   sideways on a phone. */
.app-shell.is-ops .page-head h1,
.app-shell.is-ops .page-head .lede { overflow-wrap: anywhere; }
/* The title keeps a column of its own: a side wider than what is left (the
   pipeline's filters, a partner's long name among the sources) goes under it
   rather than squeezing "Pipeline" into "Pipelin" over "e". */
.app-shell.is-ops .page-head .head-text { min-width: min(240px, 100%); }

/* The footer: the internal-tool warning, then the company line; each wraps
   onto its own lines on a phone rather than run past the edge. */
.ops-foot { align-items: flex-start; }
.ops-foot img { margin-top: 1px; }
.ops-foot span { flex: 1 1 300px; min-width: 0; line-height: 1.45; }
.ops-foot span:last-child { flex: 0 1 auto; margin-left: auto; }
@media (max-width: 720px) {
  .ops-foot span,
  .ops-foot span:last-child { flex-basis: 100%; margin-left: 0; }
}

/* A queue's secondary columns go on a phone; the row keeps what identifies it. */
@media (max-width: 720px) {
  .tbl .col-wide { display: none; }
}

/* Count pills over a list (js/ops/common.js pills()): one row that scrolls
   sideways on a phone rather than wrapping into a wall of buttons. Scoped to
   .pill-row to outrank tego.css's uppercase .pill. */
.pill-row {
  display: flex;
  gap: 8px;
  flex-wrap: nowrap;
  overflow-x: auto;
  scrollbar-width: none;
  padding-bottom: 2px;
}
.pill-row::-webkit-scrollbar { display: none; }

.pill-row .pill {
  flex: none;
  display: inline-flex;
  align-items: center;
  gap: 7px;
  height: 34px;
  padding: 0 13px;
  border-radius: 999px;
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--ink-2);
  font-family: inherit;
  font-size: 13px;
  font-weight: 500;
  letter-spacing: normal;
  text-transform: none;
  white-space: nowrap;
  cursor: pointer;
  transition: border-color 0.16s var(--ease), color 0.16s var(--ease);
}
.pill-row .pill:hover { border-color: var(--brand); color: var(--brand); }
.pill-row .pill.is-active { background: var(--brand); border-color: var(--brand); color: var(--surface); }

.pill-row .pill-count {
  display: inline-grid;
  place-items: center;
  min-width: 20px;
  height: 20px;
  padding: 0 6px;
  border-radius: 999px;
  background: var(--tone-brand-bg);
  color: var(--tone-brand-ink);
  font-size: 12px;
  font-weight: 700;
}
.pill-row .pill.is-active .pill-count { background: rgba(255, 255, 255, 0.2); color: var(--surface); }

/* The pipeline (P2) and a partner's referrals (P6): app.js board(). Columns
   side by side, each a stack of card links; a view, not a workflow. */
.board {
  display: grid;
  grid-template-columns: repeat(var(--cols, 3), minmax(0, 1fr));
  gap: 16px;
  align-items: start;
}

.board-col {
  display: flex;
  flex-direction: column;
  min-width: 0;
  padding: 12px;
  border-radius: var(--radius);
  border: 1px solid var(--border);
  background: var(--brand-tint);
}
.board-col.is-collapsed { display: none; }

.board-head { display: grid; gap: 2px; padding: 2px 4px 12px; }
.board-head h3 { display: flex; align-items: center; gap: 8px; font-size: 15px; font-weight: 700; }
.board-count {
  display: inline-grid;
  place-items: center;
  min-width: 22px;
  height: 20px;
  padding: 0 7px;
  border-radius: 999px;
  background: var(--surface);
  color: var(--brand);
  font-family: var(--font-body);
  font-size: 12px;
  font-weight: 700;
  letter-spacing: normal;
}
.board-value { font-size: 13px; font-weight: 600; color: var(--ink-2); }
.board-note { margin-top: 4px; font-size: 12px; line-height: 1.4; color: var(--muted); }

.board-cards { display: grid; gap: 10px; max-height: none; overflow-y: auto; }

.board-card {
  display: grid;
  gap: 6px;
  padding: 12px;
  border-radius: 10px;
  border: 1px solid var(--border);
  background: var(--surface);
  box-shadow: var(--shadow-sm);
  transition: border-color 0.16s var(--ease);
}
.board-card:hover { border-color: var(--brand); }
.board-card .bc-top { display: flex; align-items: center; justify-content: space-between; gap: 8px; min-width: 0; }
.board-card .bc-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 600; color: var(--ink); }
.board-card .bc-mark { flex: none; }
.board-card .bc-mark .ins-mark { --ins-h: 16px; max-width: 84px; }
.board-card .bc-vehicle { font-size: 13px; color: var(--muted); overflow-wrap: anywhere; }
.board-card .bc-foot { display: flex; align-items: center; flex-wrap: wrap; gap: 6px 10px; font-size: 12px; color: var(--muted); }
.board-card .bc-value { font-size: 13px; font-weight: 700; color: var(--ink); }
.board-card .bc-source { padding: 2px 8px; border-radius: 999px; background: var(--tone-muted-bg); color: var(--tone-muted-ink); font-weight: 600; }
.board-card .bc-initials {
  display: grid;
  place-items: center;
  width: 24px;
  height: 24px;
  margin-left: auto;
  border-radius: 999px;
  background: var(--brand-soft);
  color: var(--brand);
  font-size: 11px;
  font-weight: 700;
}
.board-empty { padding: 16px 8px; text-align: center; font-size: 13px; color: var(--muted); }

/* On a phone the columns stack, and a long one scrolls inside itself so the
   next column's head is never a screen away. */
@media (max-width: 800px) {
  .board { grid-template-columns: minmax(0, 1fr); }
  .board-cards { max-height: 420px; }
}

/* A file on a narrow screen: Actions first, above the record they act on. */
@media (max-width: 1240px) {
  .ops-file .ops-rail { order: -1; }
}

/* Drawers are already full width on a phone (section 11: min(440px, 100%)). */

/* The file queue (js/ops/files.js): one flush card, a data grid. tego.css's
   28px card padding would cost a phone 56px of a table already scrolling
   in its box, so the filter bar keeps a gutter of its own and the table
   uses .queue-wide's; an empty queue draws no dashed frame inside the
   card's own. The bar has one column the pill row cannot widen (the pills
   scroll; the page never does); on a phone the selects pair up and the
   search takes a row of its own. */
.card.queue-card { padding: 0; }
.queue-card .empty { border: 0; border-radius: 0 0 var(--radius) var(--radius); }
.queue-filters {
  grid-template-columns: minmax(0, 1fr);
  padding: 18px 16px 14px;
  border-bottom: 1px solid var(--border);
}
/* A select is as wide as its longest choice, and a partner's name is a
   choice on Clients: a long one widened its select past the card on a phone
   and to a third of the bar on a laptop. It is cut in the closed select. */
.queue-filters .inline-select { max-width: 240px; }
@media (max-width: 720px) {
  .queue-filters .inline-select { flex: 1 1 140px; min-width: 0; }
  .queue-filters .search-box { flex: 1 1 100%; min-width: 0; max-width: none; }
}
/* The queue's nine columns on a laptop: at 1280 the card is 990px inside its
   border, or 975px when the page is tall enough for a classic scrollbar
   (Windows Chrome and Edge), and the seeded book's table was 1040px, so the
   row menu sat past the card's edge. A vehicle and an assignee are one
   ellipsised line. 1280 is ops' own laptop and the spec hides the vehicle on
   a phone only, so from 960px of card the client (whose address already
   ellipsizes) keeps 150px and the middle cells tighten, as the dashboard's
   latest files do: all nine columns fit, scrollbar or not. Under 960px (a
   tablet, the 1100px icon rail) the vehicle gives way (the file has it);
   only a phone scrolls the queue in its box. The two queries are width >= and
   width <, so no fractional card width falls between them. The container is
   the file queue's own card (files.js), not every .queue-card: nine pages
   wear that class. */
.ops-files-card { container: ops-queue / inline-size; }
.queue-wide .tbl td.col-vehicle { max-width: 150px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.queue-wide .tbl td.col-assignee { max-width: 120px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
@container ops-queue (width >= 960px) {
  .queue-wide .tbl .cell-client { max-width: 150px; }
  .queue-wide .tbl td.col-vehicle { max-width: 120px; }
  .queue-wide .tbl td.col-assignee { max-width: 100px; }
  .queue-wide .tbl thead th:not(:first-child):not(:last-child),
  .queue-wide .tbl tbody td:not(:first-child):not(:last-child) { padding-left: 3px; padding-right: 3px; }
  /* Updated, after the right-aligned premium, keeps a gap the eye reads as two figures. */
  .queue-wide .tbl thead th.col-wide:nth-last-child(2),
  .queue-wide .tbl tbody td.col-wide:nth-last-child(2) { padding-left: 9px; }
}
@container ops-queue (width < 960px) {
  .queue-wide .tbl .col-vehicle { display: none; }
}

/* A file (js/ops/file.js). Its rows are section 13's .data-grid, its
   documents section 13's .doc-list, its proposal sections the .faq
   accordion; what follows is only what those do not draw. */

/* The header's assignee, beside the status and the insurer's mark (on a
   phone the three wrap: section 14's head-side rule). */
.ops-assignee { display: inline-flex; align-items: center; gap: 6px; font-size: 14px; color: var(--ink-2); white-space: nowrap; }
.ops-assignee .ico { color: var(--muted); }

/* A typed address or a long file name breaks rather than push a phone's
   page sideways. The label column gives up room where the value column is
   narrow (the 340px rail; a phone, as the portal's section 15 does), so a
   policy number ("MUA/PC/2026/48117") stays whole on its line. */
.ops-file .data-grid dd { overflow-wrap: anywhere; }
/* The seed's "MUA/PC/2026/48117" took 140px of the 142px an 84px label left,
   and "MUA/PC/2026/48307" (147px) broke before its last digit: the shorter
   label and gap give the value 158px. */
.ops-file .ops-rail .data-grid > div { gap: 12px; }
.ops-file .ops-rail .data-grid dt { width: 72px; }
@media (max-width: 720px) {
  .ops-file .data-grid > div { gap: 12px; }
  .ops-file .data-grid dt { width: 96px; }
}

/* The chosen offer and the others quoted: a mark, then its figures; on a
   phone the figure sits under its mark, the same for every insurer. */
.ops-offer { display: inline-flex; align-items: center; flex-wrap: wrap; gap: 4px 10px; }
.ops-offer .ins-mark { --ins-h: 16px; max-width: 96px; }
.ops-others { display: grid; gap: 8px; }
@media (max-width: 720px) {
  .ops-others .ops-offer { display: grid; justify-items: start; gap: 2px; }
}
.ops-hint { display: block; margin-top: 2px; font-size: 13px; font-weight: 400; color: var(--muted); }

/* The proposal: a warning over sampled answers, a section a fold, the
   declaration under them. */
.sim-note {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  margin-bottom: 8px;
  padding: 10px 12px;
  border-radius: 10px;
  background: var(--tone-warn-bg);
  color: var(--tone-warn-ink);
  font-size: 13px;
  line-height: 1.45;
}
.sim-note .ico { margin-top: 1px; }
.ops-proposal details .data-grid { padding-bottom: 10px; }
.ops-proposal details .data-grid .badge { margin-left: 6px; vertical-align: middle; }
.ops-declared { margin-top: 12px; }

/* The identity check's checks, a tick or a cross each. */
.ops-checks { display: grid; gap: 6px; margin: 0; padding: 0; list-style: none; }
.ops-checks li { display: flex; align-items: flex-start; gap: 8px; }
.ops-checks li .ico { margin-top: 2px; }
.ops-checks .is-ok .ico { color: var(--ok); }
.ops-checks .is-fail .ico { color: var(--error); }

/* Documents: a small head over each group, and a held document as a line
   (there is nothing to download until the customer uploads it). */
.ops-subhead { margin: 4px 0 2px; font-size: 13px; font-weight: 700; color: var(--muted); }
.doc-list + .ops-subhead { margin-top: 16px; }
.held-line { display: flex; align-items: flex-start; gap: 8px; padding: 8px 0; font-size: 14px; color: var(--ink-2); overflow-wrap: anywhere; }
.held-line .ico { margin-top: 2px; color: var(--muted); }

/* Notes: who and where it is shared over the words, then when. */
.ops-notes { display: grid; }
.ops-note { display: grid; gap: 6px; padding: 12px 0; border-bottom: 1px solid var(--border); }
.ops-note:first-child { padding-top: 0; }
.ops-note:last-child { padding-bottom: 0; border-bottom: 0; }
.ops-note-head { display: flex; align-items: center; flex-wrap: wrap; gap: 6px 10px; }
.ops-note-who { font-size: 14px; font-weight: 600; color: var(--ink); }
.ops-note-body { font-size: 14px; line-height: 1.5; color: var(--ink-2); white-space: pre-line; overflow-wrap: anywhere; }
.ops-note-at { font-size: 12px; color: var(--muted); }

/* The timeline: a dot on a rail per entry, the actor in bold, a note's
   words under its entry, the time last. */
.ops-timeline { display: grid; margin: 0; padding: 0; list-style: none; }
.ops-timeline li { position: relative; display: grid; gap: 2px; padding: 0 0 16px 22px; }
.ops-timeline li:last-child { padding-bottom: 0; }
.ops-timeline li::before {
  content: '';
  position: absolute;
  left: 4px;
  top: 6px;
  width: 8px;
  height: 8px;
  border-radius: 999px;
  background: var(--brand);
}
.ops-timeline li::after { content: ''; position: absolute; left: 7px; top: 18px; bottom: 2px; width: 2px; background: var(--border); }
.ops-timeline li:last-child::after { display: none; }
.ops-tl-line { font-size: 14px; color: var(--ink-2); overflow-wrap: anywhere; }
.ops-tl-line b { font-weight: 700; color: var(--ink); }
.ops-tl-note { font-size: 13px; line-height: 1.45; color: var(--ink-2); white-space: pre-line; overflow-wrap: anywhere; }
.ops-tl-at { font-size: 12px; color: var(--muted); }

/* The Actions card: its controls stacked, a hairline between groups (Send;
   the move; who works it; issue and paperwork). Every control takes the
   rail's width, which on a phone is the screen's. */
.ops-actions { display: grid; }
.ops-act { display: grid; gap: 8px; padding: 14px 0; border-top: 1px solid var(--border); }
.ops-act:first-child { padding-top: 0; border-top: 0; }
.ops-act:last-child { padding-bottom: 0; }
.ops-act > .btn { width: 100%; }
.ops-act-label { font-size: 13px; font-weight: 600; color: var(--ink-2); }
.ops-actions .inline-select { width: 100%; min-width: 0; }
/* The 340px rail leaves the select ~170px beside Move: its chevron's room
   and the button's padding give a little, so "Documents needed" stays whole. */
.ops-move { display: flex; gap: 8px; }
.ops-move .inline-select { flex: 1; padding-right: 30px; background-position: calc(100% - 12px) center; }
.ops-move .btn { flex: none; height: 40px; padding: 0 14px; }
.ops-act-row { display: flex; gap: 8px; }
.ops-act-row .btn { flex: 1 1 0; }
.ops-closed {
  padding: 10px 12px;
  border-radius: 10px;
  background: var(--tone-muted-bg);
  color: var(--ink-2);
  font-size: 13px;
  line-height: 1.45;
}

/* A text button: Assign to me, a note's Edit and Delete. */
.ops-link {
  justify-self: start;
  padding: 2px 0;
  border: 0;
  background: none;
  font: 600 13px/1.3 var(--font-body);
  color: var(--brand);
  cursor: pointer;
}
.ops-link:hover { text-decoration: underline; }
.ops-link:disabled { opacity: 0.5; cursor: default; text-decoration: none; }

/* The drawers hang off <body>, outside .app-shell where the --tone-* pairs
   live, so what they add names tego.css tokens: the Send drawer's
   warnings in the warn pair, a label's Required or Optional, and two
   figures side by side (premium and excess, start and expiry). */
.send-warnings {
  display: grid;
  gap: 6px;
  margin: 0 0 16px;
  padding: 10px 12px;
  list-style: none;
  border-radius: 10px;
  background: var(--warn-bg);
  color: color-mix(in srgb, var(--error) 62%, var(--warn-border));
  font-size: 13px;
  line-height: 1.45;
}
.send-warnings li { display: flex; align-items: flex-start; gap: 8px; }
.send-warnings .ico { flex: none; margin-top: 1px; }
.field-tag { margin-left: 4px; font-weight: 500; color: var(--muted); }
.ops-pair { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0 12px; }
.drawer .check-row { margin-bottom: 4px; }

/* The notes' own tools, and the box that adds or edits one. */
.ops-note-tools { display: inline-flex; gap: 14px; margin-left: auto; }
.ops-note-tools[hidden] { display: none; }
.ops-note-form { margin-top: 16px; padding-top: 16px; border-top: 1px solid var(--border); }
.ops-note-form .field { margin-bottom: 10px; }
.ops-note-editor { display: grid; gap: 10px; }
.ops-note-editor textarea { width: 100%; min-height: 96px; padding: 10px 12px; border: 1px solid var(--border-strong); border-radius: 10px; font-size: 14px; }
.ops-note-foot { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 10px; }
.ops-note-btns { display: flex; gap: 8px; margin-left: auto; }

/* The dashboard (js/ops/dashboard.js). From 1241px its main column sits
   beside the 312px rail, too narrow for what the preview put there: the
   queue's eight columns (Premium and Updated end up past the card's edge),
   and two chart cards side by side (the bars keep 20px of track, the
   donut's legend pushes its counts out of the card). So the column
   measures itself: under 880px the vehicle and the assignee give way in
   the latest files (the file has both), under 820px the charts stack. */
.ops-dash-main { container: ops-dash / inline-size; }
@container ops-dash (max-width: 879px) {
  .ops-latest .tbl .col-vehicle,
  .ops-latest .tbl .col-assignee { display: none; }
  /* "Documents needed" beside "6 Sept 2026" (a week-old file) is 15px wider than "Submitted" beside "4 Oct 2026":
     the middle cells tighten so a worked book's table still fits its card. */
  .ops-latest .tbl thead th:not(:first-child):not(:last-child),
  .ops-latest .tbl tbody td:not(:first-child):not(:last-child) { padding-left: 3px; padding-right: 3px; }
  /* A classic scrollbar (Windows Chrome and Edge; headless hides it) takes 15px of the page: at 1280 the card holds
     591px and the seeded table needed 597. The card's own 28px is the right gutter, so the last cell's 16px beside it
     gives up 12px (its text is left-aligned: the columns move a few pixels, no more). */
  .ops-latest .tbl thead th:last-child,
  .ops-latest .tbl tbody td:last-child { padding-right: 4px; }
}
@container ops-dash (max-width: 819px) {
  .ops-charts { grid-template-columns: minmax(0, 1fr); }
}
/* A phone: the bar's label cell gives up a little, and Sanlam Allianz's
   wide lockup shrinks to fit it, so the bars keep a track worth reading. */
@container ops-dash (max-width: 479px) {
  .ops-charts .bar-list .bar-label { width: 112px; }
  .ops-charts .bar-list .ins-mark { max-width: 112px; }
}
/* The legend's own column, so a long status ellipsizes rather than push its
   count out of the card (the implicit track would size to the widest row). */
.ops-dashboard .donut .donut-legend { grid-template-columns: minmax(0, 1fr); }
.ops-dashboard .donut .legend-row > span:nth-child(2) { min-width: 0; }
/* The ring under the arcs: an empty book draws an empty ring, not a blank. */
.ops-dashboard .donut-track { stroke: var(--brand-tint); }
/* Recent activity in the 312px rail: no time column (it left a sentence
   ~104px and broke it into one-word lines), so the sentence keeps two
   lines, the subject and the time share one line under it (the subject
   gives way, never the time), and View all closes the card. At 12px a
   file's reference and "· just now" share the rail's 168px whole: at 13px
   the reference was cut to "TEGO-2026-00…". */
.ops-dashboard .act-list .act-title {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  overflow: hidden;
  font-weight: 400;
}
.ops-dashboard .act-list .act-title b { font-weight: 600; }
/* The list's own column: its implicit track sized to the widest row, so one
   long word in a sentence (an address for a name, a name typed as markup)
   pushed every row past the card and the page sideways on a phone. A word
   longer than the line breaks inside the two lines rather than run off. */
.ops-dashboard .act-list { grid-template-columns: minmax(0, 1fr); }
.ops-dashboard .act-list .act-title { overflow-wrap: anywhere; }
.ops-dashboard .act-list .act-sub { display: flex; min-width: 0; white-space: nowrap; font-size: 12px; }
.ops-dashboard .act-sub-label { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.ops-dashboard .act-sub-time { flex: none; }
.ops-dashboard .act-sub-label + .act-sub-time { margin-left: 0.35em; }
.ops-dashboard .act-all { width: 100%; margin-top: 12px; }
/* An activity row that opens its subject. */
.act-list a.act-link:hover .act-title { color: var(--brand); }
.act-list a.act-link:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; border-radius: 8px; }

/* A claim's photos (Task 11): square thumbnails that open the image. */
.ops-photos { display: grid; grid-template-columns: repeat(auto-fill, minmax(112px, 1fr)); gap: 10px; }
.ops-photos + .doc-list { margin-top: 14px; }
.ops-photo { display: block; border-radius: 10px; overflow: hidden; border: 1px solid var(--border); background: var(--bg); }
.ops-photo img { display: block; width: 100%; aspect-ratio: 1; object-fit: cover; }
.ops-photo:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }

/* Clients (Task 12). A tag is a small word in a pill; on the list the chips
   sit under the name and wrap inside the cell (section 13's .tbl cell is a
   single line, so they say so), on a client's page each has a cross. */
.tag-chips { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 4px; white-space: normal; max-width: 200px; }
.ops-tags .tag-chips { max-width: none; margin: 0 0 12px; }
.tag-chip {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  max-width: 100%;
  padding: 2px 8px;
  border-radius: 999px;
  background: var(--tone-brand-bg);
  color: var(--tone-brand-ink);
  font-size: 12px;
  font-weight: 600;
  line-height: 1.5;
  overflow-wrap: anywhere;
}
.tag-chip .tag-x { display: inline-flex; padding: 2px; border: 0; border-radius: 999px; background: none; color: inherit; cursor: pointer; }
.tag-chip .tag-x:hover { background: color-mix(in srgb, currentColor 16%, transparent); }
.tag-chip .tag-x:focus-visible { outline: 2px solid var(--brand); outline-offset: 1px; }
.ops-tag-add { margin-bottom: 0; max-width: 320px; }
.tbl a.cell-client { text-decoration: none; color: inherit; }
.tbl a.cell-client:hover .cell-strong { color: var(--brand); }
.tbl .col-client { min-width: 160px; }
/* A partner's name as a source ("Dupont Insurance Brokers") held its column
   on one line and put Last activity past the card at 1280; it wraps, in a
   row already two lines tall for the client's name and address. */
.tbl td.col-source, .tbl td.col-source .cell-ref { white-space: normal; }
.tbl td.col-source { max-width: 180px; overflow-wrap: anywhere; }
/* On a phone the name gives way, so Stage, Value and Files stay in view. */
@media (max-width: 720px) {
  .tbl .col-client { min-width: 0; }
  .queue-wide .tbl a.cell-client, .tbl .col-client .tag-chips { max-width: 104px; }
}

/* A client's page: the same data grid as a file's, a typed address or tag
   breaking rather than pushing a phone's page sideways. Rows in a card of
   their own table keep the table's gutter. */
.ops-client .data-grid dd { overflow-wrap: anywhere; }
@media (max-width: 720px) {
  .ops-client .data-grid > div { gap: 12px; }
  .ops-client .data-grid dt { width: 96px; }
}
.ops-signins { list-style: none; margin: 0; padding: 0; display: grid; gap: 8px; font-size: 14px; }
.ops-erase { width: 100%; margin-top: 12px; color: var(--tone-error-ink); }

/* The Insurers list and an insurer's page (Task 13). Four figures to a card
   take two a row; the name beside a Paused badge keeps the mark's height. A
   typed contact breaks rather than widening a phone's page. */
.ops-ins .ins-stats { grid-template-columns: repeat(2, minmax(0, 1fr)); row-gap: 14px; }
.ops-ins .ins-mail, .ops-ins .ins-contact { overflow-wrap: anywhere; }
.ins-contact { margin-top: 4px; font-size: 13px; color: var(--ink-2); }
.ins-head .badge { margin-left: auto; }
.ops-insurer .data-grid dd { overflow-wrap: anywhere; }
.ops-ins-two { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0 16px; }
.ops-ins-form .ops-ins-hint { margin: 6px 0 18px 27px; font-size: 12px; color: var(--muted); }
.ops-ins .ins-head { padding-bottom: 6px; }
.ops-ins-form .auth-error { margin-bottom: 12px; }
.ops-ins-note { margin-top: 12px; overflow-wrap: anywhere; }
@media (max-width: 720px) {
  .ops-ins-two { grid-template-columns: minmax(0, 1fr); }
  .ops-insurer .data-grid > div { gap: 12px; }
  .ops-insurer .data-grid dt { width: 96px; }
}

/* Partners (Task 14). A cell holding a typed contact or vehicle is one
   ellipsised line, in the table's single-line row; a typed value breaks
   rather than widening a phone's page. The code is read aloud, so it is
   large and spaced. */
.tbl .cell-contact { display: block; max-width: 240px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tbl .cell-contact .cell-strong,
.tbl .cell-contact .cell-sub { overflow: hidden; text-overflow: ellipsis; }
.ops-partner .data-grid dd { overflow-wrap: anywhere; }
/* A referral's customer is the way into its Edit on a phone, where the Edit
   column gives way; it is a button drawn as the cell it replaces. */
.tbl button.cell-edit { padding: 0; border: 0; background: none; font: inherit; color: inherit; text-align: left; cursor: pointer; }
.tbl button.cell-edit:hover .cell-strong { color: var(--brand); }
.tbl button.cell-edit:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; border-radius: 4px; }
.ops-code { margin: 0 0 6px; font: 700 32px/1.15 var(--font-display, var(--font-body)); letter-spacing: 0.12em; color: var(--ink); }
.ops-link-url { margin: 0 0 12px; font-size: 13px; color: var(--ink-2); overflow-wrap: anywhere; user-select: all; }
/* A referral's date, who typed it and its file are stacked in two cells, so
   every width shows them (the vehicle goes with the phone's col-wide). A month's bar carries its counts in the label, so the
   label takes its own line and the bar and its count sit under it. */
.queue-compact .tbl .cell-contact { max-width: 110px; }
.ops-months .bar-list .bar-row { flex-wrap: wrap; row-gap: 6px; }
.ops-months .bar-list .bar-label { width: 100%; white-space: normal; }
.ops-months .bar-list .bar-track { flex: 1; min-width: 0; }
@media (max-width: 720px) {
  .ops-partner .data-grid > div { gap: 12px; }
  .ops-partner .data-grid dt { width: 96px; }
  .tbl .cell-contact { max-width: 150px; }
}

/* Reports (P2, Task 16): the funnel's note sits under it; the by-insurer table's wide columns go on a phone. */
.ops-rep-note { margin: 14px 0 0; }

/* Users (P2, Task 17): a login is an avatar, a name and its address; on a phone the avatar goes and the name gives way, so Role, Status and the menu stay in the card. */
.queue-wide .tbl .cell-user .cell-client { max-width: 220px; }
/* The console's only: P1's portal stacks the same pair (its renewal cell) at its own spacing. */
.app-shell.is-ops .tbl .cell-nowrap + .cell-sub { margin-top: 1px; }
@media (max-width: 720px) {
  .queue-wide .tbl .cell-user .avatar-xs { display: none; }
  .queue-wide .tbl .cell-user .cell-client { max-width: 112px; }
}
/* A drawer hangs off body, outside any .field radio rule of the portal: the pills lie in a row, their radio beside the words. */
.drawer .field .radio-pill { display: inline-flex; margin-bottom: 0; font-size: 14px; font-weight: 500; }
.drawer .field .radio-pill:has(input:checked) { font-weight: 600; }


/* Activity and Settings (P2, Task 18). A cell holding a person's name, a subject or a sentence is as wide as its words allow and no wider (the cells are nowrap), so the last column of the table stays inside its card. */
.tbl .ops-act-who, .tbl .ops-act-subject, .tbl .ops-act-detail { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tbl .ops-act-who { max-width: 170px; }
.tbl .ops-act-subject { max-width: 190px; }
.tbl .ops-act-detail { max-width: 300px; }
.ops-act-code { font: 12px/1.4 ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; color: var(--ink-2); }
.ops-act-date { display: inline-flex; align-items: center; gap: 8px; font-size: 13px; color: var(--muted); }
.ops-act-date .inline-select { padding-right: 12px; }
@media (max-width: 720px) {
  .ops-act-date { flex: 1 1 140px; }
  .ops-act-date .inline-select { flex: 1; min-width: 0; }
  /* A month's own name is the widest date ("28 Sept 2026"), and a sentence
     keeps its longest word whole ("Downloaded"): together they pushed the
     Detail column 2px past the card, so Who and the subject give way. */
  .tbl .ops-act-who { max-width: 56px; }
  .tbl .ops-act-subject { max-width: 68px; }
  /* The sentence wraps to two lines on a phone rather than vanish. */
  .tbl .ops-act-detail { max-width: 96px; white-space: normal; font-size: 12px; line-height: 1.3; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; }
}
.tbl .ops-set-aud { display: none; }
@media (max-width: 720px) { .ops-settings .tbl thead th:last-child { white-space: normal; overflow-wrap: anywhere; max-width: 80px; line-height: 1.25; } .ops-settings .ops-act-code { font-size: 11px; } .tbl .ops-set-aud { display: block; max-width: 150px; font-size: 12px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } }
/* The copy switch: a checkbox that reads as a switch; an event that already goes to TEGO has nothing to copy, so its switch is dimmed and cannot be turned on. */
.ops-switch { position: relative; display: inline-block; width: 40px; height: 24px; vertical-align: middle; }
.ops-switch input { position: absolute; inset: 0; width: 100%; height: 100%; margin: 0; opacity: 0; cursor: pointer; }
.ops-switch-ui { position: absolute; inset: 0; border-radius: 999px; background: var(--border-strong); transition: background 0.16s var(--ease); pointer-events: none; }
.ops-switch-ui::after { content: ''; position: absolute; top: 3px; left: 3px; width: 18px; height: 18px; border-radius: 50%; background: var(--surface); transition: transform 0.16s var(--ease); }
.ops-switch input:checked + .ops-switch-ui { background: var(--brand); }
.ops-switch input:checked + .ops-switch-ui::after { transform: translateX(16px); }
.ops-switch input:focus-visible + .ops-switch-ui { outline: 2px solid var(--brand); outline-offset: 2px; }
.ops-switch.is-off { opacity: 0.4; }
.ops-switch input:disabled { cursor: not-allowed; }
.ops-set-foot { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap; padding: 14px 20px; border-top: 1px solid var(--border); }
.ops-set-foot .hint { margin: 0; }
.ops-set-note { margin: 0; font-size: 14px; color: var(--muted); }
.ops-set-rates { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(320px, 100%), 1fr)); gap: 20px; }
.ops-settings .data-grid dd { overflow-wrap: anywhere; }
.ops-settings .card-text + .card-text { margin-top: 10px; }
.ops-settings [data-signout] { margin-top: 16px; }
@media (max-width: 720px) {
  .ops-set-tabs { flex-wrap: nowrap; overflow-x: auto; }
  .ops-set-tabs button { flex: 0 0 auto; padding: 0 16px; }
  .ops-settings .data-grid > div { gap: 12px; }
  .ops-settings .data-grid dt { width: 110px; }
}

/* The pipeline (js/ops/pipeline.js). Four columns share the page from 721px; on a phone the tabs choose the one column shown and its cards stack as a list, so the page never scrolls sideways. */
.pipe-filters { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; }
/* A select is as wide as its longest choice: a long partner name among the sources is cut in the closed select instead. */
.pipe-filters .inline-select { max-width: 220px; }
.pipe-filters .pipe-lost { white-space: nowrap; }
.pipe-tabs { display: none; margin-bottom: 12px; }
.ops-pipeline .board { --cols: 4; }
.ops-pipeline .board-card .bc-name { white-space: normal; overflow-wrap: anywhere; }
@media (max-width: 720px) {
  .pipe-filters { width: 100%; }
  .pipe-filters .inline-select { flex: 1 1 140px; min-width: 0; }
  .pipe-tabs { display: flex; }
  .pipe-tabs { flex-wrap: nowrap; }
  .pipe-tabs button { flex: 1 1 0; min-width: 0; padding: 0 4px; font-size: 13px; white-space: nowrap; }
  .ops-pipeline .board { grid-template-columns: minmax(0, 1fr); }
  .ops-pipeline .board-col:not(.is-current) { display: none; }
  .ops-pipeline .board-col { padding: 0; border: 0; background: transparent; }
  .ops-pipeline .board-cards { max-height: none; }
}

/* ---- 17. Insurer portal (P3) --------------------------------------------
   The /insurer pages (js/insurer-app.js) wear the light shell with
   is-insurer: the preview's sidebar, so the two consoles are never
   confused at a glance (the ops one is dark), with the insurer's mark
   under TEGO's. Every rule here is scoped to .app-shell.is-insurer
   unless it is a component of its own. */

/* The insurer's mark under TEGO's logo (app.js brand.mark). Section 2's
   .side-brand img sizes TEGO's logo by width; the mark keeps the height
   tego.css's insurer marks give it, and its per-insurer correction. The
   1100px icon rail has no room for it, as it has none for the tagline;
   the 800px off-canvas nav shows both again. */
.side-mark { display: block; margin-top: 12px; --ins-h: 26px; }
.side-brand .side-mark .ins-logo { width: auto; height: calc(var(--ins-h) * var(--k)); max-width: 100%; }
@media (max-width: 1100px) {
  .side-mark { display: none; }
}
/* The rail's labels are its data-tip tooltips, which .side's overflow-y
   clips; wherever the rail fits the screen they show over the page, as
   block 16 lets them for ops. */
@media (min-width: 801px) and (max-width: 1100px) and (min-height: 720px) {
  .app-shell.is-insurer .side { overflow: visible; }
}
@media (max-width: 800px) {
  .side-mark { display: block; }
  /* Section 12's rail centres the brand with justify-items, which Chromium
     now applies to block children too, and its 800px nav leaves that set:
     the mark and the tagline sit flush left under TEGO's logo, as at full
     width. */
  .app-shell.is-insurer .side-brand { justify-items: start; }
}

/* What block 16 does for ops and the insurer pages need too: an anchor
   drawn as a primary button keeps its light label, a title or lede typed
   by a person breaks inside the head, the title keeps a column of its
   own, and a nowrap figure over its line keeps the console's spacing. */
.app-shell.is-insurer a.btn-primary { color: var(--surface); }
.app-shell.is-insurer .page-head h1,
.app-shell.is-insurer .page-head .lede { overflow-wrap: anywhere; }
.app-shell.is-insurer .page-head .head-text { min-width: min(240px, 100%); }
.app-shell.is-insurer .tbl .cell-nowrap + .cell-sub { margin-top: 1px; }

/* The footer: the personal-data line, then the company line, laid out as
   the ops footer is; each wraps onto its own lines on a phone. */
.ins-foot { align-items: flex-start; }
.ins-foot img { margin-top: 1px; }
.ins-foot span { flex: 1 1 300px; min-width: 0; line-height: 1.45; }
.ins-foot span:last-child { flex: 0 1 auto; margin-left: auto; }
@media (max-width: 720px) {
  .ins-foot span,
  .ins-foot span:last-child { flex-basis: 100%; margin-left: 0; }
}

/* The dashboard (js/insurer/dashboard.js). Its figures are app.js stat
   cards in a grid that closes up when ops leave some off (section 13's
   .ins-stats is the Insurers list's figures: this one is the dashboard's).
   A phone takes them two a row, the tile over the figure, so a label of
   three words and a premium keep their card. */
.ins-dash > .ins-stats { grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 16px; margin: 0; }
@media (max-width: 800px) {
  .ins-dash > .ins-stats { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
  .ins-dash > .ins-stats .stat { padding: 14px; }
  .ins-dash > .ins-stats .stat-row { flex-direction: column; align-items: flex-start; gap: 10px; }
  .ins-dash > .ins-stats .stat-tile { width: 40px; height: 40px; }
  .ins-dash > .ins-stats .stat-value { font-size: 22px; }
  .ins-dash > .ins-stats .stat-label { font-size: 13px; }
  .ins-dash > .ins-stats .stat-delta { margin-top: 10px; font-size: 12px; }
}
/* The period switch beside the mark: the count pills (section 16) without
   a count. The head's side never runs past the page: on a phone the
   switch scrolls in its own row. */
.app-shell.is-insurer .page-head .head-side { min-width: 0; max-width: 100%; }
.app-shell.is-insurer .page-head .head-side .ins-mark { flex: none; }
.ins-period { min-width: 0; }
.ins-period .pill { height: 32px; }
/* Waiting longest and Renewals due: a line a file or a policy, what
   identifies it in bold with its customer, over the vehicle and when.
   Each line ellipsizes (the when never gives way), so a row is two lines
   at most. */
.ins-lines { display: grid; grid-template-columns: minmax(0, 1fr); }
.ins-line { display: grid; gap: 2px; padding: 11px 0; border-bottom: 1px solid var(--border); }
.ins-line:first-child { padding-top: 0; }
.ins-line:last-child { padding-bottom: 0; border-bottom: 0; }
.ins-line-main { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 14px; color: var(--ink-2); }
.ins-line-main b { font-weight: 600; color: var(--ink); }
.ins-line-sub { display: flex; min-width: 0; white-space: nowrap; font-size: 13px; color: var(--muted); }
.ins-line-what { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.ins-line-when { flex: none; }
.ins-line-what + .ins-line-when { margin-left: 0.35em; }
a.ins-line:hover .ins-line-main b { color: var(--brand); }
a.ins-line:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; border-radius: 8px; }
/* Your rate table: the date over the note, then Request a change. */
.ins-dash .ins-rate-date { margin: 0 0 4px; font-size: 14px; font-weight: 600; color: var(--ink); }
.ins-dash .ins-rate-ask { width: 100%; margin-top: 14px; }

/* Ops' Their dashboard card (js/ops/insurer.js): a checkbox a widget, its
   title over its note, the box on the title's line. */
.ops-widget-list { display: grid; gap: 12px; }
.ops-widget { display: grid; grid-template-columns: 17px minmax(0, 1fr); gap: 0 10px; align-items: start; cursor: pointer; }
.ops-widget input { width: 17px; height: 17px; margin: 2px 0 0; accent-color: var(--brand); }
.ops-widget b { display: block; font-size: 14px; font-weight: 600; line-height: 21px; color: var(--ink); }
.ops-widget-note { display: block; font-size: 13px; line-height: 1.45; color: var(--muted); }
.ops-widgets .ops-widget-hint { margin: 16px 0 0; font-size: 12px; color: var(--muted); }
.ops-widgets .auth-error { margin: 12px 0 0; }
.ops-widgets [data-act="save-widgets"] { margin-top: 16px; }

/* A file (js/insurer/file.js): ops' file page (block 16's .ops-note,
   .ops-timeline, .ops-checks, .held-line …) in the insurer's order. From
   1241px the main column (summary, answers, report, timeline) sits beside
   a 360px rail (decision, documents, notes). Narrower, the two columns are
   display: contents, so their cards are one flex column's own and order
   puts them as the spec lists them: the decision second, under the
   summary it acts on, the long answers after the notes. */
.ins-file { display: flex; flex-direction: column; gap: 16px; }
.ins-file > .ins-main,
.ins-file > .ins-rail { display: contents; }
.ins-file [data-card="summary"] { order: 1; }
.ins-file [data-card="decision"] { order: 2; }
.ins-file [data-card="documents"] { order: 3; }
.ins-file [data-card="notes"] { order: 4; }
.ins-file [data-card="answers"] { order: 5; }
.ins-file [data-card="report"] { order: 6; }
.ins-file [data-card="timeline"] { order: 7; }
@media (min-width: 1241px) {
  .ins-file { display: grid; grid-template-columns: minmax(0, 1fr) 360px; align-items: start; }
  .ins-file > .ins-main,
  .ins-file > .ins-rail { display: grid; grid-template-columns: minmax(0, 1fr); gap: 16px; }
}
/* The head's received date beside the status; a typed address or a long
   file name breaks rather than push a phone's page sideways, and the label
   column gives up room on a phone (as ops' file does). */
.ins-received { font-size: 14px; color: var(--ink-2); white-space: nowrap; }
.ins-file .data-grid dd { overflow-wrap: anywhere; }
/* Documents sit in the 360px rail, which beside a Download left a name
   eight letters and its line three: a row's automatic minimum (its file
   name at full length) is released, and Download goes under the name, in
   line with it, as the portal's rows do on a phone. */
.ins-file .doc-list .doc-row { min-width: 0; flex-wrap: wrap; row-gap: 8px; }
.ins-file .doc-list .doc-text { flex: 1 1 calc(100% - 46px); }
.ins-file .doc-list .doc-row .btn { margin-left: 46px; }
@media (max-width: 720px) {
  .ins-file .data-grid > div { gap: 12px; }
  .ins-file .data-grid dt { width: 96px; }
}

/* The summary's offer: TEGO's breakdown of the insurer's table, a line a
   step with its rupees right-aligned, the premium last over a hairline. A
   payment a line, its Simulation pill after it. */
.ins-breakdown { display: grid; gap: 4px; max-width: 340px; margin-top: 10px; padding: 10px 12px; border-radius: 10px;
  background: var(--tone-muted-bg); font-size: 13px; font-weight: 400; }
.ins-bd-title { margin-bottom: 2px; font-size: 12px; font-weight: 700; color: var(--muted); }
.ins-bd-line { display: flex; justify-content: space-between; gap: 12px; color: var(--ink-2); }
.ins-bd-line > span:last-child { flex: none; text-align: right; white-space: nowrap; font-variant-numeric: tabular-nums; }
.ins-bd-line.is-total { margin-top: 2px; padding-top: 6px; border-top: 1px solid var(--border); font-weight: 600; color: var(--ink); }
@media (max-width: 720px) {
  .ins-file .data-grid > .ins-offer-row { flex-direction: column; align-items: stretch; gap: 6px; }
  .ins-file .data-grid > .ins-offer-row dt { width: auto; }
  .ins-breakdown { max-width: none; }
}
.ins-pay { display: block; }
.ins-pay + .ins-pay { margin-top: 6px; }
.ins-pay .badge { margin-left: 6px; vertical-align: middle; }

/* The proposal in the insurer's order: a fold of sixteen questions each,
   the question's number muted before it and the answer beside it; on a
   phone the answer sits under its question, in line with its words. */
.ins-folds summary { font-size: 14px; }
.ins-answers { display: grid; margin: 0; padding-bottom: 12px; }
.ins-answer { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 4px 16px; padding: 9px 0; border-top: 1px solid var(--border); }
.ins-answer:first-child { padding-top: 0; border-top: 0; }
.ins-answer dt { display: flex; gap: 8px; min-width: 0; font-size: 13px; line-height: 1.45; color: var(--ink-2); overflow-wrap: anywhere; }
.ins-qid { flex: none; width: 30px; font-weight: 600; color: var(--muted); font-variant-numeric: tabular-nums; }
.ins-answer dd { min-width: 0; margin: 0; font-size: 14px; font-weight: 500; line-height: 1.45; color: var(--ink); overflow-wrap: anywhere; }
.ins-answer dd .badge { margin-left: 6px; vertical-align: middle; }
.ins-answer.is-not-asked dd { font-weight: 400; color: var(--muted); }
@media (max-width: 720px) {
  .ins-answer { grid-template-columns: minmax(0, 1fr); }
  .ins-answer dd { padding-left: 38px; }
}
.ins-report-note { margin-bottom: 8px; font-size: 13px; line-height: 1.5; color: var(--muted); }

/* The decision: its three buttons stacked the rail's width, or the one line
   a decided file reads. */
.ins-decide { display: grid; gap: 10px; }
.ins-decide .btn { width: 100%; justify-content: center; }
.ins-decided { font-size: 14px; line-height: 1.5; color: var(--ink-2); }

/* The Issue drawer (on <body>, so tego.css tokens): the warning under a
   premium that is not what the customer paid, in the Send drawer's warn
   pair, and the three optional papers in tighter drop zones. */
.ins-paid-warn {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  margin: 0 0 14px;
  padding: 8px 10px;
  border-radius: 10px;
  background: var(--warn-bg);
  color: color-mix(in srgb, var(--error) 62%, var(--warn-border));
  font-size: 13px;
  line-height: 1.45;
}
.ins-paid-warn[hidden] { display: none; }
.ins-paid-warn .ico { flex: none; margin-top: 1px; }
.ins-papers-note { margin: 4px 0 12px; }
.ins-papers { gap: 12px; }
.ins-papers .dropzone { padding: 12px 14px; }

/* Claims (js/insurer/claims.js): the queue's flush card, a row that opens
   in place (section 7's .row-detail) to the history, the photos and the
   notes: three columns side by side, two under 1101px (the notes a row of
   their own), one on a phone. Where the table is wider than its box (a
   tablet's icon rail), the opened claim keeps to the box's visible width
   rather than scroll away with the table. */
.ins-claims .tbl tbody tr:not(.row-detail):not(.tbl-empty) { cursor: pointer; }
.ins-claims .tbl-wrap { container: ins-claims / inline-size; }
/* The eight columns need 900px of card (1280's is 990px); narrower (the
   1100px icon rail), Updated gives way rather than put Open past the edge. */
.ins-claims { container: ins-claim-list / inline-size; }
@container ins-claim-list (width < 900px) {
  .ins-claims .tbl .col-updated { display: none; }
}
.ins-claims .tbl tbody tr.row-detail td { white-space: normal; }
.ins-claim-holder { position: sticky; left: 18px; max-width: calc(100cqw - 36px); }
.ins-claim-open { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 20px 28px; align-items: start; }
.ins-claim-part { min-width: 0; }
.ins-claims .tbl .ins-claim-part .rd-title { margin: 0 0 12px; }
.ins-claim-part .card-text { font-size: 14px; color: var(--muted); }
.ins-claim-part .ops-note-form { margin-top: 14px; padding-top: 14px; }
.ins-claim-part .ops-note-form textarea { min-height: 84px; }
.ins-claim-fail { display: flex; align-items: center; flex-wrap: wrap; gap: 10px 14px; }
@media (max-width: 1100px) {
  .ins-claim-open { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .ins-claim-part[data-part="notes"] { grid-column: 1 / -1; }
}
/* On a phone the table stacks into cards (section 15's .tbl-stack: six
   columns and a button never fit), the secondary columns go as on a phone
   queue, Open is the card's last line, and the opened claim hangs under
   its card as the rest of it, one part over the next. The queue's narrow
   gutters are a desktop table's, so a stacked cell keeps section 15's. */
@media (max-width: 720px) {
  .ins-claims .tbl-wrap { padding: 12px; }
  .ins-claims .tbl-stack .tbl tbody td { padding: 8px 0; background: transparent; }
  .ins-claims .tbl-stack .tbl td.col-wide { display: none; }
  .ins-claims .tbl-stack .ins-claim-toggle { width: 100%; justify-content: center; }
  .ins-claims .tbl-stack .tbl tr.is-open { margin-bottom: 0; border-radius: 12px 12px 0 0; background: var(--mist); }
  .ins-claims .tbl-stack .tbl tr.row-detail { padding: 14px 12px 16px; border-top: 0; border-radius: 0 0 12px 12px; background: var(--brand-tint); }
  .ins-claims .tbl-stack .tbl tr.row-detail td { display: block; padding: 0; text-align: left; }
  .ins-claims .tbl-stack .tbl tr.row-detail td::before { content: none; }
  .ins-claim-holder { position: static; max-width: none; }
  .ins-claim-open { grid-template-columns: minmax(0, 1fr); gap: 18px; }
}

/* The book's lists (js/insurer/policies.js, documents.js, customers.js,
   team.js): the queue's flush card and its .queue-wide gutters (block 16),
   its pills and pager. A typed vehicle, a file name and an uploader are one
   ellipsised line, the file name whole in its title. */
.ins-policies .tbl td.col-vehicle,
.ins-customers .tbl td.col-vehicle { max-width: 150px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Policies' eleven columns need 1110px of card, which a 1440 screen gives;
   a laptop's 1280 gives 990 (975 beside a classic scrollbar). There the
   start (a year before the expiry beside it) gives way, the vehicle keeps
   100px and the middle cells tighten, as the ops queue's do; under 970px
   (the 1100px icon rail) the plate goes too; only a phone scrolls the
   list in its box. A cover named in three words wraps rather than widen
   the row. */
.ins-policies { container: ins-policies / inline-size; }
.ins-policies .tbl td.col-vehicle { max-width: 110px; }
.ins-policies .tbl td.col-cover { white-space: normal; }
@container ins-policies (width < 1110px) {
  .ins-policies .tbl .col-starts { display: none; }
  .ins-policies .tbl td.col-vehicle { max-width: 100px; }
  .ins-policies .queue-wide .tbl thead th:not(:first-child):not(:last-child),
  .ins-policies .queue-wide .tbl tbody td:not(:first-child):not(:last-child) { padding-left: 3px; padding-right: 3px; }
  .ins-policies .queue-wide .tbl .cell-client { max-width: 140px; }
  /* Expires, after the right-aligned premium, keeps a gap the eye reads as two figures. */
  .ins-policies .queue-wide .tbl thead th.col-expires:not(:first-child):not(:last-child),
  .ins-policies .queue-wide .tbl tbody td.col-expires:not(:first-child):not(:last-child) { padding-left: 10px; }
}
@container ins-policies (width < 970px) {
  .ins-policies .tbl .col-plate { display: none; }
}
.ins-docs .ins-doc-name { display: block; max-width: 200px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; text-decoration: none; }
.ins-docs .tbl td.col-by { max-width: 170px; overflow: hidden; text-overflow: ellipsis; }
.ins-docs a.ins-doc-name:hover { color: var(--brand); }
.ins-docs .tbl .badge { white-space: nowrap; }
/* On a phone the name (the download itself) gives way, so what it is and
   what it is on come into view; a customer's name, beside two figures
   only, keeps more of itself than Clients' 104px. */
@media (max-width: 720px) {
  .ins-docs .ins-doc-name { max-width: 140px; }
  .ins-customers .queue-wide .tbl a.cell-client,
  .ins-customers .queue-wide .tbl span.cell-client { max-width: 150px; }
}

/* Upload paperwork's one target, named where a select would be. */
.ins-up-on { margin: 0; font-size: 14px; font-weight: 600; color: var(--ink); overflow-wrap: anywhere; }
.ins-up-where:empty { display: none; }

/* Team: the line saying TEGO adds people, the mail to ask beside it, in a
   card of a banner's padding (tego.css's 28px and the body's 20px would
   frame one line in 50px); on a phone the button takes a row of its own.
   The name and the address wrap there (the address after its @), so
   Status stays in the card. */
.card.ins-team-card { padding: 16px 20px; }
.card.ins-team-card > .card-body { padding: 0; }
.ins-team-note { display: flex; align-items: center; flex-wrap: wrap; gap: 12px 14px; }
.ins-team-tile { display: grid; place-items: center; flex: none; width: 36px; height: 36px; border-radius: 999px;
  background: var(--brand-soft); color: var(--brand); }
.ins-team-note .card-text { flex: 1 1 220px; min-width: 0; color: var(--ink-2); }
@media (max-width: 720px) {
  .ins-team-note .btn { flex: 1 1 100%; justify-content: center; }
  .ins-team .tbl td.col-name,
  .ins-team .tbl td.col-email { white-space: normal; }
  .ins-team .tbl td.col-email { overflow-wrap: anywhere; }
}

/* The Rate table (js/insurer/rates.js): the rate file's note and date in
   a card of the Team note's padding, then a card a section down the main
   column, Your requests in the 340px rail (one column under 1241px, as
   section 5's grid-main-rail goes). A section's label takes the larger
   share of its row, so "Each claim in the last 3 years" keeps one line at
   a laptop's width and the figures start on one edge. */
.card.ins-rate-intro-card { padding: 18px 20px; }
.card.ins-rate-intro-card > .card-body { padding: 0; }
.ins-rate-intro { display: flex; align-items: flex-start; gap: 14px; }
.ins-rate-tile { display: grid; place-items: center; flex: none; width: 36px; height: 36px; border-radius: 999px;
  background: var(--brand-soft); color: var(--brand); }
.ins-rate-intro-text { display: grid; gap: 4px; flex: 1; min-width: 0; }
.ins-rates .ins-rate-date { margin: 0; font-size: 15px; font-weight: 600; color: var(--ink); }
.ins-rate-note { margin: 0; font-size: 13px; color: var(--muted); }
.ins-rate-intro .card-text { margin-top: 6px; color: var(--ink-2); }
/* The sections are one reference read down the page: their cards drop
   tego.css's 28px to 8px (the head's and the body's own padding stay),
   so seven cards are not mostly frame and a phone's row keeps 300px, not
   260px. */
.app-shell.is-insurer .ins-rates .card[data-section] { padding: 8px; }
.ins-rate-grid { margin: 0; }
.ins-rate-grid > div { gap: 16px; }
.ins-rate-grid dt { width: 48%; }
.ins-rate-grid dd { overflow-wrap: anywhere; font-variant-numeric: tabular-nums; }
/* Your requests: a request a block, what it is about beside its date, the
   insurer's words with their line breaks, who asked and when. */
.ins-requests { display: grid; margin: 0; padding: 0; list-style: none; }
.ins-request { padding: 12px 0; border-bottom: 1px solid var(--border); }
.ins-request:first-child { padding-top: 0; }
.ins-request:last-child { padding-bottom: 0; border-bottom: 0; }
.ins-request-head { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: 2px 12px; }
.ins-request-area { font-size: 14px; font-weight: 600; color: var(--ink); }
.ins-request-from { font-size: 13px; color: var(--muted); white-space: nowrap; }
.ins-request-words { margin: 6px 0 0; font-size: 14px; line-height: 1.5; color: var(--ink-2); white-space: pre-line; overflow-wrap: anywhere; }
.ins-request-by { margin: 6px 0 0; font-size: 12px; color: var(--muted); }
/* Request a change (on <body>): the field the error names wears it. */
.drawer .field [aria-invalid="true"] { border-color: var(--error); }

/* Ops' Insurer decision card (js/ops/file.js, the rail under Actions): the
   insurer's line, a decline's reason over its hint, the insurer's words
   set off by a rule as theirs (a note's own type, line breaks kept), and,
   once TEGO moved the file, a muted last line. */
.ops-decision { display: grid; gap: 10px; }
.ops-decided { font-size: 14px; font-weight: 600; line-height: 1.5; color: var(--ink); overflow-wrap: anywhere; }
.ops-decision-reason { font-size: 14px; line-height: 1.5; color: var(--ink-2); }
.ops-decision-note { padding-left: 12px; border-left: 3px solid var(--border); }
.ops-decision-since { font-size: 13px; line-height: 1.45; color: var(--muted); }

/* ---- 18. Money (P5) ---------------------------------------------------------
   The money pages (js/ops/money.js, statements.js, statement.js, credit.js
   and js/insurer/statements.js) and what P5 adds to P2's and P3's pages.
   Every rule here is scoped to the page it serves unless it is a component
   of its own.

   A sidebar count that is a problem rather than work waiting (Monthly
   payments: the plans past the threshold) wears the warn tone, on the ops
   sidebar's ink and on the light shells alike. Only its colours change: the
   pill keeps each layout's size and the icon rail's ring (sections 2 and 12,
   block 16). */
.side-nav .count-pill.is-warn,
.app-shell.is-ops .side-nav .count-pill.is-warn { background: var(--tone-warn-bg); color: var(--tone-warn-ink); }

/* "Monthly payments" and its count are a few pixels too wide for the ops
   sidebar's 232px line (the label's box is 117px, its text 121px, 124px in
   bold when its page is open), so the label ends in an ellipsis. Let it run
   8px into the gap before the pill: the pill stays where it is, and a label
   that fills its line sits 5px from it. A two-digit count still shortens it
   with an ellipsis, never over the pill. The icon rail hides the labels. */
.app-shell.is-ops .side-nav .nav-label { margin-right: -8px; }

/* The ops side scrolls inside itself once the window is shorter than its
   fourteen items and the help card (~1067px). A classic scrollbar there, the
   ~15px one Windows Chrome and Edge draw, takes the same off every label's
   line (the 117px above is 102px) and "Monthly payments" is back to its
   ellipsis, so the side draws none. It still scrolls by wheel, by keyboard
   focus and by touch. Block 16's scrollbar-color colours nothing now. */
.app-shell.is-ops .side { scrollbar-width: none; }
.app-shell.is-ops .side::-webkit-scrollbar { display: none; }

/* With no bar nothing said the side scrolls, and on a 1366x768 laptop P2's
   last items sat below the fold with no cue. A soft light glow at its foot
   (and at its head once scrolled) says there is more, in CSS alone: two ink
   covers that move with the content (local) over two glows held at the
   box's edges (scroll), so at either end a cover hides its glow, and where
   nothing scrolls nothing shows. A child with a background of its own (the
   help card) paints over the glow. */
.app-shell.is-ops .side {
  background:
    linear-gradient(var(--ink) 30%, transparent) center top / 100% 40px no-repeat local,
    linear-gradient(transparent, var(--ink) 70%) center bottom / 100% 40px no-repeat local,
    radial-gradient(farthest-side at 50% 0, rgba(255, 255, 255, 0.18), transparent) center top / 100% 14px no-repeat scroll,
    radial-gradient(farthest-side at 50% 100%, rgba(255, 255, 255, 0.18), transparent) center bottom / 100% 14px no-repeat scroll,
    var(--ink);
}

/* Block 16 lets the rail's tooltips out from 720px tall, a height sized for
   the ops sidebar's old eleven items. The brand, fourteen items and two
   dividers end 781px down now, so in a window 720 to 780px tall the last
   items (Settings, and Activity logs under 733px) sat below the bottom of a
   box that no longer scrolled. There the side scrolls again, as it does under
   720px, and its tooltips are clipped as they are there. A fifteenth item
   moves the 780: the nav-rail scenario of tools/check-money.mjs measures the
   rail and fails when it does. */
@media (min-width: 801px) and (max-width: 1100px) and (min-height: 720px) and (max-height: 780px) {
  .app-shell.is-ops .side { overflow-y: auto; }
}

/* The four money cards (the Money page, the dashboard's row, and Monthly
   payments' buckets): section 6's stat cards, four across, two by two from
   1240px down, where P2's .grid-4 goes two by two (section 5): from 1101 to
   1240 a seven-figure amount ran past its card four across. Each note is a
   line of its own under the figure. On a phone the tile goes over the
   figure, as the insurer dashboard's do (block 17), so a label of three
   words keeps its card. */
.money-cards { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 16px; }
@media (max-width: 1240px) {
  .money-cards { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
}
/* A figure keeps its line. "Rs 201,244", a worked book's Due to insurers,
   broke after "Rs" in the 236px card at 1280, where the tile left it 132px.
   A card whose figure does not fit beside its tile puts it under the tile,
   as a phone's cards do; a seven-figure amount is no rarer for a broker. */
.money-stat .stat-row { flex-wrap: wrap; row-gap: 10px; }
.money-stat .stat-value { white-space: nowrap; }
.money-stat .stat-note { margin: 8px 0 0; font-size: 13px; line-height: 1.4; color: var(--muted); overflow-wrap: anywhere; }
.money-stat .stat-note + .stat-note { margin-top: 2px; }
/* The insurer dashboard's two money figures (P5's opt-in Due from TEGO and
   TEGO commission, marked is-money by js/insurer/dashboard.js) in P3's
   200px cards: the same two rules. */
.ins-dash > .ins-stats .stat.is-money .stat-row { flex-wrap: wrap; row-gap: 10px; }
.ins-dash > .ins-stats .stat.is-money .stat-value { white-space: nowrap; }
@media (max-width: 720px) {
  .money-cards .stat { padding: 14px; }
  .money-cards .stat-row { flex-direction: column; align-items: flex-start; gap: 10px; }
  .money-cards .stat-tile { width: 40px; height: 40px; }
  .money-cards .stat-value { font-size: 20px; }
  .money-cards .stat-label { font-size: 13px; }
  .money-stat .stat-note { font-size: 12px; }
}

/* The dashboard's row: its title, the Simulation pill and Open Money on one
   line over the four cards. It is a labelled section, and tego.css gives
   every section 3 to 6.5rem of air above and below: none here. */
.money-row { display: grid; gap: 12px; padding: 0; }
.money-row-head { display: flex; align-items: center; flex-wrap: wrap; gap: 8px 12px; }
.money-row-head h2 { font-size: 18px; }
.money-row-head .btn { margin-left: auto; }

/* The month switch in the head. */
.money-month { max-width: 200px; }

/* What stops a statement being issued (the Money page's strip, a
   statement's banner): a warn panel of lines, each a link where there is
   something to fix. */
.money-problems { display: grid; gap: 8px; padding: 14px 16px; border-radius: var(--radius); background: var(--tone-warn-bg); color: var(--tone-warn-ink); }
.money-problems h3 { display: flex; align-items: center; gap: 8px; font-size: 15px; color: inherit; }
.money-problems ul { display: grid; gap: 6px; margin: 0; padding-left: 26px; font-size: 14px; line-height: 1.5; }
.money-problems a { color: inherit; font-weight: 600; text-decoration: underline; overflow-wrap: anywhere; }

/* Due to insurers by age: three tiles, the 60+ one in the warn tone once it
   holds money (TEGO's payables: late remittance is the risk). Three across
   at every width: a phone's tile still holds "Rs 16,147". */
.money-age { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 12px; }
.money-age-tile { display: grid; gap: 2px; padding: 12px 14px; border: 1px solid var(--border); border-radius: 12px; min-width: 0; }
.money-age-label { font-size: 13px; color: var(--muted); }
.money-age-value { font-size: 18px; font-weight: 700; color: var(--ink); font-variant-numeric: tabular-nums; overflow-wrap: anywhere; }
.money-age-count { font-size: 12px; color: var(--muted); }
.money-age-tile.is-warn { border-color: transparent; background: var(--tone-warn-bg); }
.money-age-tile.is-warn .money-age-label,
.money-age-tile.is-warn .money-age-value,
.money-age-tile.is-warn .money-age-count { color: var(--tone-warn-ink); }
@media (max-width: 720px) {
  .money-age { gap: 8px; }
  .money-age-tile { padding: 10px; }
  .money-age-value { font-size: 15px; }
  /* The card's own 28px and its body's 20px left a tile 56px for "Rs 35,963",
     which broke after "Rs": the card gives up its 28px. */
  .card[data-card="by-age"] { padding-inline: 0; }
}

/* By insurer and by partner: a figure on one line, right-aligned in its
   column; the insurer's mark kept to its row. */
.money-table .cell-money { white-space: nowrap; font-variant-numeric: tabular-nums; }
.money-table .ins-mark { --ins-h: 18px; max-width: 110px; }

/* P2's Partner page on a phone: "Sept" is a letter longer than any other
   month, and a referral dated in September ("27 Sept 2026", as P5's seed
   dates Rohan's) made the referrals table 3px wider than its card. The
   customer's name gives up 8px, as the queue's does (block 16). */
@media (max-width: 720px) {
  .ops-referrals .tbl .cell-client { max-width: 104px; }
}

/* A stacked money table (section 15's .tbl-stack: every row a card on a
   phone) drops its col-wide cells there as a queue does: the stack's
   display: flex outranks block 16's .tbl .col-wide, so the money tables
   say it again. */
@media (max-width: 720px) {
  .money-stack .tbl-stack .tbl td.col-wide { display: none; }
}

/* The queue's narrow gutters (block 16's .queue-wide: 16px on a row's first
   and last cell) are a desktop table's. On a phone they indented a card's
   first line and last figure against the rest, and the cards hugged the
   flush card's edges. A stacked cell keeps section 15's padding, the cards
   sit 12px in, and block 7's row hover, which a touch leaves behind, does
   not tint one (P3's claims table does the same). */
@media (max-width: 720px) {
  .money-stack .tbl-wrap { padding: 12px; }
  .money-stack .tbl-stack .tbl tbody td { padding: 8px 0; background: transparent; }
}

/* The Statements list (js/ops/statements.js): the file queue's flush card
   and filter bar (block 16); the party select's two groups keep it to the
   bar's width. */
.money-statements .queue-filters .inline-select { max-width: 220px; }

/* A statement (js/ops/statement.js). From 1241px the banner and the totals
   sit beside a rail (Actions, the seal, the timeline) and the lines take
   the page's width below them; narrower, the grid and its columns are
   display: contents and order lays the cards out as the spec's phone does:
   Actions first, then the banner, the totals, the lines, the seal and the
   timeline. */
.money-statement { display: grid; grid-template-columns: minmax(0, 1fr); gap: 16px; }
.money-statement .data-grid dd { overflow-wrap: anywhere; }
@media (max-width: 1240px) {
  .money-statement { display: flex; flex-direction: column; }
  .money-statement > .grid-main-rail,
  .money-statement > .grid-main-rail > .stack { display: contents; }
  .money-statement [data-card="actions"] { order: 1; }
  .money-statement [data-card="problems"] { order: 2; }
  .money-statement [data-card="totals"] { order: 3; }
  .money-statement [data-card="lines"] { order: 4; }
  .money-statement [data-card="seal"] { order: 5; }
  .money-statement [data-card="timeline"] { order: 6; }
}
.money-problems li.is-blocking { font-weight: 600; }
.money-lines .cell-money { white-space: nowrap; font-variant-numeric: tabular-nums; }
.money-seal { margin: 0 0 6px; }
.money-seal code { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 13px; color: var(--ink); white-space: nowrap; }

/* An insurer's Commission card and a partner's Commission scheme card
   (js/ops/insurer.js, partner.js): the rate in force in the card's own
   weight, the warn tone when none is set, a scheduled one with Delete, the
   history newest first with each row's note under it. */
.money-rate-now { margin: 0; font-size: 15px; font-weight: 600; line-height: 1.45; color: var(--ink); overflow-wrap: anywhere; }
.money-rate-now.money-rate-none { padding: 10px 12px; border-radius: 10px; background: var(--tone-warn-bg); color: var(--tone-warn-ink); font-size: 14px; }
.money-rate-next { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; margin-top: 10px; font-size: 14px; color: var(--ink-2); }
/* The History head sits 16px under the line above it, as a Documents group
   does under the one before (.doc-list + .ops-subhead). */
.money-rate-now + .ops-subhead,
.money-rate-next + .ops-subhead { margin-top: 16px; }
.money-rate-history { display: grid; gap: 8px; margin: 0; padding: 0; list-style: none; }
.money-rate-history li { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 8px; font-size: 14px; color: var(--ink-2); }
.money-rate-note { flex-basis: 100%; font-size: 13px; color: var(--muted); overflow-wrap: anywhere; }

/* Settings → Money: the threshold inside its sentence, the CSV's header in
   a monospace box that scrolls on its own on a phone, the rules a list (the
   page reset takes every list's markers, so the rules bring their own: six
   sentences that wrap to three lines on a phone need them to read apart). */
.money-threshold label { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; font-size: 14px; font-weight: 500; }
.money-threshold input { width: 88px; }
/* The form's error sits 12px clear of Save, as the insurer's Details form's does. */
.money-settings .auth-error { margin-bottom: 12px; }
.money-csv-head { margin: 8px 0 12px; padding: 10px 12px; border-radius: 10px; background: var(--mist); overflow-x: auto; }
.money-csv-head code { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 13px; color: var(--ink); white-space: pre; }
.money-csv-rules { display: grid; gap: 6px; margin: 0 0 16px; padding-left: 20px; list-style: disc; font-size: 14px; line-height: 1.5; color: var(--ink-2); }

/* Monthly payments (js/ops/credit.js): the simulation line under the head,
   the four buckets as linked money cards (two by two on a phone), the
   Cancellation started line, the plans as the queue's card (stacked on a
   phone). Ten columns at a laptop's width keep a heading to two lines
   rather than push the card. */
.money-sim { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; margin: 0; font-size: 14px; line-height: 1.5; color: var(--ink-2); }
/* Scoped to its page: `.app-shell a { color: inherit }` outweighs a lone
   class, and the line drew in ink. A link, so it underlines on hover. */
.money-credit .money-started { justify-self: start; font-size: 14px; font-weight: 600; color: var(--tone-error-ink); }
.money-credit .money-started:hover { text-decoration: underline; }
.money-credit .tbl thead th { white-space: normal; vertical-align: bottom; }
.money-plan-link { padding: 0; border: 0; background: none; font: inherit; cursor: pointer; }
.money-overdue { color: var(--tone-error-ink); font-weight: 600; }
/* The ten columns need about 1010px with "Cancellation started" in the list,
   982px without: at 1280 the card is 990px inside its border, or 975px when the
   page is tall enough for a classic scrollbar (Windows Chrome and Edge). Under
   1040px of card (the list's 1010px and room to spare) the middle cells give
   up 3px a side, as the file queue's do (block 16), and a name is cut at 160px
   with an ellipsis (its drawer has all of it) rather than push the card. Only
   from 721px: a phone's rows are cards, where a name wraps. */
.money-credit .queue-card { container: money-plans / inline-size; }
.money-credit .tbl td.money-customer { white-space: normal; }
@media (min-width: 721px) {
  .money-credit .tbl td.money-customer { max-width: 160px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  @container money-plans (width < 1040px) {
    .money-credit .queue-wide .tbl thead th:not(:first-child):not(:last-child),
    .money-credit .queue-wide .tbl tbody td:not(:first-child):not(:last-child) { padding-left: 3px; padding-right: 3px; }
  }
}
/* On a phone the filter selects pair up, and "Cancellation started" is longer
   than half a row: the status keeps a row of its own, the other two pair up. */
@media (max-width: 720px) {
  .money-credit .queue-filters [data-status] { flex-basis: 100%; }
}

/* The plan drawer: the schedule compact, a payment's amount and day under
   its state on short lines; the warning over the confirm field. */
.money-schedule td.money-state { white-space: normal; }
.money-cancel-note { color: var(--tone-error-ink); font-weight: 600; }

/* The drawers hang off <body>, outside .app-shell where the --tone-* pairs
   live (the Send drawer's warnings, block 13, say the same), so a chip or the
   red warning in these two would draw no colour: their content declares the
   pairs it uses, from the tego.css tokens each stands for. */
.money-plan,
.money-report {
  --tone-ok-bg: color-mix(in srgb, var(--ok) 12%, var(--surface));
  --tone-ok-ink: var(--ok);
  --tone-warn-bg: var(--warn-bg);
  --tone-warn-ink: color-mix(in srgb, var(--error) 62%, var(--warn-border));
  --tone-error-bg: var(--error-bg);
  --tone-error-ink: var(--error);
  --tone-muted-bg: var(--mist);
  --tone-muted-ink: var(--muted);
}
/* A section heading a clear step under what it follows (the base .ops-subhead
   sits 4px under it), and the drawer's error pinned to the top of what is on
   screen: the confirm field is at the foot of a long drawer, and an error
   above the fold was an answer nobody saw. The import drawer's too: its
   Import sits under a long text and a report of up to fifty lines. */
.money-plan .ops-subhead { margin: 20px 0 8px; }
.drawer-body:has(.money-plan) .drawer-error,
.drawer-body:has(.money-report) .drawer-error { position: sticky; top: 0; z-index: 2; }

/* Import lender statement: the CSV in a monospace box that scrolls on its
   own, the file picker beside Check, the report under them. */
.money-csv { min-height: 160px; font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 12px; white-space: pre; overflow-wrap: normal; overflow-x: auto; }
.money-import-acts { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin-bottom: 12px; }
.money-report { display: grid; gap: 6px; font-size: 13px; line-height: 1.45; color: var(--ink-2); }
.money-report .is-clean { color: var(--tone-ok-ink); font-weight: 600; }
.money-report ul { margin: 0; padding-left: 18px; list-style: disc; color: var(--tone-error-ink); }

/* The insurer's Statements page (js/insurer/statements.js): three figures,
   three across from a tablet up and one a row on a phone, the tile beside
   the figure there (block 18's phone rule stacks them for the four-card
   rows); a statement picked from the dashboard tinted in the list. */
.money-cards.is-three { grid-template-columns: repeat(3, minmax(0, 1fr)); }
/* At a tablet's width a figure beside its tile broke after "Rs" ("Rs" over
   "24,200" at 820) and the latest statement's number ran to three lines: a
   figure that does not fit beside its tile goes under it, as the money
   cards' do. No nowrap here: under its tile a number breaks at most at a
   hyphen, where nowrap would push it past an 820 card. */
.money-cards.is-three .stat-row { flex-wrap: wrap; row-gap: 10px; }
@media (max-width: 720px) {
  .money-cards.is-three { grid-template-columns: minmax(0, 1fr); }
  .money-cards.is-three .stat-row { flex-direction: row; align-items: center; gap: 14px; }
}
.ins-statements .tbl tr.is-picked td { background: var(--brand-tint); }
/* The table's eight columns need about 950px. In a narrower card (a tablet
   at 1024 or 820, or a laptop window from 1101 to 1240px, where the full
   sidebar is back) Download sat past the card's edge, so there the lesser
   figures go (Policies, Premium, TEGO commission: the col-wide cells a
   phone drops too) and the row keeps what identifies it, what it pays,
   where it stands and Download. The PDF holds them all. */
.ins-statements .queue-card { container: ins-statements / inline-size; }
@container ins-statements (width < 960px) {
  .ins-statements .tbl .col-wide { display: none; }
}
/* A stacked card is tinted whole: its cells sit inside its padding, so tinting
   them left a white frame round the tint. */
@media (max-width: 720px) {
  .ins-statements .tbl-stack .tbl tr.is-picked { border-color: var(--brand); background: var(--brand-tint); }
  .ins-statements .tbl-stack .tbl tr.is-picked td { background: transparent; }
}

/* Ops' Their dashboard card: an opt-in widget's line under its note. */
.ops-widget-optin { display: block; margin-top: 2px; font-size: 12px; line-height: 1.4; color: var(--tone-warn-ink); }

/* A file's Payment card (js/ops/file.js): a receipt's "· Download" on one
   line, so at 390 the dot no longer ends a line over "Download". */
.money-receipt-dl { white-space: nowrap; }

/* The customer's Receipt column (js/portal-pages.js): Download receipt with
   its arrow on one line, the receipt's number under it; on a phone's
   stacked row the two stay together, right-aligned like every value. */
.cell-receipt { display: inline-grid; justify-items: start; gap: 1px; }
.cell-receipt a { display: inline-flex; align-items: center; gap: 6px; font-weight: 600; color: var(--brand); white-space: nowrap; }
@media (max-width: 720px) {
  .tbl-stack .cell-receipt { justify-items: end; }
}

/* Seven columns made the Payments table 17px wider than its card at 1280 in
   French ("Télécharger le reçu") and left English 4px to spare, and a laptop's
   classic scrollbar takes 15px from the card. From a tablet up its gutters are
   12px, not 16 (the first and last stay 16, so the table keeps its line with
   the card's title): English has ~50px to spare, French ~30px, 15px less beside
   a classic scrollbar. A phone's stacked cards keep theirs. */
@media (min-width: 721px) {
  .tbl-snug .tbl thead th, .tbl-snug .tbl tbody td { padding-left: 12px; padding-right: 12px; }
  .tbl-snug .tbl thead th:first-child, .tbl-snug .tbl tbody td:first-child { padding-left: 16px; }
  .tbl-snug .tbl thead th:last-child, .tbl-snug .tbl tbody td:last-child { padding-right: 16px; }
}

/* Beside a policy's rail the Receipt column is an arrow under its heading, and
   the heading (RECEIPT, 53px) is the widest thing in it: beside a classic
   scrollbar the table was 5px wider than its 563px card in English (French fit
   by 1px). The column gives up its left gutter and most of its right one,
   which leaves ~12px to spare in English and ~19px in French. */
@media (min-width: 721px) {
  .queue-compact .tbl thead th.col-arrow, .queue-compact .tbl tbody td.col-arrow { padding-left: 0; padding-right: 4px; }
}

/* ---- 19. Partner portal (P6) ----------------------------------------------
   The /partner pages (js/partner-app.js) wear the light shell with
   is-partner, as the insurer's wear is-insurer (block 17, which stays the
   insurer's): the preview's sidebar, so a partner never takes its portal
   for TEGO's dark ops console, with TEGO's logo over the partner's name as
   the tagline and no mark (the partner portal draws none). Every rule here
   is scoped to .app-shell.is-partner unless it is a component of its own;
   the partner's pages append their rules under this header. */

/* The rail's labels are its data-tip tooltips, which .side's overflow-y
   clips; wherever the rail fits the screen they show over the page, as
   blocks 16 and 17 let them for ops and the insurer. */
@media (min-width: 801px) and (max-width: 1100px) and (min-height: 720px) {
  .app-shell.is-partner .side { overflow: visible; }
}
/* Section 12's rail centres the brand with justify-items, which its 800px
   nav leaves set: the tagline sits flush left under TEGO's logo there, as
   at full width (block 17 does the same for the insurer's). */
@media (max-width: 800px) {
  .app-shell.is-partner .side-brand { justify-items: start; }
}

/* What blocks 16 and 17 do for ops and the insurer, the partner's pages
   need too: an anchor drawn as a primary button keeps its light label; a
   title or a lede typed by a person (a customer's name as the partner gave
   it) breaks inside the head; the title keeps a column of its own and the
   head's side never runs past the page; a nowrap figure over its line
   keeps the console's spacing. */
.app-shell.is-partner a.btn-primary { color: var(--surface); }
.app-shell.is-partner .page-head h1,
.app-shell.is-partner .page-head .lede { overflow-wrap: anywhere; }
.app-shell.is-partner .page-head .head-text { min-width: min(240px, 100%); }
.app-shell.is-partner .page-head .head-side { min-width: 0; max-width: 100%; }
.app-shell.is-partner .tbl .cell-nowrap + .cell-sub { margin-top: 1px; }

/* The chip's menu is titled with the address signed in (js/partner-app.js)
   and prints it as it was typed: section 3's title is a label in capitals,
   which would show an address nobody types. A long one breaks rather than
   run past the menu. */
.app-shell.is-partner .pop .pop-title {
  text-transform: none;
  letter-spacing: 0;
  font-size: 12px;
  font-weight: 600;
  color: var(--muted);
  overflow-wrap: anywhere;
}

/* The footer: the line about customers' names, then the company line, laid
   out as the ops and insurer footers are; each wraps onto its own lines on
   a phone. */
.ptr-foot { align-items: flex-start; }
.ptr-foot img { margin-top: 1px; }
.ptr-foot span { flex: 1 1 300px; min-width: 0; line-height: 1.45; }
.ptr-foot span:last-child { flex: 0 1 auto; margin-left: auto; }
@media (max-width: 720px) {
  .ptr-foot span,
  .ptr-foot span:last-child { flex-basis: 100%; margin-left: 0; }
}

/* The dashboard (js/partner/dashboard.js). Its four figures are section 6's
   stat cards in .grid-4; on a phone they go two by two (the spec's phone,
   where section 5 would stack them), the tile over the figure as on the
   insurer's dashboard (block 17), so a label of three words keeps its card.
   A figure's line ("Estimated until your statement for September 2026")
   wraps under its icon's first line. */
.ptr-stats .stat-delta { align-items: flex-start; line-height: 1.4; }
.ptr-stats .stat-delta svg { flex: none; margin-top: 1px; }
/* A figure keeps its line: "38% · 3 of 8" broke after "of" in the 236px card
   at 1280, where the tile left it 134px. A card whose figure does not fit
   beside its tile puts it under the tile, as block 18's money cards do and as
   a phone's cards always do. */
.ptr-stats .stat-row { flex-wrap: wrap; row-gap: 10px; }
.ptr-stats .stat-value { white-space: nowrap; }
@media (max-width: 720px) {
  .ptr-stats { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
  .ptr-stats .stat { padding: 14px; }
  .ptr-stats .stat-row { flex-direction: column; align-items: flex-start; gap: 10px; }
  .ptr-stats .stat-tile { width: 40px; height: 40px; }
  .ptr-stats .stat-value { font-size: 20px; }
  .ptr-stats .stat-label { font-size: 13px; }
  .ptr-stats .stat-delta { margin-top: 10px; font-size: 12px; }
}

/* The board (P2's board(), D28): the six statuses side by side from 721px,
   Lost hidden until its control opens it (board() draws it collapsed and
   block 16 hides it); a name breaks rather than being cut, as on the
   pipeline. On a phone it is the pipeline's: one column at a time, its
   cards a list, chosen by P2's count pills, which scroll sideways (six
   statuses do not fit the row of tabs the pipeline's four share). */
.ptr-board .board-card .bc-name { white-space: normal; overflow-wrap: anywhere; }
/* A referral with nothing earned yet has no value to print: board() still
   draws its empty span, whose gap would push the date in from the name's edge. */
.ptr-board .board-card .bc-value:empty { display: none; }
.ptr-board .ptr-board-pills { display: none; margin-bottom: 12px; }
/* Section 1 takes every paragraph's margin (.app-shell p), which a lone class
   does not outrank: the note says so under the board's head. */
.ptr-board .ptr-board-note { margin: 14px 0 0; font-size: 13px; color: var(--muted); }
.ptr-board-note a { font-weight: 600; color: var(--brand); }
.lost-toggle svg { transition: transform 0.16s var(--ease); }
.lost-toggle[aria-expanded="true"] svg { transform: rotate(180deg); }
/* The board is the widest thing on the page: its card gives up tego.css's
   28px, and its columns and cards their gutters from 721px, so six columns
   (Lost open) at a laptop's 1280 still wrap a name at its words ("Rajesh
   Bhugowandeen" broke after its tenth letter with the full gutters). */
.card.ptr-board { padding: 0; }
@media (min-width: 721px) {
  .ptr-board .board { gap: 12px; }
  .ptr-board .board-col { padding: 10px; }
  .ptr-board .board-card { padding: 10px; }
}
@media (max-width: 720px) {
  .ptr-board .ptr-board-pills { display: flex; }
  .ptr-board .lost-toggle { display: none; }
  .ptr-board .board-col:not(.is-current) { display: none; }
  /* The chosen column shows even while collapsed: a book whose only cards
     are Lost opens on Lost, and block 16 would hide it. */
  .ptr-board .board-col.is-current { display: flex; }
  .ptr-board .board-col { padding: 0; border: 0; background: transparent; }
  .ptr-board .board-cards { max-height: none; }
}

/* No referral yet: the empty state's three steps (the preview's How it
   works, made true), a left-aligned list under its centred words. */
.ptr-steps { width: min(440px, 100%); margin: 14px auto 0; text-align: left; }

/* A partner's link as text, to be read and selected whole, and the row of
   buttons under it: the dashboard's Your link here, the link card
   (js/partner-link.js) from Task 13 of P6. */
.app-shell .link-url { margin: 0 0 12px; font-size: 14px; color: var(--ink-2); overflow-wrap: anywhere; user-select: all; }
.link-actions { display: flex; flex-wrap: wrap; gap: 8px; }
.card-text + .link-actions { margin-top: 12px; }

/* Referrals (js/partner/referrals.js): the insurer's lists' flush card and
   filter bar (blocks 16 and 17); a colleague's name in Came through is one
   ellipsised line, as a vehicle is (block 16). On a phone each referral is
   a card of label and value (section 15's .tbl-stack) without its col-wide
   cells: the stack's display: flex outranks block 16's .tbl .col-wide, so
   the list says it again, with P5's stacked tables' gutters (block 18). */
.ptr-referrals .tbl td.col-came { max-width: 160px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
@media (max-width: 720px) {
  .ptr-stack .tbl-stack .tbl td.col-wide { display: none; }
  .ptr-stack .tbl-wrap { padding: 12px; }
  .ptr-stack .tbl-stack .tbl tbody td { padding: 8px 0; background: transparent; }
  /* A card has the room a queue's row has not: block 16 cuts a customer's
     name at 104px on a phone, which left "Rajesh Bhugo..." beside a label
     and a wide gap. The whole name shows, and wraps if it must. */
  .ptr-stack .tbl-stack .tbl a.cell-client { max-width: none; }
  .ptr-stack .tbl-stack .tbl .cell-client .cell-strong { white-space: normal; }
}

/* A referral (js/partner/referral.js), laid out as P3's file page is (block
   17): its status's day beside the badge in the head, as the file's
   Received; from 1241px the record and its history beside a rail holding
   the commission; narrower, one column whose order puts the commission
   under the record and the history last. A note the partner typed keeps
   its lines, and every value breaks rather than run past a phone's card.
   Section 1 takes every paragraph's margin (.app-shell p), which a lone
   class does not outrank: the amount says so under its page's class, or
   its 6px above the line under it would never apply. */
.ptr-since { font-size: 14px; color: var(--ink-2); white-space: nowrap; }
.ptr-referral { display: grid; grid-template-columns: minmax(0, 1fr); gap: 16px; }
.ptr-referral .data-grid dd { overflow-wrap: anywhere; }
.ptr-referral .ptr-note-text { white-space: pre-line; }
.ptr-referral .ptr-commission { margin: 0 0 6px; font: 700 26px/1.15 var(--font-display); letter-spacing: -0.02em; color: var(--ink); }
@media (max-width: 1240px) {
  .ptr-referral { display: flex; flex-direction: column; }
  .ptr-referral > .grid-main-rail,
  .ptr-referral > .grid-main-rail > .stack { display: contents; }
  .ptr-referral [data-card="details"] { order: 1; }
  .ptr-referral [data-card="commission"] { order: 2; }
  .ptr-referral [data-card="history"] { order: 3; }
}
@media (max-width: 720px) {
  .ptr-referral .data-grid > div { gap: 12px; }
  .ptr-referral .data-grid dt { width: 96px; }
}

/* Refer a customer (js/partner/refer.js): the form beside the link card
   from 1241px, the form first and the link card under it below (section
   5's .grid-main-rail). /partner/refer#link stops under the sticky topbar,
   and so does a field the page moves the focus to (the first one in
   error), its label in view, as on P1's portal (block 15). */
.ptr-refer [data-card="link"] { scroll-margin-top: calc(var(--ribbon-h) + var(--top-h) + 16px); }
.app-shell.is-partner :is(input, select, textarea) { scroll-margin-top: calc(var(--ribbon-h) + var(--top-h) + 44px); }
.ptr-refer-form .ptr-consent { margin: 4px 0 16px; font-size: 13px; line-height: 1.5; color: var(--muted); }
/* A failed send says so between the consent line and the button: tego.css's
   6px above a field error loses to section 1's paragraph margin (.app-shell
   p), and the button's own 4px would leave the message touching it. */
.ptr-refer-form [data-error="form"] { margin: 0 0 12px; }
/* After Send the form is replaced and the focus moves to the confirmation's
   lead line (js/partner/refer.js), so a screen reader keeps its place: a line
   nobody tabs to shows no ring, as the proposal's focused titles show none,
   and the page stops with the green tile above it (56px and a 10px gap) in
   view under the sticky topbar. */
.app-shell.is-partner .done-lead { scroll-margin-top: calc(var(--ribbon-h) + var(--top-h) + 82px); }
.app-shell.is-partner .done-lead:focus { outline: none; }

/* The link card (js/partner-link.js): the partner's Your link on Refer,
   ops' Their link on P2's partner page. The QR code is the SVG qr.js
   draws, filling a white square that keeps a quiet zone round it whatever
   the card's colour. */
.link-card { display: grid; gap: 12px; justify-items: start; }
.link-card .ops-code,
.link-card .link-url { margin: 0; }
.qr-box { width: min(220px, 100%); aspect-ratio: 1 / 1; padding: 8px; border: 1px solid var(--border); border-radius: 12px; background: var(--surface); }
.qr-box svg { display: block; width: 100%; height: 100%; }
.link-note { margin: 0; font-size: 13px; line-height: 1.5; color: var(--muted); overflow-wrap: anywhere; }

/* The counter card (js/partner-link.js), printed only: wireLinkCard() puts
   it at body's top level, where the print block below shows it alone (as
   tego.css's print block shows the quote sheet), and on screen it is never
   shown. One A4 page with no page margin of its own, as the quote sheet has
   none (tego.css's print block says why): a page margin makes Chrome print
   its header and footer (title, address, date) in it, and the dialog's
   Margins "None" drops a declared one and leaves the bordered card at the
   paper's corner. The 12 mm inset is the card's own margin in the print
   block, and the card is 270 mm tall inside it, so the card and its margins
   come to 294 mm of the page's 297 (the 3 mm to spare keep rounding from
   spilling a sliver onto a second page): TEGO's logo, the partner's name,
   the offer and the scan line each in English over its French, the QR code
   120 mm wide, the link and TEGO's line, centred, about 245 mm with a
   one-line name, 263 mm with the longest one (80 characters, three lines). */
.counter-card {
  display: none;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 5mm;
  min-height: 270mm;
  padding: 10mm 8mm;
  border: 0.5mm solid var(--border-strong);
  border-radius: 6mm;
  background: var(--surface);
  color: var(--ink);
  text-align: center;
  break-inside: avoid;
  -webkit-print-color-adjust: exact;
  print-color-adjust: exact;
}
.counter-card p { margin: 0; }
.counter-card .cc-logo { width: 46mm; height: auto; }
.counter-card .cc-partner { max-width: 100%; font: 700 8mm/1.15 var(--font-display); overflow-wrap: anywhere; }
.counter-card .cc-pair { display: grid; gap: 1.5mm; }
.counter-card .cc-en { font: 700 7.5mm/1.2 var(--font-display); }
.counter-card .cc-fr { font-size: 5mm; line-height: 1.3; color: var(--ink-2); }
.counter-card .cc-qr { width: 120mm; height: 120mm; }
.counter-card .cc-qr svg { display: block; width: 100%; height: 100%; }
.counter-card .cc-link { font-size: 4.5mm; font-weight: 600; overflow-wrap: anywhere; }
.counter-card .cc-company { font-size: 3.2mm; color: var(--muted); }

@media print {
  @page { size: A4; margin: 0; }
  body:has(> .counter-card) > * { display: none !important; }
  body > .counter-card { display: flex !important; margin: 12mm; }
}

/* Statements and Team (js/partner/statements.js, team.js) open with their
   one line in a card of a banner's padding, its icon beside the words, as
   P3's Team does (block 17); on a phone Team's way to ask for a login takes
   a row of its own. Team's name and address wrap there (the address after
   its @), so Status stays in the card; a statement's rows are P5's stacked
   money table (block 18), each figure to the cent on one line. */
.card.ptr-note-card { padding: 16px 20px; }
.card.ptr-note-card > .card-body { padding: 0; }
.ptr-note { display: flex; align-items: center; flex-wrap: wrap; gap: 12px 14px; }
.ptr-note-tile { display: grid; place-items: center; flex: none; width: 36px; height: 36px; border-radius: 999px;
  background: var(--brand-soft); color: var(--brand); }
.ptr-note .card-text { flex: 1 1 220px; min-width: 0; color: var(--ink-2); }
.ptr-statements .cell-money { white-space: nowrap; font-variant-numeric: tabular-nums; }
@media (max-width: 720px) {
  .ptr-note .btn { flex: 1 1 100%; justify-content: center; }
  .ptr-team .tbl td.col-name,
  .ptr-team .tbl td.col-email { white-space: normal; }
  .ptr-team .tbl td.col-email { overflow-wrap: anywhere; }
}

/* P2's partner page as P6 adds to it (js/ops/partner.js). The Logins card's
   table: a login is an avatar, a name and its address in one cell, as on
   P2's Users page (block 16). The name takes the width the other columns
   leave and is cut with an ellipsis past it: the main column is 597px at
   1241px and 636px at 1280px, which five columns fill with a name and an
   address of 195px, and the Users page's fixed 220px put this table 15px
   past its card. On a phone the avatar goes, so Status and the button stay
   in the card (Added and Portal terms are col-wide). A referral one of the
   partner's logins typed says "Referred by" its name under the date,
   wrapping there rather than widen a column block 18 measured to the pixel
   on a phone. The Edit drawer shows such a referral's note as text: it is
   the partner's. */
.ops-logins .tbl td.col-client { width: 100%; max-width: 0; }
.ops-logins .tbl .cell-user { min-width: 0; }
.ops-logins .tbl .cell-user .cell-client { flex: 1 1 0; min-width: 0; max-width: none; }
.ops-referrals .tbl [data-typed] { white-space: normal; overflow-wrap: anywhere; }
.ops-typed-note { margin: 0; font-size: 14px; color: var(--ink); white-space: pre-line; overflow-wrap: anywhere; }
@media (max-width: 720px) {
  .ops-logins .tbl .cell-user .avatar-xs { display: none; }
}

/* ---- 20. E-signature (P7) -----------------------------------------------------
   Ops' Signatures page (js/ops/signatures.js): the queue's flush card, its
   pills and pager (block 16), and a row that opens in place (section 7's
   .row-detail) as a claim does on the insurer's Claims page (block 17): the
   request, its signers with their evidence, and its trail, three columns
   side by side, two under 1101px (the trail a row of its own), one on a
   phone. There the table stacks into cards (section 15's .tbl-stack), Kind,
   Sent and Expires go (the opened request has them), and the opened request
   hangs under its card. Drawers are full width on a phone already (section
   11). */
.ops-sigs .tbl tbody tr:not(.row-detail):not(.tbl-empty) { cursor: pointer; }
.ops-sigs .tbl-wrap { container: ops-sigs / inline-size; }
/* The eight columns in a laptop's card (990px at 1280, 975 beside a classic
   scrollbar): a title is ops' own words, up to 120 characters, so one line
   here, whole in its tooltip and in the opened request; the signers' names
   ellipsise as a client's do; the last date's heading takes two lines
   rather than 70px. Narrower than 900px of card (a tablet, the 1100px icon
   rail), Sent gives way (the opened request has it) and the title keeps
   160px; under 800px Kind goes too; only a phone stacks. */
.ops-sigs .tbl .sig-title { display: block; max-width: 200px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.queue-wide .tbl .ops-sig-signers { max-width: 170px; }
.ops-sigs .tbl thead th.col-end { white-space: normal; }
.ops-sigs { container: ops-sig-list / inline-size; }
@container ops-sig-list (width < 900px) {
  .ops-sigs .tbl .col-sent { display: none; }
  .ops-sigs .tbl .sig-title { max-width: 160px; }
}
@container ops-sig-list (width < 800px) {
  .ops-sigs .tbl .col-kind { display: none; }
}
.ops-sigs .tbl tbody tr.row-detail td { white-space: normal; }
.sig-holder { position: sticky; left: 18px; max-width: calc(100cqw - 36px); }
.sig-open { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 20px 28px; align-items: start; }
.sig-part { min-width: 0; }
.ops-sigs .tbl .sig-part .rd-title { margin: 0 0 12px; }
/* An address, a hash and a device break rather than widen their column. */
.sig-part .data-grid > div { gap: 12px; padding: 8px 0; }
.sig-part .data-grid dt { width: 96px; }
.sig-part .data-grid dd { overflow-wrap: anywhere; }
.sig-message { white-space: pre-line; }
.sig-hash { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 12px; }
.sig-links { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 12px; }
.sig-signer + .sig-signer { margin-top: 16px; padding-top: 14px; border-top: 1px solid var(--border); }
.sig-signer-head { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 10px; margin: 0 0 2px; font-size: 14px; font-weight: 700; color: var(--ink); }
.sig-copy { display: grid; justify-items: start; gap: 6px; margin-top: 10px; }
.sig-copy .hint { font-size: 12px; color: var(--muted); }
.sig-link { justify-self: stretch; }
.sig-link input { width: 100%; min-height: 38px; padding: 8px 10px; border: 1px solid var(--border-strong); border-radius: 10px; background: var(--surface); font: inherit; font-size: 12px; color: var(--ink); }
.sig-fail { display: flex; align-items: center; flex-wrap: wrap; gap: 10px 14px; }
@media (max-width: 1100px) {
  .sig-open { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .sig-part[data-part="trail"] { grid-column: 1 / -1; }
}
@media (max-width: 720px) {
  .ops-sigs .tbl-wrap { padding: 12px; }
  .ops-sigs .tbl-stack .tbl tbody td { padding: 8px 0; background: transparent; }
  .ops-sigs .tbl-stack .tbl td.col-wide { display: none; }
  .ops-sigs .tbl-stack .tbl .sig-title { max-width: 190px; }
  .ops-sigs .tbl-stack .tbl tr.is-open { margin-bottom: 0; border-radius: 12px 12px 0 0; background: var(--mist); }
  .ops-sigs .tbl-stack .tbl tr.row-detail { padding: 14px 12px 16px; border-top: 0; border-radius: 0 0 12px 12px; background: var(--brand-tint); }
  .ops-sigs .tbl-stack .tbl tr.row-detail td { display: block; padding: 0; text-align: left; }
  .ops-sigs .tbl-stack .tbl tr.row-detail td::before { content: none; }
  .sig-holder { position: static; max-width: none; }
  .sig-open { grid-template-columns: minmax(0, 1fr); gap: 18px; }
}
/* An open row is mist (section 7), the muted chip's own ground: on it a
   cancelled or expired request's chip keeps a white one. */
.ops-sigs .tbl tbody tr.is-open .badge.t-muted { background: var(--surface); }
/* Send for signature: its error pinned to the top of what is on screen
   (Send sits at the foot of a long drawer, as block 18's plan drawer
   found), flush with the drawer's head: at top 0 the body's 20px padding
   showed what scrolled under it. Each signer's fields under their own
   heading, Add a second signer under signer 1, the drop zone wearing the
   PDF's error. */
.drawer-body:has(.sig-send) .drawer-error { position: sticky; top: -20px; z-index: 2; }
.sig-send .ops-subhead { margin: 18px 0 8px; }
.sig-send .sig-add,
.sig-send [data-remove-signer] { margin-bottom: 14px; }
.sig-send .sig-add[hidden] { display: none; }
.sig-send .uploader:has(.dz-input[aria-invalid="true"]) .dropzone { border-color: var(--error); }
/* Task 19's "Check the signature" link on the insurer's and ops' declared line, which `.app-shell a` would paint grey. */
.ops-declared a.ops-link { color: var(--brand); }
/* Signatures makes the ops side fifteen items (48px more: 44px and a 4px
   gap), so block 18's figures, counted on P5's fourteen, read one item
   short: the full side scrolls under ~1115px tall (not ~1067px), and the
   1100px icon rail's brand, fifteen items and two dividers end 829px down
   (828.58: 18px of padding, the 18.58px logo over its 14px, nine, three and
   three items with their gaps, two 25px dividers, five 4px gaps), not 781px.
   In a window under 829px tall Settings sat below the fold of a side block
   16 had stopped scrolling: there the side scrolls, and clips its tooltips.
   This rule starts where block 16 does, at 720px, and so overlaps block
   18's 720 to 780px with the same declaration: a window between 780 and
   781px tall (a fractional height, at 125% Windows scaling or a browser's
   zoom) matched neither rule while block 18 ended at 780 and this began at
   781 (P7's final review, F18). tools/check-money.mjs's nav-rail measures
   the rail's end and checks the heights either side of it. */
@media (min-width: 801px) and (max-width: 1100px) and (min-height: 720px) and (max-height: 828px) {
  .app-shell.is-ops .side { overflow-y: auto; }
}
