/* TrimPilot Mobile — dashboard/pilot/app.css (Stage 4 build plan §7.1, PR-1 full port)
 *
 * Three layers, in this exact order (cascade matters — later wins):
 *   1. The engine CSS from docs/pilot/spec/proto.html lines 171-620 (tokens, .tp-* hooks, S1-S8,
 *      cards, sheet, rows) MINUS the mock-only rules listed in the Stage 4 plan §7.2 (the MOCK-UP
 *      chrome, the drawn phone OS — status bar, home indicator, lock screen, Face ID, home screen,
 *      browser bar, system sheets/alerts, keychain bar, toast, the on-screen keyboard).
 *   2. docs/pilot/spec/look-glass.css, appended VERBATIM (all 485 lines: light, dark, the <=560px
 *      lighter blur, and the reduced-transparency / no-backdrop-filter fallbacks).
 *   3. A small real-device block (this file, PR-1) for the safe-area insets and the visual-viewport
 *      height the mock's phone frame doesn't need.
 *
 * Kept from the "drawn phone OS" list on purpose (§7.2): .tp-push and .tp-privacy (the lock-screen
 * push preview drawing in S3, and the real privacy cover) plus .tp-skeleton__* (the real loading
 * skeleton) and .tp-live.is-paused (the real paused-run UI) — none of those are mock-only.
 *
 * Do not hand-edit the two copied sections below without re-diffing against docs/pilot/spec/ — they
 * are generated by copying, not by hand.
 *
 * 🔴 PR-7 fix: `*,*::before,*::after{box-sizing:border-box}` lives at docs/pilot/spec/proto.html:100
 * — one line ABOVE the copied 171-620 range, so it never made it into this file. Every `.tp-row`,
 * `.tp-rows`, `.tp-fact` etc. below assumes border-box sizing (padding/border included in a 100%
 * width), so without this reset a row list overflows the phone by a few px the moment it holds real
 * content wide enough to matter — found via PR-7's own p7-needs-case.mjs scenario (S8's Email/Tasks/
 * Files/Timeline rows were the first real content any pilot scenario rendered inside `.tp-rows`; the
 * S4 skeleton has none). This is NOT part of the copied section and is not touched by a re-diff.
 * (PR-5 found and restored the same reset independently; the integration pass keeps this ONE copy.)
 */
*,*::before,*::after{box-sizing:border-box}


/* ══════════════ 1. Engine CSS (proto.html lines 171-620, mock-only rules stripped) ══════════════ */
/* ═══ THE PHONE · TONAL (default look) — Command Station tonal tokens, dashboard/index.html:1282 ═══ */
.tp-app{
  --tp-look-name:"tonal";
  --tp-ink:#0B0B0C; --tp-paper:#F6F5F2; --tp-idea:#FFCE00;   /* CI V3.1: ink + paper; gold only inside the logo mark */
  --tp-font:-apple-system,BlinkMacSystemFont,"SF Pro Text","Figtree","Helvetica Neue","Segoe UI",Roboto,sans-serif;
  --tp-font-display:ui-rounded,"SF Pro Rounded","Figtree",-apple-system,sans-serif;
  --tp-font-mono:ui-monospace,"SF Mono","IBM Plex Mono",Menlo,monospace;
  --tp-bg:#F6F5F2; --tp-bg-image:none;
  --tp-surface:#FFFFFF; --tp-surface-raised:#FFFFFF; --tp-surface-2:#EEECE7; --tp-surface-3:#E6E3DC;
  --tp-blur:none; --tp-bar-bg:#F6F5F2;
  --tp-line:rgba(11,11,12,.12); --tp-line-strong:rgba(11,11,12,.24);
  --tp-text:#0B0B0C; --tp-muted:#45433F; --tp-faint:#5F5C56;
  --tp-accent:#0B0B0C; --tp-accent-strong:#0B0B0C; --tp-on-accent:#F6F5F2;
  --tp-accent-soft:#EEECE7; --tp-on-accent-soft:#0B0B0C;
  --tp-me-bg:#E8E5DD; --tp-me-text:#0B0B0C;
  --tp-pilot-bg:transparent; --tp-pilot-text:#0B0B0C;
  --tp-ok:#1F5C3A; --tp-ok-soft:#E1EDE4;
  --tp-warn:#0B0B0C; --tp-warn-soft:#EEECE7; --tp-warn-line:rgba(11,11,12,.24);
  --tp-danger:#8C1D18; --tp-danger-soft:#F6E1DE;
  --tp-outline:#0B0B0C; --tp-focus:0 0 0 3px rgba(11,11,12,.38); --tp-warn-icon:#8C1D18;
  --tp-radius-sm:12px; --tp-radius:20px; --tp-radius-lg:28px; --tp-radius-pill:999px; --tp-bubble-radius:20px;
  --tp-shadow-card:0 0 0 .5px rgba(11,11,12,.04);
  --tp-shadow-sheet:0 -1px 0 rgba(11,11,12,.12);
  --tp-shadow-bar:none;
  --tp-h-primary:48px; --tp-h-secondary:44px; --tp-h-chip:38px; --tp-fs-input:16px;
  --tp-sb-h:0px; --tp-safe-b:0px;
}
.tp-app[data-scheme="dark"]{
  color-scheme:dark;
  --tp-bg:#0B0B0C; --tp-surface:#161618; --tp-surface-raised:#161618; --tp-surface-2:#1F1F22; --tp-surface-3:#27272B;
  --tp-bar-bg:#0B0B0C;
  --tp-line:rgba(246,245,242,.12); --tp-line-strong:rgba(246,245,242,.26);
  --tp-text:#F6F5F2; --tp-muted:#C4C1B9; --tp-faint:#A19E96;
  --tp-accent:#F6F5F2; --tp-accent-strong:#F6F5F2; --tp-on-accent:#0B0B0C;
  --tp-accent-soft:#27272B; --tp-on-accent-soft:#F6F5F2;
  --tp-me-bg:#27272B; --tp-me-text:#F6F5F2;
  --tp-pilot-text:#F6F5F2;
  --tp-ok:#8FD0A6; --tp-ok-soft:#16291E;
  --tp-warn:#F6F5F2; --tp-warn-soft:#27272B; --tp-warn-line:rgba(246,245,242,.26);
  --tp-danger:#F2A59E; --tp-danger-soft:#341715;
  --tp-outline:#F6F5F2; --tp-focus:0 0 0 3px rgba(246,245,242,.45); --tp-warn-icon:#F2A59E;
  --tp-shadow-card:0 0 0 .5px rgba(246,245,242,.06);
  --tp-shadow-sheet:0 -1px 0 rgba(246,245,242,.14);
}

.tp-app{position:relative;overflow:hidden;background:var(--tp-bg);background-image:var(--tp-bg-image);color:var(--tp-text);font:16px/1.45 var(--tp-font);-webkit-font-smoothing:antialiased;isolation:isolate}
.tp-app *{-webkit-tap-highlight-color:transparent}
.tp-app button{cursor:pointer;font-family:inherit}
.tp-app :focus-visible{outline:none;box-shadow:var(--tp-focus)}
.tp-app h1,.tp-app h2,.tp-app h3{font-family:var(--tp-font-display);text-wrap:balance;margin:0}
.tp-app p{margin:0}


.tp-screen{position:absolute;inset:0;display:flex;flex-direction:column;padding-top:var(--tp-sb-h);min-height:0}
.tp-scroll{flex:1 1 auto;min-height:0;overflow-y:auto;overscroll-behavior:contain;scrollbar-width:none;contain:paint}
.tp-scroll::-webkit-scrollbar{display:none}

/* ── Buttons & chips ── */
.tp-btn{display:inline-flex;align-items:center;justify-content:center;gap:8px;border:0;border-radius:var(--tp-radius-pill);font-weight:600;font-size:16px;line-height:1.2;padding:0 20px;text-align:center;transition:background-color .15s ease,opacity .15s ease}
.tp-btn--primary{min-height:var(--tp-h-primary);width:100%;background:var(--tp-accent);color:var(--tp-on-accent)}
.tp-btn--primary:active{background:var(--tp-accent-strong)}
.tp-btn--secondary{min-height:var(--tp-h-secondary);background:var(--tp-accent-soft);color:var(--tp-on-accent-soft);font-weight:600;font-size:15px}
.tp-btn--text{min-height:var(--tp-h-secondary);background:transparent;color:var(--tp-accent-strong);font-size:15px;padding:0 12px}
.tp-app[data-scheme="dark"] .tp-btn--text{color:var(--tp-accent)}
.tp-btn--danger{min-height:var(--tp-h-secondary);background:var(--tp-danger-soft);color:var(--tp-danger);font-size:15px}
.tp-btn--danger.tp-btn--primary{min-height:var(--tp-h-primary);background:var(--tp-danger);color:var(--tp-surface-raised)}
.tp-btn[disabled]{opacity:.45;cursor:not-allowed}
.tp-btnrow{display:flex;gap:8px}
.tp-btnrow>.tp-btn{flex:1 1 0}
.tp-chip{display:inline-flex;align-items:center;gap:6px;min-height:var(--tp-h-chip);padding:0 14px;border-radius:var(--tp-radius-pill);border:1px solid var(--tp-line-strong);background:var(--tp-surface-raised);color:var(--tp-text);font-size:14.5px;font-weight:500;line-height:1.2;text-align:left;max-width:100%}
.tp-chip--suggest{border-color:transparent;background:var(--tp-surface-3)}
.tp-chip--case{min-height:var(--tp-h-chip);padding:0 10px;border:0;background:transparent;color:var(--tp-accent-strong);font-weight:600;font-size:13.5px;margin-left:-10px;position:relative}
.tp-app[data-scheme="dark"] .tp-chip--case{color:var(--tp-accent)}
.tp-chip--case b{font-family:var(--tp-font-mono);font-weight:600;letter-spacing:.01em}
/* case-cards-13: --tp-h-chip (38px) is below the 44pt tap-target floor. Grown via an invisible ::after
   overlay rather than raising min-height itself, so the visible chip/link stays exactly as designed
   (no layout shift, no overlap with the -6/-10px negative margins that sit it flush with a card head or
   text line) while the actual hit area is a full 44px tall. scripts/pilot/measure.js reads this overlay's
   own box instead of the chip's visible rect. */
.tp-chip--case::after{content:"";position:absolute;left:0;right:0;top:50%;height:44px;transform:translateY(-50%)}
/* [readability 2026-09-30] .tp-cref: a case ref INSIDE prose (chat.js renderAnswer). Genuinely
   display:inline (never flex/block) so it can never become a multi-line slab mid-sentence the way
   .tp-chip--case did (a flex child is blockified regardless of its own display, and that chip's own
   span was display:block). Vertical padding on a display:inline box is painted but does not push the
   surrounding paragraph's line-height apart — that is what makes the tap target comfortable without
   the readability regression. white-space:nowrap keeps the whole "No ›" token from ever breaking
   across two lines; line-height is fixed (not inherited) so the rendered box stays predictable
   whether this sits in a <p> or a <li>. */
.tp-cref{display:inline;border:0;margin:0;padding:1px 3px;background:transparent;font-family:inherit;font-weight:600;font-size:.9em;line-height:1.2;color:var(--tp-accent-strong);white-space:nowrap;text-decoration:underline;text-decoration-color:var(--tp-line-strong);text-underline-offset:2px;border-radius:5px;cursor:pointer;-webkit-tap-highlight-color:transparent;vertical-align:baseline}
.tp-cref b{font-family:var(--tp-font-mono);font-weight:600;letter-spacing:.01em;font-style:normal}
.tp-cref:active{background:var(--tp-accent-soft)}
.tp-app[data-scheme="dark"] .tp-cref{color:var(--tp-accent)}
.tp-chip--next{background:var(--tp-accent-soft);color:var(--tp-on-accent-soft);border-color:transparent}
.tp-chip--on{background:var(--tp-accent);color:var(--tp-on-accent);border-color:transparent}
.tp-link{background:none;border:0;padding:0;color:var(--tp-accent-strong);font-weight:600;text-decoration:underline;text-underline-offset:3px;font-size:inherit}
/* tap area ≥ 44pt (case-cards-13; was 38px): stand-alone links grow via the same invisible ::after
   overlay as .tp-chip--case above; links inside running text (.tp-link--inline) already get their own
   44px area from real vertical padding + a matching negative margin, so they are excluded here. */
.tp-app .tp-link{display:inline-flex;align-items:center;min-height:var(--tp-h-chip);text-align:left;position:relative}
.tp-app .tp-link:not(.tp-link--inline)::after{content:"";position:absolute;left:0;right:0;top:50%;height:44px;transform:translateY(-50%)}
.tp-app .tp-link--inline{display:inline;min-height:0;padding:10px 0;margin:-10px 0}
/* ── found files (07.10): an inline link to a file Pilot found + the "Files in this answer" list. dashboard/pilot/filerefs.js ──
   A file path is long, so the link wraps anywhere and its padding is 12px (a 20px line plus 24px reaches the 44px floor). */
.tp-app .tp-fref{padding:14px 0;margin:-14px 0;overflow-wrap:anywhere;word-break:break-word}
.tp-fref__dir{opacity:.86;font-weight:500}
.tp-fref__name{font-weight:600}
.tp-frefs{margin:6px 0 0;padding:10px 14px 6px;border:1px solid var(--tp-line);border-radius:var(--tp-radius);background:var(--tp-surface-raised);box-shadow:var(--tp-shadow-card);min-width:0}
.tp-frefs__h{margin:0 0 2px;font-size:13px;font-weight:650;line-height:1.3;color:var(--tp-muted)}
.tp-frefs__list{list-style:none;margin:0;padding:0}
.tp-frefs__item{display:flex;align-items:center;gap:10px;min-width:0;border-top:1px solid var(--tp-line)}
.tp-frefs__item:first-child{border-top:0}
.tp-frefs__row{flex:1 1 auto;min-width:0;display:flex;flex-direction:column;justify-content:center;gap:1px;min-height:44px;padding:6px 0;color:var(--tp-text);text-decoration:none}
.tp-frefs__name{display:block;font-size:15px;font-weight:600;line-height:1.3;overflow-wrap:anywhere}
.tp-frefs__meta{display:block;font-size:13px;line-height:1.3;color:var(--tp-faint);overflow-wrap:anywhere}
.tp-app .tp-frefs__item .tp-frefs__show{flex:none;align-self:center;white-space:nowrap;font-size:14px}
.tp-frefs__more{margin:2px 0 6px;font-size:13px;line-height:1.35;color:var(--tp-faint)}
.tp-app[data-scheme="dark"] .tp-link{color:var(--tp-accent)}
.tp-seg{display:inline-flex;padding:3px;border-radius:var(--tp-radius-pill);background:var(--tp-surface-3);gap:2px}
.tp-seg button{min-height:38px;padding:0 16px;border:0;border-radius:var(--tp-radius-pill);background:transparent;font-weight:600;font-size:14.5px;color:var(--tp-muted)}
.tp-seg button[aria-pressed="true"]{background:var(--tp-surface-raised);color:var(--tp-text);box-shadow:var(--tp-shadow-card)}
.tp-logo{display:block;border-radius:22.3%;box-shadow:0 2px 8px rgba(11,11,12,.22)}
.tp-muted{color:var(--tp-muted)}
.tp-faint{color:var(--tp-faint)}
.tp-mono{font-family:var(--tp-font-mono);font-size:.92em}

