/* ===========================================================================
   The grid's remaining rules, taken from the ticketing portal's app.css.

   tms-tokens / tms-base / tms-components came across whole; these did not,
   because that app keeps them in its own app.css. Without them the column
   chooser draws inline instead of as a menu, "Group by" stacks above its
   select, the filter row loses its styling and compact rows do nothing.

   Kept as its own file rather than merged into tms-components.css so the next
   pull from that repo stays a copy rather than a merge. Portal-specific
   adjustments go at the end, under their own heading.
   ========================================================================== */

/* --- validation -------------------------------------------------------- */
.validation-message, .tms-field .validation-message {
  display: block; font-size: var(--tms-fs-cap); color: var(--tms-danger); margin-top: 5px;
}

.tms-input.invalid, .invalid .tms-input { border-color: var(--tms-danger); }

.tms-input.modified.valid { border-color: var(--tms-border-strong); }

.tms-login-error .tms-i { margin-top: 1px; flex: none; }

.tms-spinner-sm { width: 15px; height: 15px; border-width: 2px; }

/* --- grid column chooser (v2 addition) --------------------------------- */
.tms-colchooser { position: relative; }

.tms-colchooser-menu {
  position: absolute; right: 0; top: calc(100% + 4px); z-index: var(--tms-z-dropdown);
  min-width: 210px;
  display: flex; flex-direction: column; gap: 2px; padding: 8px;
  background: var(--tms-surface); border: 1px solid var(--tms-border-strong);
  border-radius: var(--tms-r); box-shadow: var(--tms-shadow-3);
}

.tms-colchooser-menu .tms-check {
  padding: 5px 7px; border-radius: var(--tms-r-sm);
  font-size: var(--tms-fs-data); color: var(--tms-text);
}

.tms-colchooser-menu .tms-check:hover { background: var(--tms-surface-2); }

/* An urgent row gets a faint wash so it reads before you reach the badge. */
.tms-grid-table tbody tr.is-urgent td:first-child + td { position: relative; }

.tms-grid-table tbody tr.is-urgent { background: color-mix(in srgb, var(--tms-danger-tint) 45%, transparent); }

.tms-grid-table tbody tr.is-urgent:hover { background: var(--tms-danger-tint); }

/* Flagged for senior review. The ribbon is the whole point — solid red and slightly wider
   than the priority stripe so it reads as a different KIND of signal, not a hotter one.
   The row itself stays neutral: flagging asks for attention, it does not mean the ticket
   is on fire, and tinting whole rows red would make a flagged queue unreadable. */
.tms-stripe-bar.tms-stripe-flag {
  background: var(--tms-danger);
  box-shadow: 0 0 0 1px color-mix(in srgb, var(--tms-danger) 40%, transparent);
}

.tms-grid-table tbody tr.is-flagged td:first-child + td { font-weight: 600; }

.tms-checklist li .tms-i { font-size: 14px; margin-top: 2px; flex: none; }

.tms-checklist li.ok .tms-i { color: var(--tms-ok); }

.tms-checklist li.todo .tms-i { color: var(--tms-text-3); }

/* The label stays put while the names scroll under it — it names the row rather than
   being one of its items. */
.tms-mention-row .tms-eyebrow {
  margin-right: 2px;
  position: sticky; left: 0; z-index: 1;
  background: var(--tms-surface-2); padding-right: 6px;
}

.tms-mention-row .tms-chip { height: 25px; font-size: var(--tms-fs-cap); }

/* ============================================================================
   Grid column resize + reorder
   ========================================================================== */
.tms-grid-table thead th { position: sticky; }

