/* ===================================================================
   TDS COMPONENTS & PATTERNS
   =================================================================== */

.tds-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-weight: 600;
  border: none;
  cursor: pointer;
  border-radius: var(--tds-radius-btn);
  font-family: inherit;
  text-decoration: none;
  gap: 6px;
}
.tds-btn--md { padding: 12px 20px; font-size: 14px; }
.tds-btn--sm { padding: 8px 14px; font-size: 12px; border-radius: 12px; }
.tds-btn--primary { background: var(--tds-blue); color: var(--tds-ink-on-accent); }
/* A disabled button LOOKS disabled (0.1.50). Without this rule a
   `<c-button disabled>` kept its full primary blue — measured on a consumer's
   « Sign out the other sessions » with one session: the page said the act
   was unavailable while the button shouted the opposite. Opacity, no
   pointer, no spring: `.tds-tap:active` must not bounce a dead control. */
.tds-btn:disabled, .tds-btn[aria-disabled="true"] {
  opacity: 0.45;
  cursor: not-allowed;
  pointer-events: none;
}
.tds-btn--primary:hover { background: var(--tds-blue-hover); }
.tds-btn--secondary { background: var(--tds-blue-soft); color: var(--tds-blue); }
/* An anchor wearing .tds-btn is a button: no underline, no visited tint —
   callers kept repairing this inline (user-seen on a tel: call row). */
a.tds-btn, a.tds-btn:visited, a.tds-btn:hover { text-decoration: none; }
.tds-btn--subtle { background: var(--tds-bg-subtle); color: var(--tds-ink-primary); }
.tds-btn--danger { background: var(--tds-ruby-soft); color: var(--tds-ruby); }

.tds-box, .tds-card {
  background: var(--tds-card);
  border-radius: var(--tds-radius-card);
  padding: clamp(18px, 2.5vw, 24px);
  border: 1px solid var(--tds-border);
  box-shadow: var(--tds-shadow-card);
}
.tds-card-header { display: flex; justify-content: space-between; align-items: flex-start; }
.tds-card-title { margin: 0; font-size: 17px; font-weight: 700; color: var(--tds-ink-primary); }
.tds-card-subtitle { margin: 4px 0 0 0; font-size: 13px; color: var(--tds-ink-secondary); }
.tds-card-body { color: var(--tds-ink-primary); }
.tds-card-header + .tds-card-body { margin-top: 16px; }
.tds-card-actions { margin-top: 18px; }

.tds-list-item {
  background: var(--tds-card);
  border-bottom: 1px solid var(--tds-border);
  color: var(--tds-ink-primary);
}
.tds-list-item:last-child { border-bottom: none; }

.tds-badge {
  font-size: 11px;
  font-weight: 700;
  padding: 4px 8px;
  border-radius: var(--tds-radius-badge);
  display: inline-flex;
  align-items: center;
  white-space: nowrap;   /* a badge is one word-shape: « EN PAUSE » must never split (fleetlens #123) */
  text-transform: uppercase;
  letter-spacing: 0.02em;
}
.tds-badge--blue { background: var(--tds-blue-soft); color: var(--tds-blue); }
.tds-badge--green { background: var(--tds-emerald-soft); color: var(--tds-emerald); }
.tds-badge--red { background: var(--tds-ruby-soft); color: var(--tds-ruby); }
.tds-badge--gray { background: var(--tds-bg-subtle); color: var(--tds-ink-secondary); }

.tds-nav-desktop {
  display: none;
  background: var(--tds-card);
  border-bottom: 1px solid var(--tds-border);
  position: sticky;
  top: 0;
  z-index: 40;
}
@media (min-width: 768px) {
  .tds-nav-desktop { display: block; }
}
.tds-nav-desktop-inner {
  max-width: var(--shell-max-width);
  margin: 0 auto;
  height: var(--nav-height-desktop);
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 32px;
}
.tds-nav-mobile {
  position: fixed;
  bottom: 0;
  left: 0;
  right: 0;
  display: flex;
  justify-content: center;
  padding: var(--tds-dock-gap) 16px max(var(--tds-dock-gap), env(safe-area-inset-bottom)) 16px;
  background: linear-gradient(to top, var(--tds-canvas) 75%, var(--tds-canvas-fade));
  z-index: 50;
  pointer-events: none;
}
@media (min-width: 768px) {
  .tds-nav-mobile { display: none; }
}
.tds-nav-mobile-bar {
  pointer-events: auto;
  background: var(--tds-dock-bg);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  border: 1px solid var(--tds-dock-border);
  border-radius: var(--tds-radius-pill);
  display: flex;
  align-items: center;
  justify-content: space-around;
  width: 100%;
  max-width: 380px;
  min-height: var(--tds-dock-bar);   /* the token is a promise the pill keeps */
  padding: 6px;
  box-shadow: var(--tds-shadow-dock);
}
.tds-nav-item {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  text-decoration: none;
  color: var(--tds-ink-secondary);
  font-size: 11px;
  font-weight: 500;
  padding: 6px 12px;
  border-radius: 12px;
  transition: color 0.15s ease;
}
.tds-nav-item.active {
  color: var(--tds-blue);
  font-weight: 600;
}
.tds-nav-item svg {
  width: 22px;
  height: 22px;
  stroke-width: 2.2;
}

.tds-data-table {
  width: 100%;
  border-collapse: collapse;
}
@media (max-width: 767px) {
  .tds-data-table, .tds-data-table tbody, .tds-data-table tr, .tds-data-table td {
    display: block;
    width: 100%;
  }
  .tds-data-table thead { display: none; }
  .tds-data-table tr {
    background: var(--tds-card);
    border: 1px solid var(--tds-border);
    border-radius: var(--tds-radius-card);
    padding: 16px;
    margin-bottom: 12px;
  }
  /* A card row is label ⟷ value, and the two must never touch: without a
     gap a long label ran straight into a long value (« Administrateur·trice
     president@bb-sierre.ch » on a consumer's console, 0.1.58), and without
     a wrapping rule the value broke mid-word or pushed the card. The value
     side also has to be ONE box: a cell holding two elements laid them out
     side by side here while they stacked on the desktop table — wrap them
     in a single element when a cell carries two levels (LAW 7). */
  .tds-data-table td {
    padding: 6px 0;
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 12px;
    overflow-wrap: anywhere;
    border: none;
  }
  .tds-data-table td::before { flex: 0 1 auto; }
  .tds-data-table td > * { min-width: 0; }
  .tds-data-table td::before {
    content: attr(data-label);
    font-size: 12px;
    font-weight: 600;
    color: var(--tds-ink-secondary);
  }
  /* LAW 7 — a cell without data-label is the card's header on mobile: the
     dominant name spans the full width and stacks, instead of being squeezed
     into a label/value flex row where long names wrap badly. */
  .tds-data-table td:not([data-label]) {
    display: block;
    padding: 0 0 8px 0;
    overflow-wrap: anywhere;
  }
  .tds-data-table td:not([data-label])::before { content: none; }
}
@media (min-width: 768px) {
  .tds-data-table {
    background: var(--tds-card);
    border: 1px solid var(--tds-border);
    border-radius: 16px;
    /* No overflow: hidden - action menus must escape the table. The table's
       own background respects the radius; only the thead cells paint square
       corners, so round those two explicitly. */
  }
  .tds-data-table thead tr:first-child th:first-child { border-top-left-radius: 15px; }
  .tds-data-table thead tr:first-child th:last-child { border-top-right-radius: 15px; }
  /* Flush inside a padding-less card (register recipe: card wraps table +
     pagination): the card is the frame — drop the table's own border and
     follow the card's larger organic radius, or the square thead corners
     poke out of the rounded card (visible in dark mode). */
  .tds-card > .tds-data-table {
    border: none;
    border-radius: var(--tds-radius-card) var(--tds-radius-card) 0 0;
  }
  .tds-card > .tds-data-table thead tr:first-child th:first-child { border-top-left-radius: calc(var(--tds-radius-card) - 1px); }
  .tds-card > .tds-data-table thead tr:first-child th:last-child { border-top-right-radius: calc(var(--tds-radius-card) - 1px); }
  .tds-card > .tds-data-table + div {
    border-bottom-left-radius: calc(var(--tds-radius-card) - 1px);
    border-bottom-right-radius: calc(var(--tds-radius-card) - 1px);
  }
  .tds-data-table th {
    background: var(--tds-bg-table-th);
    color: var(--tds-ink-secondary);
    font-size: 13px;
    font-weight: 600;
    padding: 14px 18px;
    text-align: left;
    border-bottom: 1px solid var(--tds-border);
  }
  .tds-data-table td {
    padding: 14px 18px;
    font-size: 14px;
    border-bottom: 1px solid var(--tds-border);
    color: var(--tds-ink-primary);
  }
  .tds-data-table tr:last-child td { border-bottom: none; }
}

#crud-table-body:has(tr[id^="row-"]) #empty-state-row {
  display: none !important;
}

tr.htmx-swapping {
  opacity: 0;
  transform: translateX(12px) scale(0.98);
  transition: opacity 0.25s cubic-bezier(0.2, 0, 0, 1), transform 0.25s cubic-bezier(0.2, 0, 0, 1);
}
@keyframes tds-fade-down {
  from { opacity: 0; transform: translateY(-8px) scale(0.98); }
  to { opacity: 1; transform: translateY(0) scale(1); }
}
.tds-row-new {
  animation: tds-fade-down 0.28s cubic-bezier(0.2, 0, 0, 1) forwards;
}

.tds-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.45);
  backdrop-filter: blur(4px);
  z-index: 99;
}
.tds-bottom-sheet {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  background: var(--tds-card);
  border-top-left-radius: var(--tds-radius-sheet);
  border-top-right-radius: var(--tds-radius-sheet);
  padding: 12px 24px 32px 24px;
  z-index: 100;
  max-width: 540px;
  margin: 0 auto;
  box-shadow: var(--tds-shadow-sheet);
  /* A tall sheet must scroll INSIDE itself on mobile too — the body is
     scroll-locked, so without this a long form (import mapping, funnels)
     pushed its own handle and title above the viewport with no way to
     reach them (found on the import wizard at 375px). The desktop modal
     override below tightens the cap to 90dvh. */
  max-height: calc(100dvh - 24px);
  overflow-y: auto;
}
@media (min-width: 768px) {
  .tds-bottom-sheet {
    /* Centered WITHOUT transform: a transformed ancestor becomes the
       containing block of every position:fixed descendant, which imprisoned
       a nested select_sheet's backdrop inside the modal's box (an ugly
       hard-edged gray slab instead of a full-viewport veil). Margin-auto
       centering keeps overlays nested in sheets viewport-fixed. */
    top: 0;
    bottom: 0;
    height: fit-content;
    max-height: 90dvh;
    overflow-y: auto;
    margin: auto;
    border-radius: var(--tds-radius-sheet);
    padding: 28px;
  }
}
.tds-sheet-handle {
  width: 40px;
  height: 5px;
  background: var(--tds-border);
  border-radius: 99px;
  margin: 0 auto 16px auto;
}
@media (min-width: 768px) {
  .tds-sheet-handle { display: none; }
}
.tds-sheet-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 20px;
}
.tds-sheet-title { margin: 0; font-size: 20px; font-weight: 700; }
.tds-sheet-close {
  background: none;
  border: none;
  font-size: 16px;
  color: var(--tds-ink-secondary);
  cursor: pointer;
  /* 44px minimum touch target (mobile is the primary target) */
  min-width: 44px;
  min-height: 44px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 12px;
}