/* ── S4 chat ── */
.tp-topbar{flex:none;display:grid;grid-template-columns:44px 1fr 44px;align-items:center;gap:6px;min-height:44px;padding:2px 10px 6px;background:var(--tp-bar-bg);-webkit-backdrop-filter:var(--tp-blur);backdrop-filter:var(--tp-blur);box-shadow:var(--tp-shadow-bar)}
.tp-topbar__btn{width:44px;height:44px;border-radius:50%;border:0;background:transparent;display:grid;place-items:center;color:var(--tp-text)}
.tp-topbar__btn:active{background:var(--tp-surface-3)}
.tp-topbar__title{min-width:0;height:44px;border:0;background:transparent;display:flex;flex-direction:column;align-items:center;justify-content:center;line-height:1.15;color:var(--tp-text)}
.tp-topbar__title strong{font:600 16px/1.2 var(--tp-font-display);max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.tp-topbar__title span{font-size:12.5px;color:var(--tp-faint)}   /* [chat-09] retina floor: meta text >= 12.5px */
.tp-banner{flex:none;display:flex;align-items:center;gap:10px;padding:8px 12px 8px 16px;font-size:13.5px;line-height:1.35;border-top:1px solid var(--tp-line);border-bottom:1px solid var(--tp-line)}
.tp-banner p{flex:1;min-width:0}
.tp-banner__lines{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}
.tp-banner__reason{font-size:12.5px}   /* [chat-09] retina floor */
/* [ghost-03] SMALL (a) (round 4) — the relay-down headline is a full sentence ("Subscription relay is down
   since 14:32. Your message waits here and sends when it's back. No paid credits.") that could run to 3+
   lines on a narrow phone with the icon and button eating into the row's width; clamped to 2, same pattern as
   every other multi-line text in this file. */
.tp-banner__lines p:first-child{display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;line-clamp:2;overflow:hidden}
.tp-banner--relay{background:var(--tp-warn-soft);color:var(--tp-warn);border-color:var(--tp-warn-line)}
.tp-banner--offline{background:var(--tp-surface-3);color:var(--tp-muted)}
.tp-banner--signedout{background:var(--tp-danger-soft);color:var(--tp-danger);border-color:transparent}
.tp-banner--update{background:var(--tp-accent-soft);color:var(--tp-on-accent-soft);border-color:transparent}
.tp-banner__act{flex:none;min-height:var(--tp-h-secondary);padding:0 14px;border-radius:var(--tp-radius-pill);border:1.5px solid currentColor;background:transparent;color:inherit;font-weight:700;font-size:14px}
.tp-strip{flex:none;display:flex;align-items:center;gap:8px;margin:6px 12px 4px;padding:6px 6px 6px 12px;border-radius:var(--tp-radius);background:var(--tp-surface-2)}
.tp-strip__label{flex:none;display:flex;align-items:center;gap:6px;font-size:12.5px;font-weight:700;color:var(--tp-muted);letter-spacing:.01em}
.tp-strip__label i{width:8px;height:8px;border-radius:50%;background:var(--tp-accent)}
.tp-strip__chip{flex:1 1 auto;min-width:0;justify-content:flex-start;border-color:transparent;font-size:14px}
/* the top item may wrap to 2 lines so "· draft ready" is never cut on a narrow phone */
.tp-strip__chip span{overflow:hidden;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;line-clamp:2;white-space:normal;line-height:1.2;padding:3px 0;text-wrap:balance}   /* [strip-dot] a two-line item breaks evenly, never one orphan word on line two */
.tp-strip__more{flex:none;padding:0 12px;font-weight:700;border-color:transparent;background:transparent;color:var(--tp-accent-strong)}
.tp-app[data-scheme="dark"] .tp-strip__more{color:var(--tp-accent)}
.tp-strip--empty{justify-content:center;color:var(--tp-muted);font-size:14px;min-height:50px;padding-left:12px}
/* ── [pr-b] Needs you — the top 3, in the strip's place on every chat view (current tokens; the ink-and-gold re-skin is PR D) ──
   one primary per row (the row itself, with its pill) + a 44 px "⋯" that opens Done / Snooze inline; every control ≥ 44 px,
   every row ≥ 64 px, titles clamp at 2 lines; the block scrolls inside itself rather than push the conversation off a short phone. */
.tp-top{flex:none;margin:6px 12px 4px;border-radius:var(--tp-radius);background:var(--tp-surface-2);max-height:min(52vh,420px);overflow-y:auto;overscroll-behavior:contain;scrollbar-width:none}
.tp-top::-webkit-scrollbar{display:none}
.tp-top__head{display:flex;align-items:center;justify-content:space-between;gap:8px;min-height:44px;padding:0 6px 0 14px;position:sticky;top:0;z-index:2;background:var(--tp-surface-2);border-radius:var(--tp-radius) var(--tp-radius) 0 0}   /* stays in view while the block scrolls (the Hidden list can be longer than the cap) */
.tp-top__label{display:flex;align-items:center;gap:6px;font-size:12.5px;font-weight:700;color:var(--tp-muted);letter-spacing:.01em}
.tp-top__label i{width:8px;height:8px;border-radius:50%;background:var(--tp-accent)}
.tp-top__label.is-danger{color:var(--tp-danger)}
.tp-top__label.is-danger i{background:var(--tp-danger)}
.tp-top__more{flex:none;display:inline-flex;align-items:center;gap:4px;min-height:44px;min-width:44px;padding:0 12px;border:0;border-radius:var(--tp-radius-pill);background:transparent;color:var(--tp-accent-strong);font-weight:700;font-size:14px;justify-content:center}
.tp-app[data-scheme="dark"] .tp-top__more{color:var(--tp-accent)}
.tp-top__list{display:flex;flex-direction:column;gap:6px;padding:0 6px 6px}
.tp-top__item{min-height:64px;border-radius:var(--tp-radius-sm);border:1px solid var(--tp-line);background:var(--tp-surface-raised)}
.tp-top__row{display:flex;align-items:flex-start}
.tp-top__main{flex:1 1 auto;min-width:0;min-height:64px;display:flex;align-items:flex-start;gap:10px;padding:10px 4px 10px 12px;border:0;background:transparent;text-align:left;color:var(--tp-text);text-decoration:none;border-radius:var(--tp-radius-sm)}
.tp-top__tog{flex:none;width:44px;height:44px;margin:4px 4px 0 0;display:grid;place-items:center;border:0;border-radius:var(--tp-radius-pill);background:transparent;color:var(--tp-muted)}
.tp-top__tog[aria-expanded="true"]{background:var(--tp-surface-2);color:var(--tp-text)}
.tp-top__tog[disabled]{opacity:.45}
.tp-top__txt{flex:1 1 auto;min-width:0;display:flex;flex-direction:column;gap:1px}
.tp-top__lbl{font-size:12.5px;font-weight:700;letter-spacing:.01em;color:var(--tp-muted);overflow-wrap:anywhere}
.tp-top__item--t1 .tp-top__lbl{color:var(--tp-danger)}
.tp-top__item--t2 .tp-top__lbl{color:var(--tp-warn)}
.tp-top__title{font-size:15.5px;font-weight:600;line-height:1.3;overflow-wrap:anywhere;overflow:hidden;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;line-clamp:2}
.tp-top__foot{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:4px 8px;margin-top:2px}
.tp-top__meta{flex:1 1 auto;min-width:0;font-size:13px;line-height:1.3;color:var(--tp-faint)}
.tp-top__pill{flex:none;display:inline-flex;align-items:center;gap:2px;min-height:28px;padding:0 10px;border-radius:var(--tp-radius-pill);background:var(--tp-accent-soft);color:var(--tp-on-accent-soft);font-weight:600;font-size:13.5px}
.tp-top__ctl{padding:0 10px 10px}
.tp-top__btns{gap:6px}
.tp-top__btns>.tp-btn{padding:0 6px;min-width:0}
.tp-top__opts{display:flex;flex-direction:column;gap:6px}
.tp-top__opts>.tp-btn{width:100%}
.tp-top__ctl .tp-top__btn{background:var(--tp-surface-2)}
.tp-top__btn.is-busy{opacity:.7}
.tp-top__status{display:flex;align-items:center;justify-content:space-between;gap:8px;min-height:64px;padding:0 6px 0 14px;font-size:15px;font-weight:600;color:var(--tp-muted)}
.tp-top__err{padding:0 14px 10px;font-size:13.5px;font-weight:600;color:var(--tp-danger)}
.tp-top__ctl .tp-top__err,.tp-top__ctl .tp-top__note{padding:8px 4px 0}
.tp-top__note{padding:0 14px 10px;font-size:13.5px;color:var(--tp-muted)}
.tp-top__warn{display:flex;flex-wrap:wrap;align-items:center;gap:0 6px;padding:0 14px 8px;font-size:13.5px;color:var(--tp-muted)}
/* a last-good list after a failed read keeps FULL contrast (UI audit 1, #7: no dimming): it is marked by a dashed outline and a "last checked HH:MM" line */
.tp-top.is-stale .tp-top__item{border-style:dashed;border-color:var(--tp-line-strong)}
.tp-top.is-stale .tp-top__pill{background:transparent;box-shadow:inset 0 0 0 1px var(--tp-line-strong)}
.tp-row.is-stale{border-top-style:dashed;border-top-color:var(--tp-line-strong)}
/* the failure block: an inset card like every other state (#5), Retry a real 44 x 44 target (#6) */
.tp-top--fail{display:flex;align-items:center;justify-content:space-between;gap:8px;min-height:56px;padding:6px 6px 6px 14px;max-height:none;overflow:visible}
.tp-top__failmsg{flex:1 1 auto;min-width:0;font-size:14px;font-weight:600;color:var(--tp-text)}
.tp-app .tp-link.tp-retry{flex:none;align-self:center;display:inline-flex;align-items:center;justify-content:center;min-width:44px;min-height:44px;padding:0 10px;margin:-8px -4px -8px 0;box-sizing:border-box}
.tp-app .tp-top--fail .tp-link.tp-retry{margin:0}
.tp-top__warn .tp-link.tp-retry{margin-left:auto}
/* the folded block (#2): one 44 px line, tap to unfold */
.tp-top--fold{align-self:stretch;display:flex;align-items:center;justify-content:space-between;gap:8px;height:44px;min-height:44px;padding:0 12px 0 14px;border:0;text-align:left;color:var(--tp-text);font:inherit;overflow:hidden;max-height:44px}
.tp-top--fold:active{background:var(--tp-surface-3)}
/* [pr-b-3b] the conversation scrolls under the block: a line that peeks out right below it used to sit sliced against the block's edge.
   A zero-height sibling (chat.js, region "fade") carries a 40px ramp that starts at the block's bottom edge (its 4px margin + the first 36px of
   the scroller): the page-background token, solid for the first 24px (measured: with 8px the lower half of a line stayed readable at 15% under it; the cut edge and the
   letters of a line that peeks out are never drawn), then eased to transparent (80% at 26px, 30% at 34px, 0 at 40px) by a mask. It takes no height (the 44px folded line and every anchor measurement are unchanged),
   no tap (pointer-events:none, also on the ramp) and paints above the conversation; page-background token only, no hex. The first mask is the plain
   fallback for a browser without color-mix; the eased one replaces it where color-mix exists. */
.tp-top-fade{flex:none;position:relative;z-index:2;height:0;pointer-events:none}
.tp-chat.is-card-parked .tp-top-fade::before{display:none}   /* a card parked at the top of the conversation keeps its own edge and header at full colour (syncParkedActions) */
.tp-top-fade::before{content:"";position:absolute;left:0;right:0;top:-4px;height:40px;pointer-events:none;background:var(--tp-bg);-webkit-mask-image:linear-gradient(to bottom,black 24px,transparent 40px);mask-image:linear-gradient(to bottom,black 24px,transparent 40px);-webkit-mask-image:linear-gradient(to bottom,black 24px,color-mix(in srgb,black 45%,transparent) 32px,transparent 40px);mask-image:linear-gradient(to bottom,black 24px,color-mix(in srgb,black 45%,transparent) 32px,transparent 40px)}
/* a block at its height cap scrolls inside itself: a soft fade at the bottom says more rows wait below (#9) */
.tp-top.has-more::after{content:"";position:sticky;bottom:0;display:block;height:46px;margin-top:-46px;pointer-events:none;background:linear-gradient(to bottom,transparent,var(--tp-surface-2))}
/* titles are the full subject (#1, 2 lines); a guest row's title is the guest's name (#3, 1 line) */
.tp-top__item--t3 .tp-top__title{-webkit-line-clamp:1;line-clamp:1}
.tp-top__hint{display:block}
/* "Not this" v2: the reason a hidden row came back, and the collapsed "Hidden (n) ↩" line under the list (a 44 px tap target, Undo per row) */
.tp-top__back{display:block;font-size:12.5px;font-weight:700;color:var(--tp-accent-strong)}
.tp-app[data-scheme="dark"] .tp-top__back{color:var(--tp-accent)}
.tp-top__hidden{padding:0 6px 6px}
.tp-top__hidtog{display:flex;align-items:center;min-height:44px;width:100%;padding:0 8px;border:0;background:transparent;color:var(--tp-muted);font:inherit;font-size:14px;font-weight:600;text-align:left;border-radius:var(--tp-radius-sm)}
.tp-top__hidtog:active{background:var(--tp-surface-3)}
/* while the list is open the block is a column that does not scroll as a whole: the head (or the empty line) and "Hidden (n) ↩" are fixed header rows, and ONLY the rows scroll in their own container, so the clip edge is a clean line (nothing slides under a rounded sticky corner) */
.tp-top--hidopen{display:flex;flex-direction:column;overflow:hidden}
.tp-top--hidopen > *{flex:none}
.tp-top--hidopen .tp-top__head,.tp-top--hidopen .tp-top__emptyline{position:static}
.tp-top--hidopen.has-more::after{display:none}
.tp-top--hidopen .tp-top__list{flex:0 2 auto;min-height:72px;overflow-y:auto;overscroll-behavior:contain;scrollbar-width:none}
.tp-top--hidopen .tp-top__list::-webkit-scrollbar,.tp-top__hidlist::-webkit-scrollbar{display:none}
.tp-top--hidopen .tp-top__hidden{flex:1 1 auto;min-height:108px;display:flex;flex-direction:column}
.tp-top__hidden.is-open .tp-top__hidtog{flex:none}
.tp-top__hidden.is-open .tp-top__hidtog:active{background:var(--tp-surface-3)}   /* keep the pressed state if the open list ever gets a more specific background */
.tp-top__hidden.is-open .tp-top__hidlist{flex:1 1 auto;min-height:0;overflow-y:auto;overscroll-behavior:contain;scrollbar-width:none}
/* the clip edge: 6 px of air above the first row, and a 6 px fade so a row that scrolled under the header row dissolves instead of showing a half-cut text line */
.tp-top__hidden.is-open .tp-top__hidlist,.tp-top--hidopen .tp-top__list{padding-top:6px;-webkit-mask-image:linear-gradient(to bottom,transparent 0,black 6px);mask-image:linear-gradient(to bottom,transparent 0,black 6px)}
.tp-top__hidlist{display:flex;flex-direction:column;gap:6px}
.tp-top__hid{flex:none;display:grid;grid-template-columns:minmax(0,1fr) auto;align-items:center;column-gap:8px;row-gap:4px;min-height:56px;padding:6px 6px 6px 12px;border:1px solid var(--tp-line);border-radius:var(--tp-radius-sm);background:var(--tp-surface-raised)}   /* every Hidden row is the same object: text left (title max 2 lines), Undo right and centred, an error spans both columns */
.tp-top__hidtxt{min-width:0;display:flex;flex-direction:column;gap:1px}
.tp-top__hidname{font-size:14.5px;font-weight:600;line-height:1.3;overflow:hidden;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;line-clamp:2;overflow-wrap:anywhere}
.tp-top__hidmeta{font-size:13px;color:var(--tp-faint)}
.tp-top__unhide{justify-self:end;align-self:center;min-width:64px;background:var(--tp-surface-2)}
.tp-top__hid .tp-top__err{grid-column:1 / -1;margin:0;padding:0}
.tp-top__emptyline{position:sticky;top:0;z-index:2;background:var(--tp-surface-2);border-radius:var(--tp-radius) var(--tp-radius) 0 0;display:flex;align-items:center;justify-content:center;gap:8px;min-height:50px;padding:0 12px;color:var(--tp-muted);font-size:14px}
/* the loading block (#8): the real header and three rows at the height of a typical loaded row, so the conversation below does not jump */
.tp-top.tp-top--skeleton{padding:0;margin:6px 12px 4px;background:var(--tp-surface-2);max-height:none;overflow:hidden}
.tp-top__skel{display:flex;flex-direction:column;justify-content:center;gap:8px;padding:12px 14px;box-sizing:border-box;min-height:var(--tp-top-skel,109px)}
.tp-optfoot{margin:10px 8px 4px;font-size:13px;line-height:1.4;color:var(--tp-faint)}
a.tp-row,a.tp-chip{text-decoration:none}
.tp-convo{padding:16px 16px 20px;display:flex;flex-direction:column;gap:18px}   /* [chat-10]: room for the top fade below */
.tp-empty{margin:auto 0;padding:28px 4px 8px;display:flex;flex-direction:column;gap:14px;align-items:flex-start}
.tp-empty h2{font-size:26px;font-weight:600;letter-spacing:-.01em}
.tp-empty .tp-chips{display:flex;flex-direction:column;align-items:flex-start;gap:8px}
.tp-divider{display:flex;align-items:center;gap:10px;font-size:12.5px;color:var(--tp-faint);font-weight:600}
.tp-divider::before,.tp-divider::after{content:"";flex:1;height:1px;background:var(--tp-line-strong)}
.tp-msg--me{align-self:flex-end;max-width:84%;display:flex;flex-direction:column;align-items:flex-end;gap:4px}
.tp-msg--me .tp-msg__body{background:var(--tp-me-bg);color:var(--tp-me-text);padding:10px 14px;border-radius:var(--tp-bubble-radius);border-bottom-right-radius:6px;font-size:16px;overflow-wrap:anywhere}
.tp-msg--me .tp-msg__body p+p{margin-top:6px}   /* [r3-me] her own line breaks and lists survive redisplay */
.tp-msg--me .tp-msg__body ul{margin:4px 0 0;padding-left:18px}
.tp-msg--me .tp-msg__body ol{margin:4px 0 0;padding-left:22px}   /* [answer-rows] her own numbered lines */
.tp-msg--refused{max-width:92%}   /* [r3-refused] only the note — never a bubble that looks sent */
.tp-app code{font-family:var(--tp-font-mono);font-size:.9em;padding:0 4px;border-radius:5px;background:var(--tp-surface-3)}
.tp-msg__status{font-size:13px;color:var(--tp-faint);display:flex;flex-wrap:wrap;justify-content:flex-end;align-items:center;gap:2px 10px;text-align:right}
.tp-msg__status--wait{color:var(--tp-warn);background:var(--tp-warn-soft);border:1px solid var(--tp-warn-line);border-radius:var(--tp-radius-sm);padding:6px 6px 6px 10px;justify-content:flex-start;text-align:left}
.tp-msg__status--wait > svg + span{flex:1 1 180px;min-width:0}   /* a long wait line stays beside its icon, never wraps under it */
.tp-msg__status .tp-btn--text{min-height:38px;padding:0 8px;font-size:14px;color:inherit;text-decoration:underline;text-underline-offset:3px}
.tp-msg--pilot{display:flex;flex-direction:column;gap:10px;background:var(--tp-pilot-bg);color:var(--tp-pilot-text)}
.tp-msg__meta{display:flex;flex-wrap:wrap;align-items:center;gap:4px 6px;font-size:12.5px;color:var(--tp-faint)}
.tp-msg__meta .tp-spark{color:var(--tp-accent);font-size:14px}
.tp-msg__meta strong{color:var(--tp-text);font-weight:650}
.tp-model{display:inline-flex;align-items:center;height:22px;padding:0 8px;border-radius:var(--tp-radius-pill);background:var(--tp-surface-3);color:var(--tp-muted);font-weight:600;font-size:12.5px}   /* [chat-09] retina floor */
.tp-msg--pilot .tp-msg__body{font-size:16px;line-height:1.55;max-width:62ch;overflow-wrap:anywhere}
/* [readability 2026-09-30] "▸ Read: …" used to render at full body size/color and wrap 2-3 lines.
   Quiet meta, one line, ellipsis — like the mock-up's meta rows (.tp-msg__meta is 12.5px/--tp-faint
   too) — grouped tight under the answer. margin-top pulls it in under .tp-msg--pilot's 10px gap. */
.tp-msg__shows{display:block;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:12.5px;line-height:1.35;color:var(--tp-faint);margin-top:-4px}
.tp-msg__shows+.tp-msg__shows{margin-top:-6px}
/* [answer-rows] Readable answers on a phone: (A) real lists — a hanging indent so a wrapped line lines up with
   its text and never falls back under the number or the bullet — and (B) "scan rows" for a numbered list of
   cases (chat.js renderAnswer): a number column, the case ref + title on line 1, the status on line 2 with the
   days-overdue phrase in warn/danger. Every size is >= 13.5px (the 12.5px floor stays for meta only). */
.tp-msg--pilot .tp-msg__body p+p,.tp-msg--pilot .tp-msg__body p+ul,.tp-msg--pilot .tp-msg__body p+ol,.tp-msg--pilot .tp-msg__body ul+p,.tp-msg--pilot .tp-msg__body ol+p,.tp-msg--pilot .tp-msg__body ul+ol,.tp-msg--pilot .tp-msg__body ol+ul{margin-top:10px}
.tp-msg--pilot .tp-msg__body ul,.tp-msg--pilot .tp-msg__body ol{margin:0;padding-left:1.5em}
.tp-msg--pilot .tp-msg__body ul{list-style:disc}
.tp-msg--pilot .tp-msg__body ol{list-style:decimal}
.tp-msg--pilot .tp-msg__body li+li{margin-top:7px}
.tp-msg--pilot .tp-msg__body li::marker{color:var(--tp-faint)}
.tp-msg--pilot .tp-msg__body .tp-ol--rows{list-style:none;padding-left:0;counter-reset:tp-n var(--tp-n0,0)}
.tp-msg--pilot .tp-msg__body .tp-ol--rows>li{counter-increment:tp-n;display:grid;grid-template-columns:1.35em minmax(0,1fr);column-gap:6px;align-items:baseline;margin:0;padding:9px 0}
.tp-msg--pilot .tp-msg__body .tp-ol--rows>li:first-child{padding-top:2px}
.tp-msg--pilot .tp-msg__body .tp-ol--rows>li:last-child{padding-bottom:2px}
.tp-msg--pilot .tp-msg__body .tp-ol--rows>li+li{border-top:1px solid var(--tp-line-strong)}
.tp-msg--pilot .tp-msg__body .tp-ol--rows>li::before{content:counter(tp-n);grid-column:1;grid-row:1;font-size:13.5px;font-weight:600;line-height:1.55;color:var(--tp-faint);font-variant-numeric:tabular-nums}
.tp-msg--pilot .tp-msg__body .tp-arow__head{grid-column:2;grid-row:1;min-width:0}
.tp-msg--pilot .tp-msg__body .tp-arow__title{font-weight:600}
.tp-msg--pilot .tp-msg__body .tp-arow__ref{white-space:nowrap;font-family:var(--tp-font-mono);font-size:.9em;font-weight:600;color:var(--tp-muted)}   /* a ref the server did not resolve: plain, not a link; a resolved one is the .tp-cref inside */
.tp-msg--pilot .tp-msg__body .tp-arow__sub{grid-column:2;grid-row:2;min-width:0;margin-top:1px;font-size:14px;line-height:1.4;color:var(--tp-muted);text-wrap:pretty}   /* a wrapped status never ends on one orphan word where the browser can help */
.tp-msg--pilot .tp-msg__body .tp-arow__head .tp-cref{margin-left:-3px}   /* the ref's own 3px padding would indent line 1 past line 2 */
.tp-msg--pilot .tp-msg__body .tp-od{font-weight:600;white-space:nowrap}
.tp-msg--pilot .tp-msg__body .tp-od--danger{color:var(--tp-danger)}
.tp-msg--pilot .tp-msg__body .tp-od--warn{color:var(--tp-warn-icon)}
.tp-steps{align-self:flex-start;max-width:100%}
.tp-steps__toggle{min-height:var(--tp-h-chip);padding:0 10px 0 6px;margin-left:-6px;border:0;border-radius:var(--tp-radius-sm);background:transparent;color:var(--tp-faint);font-size:13px;font-weight:600;display:inline-flex;align-items:center;gap:6px}
.tp-steps__list{margin:4px 0 0;padding:8px 12px;list-style:none;border-radius:var(--tp-radius-sm);background:var(--tp-surface-2);display:flex;flex-direction:column;gap:4px}
.tp-steps__row{display:flex;gap:8px;font-size:13.5px;color:var(--tp-muted);line-height:1.35}
.tp-steps__row svg{flex:none;margin-top:2px;color:var(--tp-ok)}
/* [readability 2026-09-30] a long email subject used to wrap 2-3 lines here; one line + ellipsis, full
   text still reachable via the span's title (chat.js). */
.tp-steps__row span{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.tp-steps__row.is-now{color:var(--tp-text);font-weight:600}
.tp-steps__row.is-now svg{color:var(--tp-accent)}
.tp-live{flex:none;margin:0 12px 6px;padding:8px 12px;border-radius:var(--tp-radius);background:var(--tp-surface-2);display:flex;flex-direction:column;gap:2px}
.tp-live__line{display:flex;align-items:center;gap:8px;min-height:var(--tp-h-chip);border:0;background:transparent;padding:0;color:var(--tp-text);font-size:14.5px;font-weight:600;text-align:left}
.tp-live__line .tp-mono{color:var(--tp-muted);font-weight:500}
.tp-live__sub{font-size:12.5px;color:var(--tp-faint)}
.tp-live .tp-steps__list{background:var(--tp-surface-raised);margin:6px 0 4px}
/* [chat-15/r2-12/navigation-context-row-wall-and-keyboard] ONE row, never a 2-row button wall: the chips sit
   in an inner horizontal scroller (.tp-context__row) so the frosted ::before/::after of .tp-context itself are
   never clipped; a soft right-edge fade shows while more chips wait to the right (chat.js markCtxMore). With
   the keyboard up only the About pill stays. */
.tp-context{flex:none;display:flex;align-items:center;margin:0 12px 6px;padding:6px;border-radius:var(--tp-radius);background:var(--tp-surface-2)}
.tp-context__row{display:flex;flex-wrap:nowrap;align-items:center;gap:6px;flex:1;min-width:0;overflow-x:auto;overscroll-behavior-x:contain;scrollbar-width:none;-webkit-overflow-scrolling:touch;border-radius:var(--tp-radius-pill)}
.tp-context__row::-webkit-scrollbar{display:none}
.tp-context__row>*{flex:0 0 auto}
.tp-context__row.is-more{-webkit-mask-image:linear-gradient(to right,#000 calc(100% - 28px),transparent);mask-image:linear-gradient(to right,#000 calc(100% - 28px),transparent)}
/* [r3-ctxfade] scrolled: a sliver of the chip that left at the left edge fades too, never a stray bracket */
.tp-context__row.is-less{-webkit-mask-image:linear-gradient(to right,transparent,#000 24px);mask-image:linear-gradient(to right,transparent,#000 24px)}
.tp-context__row.is-less.is-more{-webkit-mask-image:linear-gradient(to right,transparent,#000 24px,#000 calc(100% - 28px),transparent);mask-image:linear-gradient(to right,transparent,#000 24px,#000 calc(100% - 28px),transparent)}
/* [r3-ctxkbd] keyboard up: only the About pill stays, and the glass shrinks to it (no 60% empty band) */
.tp-app[data-kbd="up"] .tp-context{align-self:flex-start}
.tp-app[data-look="glass"][data-kbd="up"] .tp-context::before{display:none}
.tp-app[data-kbd="up"] .tp-context .tp-chip{display:none}
/* [chat-15] tap-target floor (44pt): both the pill and its × close button. */
.tp-context__about{display:inline-flex;align-items:center;gap:4px;min-width:0;max-width:calc(100vw - 48px);min-height:44px;padding:0 4px 0 10px;border-radius:var(--tp-radius-pill);background:var(--tp-accent-soft);color:var(--tp-on-accent-soft);font-size:13.5px;font-weight:600;white-space:nowrap}
.tp-context__about button{width:44px;height:44px;border:0;background:transparent;color:inherit;border-radius:50%;display:grid;place-items:center;flex:none}
/* [chat-15] "About MO0057 · Big Apt" — truncated with an ellipsis rather than wrapping the pill to 2 lines. */
.tp-context__txt{max-width:52vw;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* [email-cards-10] the revise pill's own label — 32px of text was touching the rounded top/bottom edges of
   a 38px pill because it wrapped to 2 lines; single-line + ellipsis keeps it inside one 44px capsule. */
.tp-context__label{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.tp-context .tp-chip{min-height:44px;font-size:13.5px;padding:0 12px;white-space:nowrap}
.tp-inputbar{flex:none;display:flex;flex-direction:column;gap:4px;padding:8px 12px calc(8px + var(--tp-safe-b));background:var(--tp-bar-bg);-webkit-backdrop-filter:var(--tp-blur);backdrop-filter:var(--tp-blur);border-top:1px solid var(--tp-line)}
.tp-app[data-kbd="up"] .tp-inputbar{padding-bottom:8px}
.tp-inputbar__row{display:flex;align-items:flex-end;gap:8px}
/* [r3-input] the top/bottom spacing is a TRANSPARENT BORDER, not padding: a scroll container clips at its padding
   box, so a capped field (5 lines) never shows a 6th line sliced in half at its bottom edge. The visible hairline
   is an outer ring (box-shadow spread), so the look is unchanged. */
.tp-input{flex:1 1 auto;min-width:0;display:block;font:var(--tp-fs-input)/1.4 var(--tp-font);color:var(--tp-text);background:var(--tp-surface-raised);border:solid transparent;border-width:12px 1px;box-shadow:0 0 0 1px var(--tp-line-strong);border-radius:24px;padding:0 15px;resize:none;min-height:48px;max-height:calc(5 * 1.4em + 24px);overflow-y:auto}
.tp-input::placeholder{color:var(--tp-faint)}
/* The paperclip takes 56px of the dock row. At 360px the field was 216px wide and its 186px placeholder wrapped by 2px: the
   auto-sizing field went to 69px and the whole dock grew 21px. A one-line placeholder (an ellipsis, never a wrap) plus a
   tighter gap and side padding under 375px keep the empty dock exactly as tall as before the paperclip. */
.tp-input::placeholder{white-space:nowrap;text-overflow:ellipsis;overflow:hidden}
@media (max-width:374px){.tp-inputbar__row{gap:6px}.tp-input{padding:0 13px}}
.tp-input:focus{outline:none;box-shadow:0 0 0 1px var(--tp-accent),var(--tp-focus)}
.tp-send{flex:none;width:48px;height:48px;border-radius:50%;border:0;background:var(--tp-accent);color:var(--tp-on-accent);display:grid;place-items:center;font-weight:700;font-size:12.5px}
/* [quiet-queue] while a card waits for her (or its send hold runs) the card owns the ONE filled accent button; Queue goes tonal */
.tp-send.is-quiet{background:var(--tp-accent-soft);color:var(--tp-on-accent-soft)}
.tp-send[disabled],.tp-send[aria-disabled="true"]{background:var(--tp-surface-3);color:var(--tp-faint)}   /* [chat-06/r2-16] the Queue button is aria-disabled (still tappable, so it can say why) */
.tp-send.is-queue{width:auto;padding:0 14px;border-radius:24px}
.tp-hint{display:flex;align-items:center;gap:6px;font-size:12.5px;color:var(--tp-faint);padding:0 6px}

/* ── S5 proposal cards ── */
.tp-card{background:var(--tp-surface-raised);border:1px solid var(--tp-line);border-radius:var(--tp-radius);box-shadow:var(--tp-shadow-card);padding:14px 16px 16px;display:flex;flex-direction:column;gap:12px;transition:box-shadow .3s ease,opacity .2s ease;scroll-margin:24px}
.tp-card.is-outlined{box-shadow:0 0 0 2.5px var(--tp-outline),var(--tp-shadow-card)}
.tp-card.is-dismissed{opacity:.55;box-shadow:none;background:transparent;border-style:dashed}
.tp-card__head{display:flex;gap:10px;align-items:flex-start}
.tp-card__icon{flex:none;width:36px;height:36px;border-radius:12px;display:grid;place-items:center;background:var(--tp-accent-soft);color:var(--tp-on-accent-soft)}
.tp-card__titles{flex:1;min-width:0;display:flex;flex-direction:column;align-items:flex-start}   /* r2-01: takes the row, so a short title never squeezes the chip onto two lines */
.tp-card__case{min-height:var(--tp-h-chip);margin:-6px 0 -6px -10px}
/* [ghost-06] SMALL (b), round 4 — clamp the case line to 1 with an ellipsis, but the "›" (its own flex item,
   never shrunk) always stays visible instead of being swallowed by the ellipsis. */
.tp-card__caselabel{flex:1 1 auto;min-width:0;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}
.tp-card__casearrow{flex:none;padding-left:2px}
.tp-card__title{font-size:17px;font-weight:650;line-height:1.3}
.tp-card__mail{display:flex;flex-direction:column;gap:8px;padding:12px;border-radius:var(--tp-radius-sm);background:var(--tp-surface-2)}
.tp-card__to{align-self:flex-start;min-height:38px;padding:0 10px;margin:-6px 0 -4px -10px;border:0;background:transparent;color:var(--tp-muted);font-size:14px;display:inline-flex;align-items:center;gap:6px;text-align:left}
.tp-card__to b{color:var(--tp-text);font-weight:600}
/* email-cards-12: no dead band above/below the meta block; a long value folds instead of running 9 lines */
.tp-card__meta{display:grid;grid-template-columns:auto 1fr;gap:2px 10px;font-size:13.5px;color:var(--tp-muted);margin:-6px 0 0}
.tp-card__meta dd{margin:0;color:var(--tp-text);overflow-wrap:anywhere;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:3;overflow:hidden}
/* [ghost-07] SMALL (c), round 4 — To/Cc open: a long Subject ran to 3 lines and crowded the card; the full
   text is still on `title` (long-press/hover), same pattern as Cc right above it. */
.tp-card__subject{-webkit-line-clamp:2}
.tp-card__body{font-size:15px;line-height:1.5;display:flex;flex-direction:column;gap:6px;overflow-wrap:anywhere}
/* email-cards-05: a short paragraph-count but a very long draft still folds — clamped to ~9 lines with a
   soft mask at the bottom, so 'Show all' is never skipped just because it happens to be 2-3 paragraphs */
.tp-card__body.is-clamped{max-height:calc(15px*1.5*5 + 6px);overflow:hidden;-webkit-mask-image:linear-gradient(180deg,#000 70%,transparent);mask-image:linear-gradient(180deg,#000 70%,transparent)}   /* [r3-fold] ~5 lines */
/* [r3-fold] a sent / already-answered draft is a 2-line quote of what went out — never a full open draft */
.tp-card__body.is-quote{display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;line-clamp:2;overflow:hidden;color:var(--tp-muted);font-size:14px}
.tp-card__body.is-quote p{display:inline}
.tp-card__body.is-quote p+p::before{content:" "}
.tp-card__signoff{font-size:15px;line-height:1.5;padding-top:8px;border-top:1px dashed var(--tp-line-strong);white-space:pre-line}
.tp-card__after{font-size:13px;color:var(--tp-muted)}
.tp-attach{display:flex;align-items:center;gap:8px;min-height:44px;padding:6px 4px 6px 10px;border-radius:var(--tp-radius-sm);border:1px solid var(--tp-line-strong);background:var(--tp-surface-raised);font-size:13.5px}
.tp-attach__txt{flex:1;min-width:0;display:flex;flex-direction:column;line-height:1.3}
/* email-cards-03: the name clamps to 2 lines (never 7); the meta line is size · FOLDER on ONE line, not
   the whole file name repeated a second time in monospace, wrapping mid-token */
.tp-attach__txt b{font-weight:600;display:flex;min-width:0;white-space:nowrap}   /* [r3-att] one line: the head takes the ellipsis, the extension stays */
.tp-attach__txt b .tp-attach__head{min-width:0;overflow:hidden;text-overflow:ellipsis;font:inherit;color:inherit;font-family:inherit;font-size:inherit}
.tp-attach__txt b .tp-attach__tail{flex:none;font:inherit;color:inherit;font-family:inherit;font-size:inherit}
.tp-attach.is-missing{background:var(--tp-warn-soft);border-color:var(--tp-warn-line);color:var(--tp-warn)}
.tp-attach.is-missing .tp-attach__txt span{color:var(--tp-warn);font-family:var(--tp-font)}
.tp-attach__txt span{color:var(--tp-faint);font-family:var(--tp-font-mono);font-size:12px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.tp-attach button{flex:none;width:38px;height:38px;border:0;border-radius:50%;background:transparent;color:var(--tp-muted);display:grid;place-items:center}
.tp-card__change{display:flex;flex-direction:column;gap:8px}
.tp-change{display:grid;grid-template-columns:auto 1fr;align-items:baseline;gap:4px 12px;padding:10px 12px;border-radius:var(--tp-radius-sm);background:var(--tp-surface-2)}
.tp-change__label{font-size:12.5px;font-weight:700;color:var(--tp-muted);text-transform:uppercase;letter-spacing:.05em}
.tp-change__fromto{display:flex;flex-wrap:wrap;align-items:center;gap:6px;font-size:16px}
.tp-change__from{color:var(--tp-muted);text-decoration:line-through;text-decoration-color:var(--tp-line-strong)}
.tp-change__to{font-weight:700;color:var(--tp-text)}
/* case-cards-16: at phone width the label sits ABOVE the values, which then get the full row on one line —
   never an arrow dangling at the end of line 1 with the new value floating under it */
@media (max-width:430px){.tp-change{grid-template-columns:1fr;gap:2px}}
.tp-card__note{font-size:14px;color:var(--tp-muted);line-height:1.45}
/* [r3-stale] the proposal no longer matches the case: the rows are greyed out, never a wrong struck "from" */
.tp-card__change.is-stale .tp-change{opacity:.8}   /* was .5: on the flat ink skin the dimmed muted text fell to 2.4:1; .8 keeps it >= 4.5:1 in both schemes (07.10) */
.tp-card__change.is-stale .tp-change__from{text-decoration:none}
.tp-card[data-status="stale"] .tp-card__result.is-warn{font-weight:400;font-size:14px}
.tp-card__list{margin:0;padding:0;list-style:none;display:flex;flex-direction:column;border-radius:var(--tp-radius-sm);background:var(--tp-surface-2);overflow:hidden}
/* case-cards-11: an expanded bulk list (60+ rows) scrolls inside its own box — never an 8-screen wall with
   the Apply button pushed far away and no way back */
.tp-card__list.is-open{max-height:22rem;overflow-y:auto;overscroll-behavior:contain}
.tp-card__list.is-open:not(.is-end){-webkit-mask-image:linear-gradient(180deg,#000 82%,transparent);mask-image:linear-gradient(180deg,#000 82%,transparent)}   /* r2-07: more rows below */
.tp-card__list li{display:flex;gap:10px;align-items:center;padding:8px 12px;font-size:14px;border-top:1px solid var(--tp-line);min-height:44px}
.tp-card__list li:first-child{border-top:0}
.tp-card__list li span{flex:1;min-width:0;overflow-wrap:anywhere}
.tp-card__list li small{color:var(--tp-faint);font-family:var(--tp-font-mono);font-size:12.5px}
.tp-card__list input{width:22px;height:22px;accent-color:var(--tp-accent)}
.tp-card__warn{display:flex;gap:8px;align-items:flex-start;padding:8px 12px;border-radius:var(--tp-radius-sm);background:var(--tp-warn-soft);color:var(--tp-warn);border:1px solid var(--tp-warn-line);font-size:13.5px;font-weight:600}
.tp-card__why{font-size:13.5px;color:var(--tp-muted)}
.tp-card__undo{font-size:13px;color:var(--tp-faint);display:flex;gap:6px;align-items:center}
.tp-card__history{font-size:12.5px;color:var(--tp-faint);display:flex;flex-direction:column;gap:2px;padding-left:10px;border-left:2px solid var(--tp-line-strong)}
.tp-card__actions{display:flex;flex-direction:column;gap:8px;padding-top:2px}
.tp-card__actions .tp-btnrow>.tp-btn{padding:0 10px;min-width:0}   /* email-cards-09: Edit · Redraft · Not this fit one row at 360 */
/* email-cards-02: a plain wrapper (no box of its own) so #res-<id> can be scrolled+centred on — the hold,
   then Sent/failed/already — independent of the (possibly tall) card above it. */
.tp-card__status{display:flex;flex-direction:column;gap:8px;scroll-margin:24px}   /* a real box: getBoundingClientRect must measure it */
.tp-card__status:empty{display:none}
.tp-card__edit{display:flex;flex-direction:column;gap:10px}
.tp-field{display:flex;flex-direction:column;gap:4px;font-size:12.5px;font-weight:600;color:var(--tp-muted)}
.tp-field input,.tp-field textarea,.tp-field select{font:var(--tp-fs-input)/1.45 var(--tp-font);color:var(--tp-text);background:var(--tp-surface-raised);border:1px solid var(--tp-line-strong);border-radius:var(--tp-radius-sm);padding:10px 12px;min-height:44px;width:100%}
.tp-field textarea{min-height:190px;resize:vertical}
.tp-field input:focus,.tp-field textarea:focus,.tp-field select:focus{outline:none;border-color:var(--tp-accent);box-shadow:var(--tp-focus)}
.tp-card__hold{display:flex;flex-direction:column;gap:10px;padding:12px;border-radius:var(--tp-radius-sm);background:var(--tp-surface-2)}
.tp-card__hold p{display:flex;align-items:baseline;gap:8px;font-weight:650;font-size:16px}
.tp-card__count{font:700 28px/1 var(--tp-font-display);font-variant-numeric:tabular-nums;color:var(--tp-accent-strong);min-width:1ch}
.tp-app[data-scheme="dark"] .tp-card__count{color:var(--tp-accent)}
.tp-card__progress{height:6px;border-radius:3px;background:var(--tp-surface-3);overflow:hidden}
.tp-card__progress i{display:block;height:100%;width:100%;background:var(--tp-accent);border-radius:3px;transform-origin:left;transition:transform 1s linear}
.tp-card__result{display:flex;flex-direction:column;gap:10px;padding:12px;border-radius:var(--tp-radius-sm);background:var(--tp-ok-soft);color:var(--tp-ok);font-weight:600;font-size:15px;line-height:1.4}
.tp-card__result.is-neutral{background:var(--tp-surface-2);color:var(--tp-muted)}
.tp-card__result.is-warn{background:var(--tp-warn-soft);color:var(--tp-warn);font-weight:550;overflow-wrap:break-word}   /* email-cards-07 */
.tp-card__result .tp-chip--case{margin:0;padding:0 4px;min-height:var(--tp-h-chip);color:inherit;text-decoration:underline;text-underline-offset:3px}
.tp-card__result .tp-btn--secondary{align-self:flex-start;background:var(--tp-surface-raised);color:var(--tp-text)}
.tp-card__result .tp-chip--next{align-self:flex-start}
.tp-earlier{align-self:flex-start;min-height:38px;border:0;background:transparent;color:var(--tp-faint);font-size:13.5px;font-weight:600;padding:0}
.tp-applyall{display:flex;flex-direction:column;gap:10px;padding:10px 12px;border-radius:var(--tp-radius);border:1.5px dashed var(--tp-line-strong)}
.tp-applyall>button:first-child{min-height:44px;border:0;background:transparent;color:var(--tp-accent-strong);font-weight:700;font-size:15px;text-align:left;padding:0;display:flex;align-items:center;gap:6px}
.tp-app[data-scheme="dark"] .tp-applyall>button:first-child{color:var(--tp-accent)}
.tp-inline-confirm{display:flex;flex-direction:column;gap:10px;font-size:15px;font-weight:600}
.tp-inline-confirm small{font-weight:400;color:var(--tp-muted);font-size:13px}
.tp-applyall.is-done{border-style:solid;border-color:transparent;background:var(--tp-ok-soft);color:var(--tp-ok);font-weight:600}

/* ── S6 sheet (+ shared rows) ── */
.tp-scrim{position:absolute;inset:0;background:rgba(10,16,18,.38);z-index:30;opacity:1;transition:opacity .2s ease}
.tp-sheet{position:absolute;left:0;right:0;bottom:0;z-index:31;max-height:86%;display:flex;flex-direction:column;background:var(--tp-surface);-webkit-backdrop-filter:var(--tp-blur);backdrop-filter:var(--tp-blur);border-radius:var(--tp-radius-lg) var(--tp-radius-lg) 0 0;box-shadow:var(--tp-shadow-sheet);padding-bottom:var(--tp-safe-b);transition:transform .25s cubic-bezier(.2,.8,.2,1)}
.tp-sheet__handle{align-self:center;width:36px;height:5px;border-radius:3px;background:var(--tp-line-strong);margin:8px 0 2px}
.tp-sheet__head{display:flex;align-items:center;justify-content:space-between;padding:4px 12px 8px 20px;touch-action:none}
.tp-sheet__head h2{font-size:20px;font-weight:650}
.tp-sheet .tp-scroll{padding:0 12px 16px}
.tp-section-label{font-size:12.5px;font-weight:700;letter-spacing:.05em;text-transform:uppercase;color:var(--tp-muted);padding:14px 8px 6px}
.tp-rows{display:flex;flex-direction:column;background:var(--tp-surface-raised);border-radius:var(--tp-radius);border:1px solid var(--tp-line);overflow:hidden}
.tp-row{display:flex;align-items:center;gap:12px;min-height:56px;padding:8px 8px 8px 14px;border:0;border-top:1px solid var(--tp-line);background:transparent;width:100%;text-align:left;color:var(--tp-text)}
.tp-rows>.tp-row:first-child,.tp-rows>:first-child .tp-row{border-top:0}
.tp-row__icon{flex:none;width:32px;height:32px;border-radius:10px;display:grid;place-items:center;background:var(--tp-surface-2);color:var(--tp-muted)}
.tp-row__main{flex:1;min-width:0;display:flex;flex-direction:column;gap:1px;border:0;background:transparent;text-align:left;padding:0;color:inherit;align-self:stretch;justify-content:center}
.tp-row__title{font-size:15.5px;font-weight:600;line-height:1.3;overflow-wrap:anywhere}
.tp-row__meta{font-size:13px;color:var(--tp-faint);line-height:1.3}
.tp-row__act{flex:none;min-height:44px;padding:0 14px;border-radius:var(--tp-radius-pill);border:0;background:var(--tp-accent-soft);color:var(--tp-on-accent-soft);font-weight:600;font-size:14px}
.tp-row--accent .tp-row__icon{background:var(--tp-accent);color:var(--tp-on-accent)}
.tp-row--accent .tp-row__meta{color:var(--tp-accent-strong);font-weight:600}
.tp-app[data-scheme="dark"] .tp-row--accent .tp-row__meta{color:var(--tp-accent)}
.tp-row.is-muted{opacity:.6}
/* case-cards-18: an attachment folded out of its own printed email row (S8's Files pane) is indented
   instead of carrying a literal "↳ " prefix in its name — CaseFile.nested (server/pilot/needs.ts). */
/* [r3-files] the WHOLE nested row moves in (icon included) — never text indented under a fixed icon */
.tp-row--nested{padding-left:32px}
.tp-case__pane .tp-row__meta{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
/* navigation-row-titles-unclamped: real case titles run long — clamp to 2 lines instead of
   letting the row grow into a wall of bold text (chats list + Needs-you sheet). */
.tp-row--chat .tp-row__title,.tp-sheet .tp-row__title{display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;line-clamp:2;overflow:hidden;overflow-wrap:break-word}
/* navigation-chats-preview-raw-markdown / navigation-chats-dangling-separator: chatRowMeta() now
   returns a short one-line state ("TR0180 · answered 09:05"), but keep an ellipsis guard so a long
   case title can never push this onto multiple lines. */
.tp-row--chat .tp-row__meta{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.tp-fold{min-height:44px;width:100%;border:0;background:transparent;display:flex;align-items:center;justify-content:space-between;padding:0 8px;color:var(--tp-muted);font-weight:600;font-size:14.5px}
.tp-errline{display:flex;gap:8px;align-items:center;justify-content:space-between;padding:8px 12px;margin-top:8px;border-radius:var(--tp-radius-sm);background:var(--tp-warn-soft);color:var(--tp-warn);font-size:14px;font-weight:600}

/* ── S7 chats + settings ── */
.tp-chats__bar{flex:none;display:flex;align-items:center;justify-content:space-between;padding:2px 10px 6px 20px}
.tp-chats__bar h1{font-size:28px;font-weight:650}
.tp-chats .tp-scroll{padding:4px 12px 24px;display:flex;flex-direction:column;gap:4px}
/* a flex column that overflows would shrink its children; .tp-rows has overflow:hidden, so Settings collapsed to 2 px */
.tp-chats .tp-scroll>*{flex-shrink:0}
.tp-search{width:100%;font:var(--tp-fs-input)/1.3 var(--tp-font);color:var(--tp-text);background:var(--tp-surface-3);border:1px solid transparent;border-radius:var(--tp-radius-pill);min-height:44px;padding:0 16px 0 42px;margin-top:10px}
.tp-search:focus{outline:none;border-color:var(--tp-accent);box-shadow:var(--tp-focus)}
.tp-searchwrap{position:relative}
.tp-searchwrap svg{position:absolute;left:15px;top:23px;color:var(--tp-faint);pointer-events:none}
.tp-row--chat{padding-right:4px}
.tp-row--chat .tp-row__more{flex:none;width:44px;height:44px;border:0;background:transparent;border-radius:50%;display:grid;place-items:center;color:var(--tp-muted)}
.tp-rowmenu{display:flex;flex-wrap:wrap;align-items:center;gap:6px;padding:8px 8px 10px 58px;border-top:1px dashed var(--tp-line)}
.tp-rowmenu .tp-rowmenu__cancel{margin-left:auto}   /* [r3-rowmenu] Rename · Archive, Cancel as a quiet link at the right end — one row */
.tp-row--chat .tp-row__more[aria-expanded="true"]{visibility:hidden}
.tp-rowmenu input{flex:1 1 100%;font:var(--tp-fs-input)/1.3 var(--tp-font);min-height:44px;padding:0 12px;border-radius:var(--tp-radius-sm);border:1px solid var(--tp-line-strong);background:var(--tp-surface-raised);color:var(--tp-text)}
.tp-settings{margin-top:14px}
.tp-set{display:flex;flex-direction:column;gap:6px;padding:12px 14px;border-top:1px solid var(--tp-line)}
.tp-rows>.tp-set:first-child{border-top:0}
.tp-set__label{font-size:12.5px;font-weight:700;color:var(--tp-muted);letter-spacing:.03em}
.tp-set__value{font-size:15px;line-height:1.4}
.tp-set__value .tp-link{font-size:14.5px}
.tp-set--danger .tp-set__label{color:var(--tp-danger)}
.tp-set .tp-fold{padding:0;min-height:44px}   /* r2-23: the Model row's text starts on the same left edge as every other label */
.tp-set .tp-fold.tp-set__value{min-height:38px;margin:-6px 0;color:var(--tp-text);font-weight:400;font-size:15px}   /* [r3-settings] label over value, like every other row */
.tp-picker{display:flex;flex-direction:column;gap:8px;padding-top:4px}
.tp-picker__row{display:flex;flex-wrap:wrap;gap:6px}
.tp-panel-inline{display:flex;flex-direction:column;gap:10px;padding:12px;border-radius:var(--tp-radius-sm);background:var(--tp-surface-2);font-size:14px;line-height:1.45}
.tp-panel-inline.is-danger{background:var(--tp-danger-soft);color:var(--tp-danger)}
/* navigation-logout-everywhere-confirm-wraps: the confirm buttons must stay one line each — the
   trigger above the panel is now hidden while the panel is open, so this only guards long labels. */
.tp-panel-inline .tp-btnrow{flex-direction:column}   /* [r3-settings] both log-out confirms: the action, Cancel under it */
.tp-panel-inline .tp-btnrow>.tp-btn{flex:none;width:100%;white-space:nowrap}
.tp-footnote{font-size:12.5px;color:var(--tp-faint);padding:14px 8px 4px;text-align:center}

/* ── S8 case screen ── */
.tp-returnbar{flex:none;display:flex;align-items:center;gap:4px;min-height:48px;padding:2px 12px 4px 4px;background:var(--tp-bar-bg);border-bottom:1px solid var(--tp-line)}
.tp-returnbar button{min-height:44px;border:0;background:transparent;display:inline-flex;align-items:center;gap:2px;color:var(--tp-accent-strong);font-weight:600;font-size:16px;padding:0 8px}
.tp-app[data-scheme="dark"] .tp-returnbar button{color:var(--tp-accent)}
.tp-returnbar span{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--tp-muted);font-size:14px}
.tp-case .tp-returnbar span{opacity:0;transition:opacity .15s ease}   /* the case name appears in the bar only once the head scrolled under it */
.tp-case .tp-returnbar.is-titled span{opacity:1}
/* case-cards-03: tapping a tab scrollIntoView()s .tp-tabs (case.js) — scroll-padding-top keeps a
   sliver of breathing room above it instead of jamming the track against the top edge. */
/* (a) the last row always clears the floating Ask pill: pill height 48 + its 16 gap + 24 breathing room + safe area. */
.tp-case .tp-scroll{padding:14px 16px calc(48px + 16px + 44px + var(--tp-safe-b));display:flex;flex-direction:column;gap:14px;scroll-padding-top:8px}
.tp-case__head{display:flex;flex-direction:column;gap:4px}
.tp-case__head .tp-mono{color:var(--tp-accent-strong);font-weight:600;font-size:13.5px}
.tp-app[data-scheme="dark"] .tp-case__head .tp-mono{color:var(--tp-accent)}
.tp-case__head h1{font-size:23px;font-weight:650;line-height:1.25}
.tp-case__facts{display:grid;grid-template-columns:1fr 1fr;gap:8px}
.tp-fact{padding:8px 12px;border-radius:var(--tp-radius-sm);background:var(--tp-surface-raised);border:1px solid var(--tp-line);display:flex;flex-direction:column;gap:1px;min-width:0}
.tp-fact small{font-size:12.5px;font-weight:700;letter-spacing:.05em;text-transform:uppercase;color:var(--tp-faint)}
.tp-fact span{font-size:14.5px;font-weight:600;overflow-wrap:anywhere}
.tp-tabs{display:flex;gap:4px;padding:3px;border-radius:var(--tp-radius-pill);background:var(--tp-surface-3)}
.tp-tab{flex:1;min-height:44px;border:0;border-radius:var(--tp-radius-pill);background:transparent;font-weight:600;font-size:14px;color:var(--tp-muted)}
.tp-tab.is-on{background:var(--tp-surface-raised);color:var(--tp-text);box-shadow:var(--tp-shadow-card)}
/* case-cards-03: with the Status tile gone (case-cards-09) and the duplicate Ask link gone
   (case-cards-17) a short pane can be shorter than the viewport, which would leave nothing for
   scrollIntoView() to scroll — this floor keeps the tabs reachable at the top on every case. */
/* r2-14: no artificial min-height (it left a ~330pt void under two tasks) — case.js scrolls only as far as the
   content allows. */
.tp-case__pane{display:flex;flex-direction:column;gap:10px}
/* [case-summary] the AI summary is real markdown (case.js's summaryHtml/renderCaseSummary), not a
   plain string: a headline div, then a real <ul>/<p> body, plus a collapsed-by-default "Show all"
   toggle. All colors are var(--tp-*) tokens already redefined under .tp-app[data-scheme="dark"], so
   this reads correctly in both themes without a separate dark block — only the toggle's accent color
   (matching .tp-case__ask's own light/dark split just below) needs one. overflow-wrap:anywhere on the
   container AND each item covers a long IBAN/reference with no spaces to break on. */
.tp-case__summary{font-size:15.5px;line-height:1.55;padding:12px 14px;border-radius:var(--tp-radius);background:var(--tp-surface-raised);border:1px solid var(--tp-line);overflow-wrap:anywhere}
.tp-case__summary-head{font-size:16px;font-weight:600;line-height:1.4;color:var(--tp-text)}
.tp-case__summary-head+ul,.tp-case__summary-head+p{margin-top:8px}
.tp-case__summary-head:only-child{font-weight:400;font-size:15.5px;line-height:1.55}   /* [r3-summary] a one-paragraph summary is prose, never a bold wall */
.tp-case__summary p{margin:0 0 8px;overflow-wrap:anywhere}
.tp-case__summary p:last-child{margin-bottom:0}
.tp-case__summary ul{margin:0 0 8px;padding-left:20px;list-style:disc}
.tp-case__summary ul:last-child{margin-bottom:0}
.tp-case__summary li{margin:0 0 6px;overflow-wrap:anywhere}
.tp-case__summary li:last-child{margin-bottom:0}
.tp-case__summary strong{font-weight:700}
.tp-case__summary.is-collapsed ul{list-style:none;padding-left:0}
.tp-case__summary.is-collapsed li{position:relative;padding-left:20px;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;line-clamp:2;overflow:hidden}
.tp-case__summary.is-collapsed li::before{content:"\2022";position:absolute;left:5px;top:0}
.tp-case__summary-toggle{display:inline-flex;min-height:38px;align-items:center;margin-top:2px;border:0;background:transparent;padding:0;color:var(--tp-accent-strong);font-weight:600;font-size:14.5px}
.tp-app[data-scheme="dark"] .tp-case__summary-toggle{color:var(--tp-accent)}
.tp-case__ask{align-self:flex-start;min-height:44px;border:0;background:transparent;color:var(--tp-accent-strong);font-weight:600;font-size:15px;padding:0}
.tp-app[data-scheme="dark"] .tp-case__ask{color:var(--tp-accent)}
.tp-pill{position:absolute;left:50%;transform:translateX(-50%);bottom:calc(16px + var(--tp-safe-b));z-index:5;min-height:48px;padding:0 22px;border:0;border-radius:var(--tp-radius-pill);background:var(--tp-accent);color:var(--tp-on-accent);font-weight:650;font-size:16px;box-shadow:0 4px 14px rgba(11,11,12,.24);white-space:nowrap;display:inline-flex;align-items:center;gap:8px}

/* ── Entry: S1 install · S2 sign in · S3 notifications ── */
.tp-entry{padding:18px 22px 20px;display:flex;flex-direction:column;gap:14px}
.tp-entry__hero{display:flex;flex-direction:column;align-items:flex-start;gap:12px;padding-top:6px}
.tp-entry h1{font-size:27px;font-weight:650;letter-spacing:-.01em;line-height:1.2}
.tp-entry__lede{font-size:16px;color:var(--tp-muted)}
.tp-detect{display:flex;align-items:center;gap:8px;font-size:14px;color:var(--tp-muted)}
.tp-detect b{color:var(--tp-text)}
.tp-steplist{margin:0;padding:0;list-style:none;display:flex;flex-direction:column;gap:8px}
.tp-steplist li{display:flex;align-items:center;gap:12px;padding:10px 12px;border-radius:var(--tp-radius-sm);background:var(--tp-surface-raised);border:1px solid var(--tp-line);font-size:15.5px;line-height:1.35}
.tp-steplist__n{flex:none;width:28px;height:28px;border-radius:50%;display:grid;place-items:center;background:var(--tp-accent-soft);color:var(--tp-on-accent-soft);font-weight:700;font-size:14px}
.tp-steplist__pic{flex:none;margin-left:auto;width:34px;height:34px;border-radius:9px;display:grid;place-items:center;background:var(--tp-surface-2);color:var(--tp-text)}
.tp-infoline{font-size:13.5px;color:var(--tp-muted);line-height:1.45;padding:10px 12px;border-radius:var(--tp-radius-sm);background:var(--tp-surface-2)}
.tp-reason{font-size:15.5px;color:var(--tp-muted);line-height:1.45}
.tp-reason.is-card{color:var(--tp-warn);background:var(--tp-warn-soft);padding:8px 12px;border-radius:var(--tp-radius-sm);font-weight:600}
.tp-signin .tp-field input{font-size:var(--tp-fs-input);min-height:52px;letter-spacing:.1em}
.tp-error{display:flex;gap:8px;align-items:flex-start;font-size:14px;font-weight:600;color:var(--tp-danger);background:var(--tp-danger-soft);padding:8px 12px;border-radius:var(--tp-radius-sm)}
.tp-entry__foot{margin-top:auto;display:flex;flex-direction:column;gap:10px;padding:12px 22px calc(14px + var(--tp-safe-b))}
.tp-entry__foot .tp-btn--secondary{width:100%}
.tp-desk{display:flex;flex-direction:column;gap:10px}   /* [r3-desktop] */
.tp-desk .tp-btn--secondary{width:100%}
/* onboarding-02: with the keyboard up on sign-in, drop the footer to just the primary button so the
   access-code field and any error line stay above the keyboard instead of scrolling out of view. */
.tp-app[data-kbd="up"] .tp-entry__foot{padding-bottom:10px}
.tp-app[data-kbd="up"] .tp-signin .tp-entry__foot [data-act="google"],
.tp-app[data-kbd="up"] .tp-signin .tp-entry__foot .tp-small{display:none}
.tp-app[data-kbd="up"] .tp-signin .tp-entry__hero .tp-logo{display:none}
.tp-preview{display:flex;flex-direction:column;gap:8px;padding:14px 12px;border-radius:var(--tp-radius);background:var(--tp-ink)}
.tp-okline{display:flex;align-items:center;gap:8px;font-weight:650;color:var(--tp-ok);background:var(--tp-ok-soft);padding:10px 12px;border-radius:var(--tp-radius-sm);font-size:15px}
.tp-helpline{font-size:14.5px;line-height:1.45;color:var(--tp-warn);background:var(--tp-warn-soft);padding:10px 12px;border-radius:var(--tp-radius-sm)}

/* ── Phone OS (neutral — not restyled by looks) ── */
.tp-push{display:flex;gap:10px;align-items:flex-start;width:100%;padding:11px 12px;border:0;border-radius:22px;background:#F6F5F2;color:#0B0B0C;text-align:left;font-family:-apple-system,"Figtree",sans-serif;box-shadow:0 4px 18px rgba(0,0,0,.28)}
.tp-push img,.tp-push svg.tp-logo{flex:none}
.tp-push__txt{flex:1;min-width:0;display:flex;flex-direction:column;gap:1px;font-size:14.5px;line-height:1.3}
.tp-push__txt b{font-weight:650}
.tp-push__time{font-size:12.5px;color:#55534D}
.tp-privacy{position:absolute;inset:0;z-index:90;display:grid;place-items:center;background:var(--tp-bg)}
.tp-skeleton__line{display:block;height:14px;border-radius:7px;background:var(--tp-surface-2);width:40%}
.tp-skeleton__titlewrap{min-width:0;height:44px;display:flex;align-items:center;justify-content:center}
.tp-skeleton__line--title{width:120px;height:16px}
.tp-skeleton__strip{flex:none;margin:6px 12px 4px;padding:12px;border-radius:var(--tp-radius);background:var(--tp-surface-2)}
/* [onboarding-04] .tp-convo already supplies 14px 16px (below) — the skeleton used to add its OWN
   padding:14px 16px on top, so the bubbles sat 32px from each edge instead of 16, and jumped sideways
   and up the moment the real chat loaded. gap:16px matches the mock's bubble spacing. */
.tp-skeleton__convo{padding:0;gap:16px;display:flex;flex-direction:column}
.tp-skeleton__bubble{height:54px;border-radius:var(--tp-radius);background:var(--tp-surface-2);width:70%}
.tp-skeleton__bubble--me{align-self:flex-end;width:52%}
.tp-skeleton__bubble--pilot{align-self:flex-start;width:78%}
.tp-live.is-paused{gap:8px}
.tp-live.is-paused .tp-live__line{pointer-events:none;display:flex;align-items:center;gap:8px}
.tp-live.is-paused .tp-btn{align-self:flex-start}
.tp-pointer{display:flex;justify-content:flex-end;padding:0 58px 2px 0;color:var(--tp-text);font:600 13px -apple-system,"Figtree",sans-serif;align-items:center;gap:6px}

/* small shared utilities used by the engine */
.tp-sr{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}
.tp-small{font-size:13.5px;line-height:1.4}
.tp-pad{padding:4px 8px 8px}
.tp-empty-line{padding:18px 8px;text-align:center;color:var(--tp-muted);font-size:15px}
.tp-fact--wide{grid-column:1 / -1}
.tp-steplist__pic--txt{color:var(--tp-text);font:600 13px -apple-system,"Figtree",sans-serif}
.tp-pointer{justify-content:center;padding:6px 0 4px}
.tp-rowwrap{display:flex;flex-direction:column;border-top:1px solid var(--tp-line)}
.tp-rows>.tp-rowwrap:first-child{border-top:0}
.tp-rowwrap>.tp-row{border-top:0}
.tp-chats .tp-scroll>.tp-btn--primary{margin-top:4px}
.tp-card__list label{flex:1;min-width:0;display:flex}
.tp-card__case span{line-height:1.3}
span.tp-card__case{white-space:nowrap}   /* r2-01: the non-link "New case" / bulk destination chip stays one line */
.tp-strip__chip{padding:0 12px}
.tp-app .tp-link{align-self:flex-start}
/* [strip-dot] the Needs-you label is the dot at EVERY width (the words are .tp-sr in the markup), so 360, 375, 393 and 430 look the same */

@media (prefers-reduced-motion: reduce){
  .tp-app *,.tp-app *::before,.tp-app *::after,.pg-bar *{transition:none!important;animation:none!important;scroll-behavior:auto!important}
}

/* ══════════════ 2. look-glass.css, verbatim ══════════════ */
/* ═══════════════════ LOOK · LIQUID GLASS (data-look="glass") ═══════════════════
   Apple 2025 "Liquid Glass" on the TrimPilot engine markup. CSS only; every rule is scoped
   under .tp-app[data-look="glass"] (never bare [data-look] — the reviewer's "Liquid Glass"
   button in .pg-bar carries data-look="glass" too). Inlined AFTER the engine's own rules (same style block).
   Light first (her pick 01.09); dark = a restrained frosted variant.
   Layers: soft colour mesh on the app ground → translucent cards (inset specular top edge)
   → frosted header band and input dock that the conversation scrolls UNDER → crystal buttons.
   Accent = ink #0B0B0C on warm paper #F6F5F2 (CI V3.1, mock-up V2 Look A, 07.10); the teal / mesh / translucency of the first glass pass is gone.
   Private helper tokens are --gl-*; engine tokens are --tp-* (all redefined in dark).
   Fixed by her rules and NOT touched: --tp-h-primary 48 · --tp-h-secondary 44 · --tp-h-chip 38 ·
   --tp-fs-input 16 · --tp-sb-h · --tp-safe-b. No animations; transitions are the engine's own. */

/* ─────────────── 1 · Tokens · light ─────────────── */
.tp-app[data-look="glass"]{
  --tp-look-name:"glass";
  --tp-font:-apple-system,BlinkMacSystemFont,"SF Pro Text","Figtree","Helvetica Neue","Segoe UI",Roboto,sans-serif;
  --tp-font-display:-apple-system,BlinkMacSystemFont,"SF Pro Display","Figtree","Helvetica Neue",sans-serif;
  --tp-font-mono:ui-monospace,"SF Mono","IBM Plex Mono",Menlo,monospace;

  /* ground: flat warm paper, no colour mesh (ink skin, 07.10) */
  --tp-bg:#F6F5F2;
  --tp-bg-image:none;

  /* translucent layers (.55–.75 alpha, per the approved notes) */
  --tp-surface:#FFFFFF;          /* sheet, pages */
  --tp-surface-raised:#FFFFFF;   /* cards, rows, fields */
  --tp-surface-2:#EEECE7;        /* quiet panels inside cards */
  --tp-surface-3:#E6E3DC;          /* recessed tracks: seg, tabs, progress */
  --tp-blur:none;
  --tp-bar-bg:#F6F5F2;
  --tp-line:rgba(11,11,12,.12);
  --tp-line-strong:rgba(11,11,12,.24);

  /* text — darker than tonal so every level holds ≥ 4.5:1 on the palest→darkest glass composite */
  --tp-text:#0B0B0C;
  --tp-muted:#45433F;
  --tp-faint:#5F5C56;

  --tp-accent:#0B0B0C; --tp-accent-strong:#0B0B0C; --tp-on-accent:#F6F5F2;
  --tp-accent-soft:#EEECE7;
  --tp-on-accent-soft:#0B0B0C;
  --tp-me-bg:#E8E5DD;
  --tp-me-text:#0B0B0C;
  --tp-pilot-bg:transparent; --tp-pilot-text:#0B0B0C;
  --tp-ok:#1F5C3A; --tp-ok-soft:#E1EDE4;
  --tp-warn:#0B0B0C; --tp-warn-soft:#EEECE7; --tp-warn-line:rgba(11,11,12,.24);
  --tp-danger:#8C1D18; --tp-danger-soft:#F6E1DE;
  --tp-outline:#0B0B0C;
  --tp-focus:0 0 0 3px rgba(11,11,12,.38); --tp-warn-icon:#8C1D18;
  --tp-radius-sm:14px; --tp-radius:24px; --tp-radius-lg:34px; --tp-radius-pill:999px; --tp-bubble-radius:22px;
  --tp-shadow-card:0 0 0 .5px rgba(11,11,12,.04);
  --tp-shadow-sheet:0 -1px 0 rgba(11,11,12,.12);
  /* the second shadow paints the bar tint up behind the status bar (0 px on a real phone) */
  --tp-shadow-bar:0 calc(-1 * var(--tp-sb-h)) 0 var(--tp-sb-h) var(--tp-bar-bg);

  /* private glass tokens */
  --gl-edge:transparent;                       /* specular top edge */
  --gl-border:var(--tp-line);                     /* glass rim */
  --gl-rim:var(--tp-line);                           /* hairline that keeps a light rim visible on a light mesh */
  --gl-card:#FFFFFF;
  --gl-card-strong:#FFFFFF;
  --gl-card-dim:transparent;
  --gl-card-blur:none;
  --gl-inner-line:transparent;
  --gl-paper:#F6F5F2;                      /* the email preview — the most "paper" layer */
  --gl-crystal:#EEECE7;
  --gl-crystal-press:#E3E0D8;
  --gl-crystal-shadow:none;
  --gl-crystal-text:#0B0B0C;
  --gl-prom:#0B0B0C;
  --gl-prom-press:#2A2A2D;
  --gl-prom-shadow:none;
  --gl-prom-text:#F6F5F2;
  --gl-prom-tshadow:none;
  --gl-danger:#8C1D18;
  --gl-danger-shadow:none;
  --gl-accent-line:rgba(11,11,12,.16);
  --gl-field:#FFFFFF;
  --gl-field-line:rgba(11,11,12,.30);
  --gl-field-inset:none;
  --gl-recess:none;
  --gl-band-line:rgba(11,11,12,.12);
  --gl-band-shadow:none;
  --gl-dock-top:none;
  --gl-scrim:rgba(11,11,12,.46);
  --gl-lap-bot:56px;      /* S4: the dock (live row / context row / input bar) overlaps the chat by this.
                             No top overlap in S4: the engine's centerOn() parks a tall card 12 px below the
                             scroll top, which must stay visible (the case chip lives in the card head). */
  --gl-bar-h:52px;        /* S7 chats bar and S8 return bar, fixed so the overlap is exact */
  --gl-push:#F6F5F2;
  --gl-push-time:#55534D;
  --gl-dock:#FFFFFF;                      /* the floating input capsule (iOS 26) */
  --gl-dock-shadow:0 0 0 1px rgba(11,11,12,.18);
}

/* ─────────────── 1b · Tokens · dark (restrained frosted) — every token above is redefined ─────────────── */
.tp-app[data-look="glass"][data-scheme="dark"]{
  color-scheme:dark;
  --tp-look-name:"glass";
  --tp-font:-apple-system,BlinkMacSystemFont,"SF Pro Text","Figtree","Helvetica Neue","Segoe UI",Roboto,sans-serif;
  --tp-font-display:-apple-system,BlinkMacSystemFont,"SF Pro Display","Figtree","Helvetica Neue",sans-serif;
  --tp-font-mono:ui-monospace,"SF Mono","IBM Plex Mono",Menlo,monospace;
  --tp-bg:#0B0B0C;
  --tp-bg-image:none;
  --tp-surface:#161618;
  --tp-surface-raised:#161618;
  --tp-surface-2:#1F1F22;
  --tp-surface-3:#27272B;
  --tp-blur:none;
  --tp-bar-bg:#0B0B0C;
  --tp-line:rgba(246,245,242,.12);
  --tp-line-strong:rgba(246,245,242,.26);
  --tp-text:#F6F5F2;
  --tp-muted:#C4C1B9;
  --tp-faint:#A19E96;
  --tp-accent:#F6F5F2; --tp-accent-strong:#F6F5F2; --tp-on-accent:#0B0B0C;
  --tp-accent-soft:#27272B;
  --tp-on-accent-soft:#F6F5F2;
  --tp-me-bg:#27272B;
  --tp-me-text:#F6F5F2;
  --tp-pilot-bg:transparent; --tp-pilot-text:#F6F5F2;
  --tp-ok:#8FD0A6; --tp-ok-soft:#16291E;
  --tp-warn:#F6F5F2; --tp-warn-soft:#27272B; --tp-warn-line:rgba(246,245,242,.26);
  --tp-danger:#F2A59E; --tp-danger-soft:#341715;
  --tp-outline:#F6F5F2;
  --tp-focus:0 0 0 3px rgba(246,245,242,.45); --tp-warn-icon:#F2A59E;
  --tp-radius-sm:14px; --tp-radius:24px; --tp-radius-lg:34px; --tp-radius-pill:999px; --tp-bubble-radius:22px;
  --tp-shadow-card:0 0 0 .5px rgba(246,245,242,.06);
  --tp-shadow-sheet:0 -1px 0 rgba(246,245,242,.14);
  --tp-shadow-bar:0 calc(-1 * var(--tp-sb-h)) 0 var(--tp-sb-h) var(--tp-bar-bg);

  --gl-edge:transparent;
  --gl-border:var(--tp-line);
  --gl-rim:var(--tp-line);
  --gl-card:#161618;
  --gl-card-strong:#161618;
  --gl-card-dim:transparent;
  --gl-card-blur:none;
  --gl-inner-line:transparent;
  --gl-paper:#1F1F22;
  --gl-crystal:#27272B;
  --gl-crystal-press:#323238;
  --gl-crystal-shadow:none;
  --gl-crystal-text:#F6F5F2;
  --gl-prom:#F6F5F2;
  --gl-prom-press:#D9D7D0;
  --gl-prom-shadow:none;
  --gl-prom-text:#0B0B0C;
  --gl-prom-tshadow:none;
  --gl-danger:#F2A59E;
  --gl-danger-shadow:none;
  --gl-accent-line:rgba(246,245,242,.20);
  --gl-field:#161618;
  --gl-field-line:rgba(246,245,242,.32);
  --gl-field-inset:none;
  --gl-recess:none;
  --gl-band-line:rgba(246,245,242,.12);
  --gl-band-shadow:none;
  --gl-dock-top:none;
  --gl-scrim:rgba(0,0,0,.6);
  --gl-lap-bot:56px; --gl-bar-h:52px;
  --gl-push:#2A2A2E;
  --gl-push-time:#C4C1B9;
  --gl-dock:#161618;
  --gl-dock-shadow:0 0 0 1px rgba(246,245,242,.20);
}
/* the push platter on the dark scheme needs light text (phone-side, like iOS dark notifications) */

/* (the < 560 px "lighter blur, more opaque card" overrides are gone: the ink skin has no blur and no translucency to tune) */

/* ─────────────── 2 · Type ─────────────── */
.tp-app[data-look="glass"] :is(.tp-entry h1,.tp-chats__bar h1,.tp-empty h2,.tp-case__head h1){font-weight:700;letter-spacing:-.022em}
.tp-app[data-look="glass"] .tp-sheet__head h2{font-weight:700;letter-spacing:-.015em}
.tp-app[data-look="glass"] .tp-card__title{font-weight:650;letter-spacing:-.01em}
.tp-app[data-look="glass"] .tp-topbar__title strong{font-weight:650;letter-spacing:-.01em}

/* ─────────────── 3 · Crystal controls ─────────────── */
/* quiet crystal: translucent fill + specular top edge + soft ink shadow (no blur on buttons: nested blur is a perf killer) */
.tp-app[data-look="glass"] .tp-btn--secondary,
.tp-app[data-look="glass"] .tp-chip:where(:not(.tp-chip--case,.tp-strip__more)),
.tp-app[data-look="glass"] .tp-topbar__btn,
.tp-app[data-look="glass"] .tp-row__act,
.tp-app[data-look="glass"] .tp-banner__act,
.tp-app[data-look="glass"] .tp-seg button[aria-pressed="true"],
.tp-app[data-look="glass"] .tp-tab.is-on{
  background:var(--gl-crystal);border-color:transparent;box-shadow:var(--gl-crystal-shadow);
}
.tp-app[data-look="glass"] .tp-btn--secondary{color:var(--gl-crystal-text)}
.tp-app[data-look="glass"] .tp-chip:where(:not(.tp-chip--case,.tp-strip__more)){color:var(--tp-text)}
.tp-app[data-look="glass"] .tp-topbar__btn{color:var(--tp-text)}
.tp-app[data-look="glass"] .tp-row__act{color:var(--gl-crystal-text)}
.tp-app[data-look="glass"] .tp-banner__act{border:0;color:inherit}
.tp-app[data-look="glass"] :is(.tp-btn--secondary,.tp-topbar__btn,.tp-row__act,.tp-banner__act):active,
.tp-app[data-look="glass"] .tp-chip:where(:not(.tp-chip--case,.tp-strip__more,.tp-chip--on)):active{background:var(--gl-crystal-press)}

/* prominent crystal: accent gradient sheen + specular edge + tinted halo */
.tp-app[data-look="glass"] .tp-btn--primary,
.tp-app[data-look="glass"] .tp-send,
.tp-app[data-look="glass"] .tp-pill,
.tp-app[data-look="glass"] .tp-chip--on{
  background:var(--gl-prom);color:var(--gl-prom-text);box-shadow:var(--gl-prom-shadow);text-shadow:var(--gl-prom-tshadow);border-color:transparent;
}
.tp-app[data-look="glass"] :is(.tp-btn--primary,.tp-send,.tp-pill):active{background:var(--gl-prom-press)}
.tp-app[data-look="glass"] .tp-pill{box-shadow:0 0 0 1px rgba(246,245,242,.14),0 4px 14px rgba(11,11,12,.24)}
.tp-app[data-look="glass"] .tp-send.is-quiet{background:var(--gl-crystal);color:var(--gl-crystal-text);box-shadow:var(--gl-crystal-shadow);text-shadow:none}
.tp-app[data-look="glass"] .tp-send.is-quiet:active{background:var(--gl-crystal-press)}
.tp-app[data-look="glass"] .tp-send[disabled],.tp-app[data-look="glass"] .tp-send[aria-disabled="true"]{background:var(--tp-surface-3);color:var(--tp-faint);box-shadow:var(--gl-recess);text-shadow:none}
.tp-app[data-look="glass"] .tp-btn--primary[disabled]{box-shadow:none;text-shadow:none}

/* danger: Stop, Log out everywhere */
.tp-app[data-look="glass"] .tp-btn--danger{background:var(--tp-danger-soft);color:var(--tp-danger);box-shadow:inset 0 1px 0 var(--gl-edge),inset 0 0 0 1px rgba(140,29,24,.16),0 4px 12px -6px rgba(140,29,24,.25)}
.tp-app[data-look="glass"] .tp-btn--danger.tp-btn--primary{background:var(--gl-danger);color:var(--gl-prom-text);box-shadow:var(--gl-danger-shadow)}
.tp-app[data-look="glass"][data-scheme="dark"] .tp-btn--danger.tp-btn--primary{color:#4A0F0B}
.tp-app[data-look="glass"][data-scheme="dark"] .tp-btn--danger{box-shadow:inset 0 1px 0 var(--gl-edge),inset 0 0 0 1px rgba(255,180,171,.16)}

/* next chip = accent-tinted crystal */
.tp-app[data-look="glass"] .tp-chip--next{background:var(--tp-accent-soft);color:var(--tp-on-accent-soft);box-shadow:inset 0 0 0 1px var(--gl-accent-line)}
.tp-app[data-look="glass"] .tp-chip--suggest{min-height:42px;padding:0 16px;font-weight:550}

/* recessed tracks */
.tp-app[data-look="glass"] .tp-seg,
.tp-app[data-look="glass"] .tp-tabs{background:var(--tp-surface-3);box-shadow:var(--gl-recess)}
.tp-app[data-look="glass"] .tp-seg button[aria-pressed="true"],
.tp-app[data-look="glass"] .tp-tab.is-on{color:var(--tp-text)}
/* case-cards-15 (her 03.09 rule: "toggled = accent-filled; never ship a toggle whose selected state is
   only a shadow") — placed after both glass .tp-tab.is-on rules above so it wins the cascade (same
   specificity, later wins) without touching .tp-seg, which she did not flag. */
.tp-app[data-look="glass"] .tp-tab.is-on{background:var(--tp-accent);color:var(--tp-on-accent);font-weight:700;box-shadow:none}

.tp-app[data-look="glass"] .tp-topbar__btn{width:44px;height:44px}
.tp-app[data-look="glass"] .tp-model{background:var(--gl-crystal);box-shadow:inset 0 1px 0 var(--gl-edge),0 0 0 .5px var(--gl-rim);color:var(--tp-muted)}

/* ─────────────── 4 · S4 chat: frosted header slab (top bar + strip band) and a frosted dock the chat scrolls UNDER ─────────────── */
/* stacking: the conversation sits at z 0, every bar/band/dock piece at z 3 */
.tp-app[data-look="glass"] .tp-screen > .tp-scroll{position:relative;z-index:0}
.tp-app[data-look="glass"] :is(.tp-topbar,.tp-banner,.tp-strip,.tp-live,.tp-context,.tp-inputbar,.tp-returnbar,.tp-chats__bar){position:relative;z-index:3}

/* [case-cards-02] the input dock overlaps the bottom of the scroller by --gl-lap-bot with no scroll-padding,
   so scrollIntoView aligned a target right under it, cut in half — 16px of extra clearance above the dock.
   [chat-10] a soft frosted top edge instead of a hard cut — without the mask, scrolled text is sliced flush
   against the header/strip band with nothing to soften it (looks like a rendering glitch at 3x).
   [ghost-01] MAJOR 1 (round 4) — --gl-lap-bot is a FIXED 56px (the input bar's own overlap). When the dock is
   taller (a context tray and/or the live row ALSO render above the input bar), their top edge sits well above
   where a fixed-56px fade already finished — a fully opaque line of the answer was then sliced by the tray's
   top edge, its lower half showing faintly through the glass (shots-r3/chat__answer-long-opened, 375×812 and
   393×852, dark). chat.js's syncDockObserver()/measureDockOverlap() write the REAL measured overlap (scroller
   bottom → first dock piece's top) onto the scroller as --tp-dock-over; every place below that used to assume
   --gl-lap-bot now reads that instead, falling back to --gl-lap-bot before the first measurement (or if chat.js
   ever fails to find a dock at all) — margin-bottom stays tied to the fixed CSS constant on purpose (it is what
   actually POSITIONS the dock; feeding a measured value back into it would create a resize feedback loop).
   [ghost-01b] the transparent point keeps a 32px buffer PAST --tp-dock-over, not flush with it, for TWO
   stacked reasons: (1) the first dock piece's own ::before (the blur band, below) is shifted `top:-8px` on
   purpose — its frosted band starts 8px ABOVE the dock element's measured top; (2) --tp-blur is `blur(18px)`,
   and a CSS Gaussian blur of radius R samples roughly 3×(R/2) ≈ 27px beyond an element's own box to render its
   edges without a hard cutoff — so backdrop-filter on that band pulls in (and visibly blurs) whatever the
   scroller drew up to ~27px above the band's OWN top, i.e. up to ~35px above --tp-dock-over. An 8px buffer
   left a legible blurred fragment there (verified empirically: shots-r4/chat__answer-long-opened, round 4's
   first pass, was pixel-identical to the shots-r3 "before" — same 56px overlap, same visible "Bewag Mahnung…"
   ghost text — because 56px measured is not the bug; a too-thin buffer against the blur radius is). 32px
   clears both with room to spare. */
.tp-app[data-look="glass"] .tp-screen--s4 > .tp-scroll{
  margin-bottom:calc(-1 * var(--gl-lap-bot));padding-bottom:calc(var(--tp-dock-over, var(--gl-lap-bot)) + 24px);scroll-padding-bottom:calc(var(--tp-dock-over, var(--gl-lap-bot)) + 24px);   /* [fade-end] the measured dock overlap + 24px of air: the LAST element at the end of the scroll rests just above the dock, in full colour, because .is-at-end drops the bottom fade (below) */
 
  /* [r3-fade] top: the fade starts under the strip band's overhang and runs a full line (40px) with a strong
     early ramp, so a scrolled line is never sliced flush against the band (content at rest: .tp-convo 40px top).
     bottom: the SAME fade above the dock — fully transparent 32px past the dock's real top edge (--tp-dock-over
     + 32px buffer, see [ghost-01b] above — clears the blur radius, not just the box edge).
     [fade-72] the fade zone is 72px above the dock (it was 192). 192px made a parked draft — the view she
     lands on when a draft opens, the question parked at the top and the card read downward — show a pale ghost
     Send button and a faded "Can't be unsent" line (shots-r6/needs-strip__strip__393x852__light), because the
     buttons of a long card sit in the lowest 100-190px of the band right after the park. Segments, measured up
     from the dock's real top edge: opaque at +72px, 60% at +56px, 20% at +44px, 3% at +36px, transparent at
     +32px. The last 32px stay fully transparent ON PURPOSE (the [ghost-01b] buffer above), so the 40px ramp is
     the whole fade: a line is either readable or already gone, and nothing reads through the dock's blur band.
     A button whose bottom edge sits 16px into the zone is still ~60% opaque; one fully above +72px is untouched.
     Padding and scroll-padding below are the dock overlap + 24px — the end of the scroll no longer needs the
     fade's height, because .is-at-end (below) drops the bottom half of the mask there. */
  -webkit-mask-image:linear-gradient(to bottom,transparent 0,transparent 6px,rgba(0,0,0,.5) 20px,#000 40px,#000 calc(100% - var(--tp-dock-over, var(--gl-lap-bot)) - 72px),rgba(0,0,0,.6) calc(100% - var(--tp-dock-over, var(--gl-lap-bot)) - 56px),rgba(0,0,0,.2) calc(100% - var(--tp-dock-over, var(--gl-lap-bot)) - 44px),rgba(0,0,0,.03) calc(100% - var(--tp-dock-over, var(--gl-lap-bot)) - 36px),transparent calc(100% - var(--tp-dock-over, var(--gl-lap-bot)) - 32px));
  mask-image:linear-gradient(to bottom,transparent 0,transparent 6px,rgba(0,0,0,.5) 20px,#000 40px,#000 calc(100% - var(--tp-dock-over, var(--gl-lap-bot)) - 72px),rgba(0,0,0,.6) calc(100% - var(--tp-dock-over, var(--gl-lap-bot)) - 56px),rgba(0,0,0,.2) calc(100% - var(--tp-dock-over, var(--gl-lap-bot)) - 44px),rgba(0,0,0,.03) calc(100% - var(--tp-dock-over, var(--gl-lap-bot)) - 36px),transparent calc(100% - var(--tp-dock-over, var(--gl-lap-bot)) - 32px));
}
.tp-app[data-look="glass"] .tp-screen--s4 .tp-convo{padding-top:40px}
/* [fade-end] at the end of the scroll nothing lies beyond the fade: the bottom half of the mask goes away (the top
   fade stays). app.js toggles .is-at-end on scroll / resize (TP.fadeEnd). The last element rests dock-overlap + 24px
   above the scroller's bottom — inside the 72px zone's footprint — and is only drawn in full colour because of this
   switch, which flips within the last 4px of the scroll. */
.tp-app[data-look="glass"] .tp-screen--s4 > .tp-scroll.is-at-end{
  -webkit-mask-image:linear-gradient(to bottom,transparent 0,transparent 6px,rgba(0,0,0,.5) 20px,#000 40px);
  mask-image:linear-gradient(to bottom,transparent 0,transparent 6px,rgba(0,0,0,.5) 20px,#000 40px);
}
/* [parked-actions] a card parked at its top (chat-03) with its buttons in the lowest part of the band: Send and Edit /
   Redraft / Not this must never be PALE — pale reads as disabled. While chat.js (syncParkedActions) sees a pinned, untouched
   parked card whose buttons reach into the 72px ramp, the scroller carries .is-actions-parked and the bottom of the mask is
   a HARD edge instead of the ramp: opaque down to the cut, nothing below it. The cut is dock top - 32px (the same fully
   transparent buffer the ramp ends in, so [ghost-01b] — no readable text through the dock — still holds), or the top of the
   Edit / Redraft / Not this row when the 32px line would slice through it (chat.js sets --tp-park-cut, px from the scroller's
   top). Gone the moment she scrolls or touches, or the buttons leave the ramp. Never at the end of the scroll: .is-at-end
   already drops the whole bottom half there, and its last element rests 24px above the dock, i.e. BELOW this edge.
   The TOP ramp keeps its 6 / 20 / 40px stops unless the card was nudged up into it (360 wide: the card's top is 12px under
   the scroller's top): then chat.js sets --tp-park-t0/t1/t2 so the ramp ends AT the card's top (transparent 6px above it,
   opaque at it) and the header is at full colour — what sits above is only the gap to the previous message. */
.tp-app[data-look="glass"] .tp-screen--s4 > .tp-scroll.is-actions-parked:not(.is-at-end){
  -webkit-mask-image:linear-gradient(to bottom,transparent 0,transparent var(--tp-park-t0,6px),rgba(0,0,0,.5) var(--tp-park-t1,20px),#000 var(--tp-park-t2,40px),#000 var(--tp-park-cut,calc(100% - var(--tp-dock-over, var(--gl-lap-bot)) - 32px)),transparent var(--tp-park-cut,calc(100% - var(--tp-dock-over, var(--gl-lap-bot)) - 32px)));
  mask-image:linear-gradient(to bottom,transparent 0,transparent var(--tp-park-t0,6px),rgba(0,0,0,.5) var(--tp-park-t1,20px),#000 var(--tp-park-t2,40px),#000 var(--tp-park-cut,calc(100% - var(--tp-dock-over, var(--gl-lap-bot)) - 32px)),transparent var(--tp-park-cut,calc(100% - var(--tp-dock-over, var(--gl-lap-bot)) - 32px)));
}
/* [parked-actions] a button the hard edge has already hidden takes no tap (chat.js marks it .is-parked-out) */
.tp-card__actions .tp-btn.is-parked-out{pointer-events:none}
/* [r3-sheet] the composer never glows through the Needs-you sheet */
.tp-chat.is-sheet > .tp-inputbar,.tp-chat.is-sheet > .tp-context,.tp-chat.is-sheet > .tp-live{visibility:hidden}
/* [r3-applyall] while "Apply N" is being confirmed it is the ONE primary: the per-card Apply buttons step back */
.tp-app .tp-msg--pilot:has(.tp-applyall .tp-inline-confirm) .tp-card .tp-btn--primary[data-act="primary"]{background:var(--gl-crystal,var(--tp-accent-soft));color:var(--gl-crystal-text,var(--tp-on-accent-soft));box-shadow:var(--gl-crystal-shadow,none);text-shadow:none;font-size:15px}

/* top bar: frosted, and its tint runs up behind the status bar */
.tp-app[data-look="glass"] .tp-topbar{background:var(--tp-bar-bg)}

/* banners: tinted glass bands inside the header */
.tp-app[data-look="glass"] .tp-banner{border:0;box-shadow:inset 0 1px 0 var(--gl-inner-line),inset 0 -1px 0 var(--tp-line)}
.tp-app[data-look="glass"] .tp-banner--relay{box-shadow:inset 0 1px 0 rgba(255,255,255,.5),inset 0 -1px 0 var(--tp-warn-line)}
.tp-app[data-look="glass"] .tp-banner--offline{background:var(--tp-bar-bg);color:var(--tp-muted)}
.tp-app[data-look="glass"] .tp-banner--update{background:var(--tp-surface-2)}
.tp-app[data-look="glass"][data-scheme="dark"] .tp-banner--relay{box-shadow:inset 0 1px 0 rgba(255,255,255,.06),inset 0 -1px 0 var(--tp-warn-line)}

/* Needs-you strip = crystal capsule on a frosted band (::before) that continues the top bar, so bar + strip read as
   one header slab. The capsule is painted on ::after so the band sits below it inside the strip's stacking context. */
.tp-app[data-look="glass"] .tp-strip{background:transparent}
.tp-app[data-look="glass"] .tp-strip::before{content:"";position:absolute;inset:-6px -12px -4px;z-index:-2;pointer-events:none;background:var(--tp-bar-bg);-webkit-backdrop-filter:var(--tp-blur);backdrop-filter:var(--tp-blur);box-shadow:var(--gl-band-shadow)}
.tp-app[data-look="glass"] .tp-strip::after{content:"";position:absolute;inset:0;z-index:-1;pointer-events:none;border-radius:inherit;background:var(--gl-card);box-shadow:inset 0 1px 0 var(--gl-edge),0 0 0 .5px var(--gl-rim),0 4px 14px -8px rgba(11,11,12,.18)}
.tp-app[data-look="glass"][data-scheme="dark"] .tp-strip::after{box-shadow:inset 0 1px 0 var(--gl-edge),0 0 0 .5px rgba(255,255,255,.07),0 4px 14px -8px rgba(0,0,0,.6)}
.tp-app[data-look="glass"] .tp-strip__label{color:var(--tp-muted)}
.tp-app[data-look="glass"] .tp-strip__label i{box-shadow:0 0 0 3px var(--gl-accent-line)}
.tp-app[data-look="glass"] .tp-strip__chip{padding:0 14px}
.tp-app[data-look="glass"] .tp-strip__more{border-radius:var(--tp-radius-pill)}
.tp-app[data-look="glass"] .tp-strip__more:active{background:var(--tp-surface-3)}
.tp-app[data-look="glass"] .tp-strip--empty{color:var(--tp-muted)}

/* the conversation */
.tp-app[data-look="glass"] .tp-msg--me .tp-msg__body{box-shadow:none}
.tp-app[data-look="glass"] .tp-msg__status--wait{background:var(--tp-warn-soft);border-color:var(--tp-warn-line);box-shadow:inset 0 1px 0 var(--gl-inner-line),0 4px 12px -8px rgba(11,11,12,.18)}
.tp-app[data-look="glass"] .tp-msg__meta .tp-spark{color:var(--tp-accent)}
.tp-app[data-look="glass"] .tp-divider{color:var(--tp-muted)}
.tp-app[data-look="glass"] .tp-divider::before,.tp-app[data-look="glass"] .tp-divider::after{background:linear-gradient(90deg,transparent,var(--tp-line-strong))}
.tp-app[data-look="glass"] .tp-divider::after{background:linear-gradient(90deg,var(--tp-line-strong),transparent)}
.tp-app[data-look="glass"] .tp-steps__list{box-shadow:inset 0 1px 0 var(--gl-inner-line),0 0 0 .5px var(--gl-rim)}
.tp-app[data-look="glass"] .tp-steps__toggle:active{background:var(--tp-surface-3)}

/* dock: live row + context row + input bar read as one frosted slab the chat slides under.
   live/context: band on ::before (blur), capsule on ::after, same trick as the strip */
.tp-app[data-look="glass"] .tp-live,
.tp-app[data-look="glass"] .tp-context{background:transparent}
.tp-app[data-look="glass"] .tp-live::before,
.tp-app[data-look="glass"] .tp-context::before{content:"";position:absolute;inset:0 -12px -6px;z-index:-2;pointer-events:none;background:var(--tp-bar-bg);-webkit-backdrop-filter:var(--tp-blur);backdrop-filter:var(--tp-blur)}
.tp-app[data-look="glass"] .tp-live::after,
.tp-app[data-look="glass"] .tp-context::after{content:"";position:absolute;inset:0;z-index:-1;pointer-events:none;border-radius:inherit;background:var(--gl-card);box-shadow:inset 0 1px 0 var(--gl-edge),0 0 0 .5px var(--gl-rim),0 4px 14px -8px rgba(11,11,12,.18)}
.tp-app[data-look="glass"][data-scheme="dark"] .tp-live::after,
.tp-app[data-look="glass"][data-scheme="dark"] .tp-context::after{box-shadow:inset 0 1px 0 var(--gl-edge),0 0 0 .5px rgba(255,255,255,.07),0 4px 14px -8px rgba(0,0,0,.6)}
/* the dock's top edge sits on whichever piece comes first after the chat */
.tp-app[data-look="glass"] .tp-screen--s4 > .tp-scroll + .tp-live::before,
.tp-app[data-look="glass"] .tp-screen--s4 > .tp-scroll + .tp-context::before{top:-8px;box-shadow:var(--gl-dock-top)}
.tp-app[data-look="glass"] .tp-live .tp-steps__list{background:var(--gl-paper)}
.tp-app[data-look="glass"] .tp-live__line{color:var(--tp-text)}
.tp-app[data-look="glass"] .tp-live__line svg{color:var(--tp-accent)}
.tp-app[data-look="glass"] .tp-context__about{background:var(--tp-accent-soft);box-shadow:inset 0 1px 0 var(--gl-edge),inset 0 0 0 1px var(--gl-accent-line)}

/* the input bar floats as a frosted capsule with side margins (iOS 26); the chat scrolls under and around it */
.tp-app[data-look="glass"] .tp-inputbar{margin:0 10px calc(8px + var(--tp-safe-b));padding:6px;border:0;border-radius:31px;background:var(--gl-dock);box-shadow:var(--gl-dock-shadow)}
.tp-app[data-look="glass"][data-kbd="up"] .tp-inputbar{margin-bottom:6px;padding-bottom:6px}
.tp-app[data-look="glass"] .tp-live + .tp-inputbar,
.tp-app[data-look="glass"] .tp-context + .tp-inputbar{margin-top:4px}
.tp-app[data-look="glass"] .tp-input{background:var(--gl-field);border-color:transparent;box-shadow:0 0 0 1px var(--gl-field-line),0 1px 0 1px var(--gl-inner-line)}
.tp-app[data-look="glass"] .tp-input:focus{border-color:transparent;box-shadow:0 0 0 1px var(--tp-accent),var(--tp-focus)}
.tp-app[data-look="glass"] .tp-hint{color:var(--tp-muted);padding:2px 12px 3px}

/* ─────────────── 5 · S5 proposal cards ─────────────── */
.tp-app[data-look="glass"] .tp-card{background:var(--gl-card);border-color:var(--gl-border);-webkit-backdrop-filter:var(--gl-card-blur);backdrop-filter:var(--gl-card-blur)}
.tp-app[data-look="glass"][data-scheme="dark"] .tp-card{border-color:rgba(255,255,255,.09)}
.tp-app[data-look="glass"] .tp-card.is-editing{background:var(--gl-card-strong)}
.tp-app[data-look="glass"] .tp-card.is-dismissed{background:var(--gl-card-dim);border-color:var(--tp-line-strong);-webkit-backdrop-filter:none;backdrop-filter:none}
.tp-app[data-look="glass"] .tp-card.is-outlined{box-shadow:0 0 0 2.5px var(--tp-outline)}
.tp-app[data-look="glass"] .tp-card__icon{border-radius:13px;background:var(--tp-accent-soft);box-shadow:inset 0 1px 0 var(--gl-edge),inset 0 0 0 1px var(--gl-accent-line)}
.tp-app[data-look="glass"] .tp-card__mail{background:var(--gl-paper);box-shadow:inset 0 0 0 1px var(--gl-inner-line),0 0 0 .5px var(--gl-rim)}
.tp-app[data-look="glass"] .tp-card__to:active{background:var(--tp-surface-3);border-radius:var(--tp-radius-pill)}
.tp-app[data-look="glass"] .tp-attach{background:var(--gl-crystal);border-color:transparent;box-shadow:inset 0 1px 0 var(--gl-edge),0 0 0 .5px var(--gl-rim)}
.tp-app[data-look="glass"] .tp-attach svg{color:var(--tp-accent)}
.tp-app[data-look="glass"] .tp-attach button{color:var(--tp-muted)}
.tp-app[data-look="glass"] .tp-attach button:active{background:var(--tp-surface-3)}
.tp-app[data-look="glass"] .tp-change,
.tp-app[data-look="glass"] .tp-card__list,
.tp-app[data-look="glass"] .tp-card__hold{box-shadow:inset 0 1px 0 var(--gl-inner-line),0 0 0 .5px var(--gl-rim)}
.tp-app[data-look="glass"] .tp-change__to{color:var(--tp-accent-strong)}
.tp-app[data-look="glass"][data-scheme="dark"] .tp-change__to{color:var(--tp-accent-strong)}
.tp-app[data-look="glass"] .tp-card__warn{box-shadow:inset 0 1px 0 rgba(255,255,255,.5);border-color:var(--tp-warn-line)}
.tp-app[data-look="glass"][data-scheme="dark"] .tp-card__warn{box-shadow:inset 0 1px 0 rgba(255,255,255,.06)}
.tp-app[data-look="glass"] .tp-card__progress{background:var(--tp-surface-3);box-shadow:var(--gl-recess)}
.tp-app[data-look="glass"] .tp-card__progress i{background:var(--gl-prom)}
.tp-app[data-look="glass"] .tp-card__count{color:var(--tp-accent-strong)}
.tp-app[data-look="glass"] .tp-card__result{box-shadow:inset 0 1px 0 var(--gl-inner-line),0 0 0 .5px rgba(21,90,54,.14),0 6px 16px -10px rgba(21,90,54,.35)}
.tp-app[data-look="glass"] .tp-card__result.is-neutral,
.tp-app[data-look="glass"] .tp-card__result.is-warn{box-shadow:inset 0 1px 0 var(--gl-inner-line),0 0 0 .5px var(--gl-rim)}
.tp-app[data-look="glass"][data-scheme="dark"] .tp-card__result{box-shadow:inset 0 1px 0 rgba(255,255,255,.07),0 0 0 .5px rgba(147,219,171,.18)}
.tp-app[data-look="glass"] .tp-card__result .tp-btn--secondary{background:var(--gl-crystal);color:var(--tp-text);box-shadow:var(--gl-crystal-shadow)}
.tp-app[data-look="glass"] .tp-card__history{border-left-color:var(--gl-accent-line)}
.tp-app[data-look="glass"] .tp-earlier{color:var(--tp-muted)}
.tp-app[data-look="glass"] .tp-field input,
.tp-app[data-look="glass"] .tp-field textarea,
.tp-app[data-look="glass"] .tp-field select,
.tp-app[data-look="glass"] .tp-rowmenu input{background:var(--gl-field);border-color:var(--gl-field-line);box-shadow:var(--gl-field-inset)}
.tp-app[data-look="glass"] .tp-field input:focus,
.tp-app[data-look="glass"] .tp-field textarea:focus,
.tp-app[data-look="glass"] .tp-field select:focus,
.tp-app[data-look="glass"] .tp-rowmenu input:focus{border-color:var(--tp-accent);box-shadow:var(--gl-field-inset),var(--tp-focus);outline:none}
/* Apply all (2+ case changes) — dashed glass pocket, green glass when done */
.tp-app[data-look="glass"] .tp-applyall{border-color:var(--gl-accent-line);background:rgba(255,255,255,.30);-webkit-backdrop-filter:var(--gl-card-blur);backdrop-filter:var(--gl-card-blur)}
.tp-app[data-look="glass"][data-scheme="dark"] .tp-applyall{background:rgba(255,255,255,.04)}
.tp-app[data-look="glass"] .tp-applyall.is-done{border-color:transparent;background:var(--tp-ok-soft);box-shadow:inset 0 1px 0 var(--gl-inner-line),0 0 0 .5px rgba(21,90,54,.14)}
.tp-app[data-look="glass"] .tp-inline-confirm small{color:var(--tp-muted)}

/* ─────────────── 6 · S6 Needs-you sheet + shared rows ─────────────── */
.tp-app[data-look="glass"] .tp-scrim{background:var(--gl-scrim)}
.tp-app[data-look="glass"] .tp-sheet{border-top:0}
.tp-app[data-look="glass"] .tp-sheet__handle{background:var(--tp-line-strong);width:40px}
.tp-app[data-look="glass"] .tp-rows{background:var(--tp-surface-raised);border-color:var(--gl-border);box-shadow:var(--tp-shadow-card);-webkit-backdrop-filter:var(--gl-card-blur);backdrop-filter:var(--gl-card-blur)}
.tp-app[data-look="glass"][data-scheme="dark"] .tp-rows{border-color:rgba(255,255,255,.08)}
.tp-app[data-look="glass"] .tp-row:where(button):active,
.tp-app[data-look="glass"] .tp-row__main:active{background:var(--tp-surface-3)}
.tp-app[data-look="glass"] .tp-row__icon{border-radius:11px;background:var(--gl-crystal);color:var(--tp-muted);box-shadow:inset 0 1px 0 var(--gl-edge),0 0 0 .5px var(--gl-rim)}
.tp-app[data-look="glass"] .tp-row--accent .tp-row__icon{background:var(--gl-prom);color:var(--gl-prom-text);box-shadow:var(--gl-prom-shadow)}
.tp-app[data-look="glass"] .tp-row__meta{color:var(--tp-faint)}
.tp-app[data-look="glass"] .tp-row--accent .tp-row__meta{color:var(--tp-accent-strong)}
.tp-app[data-look="glass"][data-scheme="dark"] .tp-row--accent .tp-row__meta{color:var(--tp-accent)}
.tp-app[data-look="glass"] .tp-section-label{color:var(--tp-muted)}
.tp-app[data-look="glass"] .tp-errline{box-shadow:inset 0 1px 0 var(--gl-inner-line),0 0 0 .5px var(--tp-warn-line)}
.tp-app[data-look="glass"] .tp-fold:active{background:var(--tp-surface-3);border-radius:var(--tp-radius-sm)}

/* ─────────────── 7 · S7 chats + settings ─────────────── */
.tp-app[data-look="glass"] .tp-chats__bar{height:var(--gl-bar-h);background:var(--tp-bar-bg);-webkit-backdrop-filter:var(--tp-blur);backdrop-filter:var(--tp-blur);box-shadow:var(--tp-shadow-bar),0 1px 0 var(--gl-band-line)}
.tp-app[data-look="glass"] .tp-chats > .tp-scroll{margin-top:calc(-1 * var(--gl-bar-h));padding-top:calc(40px + var(--gl-bar-h));scroll-padding-top:calc(var(--gl-bar-h) + 40px);
  /* [r3-fade] a full line of fade under the bar — "+ New chat" / "Settings" are never sliced by its bottom edge.
     [ghost-04] SMALL (d) (round 4) — the old ramp finished at +32px but padding-top was only +28px: content at
     rest sat 4px INSIDE the still-fading zone, so scrolling back up after opening Settings sliced "+ New chat"
     against the header. Now the same 40px ramp as the chat/case top fades, with padding-top/scroll-padding-top
     grown to match — content at rest (and a scrollIntoView target) always starts past the point the mask is
     fully opaque. */
  -webkit-mask-image:linear-gradient(to bottom,transparent 0,transparent var(--gl-bar-h),rgba(0,0,0,.12) calc(var(--gl-bar-h) + 8px),rgba(0,0,0,.5) calc(var(--gl-bar-h) + 20px),#000 calc(var(--gl-bar-h) + 40px));mask-image:linear-gradient(to bottom,transparent 0,transparent var(--gl-bar-h),rgba(0,0,0,.12) calc(var(--gl-bar-h) + 8px),rgba(0,0,0,.5) calc(var(--gl-bar-h) + 20px),#000 calc(var(--gl-bar-h) + 40px))}
.tp-app[data-look="glass"] .tp-search{background:var(--gl-field);border-color:var(--gl-field-line);box-shadow:var(--gl-field-inset)}
.tp-app[data-look="glass"] .tp-search:focus{border-color:var(--tp-accent);box-shadow:var(--gl-field-inset),var(--tp-focus)}
.tp-app[data-look="glass"] .tp-searchwrap svg{color:var(--tp-muted)}
.tp-app[data-look="glass"] .tp-rowmenu{border-top-color:var(--tp-line);background:rgba(255,255,255,.28)}
.tp-app[data-look="glass"][data-scheme="dark"] .tp-rowmenu{background:rgba(255,255,255,.03)}
.tp-app[data-look="glass"] .tp-row__more:active{background:var(--tp-surface-3)}
.tp-app[data-look="glass"] .tp-set__label{color:var(--tp-muted)}
.tp-app[data-look="glass"] .tp-panel-inline{box-shadow:inset 0 1px 0 var(--gl-inner-line),0 0 0 .5px var(--gl-rim)}
.tp-app[data-look="glass"] .tp-panel-inline.is-danger{box-shadow:inset 0 1px 0 var(--gl-inner-line),0 0 0 .5px rgba(140,29,24,.18)}
.tp-app[data-look="glass"] .tp-footnote{color:var(--tp-muted)}

/* ─────────────── 8 · S8 case screen ─────────────── */
.tp-app[data-look="glass"] .tp-returnbar{height:var(--gl-bar-h);border-bottom:0;background:var(--tp-bar-bg);-webkit-backdrop-filter:var(--tp-blur);backdrop-filter:var(--tp-blur);box-shadow:var(--tp-shadow-bar),0 1px 0 var(--gl-band-line)}
.tp-app[data-look="glass"] .tp-case > .tp-scroll{margin-top:calc(-1 * var(--gl-bar-h));padding-top:calc(40px + var(--gl-bar-h));scroll-padding-top:calc(var(--gl-bar-h) + 40px);padding-bottom:calc(88px + var(--tp-safe-b));scroll-padding-bottom:calc(88px + var(--tp-safe-b));   /* [fade-end] the Ask pill's overlap (16px + 48px) + 24px of air: the last line at the end of the scroll rests just above the pill, in full colour (.is-at-end drops the bottom fade) */

  /* r2-14: nothing reads through the translucent return bar — the scroller fades out under it.
     [ghost-02] MAJOR 2 (round 4) — the old ramp was only 18px (transparent → opaque), so a scrolled title or
     fact value could sit half-inside it and read as sliced in half rather than faded (shots-r3/case-cards__
     case-tab-tasks, case-tab-files, both light+dark, and case-summary-expanded-end at 1280×900). Now the SAME
     40px ramp + early step as the chat top fade (opaque only past +40px: transparent to bar-h, ~.12 at +8px,
     ~.5 at +20px, opaque at +40px) — and padding-top grew to match (40px, not 20px) so content AT REST starts
     exactly where the fade finishes, never sitting inside the still-fading zone itself. scroll-padding-top grew
     the same amount, so a scrollIntoView target lands clear of the ramp too, not just 10px under the bar.
     [r3-pill] bottom: text dissolves ABOVE the floating Ask pill — never a line sliced by the pill with its
     rest showing below it (the summary card, a long pane). [ghost-05] SMALL (e) — the old 32px ramp left a
     "half email row" faintly visible above the pill (only 8px of buffer past full transparency); lengthened to
     48px and pushed the transparent point to 16px above the pill's own top edge. */
  -webkit-mask-image:linear-gradient(to bottom,transparent 0,transparent var(--gl-bar-h),rgba(0,0,0,.12) calc(var(--gl-bar-h) + 8px),rgba(0,0,0,.5) calc(var(--gl-bar-h) + 20px),#000 calc(var(--gl-bar-h) + 40px),#000 calc(100% - 128px - var(--tp-safe-b)),transparent calc(100% - 80px - var(--tp-safe-b)));
  mask-image:linear-gradient(to bottom,transparent 0,transparent var(--gl-bar-h),rgba(0,0,0,.12) calc(var(--gl-bar-h) + 8px),rgba(0,0,0,.5) calc(var(--gl-bar-h) + 20px),#000 calc(var(--gl-bar-h) + 40px),#000 calc(100% - 128px - var(--tp-safe-b)),transparent calc(100% - 80px - var(--tp-safe-b)))}
.tp-app[data-look="glass"] .tp-case > .tp-scroll.is-at-end{   /* [fade-end] end of the scroll: only the top fade stays */
  -webkit-mask-image:linear-gradient(to bottom,transparent 0,transparent var(--gl-bar-h),rgba(0,0,0,.12) calc(var(--gl-bar-h) + 8px),rgba(0,0,0,.5) calc(var(--gl-bar-h) + 20px),#000 calc(var(--gl-bar-h) + 40px));
  mask-image:linear-gradient(to bottom,transparent 0,transparent var(--gl-bar-h),rgba(0,0,0,.12) calc(var(--gl-bar-h) + 8px),rgba(0,0,0,.5) calc(var(--gl-bar-h) + 20px),#000 calc(var(--gl-bar-h) + 40px))}
.tp-app[data-look="glass"] .tp-returnbar button{border-radius:var(--tp-radius-pill)}
.tp-app[data-look="glass"] .tp-returnbar button:active{background:var(--tp-surface-3)}
.tp-app[data-look="glass"] .tp-returnbar span{color:var(--tp-muted)}
.tp-app[data-look="glass"] .tp-fact,
.tp-app[data-look="glass"] .tp-case__summary{background:var(--gl-card);border-color:var(--gl-border);box-shadow:var(--tp-shadow-card);-webkit-backdrop-filter:var(--gl-card-blur);backdrop-filter:var(--gl-card-blur)}
.tp-app[data-look="glass"][data-scheme="dark"] .tp-fact,
.tp-app[data-look="glass"][data-scheme="dark"] .tp-case__summary{border-color:rgba(255,255,255,.08)}
.tp-app[data-look="glass"] .tp-fact small{color:var(--tp-muted)}
.tp-app[data-look="glass"] .tp-case__ask{color:var(--tp-accent-strong)}
.tp-app[data-look="glass"][data-scheme="dark"] .tp-case__ask{color:var(--tp-accent)}

/* ─────────────── 9 · Entry: S1 install · S2 sign in · S3 notifications ─────────────── */
.tp-app[data-look="glass"] .tp-entry__lede,
.tp-app[data-look="glass"] .tp-detect{color:var(--tp-muted)}
.tp-app[data-look="glass"] .tp-steplist li{background:var(--gl-card);border-color:var(--gl-border);box-shadow:var(--tp-shadow-card);-webkit-backdrop-filter:var(--gl-card-blur);backdrop-filter:var(--gl-card-blur)}
.tp-app[data-look="glass"][data-scheme="dark"] .tp-steplist li{border-color:rgba(255,255,255,.08)}
.tp-app[data-look="glass"] .tp-steplist__n{background:var(--gl-prom);color:var(--gl-prom-text);box-shadow:var(--gl-prom-shadow);text-shadow:var(--gl-prom-tshadow)}
.tp-app[data-look="glass"] .tp-steplist__pic{background:var(--gl-crystal);box-shadow:inset 0 1px 0 var(--gl-edge),0 0 0 .5px var(--gl-rim)}
.tp-app[data-look="glass"] .tp-infoline{color:var(--tp-muted);box-shadow:inset 0 1px 0 var(--gl-inner-line),0 0 0 .5px var(--gl-rim);-webkit-backdrop-filter:var(--gl-card-blur);backdrop-filter:var(--gl-card-blur)}
.tp-app[data-look="glass"] .tp-reason{color:var(--tp-muted)}
.tp-app[data-look="glass"] .tp-reason.is-card,
.tp-app[data-look="glass"] .tp-helpline{color:var(--tp-warn);box-shadow:inset 0 1px 0 var(--gl-inner-line),0 0 0 .5px var(--tp-warn-line)}
.tp-app[data-look="glass"] .tp-error{box-shadow:inset 0 1px 0 var(--gl-inner-line),0 0 0 .5px rgba(140,29,24,.18)}
.tp-app[data-look="glass"] .tp-okline{box-shadow:inset 0 1px 0 var(--gl-inner-line),0 0 0 .5px rgba(21,90,54,.16)}
.tp-app[data-look="glass"] .tp-signin .tp-field input{background:var(--gl-field)}
.tp-app[data-look="glass"] .tp-logo{box-shadow:0 1px 0 rgba(255,255,255,.6),0 10px 26px -8px rgba(11,11,12,.45)}
/* S3 preview = a little lock-screen wallpaper with glass platters */
.tp-app[data-look="glass"] .tp-preview{border-radius:var(--tp-radius);padding:16px 12px;background:var(--tp-ink);box-shadow:0 0 0 .5px rgba(11,11,12,.2)}

/* ─────────────── 10 · Lock screen + push platters (iOS 26 glass) ─────────────── */
.tp-app[data-look="glass"] .tp-lock{background:#0B0B0C}
.tp-app[data-look="glass"] .tp-lock__time{color:#F6F5F2}
.tp-app[data-look="glass"] .tp-lock__foot span{background:rgba(246,245,242,.14);box-shadow:none}
.tp-app[data-look="glass"] .tp-lock__btn{background:rgba(246,245,242,.14)}
.tp-app[data-look="glass"] .tp-lock__btn[aria-pressed="true"]{background:#F6F5F2;color:#0B0B0C}
.tp-app[data-look="glass"] .tp-push{background:var(--gl-push);box-shadow:0 4px 18px rgba(0,0,0,.32)}
.tp-app[data-look="glass"][data-scheme="dark"] .tp-push{color:#F6F5F2}
.tp-app[data-look="glass"] .tp-push__time{color:var(--gl-push-time)}
.tp-app[data-look="glass"] .tp-home__dock{box-shadow:none}
.tp-app[data-look="glass"] .tp-home__toast{background:rgba(11,11,12,.72);box-shadow:none}

/* ─────────────── 11 · Links, text buttons, focus ─────────────── */
.tp-app[data-look="glass"] .tp-btn--text:active{background:var(--tp-surface-3)}
.tp-app[data-look="glass"] .tp-msg__status .tp-btn--text{color:inherit}
/* focus ring as an outline so it survives the crystal box-shadows (fields keep their own glow) */
.tp-app[data-look="glass"] :focus-visible:not(input,textarea,select){outline:2.5px solid var(--tp-accent);outline-offset:2px}

/* ─────────────── 12 · Fallbacks: none needed — the ink skin is already opaque (no backdrop-filter, no translucency to fall back from) ─────────────── */
/* ═══════════════════ end LIQUID GLASS ═══════════════════ */


/* ═══ Real-device block (PR-1, §7.1) — the .pg-device[data-frame] mock wrapper doesn't exist on a
   real phone; --tp-sb-h/--tp-safe-b come from the actual safe-area insets, and --tp-vvh (written by
   app.js on every visualViewport resize) keeps the app pinned to the visible viewport when the
   keyboard is up. ═══ */
.tp-app{position:fixed;inset:0;height:var(--tp-vvh,100dvh);--tp-sb-h:env(safe-area-inset-top);--tp-safe-b:env(safe-area-inset-bottom)}
html,body{margin:0;background:#F6F5F2}
@media (prefers-color-scheme: dark){ html,body{background:#0B0B0C} }

/* navigation-desktop-fullbleed: on a laptop the phone shell stays a phone-width column, centred —
   never an edge-to-edge stretch of the mobile layout (mock: glass-desktop.png). */
@media (min-width:600px){
  .tp-app{max-width:480px;margin-inline:auto;box-shadow:0 0 0 1px var(--tp-line),0 30px 70px rgba(11,11,12,.18)}
}

/* [desk-install] the laptop install page: the phone column would leave its lower two-thirds empty, so on a wide
   window this one screen drops the column and centres a single glass card, hero left and the way in right.
   Phone and tablet widths (and every other screen, incl. the chat) keep the column above. Existing tokens only. */
.tp-entry__side{display:flex;flex-direction:column;gap:14px}
@media (min-width:600px){
  .tp-app:has(.tp-install--desk){max-width:none;box-shadow:none}
  .tp-install--desk .tp-scroll{display:flex;padding:32px 24px}   /* margin:auto below centres it both ways and still scrolls from the top when the window is short */
  .tp-install--desk .tp-entry{margin:auto;width:min(860px,100%);box-sizing:border-box;flex-direction:row;align-items:center;gap:56px;padding:56px 60px;border-radius:var(--tp-radius-lg);background:var(--tp-surface-raised);border:1px solid var(--tp-line);box-shadow:var(--tp-shadow-card)}
  .tp-install--desk .tp-entry__hero{flex:1 1 0;min-width:0;padding-top:0;gap:16px}
  .tp-install--desk .tp-entry h1{font-size:34px}
  .tp-install--desk .tp-entry__lede{font-size:18px}
  .tp-install--desk .tp-entry__side{flex:1 1 0;min-width:0;gap:18px;padding-left:56px;border-left:1px solid var(--tp-line)}
  .tp-install--desk .tp-desk{gap:12px}
  .tp-app[data-look="glass"] .tp-install--desk .tp-entry{background:var(--gl-card);border-color:var(--gl-border);box-shadow:var(--tp-shadow-card);-webkit-backdrop-filter:var(--gl-card-blur);backdrop-filter:var(--gl-card-blur)}
  .tp-app[data-look="glass"][data-scheme="dark"] .tp-install--desk .tp-entry{border-color:rgba(255,255,255,.09)}
}

/* ═══ PR-6 additions — its scoped `.tp-row{box-sizing:border-box}` workaround is gone: the global reset above covers it. ═══ */

/* ═══ integration additions (29.09, chat.js / cards.js / case.js) ═══
   - `hidden` must beat the author `display` of .tp-screen / .tp-hint (S8 hides the chat section
     underneath instead of rebuilding it, so the draft and an open card edit survive the round trip).
   - the sheet's scrim + sheet travel in one patchable wrapper that must not create a box.
   - small hooks for the new card lines (removed attachment, excluded bulk email, busy card, revise). */
#tpApp [hidden]{display:none !important}
.tp-sheetwrap{display:contents}
.tp-card.is-busy .tp-card__actions{opacity:.72}
.tp-card__removed{font-size:13px;color:var(--tp-muted)}
.tp-card__list li.is-excluded span{color:var(--tp-faint);text-decoration:line-through;text-decoration-color:var(--tp-line-strong)}
/* case-cards-10 + case-cards-14: an <em>, never a <small> (which would inherit .tp-card__list li small's
   mono font) — one quiet line under the subject, ellipsized rather than wrapping to 2 lines, at the
   13px case-cards-14 asked for (already satisfied here, so its own base-rule bump is superseded by this
   more specific selector — see both branches' reports). */
.tp-card__from{display:block;font:400 13px/1.35 var(--tp-font);font-style:normal;color:var(--tp-faint);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.tp-case__full{display:inline-flex;align-items:center;text-decoration:none}
.tp-msg__note{flex-basis:100%}
/* the inline "change" (filing toggle) / "Put back" links sit in 13 px lines: grow their invisible tap area to
   the 38 px floor without moving the line (same trick as .tp-link--inline, a little taller) */
.tp-card__after .tp-link--inline,.tp-card__removed .tp-link--inline,.tp-set__value .tp-link--inline{padding:12px 0;margin:-12px 0}
.tp-msg__status .tp-btn--text{min-width:44px}   /* a short "OK" still meets the tap floor */
/* ═══ end integration additions ═══ */
/* ═══ ink skin (07.10, mock-up V2 Look A): the warning triangles carry the danger red; the warning text itself is ink on a neutral ground ═══ */
.tp-app :is(.tp-banner--relay,.tp-card__warn,.tp-errline,.tp-helpline,.tp-reason.is-card,.tp-attach.is-missing,.tp-msg__status--wait,.tp-upchip.is-wait,.tp-up__ring.is-wait)>svg{color:var(--tp-warn-icon)}


/* ═══ phone uploads (02.10): the dock's paperclip + upload chips, the files under a bubble, the filing card, the case's "+ Add files" ═══
   Existing tokens only (light, dark and glass all come through them); one glass override block at the end. No animations. */
/* the ONE hidden <input type=file> (appended to <body> by chat.js): off-screen but still in the layout, so iOS opens its picker */
.tp-filepick{position:fixed;top:0;left:0;width:1px;height:1px;opacity:0;pointer-events:none;overflow:hidden}

/* the paperclip: a quiet 48 px round button left of the field (tonal, so the filled Send stays the one loud thing in the dock) */
.tp-clip{flex:none;width:48px;height:48px;border-radius:50%;border:0;background:var(--tp-surface-3);color:var(--tp-muted);display:grid;place-items:center}
.tp-clip:active{background:var(--tp-line-strong)}

/* the chips above the dock: one scrolling row, a chip never wider than ~3/4 of the phone */
.tp-upchips-wrap{display:flex;flex-direction:column;gap:2px;min-width:0}
/* author CSS beats the UA's [hidden] rule: without this the EMPTY wrap stayed a flex item and the dock grew by the 4px column gap */
.tp-upchips-wrap[hidden]{display:none}
.tp-upchips{display:flex;gap:8px;overflow-x:auto;overscroll-behavior-x:contain;scrollbar-width:none;padding:2px 0 6px;min-width:0}
.tp-upchips::-webkit-scrollbar{display:none}
.tp-upchip{flex:none;display:flex;align-items:center;gap:8px;min-height:52px;max-width:min(76vw,290px);padding:6px 4px 6px 10px;border:1px solid var(--tp-line-strong);border-radius:16px;background:var(--tp-surface-raised);color:var(--tp-text)}
.tp-upchip__txt{display:flex;flex-direction:column;min-width:0;line-height:1.25}
.tp-upchip__txt b{display:block;min-width:0;font-size:14px;font-weight:600}
.tp-upchip__txt small{display:block;font-size:12.5px;color:var(--tp-faint);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.tp-upchip__x{flex:none;width:44px;height:44px;margin:-6px 0;border:0;background:transparent;color:var(--tp-muted);border-radius:50%;display:grid;place-items:center}
.tp-upchip__retry{flex:none;min-height:44px;margin:-6px 0;padding:0 8px;border:0;background:transparent;color:var(--tp-accent-strong);font-weight:700;font-size:14px}
.tp-app[data-scheme="dark"] .tp-upchip__retry{color:var(--tp-accent)}
.tp-upchip.is-wait{background:var(--tp-warn-soft);border-color:var(--tp-warn-line)}
.tp-upchip.is-wait .tp-upchip__txt small{color:var(--tp-warn)}
.tp-upchip.is-fail{background:var(--tp-danger-soft);border-color:var(--tp-danger)}
.tp-upchip.is-fail .tp-upchip__txt small{color:var(--tp-danger);white-space:normal;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;line-clamp:2}   /* round 2 (W1): the refusal sentence ('You can’t add files to this folder') is the message — two lines, not an ellipsis */
.tp-upnote{font-size:12.5px;line-height:1.35;color:var(--tp-warn);padding:0 6px 4px}

/* the file name as head + tail: a narrow place ellipsizes the HEAD, the extension and the last characters always show */
.tp-fn{display:flex;min-width:0;max-width:100%}
.tp-fn__head{min-width:0;flex:0 1 auto;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.tp-fn__tail{flex:none;white-space:pre}

/* the ring: progress while it goes up (a 0-100 arc from --p), a check / clock / warning once it is not going up any more */
.tp-up__ring{flex:none;width:28px;height:28px;display:grid;place-items:center;border-radius:50%;color:var(--tp-accent)}
.tp-up__ring > svg.tp-up__svg{width:28px;height:28px;transform:rotate(-90deg)}
.tp-up__trk{fill:none;stroke:var(--tp-surface-3);stroke-width:2.8}
.tp-up__arc{fill:none;stroke:var(--tp-accent);stroke-width:2.8;stroke-linecap:round;stroke-dasharray:100;stroke-dashoffset:calc(100 - var(--p,0))}
.tp-up__ring.is-done{background:var(--tp-ok-soft);color:var(--tp-ok)}
.tp-up__ring.is-wait{background:var(--tp-warn-soft);color:var(--tp-warn)}
.tp-up__ring.is-fail{background:var(--tp-danger-soft);color:var(--tp-danger)}
.tp-upchip.is-wait .tp-up__ring.is-wait{background:transparent}
.tp-upchip.is-fail .tp-up__ring.is-fail{background:transparent}

/* her message: the files under it, right-aligned like the bubble */
.tp-msg__files{display:flex;flex-direction:column;align-items:flex-end;gap:4px;max-width:100%;min-width:0}
.tp-msg__file{display:inline-flex;align-items:center;gap:6px;max-width:100%;min-width:0;padding:6px 10px;border-radius:14px;background:var(--tp-me-bg);color:var(--tp-me-text);font-size:13.5px;line-height:1.3}
.tp-msg__file svg{flex:none}
.tp-msg__file small{flex:none;font-size:12.5px;white-space:nowrap;opacity:.85}
.tp-msg__file.is-fail{background:var(--tp-danger-soft);color:var(--tp-danger)}

/* the filing card */
.tp-card__fdest{display:flex;gap:8px;align-items:baseline;font-size:14.5px;line-height:1.4}
.tp-card__farrow{flex:none;color:var(--tp-accent-strong);font-weight:700}
.tp-app[data-scheme="dark"] .tp-card__farrow{color:var(--tp-accent)}
.tp-card__fwhere{min-width:0;overflow-wrap:anywhere}
.tp-card__fwhere b{font-family:var(--tp-font-mono);font-weight:600;color:var(--tp-accent-strong)}
.tp-app[data-scheme="dark"] .tp-card__fwhere b{color:var(--tp-accent)}
/* the folder path takes its own line under the case number, so a long path never leaves a dangling dot at a line end */
.tp-card__fsep{display:none}
.tp-card__fpath{display:block;margin-top:2px;color:var(--tp-muted);font-size:13px}
.tp-card__files{display:flex;flex-direction:column;gap:12px}
.tp-ffield{display:flex;flex-direction:column;gap:4px;min-width:0}
.tp-ffield label{display:flex;flex-direction:column;gap:1px;min-width:0;font-size:12.5px;font-weight:600;color:var(--tp-muted)}
.tp-ffield__was{display:block;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-weight:400;color:var(--tp-faint)}
.tp-ffield__in{font:var(--tp-fs-input)/1.4 var(--tp-font);color:var(--tp-text);background:var(--tp-surface-raised);border:1px solid var(--tp-line-strong);border-radius:var(--tp-radius-sm);padding:10px 12px;min-height:44px;width:100%;min-width:0;display:block;box-sizing:border-box;resize:none;overflow:hidden;white-space:pre-wrap;overflow-wrap:anywhere;word-break:break-word}
.tp-ffield__in:focus{outline:none;border-color:var(--tp-accent);box-shadow:var(--tp-focus)}
.tp-card__flist{margin:0;padding:0;list-style:none;display:flex;flex-direction:column;gap:8px}
.tp-card__flist li{display:flex;gap:8px;align-items:flex-start;font-size:14.5px;line-height:1.4}
.tp-flist__mark{flex:none;width:18px;font-weight:700;text-align:center}
.tp-card__flist li.is-ok .tp-flist__mark{color:var(--tp-ok)}
.tp-card__flist li.is-bad .tp-flist__mark{color:var(--tp-danger)}
.tp-flist__name{display:flex;flex-direction:column;min-width:0;overflow-wrap:anywhere}
.tp-flist__name small{font-size:13px;color:var(--tp-danger)}
.tp-card__flist.is-undone .tp-flist__name{color:var(--tp-muted)}
.tp-card__other{display:flex;flex-direction:column;gap:10px;padding:12px;border-radius:var(--tp-radius-sm);background:var(--tp-surface-2)}
.tp-card__otherchips{display:flex;flex-wrap:wrap;gap:8px}

/* the case screen's "+ Add files" and the rows of files still going up */
.tp-addfiles{width:100%;min-height:var(--tp-h-primary)}
.tp-rows--up{border-radius:var(--tp-radius-sm)}
.tp-up__bar{display:block;height:4px;margin-top:6px;border-radius:2px;background:var(--tp-surface-3);overflow:hidden}
.tp-up__bar i{display:block;height:100%;border-radius:2px;background:var(--tp-accent)}
.tp-row--up.is-waiting .tp-row__meta{color:var(--tp-warn)}
.tp-row--up.is-failed .tp-row__meta{color:var(--tp-danger)}
.tp-row--up .tp-row__acts{display:flex;flex-wrap:wrap;gap:8px;margin-top:6px}
.tp-row--up .tp-row__act{padding:0 14px}
.tp-row--up .tp-row__act[data-act="caseUpRemove"]{background:transparent;color:var(--tp-muted)}

/* glass look: the paperclip is crystal like the other tonal buttons; chips and fields use the glass field */
.tp-app[data-look="glass"] .tp-clip{background:var(--gl-crystal);color:var(--gl-crystal-text);box-shadow:var(--gl-crystal-shadow)}
.tp-app[data-look="glass"] .tp-clip:active{background:var(--gl-crystal-press)}
.tp-app[data-look="glass"] .tp-upchip{background:var(--gl-field);border-color:var(--gl-field-line);box-shadow:var(--gl-field-inset)}
.tp-app[data-look="glass"] .tp-upchip.is-wait{background:var(--tp-warn-soft);border-color:var(--tp-warn-line)}
.tp-app[data-look="glass"] .tp-upchip.is-fail{background:var(--tp-danger-soft);border-color:var(--tp-danger)}
.tp-app[data-look="glass"] .tp-ffield__in{background:var(--gl-field);border-color:var(--gl-field-line);box-shadow:var(--gl-field-inset)}
.tp-app[data-look="glass"] .tp-ffield__in:focus{border-color:var(--tp-accent);box-shadow:var(--gl-field-inset),var(--tp-focus)}
.tp-app[data-look="glass"] .tp-card__other{background:var(--tp-surface-2)}
.tp-app[data-look="glass"] .tp-addfiles{background:var(--gl-crystal);color:var(--gl-crystal-text);box-shadow:var(--gl-crystal-shadow)}
/* ═══ end phone uploads ═══ */
/* ═══ [workable-tasks] (02.10) the Tasks pane — Done circle, expand-in-place, the clean-up card ═══
   Existing tokens only. Every tap target is ≥ 44 px; every long text clamps at 2 lines until it is tapped open. */
#tpCaseScroll{scroll-padding-bottom:128px}
.tp-task{display:flex;align-items:flex-start;gap:2px;padding:2px 12px 8px 2px;border-top:1px solid var(--tp-line);background:transparent;color:var(--tp-text)}
.tp-rows>.tp-task:first-child{border-top:0}
.tp-task__check{flex:none;width:48px;height:48px;border:0;background:transparent;display:grid;place-items:center;padding:0;color:inherit}
.tp-task__ring{width:26px;height:26px;border-radius:50%;border:2px solid var(--tp-muted);display:grid;place-items:center;box-sizing:border-box;transition:background-color .15s ease,border-color .15s ease}
.tp-task__check:active .tp-task__ring{background:var(--tp-accent-soft);border-color:var(--tp-accent)}
.tp-task__ring.is-on{background:var(--tp-ok);border-color:var(--tp-ok);color:var(--tp-surface-raised)}
.tp-task__ring.is-off{border-color:var(--tp-line-strong);color:var(--tp-faint)}
.tp-task__body{flex:1;min-width:0;display:flex;flex-direction:column;gap:0;padding-top:2px}
.tp-task__text{display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;line-clamp:2;-webkit-box-pack:center;overflow:hidden;overflow-wrap:anywhere;text-align:left;border:0;background:transparent;padding:8px 0 4px;margin:0;min-height:44px;font:600 15.5px/1.35 var(--tp-font);color:var(--tp-text);width:100%}
span.tp-task__text{min-height:0;padding:12px 0 2px}
.tp-task.is-open .tp-task__text{display:block;-webkit-line-clamp:unset;line-clamp:unset;overflow:visible}
.tp-case__pane .tp-task .tp-row__meta{white-space:normal;overflow:visible;text-overflow:clip;padding-bottom:2px}
.tp-task__was{color:var(--tp-faint)}
.tp-task__moved{color:var(--tp-accent-strong);font-weight:600}
.tp-task.is-just-done{background:var(--tp-ok-soft)}
.tp-task__text.is-done{text-decoration:line-through;text-decoration-color:var(--tp-faint);color:var(--tp-muted);font-weight:500}
.tp-task__meta.is-done{color:var(--tp-ok)}
.tp-task__text.is-retired{color:var(--tp-faint);font-weight:500}
.tp-task__line{display:flex;align-items:center;flex-wrap:wrap;gap:0 8px}
.tp-task__line .tp-row__meta{flex:1 1 auto;min-width:0}
.tp-task__undo{flex:none;min-width:44px;min-height:44px;padding:0 12px;margin:0 -10px 0 -12px;border:0;background:transparent;color:var(--tp-accent-strong);font:600 14.5px/1.2 var(--tp-font)}
.tp-task__undo:active{opacity:.6}
.tp-task__undo.is-saving,.tp-task__undo[aria-disabled="true"]{color:var(--tp-muted);font-weight:500;pointer-events:none}   /* "Saving…": quiet but readable (no opacity: a faded accent fails contrast) */
.tp-task.is-readonly .tp-task__text{display:block;-webkit-line-clamp:unset;line-clamp:unset;overflow:visible}
.tp-cl__line.is-changed .tp-cl__tick{opacity:.4;pointer-events:none}
.tp-task__group{display:flex;flex-direction:column;gap:6px;margin-top:8px}
.tp-task__grouphead{font:600 13px/1.2 var(--tp-font);letter-spacing:.02em;color:var(--tp-muted);padding:6px 6px 0}
.tp-task__group--retired .tp-rows{background:var(--tp-surface-2)}
.tp-task.is-done .tp-task__text,.tp-task.is-retired .tp-task__text{min-height:0}
.tp-task__more{display:flex;flex-direction:column;gap:10px;margin:2px 0 6px}
.tp-task__acts{display:grid;grid-template-columns:1fr 1fr;gap:8px}
.tp-task__act{min-height:44px;padding:0 10px;font-size:14.5px;white-space:nowrap}
.tp-task__act--ai{grid-column:1 / -1}
.tp-task__act[aria-expanded="true"]{box-shadow:inset 0 0 0 2px var(--tp-accent)}
.tp-task__panel{display:flex;flex-direction:column;gap:10px;padding:10px 12px 12px;border-radius:var(--tp-radius-sm);background:var(--tp-surface-2)}
.tp-task__q{font:600 14px/1.3 var(--tp-font);color:var(--tp-muted)}
.tp-task__chips{display:flex;flex-wrap:wrap;gap:8px}
.tp-task__chip{min-height:44px;padding:0 16px}
.tp-task__input{box-sizing:border-box;width:100%;min-height:44px;padding:0 12px;border-radius:var(--tp-radius-sm);border:1px solid var(--tp-line-strong);background:var(--tp-surface-raised);color:var(--tp-text);font:var(--tp-fs-input)/1.3 var(--tp-font)}
.tp-task__field{display:flex;align-items:center;gap:10px}
.tp-task__field>span{flex:none;font:600 14px/1.2 var(--tp-font);color:var(--tp-muted)}
.tp-task__other{display:flex;align-items:center;gap:8px}
.tp-task__save{flex:none;width:auto;min-height:44px;padding:0 16px;font-size:15px}
.tp-task__err{font-size:13px;line-height:1.35;color:var(--tp-danger);padding:2px 0 6px}
.tp-case__pane>.tp-task__err{padding:0 6px}
.tp-task__err.is-info{color:var(--tp-muted)}
/* the full-width "Review N overdue tasks" */
.tp-review{display:flex;align-items:center;gap:10px;width:100%;min-height:52px;padding:0 16px;border:0;border-radius:var(--tp-radius);background:var(--tp-accent-soft);color:var(--tp-on-accent-soft);font:600 15.5px/1.2 var(--tp-font);text-align:left}
.tp-review>span{flex:1;min-width:0}
.tp-review[aria-disabled="true"]{opacity:.75}
/* the inline clean-up card */
.tp-cl{display:flex;flex-direction:column;gap:12px;padding:14px 14px 10px;border-radius:var(--tp-radius);background:var(--tp-surface-raised);border:1px solid var(--tp-line);box-shadow:var(--tp-shadow-card)}
.tp-cl__head{display:flex;flex-direction:column;gap:2px}
.tp-cl__kick{display:inline-flex;align-items:center;gap:6px;font:600 13px/1.2 var(--tp-font);color:var(--tp-accent-strong)}
.tp-cl h2{font-size:19px;font-weight:650;line-height:1.25}
.tp-cl__fallback{font-size:13.5px;line-height:1.4;padding:9px 11px;border-radius:var(--tp-radius-sm);background:var(--tp-warn-soft);color:var(--tp-warn);border:1px solid var(--tp-warn-line)}
.tp-cl__lines{list-style:none;margin:0;padding:0;display:flex;flex-direction:column}
.tp-cl__line{display:flex;flex-direction:column;gap:8px;padding:12px 0;border-top:1px solid var(--tp-line)}
.tp-cl__line:first-child{border-top:0;padding-top:2px}
.tp-cl__line.is-off .tp-cl__text,.tp-cl__line.is-off .tp-cl__sub{opacity:.55}
.tp-cl__top{display:flex;align-items:flex-start;gap:4px}
.tp-cl__tick{flex:none;width:44px;height:44px;margin-left:-10px;padding:0;border:0;background:transparent;display:grid;place-items:center}
.tp-cl__box{width:24px;height:24px;border-radius:7px;border:2px solid var(--tp-muted);box-sizing:border-box;display:grid;place-items:center}
.tp-cl__box.is-on{background:var(--tp-accent);border-color:var(--tp-accent);color:var(--tp-on-accent)}
.tp-cl__text{flex:1;min-width:0;padding-top:11px;font:500 15px/1.4 var(--tp-font);display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;line-clamp:2;overflow:hidden;overflow-wrap:anywhere}
.tp-cl__seg{display:flex;width:100%;box-sizing:border-box}
.tp-cl__seg button{flex:1 1 0;min-height:44px;padding:0 6px;font-size:14.5px}
.tp-cl__seg button[aria-pressed="true"]{background:var(--tp-accent);color:var(--tp-on-accent);box-shadow:none}
.tp-cl__sub{font-size:14px;line-height:1.4;color:var(--tp-muted);overflow-wrap:anywhere}
.tp-cl__sub b{font-weight:600;color:var(--tp-text)}
.tp-cl__sub--field{display:flex;align-items:center;gap:10px}
.tp-cl__sub--field select{flex:1 1 auto;min-width:0}
.tp-cl__datewrap{position:relative;display:inline-flex}
.tp-cl__datetext{display:inline-flex;align-items:center;min-height:44px;padding:0 16px;border-radius:var(--tp-radius-pill);background:var(--tp-accent-soft);color:var(--tp-on-accent-soft);font-weight:600;font-size:14.5px}
.tp-cl__date{position:absolute;inset:0;width:100%;height:100%;min-height:44px;opacity:0;padding:0;cursor:pointer}
.tp-cl__foot{display:flex;flex-direction:column;align-items:stretch;gap:2px;padding-top:2px}
.tp-cl__foot .tp-btn--text{align-self:center}
.tp-cl__foot .tp-btn--primary[aria-disabled="true"]{opacity:.45}
.tp-cl__banner{display:flex;align-items:center;gap:10px;min-height:52px;padding:6px 8px 6px 14px;border-radius:var(--tp-radius);background:var(--tp-ok-soft);color:var(--tp-ok);font:600 15px/1.25 var(--tp-font)}
.tp-cl__banner.is-quiet{background:var(--tp-surface-2);color:var(--tp-muted)}
.tp-cl__bannertext{flex:1;min-width:0;display:flex;flex-direction:column}
.tp-cl__bannertext small{font:500 12.5px/1.35 var(--tp-font);color:var(--tp-muted)}
.tp-cl__undo{flex:none;min-height:44px;min-width:44px;padding:0 14px;border:0;border-radius:var(--tp-radius-pill);background:transparent;color:var(--tp-ok);font:700 15px/1.2 var(--tp-font);text-decoration:underline;text-underline-offset:3px}
.tp-cl__undo[disabled]{opacity:.5}
.tp-hint.is-draft{align-items:flex-start;line-height:1.35}
.tp-hint.is-draft svg{flex:none;margin-top:1px}
/* glass look — the same crystal / field recipes the rest of the app uses */
.tp-app[data-look="glass"] .tp-review{background:var(--gl-crystal);color:var(--gl-crystal-text);box-shadow:var(--gl-crystal-shadow)}
.tp-app[data-look="glass"] .tp-review:active{background:var(--gl-crystal-press)}
.tp-app[data-look="glass"] .tp-task__input{background:var(--gl-field);border-color:var(--gl-field-line);box-shadow:var(--gl-field-inset)}
.tp-app[data-look="glass"] .tp-task__input:focus{border-color:var(--tp-accent);box-shadow:var(--gl-field-inset),var(--tp-focus);outline:none}
.tp-app[data-look="glass"] .tp-task__panel{background:var(--tp-surface-3);box-shadow:var(--gl-recess)}
.tp-app[data-look="glass"] .tp-task__act--ai{color:var(--gl-crystal-text)}
.tp-app[data-look="glass"] .tp-task__act[aria-expanded="true"]{box-shadow:inset 0 0 0 2px var(--tp-accent),var(--gl-crystal-shadow)}
.tp-app[data-look="glass"] .tp-cl{background:var(--tp-surface-raised);border-color:var(--gl-border);box-shadow:var(--tp-shadow-card);-webkit-backdrop-filter:var(--gl-card-blur);backdrop-filter:var(--gl-card-blur)}
.tp-app[data-look="glass"][data-scheme="dark"] .tp-cl{border-color:rgba(255,255,255,.08)}
.tp-app[data-look="glass"] .tp-cl__seg button[aria-pressed="true"]{background:var(--tp-accent);color:var(--tp-on-accent);box-shadow:none}
.tp-app[data-look="glass"] .tp-task.is-just-done{background:var(--tp-ok-soft)}
.tp-app[data-look="glass"] .tp-task__group--retired .tp-rows{background:var(--tp-surface-2)}
/* ═══ end workable tasks ═══ */

/* ── read cards (Pilot PR A): what Pilot looked up. Not proposals: no Apply, nothing to undo. dashboard/pilot/reads.js ── */
.tp-read{margin:4px 0 0;padding:12px 14px 10px;border:1px solid var(--tp-line);border-radius:var(--tp-radius);background:var(--tp-surface-raised);box-shadow:var(--tp-shadow-card);min-width:0}
.tp-read__title{font-size:15px;font-weight:650;line-height:1.3;margin:0 0 6px;overflow-wrap:anywhere}
.tp-read__rows{list-style:none;margin:0;padding:0}
.tp-read__row{border-top:1px solid var(--tp-line);min-width:0}
.tp-read__row:first-child{border-top:0}
.tp-read__open,.tp-read__plain{display:flex;align-items:center;gap:8px;min-height:44px;width:100%;padding:6px 0;border:0;background:transparent;color:var(--tp-text);text-align:left;text-decoration:none;font:inherit}
.tp-read__open{cursor:pointer}
.tp-read__main{flex:1 1 auto;min-width:0;display:flex;flex-direction:column;gap:1px}
.tp-read__rt{display:block;font-size:15px;font-weight:600;line-height:1.3;overflow-wrap:anywhere}
.tp-read__rm{display:block;font-size:13px;line-height:1.3;color:var(--tp-faint);overflow-wrap:anywhere}
.tp-read__go{flex:none;color:var(--tp-accent-strong);font-size:18px;padding-left:4px}
.tp-read__fields{margin:0 0 6px;display:flex;flex-direction:column;gap:2px}
.tp-read__field{display:grid;grid-template-columns:auto 1fr;gap:2px 10px;font-size:13.5px;line-height:1.35}
.tp-read__field dt{color:var(--tp-muted)}
.tp-read__field dd{margin:0;display:flex;align-items:center;gap:8px;min-width:0;overflow-wrap:anywhere}
.tp-read__copy{flex:none;min-height:44px;padding:0 10px;border-radius:var(--tp-radius-pill);border:1px solid var(--tp-line-strong);background:transparent;color:var(--tp-accent-strong);font-size:12.5px;font-weight:600}
.tp-read__more,.tp-read__note{margin:6px 0 0;font-size:13px;line-height:1.35;color:var(--tp-faint)}
.tp-read__links{display:flex;flex-wrap:wrap;gap:6px 14px;margin-top:6px}
.tp-read__link{display:inline-flex;align-items:center;min-height:44px;color:var(--tp-accent-strong);font-size:14px;font-weight:600;text-decoration:none}

/* ── found emails (07.10, her ask: "Tap opens + Draft reply"): the link in an answer, the offer buttons under it, the full-screen
   reader and the tappable Case rows. dashboard/pilot/mailrefs.js · mail.js · case.js. Ink tokens only: no literal colour below. ── */
/* the link in an answer: an inline button that reads as a link; the hit area is a full 44px through the same ::after overlay the case chips use */
.tp-maillink{display:inline;position:relative;border:0;margin:0;padding:0;background:transparent;font:inherit;line-height:inherit;color:var(--tp-text);text-align:inherit;text-decoration:underline;text-decoration-thickness:1.5px;text-decoration-color:var(--tp-line-strong);text-underline-offset:3px;overflow-wrap:anywhere;cursor:pointer;border-radius:4px}
.tp-maillink:active{background:var(--tp-surface-2)}
.tp-maillink::after{content:"";position:absolute;left:-2px;right:-2px;top:50%;height:44px;transform:translateY(-50%)}
/* "Draft reply to X" / "Open TR0004" under the latest answer */
.tp-offers{display:flex;flex-wrap:wrap;gap:8px;margin:8px 0 0}
.tp-offers .tp-chip{min-height:44px;padding:0 16px;font-weight:600}
/* a Case row that opens something: a real button, a chevron at the end */
.tp-row--go{cursor:pointer;font:inherit}
.tp-row--go:active{background:var(--tp-surface-2)}
.tp-row--go>svg:last-child{flex:none;color:var(--tp-faint)}
/* the reader layer sits over the whole app frame; below the privacy cover (90) */
.tp-layer{position:absolute;inset:0;z-index:40;display:flex;flex-direction:column;padding-top:var(--tp-sb-h);background:var(--tp-bg);color:var(--tp-text);min-height:0}
/* ── the full-screen PDF / photo viewer (dashboard/pilot/viewer.js, M2). Look from the approved mock (OVK.pdf). z-index 50: above the reader (40), below the privacy cover (90). ── */
.tp-viewer{z-index:50;background:#1d1f21}
.pv{flex:1 1 auto;min-height:0;display:flex;flex-direction:column;background:#1d1f21;color:#F6F5F2}
.pv__top{flex:none;display:flex;align-items:center;gap:4px;min-height:52px;padding:4px;background:#1d1f21;border-bottom:1px solid rgba(246,245,242,.14)}
.pv__x{flex:none;width:44px;height:44px;border:0;border-radius:50%;background:transparent;color:#F6F5F2;display:grid;place-items:center}
.pv__x:active{background:rgba(246,245,242,.14)}
.pv__name{flex:1 1 auto;min-width:0;display:flex;justify-content:center;font-size:15px;font-weight:600;line-height:1.25}
.pv__name .tp-fn{justify-content:center}
.pv__count{flex:none;min-width:56px;width:auto;text-align:center;font:500 12.5px/1 var(--tp-font-mono);color:#C4C1B9;white-space:nowrap}
.pv__scroll{position:relative;flex:1 1 auto;min-height:0;overflow:auto;overscroll-behavior:contain;-webkit-overflow-scrolling:touch;background:#1d1f21;scrollbar-width:none;touch-action:pan-x pan-y;-webkit-user-select:none;user-select:none;-webkit-touch-callout:none}
.pv__scroll::-webkit-scrollbar{display:none}
.pv__stack{box-sizing:border-box;display:flex;flex-direction:column;gap:12px;padding:12px;width:calc(var(--pv-zoom,1) * 100% - (var(--pv-zoom,1) - 1) * 24px)}
.pv__sheet{position:relative;flex:none;width:100%;aspect-ratio:var(--pv-ar,.7071);background:#fff;border-radius:2px;overflow:hidden;box-shadow:0 1px 4px rgba(0,0,0,.55);touch-action:pan-x pan-y;-webkit-user-select:none;user-select:none;-webkit-touch-callout:none}
.pv__sheet canvas{display:block;width:100%;height:100%}
.pv__sheet.is-failed::after{content:"This page could not be drawn.";position:absolute;inset:0;display:grid;place-items:center;padding:16px;text-align:center;font-size:13px;color:#5a5852}
.pv__img{display:block;width:100%;height:auto;border-radius:2px;background:#fff;-webkit-user-drag:none;touch-action:pan-x pan-y}
.pv__msg{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:14px;min-height:100%;padding:32px 28px;text-align:center;color:#F6F5F2}
.pv__msg p{margin:0;font-size:15px;line-height:1.45;max-width:30ch}
.pv__msg>svg{color:#C4C1B9}
.pv__b.pv__retry{flex:none;min-width:160px}
.pv__sheet--skel{width:56%;max-width:220px;display:flex;flex-direction:column;gap:10px;padding:18px 16px;box-shadow:none}
.pv__sheet--skel i{display:block;height:9px;border-radius:5px;background:#e3e1db}
.pv__sheet--skel i:nth-child(2){width:80%}.pv__sheet--skel i:nth-child(3){width:92%}.pv__sheet--skel i:nth-child(4){width:60%}
@media (prefers-reduced-motion:no-preference){.pv__sheet--skel i{animation:pvPulse 1.4s ease-in-out infinite}@keyframes pvPulse{50%{opacity:.45}}}
.pv__bar{flex:none;display:flex;flex-direction:column;gap:6px;padding:8px 12px calc(10px + var(--tp-safe-b));background:#161718;border-top:1px solid rgba(246,245,242,.14);color:#F6F5F2}
.pv__path{margin:0;display:flex;align-items:center;gap:6px;min-width:0;font-size:12.5px;line-height:1.3;color:#C4C1B9}
.pv__path svg{flex:none}
.pv__who{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.pv__path .tp-fn{font-family:var(--tp-font-mono);font-size:12px}
.pv__acts{display:flex;gap:8px}
.pv__b{flex:1 1 0;min-width:0;min-height:44px;display:inline-flex;align-items:center;justify-content:center;gap:6px;padding:0 8px;border-radius:999px;border:1px solid rgba(246,245,242,.34);background:transparent;color:#F6F5F2;font-size:14.5px;font-weight:600;white-space:nowrap}
.pv__b:active{background:rgba(246,245,242,.14)}
.ml{flex:1 1 auto;min-height:0;display:flex;flex-direction:column}
.ml__scroll{flex:1 1 auto;padding:14px 16px 20px;display:flex;flex-direction:column;outline:0}
.ml__subject{margin:0 0 12px;font-size:21px;line-height:1.25;font-weight:700;letter-spacing:-.015em;overflow-wrap:break-word}
.ml__case{align-self:flex-start;max-width:100%;min-height:44px;margin:0 0 10px -10px}
.ml__from{display:flex;align-items:center;gap:10px;margin-bottom:8px}
.ml__av{flex:none;width:40px;height:40px;border-radius:50%;background:var(--tp-surface-3);color:var(--tp-text);display:grid;place-items:center;font-size:16px;font-weight:700}
.ml__av.is-you{background:var(--tp-accent);color:var(--tp-on-accent)}
.ml__who{flex:1 1 auto;min-width:0;display:flex;flex-direction:column}
.ml__who b{font-size:15.5px;line-height:1.25;overflow-wrap:anywhere}
.ml__who small{font-size:12.5px;line-height:1.3;color:var(--tp-faint);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.ml__from time{flex:none;text-align:right;font-size:12px;line-height:1.3;color:var(--tp-muted);white-space:nowrap}
.ml__to{margin:0 0 14px;padding-bottom:12px;border-bottom:1px solid var(--tp-line);font-size:13px;color:var(--tp-muted);overflow-wrap:anywhere}
.ml__to span{color:var(--tp-faint);margin-right:4px}
.ml__body{font-size:16px;line-height:1.55;overflow-wrap:break-word}
.ml__body p{margin:0 0 .85em}
.ml__body a,.ml__msg a{color:var(--tp-accent-strong);text-decoration:underline;text-underline-offset:3px;overflow-wrap:anywhere}
.tp-app[data-scheme="dark"] .ml__body a,.tp-app[data-scheme="dark"] .ml__msg a{color:var(--tp-accent)}
.ml__empty,.ml__cut,.ml__older,.ml__saved{margin:0 0 .85em;font-size:13.5px;line-height:1.4;color:var(--tp-faint)}
.ml__saved{display:flex;align-items:center;gap:6px;margin:0 0 10px;color:var(--tp-muted)}
.ml__older{margin:12px 0 0}
.ml__atts{display:flex;flex-direction:column;gap:8px;margin:10px 0 4px}
.ml__att{display:flex;align-items:center;gap:12px;width:100%;min-height:56px;padding:8px 12px;border-radius:14px;border:1px solid var(--tp-line-strong);background:var(--tp-surface);color:var(--tp-text);text-align:left}
.ml__att>svg{flex:none;color:var(--tp-muted)}
.ml__attn{flex:1 1 auto;min-width:0;display:flex;flex-direction:column;gap:2px}
.ml__attn .tp-fn{font-size:14.5px;font-weight:600;overflow-wrap:anywhere}
.ml__attn small{font-size:12.5px;color:var(--tp-faint)}
.ml__earlier{align-self:flex-start;display:inline-flex;align-items:center;gap:6px;min-height:44px;margin:8px 0 0;padding:0 12px 0 8px;border:0;border-radius:12px;background:var(--tp-surface-2);color:var(--tp-text);font-size:14.5px;font-weight:600}
.ml__thread{display:flex;flex-direction:column;margin-top:10px;border-top:1px solid var(--tp-line)}
.ml__msg{padding:14px 0;border-bottom:1px solid var(--tp-line)}
.ml__msg header{display:flex;align-items:center;gap:10px;margin-bottom:8px}
.ml__msg header div{min-width:0}
.ml__msg header b{display:block;font-size:15px;overflow-wrap:anywhere}
.ml__msg header small{display:block;font-size:12.5px;color:var(--tp-faint);overflow-wrap:anywhere}
.ml__msg p{margin:0 0 .7em;font-size:15.5px;line-height:1.55;overflow-wrap:break-word}
.ml__msg .ml__cut{font-size:13.5px}
.ml__msg--you{margin:14px -16px 0;padding:14px 16px;border:0;background:var(--tp-surface-2)}
.ml__end{flex:none;height:4px}
.ml__bar{flex:none;display:flex;flex-direction:column;gap:8px;padding:10px 12px calc(10px + var(--tp-safe-b));background:var(--tp-bar-bg);border-top:1px solid var(--tp-line)}
.ml__bar:empty{display:none}
.ml__btns{display:flex;gap:8px}
.ml__btns .tp-btn{flex:1 1 auto;width:auto;min-width:0;min-height:48px;padding:0 10px;font-size:15px;white-space:nowrap;overflow:hidden}
.ml__btns .tp-btn svg{flex:none}
.ml__note,.ml__runnote{margin:0;font-size:13.5px;line-height:1.35;color:var(--tp-muted)}
.ml__run{display:flex;flex-direction:column;gap:8px;padding:2px 2px 0}
.ml__runh{display:flex;align-items:center;gap:8px;font-size:15px}
.ml__runh b{flex:1 1 auto;font-weight:650}
.ml__cancel{min-height:44px}
.ml__run .tp-steps__list{margin:0}
.ml__run .tp-steps__row span{white-space:normal;overflow:visible}
.ml__err{display:flex;align-items:flex-start;gap:10px;margin:6px 0 14px;padding:12px 14px;border-radius:var(--tp-radius-sm);background:var(--tp-surface-2);color:var(--tp-text)}
.ml__err svg{flex:none;margin-top:2px;color:var(--tp-danger)}
.ml__err p{margin:0;font-size:15px;line-height:1.4}
.ml__retry{align-self:stretch;min-height:48px}
.ml__skel{display:flex;flex-direction:column;gap:12px}
.ml__bone{height:14px;border-radius:7px;background:var(--tp-surface-3)}
.ml__bone--h{height:26px;width:78%}
.ml__bone--from{height:40px;width:55%;border-radius:20px}
.ml__bone--short{width:62%}

/* ── 12.10 Doc Scanner (scan.js, cards.js scan header) — appended at the END of the file so a parallel edit higher up never clashes ── */
.tp-addrow{display:flex;gap:8px}
.tp-addrow .tp-addfiles{flex:1 1 0;width:auto;min-width:0}
.tp-addrow .tp-addscan{flex:0 0 auto;min-height:var(--tp-h-primary);padding:0 22px}
.tp-row[disabled]{opacity:.5;pointer-events:none}
.tp-cam__alt{margin:14px 4px 6px;text-align:center}
.tp-cam__alt .tp-link{min-height:44px;padding:0 12px;background:transparent;border:0;font-size:15px;color:var(--tp-accent-strong);text-decoration:underline}
.tp-app[data-scheme="dark"] .tp-cam__alt .tp-link{color:var(--tp-accent)}
.tp-scan{position:fixed;inset:0;z-index:60;display:flex;flex-direction:column;background:var(--tp-ink);color:var(--tp-paper);padding-top:env(safe-area-inset-top)}
.tp-scan__top{flex:none;display:flex;align-items:center;justify-content:space-between;gap:12px;min-height:52px;padding:0 6px 0 18px}
.tp-scan__title{font-weight:650;font-size:16px}
.tp-scan__close{flex:none;width:48px;height:48px;border:0;border-radius:50%;background:transparent;color:var(--tp-paper);display:grid;place-items:center}
.tp-scan__stage{position:relative;flex:1 1 auto;min-height:0;overflow:hidden;display:flex;align-items:center;justify-content:center}
.tp-scan__video{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;background:var(--tp-ink)}
.tp-scan__frame{position:absolute;top:5%;bottom:5%;left:50%;aspect-ratio:210/297;max-width:92%;transform:translateX(-50%);border:2px solid var(--tp-paper);border-radius:10px;box-shadow:0 0 0 100vmax color-mix(in srgb, var(--tp-ink) 45%, transparent);pointer-events:none}
.tp-scan__hint{position:absolute;left:16px;right:16px;bottom:10px;margin:0;text-align:center;font-size:14px;line-height:1.35;color:var(--tp-paper);text-shadow:0 1px 3px color-mix(in srgb, var(--tp-ink) 85%, transparent)}
.tp-scan[data-mode="review"] .tp-scan__frame,.tp-scan[data-mode="review"] .tp-scan__hint,.tp-scan[data-mode="fallback"] .tp-scan__frame{display:none}
.tp-scan[data-mode="fallback"] .tp-scan__video{display:none}
.tp-scan__review{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;gap:12px;padding:12px 16px;background:var(--tp-ink)}
.tp-scan__review:empty{display:none}
.tp-scan__review img{flex:1 1 auto;min-height:0;max-width:100%;object-fit:contain;border-radius:8px;background:var(--tp-surface-3)}
.tp-scan__revbtns{flex:none;display:flex;gap:8px;justify-content:center;flex-wrap:wrap}
.tp-scan__fallback{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:12px;padding:24px;text-align:center;background:var(--tp-ink)}
.tp-scan__fallback[hidden]{display:none}
.tp-scan__fallback h2{font-size:20px;color:var(--tp-paper)}
.tp-scan__fallback p{margin:0;font-size:15.5px;line-height:1.4;color:var(--tp-paper);opacity:.85}
.tp-scan__fallback .tp-btn--primary{background:var(--tp-paper);color:var(--tp-ink);width:auto;min-width:220px}
.tp-app[data-look] .tp-scan .tp-scan__fallback .tp-btn--primary{background:var(--tp-paper);color:var(--tp-ink);box-shadow:none;text-shadow:none;border:0;min-height:var(--tp-h-primary)}  /* a real fill: the glass look's primary rule otherwise leaves ink on ink (review 12.10) */
.tp-scan[data-mode="fallback"] .tp-scan__shutter{visibility:hidden}  /* no camera: the shutter is not offered (the button in the middle does the job) */
.tp-scan__note{flex:none;margin:0;padding:8px 18px;text-align:center;font-size:14.5px;line-height:1.35;font-weight:600;color:var(--tp-paper);background:color-mix(in srgb, var(--tp-paper) 14%, var(--tp-ink))}  /* round 2: the refusal note, visible in the camera, the review panel and the no-camera screen */
.tp-scan__note[hidden]{display:none}
.tp-app .tp-scan .tp-btn--text,.tp-app[data-scheme="dark"] .tp-scan .tp-btn--text{color:var(--tp-paper);text-decoration:underline;text-underline-offset:3px}  /* round 2: Back is a text button on the ink panel — the app's accent text colour was ink on ink in light mode */
.tp-app[data-look="glass"] .tp-scan .tp-btn--text:active{background:color-mix(in srgb, var(--tp-paper) 16%, transparent)}
.tp-scan__strip{flex:none;display:flex;gap:8px;align-items:center;overflow-x:auto;min-height:72px;padding:8px 14px;-webkit-overflow-scrolling:touch;scrollbar-width:none}
.tp-scan__strip::-webkit-scrollbar{display:none}
.tp-scan__empty{margin:0 auto;font-size:14px;color:var(--tp-paper);opacity:.7}
.tp-scan__thumb{position:relative;flex:none;width:56px;height:56px;border:2px solid transparent;border-radius:8px;padding:0;overflow:hidden;background:var(--tp-surface-3);color:var(--tp-ink);display:grid;place-items:center}
.tp-scan__thumb img{width:100%;height:100%;object-fit:cover;display:block}
.tp-scan__thumb.is-on{border-color:var(--tp-paper)}
.tp-scan__thumb.is-retake{border-color:var(--tp-danger-soft);opacity:.65}
.tp-scan__num{position:absolute;right:3px;bottom:3px;min-width:18px;height:18px;padding:0 4px;border-radius:9px;background:var(--tp-ink);color:var(--tp-paper);font-size:11.5px;font-weight:650;line-height:18px;text-align:center}
.tp-scan__bar{flex:none;display:grid;grid-template-columns:minmax(0,1fr) auto minmax(max-content,1fr);align-items:center;gap:12px;padding:8px 18px calc(14px + env(safe-area-inset-bottom))}
.tp-scan__shutter{flex:none;width:72px;height:72px;border-radius:50%;border:4px solid var(--tp-paper);background:transparent;padding:0;display:grid;place-items:center}
.tp-scan__shutter span{display:block;width:54px;height:54px;border-radius:50%;background:var(--tp-paper)}
.tp-scan__shutter:active span{transform:scale(.9)}
.tp-scan__shutter:disabled{opacity:.4}
.tp-scan__done{justify-self:end;width:auto;min-width:112px;padding:0 16px;white-space:nowrap;background:var(--tp-paper);color:var(--tp-ink)}
.tp-app[data-look] .tp-scan .tp-scan__done{background:var(--tp-paper);color:var(--tp-ink);box-shadow:none;text-shadow:none}  /* beats the glass look's primary fill: ink-on-ink in light mode */
.tp-scan__done:disabled{opacity:.45}
.tp-scan :focus-visible{outline:none;box-shadow:0 0 0 3px color-mix(in srgb, var(--tp-paper) 60%, transparent)}
.tp-scancard{display:flex;flex-direction:column;gap:8px;margin:0 0 12px;padding:12px;border-radius:var(--tp-radius-sm);background:var(--tp-surface-2)}
.tp-scancard__top{display:flex;align-items:center;gap:10px}
.tp-scancard__pdf{flex:none;width:40px;height:40px;border-radius:10px;display:grid;place-items:center;background:var(--tp-surface-3);color:var(--tp-muted)}
.tp-scancard__main{flex:1;min-width:0;display:flex;flex-direction:column;gap:1px}
.tp-scancard__line{font-size:15.5px;font-weight:650;line-height:1.3;overflow-wrap:anywhere}
.tp-scancard__sub{font-size:13px;line-height:1.3;color:var(--tp-faint);overflow-wrap:anywhere}
.tp-scancard__pill{flex:none;align-self:flex-start;padding:3px 10px;border-radius:var(--tp-radius-pill);font-size:12.5px;font-weight:650;line-height:1.4;background:var(--tp-accent-soft);color:var(--tp-on-accent-soft);white-space:nowrap}
.tp-scancard__pill.is-ambiguous,.tp-scancard__pill.is-probably{background:var(--tp-warn-soft);color:var(--tp-text);box-shadow:inset 0 0 0 1px var(--tp-warn-line)}
.tp-scancard__pill.is-sure,.tp-scancard__pill.is-created{background:var(--tp-ok-soft);color:var(--tp-ok)}
.tp-scancard__pill.is-none{background:var(--tp-surface-3);color:var(--tp-muted)}
.tp-scancard__why b{font-weight:650;color:var(--tp-text)}
.tp-scancard__chips{display:flex;flex-wrap:wrap;gap:8px}
.tp-scancard .tp-rows{background:var(--tp-surface-raised)}
.tp-scancard .sc-routes .tp-row__meta{overflow-wrap:anywhere;white-space:normal}
.sc-ambrow[aria-pressed="true"]{background:var(--tp-accent-soft)}
.sc-ambrow[aria-pressed="true"] .tp-row__icon{background:var(--tp-accent);color:var(--tp-on-accent)}
.tp-scancard .tp-row__chev{flex:none;color:var(--tp-faint);display:grid;place-items:center}
@keyframes tp-flash{0%{box-shadow:0 0 0 3px var(--tp-accent)}100%{box-shadow:0 0 0 0 transparent}}
.tp-card.is-flash{animation:tp-flash 1.6s ease-out 1}
@media (prefers-reduced-motion:reduce){.tp-card.is-flash{animation:none;outline:2px solid var(--tp-accent)}}
.tp-scancard__why{margin:0;font-size:14px;line-height:1.4;color:var(--tp-muted)}
.tp-scancard__bad{display:flex;align-items:center;gap:8px;margin:0;font-size:14px;line-height:1.35;color:var(--tp-danger)}
.tp-scancard__bad svg{flex:none}
.tp-scancard__bad span{flex:1;min-width:0}
.tp-scancard__retake{min-height:44px}
.tp-scancard__open{display:inline-flex;align-items:center;gap:8px;min-height:44px;margin:0;font-size:15px;font-weight:600;color:var(--tp-accent-strong);text-decoration:underline}
.tp-app[data-scheme="dark"] .tp-scancard__open{color:var(--tp-accent)}
.tp-scancard__open.is-laptop{text-decoration:none;font-weight:500;color:var(--tp-muted)}
.tp-card__fwhere b.tp-card__nocase,.tp-app[data-scheme="dark"] .tp-card__fwhere b.tp-card__nocase{font-family:inherit;font-weight:400;color:var(--tp-muted)}
/* a file row that opens in the viewer, and the plain "open this on the laptop" row beside it */
button.ml__att{font:inherit;cursor:pointer}
button.ml__att>svg:last-child{margin-left:auto;color:var(--tp-faint)}
.ml__att--plain{border-style:dashed;background:transparent}
.ml__att--plain .ml__attn small{color:var(--tp-muted)}
