/* Shared mobile components for PoolBooks (wave one).
   Sheet, IconButton, Button variants, Field, ActionBar, ListRow, Chip.
   Rules these exist to hold:
   - Every tappable thing has a 44px minimum hit area, built in, so a new drawer cannot forget it.
   - Every text input is 16px or larger, because iOS Safari zooms the page on focus below that.
   - Colour carries meaning: primary = ocean, money = navy, danger = coral, secondary = aqua wash.
   - Reads brand tokens only. No hex values here, and no var() fallbacks (a fallback hides a missing token).
   Under 861px a Sheet is a bottom slide-up. From 861px up the same markup is a right-hand drawer. */

/* ── Sheet ─────────────────────────────────────────────────────────────── */
/* z-index 259/260 and up (m-components.js re-stamps per stack position): PoolBooks' own side panels sit
   at 240, so a sheet opened FROM one has to clear it. The toast is higher still (#toast in app.css). */
.m-scrim {
  position: fixed; inset: 0; z-index: 259; background: rgba(6, 40, 64, .45);
  opacity: 0; pointer-events: none; transition: opacity .2s ease;
}
.m-scrim.open { opacity: 1; pointer-events: auto; }

.m-sheet {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 260;
  display: flex; flex-direction: column;
  max-height: 92dvh; min-height: 40dvh;
  background: var(--tf-white); color: var(--text-body); font-family: var(--font-sans);
  border-radius: 20px 20px 0 0; box-shadow: var(--shadow-md);
  transform: translateY(102%); visibility: hidden;
  transition: transform .26s cubic-bezier(.32, .72, 0, 1), visibility 0s linear .26s;
}
.m-sheet.open { transform: translateY(0); visibility: visible; transition-delay: 0s; }
/* Stacking order (a form over the actions list) is set per position by m-components.js, not here. */
.m-sheet.m-sheet--short { min-height: 0; }

.m-sheet-grab { flex: none; width: 40px; height: 5px; border-radius: 3px; background: var(--tf-ink-200); margin: 10px auto 2px; touch-action: none; }
.m-sheet-head { flex: none; display: flex; align-items: flex-start; gap: 12px; padding: 8px 16px 12px; border-bottom: 1px solid var(--tf-ink-100); }
.m-sheet-title-wrap { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 4px; }
.m-sheet-title { margin: 0; font-family: var(--font-display); font-size: 1.2rem; line-height: 1.25; color: var(--text-strong); overflow-wrap: anywhere; }
.m-sheet-sub { font-size: .875rem; color: var(--text-muted); }
.m-sheet-body { flex: 1; min-height: 0; overflow-y: auto; overscroll-behavior: contain; padding: 14px 16px; display: flex; flex-direction: column; gap: 14px; }
.m-sheet-body > * { flex: none; }

@media (min-width: 861px) {
  .m-sheet { left: auto; top: 0; width: 480px; max-height: none; min-height: 0; border-radius: 0; transform: translateX(102%); }
  .m-sheet.open { transform: translateX(0); }
  .m-sheet-grab { display: none; }
}
@media (prefers-reduced-motion: reduce) { .m-sheet, .m-scrim { transition: none; } }

/* ── IconButton: a 44px tinted square, so it looks tappable and is easy to hit ── */
.m-iconbtn {
  flex: none; width: 44px; height: 44px; padding: 0; border: 1px solid var(--tf-ink-200); border-radius: 12px;
  background: var(--tf-aqua-050); color: var(--tf-ocean-800); cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
}
.m-iconbtn svg { width: 22px; height: 22px; }
.m-iconbtn:active { background: var(--tf-aqua-soft); }
.m-iconbtn:focus-visible, .m-btn:focus-visible, .m-row:focus-visible, .m-chip-btn:focus-visible { outline: 2px solid var(--tf-ocean-800); outline-offset: 2px; }

/* ── Button variants. 48px tall; one style per meaning. ──────────────────── */
.m-btn {
  min-height: 48px; padding: 0 18px; border-radius: 12px; border: 1px solid transparent; cursor: pointer;
  font-family: var(--font-sans); font-size: 1rem; font-weight: 600; line-height: 1.2;
  display: inline-flex; align-items: center; justify-content: center; gap: 8px; text-align: center;
}
.m-btn svg { width: 20px; height: 20px; flex: none; }
.m-btn--block { width: 100%; }
.m-btn--primary { background: var(--tf-ocean-800); color: var(--tf-white); }
.m-btn--primary:active { background: var(--tf-ocean-700); }
.m-btn--secondary { background: var(--tf-aqua-050); color: var(--tf-ocean-800); border-color: var(--tf-ink-200); }
.m-btn--secondary:active { background: var(--tf-aqua-soft); }
.m-btn--money { background: var(--tf-navy); color: var(--tf-white); }
.m-btn--money:active { background: var(--tf-ink-700); }
.m-btn--danger { background: var(--tf-coral-bg); color: var(--tf-coral-text); border-color: var(--tf-coral); }
.m-btn:disabled { opacity: .45; cursor: not-allowed; }