.tds-drawer-panel {
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  width: 100%;
  max-width: 520px;
  background: var(--tds-card);
  box-shadow: var(--tds-shadow-drawer);
  z-index: 100;
  display: flex;
  flex-direction: column;
  padding: 28px;
  overflow-y: auto;
}
.tds-drawer-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 24px;
  padding-bottom: 14px;
  border-bottom: 1px solid var(--tds-border);
}
.tds-drawer-title { margin: 0; font-size: 19px; font-weight: 700; }
.tds-drawer-close {
  background: none;
  border: none;
  font-size: 16px;
  min-width: 44px;
  min-height: 44px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 12px;
  color: var(--tds-ink-secondary);
  cursor: pointer;
  padding: 6px;
  border-radius: 8px;
}

.opacity-0 { opacity: 0; }
.opacity-100 { opacity: 1; }
.translate-y-full { transform: translateY(100%); }
.translate-y-4 { transform: translateY(16px); }
.translate-y-0 { transform: translateY(0); }
.translate-x-full { transform: translateX(100%); }
.translate-x-0 { transform: translateX(0); }
.tds-fade-enter, .tds-fade-leave { transition: opacity 0.2s ease; }
.tds-slide-enter, .tds-slide-leave { transition: transform 0.25s cubic-bezier(0.2, 0, 0, 1); }
.tds-drawer-enter, .tds-drawer-leave { transition: transform 0.28s cubic-bezier(0.2, 0, 0, 1); }
/* Off-screen state: from the right on desktop, from the BOTTOM on mobile */
.tds-drawer-off { transform: translateX(100%); }

/* LAW 8 — on mobile the drawer morphs into a full-height sheet rising from
   the bottom; a side panel is a desktop pattern. */
@media (max-width: 767px) {
  .tds-drawer-panel {
    top: auto;
    left: 0;
    height: 92dvh;
    max-width: none;
    border-radius: var(--tds-radius-sheet) var(--tds-radius-sheet) 0 0;
    padding: 14px 16px calc(14px + env(safe-area-inset-bottom)) 16px;
    box-shadow: var(--tds-shadow-sheet);
  }
  .tds-drawer-off { transform: translateY(100%); }
}

.tds-step-bar {
  flex: 1;
  height: 4px;
  background: var(--tds-border);
  border-radius: 99px;
  transition: background-color 0.3s ease;
}
.tds-step-bar.is-active { background: var(--tds-blue); }

.tds-giant-input {
  width: 100%;
  font-size: clamp(24px, 4vw, 32px);
  font-weight: 700;
  color: var(--tds-ink-primary);
  background: transparent;
  border: none;
  border-bottom: 2px solid var(--tds-border);
  padding: 12px 0;
  border-radius: 0;
  outline: none;
  font-family: inherit;
  transition: border-color 0.2s ease;
}
.tds-giant-input:focus { border-color: var(--tds-blue); }

.tds-form-group { display: flex; flex-direction: column; gap: 6px; }
.tds-input-label { font-size: 13px; font-weight: 600; color: var(--tds-ink-secondary); }
.tds-input {
  background: var(--tds-bg-input);
  border: 1px solid var(--tds-border);
  border-radius: 12px;
  padding: 12px 14px;
  font-size: 15px;
  color: var(--tds-ink-primary);
  outline: none;
  font-family: inherit;
}
.tds-input:focus { border-color: var(--tds-blue); background: var(--tds-card); }
.tds-input.is-invalid { border-color: var(--tds-ruby); background: var(--tds-ruby-soft); }

.tds-segmented-control {
  background: var(--tds-bg-subtle);
  padding: 3px;
  border-radius: 14px;
  display: flex;
  gap: 2px;
  overflow-x: auto;
  scrollbar-width: none;
}
.tds-segmented-control::-webkit-scrollbar { display: none; }
/* An item never wraps its label (0.1.53): `flex: 1` alone let four
   « Active (15) » pills shrink until every label broke over two lines at
   375 px — the squeeze §9 forbids. Items keep their natural width, share
   the slack when the row fits, and the control SCROLLS when it does not. */
.tds-segment-item {
  flex: 1 0 auto;
  white-space: nowrap;
  padding: 8px 14px;
  font-size: 13px;
  font-weight: 600;
  color: var(--tds-ink-secondary);
  background: transparent;
  border: none;
  border-radius: 11px;
  cursor: pointer;
  transition: all 0.15s ease;
}
.tds-segment-item.is-active {
  background: var(--tds-card);
  color: var(--tds-ink-primary);
  box-shadow: var(--tds-shadow-segment);
}

.tds-toast-container {
  position: fixed;
  bottom: calc(var(--tds-dock-clear) + 4px);
  left: 0;
  right: 0;
  display: flex;
  justify-content: center;
  z-index: 110;
  pointer-events: none;
}
.tds-toast {
  pointer-events: auto;
  background: var(--tds-toast-bg);
  border: 1px solid var(--tds-toast-border);
  backdrop-filter: blur(8px);
  color: var(--tds-toast-ink);
  padding: 12px 20px;
  border-radius: var(--tds-radius-pill);
  font-size: 14px;
  font-weight: 500;
  box-shadow: var(--tds-shadow-toast);
}
.tds-toast--info { background: var(--tds-toast-bg); }
.tds-toast--success { background: rgba(5, 150, 105, 0.95); }
.tds-toast--danger { background: rgba(240, 68, 82, 0.95); }
.tds-toast-enter, .tds-toast-leave { transition: all 0.2s cubic-bezier(0.2, 0, 0, 1); }

.tds-skeleton {
  background: linear-gradient(90deg, var(--tds-shimmer-base) 25%, var(--tds-shimmer-highlight) 50%, var(--tds-shimmer-base) 75%);
  background-size: 200% 100%;
  animation: tds-shimmer 1.4s linear infinite, tds-skeleton-breathe 2.8s ease-in-out infinite;
}
@keyframes tds-shimmer {
  0% { background-position: 200% 0; }
  100% { background-position: -200% 0; }
}
@keyframes tds-skeleton-breathe {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.72; }
}

.tds-spinner {
  width: 18px;
  height: 18px;
  border: 2px solid var(--tds-border);
  border-top-color: var(--tds-blue);
  border-radius: 50%;
  animation: tds-spin 0.6s linear infinite;
  display: none;
}
.htmx-request.tds-spinner, .htmx-request .tds-spinner { display: inline-block; }
@keyframes tds-spin { to { transform: rotate(360deg); } }

/* ===================================================================
   LAW 4 — CONTINUOUS REACHABILITY (STICKY THUMB CTA)
   =================================================================== */
.tds-sticky-cta {
  position: fixed;
  bottom: 0;
  left: 0;
  right: 0;
  padding: 12px 20px calc(12px + env(safe-area-inset-bottom)) 20px;
  background: linear-gradient(to top, var(--tds-canvas) 80%, var(--tds-canvas-fade));
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  z-index: 45;
  display: flex;
  justify-content: center;
  pointer-events: none;
}
.tds-sticky-cta-inner {
  width: 100%;
  max-width: var(--content-max-width);
  pointer-events: auto;
}

/* ===================================================================
   LAW 3 — FORGIVENESS (UNDO TOAST)
   =================================================================== */
.tds-toast-body { display: flex; align-items: center; gap: 4px; }
.tds-toast-sep { opacity: 0.45; padding: 0 2px; }
.tds-toast-undo {
  background: none;
  border: none;
  padding: 2px 4px;
  font: inherit;
  font-weight: 700;
  color: #8ec5ff;
  cursor: pointer;
  border-radius: 6px;
}
.tds-toast-undo:hover { text-decoration: underline; }

/* ===================================================================
   LAW 6 — BENEVOLENT EMPTY STATES
   =================================================================== */
.tds-empty-state {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  gap: 6px;
  padding: 48px 24px;
}
.tds-empty-state-icon {
  font-size: 30px;
  line-height: 1;
  margin-bottom: 6px;
  opacity: 0.7;
}
.tds-empty-state-title {
  margin: 0;
  font-size: 16px;
  font-weight: 700;
  color: var(--tds-ink-primary);
}
.tds-empty-state-description {
  margin: 0;
  font-size: 13px;
  line-height: 1.5;
  max-width: 34ch;
  color: var(--tds-ink-secondary);
}
.tds-empty-state-action { margin-top: 14px; }
/* An empty-state row must never inherit the mobile card morph of a data row. */
@media (max-width: 767px) {
  .tds-data-table tr#empty-state-row { padding: 0; border: none; background: none; }
  .tds-data-table tr#empty-state-row td { display: block; }
  .tds-data-table tr#empty-state-row td::before { content: none; }
}

/* ===================================================================
   LAW 2 — "ONE BIG QUESTION" FUNNEL PROGRESS
   =================================================================== */
.tds-step-bar-group {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-bottom: 20px;
}

/* ===================================================================
   LAW 7 — FAST VISUAL SCANNING (2-LEVEL ROWS)
   =================================================================== */
.tds-row-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 3px; }
.tds-row-line {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
}
/* Opt-in for rows whose slot carries a control CLUSTER (two buttons, a
   badge + button): when space runs out the controls wrap BELOW the text
   instead of crushing the label to a few characters (user-found twice at
   375px: consent rows, then a long email vs Make primary + remove). Give
   the slot cluster margin-left:auto so it right-aligns on both lines. */
.tds-list-item.tds-row-wrap { flex-wrap: wrap; row-gap: 10px; }
.tds-list-item.tds-row-wrap .tds-row-main { min-width: 200px; }
/* A row's controls sit AFTER the text block (0.1.54). With `tds-row-wrap`
   the text block keeps its natural width, and the value or badge at its
   right edge touched the first button (measured on two consumers' task
   pages and two-factor rows); and when the cluster wrapped BELOW the text,
   nothing separated it from a two-line sublabel — hence the row-gap above.
   Padding on the text block, not a margin on the controls: the controls
   often carry `margin-left: auto` inline, which would win over a stylesheet
   margin. */
.tds-list-item > .tds-row-main:not(:last-child) { padding-right: 12px; }

.tds-row-label {
  font-size: 15px;
  font-weight: 600;
  color: var(--tds-ink-primary);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  min-width: 0;   /* a flex child defaults to min-width:auto — without this the ellipsis never fires and the row widens the page (fleetlens #128, 375px) */
}
.tds-row-value {
  font-size: 15px;
  font-weight: 700;
  color: var(--tds-ink-primary);
  font-variant-numeric: tabular-nums;
  flex-shrink: 0;
}
.tds-row-meta {
  font-size: 12px;
  color: var(--tds-ink-secondary);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  min-width: 0;
}
/* Opt-in for SENTENCE rows (an attention list, a summary line): the text
   wraps over lines instead of being cut to an ellipsis — a cut sentence
   hides the point. Names and key-value rows keep the one-line default. */
.tds-list-item.tds-row-text-wrap .tds-row-label,
.tds-list-item.tds-row-text-wrap .tds-row-meta { white-space: normal; }
@media (max-width: 767px) {
  /* On a phone the sublabel is nearly always a sentence, and 375 px of
     ellipsis hides the half that carries the meaning ("Write to the
     FleetLens team — your netw…"). It wraps instead: the row grows a line
     and keeps its sense. The LABEL stays on one line, so the row still
     reads as a row. Above 768 px the one-line ellipsis is the design. */
  .tds-row-meta { white-space: normal; }
}
.tds-row-chevron {
  font-size: 18px;
  line-height: 1;
  color: var(--tds-ink-muted);
  flex-shrink: 0;
  margin-left: 10px;
}

/* ===================================================================
   LAW 8 — SPATIAL COHERENCE
   =================================================================== */
