/* Ticketing — ported from the design handoff (ui_kits/ticketing/source/ticket.css).
 *
 * Only what design/styles.css and design/portal-overrides.css do not already
 * cover. Semantic tokens throughout, no raw hex — every value resolves from the
 * live token layer, which is what lets this sit on the existing shell without
 * restyling anything it did not add.
 *
 * Two blocks from the source are deliberately NOT here:
 *   * `.rev*`, the dark design-review strip. The handoff marks it as
 *     scaffolding for switching form density and health state during review.
 *   * the `.tkt-chat` / `.tkt-welcome` / `.tkt-ask` group, which restyles the
 *     Ask SARA home page. That page is a RECONSTRUCTION in the prototype,
 *     present only so the status pill sits in real context; the live one is
 *     already built and shipping these rules would restyle it to match a mockup
 *     of itself.
 *
 * Everything else is ported as written. Where the prototype and the live portal
 * disagree on shell details, the live portal wins — the handoff says so, and it
 * is the reason the kit was built on the portal's own classes.
 */

/* ---------- status pill: the popover's ticketing actions ---------- */
.service-status-toggle{font:var(--type-caption);font-weight:var(--weight-semibold);cursor:pointer}
.tkt-scrim{position:fixed;inset:0;z-index:50}
.tkt-new{overflow:hidden}
.tkt-new .sa-nav__text{flex:0 1 auto;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.service-status-popover{z-index:71}
.tkt-callout{display:flex;gap:var(--space-4);align-items:flex-start;padding:var(--space-4) var(--space-5);border:1px solid;border-radius:var(--radius-sm);font:var(--type-caption)}
.tkt-callout i{flex:none;font-size:var(--icon-sm);margin-top:1px}
.tkt-callout>div{display:flex;flex-direction:column;gap:2px;min-width:0}
.tkt-callout b{font:var(--type-label)}
.tkt-popacts{display:flex;flex-direction:column;gap:1px;padding-top:var(--space-4);border-top:1px solid var(--border-subtle);margin:0 calc(var(--space-3) * -1) calc(var(--space-3) * -1)}
.tkt-popact{display:flex;align-items:center;gap:var(--space-4);width:100%;padding:var(--space-4) var(--space-4);border:0;background:transparent;border-radius:var(--radius-sm);font:var(--type-label);color:var(--text-primary);cursor:pointer;text-align:left}
.tkt-popact:hover{background:var(--surface-hover)}
.tkt-popact i{color:var(--text-tertiary);font-size:var(--icon-md);flex:none}
.tkt-popact--primary{color:var(--ember-700)}
.tkt-popact--primary i{color:var(--ember-600)}
.tkt-popact__cnt{margin-left:auto;font:var(--type-mono-xs);color:var(--text-tertiary)}

/* ---------- page furniture ---------- */
.tkt-section{max-width:900px}
.tkt-head{display:flex;flex-direction:column;gap:var(--space-3);align-items:flex-start}
.tkt-head--row{flex-direction:row;align-items:flex-end;gap:var(--space-6);flex-wrap:wrap}
.tkt-head--row>button{margin-left:auto}
.tkt-h1{font-family:var(--font-display);font-size:var(--text-2xl);font-weight:var(--weight-semibold);letter-spacing:var(--tracking-snug);color:var(--text-primary);line-height:var(--leading-tight)}
.tkt-h2{font-family:var(--font-display);font-size:var(--text-xl);font-weight:var(--weight-semibold);letter-spacing:var(--tracking-snug);color:var(--text-primary);line-height:var(--leading-snug)}
.tkt-sub{font:var(--type-body-sm);color:var(--text-secondary);max-width:var(--measure-prose)}
.tkt-overline{font:var(--type-overline);text-transform:uppercase;letter-spacing:var(--tracking-caps);color:var(--text-tertiary)}
.tkt-mono{font:var(--type-mono-xs);color:var(--text-tertiary)}
.tkt-tags{display:flex;align-items:center;gap:var(--space-4);flex-wrap:wrap}
.tkt-ref{font:var(--type-mono-xs);color:var(--text-secondary);background:var(--surface-sunken);border:1px solid var(--border-subtle);border-radius:var(--radius-xs);padding:1px var(--space-3);white-space:nowrap}
.tkt-prio{display:inline-flex;align-items:center;gap:var(--space-3);font:var(--type-overline);text-transform:uppercase;letter-spacing:var(--tracking-caps);color:var(--text-tertiary)}
.tkt-prio i{width:6px;height:6px;border-radius:var(--radius-pill);background:currentColor;display:block}
.tkt-prio--low{color:var(--text-tertiary)}
.tkt-prio--normal{color:var(--verdigris-600)}
.tkt-prio--high{color:var(--ember-600)}
.tkt-prio--urgent{color:var(--status-danger-fg)}
.tkt-stack{display:flex;flex-direction:column;gap:var(--space-6)}
.tkt-two{display:grid;grid-template-columns:1fr 300px;gap:var(--space-8);align-items:start}
.tkt-hint{font:var(--type-caption);color:var(--text-tertiary)}
.tkt-none{padding:var(--space-9);text-align:center;font:var(--type-body-sm);color:var(--text-tertiary)}

/* ---------- report form ---------- */
.tkt-num{flex:none;width:24px;height:24px;border-radius:var(--radius-pill);background:var(--action-primary-bg);color:var(--action-primary-fg);display:flex;align-items:center;justify-content:center;font:var(--type-mono-xs);font-weight:var(--weight-semibold)}
.tkt-cats{display:grid;grid-template-columns:1fr 1fr;gap:var(--space-4)}
.tkt-cats--tight{grid-template-columns:repeat(3,1fr)}
.tkt-cat{display:flex;gap:var(--space-4);padding:var(--space-5);border:1px solid var(--border-default);border-radius:var(--radius-sm);background:var(--surface-card);cursor:pointer;text-align:left;transition:border-color var(--duration-fast) var(--ease-standard),background var(--duration-fast) var(--ease-standard)}
.tkt-cat:hover{border-color:var(--border-strong);background:var(--surface-hover)}
.tkt-cat.is-selected{border-color:var(--ember-400);background:var(--surface-selected)}
.tkt-cat i{flex:none;font-size:var(--icon-md);color:var(--text-tertiary);margin-top:1px}
.tkt-cat.is-selected i{color:var(--ember-600)}
.tkt-cat__body{display:flex;flex-direction:column;gap:2px;min-width:0}
.tkt-cat__t{font:var(--type-label);color:var(--text-primary)}
.tkt-cat__d{font:var(--type-caption);color:var(--text-tertiary)}
.tkt-cats--tight .tkt-cat__d{display:none}
.tkt-route{display:flex;align-items:center;gap:var(--space-3);margin-top:var(--space-5);font:var(--type-caption);color:var(--text-secondary)}
.tkt-route i{color:var(--text-tertiary);font-size:var(--icon-sm)}
.tkt-route b{color:var(--text-primary);font-weight:var(--weight-semibold)}
.tkt-area{min-height:110px}
.tkt-tags{display:flex;gap:var(--space-3);flex-wrap:wrap}
.tkt-ctx__head{display:flex;align-items:center;gap:var(--space-4);font:var(--type-label);color:var(--text-primary)}
.tkt-ctx__head i{color:var(--text-tertiary);font-size:var(--icon-sm)}
.tkt-ctx__head button{margin-left:auto;font:var(--type-caption)}
.tkt-dl{display:grid;grid-template-columns:auto 1fr;gap:var(--space-3) var(--space-5);margin-top:var(--space-5)}
.tkt-dl dt{font:var(--type-overline);text-transform:uppercase;letter-spacing:var(--tracking-caps);color:var(--text-tertiary);padding-top:2px}
.tkt-dl dd{margin:0;font:var(--type-mono-xs);color:var(--text-secondary);overflow-wrap:anywhere}
.tkt-dl--plain dd{font:var(--type-caption)}
.tkt-submit{display:flex;align-items:center;gap:var(--space-5);flex-wrap:wrap}
.tkt-submit__note{font:var(--type-caption);color:var(--text-tertiary);max-width:36ch}

/* The file zone's label and hint. `.sa-file__hint` carries a margin-top but no
   display, so inside an inline wrapper it never breaks and reads as
   "choose a filePNG or JPEG". Fixed HERE, scoped to our own wrapper, rather
   than by adding display:block to the shared component — the handoff is
   explicit that the existing system classes are reused and not restyled, and a
   change there would land on every file input in the portal. */
.tkt-file__label{display:flex;flex-direction:column;min-width:0}

/* ---------- confirmation ---------- */
.tkt-done{text-align:center}
.tkt-done .sa-card__body{display:flex;flex-direction:column;align-items:center;gap:var(--space-5);padding:var(--space-11) var(--space-8)}
.tkt-done__mark{width:42px;height:42px;border-radius:var(--radius-pill);background:var(--status-success-bg);border:1px solid var(--status-success-border);color:var(--status-success-fg);display:flex;align-items:center;justify-content:center;font-size:var(--icon-lg)}
.tkt-done__ref{display:flex;flex-direction:column;align-items:center;gap:var(--space-3);padding:var(--space-5) var(--space-8);border:1px solid var(--border-default);border-radius:var(--radius-sm);background:var(--surface-quiet)}
.tkt-done__r{font-family:var(--font-mono);font-size:var(--text-lg);font-weight:var(--weight-semibold);color:var(--text-primary)}
.tkt-done__next{display:flex;flex-direction:column;gap:var(--space-3);text-align:left;max-width:52ch;margin:0;padding-left:var(--space-6);font:var(--type-body-sm);color:var(--text-secondary)}
.tkt-done__next li::marker{color:var(--ember-600)}
.tkt-done__next b{color:var(--text-primary);font-weight:var(--weight-semibold)}
.tkt-done__acts{display:flex;gap:var(--space-4)}

/* ---------- thread ---------- */
.tkt-thread{display:flex;flex-direction:column;gap:var(--space-6)}
.tkt-msg{display:flex;gap:var(--space-5)}
.tkt-av{width:28px;height:28px;font-size:var(--text-2xs)}
.tkt-av--me{background:var(--surface-selected);border-color:var(--ember-200);color:var(--ember-700)}
.tkt-av--int{background:var(--status-warning-bg);border-color:var(--status-warning-border);color:var(--status-warning-fg)}
.tkt-msg__body{flex:1;min-width:0;padding:var(--space-5) var(--space-6);border:1px solid var(--border-subtle);border-radius:var(--radius-sm);background:var(--surface-quiet)}
.tkt-msg--int .tkt-msg__body{background:var(--status-warning-bg);border-color:var(--status-warning-border);border-style:dashed}
.tkt-msg__head{display:flex;align-items:center;gap:var(--space-4);margin-bottom:var(--space-3)}
.tkt-msg__head b{font:var(--type-label);color:var(--text-primary)}
.tkt-msg__at{margin-left:auto;font:var(--type-mono-xs);color:var(--text-tertiary)}
.tkt-msg__body p{font:var(--type-body-sm);color:var(--text-secondary);margin:0}
.tkt-reply{margin-top:var(--space-7);padding-top:var(--space-6);border-top:1px solid var(--border-subtle)}
.tkt-reply__foot{display:flex;align-items:center;gap:var(--space-4);margin-top:var(--space-4);flex-wrap:wrap}

/* ---------- my tickets rows ---------- */
.tkt-row{display:flex;align-items:center;gap:var(--space-5);width:100%;padding:var(--space-5) var(--space-6);border:0;border-bottom:1px solid var(--border-subtle);background:transparent;cursor:pointer;text-align:left;transition:background var(--duration-fast) var(--ease-standard)}
.tkt-row:last-child{border-bottom:0}
.tkt-row:hover{background:var(--surface-hover)}
.tkt-row__grow{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}
.tkt-row__subj{font:var(--type-label);color:var(--text-primary)}
.tkt-row__meta{font:var(--type-caption);color:var(--text-tertiary)}

/* ---------- support inbox ---------- */
/* The handoff puts `.tkt-fixed` on `.container`. The portal already had a hook
   for a page that manages its own scrolling — `app-main--fixed`, established by
   the data explorer — so that is used instead and these two rules are kept only
   for anyone porting the kit elsewhere. Where the prototype and the live portal
   disagree on shell details, the live portal wins. */
.tkt-fixed{height:100vh;min-height:0;overflow:hidden}
.tkt-fixed .app-main{min-height:0;overflow:hidden}
.tkt-inbox{flex:1;min-height:0;display:grid;grid-template-columns:minmax(300px,360px) 1fr}
.tkt-inbox--focus{grid-template-columns:104px 1fr}
.tkt-list{display:flex;flex-direction:column;min-height:0;border-right:1px solid var(--border-default);background:var(--surface-quiet)}
.tkt-list__filters{flex:none;display:flex;flex-direction:column;gap:var(--space-4);padding:var(--space-5);border-bottom:1px solid var(--border-subtle)}
.tkt-inbox--focus .tkt-list__filters,.tkt-inbox--focus .tkt-list__count{display:none}
.tkt-tabs{display:flex;width:100%}
.tkt-tabs .sa-tab{flex:1;justify-content:center;padding:var(--space-3) var(--space-3)}
.tkt-list__selects{display:grid;grid-template-columns:1fr 1fr;gap:var(--space-3)}
.tkt-list__count{flex:none;padding:var(--space-4) var(--space-6);font:var(--type-overline);text-transform:uppercase;letter-spacing:var(--tracking-caps);color:var(--text-tertiary);border-bottom:1px solid var(--border-subtle)}
.tkt-list__rows{flex:1;min-height:0;overflow-y:auto}
.tkt-ibx{display:flex;gap:var(--space-4);width:100%;padding:var(--space-5) var(--space-6);border:0;border-bottom:1px solid var(--border-subtle);background:transparent;cursor:pointer;text-align:left;transition:background var(--duration-fast) var(--ease-standard)}
.tkt-ibx:hover{background:var(--surface-hover)}
.tkt-ibx.is-selected{background:var(--surface-card);box-shadow:inset 2px 0 0 var(--ember-600)}
.tkt-ibx__prio{flex:none;display:flex;justify-content:center;padding-top:6px}
.tkt-ibx__prio i{width:6px;height:6px;border-radius:var(--radius-pill);background:currentColor;display:block}
.tkt-ibx__grow{flex:1;min-width:0;display:flex;flex-direction:column;gap:var(--space-3)}
.tkt-ibx__top{display:flex;align-items:center;gap:var(--space-3);flex-wrap:wrap}
.tkt-ibx__subj{font:var(--type-label);color:var(--text-primary);display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
.tkt-ibx__meta{display:flex;align-items:center;gap:var(--space-3);font:var(--type-caption);color:var(--text-tertiary)}
.tkt-ibx__who{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.tkt-ibx__age{margin-left:auto;font:var(--type-mono-xs);flex:none}
.tkt-who{width:20px;height:20px;font-size:9px}
.tkt-who--none{border-style:dashed;color:var(--text-tertiary)}
.tkt-inbox--focus .tkt-ibx{flex-direction:column;align-items:center;gap:var(--space-3);padding:var(--space-5) var(--space-3)}
.tkt-inbox--focus .tkt-ibx__subj,.tkt-inbox--focus .tkt-ibx__meta,.tkt-inbox--focus .tkt-ibx__top .sa-badge{display:none}
.tkt-inbox--focus .tkt-ibx__grow{align-items:center}
.tkt-det{min-height:0;overflow-y:auto;padding:var(--space-8) var(--space-9) var(--space-11);display:flex;flex-direction:column;gap:var(--space-6)}
.tkt-det__head{display:flex;flex-direction:column;gap:var(--space-3);padding-bottom:var(--space-6);border-bottom:1px solid var(--border-subtle)}
.tkt-ctrls{display:flex;gap:var(--space-5);flex-wrap:wrap}
.tkt-ctrl{flex:1;min-width:150px;gap:var(--space-3)}
.tkt-det__grid{display:grid;grid-template-columns:1fr 260px;gap:var(--space-8);align-items:start}
.tkt-side{display:flex;flex-direction:column;gap:var(--space-4)}
.tkt-side__name{font:var(--type-label);color:var(--text-primary);margin-top:var(--space-4)}
.tkt-side__org{font:var(--type-caption);color:var(--text-secondary);margin:2px 0 var(--space-3)}
.tkt-acts{display:flex;flex-direction:column;gap:1px;margin:var(--space-4) calc(var(--space-3) * -1) 0}
.tkt-act{display:flex;align-items:center;gap:var(--space-4);width:100%;padding:var(--space-3) var(--space-3);border:0;background:transparent;border-radius:var(--radius-xs);font:var(--type-body-sm);color:var(--text-primary);cursor:pointer;text-align:left}
.tkt-act:hover{background:var(--surface-hover)}
.tkt-act i{color:var(--text-tertiary);font-size:var(--icon-sm);flex:none}
@media (max-width:1200px){.tkt-det__grid,.tkt-two{grid-template-columns:1fr}}
/* One pane at a time. Below 900px the list and a ticket do not fit side by
   side, so the inbox shows the list, a row opens its ticket in the list's
   place (support.js sets `tkt-inbox--ticket` while one is open), and the
   ticket has a way back. Until 2026-10-01 this rule hid the list and the
   script opened the first ticket, so a phone showed one ticket and nothing
   that led to another. The width is also in support.js, onePane(). */
.tkt-det__back{display:none}
@media (max-width:900px){
  .tkt-inbox,.tkt-inbox--focus{grid-template-columns:minmax(0,1fr)}
  .tkt-inbox--ticket .tkt-list{display:none}
  .tkt-inbox:not(.tkt-inbox--ticket) .tkt-det{display:none}
  .tkt-list{border-right:0}
  /* A link is a small thing to hit with a thumb, so this one is given height. */
  .tkt-det__back{display:inline-flex;align-self:flex-start;min-height:var(--control-height-md)}
  .tkt-det{padding:var(--space-5) var(--space-6) var(--space-10);gap:var(--space-5)}
  /* `1fr` alone lets one long line widen the column past the screen. */
  .tkt-det__grid{grid-template-columns:minmax(0,1fr)}
  .tkt-cats,.tkt-cats--tight{grid-template-columns:1fr}
}
/* Between a phone and 900px there is width to spare and, on a phone held
   sideways, little height. The search box and the two filters share a line
   and the tabs take the next, so more of the screen is left for the rows. */
@media (min-width:601px) and (max-width:900px){
  .tkt-list__filters{flex-direction:row;flex-wrap:wrap;align-items:center}
  .tkt-list__filters>.sa-inputwrap{flex:1 1 240px}
  .tkt-list__selects{flex:1 1 300px}
  .tkt-tabs{order:1;flex:1 0 100%}
}
@media (max-width:600px){
  /* Six tabs do not fit one line of a phone: two lines of three. */
  .tkt-tabs{flex-wrap:wrap}
  .tkt-tabs .sa-tab{flex:1 0 30%}
  /* My tickets on a phone: the reference and the status on one line, the
     subject under them at full width. Side by side the subject was left a
     column one word wide. */
  .tkt-row{flex-wrap:wrap}
  .tkt-row__grow{order:1;flex:1 0 100%}
  .tkt-row>i{margin-left:auto}
  /* A message on a phone: the name on one line, the time under it. Side by
     side they do not fit, and each broke in two. The control to withdraw a
     message sits in the corner, so it takes no line of its own. */
  .tkt-msg__head{flex-wrap:wrap;row-gap:0;padding-right:var(--space-8)}
  .tkt-msg__at{flex-basis:100%;margin-left:0}
  .tkt-msg__body{position:relative}
  .tkt-msg__head .tkt-msgact{position:absolute;top:var(--space-4);right:var(--space-4);margin-left:0}
}
/* The control to withdraw a message shows when the pointer is over the
   message. A finger has no "over", so on a touch screen it is always there. */
@media (hover:none){.tkt-msg__head .tkt-msgact{opacity:1}}

/* ---------- status history ---------- */
.tkt-uptime{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:var(--space-5);margin-top:var(--space-5)}
.tkt-uptime__cell{display:flex;flex-direction:column;gap:2px;padding-left:var(--space-5);border-left:2px solid var(--border-subtle)}
.tkt-uptime__name{font:var(--type-caption);color:var(--text-secondary)}
.tkt-uptime__pct{font-family:var(--font-mono);font-size:var(--text-md);font-weight:var(--weight-semibold);color:var(--text-primary)}
.tkt-uptime__now{font:var(--type-overline);text-transform:uppercase;letter-spacing:var(--tracking-caps)}
.tkt-hist{display:flex;flex-direction:column;gap:var(--space-4);padding:var(--space-6) var(--space-7);border-bottom:1px solid var(--border-subtle)}
.tkt-hist:last-child{border-bottom:0}
.tkt-hist__top{display:flex;align-items:center;gap:var(--space-4);flex-wrap:wrap}
.tkt-hist__title{font:var(--type-label);font-size:var(--text-base);color:var(--text-primary);flex:1;min-width:0}
.tkt-hist__note{font:var(--type-body-sm);color:var(--text-secondary);max-width:var(--measure-prose)}
.tkt-hist__meta{display:grid;grid-template-columns:repeat(auto-fit,minmax(120px,1fr));gap:var(--space-4);margin:0}
.tkt-hist__meta div{display:flex;flex-direction:column;gap:2px}
.tkt-hist__meta dt{font:var(--type-overline);text-transform:uppercase;letter-spacing:var(--tracking-caps);color:var(--text-tertiary)}
.tkt-hist__meta dd{margin:0;font:var(--type-caption);color:var(--text-secondary)}
.tkt-hist__foot{font:var(--type-caption);color:var(--text-tertiary)}


/* A withdrawn message. Keeps its place in the thread and loses its text, so the
   reply that answered it still has something to point at — a removed row would
   read as a fault rather than as a decision somebody took and signed. */
.tkt-msg--gone .tkt-msg__body{background:var(--surface-sunken);border-style:dashed}
.tkt-msg--gone .tkt-msg__body p{color:var(--text-tertiary)}
.tkt-av--gone{background:var(--surface-sunken);border-color:var(--border-default);color:var(--text-tertiary)}
/* Only on hover or focus: a row of delete buttons down a thread invites the
   click, and this one edits a record of a conversation. */
.tkt-msgact{margin-left:var(--space-4);opacity:0;transition:opacity var(--duration-fast) var(--ease-standard)}
.tkt-msg:hover .tkt-msgact,.tkt-msgact:focus-visible{opacity:1}
.tkt-msg--gone .tkt-msgact{opacity:1}


/* ============================================================
   Export log — the administrator's view of the export path.

   It lives here rather than in a file of its own because it is the same
   family of surface as the ticket inbox: a record list with an expandable
   detail, built from the same tokens. A second stylesheet would be a second
   place for those to drift.

   A TABLE AND NOT CARDS, which is the one real difference from My exports.
   Cards read well for the handful of exports a researcher owns; the question
   here is comparative — who took out how much, when, decided by what — and
   comparison across rows is what a table is for.
   ============================================================ */
.xlog-wrap{padding:var(--space-8) var(--space-7) var(--space-9);max-width:1400px;margin:0 auto;
  /* A flex item in .content-section--fixed, and a flex item never shrinks below
     its content unless told to. Without this the wrap grew to the table's full
     width -- 919px inside a 342px section on a phone -- and the section's
     overflow:hidden clipped it, so the right half of the Export log and of
     Training data simply was not there. With it, the table scrolls inside
     .xlog-scroll as the comment on that rule always intended. Found 2026-09-16
     in a headless browser at 390x844. */
  min-width:0;width:100%;box-sizing:border-box}

.xlog-ctrls{display:flex;align-items:center;gap:var(--space-5);flex-wrap:wrap;
  margin:var(--space-6) 0 var(--space-5)}
.xlog-tabs{display:flex;gap:2px;background:var(--surface-sunken);padding:2px;
  border-radius:var(--radius-md);max-width:100%;overflow-x:auto}
.xlog-tab{flex:none;white-space:nowrap}
.xlog-tab{border:0;background:transparent;cursor:pointer;padding:6px var(--space-5);
  border-radius:calc(var(--radius-md) - 2px);font:var(--type-caption);color:var(--text-secondary);
  transition:background var(--duration-fast) var(--ease-standard)}
.xlog-tab:hover{color:var(--text-primary)}
.xlog-tab.is-on{background:var(--surface-card);color:var(--text-primary);
  box-shadow:var(--shadow-xs)}
.xlog-search{flex:1;min-width:220px;max-width:340px;padding:7px var(--space-5);
  border:1px solid var(--border-default);border-radius:var(--radius-md);
  background:var(--surface-card);color:var(--text-primary);font:var(--type-body-sm)}

/* The table scrolls inside its own box. The page must never scroll sideways —
   a monitoring surface that moves under the cursor is one people stop reading. */
.xlog-scroll{container-type:inline-size;overflow-x:auto;border:1px solid var(--border-subtle);
  border-radius:var(--radius-lg);background:var(--surface-card)}
.xlog-tbl{width:100%;border-collapse:separate;border-spacing:0;font:var(--type-body-sm)}
.xlog-tbl th{text-align:left;padding:var(--space-4) var(--space-5);
  font:var(--type-overline);text-transform:uppercase;letter-spacing:var(--tracking-caps);
  color:var(--text-tertiary);border-bottom:1px solid var(--border-subtle);white-space:nowrap}
.xlog-tbl td{padding:var(--space-4) var(--space-5);border-bottom:1px solid var(--border-subtle);
  vertical-align:top}
.xlog-tbl tbody tr:last-child td{border-bottom:0}
.xlog-row:hover{background:var(--surface-hover)}
.xlog-row.is-open{background:var(--surface-selected)}
.xlog-num{text-align:right;white-space:nowrap}
.xlog-when{white-space:nowrap;color:var(--text-secondary);font-variant-numeric:tabular-nums}
.xlog-name{display:block;color:var(--text-primary);font-weight:var(--weight-medium);
  word-break:break-word}
.xlog-sub{display:block;font:var(--type-caption);color:var(--text-tertiary);margin-top:2px}
.xlog-file{min-width:220px}
.xlog-who{min-width:160px}
/* Removed by the researcher is stated, never implied by a greyed-out row: the
   record is intact and only their copy is gone. */
.xlog-gone{color:var(--text-tertiary);font-style:italic}

/* Four different things, four different words. "Retention ended" is a promise
   kept and must not look like a failure; "Not kept — check the log" is an
   approved file whose archive write failed, and that one IS a failure. */
.xlog-keep{display:inline-block;white-space:nowrap;font:var(--type-caption);
  padding:2px var(--space-4);border-radius:var(--radius-pill);border:1px solid transparent}
.xlog-keep--yes{color:var(--status-success-fg);border-color:currentColor}
.xlog-keep--past{color:var(--text-tertiary);border-color:var(--border-default)}
.xlog-keep--no{color:var(--text-tertiary)}
.xlog-keep--bad{color:var(--status-danger-fg);border-color:currentColor}

.xlog-more{border:0;background:transparent;cursor:pointer;font:var(--type-caption);
  color:var(--text-secondary);text-decoration:underline;text-underline-offset:3px;padding:0}
.xlog-more:hover{color:var(--text-primary)}

.xlog-det td{background:var(--surface-sunken)}
.xlog-det__in{display:flex;flex-direction:column;gap:var(--space-5);padding:var(--space-4) 0;
  /* The detail lives in a row of a table that is wider than a phone, so it was
     as wide as the table and its right half needed a sideways swipe to read.
     Sized to the visible box instead (100cqi of .xlog-scroll) and pinned to its
     left edge, it stays readable wherever the table is scrolled. On a desktop
     the box and the table are the same width and nothing changes. */
  position:sticky;left:var(--space-5);box-sizing:border-box;
  width:calc(100cqi - 2 * var(--space-5));min-width:0}
.xlog-det__in pre,.xlog-det__in table{max-width:100%}
.xlog-det__grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));
  gap:var(--space-4) var(--space-6)}