/* ── Field: label above, 48px control, 16px text ─────────────────────────── */
.m-field { display: flex; flex-direction: column; gap: 6px; min-width: 0; }
.m-field > label, .m-label { font-size: .8125rem; font-weight: 700; letter-spacing: .02em; color: var(--text-muted); }
.m-field input, .m-field select, .m-field textarea {
  width: 100%; min-height: 48px; padding: 10px 12px; box-sizing: border-box;
  font-family: var(--font-sans); font-size: 1rem; color: var(--text-strong);
  background: var(--tf-white); border: 1px solid var(--tf-ink-300); border-radius: 12px;
}
/* A select draws its caret INSIDE the border (two token-coloured triangles), and a month or date input keeps its picker icon inside it. */
.m-field select { appearance: none; -webkit-appearance: none; padding-right: 36px;
  background-image: linear-gradient(45deg, transparent 50%, var(--text-muted) 50%), linear-gradient(135deg, var(--text-muted) 50%, transparent 50%);
  background-position: calc(100% - 18px) 50%, calc(100% - 13px) 50%; background-size: 5px 5px, 5px 5px; background-repeat: no-repeat; }
.m-field input[type="month"], .m-field input[type="date"] { padding-right: 10px; }
.m-field input[type="month"]::-webkit-calendar-picker-indicator, .m-field input[type="date"]::-webkit-calendar-picker-indicator { margin: 0; padding: 0 0 0 6px; opacity: .6; cursor: pointer; }
.m-field textarea { min-height: 96px; line-height: 1.45; resize: vertical; }
.m-field input:focus, .m-field select:focus, .m-field textarea:focus {
  outline: none; border-color: var(--tf-ocean-800); box-shadow: 0 0 0 3px var(--tf-aqua-050);
}
.m-field-hint { font-size: .8125rem; color: var(--text-muted); }
.m-field-error { font-size: .8125rem; color: var(--status-danger-text); }

/* A big tappable choice (radio or checkbox as a card). The whole card is the target.
   The card's height is its content plus padding and nothing else: a min-height here left a band of
   empty space under one-line descriptions. */
.m-choice { display: flex; gap: 12px; align-items: flex-start; padding: 12px 14px; border: 1px solid var(--tf-ink-200); border-radius: 12px; background: var(--tf-white); cursor: pointer; line-height: 1.35; }
.m-choice input { flex: none; width: 24px; height: 24px; margin: 1px 0 0; accent-color: var(--tf-ocean-800); }
.m-choice:has(input:checked) { border-color: var(--tf-ocean-800); background: var(--tf-aqua-050); }
.m-choice-t { display: block; font-weight: 600; color: var(--text-strong); font-size: .9375rem; }
.m-choice-d { display: block; font-size: .8125rem; color: var(--text-muted); margin-top: 2px; }

/* ── ActionBar: pinned to the bottom of the sheet, always visible ────────── */
.m-actionbar {
  flex: none; display: flex; gap: 10px; align-items: center;
  padding: 12px 16px calc(12px + env(safe-area-inset-bottom, 0px));
  border-top: 1px solid var(--tf-ink-100); background: var(--tf-white);
}
.m-actionbar .m-btn { flex: 1; min-width: 0; }