@keyframes tds-slide-in-right {
  from { opacity: 0; transform: translateX(24px); }
  to { opacity: 1; transform: none; }
}
/* Drifting forward in a funnel. */
.tds-forward-enter {
  /* Fill BACKWARDS, never both/forwards: a persisted final keyframe —
     even `transform: none` — is serialized as an identity matrix and
     stays a containing block for every position:fixed descendant, so a
     select_sheet inside the fragment opened its modal INSIDE the drawer
     (measured: computed transform matrix(1,0,0,1,0,0) with `both`,
     `none` with `backwards`). After the animation the wrapper reverts
     to its stylesheet state: no transform at all. */
  animation: tds-slide-in-right 0.28s cubic-bezier(0.2, 0, 0, 1) backwards;
}
/* Dismissing: translate 12px right and collapse height (250-300ms). */
.tds-swap-out.htmx-swapping, .tds-list-item.htmx-swapping {
  opacity: 0;
  transform: translateX(12px);
  max-height: 0;
  padding-top: 0;
  padding-bottom: 0;
  overflow: hidden;
  transition: opacity 0.28s cubic-bezier(0.2, 0, 0, 1),
              transform 0.28s cubic-bezier(0.2, 0, 0, 1),
              max-height 0.28s cubic-bezier(0.2, 0, 0, 1),
              padding 0.28s cubic-bezier(0.2, 0, 0, 1);
}

/* ===================================================================
   COMPLETION — SPRING CHECKMARK
   =================================================================== */
@keyframes tds-scale-bounce {
  0% { transform: scale(0.4); opacity: 0; }
  60% { transform: scale(1.08); opacity: 1; }
  100% { transform: scale(1); opacity: 1; }
}
.tds-completion-check {
  width: 72px;
  height: 72px;
  border-radius: 50%;
  background: var(--tds-blue-soft);
  color: var(--tds-blue);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 34px;
  font-weight: 800;
  animation: tds-scale-bounce 0.5s cubic-bezier(0.34, 1.56, 0.64, 1) both;
}

/* ===================================================================
   SEARCH & FILTER
   =================================================================== */
.tds-search-field { position: relative; display: flex; align-items: center; }
/* The component ships its own one-tap ✕ — WebKit's built-in cancel button
   next to it reads as TWO crosses. */
.tds-search-field input[type="search"]::-webkit-search-cancel-button { -webkit-appearance: none; appearance: none; display: none; }
.tds-search-field .tds-input { width: 100%; padding-left: 38px; }
.tds-search-icon {
  position: absolute;
  left: 14px;
  font-size: 13px;
  color: var(--tds-ink-muted);
  pointer-events: none;
}
.tds-search-field .tds-spinner { position: absolute; right: 14px; }

/* ===================================================================
   SELECTION CONTROLS — CHECKBOX / RADIO TILE / SWITCH / STEPPER
   =================================================================== */
.tds-checkbox {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  cursor: pointer;
}
.tds-checkbox input {
  position: absolute;
  opacity: 0;
  pointer-events: none;
}
.tds-checkbox-box {
  width: 22px;
  height: 22px;
  border-radius: 7px;
  border: 1.5px solid var(--tds-border);
  background: var(--tds-bg-input);
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  transition: background 0.18s ease, border-color 0.18s ease;
}
.tds-checkbox-box svg {
  width: 13px;
  height: 13px;
  fill: none;
  stroke: var(--tds-ink-on-accent);
  stroke-width: 2.5;
  stroke-linecap: round;
  stroke-linejoin: round;
  stroke-dasharray: 20;
  stroke-dashoffset: 20;
  transition: stroke-dashoffset 0.22s ease 0.05s;
}
.tds-checkbox input:checked + .tds-checkbox-box {
  background: var(--tds-blue);
  border-color: var(--tds-blue);
}
.tds-checkbox input:checked + .tds-checkbox-box svg { stroke-dashoffset: 0; }
.tds-checkbox input:focus-visible + .tds-checkbox-box {
  outline: 3px solid var(--tds-blue-glow);
  outline-offset: 1px;
}
.tds-checkbox-label { font-size: 14px; color: var(--tds-ink-primary); }

.tds-radio-group { display: grid; grid-template-columns: minmax(0, 1fr); gap: 10px; }
.tds-radio-tile {
  position: relative;
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 14px 16px;
  border: 1.5px solid var(--tds-border);
  border-radius: 16px;
  background: var(--tds-card);
  cursor: pointer;
  transition: border-color 0.15s ease, background 0.15s ease;
}
.tds-radio-tile input {
  position: absolute;
  opacity: 0;
  pointer-events: none;
}
.tds-radio-dot {
  width: 20px;
  height: 20px;
  border-radius: 50%;
  border: 1.5px solid var(--tds-border);
  background: var(--tds-bg-input);
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  transition: background 0.15s ease, border-color 0.15s ease;
}
.tds-radio-dot::after {
  content: "";
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--tds-ink-on-accent);
  transform: scale(0);
  transition: transform 0.18s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.tds-radio-tile:has(input:checked) {
  border-color: var(--tds-blue);
  background: var(--tds-blue-soft);
}
.tds-radio-tile:has(input:checked) .tds-radio-dot {
  background: var(--tds-blue);
  border-color: var(--tds-blue);
}
.tds-radio-tile:has(input:checked) .tds-radio-dot::after { transform: scale(1); }
.tds-radio-tile:has(input:focus-visible) {
  outline: 3px solid var(--tds-blue-glow);
  outline-offset: 1px;
}
.tds-radio-tile-title { display: block; font-size: 14px; font-weight: 650; color: var(--tds-ink-primary); }
.tds-radio-tile-desc { display: block; font-size: 12px; color: var(--tds-ink-secondary); margin-top: 2px; }
.tds-radio-tile-meta {
  margin-left: auto;
  font-size: 14px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--tds-ink-primary);
  flex-shrink: 0;
}

.tds-switch {
  display: inline-flex;
  align-items: center;
  gap: 12px;
  cursor: pointer;
}
.tds-switch input {
  position: absolute;
  opacity: 0;
  pointer-events: none;
}
.tds-switch-track {
  width: 44px;
  height: 26px;
  border-radius: 13px;
  background: var(--tds-bg-subtle);
  position: relative;
  flex-shrink: 0;
  transition: background 0.2s ease;
}
.tds-switch-thumb {
  position: absolute;
  top: 3px;
  left: 3px;
  width: 20px;
  height: 20px;
  border-radius: 50%;
  background: var(--tds-ink-on-accent);
  border: 1px solid var(--tds-border);
  transition: transform 0.22s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.tds-switch input:checked + .tds-switch-track { background: var(--tds-blue); }
.tds-switch input:checked + .tds-switch-track .tds-switch-thumb {
  transform: translateX(18px);
  border-color: transparent;
}
.tds-switch input:focus-visible + .tds-switch-track {
  outline: 3px solid var(--tds-blue-glow);
  outline-offset: 1px;
}

.tds-stepper {
  display: inline-flex;
  align-items: center;
  border: 1px solid var(--tds-border);
  border-radius: 12px;
  background: var(--tds-bg-input);
}
.tds-stepper button {
  width: 38px;
  height: 38px;
  border: none;
  background: none;
  font-size: 18px;
  color: var(--tds-blue);
  cursor: pointer;
}
.tds-stepper button:disabled { color: var(--tds-ink-muted); opacity: 0.4; cursor: not-allowed; }
.tds-stepper-value {
  min-width: 40px;
  text-align: center;
  font-size: 15px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--tds-ink-primary);
}

/* ===================================================================
   SELECT SHEET — TOSS-STYLE PICKER
   =================================================================== */
.tds-select-trigger {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  width: 100%;
  cursor: pointer;
  text-align: left;
}
.tds-select-option {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 13px 14px;
  border: none;
  border-radius: 12px;
  background: none;
  cursor: pointer;
  font-size: 15px;
  color: var(--tds-ink-primary);
  text-align: left;
}
.tds-select-option:hover { background: var(--tds-bg-subtle); }
.tds-select-option.is-active { color: var(--tds-blue); font-weight: 700; }
.tds-select-option.is-active::after { content: "✓"; flex-shrink: 0; }

/* ===================================================================
   FILE UPLOAD — DRAG & DROP ZONE
   =================================================================== */
.tds-file-upload {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 6px;
  padding: 28px 20px;
  border: 1.5px dashed var(--tds-border);
  border-radius: 16px;
  background: var(--tds-bg-input);
  cursor: pointer;
  text-align: center;
  transition: border-color 0.15s ease, background 0.15s ease;
}
.tds-file-upload:hover, .tds-file-upload.is-dragging {
  border-color: var(--tds-blue);
  background: var(--tds-blue-soft);
}
.tds-file-upload-icon { font-size: 24px; opacity: 0.75; }
.tds-file-upload-title { font-size: 14px; font-weight: 600; color: var(--tds-ink-primary); }
.tds-file-upload-hint { font-size: 12px; color: var(--tds-ink-muted); }
.tds-file-chip {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 6px 12px;
  border-radius: 10px;
  background: var(--tds-bg-subtle);
  font-size: 13px;
  color: var(--tds-ink-primary);
}

/* ===================================================================
   DATA & METRICS — STAT CARD / PROGRESS / BANNER / AVATAR
   =================================================================== */