.xlog-f{display:flex;flex-direction:column;gap:2px;min-width:0}
.xlog-f__k{font:var(--type-overline);text-transform:uppercase;
  letter-spacing:var(--tracking-caps);color:var(--text-tertiary)}
.xlog-f__v{font:var(--type-caption);color:var(--text-secondary);word-break:break-all}
.xlog-mono{font-family:var(--font-mono);font-size:var(--text-xs)}
.xlog-reason{margin:0;font:var(--type-body-sm);color:var(--text-primary);
  max-width:var(--measure-prose)}

/* Every check, including the ones that passed. An operator asked whether the
   reviewer was wrong cannot answer that from the decisive check alone. */
.xlog-checks{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:2px}
.xlog-checks li{display:grid;grid-template-columns:16px 150px 1fr;gap:var(--space-4);
  align-items:baseline;font:var(--type-caption);color:var(--text-tertiary)}
.xlog-checks li.is-hit{color:var(--text-primary)}
.xlog-checks li.is-hit i{color:var(--status-warning-fg)}
.xlog-checks li i{color:var(--status-success-fg);font-size:var(--icon-sm)}
.xlog-checks__n{font-weight:var(--weight-medium)}
.xlog-checks__t{color:var(--text-secondary)}

.xlog-dl{width:100%;border-collapse:collapse;font:var(--type-caption);max-width:720px}
.xlog-dl th{text-align:left;padding:2px var(--space-5) 2px 0;color:var(--text-tertiary);
  font:var(--type-overline);text-transform:uppercase;letter-spacing:var(--tracking-caps)}