/* ── ListRow: a 56px tappable row with icon, label, optional value and chevron ── */
.m-list { display: flex; flex-direction: column; border: 1px solid var(--tf-ink-100); border-radius: 14px; overflow: hidden; background: var(--tf-white); }
.m-list-label { font-size: .75rem; font-weight: 700; letter-spacing: .06em; text-transform: uppercase; color: var(--text-muted); padding: 4px 4px 6px; }
.m-row {
  display: flex; align-items: center; gap: 12px; width: 100%; min-height: 56px; padding: 8px 14px;
  border: 0; border-bottom: 1px solid var(--tf-ink-100); background: var(--tf-white);
  font-family: var(--font-sans); text-align: left; cursor: pointer; color: var(--text-strong);
}
.m-row:last-child { border-bottom: 0; }
.m-row:active { background: var(--tf-aqua-050); }
.m-row-ic { flex: none; width: 36px; height: 36px; border-radius: 10px; display: flex; align-items: center; justify-content: center; background: var(--tf-aqua-050); color: var(--tf-ocean-800); }
.m-row-ic svg { width: 20px; height: 20px; }
.m-row-tx { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.m-row-t { font-size: .9375rem; font-weight: 600; }
.m-row-d { font-size: .8125rem; color: var(--text-muted); overflow-wrap: anywhere; }
.m-row-v { flex: none; font-size: .9375rem; font-weight: 600; font-variant-numeric: tabular-nums; }
.m-row-chev { flex: none; width: 18px; height: 18px; color: var(--tf-ink-400); }
.m-row--money .m-row-ic { background: var(--tf-navy); color: var(--tf-white); }
.m-row--danger { color: var(--tf-coral-text); }
.m-row--danger .m-row-ic { background: var(--tf-coral-bg); color: var(--tf-coral-text); }
.m-row--danger .m-row-d { color: var(--tf-coral-text); }
.m-row[disabled] { opacity: .5; cursor: not-allowed; }

/* ── Chips and status pill ───────────────────────────────────────────────── */
.m-pill { white-space: nowrap; display: inline-block; align-self: flex-start; font-size: .75rem; font-weight: 700; letter-spacing: .04em; text-transform: uppercase; padding: 3px 10px; border-radius: 99px; background: var(--status-info-soft); color: var(--status-info-text); }
.m-pill--ok { background: var(--status-success-soft); color: var(--status-success-text); }
.m-pill--warn { background: var(--status-warning-soft); color: var(--status-warning-text); }
/* A tappable name (the customer, from any panel). The tap area is 44px; the chip looks like a chip. */
.m-chip-btn {
  display: inline-flex; align-items: center; gap: 6px; min-height: 44px; padding: 0 14px; border-radius: 99px;
  border: 1px solid var(--tf-ink-200); background: var(--tf-aqua-050); color: var(--tf-ocean-800);
  font-family: var(--font-sans); font-size: .9375rem; font-weight: 600; cursor: pointer; align-self: flex-start;
}
.m-chip-btn svg { width: 18px; height: 18px; }
/* A chip that carries an on/off state. Off is coral because it means "we are not reaching them". */
.m-chip-btn--compact { min-height: 40px; padding: 0 10px; font-size: .8125rem; }
.m-chip-btn--filter { background: var(--tf-white); border-color: var(--tf-ink-200); color: var(--text-body); }
.m-chip-btn[aria-pressed="true"] { background: var(--tf-aqua-050); border-color: var(--tf-ocean-800); color: var(--tf-ocean-800); }
.m-chip-btn--off { background: var(--tf-coral-bg); color: var(--tf-coral-text); border-color: var(--tf-coral); }
.m-pill--off { background: var(--tf-coral-bg); color: var(--tf-coral-text); }

/* ── Tabs: a row of 44px buttons that swaps panels, so one long scroll becomes four short ones ── */
.m-tabs { display: flex; gap: 6px; padding: 8px 0; position: sticky; top: 0; z-index: 2; background: var(--tf-white); overflow-x: auto; }
.m-tab {
  flex: 1 0 auto; min-height: 44px; padding: 0 14px; border-radius: 12px; cursor: pointer;
  border: 1px solid var(--tf-ink-200); background: var(--tf-white); color: var(--text-muted);
  font-family: var(--font-sans); font-size: .9375rem; font-weight: 600; white-space: nowrap;
}
.m-tab[aria-selected="true"] { background: var(--tf-aqua-050); color: var(--tf-ocean-800); border-color: var(--tf-ocean-800); }
.m-tab:focus-visible { outline: 2px solid var(--tf-ocean-800); outline-offset: 2px; }

/* ── Callout: the one inline notice. Stays put until the condition clears or it is answered. ──
   Use it for anything that gates an action or needs the person to DO something (a full block, a silent
   change the customer must be told about, a refused save). It sits next to the control it is about, which
   is why it is not a toast: a toast leaves while you still need it, and covers the buttons you need.
   Outcomes after a sheet closes ("Visit moved") stay on the app's existing toast.
   Tones: info, warn (needs action), danger (refused or failed), success. Optional title and actions. */
.m-callout {
  display: flex; gap: 12px; align-items: flex-start; padding: 12px 14px; border-radius: 14px;
  border: 1px solid var(--status-info-border); background: var(--status-info-soft); color: var(--status-info-text);
  font-size: .9375rem; line-height: 1.45;
}
.m-callout-ic { flex: none; width: 26px; height: 26px; border-radius: 50%; display: flex; align-items: center; justify-content: center; background: var(--status-info); color: var(--tf-white); }
.m-callout-ic svg { width: 16px; height: 16px; }
.m-callout-body { flex: 1; min-width: 0; overflow-wrap: anywhere; }
.m-callout-t { margin: 0 0 2px; font-weight: 700; }
.m-callout-actions { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 10px; }
.m-callout-actions .m-btn { flex: 1 1 auto; }
.m-callout--warn { border-color: var(--status-warning-border); background: var(--status-warning-soft); color: var(--status-warning-text); }
.m-callout--warn .m-callout-ic { background: var(--status-warning); }
.m-callout--danger { border-color: var(--status-danger-border); background: var(--status-danger-soft); color: var(--status-danger-text); }
.m-callout--danger .m-callout-ic { background: var(--status-danger); }
.m-callout--success { border-color: var(--status-success-border); background: var(--status-success-soft); color: var(--status-success-text); }
.m-callout--success .m-callout-ic { background: var(--status-success); }

/* ── Plain summary card used inside a sheet body ─────────────────────────── */
.m-card { border: 1px solid var(--tf-ink-100); border-radius: 14px; padding: 14px; background: var(--tf-white); display: flex; flex-direction: column; gap: 6px; }
.m-card-big { font-family: var(--font-display); font-size: 1.8rem; line-height: 1.1; color: var(--text-strong); font-variant-numeric: tabular-nums; }
.m-card-note { font-size: .875rem; color: var(--text-muted); }
.m-kv { display: flex; justify-content: space-between; gap: 16px; padding: 10px 0; border-bottom: 1px solid var(--tf-ink-100); font-size: .9375rem; }
.m-kv:last-child { border-bottom: 0; }
.m-kv > :first-child { color: var(--text-muted); flex: none; }
.m-kv > :last-child { color: var(--text-strong); font-weight: 600; text-align: right; min-width: 0; overflow-wrap: anywhere; }

/* ── Touch drag (MDrag in m-components.js) ───────────────────────────────── */
.m-drag-ghost { position: fixed; z-index: 9500; margin: 0; pointer-events: none; opacity: .92; box-shadow: var(--shadow-md); background: var(--tf-white); border-radius: 12px; }
.m-drag-src { opacity: .35; }
.m-drop-over { outline: 2px dashed var(--tf-ocean-800); outline-offset: -2px; background: var(--tf-aqua-050); }
html.m-dragging { overscroll-behavior: none; -webkit-user-select: none; user-select: none; }

/* Floating home for MCallout.askFloating: a question with no control on screen to sit beside. */
#m-ask-host { position: fixed; left: 12px; right: 12px; bottom: calc(12px + env(safe-area-inset-bottom, 0px)); z-index: 420; max-width: 480px; margin: 0 auto; box-shadow: var(--shadow-md); border-radius: 14px; }
#m-ask-host:empty, #m-ask-host:not(:has(.m-callout)) { display: none; }

/* ── Search: one box, 48px, 16px text (iOS zooms below 16). Used above lists. ── */
.m-search {
  display: flex; align-items: center; gap: 8px; min-height: 48px; padding: 0 12px; box-sizing: border-box;
  background: var(--tf-white); border: 1px solid var(--tf-ink-300); border-radius: 12px;
}
.m-search svg { flex: none; width: 20px; height: 20px; color: var(--text-muted); }
.m-search input {
  flex: 1; min-width: 0; min-height: 44px; border: 0; outline: 0; background: transparent;
  font-family: var(--font-sans); font-size: 1rem; color: var(--text-strong);
}
.m-search:focus-within { border-color: var(--tf-ocean-800); box-shadow: 0 0 0 3px var(--tf-aqua-050); }

/* ── Patterns promoted from the Schedule, Dashboard and Reputation rebuilds (2026-10-19) ────────────────────
   Five pieces that three screens each needed. Defined here once; the screens use these names and nothing else
   hand-rolls them. Tokens only, no fallbacks. */

/* Chip-and-picker: one value that is changed from a list. A .m-chip-btn showing the current value and a chevron,
   with data-m-open pointing at a short .m-sheet of .m-choice radios that closes itself on change. Used for Tech,
   the Dashboard period and the Reputation section. Not a new class: it is .m-chip-btn + .m-sheet--short. */

/* Day row: a date tile, what the day holds, an optional money tag, a chevron. Extends .m-row. */
.m-dayrow { align-items: center; min-height: 64px; }
.m-dayrow.selected { background: var(--tf-aqua-050); }
.m-dayrow.off { opacity: .7; }
.m-datetile { flex: none; width: 48px; height: 48px; border-radius: 12px; background: var(--tf-aqua-050); color: var(--tf-ocean-800); display: flex; flex-direction: column; align-items: center; justify-content: center; line-height: 1.05; }
.m-datetile small { font-size: .6875rem; font-weight: 700; letter-spacing: .06em; }
.m-datetile b { font-family: var(--font-display); font-size: 1.15rem; }
.m-dayrow.today .m-datetile { background: var(--tf-ocean-800); color: var(--tf-white); }
.m-dayrow.off .m-datetile { background: var(--tf-ink-100); color: var(--text-muted); }
.m-loads { display: flex; gap: 12px; flex-wrap: wrap; }
.m-load { display: inline-flex; align-items: center; gap: 6px; font-size: .75rem; color: var(--text-muted); }
.m-load em { font-style: normal; }
.m-load i { display: inline-block; width: 40px; height: 6px; border-radius: 99px; background: var(--tf-ink-100); overflow: hidden; }
.m-load i s { display: block; height: 100%; background: var(--tf-ocean-800); }
.m-load.full { color: var(--tf-coral-text); }
.m-load.full i s { background: var(--tf-coral-text); }
.m-duetag { flex: none; font-size: .8125rem; font-weight: 700; color: var(--tf-navy); background: var(--tf-aqua-050); padding: 3px 8px; border-radius: 8px; }

/* Count tabs: a number over a label, one lane visible at a time. Extends .m-tabs / .m-tab. Put the number in a <b>.
   Add .urgent to a tab whose number needs a decision and it turns coral. */
.m-counttabs { padding: 0; gap: 6px; }
.m-counttabs .m-tab { flex: 1 1 0; padding: 0 4px; display: flex; flex-direction: column; align-items: center; justify-content: center; line-height: 1.15; font-size: .8125rem; }
.m-counttabs .m-tab b { font-size: 1rem; }
.m-counttabs .m-tab.urgent b { color: var(--tf-coral-text); }

/* Stat strip: three headline numbers in one card, each tappable, with an optional header row (title and a chip). */
.m-statstrip { background: var(--tf-white); border: 1px solid var(--tf-ink-100); border-radius: 14px; }
.m-statstrip-head { display: flex; align-items: center; justify-content: space-between; padding: 10px 14px 0; }
.m-statstrip-head b { font-family: var(--font-display); font-size: 1.05rem; color: var(--text-strong); }
.m-statstrip-row { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); }
.m-stat { border: 0; border-right: 1px solid var(--tf-ink-100); background: transparent; padding: 10px 6px; min-height: 64px; text-align: center; cursor: pointer; font-family: var(--font-sans); }
.m-stat:last-child { border-right: 0; }
.m-stat small { display: block; font-size: .6875rem; letter-spacing: .06em; text-transform: uppercase; color: var(--text-muted); font-weight: 700; }
.m-stat b { display: block; font-family: var(--font-display); font-size: 1.25rem; color: var(--text-strong); line-height: 1.2; margin-top: 2px; }