.tms-grid-table thead th .tms-th-label {
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* The grab handle sits in the header's right gutter. */
.tms-col-resize {
  position: absolute; top: 0; right: 0; bottom: 0; width: 9px;
  cursor: col-resize; touch-action: none; z-index: 3;
}

.tms-col-resize::after {
  content: ""; position: absolute; top: 6px; bottom: 6px; right: 4px; width: 1px;
  background: var(--tms-border-strong); opacity: 0;
  transition: opacity var(--tms-fast);
}

.tms-grid-table thead th:hover .tms-col-resize::after { opacity: 1; }

.tms-col-resize:hover::after { opacity: 1; background: var(--tms-accent); width: 2px; }

/* Reorder feedback: the dragged header fades, the drop target shows an insert rail. */
.tms-grid-table thead th[draggable="true"] { cursor: grab; }

.tms-grid-table thead th.is-dragging { opacity: .4; cursor: grabbing; }

.tms-grid-table thead th.is-droptarget { box-shadow: inset 2px 0 0 var(--tms-accent); }

/* Cells must clip, or a narrowed column is overflowed by its content. */
.tms-grid-table td { overflow: hidden; text-overflow: ellipsis; }

.tms-grid-table td.tms-stripe { overflow: visible; }

.tms-queue-row .tms-stripe-bar { height: 34px; flex: none; }

/* The age and badge columns are dense — let them breathe rather than clip. */
.tms-grid-table td.tms-nowrap { white-space: nowrap; overflow: visible; }

/* ============================================================================
   Grid filter row
   ========================================================================== */
.tms-grid-table thead tr.tms-filter-row th {
  position: sticky; top: var(--tms-th-h, 38px); z-index: 2;
  padding: 5px 6px; background: var(--tms-surface-2);
  border-bottom: 1px solid var(--tms-border);
}

.tms-filter-input {
  width: 100%; height: 27px; padding: 0 7px;
  background: var(--tms-surface); color: var(--tms-text);
  border: 1px solid var(--tms-border); border-radius: var(--tms-r-sm);
  font-size: var(--tms-fs-cap); font-weight: 450;
}

.tms-filter-input:focus {
  outline: none; border-color: var(--tms-accent);
  box-shadow: 0 0 0 2px var(--tms-accent-tint);
}

select.tms-filter-input { cursor: pointer; }

/* --- header gesture feedback (JS-driven) -------------------------------- */
.tms-grid-table thead th.is-resizing { background: var(--tms-accent-tint); }

.tms-grid-table thead th.is-dragging { opacity: .45; }

.tms-grid-table thead th.is-droptarget-before { box-shadow: inset 3px 0 0 var(--tms-accent); }

.tms-grid-table thead th.is-droptarget-after  { box-shadow: inset -3px 0 0 var(--tms-accent); }

/* Headers are the drag handle, so show the grab affordance — except on the
   resize gutter, which has its own cursor. */
.tms-grid-table thead tr:first-child th[data-colkey] { cursor: grab; }

.tms-grid-table thead tr:first-child th[data-colkey]:active { cursor: grabbing; }

.tms-grid-table thead tr.tms-filter-row th { cursor: default; }

/* ============================================================================
   Scrollbars — the grid's horizontal bar was rendering in the browser's default
   light chrome, which reads as a white slab across a dark page.
   ========================================================================== */
.tms-grid-scroll {
  scrollbar-width: thin;                                   /* Firefox */
  scrollbar-color: var(--tms-border-strong) transparent;
}

.tms-grid-scroll::-webkit-scrollbar { height: 11px; width: 11px; }

.tms-grid-scroll::-webkit-scrollbar-track {
  background: var(--tms-surface-2);
  border-top: 1px solid var(--tms-border);
}

.tms-grid-scroll::-webkit-scrollbar-thumb {
  background: var(--tms-border-strong); border-radius: 999px;
  border: 2px solid var(--tms-surface-2);                   /* inset the thumb */
}

.tms-grid-scroll::-webkit-scrollbar-thumb:hover { background: var(--tms-text-3); }

.tms-grid-scroll::-webkit-scrollbar-corner { background: var(--tms-surface-2); }

/* Same treatment for the other scrolling panels. */
.tms-bell-list, .tms-colchooser-list, .tms-select-list, .tms-fmenu-list, .tms-modal-b {
  scrollbar-width: thin;
  scrollbar-color: var(--tms-border-strong) transparent;
}

.tms-bell-list::-webkit-scrollbar,
.tms-colchooser-list::-webkit-scrollbar,
.tms-select-list::-webkit-scrollbar,
.tms-fmenu-list::-webkit-scrollbar,
.tms-modal-b::-webkit-scrollbar { width: 10px; height: 10px; }

.tms-bell-list::-webkit-scrollbar-thumb,
.tms-colchooser-list::-webkit-scrollbar-thumb,
.tms-select-list::-webkit-scrollbar-thumb,
.tms-fmenu-list::-webkit-scrollbar-thumb,
.tms-modal-b::-webkit-scrollbar-thumb {
  background: var(--tms-border-strong); border-radius: 999px;
  border: 2px solid var(--tms-surface);
}

/* The scroll container owns the bottom corners, so round them with the card. */
.tms-grid-scroll { border-radius: var(--tms-r-lg); }

/* ============================================================================
   Multi-select column filter
   ========================================================================== */
.tms-fmenu { position: relative; }

.tms-fmenu-btn {
  display: flex; align-items: center; gap: 4px; width: 100%; height: 27px;
  padding: 0 6px 0 7px; background: var(--tms-surface); color: var(--tms-text-2);
  border: 1px solid var(--tms-border); border-radius: var(--tms-r-sm);
  font-size: var(--tms-fs-cap); font-weight: 450; text-align: left;
  transition: border-color var(--tms-fast), color var(--tms-fast), background-color var(--tms-fast);
}

.tms-fmenu-btn:hover { border-color: var(--tms-border-strong); color: var(--tms-text); }

.tms-fmenu-btn.is-on {
  background: var(--tms-accent-tint); border-color: var(--tms-accent-line);
  color: var(--tms-accent-dark); font-weight: 600;
}

.tms-fmenu-btn .tms-i { margin-left: auto; font-size: 13px; flex: none; }

.tms-fmenu.is-open .tms-fmenu-btn .tms-i { transform: rotate(180deg); }

.tms-fmenu-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.tms-fmenu-pop {
  position: absolute; left: 0; top: calc(100% + 4px); z-index: var(--tms-z-dropdown);
  min-width: max(190px, 100%); max-width: 300px;
  background: var(--tms-surface); border: 1px solid var(--tms-border-strong);
  border-radius: var(--tms-r); box-shadow: var(--tms-shadow-3); overflow: hidden;
  display: flex; flex-direction: column;
}

.tms-fmenu-search, .tms-fmenu-actions, .tms-fmenu-pop .tms-pop-h, .tms-fmenu-pop .tms-pop-f { flex: none; }

.tms-fmenu-search { padding: 7px; border-bottom: 1px solid var(--tms-border); }

.tms-fmenu-search input {
  width: 100%; height: 28px; padding: 0 8px;
  background: var(--tms-surface-2); color: var(--tms-text);
  border: 1px solid transparent; border-radius: var(--tms-r-sm); font-size: var(--tms-fs-cap);
}

.tms-fmenu-search input:focus { outline: none; border-color: var(--tms-accent); }

.tms-fmenu-actions {
  display: flex; gap: 4px; padding: 5px 6px;
  border-bottom: 1px solid var(--tms-border); background: var(--tms-surface-2);
}

.tms-fmenu-actions .tms-btn { flex: 1; }

/* The popover is pinned to the viewport and given a max-height in JS, so it has to be a
   flex column: the list absorbs whatever is left after the header, actions and footer, and
   scrolls inside itself. With a fixed max-height here the footer was pushed out of the box
   on a short grid, taking the Done button with it. */
.tms-fmenu-list {
  list-style: none; margin: 0; padding: 4px;
  flex: 1 1 auto; min-height: 0; overflow-y: auto;
}

.tms-fmenu-list .tms-check {
  width: 100%; padding: 5px 7px; border-radius: var(--tms-r-sm);
  font-size: var(--tms-fs-data); color: var(--tms-text);
}

.tms-fmenu-list .tms-check:hover { background: var(--tms-surface-2); }

.tms-fmenu-list .tms-check span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.tms-fmenu-none { padding: 14px 10px; text-align: center; color: var(--tms-text-3); font-size: var(--tms-fs-data); }

/* --- multi-column sort indicator ---------------------------------------- */
.tms-grid-table thead th .tms-sort { display: inline-flex; align-items: center; gap: 1px; }

.tms-sort-ord {
  font-size: 9px; font-weight: 700; line-height: 1;
  color: var(--tms-accent); font-variant-numeric: tabular-nums;
}

/* ============================================================================
   Shared popover chrome — header with a close button, and a footer.
   Every lingering popover (column chooser, column filter, multi-select) gets one,
   so none of them can trap you: the column chooser used to cover the only button
   that closed it.
   ========================================================================== */
.tms-pop-h {
  display: flex; align-items: center; gap: 8px;
  padding: 7px 8px 7px 10px; border-bottom: 1px solid var(--tms-border);
  background: var(--tms-surface-2);
}

.tms-pop-h .tms-eyebrow {
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

.tms-pop-x {
  margin-left: auto; flex: none;
  width: 22px; height: 22px; display: grid; place-items: center;
  border-radius: var(--tms-r-sm); color: var(--tms-text-3); font-size: 13px;
  transition: background-color var(--tms-fast), color var(--tms-fast);
}

.tms-pop-x:hover { background: var(--tms-surface-3); color: var(--tms-text); }

.tms-pop-f {
  display: flex; align-items: center; gap: 6px;
  padding: 7px 8px; border-top: 1px solid var(--tms-border);
  background: var(--tms-surface-2);
}

.tms-pop-f .tms-btn:last-child { margin-left: auto; }

.tms-pop-count { font-size: 11.5px; color: var(--tms-text-3); }

/* The chooser's checkbox list scrolls; header and footer stay put. */
.tms-colchooser-list {
  display: flex; flex-direction: column; gap: 2px;
  padding: 6px; flex: 1; min-height: 0; overflow-y: auto;
}

/* The menu no longer pads itself — header, list and footer own their spacing.
   It is also the height cap and the ONLY non-scrolling shell: a flex column that clips,
   so the checkbox list inside it is the single scroller. Declared here rather than in the
   base rule above because this rule comes later and would otherwise reset display back
   to block, which is exactly what left the popup unbounded with no scrollbar at all. */
.tms-colchooser-menu {
  padding: 0;
  display: flex; flex-direction: column;
  max-height: min(340px, 70vh); overflow: hidden;
}

/* Header and footer keep their size; only the list gives. */
.tms-colchooser-menu .tms-pop-h,
.tms-colchooser-menu .tms-pop-f { flex: none; }

/* Window picker on the solved list. Sized to its content and to match the toolbar
   buttons beside it, rather than the full-width form inputs .tms-input assumes. */
.tms-window-pick {
  width: auto;
  padding: 5px 8px;
  font-size: 13px;
}

.tms-perf-table th.tms-num, .tms-perf-table td.tms-num { text-align: right; }

.tms-act-table th.tms-num, .tms-act-table td.tms-num { text-align: right; }

/* Group-by picker in the grid toolbar.
   .tms-input is a full-width, 40px-tall FORM control; the toolbar holds 29px chips and
   buttons and is a wrapping flex row. Left to inherit, the select stretched into whatever
   space was going and stood a head taller than everything beside it. Sized explicitly and
   flex:none so it neither grows nor collapses as the toolbar wraps. */
.tms-groupby { display: inline-flex; align-items: center; gap: 6px; flex: none; }

.tms-groupby > span { font-size: 11px; color: var(--tms-text-3); white-space: nowrap; }

.tms-groupby select {
  flex: none;
  width: 132px;          /* fits the longest option without sizing to it */
  height: 29px;          /* matches .tms-chip and .tms-btn-sm in the same row */
  padding: 0 6px;
  font-size: 12.5px;
  border-radius: var(--tms-r-sm);
}

/* The control must never grow past its column, whatever is selected. */
.tms-flow-org .tms-select-control {
  flex-wrap: nowrap; overflow: hidden;
}

.tms-flow-org .tms-select-chip { max-width: 100%; }

.tms-flow-org .tms-select-control {
  min-height: 28px; height: 28px; padding: 0 8px; font-size: 12px;
}

/* Select all / Clear row inside a multi-select. flex:none so it keeps its height while
   the option list below takes the remaining space and scrolls. */
.tms-select-actions {
  display: flex; gap: 6px; flex: none;
  padding: 6px 8px; border-bottom: 1px solid var(--tms-border);
}

.tms-select-actions button { flex: 1; }

/* A cell held to one line, clipped with an ellipsis.
   td already sets overflow:hidden and text-overflow:ellipsis, but neither does anything
   until the text is stopped from wrapping — which is why these cells grew to two lines
   instead of truncating. The inner span carries it too, so a templated cell truncates the
   same as a plain one. */
/* display:block was on the CELL, which is what pushed the text to the top and stopped
   the column resizing: a td that is not a table-cell no longer takes part in the table
   layout, so vertical-align does nothing and the column-width algorithm ignores it.
   Only the inner span becomes a block; the cell stays a cell. */
.tms-grid-table td.tms-1line {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.tms-grid-table td.tms-1line > span {
  display: block;
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* ============================================================================
   Compact rows
   Roughly 40% more rows per screen. Padding and line-height do the work; the
   font drops only slightly, because shrinking text is what makes a "compact"
   mode unreadable rather than dense.
   ========================================================================== */
/* Ticket rows only — :not(.tms-grouprow) throughout.
   Squeezing the group headings clipped their text, and a heading is the one row on
   screen that has to stay readable: it is what tells you which block you are looking at.
   Compacting is about fitting more TICKETS, not more furniture. */
.tms-grid-scroll.is-dense .tms-grid-table tbody tr:not(.tms-grouprow) { height: 30px; }

.tms-grid-scroll.is-dense .tms-grid-table tbody tr:not(.tms-grouprow) > td {
  padding: 2px 8px; line-height: 1.25;
}

/* The filter row pins itself at --tms-th-h, the height of the header row above it.
   Compact shrank that header without telling the variable, so the filter row stayed at
   38px — 14px below where the header now ends — and sat on top of the first body row.
   That is what was cutting the group heading in half; the heading was never the problem.
   Declared on the scroller so it inherits down to the sticky cell. */
.tms-grid-scroll.is-dense { --tms-th-h: 24px; }

.tms-grid-scroll.is-dense .tms-grid-table thead th { padding: 3px 8px; }

.tms-grid-scroll.is-dense .tms-grid-table { font-size: 12.5px; }

/* Padding stops mattering once something inside the row is taller than the row wants
   to be. These are what actually set the floor. */
.tms-grid-scroll.is-dense tbody tr:not(.tms-grouprow) .tms-avatar {
  width: 16px; height: 16px; font-size: 9px;
}

.tms-grid-scroll.is-dense tbody tr:not(.tms-grouprow) .tms-pill {
  padding: 0 5px; font-size: 10px; line-height: 14px; height: 14px;
}

.tms-grid-scroll.is-dense tbody tr:not(.tms-grouprow) .tms-i { font-size: 11px; }

.tms-grid-scroll.is-dense .tms-bd-est { padding: 0 4px; }

/* A cell that wraps to two lines is two rows tall however little padding it has, so in
   compact every ticket cell is held to one line. Group headings are exempt. */
.tms-grid-scroll.is-dense tbody tr:not(.tms-grouprow) > td,
.tms-grid-scroll.is-dense tbody tr:not(.tms-grouprow) > td > span {
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

/* Group headings keep their room and their full text.
   overflow stays HIDDEN: with it visible the heading rendered outside its own row and
   slid under the sticky filter row above, which is what clipped "UNDEFINED". A heading
   that escapes its row is a heading that ends up behind something. */
.tms-grid-scroll.is-dense .tms-grouprow > td {
  padding: 6px 12px;
  line-height: 1.5;
  white-space: nowrap;
  overflow: hidden;
}

/* The priority ribbon.
   Two things moved it. The blanket "padding: 0 8px" above outranks the base rule that
   zeroes the stripe cell, so the ribbon was pushed 8px inward; and .tms-stripe-bar has a
   fixed height of 38px, which in a 22px row overflowed the cell — the cell is
   overflow:visible by design, so the bar simply hung out of its row.
   Both are pinned back here rather than left to inheritance. */
.tms-grid-scroll.is-dense .tms-grid-table tbody tr:not(.tms-grouprow) > td.tms-stripe {
  padding: 0;
  width: 3px;
}

.tms-grid-scroll.is-dense tbody tr:not(.tms-grouprow) .tms-stripe-bar { height: 22px; }

/* ============================================================================
   Card list — the grid's phone layout
   ========================================================================== */
.tms-cards { display: flex; flex-direction: column; gap: 8px; }

.tms-cards-group {
  margin: 10px 0 2px; font-size: 11px; font-weight: 700;
  letter-spacing: .075em; text-transform: uppercase; color: var(--tms-text-3);
}

.tms-card-row {
  background: var(--tms-surface); border: 1px solid var(--tms-border);
  border-radius: var(--tms-r); padding: 10px 12px;
  box-shadow: var(--tms-shadow-1); cursor: pointer;
}

.tms-card-row:active { background: var(--tms-surface-2); }

/* The urgent and flagged row treatments carry over as a left edge, which is the one
   part of the desktop stripe that still reads at this size. */
.tms-card-row.is-urgent  { border-left: 3px solid var(--tms-danger); }

.tms-card-row.is-flagged { border-left: 3px solid var(--tms-danger); }

/* Sort control, shown only in card mode. */
.tms-card-sort { width: auto; max-width: 150px; height: 38px; padding: 0 8px; font-size: 12.5px; }

.tms-jump-go .tms-i { width: 13px; height: 13px; transform: rotate(-90deg); }

.tms-type.is-icon .tms-i { width: 14px; height: 14px; }

.tms-t-stuck-rmd .tms-i { width: 12px; height: 12px; }

/* Both controls keep the standard 40px .tms-input height rather than a shrunken one.
   The role box was forced to 30px while the picker beside it renders a full-height
   control, so the two sat at different heights on the same row and neither lined up
   with the remove button. Matching the platform height is simpler than tuning two. */
.tms-grp-role { width: 160px; flex: none; }

.tms-grp-up .tms-i { width: 12px; height: 12px; }

.tms-msg-btn .tms-i { width: 12px; height: 12px; }


/* ===========================================================================
   Portal-specific: the parts that answer to this app rather than to the grid.
   ========================================================================== */

/* The portal has one density switch, in the header; the grids are told what it
   says (TmsGrid's Dense parameter) rather than keeping a setting of their own,
   so everything below hangs off the grid's own is-dense class.

   What is left here is the furniture the PORTAL draws inside grid cells —
   badges, the location gradient, the achievement bar. Sized for the old wide
   table, they were what held a compact row open. */
.tms .att-badge { min-width: 0; padding: 0 8px; font-size: 10px; line-height: 19px; }
.tms .badge { padding: 0 7px; font-size: 10px; line-height: 19px; }
.tms .cell-chip { padding: 0 7px; min-width: 46px; }
.tms .grad-loc { height: 20px; }
.tms .grad-loc-text { font-size: 9.5px; line-height: 20px; }
.tms .pct .bar { min-width: 30px; }
.tms .pct { gap: 4px; }
.tms .pct b { font-size: 10.5px; }
.tms .icon-btn { padding: 0 3px; font-size: 11px; }
.tms .tms-expander { width: 18px; height: 18px; }
.tms .tms-grid-table td.tms-expander-cell { padding: 0 0 0 6px; }

/* The drill-down is a table of its own and keeps its own spacing. */
.tms-grid-scroll.is-dense .tms-detail-row > td { white-space: normal; overflow: visible; }
.tms .pcttxt { margin-left: 4px; }

/* Columns laid out to their declared widths. Cells clip, in both densities:
   with table-layout fixed a cell that will not fit overflows its neighbour
   instead of widening its own column. */
.tms-grid-table.is-fixed { table-layout: fixed; }

.tms-grid-table.is-fixed tbody tr:not(.tms-detail-row) > td {
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

.tms-grid-table.is-fixed tbody tr:not(.tms-detail-row) > td > span:not(.badge):not(.pct) {
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* The branch the board belongs to, beside the search box. Each branch has a
   grid of its own, so this is the grid's subject and not a column of it. */
.grid-branch {
  font-size: 12.5px; font-weight: 700; letter-spacing: .04em;
  color: var(--tms-accent-dark); white-space: nowrap;
  padding: 3px 9px; border-radius: var(--tms-r-sm);
  background: var(--tms-accent-tint); border: 1px solid var(--tms-accent-line);
}

/* Dark mode: the grid sits on the page's own ground rather than on a lighter
   card, so a row and the detail under it read as one surface. The hover and the
   group heading take the card colour instead, which is what separates them. */
html[data-theme="dark"] .tms .tms-grid-scroll,
html[data-theme="dark"] .tms .tms-grid-table,
html[data-theme="dark"] .tms .tms-grid-table thead th,
html[data-theme="dark"] .tms .tms-grid-table thead tr.tms-filter-row th,
html[data-theme="dark"] .tms .tms-grid-foot {
  background: var(--bg);
}

html[data-theme="dark"] .tms .tms-grid-table tbody tr:hover,
html[data-theme="dark"] .tms .tms-grid-table tbody tr.tms-grouprow,
html[data-theme="dark"] .tms .tms-grid-table tbody tr.tms-grouprow:hover {
  background: var(--card);
}

html[data-theme="dark"] .tms .tms-grid-table tbody tr.tms-detail-row,
html[data-theme="dark"] .tms .tms-grid-table tbody tr.tms-detail-row:hover {
  background: var(--bg);
}

/* Capsules, as on the attendance report: fully rounded, tinted background,
   saturated text and a 1px border of the same hue. The board drew these as
   soft-cornered blocks, which read as a different kind of thing to the same
   ON / NEAR / OFF values one screen over. */
.tms .badge { border-radius: 999px; border: 1px solid transparent; }

.tms .b-good { border-color: color-mix(in srgb, var(--good) 35%, transparent); }
.tms .b-warn { border-color: color-mix(in srgb, var(--warn) 35%, transparent); }
.tms .b-bad { border-color: color-mix(in srgb, var(--bad) 35%, transparent); }
.tms .b-purple { border-color: color-mix(in srgb, var(--purple) 35%, transparent); }
.tms .b-accent { border-color: color-mix(in srgb, var(--accent) 35%, transparent); }
.tms .b-muted { border-color: var(--line); }

/* The location cell is a gradient rather than a tint — the shape is what makes
   it read as the same family. */
.tms .grad-loc { border-radius: 999px; }

/* The location cell is a fixed 170px band by default, which a 100px column cuts
   off on the right — and switching to comfortable rows switched the width with
   it. Inside a grid it takes the width of its own column instead, whatever the
   density is. */
.tms .grad-loc { width: auto; min-width: 0; max-width: 100%; }

/* The grid sits flush inside a panel, which left its toolbar and footer hard
   against the panel's edge. The table itself stays full-bleed — a row that runs
   the width of the panel is the point. */
/* Lined up with the filter row rather than with the panel: the search box takes
   the same left edge as the first column's filter field, and the controls on the
   right take the last one's right edge. The gutter is the table's own (8px), not
   the panel's. Equal air above and below so the row sits in the middle of the
   space between the panel heading and the column headings. */
.panel > .tms .tms-grid-toolbar { padding: 0 8px; margin: 10px 0; }
.panel > .tms .tms-grid-foot { padding-left: 8px; padding-right: 8px; }
.panel > .tms .tms-tiles { padding: 0 8px; }

/* Comfortable rows are about height, not type size. These columns are sized to
   fit the whole board on one screen; growing the text a point in comfortable
   mode only truncated it ("47/47 10…"), so the size stays put and the row
   height is what changes. */
.tms .tms-grid-table { font-size: 12.5px; }

/* Columns are tuned to the pixel here, so the cell gutter has to be the same in
   both densities — comfortable's wider padding ate 8px per column and put the
   short numeric cells back into ellipsis. Height still changes; width does not. */
.tms .tms-grid-table thead th,
.tms .tms-grid-table tbody tr:not(.tms-detail-row) > td {
  padding-left: 8px; padding-right: 8px;
}