.xlog-dl td{padding:2px var(--space-5) 2px 0;color:var(--text-secondary)}
.xlog-tag{display:inline-block;padding:0 6px;border-radius:var(--radius-pill);
  background:var(--surface-quiet);color:var(--text-tertiary);font-size:var(--text-xs)}
.xlog-none{margin:0;font:var(--type-caption);color:var(--text-tertiary)}
.xlog-det__acts{display:flex;align-items:center;gap:var(--space-5);flex-wrap:wrap}
.xlog-foot{margin:var(--space-5) 0 0;font:var(--type-caption);color:var(--text-tertiary)}

@media (max-width:900px){.xlog-wrap{padding:var(--space-6) var(--space-5)}}

/* --- Training data (training.js) ------------------------------------------
   Built on the export log's table, tabs and detail rows above; only what that
   page has no need for is here. Admins only, read-only. */
.trn-stats{display:grid;grid-template-columns:repeat(auto-fit,minmax(190px,1fr));
  gap:var(--space-5);margin:var(--space-7) 0 var(--space-6)}
.trn-stats .sa-stat__foot{white-space:normal}
.trn-block{margin-top:var(--space-7)}
.trn-h2{font:var(--type-subheading);color:var(--text-primary);margin:var(--space-7) 0 var(--space-4)}
.trn-block .trn-h2{margin-top:0}
.trn-authors{margin:var(--space-4) 0 0;font:var(--type-caption);color:var(--text-secondary)}
.trn-authors .xlog-f__k{margin-right:var(--space-3)}
.trn-inline{display:inline;margin:0 0 0 var(--space-3)}
.trn-selectwrap{width:auto;min-width:200px}
.trn-tbl .trn-q{min-width:260px;max-width:420px}
.trn-tbl .trn-ans{min-width:240px;max-width:420px;color:var(--text-secondary)}
.trn-clamp{display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
.trn-nowrap{white-space:nowrap}
.trn-sql{margin:0;padding:var(--space-4) var(--space-5);background:var(--surface-card);
  border:1px solid var(--border-subtle);border-radius:var(--radius-sm);
  font:var(--type-mono-xs);color:var(--text-primary);white-space:pre-wrap;word-break:break-word}
.trn-dl{max-width:none}
.trn-dl td{vertical-align:top;padding-top:var(--space-2);padding-bottom:var(--space-2)}
.trn-answer{margin:var(--space-4) 0 0;font:var(--type-body-sm);color:var(--text-primary);max-width:var(--measure-prose)}
.trn-answer .xlog-f__k{display:block;margin-bottom:2px}
.trn-pager{display:flex;align-items:center;gap:var(--space-4);justify-content:flex-end;
  margin-top:var(--space-5);flex-wrap:wrap}
.trn-foot{font:var(--type-caption);color:var(--text-tertiary);margin:var(--space-4) 0 0}
.trn-pager .trn-foot{margin:0 auto 0 0}
.trn-of{font:var(--type-body);color:var(--text-tertiary)}
.trn-bar{display:block;height:4px;border-radius:2px;background:var(--border-subtle);margin:0 0 var(--space-3);overflow:hidden}
.trn-bar>span{display:block;height:100%;background:var(--status-success-fg,var(--text-primary))}
.trn-start{display:flex;align-items:center;gap:var(--space-4);flex-wrap:wrap;margin:var(--space-6) 0 0}
.trn-notice{align-items:center;justify-content:space-between;margin:0 0 var(--space-4);flex-wrap:wrap}
.trn-decide{margin:0 0 var(--space-6);padding:0 0 var(--space-6);border-bottom:1px solid var(--border-subtle)}
.trn-decide__answer{font:var(--type-body);color:var(--text-primary);max-width:var(--measure-prose);margin:0 0 var(--space-5)}
.trn-decide__answer .xlog-f__k{display:block;margin-bottom:var(--space-2)}
.trn-decide__btns{display:flex;align-items:center;gap:var(--space-4);flex-wrap:wrap}
.trn-decided{align-items:center;justify-content:space-between;flex-wrap:wrap;max-width:var(--measure-prose)}
.trn-flag{display:flex;gap:var(--space-3);align-items:flex-start;margin:0 0 var(--space-4);font:var(--type-body-sm);color:var(--text-secondary)}
.trn-why{display:flex;flex-direction:column;gap:var(--space-3);max-width:var(--measure-prose)}
.trn-why .tkt-reply__foot{margin-top:0}
@media (hover:none){.trn-keys{display:none}}
@media (max-width:600px){
  .trn-decide__btns .sa-btn,.trn-why .tkt-reply__foot .sa-btn{flex:1 1 0}
  .trn-decide__btns .tkt-hint{flex-basis:100%}
  .trn-start .sa-btn{width:100%}
}
.trn-error{margin:var(--space-5) 0;padding:var(--space-4) var(--space-5);font:var(--type-body-sm);
  color:var(--status-danger-fg);background:var(--status-danger-bg);
  border:1px solid var(--status-danger-border);border-radius:var(--radius-sm)}
@media (max-width:900px){
  .trn-stats{grid-template-columns:repeat(2,minmax(0,1fr))}
  .trn-selectwrap{min-width:0;flex:1}
  .trn-tbl .trn-q,.trn-tbl .trn-ans{min-width:200px}
}


/* SARA's list (support.js listThread, PROJECT.md P2.70): the notes under an
   entry and the closed entries fold behind the design's tool-call line
   (design/components/ai, .sa-tool). Its panel is display:flex, which would
   beat the hidden attribute, so a closed fold is hidden here. */
.tkt-fold{max-width:none;margin-top:var(--space-4)}
.tkt-fold > .sa-tool__panel[hidden]{display:none}
.tkt-fold__caret{margin-left:auto;flex:none}
/* One line at any width: the name stays whole and the rest ends in an ellipsis. */
.tkt-fold .sa-tool__name{white-space:nowrap}
.tkt-fold .sa-tool__server{min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.tkt-fold .sa-tool__panel > .tkt-thread{gap:var(--space-4)}
.tkt-msg__body .tkt-fold__what{font:var(--type-label);color:var(--text-secondary);margin:0 0 var(--space-2)}
.tkt-list-about{margin:0}
/* Inside a fold a message goes without its avatar: the line above says what it is. */
.tkt-fold .tkt-av{display:none}