/* Work card: one item that needs a decision, one primary action, the rest behind a more button.
   .m-qcard > .m-qhead (an optional icon tile, .m-qkind, .m-qage) · .m-qamt (the figure) · .m-qtext · .m-qacts (primary first).
   Spacing is margins on the parts, not a flex gap, so a consumer can add its own pieces between them without doubling it.
   .m-qage is quiet text; .warn and .alert raise it. Consumers: the Dashboard queue card and the Reputation approval card. */
.m-qcard { background: var(--tf-white); border: 1px solid var(--tf-ink-100); border-radius: 16px; box-shadow: var(--shadow-md); padding: 20px; }
.m-qhead { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-bottom: 14px; }
.m-qkind { font-size: var(--fs-eyebrow); font-weight: 700; letter-spacing: .07em; text-transform: uppercase; color: var(--text-muted); }
.m-qage { margin-left: auto; font-size: var(--fs-xs); color: var(--text-muted); white-space: nowrap; }
.m-qage.warn { color: var(--status-warning-text); }
.m-qage.alert { color: var(--status-danger-text); font-weight: 600; }
.m-qamt { font-family: var(--font-display); font-size: var(--fs-2xl); color: var(--text-strong); margin: 10px 0 4px; font-variant-numeric: tabular-nums; }
.m-qtext { margin: 8px 0 0; font-size: .9375rem; line-height: 1.45; }
.m-qacts { display: flex; flex-direction: column; gap: 8px; margin-top: 14px; }