.tds-stat-card {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 18px;
  border: 1px solid var(--tds-border);
  border-radius: 20px;
  background: var(--tds-card);
  box-shadow: var(--tds-shadow-card);
  min-width: 0;
  /* The card is a query container so its value can size itself to the
     card (0.1.61): five cards on a 1128 px desktop gave each 165 px of
     content, and « 2'449.65 CHF » at 26 px needs 175 — the one figure a
     treasurer opened the screen for was cut to « 2'449.65 C… ». */
  container-type: inline-size;
}
.tds-stat-label { font-size: 12px; font-weight: 600; color: var(--tds-ink-secondary); }
.tds-stat-value {
  /* 26 px when the card is wide, down to 18 px as it narrows — 13 % of
     the card's content width: a 13-character Swiss amount fits a 165 px
     card at 21.5 px. Past that the ellipsis and the tooltip remain the
     honest fallback, never a clipped figure at full size. */
  font-size: clamp(18px, 13cqi, 26px);
  font-weight: 800;
  color: var(--tds-ink-primary);
  font-variant-numeric: tabular-nums;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.tds-stat-delta { font-size: 12px; font-weight: 700; }
.tds-stat-delta--up { color: var(--tds-emerald); }
.tds-stat-delta--down { color: var(--tds-ruby); }
.tds-stat-hint { font-size: 12px; color: var(--tds-ink-muted); }

.tds-progress { display: flex; flex-direction: column; gap: 6px; }
.tds-progress-label {
  display: flex;
  justify-content: space-between;
  font-size: 12px;
  font-weight: 600;
  color: var(--tds-ink-secondary);
  font-variant-numeric: tabular-nums;
}
.tds-progress-track {
  height: 8px;
  border-radius: 4px;
  background: var(--tds-bg-subtle);
  overflow: hidden;
}
.tds-progress-fill {
  height: 100%;
  border-radius: 4px;
  background: var(--tds-blue);
  transition: width 0.4s cubic-bezier(0.2, 0, 0, 1);
}

.tds-banner {
  display: flex;
  gap: 12px;
  align-items: flex-start;
  padding: 14px 16px;
  border-radius: 14px;
}
.tds-banner--info { background: var(--tds-blue-soft); }
.tds-banner--success { background: var(--tds-emerald-soft); }
.tds-banner--danger { background: var(--tds-ruby-soft); }
.tds-banner-icon { font-size: 18px; line-height: 1.3; }
.tds-banner-title { font-size: 14px; font-weight: 700; color: var(--tds-ink-primary); }
.tds-banner-body { font-size: 13px; line-height: 1.5; color: var(--tds-ink-secondary); }
.tds-banner-title + .tds-banner-body { margin-top: 2px; }

.tds-avatar {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: var(--tds-blue-soft);
  color: var(--tds-blue);
  font-weight: 700;
  overflow: hidden;
  flex-shrink: 0;
  user-select: none;
}
.tds-avatar--sm { width: 28px; height: 28px; font-size: 11px; }
.tds-avatar--md { width: 36px; height: 36px; font-size: 13px; }
.tds-avatar--lg { width: 48px; height: 48px; font-size: 16px; }
.tds-avatar img { width: 100%; height: 100%; object-fit: cover; }
.tds-avatar-stack { display: inline-flex; align-items: center; }
.tds-avatar-stack .tds-avatar { border: 2px solid var(--tds-card); margin-left: -8px; }
.tds-avatar-stack .tds-avatar:first-child { margin-left: 0; }

/* Search clear button (sits left of the spinner slot) */
.tds-search-clear {
  position: absolute;
  right: 38px;
  width: 22px;
  height: 22px;
  border: none;
  border-radius: 50%;
  background: var(--tds-bg-subtle);
  color: var(--tds-ink-secondary);
  font-size: 11px;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
}

/* ===================================================================
   SORTABLE TABLE HEADERS
   =================================================================== */
.tds-data-table th.tds-th-sort { padding: 0; }
.tds-th-sort-btn {
  width: 100%;
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 14px 18px;
  border: none;
  background: none;
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  color: inherit;
  cursor: pointer;
  white-space: nowrap;
}
.tds-th-sort--right .tds-th-sort-btn { justify-content: flex-end; }
.tds-th-sort-icon { font-size: 10px; color: var(--tds-ink-muted); }
.tds-th-sort-icon.is-active { color: var(--tds-blue); }

/* ===================================================================
   CALENDAR — MONTH PLANNING VIEW
   =================================================================== */
.tds-calendar {
  background: var(--tds-card);
  border: 1px solid var(--tds-border);
  border-radius: 20px;
  padding: 16px;
  box-shadow: var(--tds-shadow-card);
}
.tds-calendar-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 12px;
}
.tds-calendar-title { font-size: 15px; font-weight: 700; color: var(--tds-ink-primary); }
.tds-calendar-grid {
  display: grid;
  grid-template-columns: repeat(7, minmax(0, 1fr));
  gap: 4px;
}
.tds-calendar-weekdays {
  margin-bottom: 4px;
  font-size: 11px;
  font-weight: 600;
  color: var(--tds-ink-muted);
  text-align: center;
}
.tds-calendar-day {
  min-height: 72px;
  border-radius: 10px;
  padding: 6px;
  background: var(--tds-bg-input);
  display: flex;
  flex-direction: column;
  gap: 3px;
  min-width: 0;
}
.tds-calendar-day.is-outside { opacity: 0.35; background: transparent; }
.tds-calendar-day.is-today { outline: 2px solid var(--tds-blue); outline-offset: -2px; }
.tds-calendar-daynum {
  font-size: 11px;
  font-weight: 600;
  color: var(--tds-ink-secondary);
  font-variant-numeric: tabular-nums;
}
.tds-calendar-day.is-today .tds-calendar-daynum { color: var(--tds-blue); }
.tds-calendar-event {
  font-size: 10px;
  font-weight: 600;
  padding: 2px 5px;
  border-radius: 5px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.tds-calendar-event--blue { background: var(--tds-blue-soft); color: var(--tds-blue); }
.tds-calendar-event--green { background: var(--tds-emerald-soft); color: var(--tds-emerald); }
.tds-calendar-event--red { background: var(--tds-ruby-soft); color: var(--tds-ruby); }
.tds-calendar-event--gray { background: var(--tds-bg-subtle); color: var(--tds-ink-secondary); }
@media (max-width: 767px) {
  .tds-calendar-day { min-height: 46px; padding: 4px; }
  .tds-calendar-event {
    font-size: 0;
    width: 7px;
    height: 7px;
    padding: 0;
    border-radius: 50%;
    flex-shrink: 0;
  }
  .tds-calendar-event--blue { background: var(--tds-blue); }
  .tds-calendar-event--green { background: var(--tds-emerald); }
  .tds-calendar-event--red { background: var(--tds-ruby); }
  .tds-calendar-event--gray { background: var(--tds-ink-muted); }
}

/* ===================================================================
   ATTENDANCE GRID — FAST TACTILE CHECK-IN
   =================================================================== */
.tds-attendance {
  overflow-x: auto;
  border: 1px solid var(--tds-border);
  border-radius: 16px;
  background: var(--tds-card);
}
.tds-attendance-table { border-collapse: collapse; width: 100%; }
.tds-attendance-table th {
  background: var(--tds-bg-table-th);
  color: var(--tds-ink-secondary);
  font-size: 12px;
  font-weight: 600;
  padding: 10px 12px;
  text-align: center;
  border-bottom: 1px solid var(--tds-border);
  white-space: nowrap;
}
.tds-attendance-table td {
  padding: 6px 12px;
  text-align: center;
  border-bottom: 1px solid var(--tds-border);
}
.tds-attendance-table tr:last-child td { border-bottom: none; }
.tds-attendance-name {
  position: sticky;
  left: 0;
  background: var(--tds-card);
  text-align: left !important;
  font-size: 14px;
  font-weight: 600;
  color: var(--tds-ink-primary);
  white-space: nowrap;
  z-index: 1;
}
th.tds-attendance-name { background: var(--tds-bg-table-th); }
.tds-attendance-cell {
  width: 34px;
  height: 34px;
  border: none;
  border-radius: 10px;
  background: var(--tds-bg-subtle);
  color: var(--tds-ink-muted);
  font-size: 14px;
  font-weight: 700;
  cursor: pointer;
  transition: background 0.15s ease, color 0.15s ease;
}
.tds-attendance-cell.is-present { background: var(--tds-emerald-soft); color: var(--tds-emerald); }
.tds-attendance-cell.is-absent { background: var(--tds-ruby-soft); color: var(--tds-ruby); }
.tds-attendance-rate {
  font-size: 13px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--tds-ink-primary);
  text-align: right !important;
  white-space: nowrap;
}

/* ===================================================================
   TIMELINE — VERTICAL ACTIVITY FEED
   =================================================================== */
.tds-timeline {
  list-style: none;
  margin: 0;
  padding: 0;
}
.tds-timeline-item {
  position: relative;
  display: flex;
  gap: 14px;
  padding: 0 0 22px 0;
}
.tds-timeline-item:last-child { padding-bottom: 0; }
.tds-timeline-item::before {
  content: "";
  position: absolute;
  left: 13px;
  top: 28px;
  bottom: 0;
  width: 2px;
  background: var(--tds-border);
}
.tds-timeline-item:last-child::before { content: none; }
.tds-timeline-dot {
  width: 28px;
  height: 28px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 13px;
  flex-shrink: 0;
  z-index: 1;
}
.tds-timeline-dot--blue { background: var(--tds-blue-soft); color: var(--tds-blue); }
.tds-timeline-dot--green { background: var(--tds-emerald-soft); color: var(--tds-emerald); }
.tds-timeline-dot--red { background: var(--tds-ruby-soft); color: var(--tds-ruby); }
.tds-timeline-dot--gray { background: var(--tds-bg-subtle); color: var(--tds-ink-secondary); }
.tds-timeline-body { min-width: 0; padding-top: 4px; }
.tds-timeline-title {
  font-size: 14px;
  font-weight: 650;
  color: var(--tds-ink-primary);
  display: flex;
  align-items: baseline;
  gap: 8px;
  flex-wrap: wrap;
}
.tds-timeline-meta { font-size: 12px; font-weight: 500; color: var(--tds-ink-muted); }
.tds-timeline-sub { font-size: 13px; color: var(--tds-ink-secondary); margin-top: 2px; }

/* ===================================================================
   TOOLTIP — PURE CSS, TOAST-TONED
   =================================================================== */
.tds-tooltip {
  position: relative;
  display: inline-flex;
  border-bottom: 1px dotted var(--tds-ink-muted);
  cursor: help;
}
.tds-tooltip::after {
  content: attr(data-tip);
  position: absolute;
  left: 50%;
  bottom: calc(100% + 8px);
  transform: translateX(-50%) translateY(2px);
  background: var(--tds-toast-bg);
  color: var(--tds-toast-ink);
  border: 1px solid var(--tds-toast-border);
  font-size: 12px;
  font-weight: 500;
  line-height: 1.4;
  padding: 6px 10px;
  border-radius: 8px;
  white-space: nowrap;
  max-width: 260px;
  overflow: hidden;
  text-overflow: ellipsis;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.15s ease, transform 0.15s ease;
  z-index: 60;
}
.tds-tooltip[data-position="bottom"]::after {
  bottom: auto;
  top: calc(100% + 8px);
  transform: translateX(-50%) translateY(-2px);
}
.tds-tooltip:hover::after, .tds-tooltip:focus-visible::after {
  opacity: 1;
  transform: translateX(-50%) translateY(0);
}
/* Anchored instead of centred (data-align) — a hint on the last column of a
   table hangs past the page when its pill is centred, and an absolutely
   positioned pseudo widens the document. These rules sit AFTER the hover
   rule above on purpose: they tie with it on specificity, so source order
   is what lets them win. */
.tds-tooltip[data-align="end"]::after { left: auto; right: 0; transform: translateY(2px); }
.tds-tooltip[data-align="end"]:hover::after,
.tds-tooltip[data-align="end"]:focus-visible::after { transform: translateY(0); }
.tds-tooltip[data-align="start"]::after { left: 0; right: auto; transform: translateY(2px); }
.tds-tooltip[data-align="start"]:hover::after,
.tds-tooltip[data-align="start"]:focus-visible::after { transform: translateY(0); }

/* A hint that is a SENTENCE (data-wrap): the default pill is one nowrap line
   with overflow hidden, which cuts it without a sign. Width is capped against
   the viewport too, so it never runs off a 375px screen. */
.tds-tooltip[data-wrap="true"]::after {
  white-space: normal;
  width: max-content;
  /* The pill is centred on its word and, being absolutely positioned, its
     box contributes to the page's scrollable width — a wide one measured
     383px of layout viewport on a 375px phone. Capped so a centred pill
     stays inside the screen. A wrapping hint therefore belongs on a word
     that is not hugging the edge of its card. */
  max-width: min(280px, 62vw);
  text-align: left;
}

/* ===================================================================
   SWISS QR-BILL — PRINT DOCUMENT (ALWAYS WHITE, BOTH THEMES)
   =================================================================== */