/* Callout facts and field (MCallout.ask options): the specifics being approved, and one reason box answered with the question. */
.m-callout-facts { margin: 8px 0 0; display: grid; gap: 4px; }
.m-callout-facts > div { display: flex; justify-content: space-between; gap: 12px; font-size: .875rem; }
.m-callout-facts dt { color: var(--text-muted); }
.m-callout-facts dd { margin: 0; font-weight: 600; color: var(--text-strong); text-align: right; font-variant-numeric: tabular-nums; }
.m-callout-field { display: block; margin-top: 10px; }
.m-callout-field span { display: block; font-size: .8125rem; font-weight: 600; color: var(--text-strong); margin-bottom: 4px; }
.m-callout-field input { width: 100%; box-sizing: border-box; min-height: 48px; padding: 0 12px; border: 1px solid var(--tf-ink-300); border-radius: 12px; font: inherit; font-size: 1rem; background: var(--tf-white); }


/* ── Board and DataTable (2026-10-19) ─────────────────────────────────────────────────────────────────────
   Two views of the same records, the way every CRM does it. Neither knows what a lead is: they take rows and
   callbacks (m-components.js: MBoard, MTable). Tokens only, no fallbacks. A tag on a card is .m-pill.m-pill--tag.

   Board: .m-board > .m-board-tabs (a .m-tabs.m-counttabs, shown under 861px only) + .m-board-cols > .m-board-col
   (header with a count, cards or an empty state). A card is .m-board-card (draggable, focusable) holding the
   consumer's own markup; .m-bc-* are the anatomy of a compact card. Drop targets get .m-drop-over. */
.m-pill--tag { text-transform: none; letter-spacing: 0; align-self: auto; padding: 1px 7px; font-size: .6875rem; font-weight: 600; }
.m-board-cols { display: grid; grid-template-columns: repeat(var(--m-board-n), minmax(0, 1fr)); gap: 0; align-items: stretch; border: 1px solid var(--tf-ink-200); border-radius: 12px; background: var(--tf-white); overflow: hidden; }
.m-board-col { box-shadow: inset 0 3px 0 var(--m-accent, var(--tf-ink-200)); display: flex; flex-direction: column; gap: 10px; min-width: 0; min-height: 260px; padding: 12px; border-left: 1px solid var(--tf-ink-100); background: transparent; }
.m-board-col:first-child { border-left: 0; }
.m-board-colh { display: flex; align-items: baseline; justify-content: space-between; padding: 6px 4px 6px; font-family: var(--font-display); font-size: 1.0625rem; font-weight: 700; color: var(--text-strong); }
.m-board-colh b { font-family: var(--font-display); font-size: 1.25rem; font-weight: 700; color: var(--text-muted); }
.m-board-card { padding: 12px 14px; border: 1px solid var(--tf-ink-200); border-radius: 10px; background: var(--tf-white); box-shadow: var(--shadow-sm); cursor: pointer; touch-action: pan-y; }
.m-board-card:hover { border-color: var(--tf-ocean-800); }
.m-board-card:focus-visible { outline: 2px solid var(--tf-ocean-800); outline-offset: 2px; }
.m-board-card.dragging { opacity: .4; }
.m-bc-head { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; }
.m-bc-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: .9375rem; font-weight: 600; color: var(--text-strong); }
.m-bc-age { flex: none; font-size: .75rem; color: var(--text-muted); white-space: nowrap; }
.m-bc-sub { margin-top: 1px; font-size: .75rem; color: var(--text-muted); }
.m-bc-text { margin-top: 6px; font-size: .8125rem; color: var(--text-body); display: -webkit-box; -webkit-line-clamp: 1; -webkit-box-orient: vertical; overflow: hidden; }
.m-bc-tags { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 7px; }
.m-board-empty { padding: 30px 10px; text-align: center; font-size: .8125rem; color: var(--text-muted); }
.m-board-empty b { display: block; margin-bottom: 2px; font-size: .875rem; color: var(--text-body); }
.m-board-tabs { display: none; }
/* A drop row that appears only while something is being dragged (html.m-dragging, set by MDrag and by the mouse drag). */
.m-board-dock { position: fixed; left: 0; right: 0; bottom: 0; z-index: 9400; display: none; gap: 8px; justify-content: center; padding: 10px 16px calc(10px + env(safe-area-inset-bottom)); background: var(--tf-navy); }
html.m-dragging .m-board-dock { display: flex; }
.m-board-dock [data-m-drop] { flex: 1 1 0; max-width: 220px; min-height: 56px; display: flex; align-items: center; justify-content: center; text-align: center; border: 2px dashed var(--tf-ink-300); border-radius: 12px; color: var(--tf-white); font-weight: 700; font-size: .875rem; }
.m-board-dock [data-m-drop].m-drop-over { background: var(--tf-ocean-800); border-style: solid; outline: none; }
@media (max-width: 860px) {
  .m-board-tabs { display: flex; }
  .m-board-cols { grid-template-columns: 1fr; }
  .m-board-col:not(.on) { display: none; }
  .m-board-col { min-height: 0; border-left: 0; }
}

/* DataTable: a real <table> (header, rows, an action cell per row), an optional filter bar above it (put your own
   .m-field / .m-search controls in .m-table-bar) and a footer reading "n to m of N" with Previous and Next.
   Sortable headers are buttons carrying aria-sort. Empty and no-results are separate states, because "nothing
   here yet" and "nothing matches" ask the person to do different things. */