.tds-qr-bill {
  background: #ffffff;
  color: #000000;
  border: 1px dashed #9ca3af;
  border-radius: 4px;
  padding: 14px;
  font-family: Arial, Helvetica, sans-serif;
}
.tds-qr-bill-scissors { font-size: 13px; color: #6b7280; margin-bottom: 4px; }
.tds-qr-bill-columns { display: flex; gap: 20px; flex-wrap: wrap; }
.tds-qr-bill-receipt {
  flex: 1;
  min-width: 170px;
  border-right: 1px dashed #9ca3af;
  padding-right: 20px;
}
.tds-qr-bill-payment { flex: 2.2; min-width: 260px; }
@media (max-width: 640px) {
  .tds-qr-bill-receipt { border-right: none; padding-right: 0; }
}
.tds-qr-bill-heading { font-size: 12px; font-weight: 700; margin-bottom: 10px; }
.tds-qr-bill-label { font-size: 8.5px; font-weight: 700; margin-top: 8px; }
.tds-qr-bill-value { font-size: 11px; line-height: 1.35; }
.tds-qr-bill-qr { width: 130px; height: 130px; flex-shrink: 0; }
.tds-qr-bill-qr svg { width: 100%; height: 100%; display: block; }

/* ===================================================================
   CONTENT TABS (underline style — the segmented control filters lists)
   =================================================================== */
.tds-tabs {
  display: flex;
  gap: 2px;
  border-bottom: 1px solid var(--tds-border);
  overflow-x: auto;
  scrollbar-width: none;
}
.tds-tabs::-webkit-scrollbar { display: none; }
.tds-tab {
  padding: 10px 14px;
  border: none;
  background: none;
  font: inherit;
  font-size: 14px;
  font-weight: 600;
  color: var(--tds-ink-secondary);
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
  cursor: pointer;
  white-space: nowrap;
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
.tds-tab:hover { color: var(--tds-ink-primary); }
.tds-tab.is-active { color: var(--tds-ink-primary); border-bottom-color: var(--tds-blue); }
.tds-tab-badge {
  font-size: 11px;
  font-weight: 700;
  padding: 1px 7px;
  border-radius: 99px;
  background: var(--tds-blue-soft);
  color: var(--tds-blue);
}
.tds-tab-panel { padding-top: 18px; }

/* ===================================================================
   BREADCRUMB
   =================================================================== */
.tds-breadcrumb {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 13px;
  flex-wrap: wrap;
}
.tds-breadcrumb-link {
  color: var(--tds-ink-secondary);
  text-decoration: none;
  font-weight: 500;
  border-radius: 6px;
}
.tds-breadcrumb-link:hover { color: var(--tds-blue); }
.tds-breadcrumb-sep { color: var(--tds-ink-muted); }
.tds-breadcrumb-current { color: var(--tds-ink-primary); font-weight: 650; }

/* ===================================================================
   TAG INPUT
   =================================================================== */
.tds-tag-input {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  align-items: center;
  cursor: text;
  min-height: 46px;
}
.tds-tag {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 6px 4px 10px;
  border-radius: 9px;
  background: var(--tds-blue-soft);
  color: var(--tds-blue);
  font-size: 13px;
  font-weight: 600;
}
.tds-tag-remove {
  border: none;
  background: none;
  color: inherit;
  opacity: 0.65;
  font-size: 10px;
  cursor: pointer;
  padding: 2px;
  border-radius: 4px;
}
.tds-tag-remove:hover { opacity: 1; }
.tds-tag-draft {
  flex: 1;
  min-width: 120px;
  border: none;
  background: none;
  font: inherit;
  font-size: 14px;
  color: var(--tds-ink-primary);
  outline: none;
  padding: 4px 0;
}
.tds-tag-draft::placeholder { color: var(--tds-ink-muted); }

/* ===================================================================
   COLOR SWATCHES
   =================================================================== */
.tds-swatches { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.tds-swatch {
  width: 30px;
  height: 30px;
  border-radius: 50%;
  border: 2px solid var(--tds-border);
  cursor: pointer;
  padding: 0;
  transition: transform 0.15s ease, outline-color 0.15s ease;
}
.tds-swatch.is-active {
  outline: 3px solid var(--tds-blue-glow);
  border-color: var(--tds-blue);
  transform: scale(1.1);
}
.tds-swatch--custom {
  position: relative;
  background: var(--tds-bg-subtle);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--tds-ink-secondary);
  font-weight: 700;
}
.tds-swatch--custom input[type="color"] {
  position: absolute;
  inset: 0;
  opacity: 0;
  cursor: pointer;
}
.tds-swatch-hex {
  font-size: 12px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  color: var(--tds-ink-secondary);
}

/* ===================================================================
   EDITOR SUITE — TOOLBAR / MERGE TAG / PAPER / SPLIT PREVIEW
   =================================================================== */
.tds-toolbar {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  padding: 8px 10px;
  background: var(--tds-card);
  border: 1px solid var(--tds-border);
  border-radius: 14px;
}
.tds-toolbar-label { font-size: 12px; font-weight: 600; color: var(--tds-ink-muted); padding: 0 4px; }
.tds-toolbar-sep { width: 1px; height: 22px; background: var(--tds-border); margin: 0 4px; }

.tds-merge-tag {
  display: inline-block;
  padding: 1px 8px;
  border-radius: 7px;
  background: var(--tds-blue-soft);
  color: var(--tds-blue);
  font-size: 0.85em;
  font-weight: 650;
  white-space: nowrap;
  user-select: all;
}

.tds-paper {
  background: #ffffff;
  color: #191f28;
  aspect-ratio: 210 / 297;
  width: 100%;
  border-radius: 6px;
  border: 1px solid var(--tds-border);
  box-shadow: var(--tds-shadow-card);
  padding: clamp(20px, 7%, 48px);
  overflow: auto;
  font-size: 13px;
  line-height: 1.55;
}
.tds-paper h1, .tds-paper h2, .tds-paper h3 { color: #191f28; margin: 0 0 8px 0; line-height: 1.25; }
.tds-paper h2 { font-size: 20px; }
.tds-paper h3 { font-size: 16px; }
.tds-paper p { margin: 0 0 10px 0; }
.tds-paper ul, .tds-paper ol { margin: 0 0 10px 0; padding-left: 20px; }
.tds-paper blockquote {
  margin: 0 0 10px 0;
  padding: 8px 14px;
  border-left: 3px solid #3182f6;
  background: #f4f6f8;
}
.tds-paper blockquote cite { display: block; font-size: 11px; color: #6b7684; margin-top: 4px; }
.tds-paper table { border-collapse: collapse; width: 100%; margin: 0 0 10px 0; }
.tds-paper th, .tds-paper td { border: 1px solid #d5dade; padding: 6px 8px; text-align: left; font-size: 12px; }
.tds-paper th { background: #f4f6f8; font-weight: 700; }

.tds-template-preview { display: grid; grid-template-columns: minmax(0, 1fr); gap: 18px; }
.tds-template-preview-editor, .tds-template-preview-pane { min-width: 0; }
@media (min-width: 1024px) {
  .tds-template-preview { grid-template-columns: minmax(0, 1.2fr) minmax(0, 1fr); align-items: start; }
}

/* ===================================================================
   BLOCK EDITOR — EDITOR.JS SKINNED WITH TDS TOKENS
   =================================================================== */
.tds-block-editor {
  background: var(--tds-bg-input);
  border: 1px solid var(--tds-border);
  border-radius: 16px;
  padding: 10px 18px;
  min-height: 340px;
  color: var(--tds-ink-primary);
}
.tds-block-editor:focus-within { border-color: var(--tds-blue); }
.tds-block-editor .codex-editor__redactor { padding-bottom: 80px !important; }
.tds-block-editor .ce-block__content,
.tds-block-editor .ce-toolbar__content { max-width: none; }
.tds-block-editor ::selection { background: var(--tds-blue-glow); }
.tds-block-editor .ce-paragraph[data-placeholder]:empty::before { color: var(--tds-ink-muted); }
.tds-block-editor .ce-toolbar__plus,
.tds-block-editor .ce-toolbar__settings-btn {
  color: var(--tds-ink-secondary);
  background: var(--tds-card);
  border: 1px solid var(--tds-border);
  border-radius: 8px;
}
.tds-block-editor .ce-toolbar__plus:hover,
.tds-block-editor .ce-toolbar__settings-btn:hover { background: var(--tds-bg-subtle); color: var(--tds-ink-primary); }
/* Editor.js popovers & inline toolbar follow the theme via its CSS vars */
.tds-block-editor .ce-popover,
.tds-block-editor .ce-inline-toolbar {
  --color-background-default: var(--tds-card);
  --color-background-item-hover: var(--tds-bg-subtle);
  --color-background-item-focus: var(--tds-blue-glow);
  --color-text-primary: var(--tds-ink-primary);
  --color-text-secondary: var(--tds-ink-secondary);
  --color-border: var(--tds-border);
  --color-shadow-icon: transparent;
  background: var(--tds-card);
  border-color: var(--tds-border);
  color: var(--tds-ink-primary);
}
.tds-block-editor .ce-inline-tool,
.tds-block-editor .ce-inline-toolbar__dropdown { color: var(--tds-ink-primary); }
.tds-block-editor .ce-inline-tool:hover,
.tds-block-editor .ce-inline-toolbar__dropdown:hover { background: var(--tds-bg-subtle); }
.tds-block-editor .tc-wrap { --color-border: var(--tds-border); --color-background: var(--tds-bg-subtle); }
.tds-block-editor .tc-cell, .tds-block-editor .tc-row { border-color: var(--tds-border); }

/* ===================================================================
   WORKFLOW BUILDER — VERTICAL RAIL
   =================================================================== */
.tds-workflow { list-style: none; margin: 0; padding: 0; }
.tds-workflow-step { display: flex; gap: 14px; }
.tds-workflow-rail {
  display: flex;
  flex-direction: column;
  align-items: center;
  flex-shrink: 0;
  width: 34px;
}
.tds-workflow-dot {
  width: 34px;
  height: 34px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 15px;
  z-index: 1;
}
.tds-workflow-dot--trigger { background: var(--tds-blue-soft); color: var(--tds-blue); }
.tds-workflow-dot--condition { background: var(--tds-bg-subtle); color: var(--tds-ink-secondary); }
.tds-workflow-dot--action { background: var(--tds-emerald-soft); color: var(--tds-emerald); }
.tds-workflow-dot--delay { background: var(--tds-bg-subtle); color: var(--tds-ink-secondary); }
.tds-workflow-line { flex: 1; width: 2px; background: var(--tds-border); margin: 4px 0; }
.tds-workflow-card {
  flex: 1;
  min-width: 0;
  background: var(--tds-card);
  border: 1px solid var(--tds-border);
  border-radius: 16px;
  padding: 14px 16px;
  margin-bottom: 14px;
  box-shadow: var(--tds-shadow-card);
}
.tds-workflow-head { display: flex; justify-content: space-between; gap: 10px; align-items: flex-start; }
.tds-workflow-kind {
  font-size: 10px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--tds-ink-muted);
}
.tds-workflow-kind--trigger { color: var(--tds-blue); }
.tds-workflow-kind--action { color: var(--tds-emerald); }
.tds-workflow-title { font-size: 14px; font-weight: 650; color: var(--tds-ink-primary); margin-top: 2px; }
.tds-workflow-sub { font-size: 12px; color: var(--tds-ink-secondary); margin-top: 2px; }
.tds-workflow-actions { display: flex; gap: 4px; flex-shrink: 0; }
.tds-workflow-body { margin-top: 12px; }
.tds-workflow-add-row { list-style: none; display: flex; padding-left: 48px; margin-bottom: 14px; }
.tds-workflow-add {
  border: 1.5px dashed var(--tds-border);
  background: none;
  color: var(--tds-ink-secondary);
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  padding: 10px 18px;
  border-radius: 12px;
  cursor: pointer;
  transition: border-color 0.15s ease, color 0.15s ease;
}
.tds-workflow-add:hover { border-color: var(--tds-blue); color: var(--tds-blue); }

.tds-condition-row {
  display: grid;
  grid-template-columns: minmax(0, 1.2fr) minmax(0, 0.8fr) minmax(0, 1fr) auto;
  gap: 10px;
  align-items: center;
}
.tds-condition-field, .tds-condition-op, .tds-condition-value { min-width: 0; }
.tds-condition-actions { flex-shrink: 0; }
@media (max-width: 640px) {
  .tds-condition-row { grid-template-columns: minmax(0, 1fr); }
}

/* ===================================================================
   STATUS FLOW — READ-ONLY PIPELINE
   =================================================================== */
.tds-status-flow { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.tds-status-flow-item { display: inline-flex; align-items: center; gap: 8px; }
.tds-status-flow-item + .tds-status-flow-item::before {
  content: "›";
  color: var(--tds-ink-muted);
  font-size: 16px;
}
.tds-status-chip {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 7px 14px;
  border-radius: 99px;
  font-size: 13px;
  font-weight: 650;
  border: 1.5px solid transparent;
}
.tds-status-chip--blue { background: var(--tds-blue-soft); color: var(--tds-blue); }
.tds-status-chip--green { background: var(--tds-emerald-soft); color: var(--tds-emerald); }
.tds-status-chip--red { background: var(--tds-ruby-soft); color: var(--tds-ruby); }
.tds-status-chip--gray { background: var(--tds-bg-subtle); color: var(--tds-ink-secondary); }
.tds-status-chip.is-current { border-color: currentColor; }
.tds-status-chip-count {
  font-variant-numeric: tabular-nums;
  font-weight: 800;
  font-size: 12px;
  opacity: 0.85;
}

/* ===================================================================
   SIGNATURE PAD
   =================================================================== */
.tds-signature {
  position: relative;
  border: 1.5px dashed var(--tds-border);
  border-radius: 16px;
  background: var(--tds-bg-input);
  overflow: hidden;
}
.tds-signature canvas {
  display: block;
  width: 100%;
  color: var(--tds-ink-primary); /* stroke color follows the theme */
  cursor: crosshair;
  touch-action: none;
}
.tds-signature-hintline {
  position: absolute;
  left: 10%;
  right: 10%;
  bottom: 28px;
  border-bottom: 1px solid var(--tds-border);
  pointer-events: none;
}
.tds-signature-empty {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--tds-ink-muted);
  font-size: 14px;
  font-weight: 500;
  pointer-events: none;
}
.tds-signature-clear { position: absolute; top: 8px; right: 8px; }

/* ===================================================================
   SMART BLOCK — COMPUTED SNIPPET PLACEHOLDER
   =================================================================== */
.tds-smart-block {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 12px 14px;
  margin: 6px 0;
  border: 1.5px dashed var(--tds-blue);
  border-radius: 12px;
  background: var(--tds-blue-soft);
  user-select: none;
}
.tds-smart-block-icon {
  width: 26px;
  height: 26px;
  border-radius: 8px;
  background: var(--tds-blue);
  color: var(--tds-ink-on-accent);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 14px;
  font-weight: 700;
  flex-shrink: 0;
}
.tds-smart-block-label { font-size: 14px; font-weight: 650; color: var(--tds-ink-primary); }
.tds-smart-block-badge {
  margin-left: auto;
  font-size: 10px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--tds-blue);
}

.tds-sms-preview {
  max-width: 340px;
  padding: 12px 16px;
  border-radius: 18px 18px 18px 4px;
  background: var(--tds-bg-subtle);
  color: var(--tds-ink-primary);
  font-size: 13px;
  line-height: 1.5;
}

/* ===================================================================
   EMAIL PREVIEW FRAME (always light — it previews the recipient's inbox)
   =================================================================== */
.tds-email-frame {
  background: #ffffff;
  color: #191f28;
  border: 1px solid var(--tds-border);
  border-radius: 12px;
  overflow: hidden;
  box-shadow: var(--tds-shadow-card);
}
.tds-email-frame-header {
  padding: 12px 18px;
  border-bottom: 1px solid #eceef0;
  background: #fafbfc;
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 3px;
}
.tds-email-frame-row { font-size: 12px; color: #6b7684; }
.tds-email-frame-row strong { color: #191f28; font-weight: 650; }
.tds-email-frame-subject { font-size: 14px; font-weight: 700; color: #191f28; }
.tds-email-frame-body { padding: 20px 18px; font-size: 13px; line-height: 1.55; }
.tds-email-frame-body h1, .tds-email-frame-body h2, .tds-email-frame-body h3 { margin: 0 0 8px 0; }
.tds-email-frame-body p { margin: 0 0 10px 0; }
.tds-email-frame-body table { border-collapse: collapse; width: 100%; margin: 0 0 10px 0; }
.tds-email-frame-body th, .tds-email-frame-body td { border: 1px solid #d5dade; padding: 6px 8px; text-align: left; font-size: 12px; }
.tds-email-frame-body th { background: #f4f6f8; }
.tds-email-frame-body blockquote { margin: 0 0 10px 0; padding: 8px 14px; border-left: 3px solid #3182f6; background: #f4f6f8; }
.tds-email-frame-body blockquote cite { display: block; font-size: 11px; color: #6b7684; margin-top: 4px; }

.tds-sms-preview { white-space: pre-line; }
.tds-sms-meta { display: block; margin-top: 6px; font-size: 11px; color: var(--tds-ink-muted); font-variant-numeric: tabular-nums; }

/* Dashed "add a widget" card at the end of a tenant KPI strip */
.tds-widget-add {
  border: 1.5px dashed var(--tds-border);
  border-radius: 20px;
  background: none;
  color: var(--tds-ink-secondary);
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  min-height: 86px;
  cursor: pointer;
  transition: border-color 0.15s ease, color 0.15s ease;
}
.tds-widget-add:hover { border-color: var(--tds-blue); color: var(--tds-blue); }

/* ===================================================================
   ACTION MENU — smart placement, token-based elevation
   =================================================================== */
.tds-action-menu { position: relative; display: inline-block; }
.tds-action-menu-panel {
  position: absolute;
  right: 0;
  top: calc(100% + 6px);
  background: var(--tds-card);
  border: 1px solid var(--tds-border);
  border-radius: 14px;
  box-shadow: var(--tds-shadow-dock);
  padding: 6px;
  z-index: 50;
  min-width: 160px;
  /* An absolutely-positioned panel shrink-to-fits against its tiny
     containing block (the ••• button), so any item label wider than
     min-width used to WRAP and center ("Name an administrator…",
     user-flagged). nowrap makes the longest label the panel's floor —
     and flex column keeps the items STACKED (inline-level items relied
     on line wrapping to stack, which nowrap would otherwise forbid). */
  display: flex;
  flex-direction: column;
  gap: 2px;
  white-space: nowrap;
}
.tds-action-menu-panel.is-up {
  top: auto;
  bottom: calc(100% + 6px);
}

/* Utility: show the full text on hover, but ONLY when it is actually
   truncated (the element toggles .is-clipped by comparing scrollWidth to
   clientWidth on mouseenter). Toast-toned, theme-safe. */
.tds-clip-tip { position: relative; }
.tds-clip-tip.is-clipped::after {
  content: attr(data-tip);
  position: absolute;
  left: 0;
  bottom: calc(100% + 6px);
  background: var(--tds-toast-bg);
  color: var(--tds-toast-ink);
  border: 1px solid var(--tds-toast-border);
  font-size: 12px;
  font-weight: 600;
  line-height: 1.4;
  padding: 6px 10px;
  border-radius: 8px;
  white-space: nowrap;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.15s ease;
  z-index: 60;
}
.tds-clip-tip.is-clipped:hover::after { opacity: 1; }

/* ===================================================================
   PAGE SCAFFOLDING — HEADER / STACK / FIELD GRID
   =================================================================== */
.tds-page-header { padding: 28px 0 18px 0; }
.tds-page-header .tds-breadcrumb { margin-bottom: 10px; }
.tds-page-header-row {
  display: flex;
  justify-content: space-between;
  align-items: flex-end;
  gap: 16px;
  flex-wrap: wrap;
}
.tds-page-title { font-size: clamp(24px, 4vw, 30px); margin: 0; }
.tds-page-subtitle { margin: 6px 0 0 0; color: var(--tds-ink-secondary); max-width: 620px; }
.tds-page-header-meta { margin-top: 8px; }
.tds-page-actions { display: flex; gap: 10px; flex-wrap: wrap; }

/* Single-column grids declare `minmax(0, 1fr)`, never an implicit `auto`
   track. An auto track grows to its item's MIN-CONTENT, and one
   `white-space: nowrap` descendant — a `.tds-row-meta` carrying a sentence,
   a tabular figure, a long file name — makes that min-content the whole
   string: the track widens past the viewport, the page grows a horizontal
   scrollbar and the reader has to zoom out to see the right edge of every
   card. Found on FleetLens's account screen at 375 px: the layout viewport
   measured 521 px for a 375 px device. `minmax(0, …)` caps the track at the
   container, so `text-overflow: ellipsis` does the job it was written for.
   `min-width: 0` on the items does NOT fix this — measured, it changes
   nothing: intrinsic track sizing does not consult it. */
.tds-stack { display: grid; grid-template-columns: minmax(0, 1fr); }
/* The columns live HERE, not in the component's inline style: the track
   floor is `min(<min>, 100%)` so a container narrower than the floor gets
   one column instead of overflowing, and the guard test can see it. */
.tds-field-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(var(--tds-field-min, 240px), 100%), 1fr));
  gap: 16px;
}

/* ===================================================================
   BIDIRECTIONAL COMMUNICATION — THREAD / COMPOSER / ANNOUNCEMENTS
   =================================================================== */
.tds-thread {
  display: flex;
  flex-direction: column;
  gap: 14px;
  overflow-y: auto;
  max-height: 55vh;
  padding: 4px 2px;
}
.tds-msg { display: flex; gap: 10px; max-width: 88%; }
.tds-msg--mine { align-self: flex-end; flex-direction: row-reverse; }
.tds-msg-avatar { margin-top: 18px; }
.tds-msg-main { min-width: 0; display: flex; flex-direction: column; gap: 4px; }
.tds-msg--mine .tds-msg-main { align-items: flex-end; }
.tds-msg-author { font-size: 11px; font-weight: 600; color: var(--tds-ink-secondary); }
.tds-msg-time { font-weight: 500; color: var(--tds-ink-muted); }
.tds-msg-bubble {
  padding: 10px 14px;
  border-radius: 16px 16px 16px 4px;
  background: var(--tds-bg-subtle);
  color: var(--tds-ink-primary);
  font-size: 14px;
  line-height: 1.5;
  overflow-wrap: anywhere;
}
.tds-msg--mine .tds-msg-bubble {
  border-radius: 16px 16px 4px 16px;
  background: var(--tds-blue);
  color: var(--tds-ink-on-accent);
}

.tds-composer {
  display: flex;
  align-items: flex-end;
  gap: 8px;
  margin-top: 14px;
  padding: 8px;
  border: 1px solid var(--tds-border);
  border-radius: 18px;
  background: var(--tds-bg-input);
}
.tds-composer:focus-within { border-color: var(--tds-blue); }
.tds-composer-input {
  flex: 1;
  border: none;
  background: none;
  resize: none;
  font: inherit;
  font-size: 14px;
  line-height: 1.45;
  color: var(--tds-ink-primary);
  outline: none;
  padding: 6px 8px;
  max-height: 120px;
}
.tds-composer-input::placeholder { color: var(--tds-ink-muted); }
.tds-composer-send {
  width: 38px;
  height: 38px;
  border: none;
  border-radius: 12px;
  background: var(--tds-blue);
  color: var(--tds-ink-on-accent);
  font-size: 15px;
  cursor: pointer;
  flex-shrink: 0;
}
.tds-composer-send:hover { background: var(--tds-blue-hover); }

.tds-quick-action {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  padding: 18px 12px;
  border: none;
  border-radius: 20px;
  background: var(--tds-card);
  box-shadow: var(--tds-shadow-card);
  cursor: pointer;
  text-align: center;
  font: inherit;
  transition: background 0.15s ease;
  min-width: 0;
}
.tds-quick-action:hover { background: var(--tds-blue-soft); }
.tds-quick-action-icon {
  width: 46px;
  height: 46px;
  border-radius: 16px;
  background: var(--tds-blue-soft);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 22px;
}
.tds-quick-action-label { font-size: 13px; font-weight: 650; color: var(--tds-ink-primary); line-height: 1.25; }
.tds-quick-action-sub { font-size: 11px; color: var(--tds-ink-secondary); }

.tds-announcement {
  background: var(--tds-card);
  border: 1px solid var(--tds-border);
  border-radius: 20px;
  padding: 18px;
  box-shadow: var(--tds-shadow-card);
}
.tds-announcement-head { display: flex; justify-content: space-between; gap: 12px; align-items: flex-start; }
.tds-announcement-title { font-size: 15px; font-weight: 700; color: var(--tds-ink-primary); }
.tds-announcement-meta { font-size: 12px; color: var(--tds-ink-muted); margin-top: 2px; }
.tds-announcement-badges { display: flex; gap: 6px; flex-wrap: wrap; justify-content: flex-end; }
.tds-announcement-body { margin-top: 10px; font-size: 14px; line-height: 1.55; color: var(--tds-ink-secondary); }
.tds-announcement-footer { margin-top: 14px; border-top: 1px solid var(--tds-border); padding-top: 14px; }

.tds-rsvp { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.tds-rsvp-btn {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 8px 14px;
  border: 1.5px solid var(--tds-border);
  border-radius: 12px;
  background: none;
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  color: var(--tds-ink-primary);
  cursor: pointer;
  font-variant-numeric: tabular-nums;
}
.tds-rsvp-btn--yes.is-active { border-color: var(--tds-emerald); background: var(--tds-emerald-soft); color: var(--tds-emerald); }
.tds-rsvp-btn--no.is-active { border-color: var(--tds-ruby); background: var(--tds-ruby-soft); color: var(--tds-ruby); }
.tds-rsvp-pending { font-size: 12px; color: var(--tds-ink-muted); font-variant-numeric: tabular-nums; }

.tds-unread-dot {
  display: inline-block;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--tds-blue);
  flex-shrink: 0;
}

/* ===================================================================
   AI ASSISTANCE — violet accent is reserved for AI affordances
   =================================================================== */
.tds-ai-btn { background: var(--tds-ai-soft); color: var(--tds-ai); }
.tds-ai-btn:hover { filter: brightness(1.05); }
.tds-ai-spark { font-size: 0.95em; }

.tds-typing {
  display: none;
  align-items: center;
  gap: 4px;
  padding: 4px 2px;
}
.tds-typing.htmx-request { display: inline-flex; }
.tds-typing span {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--tds-ai);
  animation: tds-typing-pulse 1.1s ease-in-out infinite;
}
.tds-typing span:nth-child(2) { animation-delay: 0.15s; }
.tds-typing span:nth-child(3) { animation-delay: 0.3s; }
@keyframes tds-typing-pulse {
  0%, 100% { opacity: 0.25; transform: translateY(0); }
  40% { opacity: 1; transform: translateY(-3px); }
}

.tds-ai-suggestion {
  border: 1.5px dashed var(--tds-ai);
  border-radius: 16px;
  background: var(--tds-ai-soft);
  padding: 14px 16px;
}
.tds-ai-suggestion-head {
  font-size: 12px;
  font-weight: 700;
  color: var(--tds-ai);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  margin-bottom: 8px;
}
.tds-ai-suggestion-body { font-size: 14px; line-height: 1.55; color: var(--tds-ink-primary); }
.tds-ai-suggestion-actions { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 12px; }

.tds-suggestion-chip {
  display: inline-block;
  padding: 8px 14px;
  margin: 4px 6px 4px 0;
  border: 1px solid var(--tds-ai);
  border-radius: 14px;
  background: var(--tds-ai-soft);
  color: var(--tds-ink-primary);
  font: inherit;
  font-size: 13px;
  text-align: left;
  cursor: pointer;
  transition: filter 0.15s ease;
}
.tds-suggestion-chip:hover { filter: brightness(1.05); }

/* ===================================================================
   THREAD VIEW — conversation layout inside the drawer/sheet
   (header fixed, thread scrolls, suggestions + composer PINNED — LAW 4)
   =================================================================== */
.tds-thread-view {
  display: flex;
  flex-direction: column;
  flex: 1;
  min-height: 0;
}
.tds-thread-view-head {
  display: flex;
  align-items: center;
  gap: 12px;
  padding-bottom: 14px;
  border-bottom: 1px solid var(--tds-border);
  margin-bottom: 10px;
  flex-shrink: 0;
}
.tds-thread-view .tds-thread {
  flex: 1;
  min-height: 0;
  max-height: none;
}
.tds-thread-view .tds-composer { margin-top: 8px; flex-shrink: 0; }

/* The global drawer's slot is part of the drawer's column (0.1.59). §4.3
   promises that a `.tds-thread-view` dropped in a drawer pins its composer
   at the bottom, and the drawer's body is the flex column that makes that
   possible — but the shell swaps fragments into a plain `<div>` sitting
   between the two, and a plain div does not stretch. Measured at 375px on
   the inbox: the panel ran the full 747px, the thread stopped at 520, and
   the composer — the one thing a phone reader reaches for — floated in the
   middle with 290px of dead surface beneath it.
   `flex: 1 0 auto` and not `flex: 1`: the basis stays the content's own
   height, so SHORT content grows to fill the panel (which is what pins the
   composer) while TALL content is never shrunk into a clipped box the
   drawer's scroll cannot reach. */
.tds-drawer-slot {
  display: flex;
  flex-direction: column;
  flex: 1 0 auto;
}
.tds-suggestion-row {
  display: flex;
  align-items: center;
  gap: 8px;
  overflow-x: auto;
  padding: 8px 0 2px 0;
  flex-shrink: 0;
  scrollbar-width: none;
}
.tds-suggestion-row::-webkit-scrollbar { display: none; }
.tds-suggestion-row .tds-suggestion-chip {
  flex-shrink: 0;
  margin: 0;
  white-space: nowrap;
  max-width: 280px;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* LAW 4 — on mobile the sticky CTA floats ABOVE the pill dock, never under
   it. `--tds-dock-clear` already holds the safe area; adding it again here
   is how the lift used to be computed from a number the dock did not
   honour (django-tds #1). */
@media (max-width: 767px) {
  .tds-sticky-cta {
    bottom: var(--tds-dock-clear);
    padding-bottom: 10px;
  }
}
/* A page whose last content must stay readable above a sticky CTA (LAW 4,
   the other half): put this on the page root. It reserves the CTA and the
   hint line it grows by; the shell already reserves the dock. */
.tds-cta-reserve { padding-bottom: calc(var(--tds-cta-height) + var(--tds-cta-hint)); }

/* In a stacked condition row, a lone static operator word ("is") on its own
   line reads as noise — hide it; select-based operators (workflow) remain. */
@media (max-width: 640px) {
  .tds-condition-op:has(> span:only-child) { display: none; }
}

/* ===================================================================
   BOOSTED-NAVIGATION PROGRESS (thin top bar, never a blocking loader)
   =================================================================== */
body.tds-navigating::after {
  content: "";
  position: fixed;
  top: 0;
  left: 0;
  height: 3px;
  border-radius: 0 2px 2px 0;
  background: var(--tds-blue);
  z-index: 200;
  animation: tds-nav-progress 1.4s cubic-bezier(0.2, 0, 0, 1) forwards;
}
@keyframes tds-nav-progress {
  from { width: 0; }
  60% { width: 62%; }
  to { width: 86%; }
}

/* ===================================================================
   AUTH SHELL — the very first Toss impression
   =================================================================== */
.tds-auth-shell {
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 24px 20px calc(24px + env(safe-area-inset-bottom)) 20px;
}
.tds-auth-card { width: 100%; max-width: 420px; }
.tds-auth-brand {
  font-size: 22px;
  font-weight: 800;
  color: var(--tds-ink-primary);
  text-align: center;
  margin-bottom: 28px;
}
.tds-auth-hint {
  margin: 24px 0 0 0;
  text-align: center;
  font-size: 12px;
  color: var(--tds-ink-muted);
}

/* ===================================================================
   BROWSER FRAME — web-channel preview (theme-aware, unlike print)
   =================================================================== */
.tds-browser-frame {
  border: 1px solid var(--tds-border);
  border-radius: 14px;
  overflow: hidden;
  background: var(--tds-card);
  box-shadow: var(--tds-shadow-card);
}
.tds-browser-frame-bar {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 12px;
  background: var(--tds-bg-table-th);
  border-bottom: 1px solid var(--tds-border);
}
.tds-browser-frame-dots { display: inline-flex; gap: 5px; }
.tds-browser-frame-dots span {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--tds-bg-subtle);
  border: 1px solid var(--tds-border);
}
.tds-browser-frame-url {
  flex: 1;
  text-align: center;
  font-size: 11px;
  font-weight: 600;
  color: var(--tds-ink-muted);
  background: var(--tds-bg-input);
  border-radius: 8px;
  padding: 4px 10px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.tds-browser-frame-body { padding: 20px 18px; font-size: 14px; line-height: 1.6; color: var(--tds-ink-primary); }
.tds-browser-frame-body h1, .tds-browser-frame-body h2 { margin: 0 0 10px 0; color: var(--tds-ink-primary); }
.tds-browser-frame-body h2 { font-size: 22px; font-weight: 800; }
.tds-browser-frame-body h3 { margin: 0 0 8px 0; font-size: 16px; }
.tds-browser-frame-body p { margin: 0 0 12px 0; color: var(--tds-ink-secondary); }
.tds-browser-frame-body ul, .tds-browser-frame-body ol { margin: 0 0 12px 0; padding-left: 20px; color: var(--tds-ink-secondary); }
.tds-browser-frame-body blockquote {
  margin: 0 0 12px 0;
  padding: 10px 14px;
  border-left: 3px solid var(--tds-blue);
  background: var(--tds-bg-subtle);
  border-radius: 0 10px 10px 0;
}
.tds-browser-frame-body blockquote cite { display: block; font-size: 12px; color: var(--tds-ink-muted); margin-top: 4px; }

/* ===================================================================
   WEBSHOP — PRODUCT CARD
   =================================================================== */
.tds-product-card {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 16px;
  background: var(--tds-card);
  border: 1px solid var(--tds-border);
  border-radius: 20px;
  box-shadow: var(--tds-shadow-card);
  min-width: 0;
}
.tds-product-figure {
  height: 72px;
  border-radius: 14px;
  background: var(--tds-bg-input);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 34px;
}
.tds-product-name { font-size: 14px; font-weight: 700; color: var(--tds-ink-primary); }
.tds-product-desc { font-size: 12px; color: var(--tds-ink-secondary); line-height: 1.45; }
.tds-product-foot {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 8px;
  margin-top: auto;
}
.tds-product-price { font-size: 15px; font-weight: 800; font-variant-numeric: tabular-nums; color: var(--tds-ink-primary); }
.tds-product-actions { display: grid; grid-template-columns: minmax(0, 1fr); gap: 8px; }

/* Six dock tabs must still breathe on a 375px phone */
@media (max-width: 420px) {
  .tds-nav-item { padding: 6px 7px; font-size: 10px; }
}

/* ===================================================================
   FILE LIBRARY — FILE / FOLDER TILES & PHOTO GRID
   =================================================================== */
.tds-file-tile {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 16px;
  border-bottom: 1px solid var(--tds-border);
}
.tds-file-tile:last-child { border-bottom: none; }
.tds-file-tile-icon { font-size: 22px; flex-shrink: 0; }
.tds-file-tile-main { flex: 1; min-width: 0; }
.tds-file-tile-name {
  font-size: 14px;
  font-weight: 650;
  color: var(--tds-ink-primary);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.tds-file-tile-meta { font-size: 12px; color: var(--tds-ink-muted); margin-top: 2px; }

.tds-folder-tile {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 6px;
  padding: 16px;
  border: none;
  border-radius: 20px;
  background: var(--tds-card);
  box-shadow: var(--tds-shadow-card);
  cursor: pointer;
  text-align: left;
  font: inherit;
  min-width: 0;
  transition: background 0.15s ease;
}
.tds-folder-tile:hover { background: var(--tds-blue-soft); }
.tds-folder-tile-icon { font-size: 26px; }
.tds-folder-tile-name { font-size: 14px; font-weight: 700; color: var(--tds-ink-primary); }
.tds-folder-tile-count { font-size: 12px; color: var(--tds-ink-secondary); }

.tds-photo-grid {
  display: grid;
  gap: 10px;
  grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
}
.tds-photo {
  position: relative;
  aspect-ratio: 4 / 3;
  border: none;
  border-radius: 14px;
  overflow: hidden;
  padding: 0;
  cursor: zoom-in;
  background: var(--tds-bg-subtle);
}
.tds-photo img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* ===================================================================
   LIGHTBOX — fullscreen photo viewer
   =================================================================== */
.tds-lightbox {
  position: fixed;
  inset: 0;
  z-index: 120;
  background: rgba(10, 13, 17, 0.92);
  backdrop-filter: blur(6px);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
}
.tds-lightbox-figure {
  margin: 0;
  max-width: min(920px, 92vw);
  text-align: center;
}
.tds-lightbox-figure img {
  max-width: 100%;
  max-height: 78dvh;
  border-radius: 16px;
  display: block;
}
.tds-lightbox-figure figcaption {
  margin-top: 12px;
  font-size: 14px;
  font-weight: 600;
  color: #f2f4f6;
}
.tds-lightbox-close,
.tds-lightbox-nav {
  position: absolute;
  border: none;
  background: rgba(255, 255, 255, 0.12);
  color: #f2f4f6;
  min-width: 44px;
  min-height: 44px;
  border-radius: 14px;
  font-size: 20px;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.tds-lightbox-close { top: max(16px, env(safe-area-inset-top)); right: 16px; }
.tds-lightbox-nav { top: 50%; transform: translateY(-50%); font-size: 28px; }
.tds-lightbox-nav--prev { left: 12px; }
.tds-lightbox-nav--next { right: 12px; }

/* Full-bleed content inside a padded card: row dividers reach the card
   edges. Cancels the card's own clamp() padding exactly — never hardcode
   negative margins against it. */
.tds-card-bleed {
  margin-left: calc(-1 * clamp(18px, 2.5vw, 24px));
  margin-right: calc(-1 * clamp(18px, 2.5vw, 24px));
}
.tds-card-bleed:last-child { margin-bottom: calc(-1 * clamp(18px, 2.5vw, 24px)); }

/* ===================================================================
   NAV BADGE — the calm "something awaits you" pill
   =================================================================== */
.tds-nav-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 17px;
  height: 17px;
  padding: 0 5px;
  border-radius: 99px;
  background: var(--tds-ruby);
  color: #ffffff;
  font-size: 10px;
  font-weight: 800;
  line-height: 1;
  font-variant-numeric: tabular-nums;
}
.tds-nav-badge.is-empty { display: none; }
/* Desktop navbar: inline after the label */
.tds-nav-desktop .tds-nav-badge { margin-left: 6px; }
/* Mobile dock: perched on the icon's shoulder */
.tds-nav-mobile .tds-nav-item { position: relative; }
.tds-nav-mobile .tds-nav-badge {
  position: absolute;
  top: 2px;
  right: calc(50% - 22px);
  border: 2px solid var(--tds-dock-bg);
}

/* ===================================================================
   SYSTEMIC BUSY STATE — every button that fires a request shows it and
   cannot be double-tapped (slow gym-hall networks, LAW 5)
   =================================================================== */
.tds-btn.htmx-request,
form.htmx-request .tds-btn[type="submit"] {
  pointer-events: none;
  opacity: 0.75;
  position: relative;
}
.tds-btn.htmx-request::after,
form.htmx-request .tds-btn[type="submit"]::after {
  content: "";
  width: 14px;
  height: 14px;
  margin-left: 8px;
  border: 2px solid currentColor;
  border-top-color: transparent;
  border-radius: 50%;
  animation: tds-spin 0.6s linear infinite;
}

/* Scroll containment: a sheet or thread reaching its end must never start
   scrolling the page behind it (native feel on iOS) */
.tds-bottom-sheet,
.tds-drawer-panel,
.tds-thread,
.tds-attendance {
  overscroll-behavior: contain;
}

/* ===================================================================
   DISTINCTION SET — SPARKLINE / OTP / POLL / PULSE / CELEBRATION
   =================================================================== */
.tds-sparkline { display: block; margin-top: 8px; overflow: visible; }
.tds-sparkline polyline {
  stroke: var(--tds-blue);
  stroke-width: 2.5;
  stroke-linecap: round;
  stroke-linejoin: round;
  vector-effect: non-scaling-stroke;
}

.tds-otp { display: flex; gap: 8px; justify-content: center; }
.tds-otp-box {
  width: 46px;
  height: 56px;
  text-align: center;
  font-size: 22px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--tds-ink-primary);
  background: var(--tds-bg-input);
  border: 1.5px solid var(--tds-border);
  border-radius: 12px;
  outline: none;
}
.tds-otp-box:focus { border-color: var(--tds-blue); background: var(--tds-card); }

.tds-poll { display: grid; grid-template-columns: minmax(0, 1fr); gap: 8px; }
.tds-poll-option {
  position: relative;
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 10px;
  padding: 11px 14px;
  border: 1.5px solid var(--tds-border);
  border-radius: 12px;
  background: var(--tds-bg-input);
  font: inherit;
  font-size: 14px;
  color: var(--tds-ink-primary);
  cursor: pointer;
  overflow: hidden;
  text-align: left;
}
.tds-poll-option.is-mine { border-color: var(--tds-blue); font-weight: 650; }
.tds-poll-fill {
  position: absolute;
  inset: 0 auto 0 0;
  background: var(--tds-blue-soft);
  transition: width 0.5s cubic-bezier(0.2, 0, 0, 1);
}
.tds-poll-label, .tds-poll-count { position: relative; }
.tds-poll-count { font-weight: 700; font-variant-numeric: tabular-nums; font-size: 13px; color: var(--tds-ink-secondary); }
.tds-poll-total { font-size: 12px; color: var(--tds-ink-muted); font-variant-numeric: tabular-nums; }

.tds-pulse-question { font-size: 13px; font-weight: 600; color: var(--tds-ink-secondary); margin-bottom: 10px; }
.tds-pulse-row { display: flex; gap: 10px; }
.tds-pulse-emoji {
  font-size: 26px;
  background: var(--tds-bg-input);
  border: 1.5px solid var(--tds-border);
  border-radius: 14px;
  width: 52px;
  height: 52px;
  cursor: pointer;
  transition: transform 0.18s cubic-bezier(0.34, 1.56, 0.64, 1), opacity 0.2s ease, border-color 0.2s ease;
}
.tds-pulse-emoji.is-picked { border-color: var(--tds-blue); background: var(--tds-blue-soft); transform: scale(1.15); }
.tds-pulse-emoji.is-faded { opacity: 0.35; }

.tds-celebration {
  display: flex;
  flex-wrap: wrap; /* actions drop below the text on narrow screens */
  align-items: center;
  gap: 14px;
  padding: 16px 18px;
  border-radius: 20px;
  background: linear-gradient(120deg, var(--tds-blue-soft), var(--tds-ai-soft));
  border: 1px solid var(--tds-border);
}
.tds-celebration-main { flex: 1; min-width: 200px; }
.tds-celebration-icon { display: inline-block; font-size: 30px; animation: tds-celebrate 2.2s ease-in-out infinite; }
@media (prefers-reduced-motion: reduce) {
  .tds-celebration-icon { animation: none; }
}
@keyframes tds-celebrate {
  0%, 100% { transform: rotate(0) scale(1); }
  10% { transform: rotate(-8deg) scale(1.1); }
  20% { transform: rotate(6deg) scale(1.05); }
  30% { transform: rotate(0) scale(1); }
}
.tds-celebration-title { font-size: 14px; font-weight: 700; color: var(--tds-ink-primary); }
.tds-celebration-body { font-size: 13px; color: var(--tds-ink-secondary); margin-top: 2px; }
.tds-celebration-actions { margin-left: auto; flex-shrink: 0; }

/* ============================================= RESPONSIVE VISIBILITY
   Utilities for the table→card morph and any value whose detail only
   makes sense on one form factor (e.g. a subdomain's ".yaaka.ch" suffix
   is noise on a 375px card). Hide, never truncate, information that the
   other breakpoint carries in full. */
@media (max-width: 767px) {
  .tds-hide-mobile { display: none !important; }
}
@media (min-width: 768px) {
  .tds-hide-desktop { display: none !important; }
}

/* ============================================= UNSAVED-CHANGES GUARD
   Serene dirty-state signalling (c-unsaved_guard). While a form with
   data-dirty-guard is dirty, its submit buttons glow and every
   [data-dirty-indicator] element un-hides — permanent, calm information
   instead of a surprise dialog. Glow via outline + token (never a
   hardcoded box-shadow, §3.3). */
.tds-btn.is-dirty { outline: 3px solid var(--tds-blue-glow); outline-offset: 1px; }
.tds-dirty-indicator {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 12px;
  font-weight: 700;
  color: var(--tds-ink-secondary);
  background: var(--tds-bg-subtle);
  border: 1px solid var(--tds-border);
  border-radius: 999px;
  padding: 4px 10px;
  white-space: nowrap;
}
.tds-dirty-indicator::before {
  content: '';
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--tds-blue);
  flex-shrink: 0;
}
/* [hidden] is handled once, in reset.css (0.1.44) */
.tds-sticky-cta-hint { display: flex; justify-content: center; margin-bottom: 8px; }

/* Sheet dismiss guard: the calm inline choice shown when a user dismissal
   would discard unsaved edits (§5.8 generalized to sheets). */
.tds-sheet-discard-guard {
  margin-top: 16px;
  padding-top: 14px;
  border-top: 1px solid var(--tds-border);
}

/* ===================================================================
   INTERFACE LANGUAGE SWITCHER (0.1.45)
   =================================================================== */
.tds-locale-switcher { display: flex; gap: 4px; align-items: center; }
.tds-locale-switcher form { margin: 0; }
.tds-locale-item {
  background: none;
  border: none;
  cursor: pointer;
  font: inherit;
  font-size: 12px;
  font-weight: 500;
  padding: 6px 8px;
  border-radius: 8px;
  color: var(--tds-ink-muted);
}
.tds-locale-item[aria-current="true"] {
  color: var(--tds-ink-primary);
  font-weight: 700;
  background: var(--tds-bg-subtle);
}

/* ===================================================================
   IMPERSONATION GUARD (0.1.45, self-styled since 0.1.48)
   The banner's rules live IN the component template, as a <style> block
   the pill carries with it: it is rendered from a hook that runs on every
   response, and the surfaces where the guard matters most — a Django admin
   page, an entrance shell, an error page — never load THIS file. With the
   rules here, the admin showed a flat red strip at the end of the document
   instead of a fixed pill (found on yaaka's admin at 0.1.47).
   =================================================================== */


/* THE 16px FLOOR ON A TOUCH DEVICE (0.1.59) — see the long note in
   reset.css. Every class below lands on a text-entry control and declares
   less than 16px, so mobile Safari zooms the page to focus it and leaves the
   reader to pinch back out. They keep their designed size where a mouse is
   the pointer; on a touchscreen they rise to the floor, which also makes
   them a more comfortable target. `.tds-giant-input` (24-32px) and
   `.tds-otp-box` (22px) are already above it and are left alone. Any NEW
   control joins this list — `TouchZoomFloorTests` reads the templates for
   controls, not this block, so one that is missing fails the suite.

   IT LIVES AT THE END OF THE SHEET, and must stay there. A media query
   adds NO specificity, so this block ties with every rule it lifts and
   wins on source order alone: parked mid-file it raised `.tds-input`
   (declared above it) and left `.tds-tag-draft` and `.tds-composer-input`
   (declared below it) at 14px — measured in the browser, which is the
   only reason the half-fix was caught. The test pins the ordering. */
@media (any-pointer: coarse) {
  .tds-input,
  .tds-tag-draft,
  .tds-composer-input { font-size: 16px; }
}