.m-table-bar { display: flex; flex-wrap: wrap; gap: 10px; align-items: flex-end; margin-bottom: 12px; }
.m-table-wrap { overflow-x: auto; border: 1px solid var(--tf-ink-100); border-radius: 12px; background: var(--tf-white); }
.m-table { width: 100%; min-width: 760px; table-layout: fixed; border-collapse: collapse; font-size: .875rem; color: var(--text-body); }
.m-table th { position: sticky; top: 0; padding: 10px 12px; border-bottom: 1px solid var(--tf-ink-100); background: var(--tf-white); text-align: left; font-size: .6875rem; font-weight: 700; letter-spacing: .06em; text-transform: uppercase; color: var(--text-muted); white-space: nowrap; }
.m-table th button { all: unset; cursor: pointer; display: inline-flex; gap: 4px; align-items: center; min-height: 32px; }
.m-table th button:focus-visible { outline: 2px solid var(--tf-ocean-800); outline-offset: 2px; }
.m-table th[aria-sort="ascending"] button::after { content: "\2191"; }
.m-table th[aria-sort="descending"] button::after { content: "\2193"; }
/* One line per cell. A column with a width keeps it; the others share what is left and end in an ellipsis. */
.m-table td { padding: 0 12px; height: 46px; border-bottom: 1px solid var(--tf-ink-100); vertical-align: middle; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.m-table tbody tr:last-child td { border-bottom: 0; }
.m-table tbody tr:hover { background: var(--tf-ink-050); }
.m-table td.m-table-act { text-align: right; overflow: visible; }
.m-table-open { all: unset; cursor: pointer; display: block; max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 600; color: var(--text-strong); }
.m-table-open:hover { text-decoration: underline; }
.m-table-open:focus-visible { outline: 2px solid var(--tf-ocean-800); outline-offset: 2px; }
/* The row action: a compact text control, not a button slab. */
.m-table-action { all: unset; cursor: pointer; display: inline-flex; align-items: center; gap: 6px; min-height: 32px; padding: 0 10px; border-radius: 8px; font-size: .8125rem; font-weight: 600; color: var(--tf-ocean-800); }
.m-table-action svg { width: 15px; height: 15px; }
.m-table-action:hover { background: var(--tf-aqua-050); }
.m-table-action:focus-visible { outline: 2px solid var(--tf-ocean-800); outline-offset: 2px; }
.m-table-ask .m-callout-actions .m-btn { flex: 0 0 auto; min-height: 36px; padding: 0 18px; font-size: .875rem; }
.m-table-ask td { padding: 8px 12px; height: auto; background: var(--tf-ink-050); white-space: normal; }
.m-table-state { padding: 40px 12px; text-align: center; color: var(--text-muted); }
.m-table-state b { display: block; color: var(--text-body); }
.m-table-foot { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-top: 8px; font-size: .8125rem; color: var(--text-muted); }
.m-table-foot span:last-child { display: inline-flex; gap: 4px; }
.m-table-pg { all: unset; cursor: pointer; min-height: 32px; padding: 0 10px; border-radius: 8px; font-size: .8125rem; font-weight: 600; color: var(--tf-ocean-800); }
.m-table-pg:hover:not(:disabled) { background: var(--tf-aqua-050); }
.m-table-pg:focus-visible { outline: 2px solid var(--tf-ocean-800); outline-offset: 2px; }
.m-table-pg:disabled { color: var(--tf-ink-400); cursor: default; }
.m-table-wrap[aria-busy="true"] { opacity: .6; }
.m-sr { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }

/* A small colour dot beside a state's name (a stage, an outcome). Component-owned shape; the colour comes from a modifier the
   consumer defines out of status tokens, because a hue here is a STATE, never decoration. */
.m-dot { display: inline-block; flex: none; width: 9px; height: 9px; margin-right: 7px; border-radius: 50%; vertical-align: baseline; background: var(--tf-ink-400); }
.m-counttabs .m-tab span { display: inline-flex; align-items: center; }
.m-counttabs .m-tab .m-dot { margin-right: 4px; width: 8px; height: 8px; }
.m-counttabs .m-tab { min-width: 0; padding: 0 2px; font-size: .75rem; }
/* One line of a long cell in a table, ending in an ellipsis. */
.m-table-clamp { display: block; max-width: 30ch; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* Segmented toggle: ONE two-way view switch (Unread / Read), never two buttons. */
.m-seg { display: inline-flex; padding: 3px; gap: 2px; border-radius: 10px; background: var(--tf-ink-100); }
.m-seg button { min-height: 40px; padding: 0 14px; border: 0; border-radius: 8px; background: transparent; color: var(--text-muted); font: 600 var(--fs-sm) var(--font-sans); cursor: pointer; }
.m-seg button[aria-pressed="true"] { background: var(--tf-white); color: var(--text-strong); box-shadow: var(--shadow-sm); }
/* Text link: a quiet action that is not the point of the screen (Mark all read, Mark unread). */
.m-link { border: 0; background: transparent; color: var(--tf-ocean-800); font: 600 var(--fs-sm) var(--font-sans); cursor: pointer; min-height: 44px; padding: 0 6px; }
.m-link:hover { text-decoration: underline; }
/* Tappable row: the row itself is the control. Dot = unread, chevron = it opens something. */
.m-taprow { display: flex; gap: 10px; align-items: flex-start; min-height: 56px; padding: 12px 8px; cursor: pointer; border-bottom: 1px solid var(--border); }
.m-taprow:hover { background: var(--tf-aqua-050); }
.m-taprow:focus-visible { outline: 2px solid var(--tf-ocean-800); outline-offset: -2px; }
.m-taprow-dot { flex: none; width: 9px; height: 9px; margin-top: 6px; border-radius: 50%; background: var(--tf-ocean-800); }
.m-taprow--read .m-taprow-dot { background: transparent; border: 1.5px solid var(--tf-ink-300); }
.m-taprow-go { flex: none; align-self: center; width: 18px; height: 18px; color: var(--tf-ink-400); }

/* Segmented control: one joined control for a view switch (Board | List | Closed). Markup: .m-seg > button[role=tab][aria-selected]. */
.m-seg { display: inline-flex; flex: none; border: 1px solid var(--tf-ink-200); border-radius: 10px; overflow: hidden; background: var(--tf-white); }
.m-seg > button { min-height: 44px; padding: 0 16px; border: 0; background: transparent; font-family: var(--font-sans); font-size: .875rem; font-weight: 600; color: var(--text-muted); cursor: pointer; }
.m-seg > button[aria-selected="true"] { background: var(--tf-aqua-050); color: var(--tf-ocean-800); }
.m-seg > button:focus-visible { outline: 2px solid var(--tf-ocean-800); outline-offset: -2px; }

/* Count link: a figure that jumps somewhere. Plain text with an optional dot, no box: quieter than a chip. Put the number in a <b>. */
.m-countlink { display: inline-flex; align-items: center; gap: 0; min-height: 44px; padding: 0 6px; border: 0; background: none; font-family: var(--font-sans); font-size: .8125rem; color: var(--text-muted); cursor: pointer; white-space: nowrap; }
.m-countlink b { margin: 0 5px 0 0; font-family: var(--font-display); font-size: 1.25rem; font-weight: 700; line-height: 1; color: var(--text-strong); }
.m-countlink .m-dot { margin-right: 6px; }
.m-countlink.is-zero b { color: var(--tf-ink-400); font-weight: 400; }
.m-countlink.is-zero span { color: var(--tf-ink-500); }
.m-countlink:hover span { text-decoration: underline; }
.m-countlink:focus-visible { outline: 2px solid var(--tf-ocean-800); outline-offset: 2px; border-radius: 6px; }

/* Desktop density: pointer devices get calmer 40px controls. Phones keep the 44px touch rule above. */
@media (min-width: 861px) {
  .m-seg > button { min-height: 38px; }
  .m-countlink { min-height: 32px; }
  .m-chip-btn--filter { min-height: 30px; padding: 0 11px; font-size: .75rem; }
  .m-table-bar .m-field input, .m-table-bar .m-field select { min-height: 40px; font-size: .875rem; padding-top: 0; padding-bottom: 0; }
  .m-table-bar .m-btn { min-height: 40px; }
  .m-search.m-search--compact { min-height: 40px; }
  .m-search.m-search--compact input { min-height: 38px; font-size: .875rem; }
}

@media (max-width: 860px) {
  /* A phone's filter bar is two columns, not a tall stack; the quiet action takes its own row. */
  .m-table-bar { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; align-items: end; }
  .m-table-bar .m-table-action { grid-column: 1 / -1; justify-self: start; }
}

/* Desktop rhythm for the board lanes: real lanes that fill the viewport, with air between the cards. */
@media (min-width: 861px) {
  .m-board-col { gap: 12px; padding: 14px 14px 18px; min-height: max(380px, calc(100vh - 340px)); }
  .m-board-colh { margin: 0 -14px 2px; padding: 8px 18px 12px; border-bottom: 1px solid var(--tf-ink-100); }
}

/* A whole table row that opens something: pointer, a visible hover and focus. Controls inside it (a tag, the row action) do not also open it. */
.m-table tbody tr.m-table-clickable { cursor: pointer; }
.m-table tbody tr.m-table-clickable:focus-visible { outline: 2px solid var(--tf-ocean-800); outline-offset: -2px; background: var(--tf-aqua-050); }
/* A tag that DOES something (a button), as opposed to a plain pill that only informs. */
.m-pill--action { border: 0; font-family: var(--font-sans); cursor: pointer; }
.m-pill--action:hover { filter: brightness(.95); text-decoration: underline; }
.m-pill--action:focus-visible { outline: 2px solid var(--tf-ocean-800); outline-offset: 1px; }
