/* TM paketi — kaynak sirasi korunur. Uretici: scripts/build_assets.py */

/* ===== css/ds/ds-live.css ===== */
/* =================================================================
   DS — CANLI PERFORMANS (Faz 4b, 2026-09-13). Page-specific re-skin for
   templates/pages/dashboard_live.html once it opts into .tm-ds (tmv2_ds_scope
   block). The three page-owned overlay files (v2/components/live-dashboard.css,
   live-actions-v2.css, dashboard/live-perf-polish-2026-06-08.css — docs/ui-audit.md
   Ek A "Canlı Performans: bırakılabilir", 3.366 satır / 430 !important) now load
   only behind ?legacy=1; this file restates what the page still needs from
   tokens/primitives. KPI cards are NOT here — they are .kpi-card (tm-kpi.js
   buildCard(), same DOM as Genel Bakış) and are already re-skinned by
   ds-stat-card.css; this file only fixes the live-grid-specific min-height
   collision with dashboard-vanilla.css (kept, shared, not gated).

   Everything below is scoped .tm-ds .tm-live-page (or narrower) on purpose —
   .tm-ds alone is shared with the Genel Bakış/Siparişler DS pages (other
   agents own those); no rule here may leak outside this page's DOM.

   Class names are the JS/template contract (docs/ui-audit.md Ek B) and are
   never renamed here — only re-skinned. Reduced motion is already global
   under .tm-ds (ds-primitives.css); nothing here needs its own query except
   the one 600ms value-changed flash, which must stay off under
   prefers-reduced-motion.
   ================================================================= */

/* ---------- Page rhythm: `.tm-live-page { display:flex; flex-direction:column;
   gap:8px }` lived in the now-gated v2/components/live-dashboard.css — it was
   the page's ONLY vertical-rhythm mechanism (header/KPI/banners/main-grid/
   table). Without it children fall back to ad-hoc margins → 34/42/44px
   uneven gaps (layout-lint R3, live-r1/r2). Restated at the reference's one
   row gap (24). ---------- */
.tm-ds .tm-live-page {
  display: flex;
  flex-direction: column;
  gap: var(--tm-space-6);
  padding: var(--tm-space-6) 0;   /* same page box as Genel Bakış / Siparişler: shell gutter only, 24 top/bottom */
}

/* ---------- KPI grid: legacy `.tm-live-page .tm-live-kpi-grid .kpi-card`
   (dashboard-vanilla.css, class specificity 0,3,0) ties with ds-stat-card's
   `.tm-ds .kpi-card` (0,2,0) by specificity in the OTHER direction (higher);
   restated here at matching specificity so ds.css (loaded last) wins. ---- */
.tm-ds .tm-live-page .tm-live-kpi-grid.kpi-grid { margin: 0; }
/* r4 (2026-09-13, coordinator): 24/34/44/42px uneven vertical rhythm
   (layout-lint R3) — the demo-tour CTA's own `margin: 6px 0 10px` (template-
   inline, unconditional) stacked on top of `.tm-live-page { gap:24px }`.
   Neighbouring banners in this same template already document the pattern
   ("margin:0 -> dikey aralık parent gap'inden gelir"); restated here so
   ?legacy=1 keeps its original spacing. .tm-kpi-row / .tm-live-main-grid /
   .tm-live-orders-card margins excluded at the source
   (ui-stability-round4-2026-06-05.css, same commit). */
.tm-ds .tm-live-page .tm-demo-tour-cta { margin: 0; }
/* dashboard-vanilla.css (shared with Genel Bakış, not edited here) also sets
   `.tm-live-page .tm-live-main-grid { margin-top: 16px }` at (0,2,0) — beats
   the template's own inline `margin-top: 0` (0,1,0). Restated at (0,3,0). */
.tm-ds .tm-live-page .tm-live-main-grid { margin-top: 0; column-gap: var(--tm-space-4); row-gap: var(--tm-space-6); align-items: start; grid-template-columns: minmax(0, 1fr); }
/* 2026-09-13 (kullanıcı kararı): "Öncelikli aksiyonlar" (aksiyon merkezi) sayfadan kaldırıldı — DS kapsamında gizli,
   DOM/JS sözleşmesi (tmActionInsights) yerinde; grafik satırı tam genişlik: donut 4 + saatlik akış 8 yan yana. */
.tm-ds .tm-live-page #tmActionInsights, .tm-ds .tm-live-page .tm-live-main-grid__sidebar, .tm-ds .tm-live-page #tmDemoTourCta { display: none; }   /* kullanıcı kararı 2026-09-13: aksiyon merkezi ve demo tur daveti Canlı sayfasından kaldırıldı (DOM/JS sözleşmesi yerinde) */   /* the aside wrapper kept a 96px slot */
.tm-ds .tm-live-page .tm-live-main-grid { display: block; }   /* the content column is the only visible child now; as a grid the empty aside slot kept adding a 24px row gap */
.tm-ds .tm-live-page .tm-live-main-grid__content { grid-area: auto; grid-column: 1 / -1; grid-row: 1; min-width: 0; }   /* strict lint 2026-09-13: gap was 20 (not a token); stretch made the donut card 97px taller than its content */
.tm-ds .tm-live-page .tm-live-main-grid__content > .ch-grid,
.tm-ds .tm-live-page .tm-live-main-grid__content > .tm-dashboard-ch-grid { align-content: start; }
.tm-ds .tm-live-page .tm-live-kpi-grid .kpi-card { min-height: var(--tm-dash-kpi-h); }
/* ds-stat-card.css absolute-positions .kpi-head-tools assuming .kpi-card is
   the containing block; tm-kpi.css's `.kpi-head { position: relative }`
   (kept, shared, not edited here) makes .kpi-head the real one, so the
   live badge lands ~17px too low (into the value row). Every card on this
   page is mode:'live' (docs/ui-audit.md Ek B tm-kpi.js), so the badge is
   always present here — re-anchored to .kpi-head's own box, this page only. */
/* 2026-09-24: aynı hizalama artık ds-stat-card.css'te (tüm sayfalar) — sayfa-özel kural kaldırıldı. */
/* Every card on this page carries the "CANLI" live badge (mode:'live' for
   the whole grid, not just one accent card) — at 5-up card width (≈150px)
   the text collided with the label. The reference has no such badge at all
   (docs/ui-reference-spec.md §1); kept as a plain dot (still communicates
   "live"), dropped the redundant text + pill chrome to reclaim label width
   and cut one more saturated-colour use per card (target ≤20/page). */
.tm-ds .tm-live-page .kpi-livebadge {
  gap: 0;
  padding: 0;
  height: auto;
  width: 6px;
  overflow: hidden;
  white-space: nowrap;
  background: transparent;
}
.tm-ds .tm-live-page .kpi-livebadge .live-dot { width: 6px; height: 6px; flex-shrink: 0; }

/* ---------- Chart row (donut + hourly): ds-chart-card.css moved
   .ch-grid/.tm-dashboard-ch-grid to a 12-col grid with span-{3,4,6,8,12}
   only (Genel Bakış's vocabulary — owned file, not edited here). This page's
   template still carries the older 6-col span-2/span-4 classes
   (tm-vanilla-dashboard-charts.css, also used in ?legacy=1 mode) for the
   1:2 donut/hourly split. Re-mapped onto the 12-col grid so the ratio is
   unchanged in both modes; the template classes are not renamed. */
/* 2026-09-13: aksiyon merkezi kaldırılınca ızgara tam sayfa genişliğinde (888+ px) → donut 4 + saatlik akış 8 yan yana
   (kullanıcı kararı). Tablette alt alta. (Önceki ~500 px'lik sütunda 1:2 bölünme donut kartını 159 px'e düşürüyordu.) */
.tm-ds .tm-live-page .tm-dashboard-ch-grid--live > .ch-panel.span-2 { grid-column: span 4; }
.tm-ds .tm-live-page .tm-dashboard-ch-grid--live > .ch-panel.span-4 { grid-column: span 8; }
/* DÜŞÜK-VERİ BOŞLUĞU (2026-09-18): grid satırı (align-items:stretch varsayılan) iki paneli EN
   UZUNA gerip kısa donut kartını dev boşlukla dolduruyordu — az veride donut ortada asılı, altında
   boşluk. Satır gerdirmesini kapat → her panel İÇERİK yüksekliğinde. Dolu veride de düzgün kalır. */
/* 2026-09-24 (kullanıcı): iki kart AYNI boyda olmalı. Satır gerdirmesi açık; saatlik akış paneli
   kendi içerik boyunda kalır (align-self:start) → satır yüksekliği = ikisinin uzunu; donut kartı ona
   gerilir, boş/dolu içeriği dikeyde ortalanır (aşağıda). Böylece ne az-veride kısa kart ne de dolu
   veride saatlik akışın altında boşluk kalır. */
.tm-ds .tm-live-page .tm-dashboard-ch-grid--live { align-items: stretch; }
.tm-ds .tm-live-page .tm-dashboard-ch-grid--live > .ch-panel.tm-live-hourly-panel { align-self: start; }
.tm-ds .tm-live-page .tm-dashboard-ch-grid--live > .ch-panel.span-2 { display: flex; flex-direction: column; }
.tm-ds .tm-live-page .tm-dashboard-ch-grid--live > .ch-panel.span-2 > .ch-mount { flex: 1 1 auto; display: flex; align-items: center; justify-content: center; min-height: 0; }
.tm-ds .tm-live-page .tm-dashboard-ch-grid--live > .ch-panel.span-2 > .ch-mount > .tm-live-empty { flex: 1 1 auto; align-self: stretch; }
/* Boş durum ikonu + yumuşak süzülme (kullanıcı isteği, 2026-09-24); hareket tercihine saygılı. */
@media (prefers-reduced-motion: no-preference) {
  .tm-ds .tm-live-page .tm-live-empty svg { animation: tmEmptyFloat 3.2s ease-in-out infinite; }
}
@media (max-width: 1099.98px) {   /* same breakpoint as the hourly chart's responsive height (tm-vanilla-dashboard-charts.css) */
  .tm-ds .tm-live-page .tm-dashboard-ch-grid--live > .ch-panel.span-2,
  .tm-ds .tm-live-page .tm-dashboard-ch-grid--live > .ch-panel.span-4 { grid-column: span 12; }
}

/* ================= Top strip: pulse line row + controls row =================
   Measured 2026-09-13 (layout-shift sources): with `flex-wrap: wrap` the strip
   was ONE row while the pulse line held skeletons (380px) and wrapped to TWO
   rows once JS filled it (643px) → header 34→73px, everything below moved
   39px = CLS 0.22. Two explicit rows from the first paint: no shift. */
.tm-ds .tm-live-page .tm-live-header {
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;           /* one row when it fits (≥~1500px), two rows below — deterministic because every stat value reserves its width (min-width in ch) */
  align-items: center;
  justify-content: space-between;
  gap: var(--tm-space-3) var(--tm-space-6);
  padding: 0;
  margin: 0;
}
.tm-ds .tm-live-page .tm-live-header > .tm-live-pulseline { width: auto; flex: 1 1 auto; min-height: var(--tm-type-caption-lh); }
.tm-ds .tm-live-page .tm-live-pulseline {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--tm-space-4);
  min-width: 0;
}
.tm-ds .tm-live-page .tm-live-stat {
  display: flex;
  align-items: baseline;
  gap: var(--tm-space-1);
  font-size: var(--tm-type-caption);
  line-height: var(--tm-type-caption-lh);
  white-space: nowrap;
}
/* r4 (2026-09-13, coordinator): dashboard-vanilla.css (shared, not edited
   here) sets `.tm-live-page .tm-live-stat__label { font-size: var(--tm-type-micro) }` /
   `__value { font-size: var(--tm-type-caption) }` (0,2,0) — 2 of the page's off-scale type
   steps. My rules below are (0,3,0) but were silent on font-size, so the
   legacy value still won (same bug class as kpi-head-tools/.num mono).
   Restated at the nearest DS steps (micro 11 / caption 12). */
.tm-ds .tm-live-page .tm-live-stat__label {
  color: var(--tm-text-muted);
  font-size: var(--tm-type-micro);
  line-height: var(--tm-type-micro-lh);
  text-transform: none;
  letter-spacing: 0;
  font-weight: var(--tm-weight-medium);
}
.tm-ds .tm-live-page .tm-live-stat__value {
  color: var(--tm-text-primary);
  font-size: var(--tm-type-caption);
  line-height: var(--tm-type-caption-lh);
  font-weight: var(--tm-weight-semibold);
  font-variant-numeric: tabular-nums;
  min-width: 3ch;
}
/* r4 (2026-09-13, coordinator): remaining 0.0025 load-CLS came from these
   three values arriving async and widening past the blanket 3ch guess
   (measured: "şimdi · Trendyol · ₺900" 143px≈21ch, "10 sip/sa (tipik 0,9)"
   121px≈18ch, "7,4% (5/68)" 76px≈11ch) — sized per stat so the final value
   never grows past its reserved box. */
#tmLiveLastOrder.tm-live-stat__value { min-width: 21ch; }
#tmLivePace.tm-live-stat__value { min-width: 18ch; }
#tmLiveCancelRate.tm-live-stat__value { min-width: 11ch; }

/* r4 (2026-09-13, coordinator): the demo-tour CTA (only demo users) toggles
   `.is-hidden` (display:none -> flex) client-side, AFTER first paint, once a
   session/localStorage dismissal check resolves (template inline <script>,
   not edited here). display:none reserves zero space, so the reveal shifted
   .tm-live-main-grid down — the single largest CLS contributor measured
   (r9/r4-base). `visibility:hidden` reserves the box's final height from the
   very first paint; the class-remove then only changes visibility, zero
   layout shift. Trade-off (documented, not solved): a user who dismissed the
   CTA earlier in the session now sees a permanent empty-but-present slot for
   the rest of this page life — the underlying show/hide model is JS state
   this task does not touch. */
.tm-ds .tm-live-page .tm-demo-tour-cta.is-hidden {
  display: flex;
  visibility: hidden;
  pointer-events: none;
}
.tm-ds .tm-live-page .tm-live-header__row--controls-only { margin: 0; flex-shrink: 0; }
.tm-ds .tm-live-page .tm-live-controls {
  display: flex;
  align-items: center;
  gap: var(--tm-space-2);
  flex-wrap: wrap;
}
.tm-ds .tm-live-page .tm-live-status {
  display: inline-flex;
  align-items: center;
  gap: var(--tm-space-1);
  height: 28px;
  padding: 0 var(--tm-space-2);
  border-radius: var(--tm-radius-control);
  background: var(--tm-bg-subtle);
  color: var(--tm-text-secondary);
  font-size: var(--tm-type-caption);
  line-height: var(--tm-type-caption-lh);
  font-weight: var(--tm-weight-medium);
}
.tm-ds .tm-live-page .tm-live-status[data-state="ok"] { background: var(--tm-success-bg); color: var(--tm-success-fg); }
.tm-ds .tm-live-page .tm-live-status[data-state="error"] { background: var(--tm-danger-bg); color: var(--tm-danger-fg); }
.tm-ds .tm-live-page .tm-live-status__dot { width: 7px; height: 7px; border-radius: var(--tm-radius-full); background: currentColor; flex-shrink: 0; }
.tm-ds .tm-live-page .tm-live-select,
.tm-ds .tm-live-page .tm-live-platform-select {
  height: 28px;
  padding: 0 var(--tm-space-2);
  border: 1px solid var(--tm-border);
  border-radius: var(--tm-radius-control);
  background: var(--tm-bg-surface);
  color: var(--tm-text-primary);
  font-size: var(--tm-type-caption);
  line-height: var(--tm-type-caption-lh);
  box-shadow: none;
}
.tm-ds .tm-live-page .tm-live-header .btn {
  box-shadow: none;
  background: var(--tm-bg-surface);
  border: 1px solid var(--tm-border);
  color: var(--tm-text-primary);
  border-radius: var(--tm-radius-control);
  transform: none;
}
.tm-ds .tm-live-page .tm-live-header .btn:hover { box-shadow: none; transform: none; background: var(--tm-bg-subtle); }
.tm-ds .tm-live-page .tm-live-header .btn--primary {
  background: var(--tm-accent-solid);
  border-color: var(--tm-accent-solid);
  color: var(--tm-on-accent);
}
.tm-ds .tm-live-page .tm-live-header .btn--primary:hover { background: var(--tm-accent-solid); box-shadow: none; }
.tm-ds .tm-live-page .tm-actions-overflow summary {
  height: 28px;
  display: inline-flex;
  align-items: center;
  padding: 0 var(--tm-space-2);
  border: 1px solid var(--tm-border);
  border-radius: var(--tm-radius-control);
  color: var(--tm-text-secondary);
  font-size: var(--tm-type-caption);
  cursor: pointer;
}
/* a disclosure popout is a floating layer, but its class name carries no
   "overlay/dropdown/menu" keyword for the shadow-scope lint to key off —
   named explicitly here instead of relying on --tm-shadow-overlay */
.tm-ds .tm-live-page .tm-actions-overflow__body {
  border: 1px solid var(--tm-border);
  border-radius: var(--tm-radius-control);
  background: var(--tm-bg-surface);
  box-shadow: none;
}

/* ================================ Action centre ============================
   Card chrome (surface/border/radius/24-inset/shadow) already comes from
   ds-primitives .tm-card — .tm-action-insights carries that class. Only the
   list/row/status colour is page-specific. */
.tm-ds .tm-live-page .tm-insights-filters { display: flex; flex-wrap: wrap; gap: var(--tm-space-2); }
.tm-ds .tm-live-page .tm-action-insights__last-check {
  font-size: var(--tm-type-micro);
  line-height: var(--tm-type-micro-lh);
  color: var(--tm-text-muted);
}
.tm-ds .tm-live-page .tm-action-grid { display: flex; flex-direction: column; gap: var(--tm-space-2); }
.tm-ds .tm-live-page .tm-action-card {
  display: flex;
  flex-direction: column;
  gap: var(--tm-space-1);
  width: 100%;
  padding: var(--tm-space-3);
  border: 1px solid var(--tm-border);
  border-left: 3px solid var(--tm-border);
  border-radius: var(--tm-radius-control);
  background: var(--tm-bg-surface);
  color: var(--tm-text-primary);
  text-align: left;
  cursor: pointer;
  transition: none;
}
.tm-ds .tm-live-page .tm-action-card:hover { background: var(--tm-bg-subtle); }
/* colour only for status — the severity stripe, nothing else changes */
.tm-ds .tm-live-page .tm-action-card[data-severity="critical"] { border-left-color: var(--tm-danger-fg); }
.tm-ds .tm-live-page .tm-action-card[data-severity="warning"]  { border-left-color: var(--tm-warning-fg); }
.tm-ds .tm-live-page .tm-action-card[data-severity="info"]     { border-left-color: var(--tm-info-fg); }
.tm-ds .tm-live-page .tm-action-card[data-severity="success"]  { border-left-color: var(--tm-success-fg); }
.tm-ds .tm-live-page .tm-action-card__head { display: flex; align-items: center; gap: var(--tm-space-2); }
.tm-ds .tm-live-page .tm-action-card__icon {
  display: inline-flex; align-items: center; justify-content: center;
  width: 22px; height: 22px; border-radius: var(--tm-radius-full);
  background: var(--tm-bg-subtle); color: var(--tm-text-secondary); flex-shrink: 0;
}
.tm-ds .tm-live-page .tm-action-card__icon i,
.tm-ds .tm-live-page .tm-action-card__icon svg { width: 12px; height: 12px; }
.tm-ds .tm-live-page .tm-action-card__badge {
  font-size: var(--tm-type-micro);
  line-height: var(--tm-type-micro-lh);
  color: var(--tm-text-muted);
  text-transform: uppercase;
  letter-spacing: var(--tm-tracking-wide, 0.02em);
}
.tm-ds .tm-live-page .tm-action-card__chevron { margin-left: auto; color: var(--tm-text-muted); flex-shrink: 0; }
.tm-ds .tm-live-page .tm-action-card__chevron i,
.tm-ds .tm-live-page .tm-action-card__chevron svg { width: 14px; height: 14px; }
.tm-ds .tm-live-page .tm-action-card__title {
  margin: 0;
  font-size: var(--tm-type-body);
  line-height: var(--tm-type-body-lh);
  font-weight: var(--tm-weight-medium);
  color: var(--tm-text-primary);
}
.tm-ds .tm-live-page .tm-action-card__desc {
  margin: 0;
  font-size: var(--tm-type-caption);
  line-height: var(--tm-type-caption-lh);
  color: var(--tm-text-secondary);
}
.tm-ds .tm-live-page .tm-action-card__meta { display: flex; flex-wrap: wrap; gap: var(--tm-space-1); }
.tm-ds .tm-live-page .tm-action-card__pill,
.tm-ds .tm-live-page .tm-action-card__sub-metric {
  display: inline-flex; align-items: center;
  height: 18px; padding: 0 var(--tm-space-1);
  border-radius: var(--tm-radius-control);
  background: var(--tm-bg-subtle);
  color: var(--tm-text-muted);
  font-size: var(--tm-type-micro);
  line-height: var(--tm-type-micro-lh);
}
.tm-ds .tm-live-page .tm-action-card__pill--impact { background: var(--tm-warning-bg); color: var(--tm-warning-fg); }
.tm-ds .tm-live-page .tm-action-card__metric,
.tm-ds .tm-live-page .tm-action-card__footer {
  display: flex; align-items: center; gap: var(--tm-space-1);
  font-size: var(--tm-type-caption); line-height: var(--tm-type-caption-lh);
}
.tm-ds .tm-live-page .tm-action-card__metric-label,
.tm-ds .tm-live-page .tm-action-card__cta { color: var(--tm-text-muted); }
.tm-ds .tm-live-page .tm-action-card__metric-value { font-weight: var(--tm-weight-semibold); font-variant-numeric: tabular-nums; }
.tm-ds .tm-live-page .tm-action-allclear {
  display: flex; align-items: center; gap: var(--tm-space-3);
  padding: var(--tm-space-3);
  color: var(--tm-text-secondary);
  font-size: var(--tm-type-caption);
  line-height: var(--tm-type-caption-lh);
}
.tm-ds .tm-live-page .tm-action-allclear__icon { color: var(--tm-text-muted); flex-shrink: 0; }
.tm-ds .tm-live-page .tm-action-allclear__title { margin: 0; font-weight: var(--tm-weight-semibold); color: var(--tm-text-primary); }
.tm-ds .tm-live-page .tm-action-allclear__desc { margin: 0; }

/* ============================== Orders table =============================
   `.tm-live-tbl` also carries `.tm-table` → row height 52/40, sticky head,
   hover and .tm-num already come from ds-table.css. Only the live-specific
   cell types (order-number mono, `.num` alias, pill, product, status) and
   the filter bar / pager are page-specific. */
.tm-ds .tm-live-page .tm-live-filterbar { display: flex; flex-wrap: wrap; align-items: center; gap: var(--tm-space-3); }
.tm-ds .tm-live-page .tm-live-search {
  display: flex; align-items: center; gap: var(--tm-space-2);
  height: 32px; padding: 0 var(--tm-space-3);
  border: 1px solid var(--tm-border); border-radius: var(--tm-radius-control);
  background: var(--tm-bg-surface); color: var(--tm-text-muted); flex: 1 1 220px; min-width: 160px;
}
.tm-ds .tm-live-page .tm-live-search input {
  border: 0; background: transparent; color: var(--tm-text-primary);
  font-size: var(--tm-type-body); line-height: var(--tm-type-body-lh); width: 100%;
}
.tm-ds .tm-live-page .tm-live-filtergroup { display: flex; align-items: center; gap: var(--tm-space-2); }
.tm-ds .tm-live-page .tm-live-filtergroup__label { font-size: var(--tm-type-caption); color: var(--tm-text-muted); }
/* r4 (2026-09-13, coordinator): amounts/net-kâr/marj were rendering mono —
   attributed via computed-style probe: tm-v2.css:478 `.tm-table td.num {
   font-family: var(--ff-num); font-variant-numeric: tabular-nums; font-weight:600; color:var(--ink); }` (shared,
   not edited here) is silent-but-still-applies on any property MY higher-
   specificity rule below doesn't also set (the class of bug ds-live.css
   already hit twice — kpi-head-tools/donut-span). Spec: mono ONLY for the
   order number; amounts/net-kâr/marj are body-face + tabular-nums. */
.tm-ds .tm-live-page .tm-live-tbl td.num,
.tm-ds .tm-live-page .tm-live-tbl th.num {
  text-align: right;
  font-variant-numeric: tabular-nums;
  font-family: var(--tm-font-sans);
  font-weight: var(--tm-weight-regular);
  color: var(--tm-text-primary);
}
.tm-ds .tm-live-page .tm-live-tbl .tm-mono,
.tm-ds .tm-live-page .tm-live-tbl td[data-cell="order"] {
  font-family: var(--tm-font-mono);
  font-size: var(--tm-type-caption);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  font-variant-numeric: tabular-nums;
}

/* r4 (2026-09-13, coordinator): "Durum" clipped past the card's right edge at
   1280 (measured: card content 838px, table auto-width 900px). table-layout:
   fixed + explicit widths from the header row (thead defines all 8 columns
   in a fixed template order, not JS-reordered — nth-child is safe); product
   name gets the remainder and already ellipsizes internally
   (.tm-live-product__name max-width:22ch). Column budget sums to 838px. */
.tm-ds .tm-live-page .tm-live-tbl { table-layout: fixed; width: 100%; }
/* r4 (2026-09-13, coordinator): "19:16" (5-char mono, 12px) needs 60px —
   54px was clipping it to "19:_" via the shared `.tm-mono` ellipsis rule
   (td[data-cell="time"] also carries .tm-mono). Widened Saat 54->60,
   trimmed 6px total off Net Kâr/Marj (both plain percentages/amounts, no
   truncation risk at the new widths). Budget still sums to 838px. */
/* polish (2026-09-13, item 3): "Hepsiburada" (11 chars) clipped in the 84px
   Pazaryeri column — measured (Playwright): td clientWidth===scrollWidth===84
   at 1280, i.e. the word was cut, not ellipsized (the existing rule set
   `text-overflow:ellipsis` without `white-space:nowrap`, which is a no-op per
   spec — an unbreakable word just overflows and gets clipped by
   `overflow:hidden` instead of showing "…"). Widened Pazaryeri 84->108px +
   added the missing `white-space:nowrap` so any future longer platform name
   ellipsizes instead of clipping silently. Saat is NOT shortened to fund this
   — 54px was proven to clip "19:16" one round ago (comment above); the table
   is `width:100%` with one flexible column (Ürün, nth-child(4), `width:auto`),
   so the +24px comes out of Ürün's remainder automatically, not neighbours. */
.tm-ds .tm-live-page .tm-live-tbl th:nth-child(1),
.tm-ds .tm-live-page .tm-live-tbl td:nth-child(1) { width: 60px; }
.tm-ds .tm-live-page .tm-live-tbl th:nth-child(2),
.tm-ds .tm-live-page .tm-live-tbl td:nth-child(2) { width: 108px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tm-ds .tm-live-page .tm-live-tbl th:nth-child(3),
.tm-ds .tm-live-page .tm-live-tbl td:nth-child(3) { width: 130px; }
.tm-ds .tm-live-page .tm-live-tbl th:nth-child(4),
.tm-ds .tm-live-page .tm-live-tbl td:nth-child(4) { width: auto; overflow: hidden; }
.tm-ds .tm-live-page .tm-live-tbl th:nth-child(5),
.tm-ds .tm-live-page .tm-live-tbl td:nth-child(5) { width: 86px; }
.tm-ds .tm-live-page .tm-live-tbl th:nth-child(6),
.tm-ds .tm-live-page .tm-live-tbl td:nth-child(6) { width: 86px; }
.tm-ds .tm-live-page .tm-live-tbl th:nth-child(7),
.tm-ds .tm-live-page .tm-live-tbl td:nth-child(7) { width: 58px; }
.tm-ds .tm-live-page .tm-live-tbl th:nth-child(8),
.tm-ds .tm-live-page .tm-live-tbl td:nth-child(8) { width: 88px; }
.tm-ds .tm-live-page .tm-live-pill { max-width: 100%; overflow: hidden; text-overflow: ellipsis; }
.tm-ds .tm-live-page .tm-live-tbl td.tm-cell-pos { color: var(--tm-success-fg); font-weight: var(--tm-weight-semibold); }
.tm-ds .tm-live-page .tm-live-tbl td.tm-cell-neg { color: var(--tm-danger-fg); font-weight: var(--tm-weight-semibold); }
.tm-ds .tm-live-page .tm-live-tbl td.tm-cell-unknown { color: var(--tm-text-muted); }
/* maliyet-eksik uyarısı (Canlı Performans, "Bugünün Siparişleri") — satır rozeti
   + kart başlığı sayaç satırı. Renk yalnız --tm-warning-*; boşluk 7-token setinden. */
.tm-ds .tm-live-page .tm-live-cost-badge {
  display: inline-flex; align-items: center; gap: var(--tm-space-1);
  height: 20px; padding: 0 var(--tm-space-2);
  border-radius: var(--tm-radius-control);
  background: var(--tm-warning-bg); color: var(--tm-warning-fg);
  font-size: var(--tm-type-micro); line-height: var(--tm-type-micro-lh); font-weight: var(--tm-weight-medium);
  white-space: nowrap; flex-shrink: 0;
}
.tm-ds .tm-live-page .tm-live-missing-cost-note {
  margin: 0;
  font-size: var(--tm-type-caption); line-height: var(--tm-type-caption-lh);
  color: var(--tm-warning-fg); font-weight: var(--tm-weight-medium);
}
.tm-ds .tm-live-page .tm-live-missing-cost-note a { color: inherit; }
.tm-ds .tm-live-page .tm-live-pill {
  display: inline-flex; align-items: center; gap: var(--tm-space-1);
  color: var(--tm-text-secondary); font-size: var(--tm-type-caption); white-space: nowrap;
}
.tm-ds .tm-live-page .tm-live-pill__dot { width: 6px; height: 6px; border-radius: var(--tm-radius-full); background: var(--tm-accent); flex-shrink: 0; }
.tm-ds .tm-live-page .tm-live-product { display: flex; align-items: center; gap: var(--tm-space-2); min-width: 0; }
.tm-ds .tm-live-page .tm-live-product__img { width: 28px; height: 28px; border-radius: var(--tm-radius-control); flex-shrink: 0; background: var(--tm-bg-subtle); object-fit: cover; }
.tm-ds .tm-live-page .tm-live-product__name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 22ch; }
/* status — the reference StatusBadge: soft bg + text, colour is the only signal */
.tm-ds .tm-live-page .tm-live-state-badge {
  display: inline-flex; align-items: center; gap: var(--tm-space-1);
  height: 22px; padding: 0 var(--tm-space-2);
  border-radius: var(--tm-radius-control);
  background: var(--tm-bg-subtle); color: var(--tm-text-secondary);
  font-size: var(--tm-type-caption); line-height: var(--tm-type-caption-lh); font-weight: var(--tm-weight-medium);
  white-space: nowrap;
}
.tm-ds .tm-live-page .tm-live-state-badge[data-status="completed"] { background: var(--tm-success-bg); color: var(--tm-success-fg); }
.tm-ds .tm-live-page .tm-live-state-badge[data-status="cancelled"] { background: var(--tm-danger-bg); color: var(--tm-danger-fg); }
.tm-ds .tm-live-page .tm-live-state-badge[data-status="returned"] { background: var(--tm-warning-bg); color: var(--tm-warning-fg); }
.tm-ds .tm-live-page .tm-live-tblfoot {
  display: flex; align-items: center; justify-content: space-between; gap: var(--tm-space-3);
  padding-top: var(--tm-space-3);
  font-size: var(--tm-type-caption); color: var(--tm-text-muted); font-variant-numeric: tabular-nums;
}
.tm-ds .tm-live-page .tm-live-pager { display: flex; align-items: center; gap: var(--tm-space-1); }
.tm-ds .tm-live-page .tm-live-pager__btn,
.tm-ds .tm-live-page .tm-live-pager__num {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 26px; height: 26px; padding: 0 var(--tm-space-1);
  border: 1px solid var(--tm-border); border-radius: var(--tm-radius-control);
  background: var(--tm-bg-surface); color: var(--tm-text-secondary);
  font-size: var(--tm-type-caption); font-variant-numeric: tabular-nums; cursor: pointer;
}
.tm-ds .tm-live-page .tm-live-pager__num[aria-current="true"],
.tm-ds .tm-live-page .tm-live-pager__num.is-active { background: var(--tm-accent-bg); color: var(--tm-accent-fg); border-color: transparent; }

/* live update: a row that just arrived gets the same --tm-dur-morph fading highlight
   as a KPI value (ds-stat-card tmKpiFlash) — colour only, no motion, nothing
   else in the row shifts. Off entirely under prefers-reduced-motion (the
   .tm-ds * rule in ds-primitives.css already zeroes animation-duration). */
@keyframes tmLiveRowFlash {
  from { background-color: var(--tm-accent-bg); }
  to   { background-color: transparent; }
}
.tm-ds .tm-live-page .tm-live-tbl tbody tr.is-new { animation: tmLiveRowFlash var(--tm-dur-morph) var(--tm-ease-out) 1; }

/* 2026-09-13 (sert lint r7): tur şeridi → grafik satırı 48 px (24 sayfa + 24 legacy iç boşluk) → 24 */
.tm-ds .tm-live-page .tm-live-main-grid { padding: 0; }
.tm-ds .tm-live-page .tm-live-main-grid__content { margin: 0; padding: 0; }
/* donut kartı (4/12, ~300 px) saatlik akış kartıyla aynı boyda (satır hizası): halka üstte, legend altta tam genişlik,
   içerik kartın boyuna yayılır — yan yana sıkışan legend ("p 8", "%1") ve 291 px boş alt kalmaz */
.tm-ds .tm-live-page .tm-dashboard-ch-grid--live > .ch-panel.span-2 .ch-body { display: flex; flex-direction: column; }
.tm-ds .tm-live-page .tm-dashboard-ch-grid--live > .ch-panel.span-2 .ch-mount { flex: 1 1 auto; display: flex; }
.tm-ds .tm-live-page .tm-dashboard-ch-grid--live > .ch-panel.span-2 .ch-donut-wrap { flex: 1 1 auto; flex-direction: column; flex-wrap: nowrap; align-items: center; justify-content: space-between; gap: var(--tm-space-4); }
.tm-ds .tm-live-page .tm-dashboard-ch-grid--live > .ch-panel.span-2 .ch-donut-wrap svg.ch-donut { width: 200px; height: 200px; max-width: 100%; }
.tm-ds .tm-live-page .tm-dashboard-ch-grid--live > .ch-panel.span-2 .ch-donut-wrap .ch-legend { width: 100%; max-width: none; flex: 0 0 auto; }

/* hourly chart meta (legend + totals): a plain caption row, not a tinted box (reference chart cards carry only a
   segmented control and the plot) */
.tm-ds .tm-live-page .tm-live-hourly-meta { display: flex; flex-wrap: wrap; align-items: center; gap: var(--tm-space-2) var(--tm-space-6); padding: 0; margin: 0; background: transparent; border: 0; border-radius: 0; box-shadow: none; font-size: var(--tm-type-caption); line-height: var(--tm-type-caption-lh); color: var(--tm-text-secondary); }
.tm-ds .tm-live-page .tm-live-hourly-meta[hidden] { display: none; }
.tm-ds .tm-live-page .tm-live-hourly-legend { display: flex; gap: var(--tm-space-4); align-items: center; }
.tm-ds .tm-live-page .tm-live-hourly-legend__item { display: inline-flex; align-items: center; gap: var(--tm-space-2); color: var(--tm-text-secondary); font-weight: var(--tm-weight-medium); }
.tm-ds .tm-live-page .tm-live-hourly-legend__swatch { width: 14px; height: 2px; border-radius: var(--tm-radius-full); background: var(--tm-chart-1); display: inline-block; }
.tm-ds .tm-live-page .tm-live-hourly-legend__swatch.is-baseline { background: var(--tm-border-strong); }
.tm-ds .tm-live-page .tm-live-hourly-stats { display: flex; flex-wrap: wrap; gap: var(--tm-space-2) var(--tm-space-4); margin-left: auto; color: var(--tm-text-muted); font-family: var(--tm-font-sans); }
.tm-ds .tm-live-page .tm-live-hourly-stats strong, .tm-ds .tm-live-page .tm-live-hourly-stats b { color: var(--tm-text-primary); font-weight: var(--tm-weight-semibold); font-family: var(--tm-font-sans); }

/* 2026-09-13 (kullanıcı: "şeritteki elemanlar niye farklı boyutlarda, KPI üstünde niye bu kadar boşluk"):
   üst şeritteki her kontrol 32 px, aynı yarıçap, aynı hairline; nabız çipleri de aynı kutu; şerit → KPI 24 px. */
.tm-ds .tm-live-page .tm-live-header { gap: var(--tm-space-2) var(--tm-space-6); }
.tm-ds .tm-live-page .tm-live-stat,
.tm-ds .tm-live-page .tm-live-status,
.tm-ds .tm-live-page .tm-live-select,
.tm-ds .tm-live-page .tm-live-platform-select,
.tm-ds .tm-live-page .tm-live-header .btn,
.tm-ds .tm-live-page .tm-live-controls > * { box-sizing: border-box; height: 32px; min-height: 32px; padding-top: 0; padding-bottom: 0; border-radius: var(--tm-radius-control); font-size: var(--tm-type-caption); line-height: var(--tm-type-caption-lh); }
.tm-ds .tm-live-page .tm-live-stat { padding-left: var(--tm-space-3); padding-right: var(--tm-space-3); border: 1px solid var(--tm-border); background: var(--tm-bg-surface); align-items: center; }
.tm-ds .tm-live-page .tm-live-status { padding-left: var(--tm-space-3); padding-right: var(--tm-space-3); }
.tm-ds .tm-live-page .tm-live-header .btn { display: inline-flex; align-items: center; gap: var(--tm-space-1); padding-left: var(--tm-space-3); padding-right: var(--tm-space-3); }
.tm-ds .tm-live-page .tm-live-pulseline { gap: var(--tm-space-2); }

/* 2026-09-13 prod geri bildirimi (kullanıcı: "KPI kartlarının üstünde çok fazla boşluk"): üst şeritteki 2 px dikey ayraç
   (`div.tmdr`) 68 px boyundaydı ve satırı 32 → 68 px'e itiyordu (18 px üst + 18 px alt hava). Ayraç gizli; şerit içerik boyunda.
   Fiyat kuralı kapsam uyarısı (`.tm-cov-alert`) Canlı sayfasından kaldırıldı (kullanıcı kararı; Fiyatlandırma sayfasında duruyor). */
.tm-ds .tm-live-page .tm-live-header > .tmdr { display: none; }
.tm-ds .tm-live-page .tm-cov-alert { display: none; }

/* 2026-09-13 prod (gerçek veri): ürün hücresindeki "Mağazada aç" bağlantısı üç satıra kırılıyordu (ikon / metin / dış-bağlantı ikonu).
   Tek satır, ürün adının yanında, ikonlar 12 px. Demo verisinde mağaza bağlantısı olmadığı için yerelde görünmüyordu.
   🔴 2026-10-07 (kullanıcı kararı, ekran görüntüsüyle bildirildi — İKİ TUR):
   ① "Satın al" dolu-mavi, "Mağazada aç" çıplak linkti — özel renk/boyut kuralları
   (eski `.tm-live-product__go` / `--buy`) buradan KALDIRILDI.
   ② İlk düzeltme ikisine `tm-btn--primary`/`tm-btn--ghost` verdi (hâlâ renk ayrımı
   vardı) — kullanıcı "ikisi de AYNI stil" derken BİREBİR aynı sınıfı kastetti.
   İkisi artık TIPATIP AYNI `class` dizgesini taşıyor (`tm-btn tm-btn--ghost
   tm-btn--sm tm-live-product__go`, bkz. dashboard-canli-init.js) — dolu renk YOK,
   hangisinin "satın al" olduğu yalnız `data-tm-satin-al` özniteliğinden anlaşılır.
   Bu dosyada hiçbir renk/buton-stili tanımı YOK; yalnız grup hizalaması (ürün
   adından ayrı, hücrenin sağında) ve ikon/etiket boyutu kaldı. Grup:
   `tm-live-product__actions` (static/js/dashboard/dashboard-canli-init.js —
   buyBtn + goLink burada sarılır). */
.tm-ds .tm-live-page .tm-live-product__actions { display: inline-flex; align-items: center; gap: var(--tm-space-2); margin-left: auto; flex-shrink: 0; }
.tm-ds .tm-live-page .tm-live-product__go-icon,
.tm-ds .tm-live-page .tm-live-product__go-ext { width: 12px; height: 12px; flex-shrink: 0; }
.tm-ds .tm-live-page .tm-live-product__go-label { white-space: nowrap; }
.tm-ds .tm-live-page td[data-cell="product"] > *, .tm-ds .tm-live-page .tm-live-product { display: inline-flex; align-items: center; gap: var(--tm-space-2); min-width: 0; max-width: 100%; }


/* ═══ Pazaryeri kırılımı — donut altındaki boşluğun doldurulması (2026-09-17).
   Kullanıcı: "bu alan çok boş ve kötü duruyor." Donut YALNIZ sipariş ADEDİ payını
   gösteriyordu; "hangi pazaryeri para kazandırıyor" cevapsızdı.

   🔴 Bu blok donut'un KENDİ legend'ini GİZLER: satırlar onun yerine geçer.
   İlk denemede ikisi birden duruyordu → aynı kartta iki platform listesi, kart
   ~950px'e uzadı (boşluktan daha kötü). Satırlar legend'in verdiği her şeyi
   (ad · adet · pay) veriyor, üstüne ciro/kâr/çubuk ekliyor. ═══ */
.tm-ds .tm-live-page #tmLivePlatformVanilla .ch-legend { display: none; }

.tm-ds .tm-live-page .tm-live-plat {
  display: flex;
  flex-direction: column;
  gap: var(--tm-space-3);
  margin-top: var(--tm-space-3);
  padding-top: var(--tm-space-3);
  border-top: 1px solid var(--tm-border);
}
.tm-ds .tm-live-page .tm-live-plat[hidden] { display: none; }
.tm-ds .tm-live-page .tm-live-plat__row { display: flex; flex-direction: column; gap: 3px; }
.tm-ds .tm-live-page .tm-live-plat__head {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: var(--tm-space-2); min-width: 0;
}
.tm-ds .tm-live-page .tm-live-plat__name {
  display: inline-flex; align-items: center; gap: var(--tm-space-2);
  min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  font-size: var(--tm-type-body); color: var(--tm-text-primary);
}
.tm-ds .tm-live-page .tm-live-plat__dot {
  width: 8px; height: 8px; flex: 0 0 auto; border-radius: var(--tm-radius-full);
  background: var(--tm-text-muted);
}
.tm-ds .tm-live-page .tm-live-plat__rev {
  font-variant-numeric: tabular-nums; font-weight: var(--tm-weight-semibold);
  font-size: var(--tm-type-body); color: var(--tm-text-primary); flex-shrink: 0;
}
/* Çubuk: ray + dolgu. Dolgu rengi donut diliminin rengiyle AYNI (JS'ten inline). */
.tm-ds .tm-live-page .tm-live-plat__bar {
  height: 5px; border-radius: var(--tm-radius-full);
  background: var(--tm-surface-sunken); overflow: hidden;
}
.tm-ds .tm-live-page .tm-live-plat__bar > span {
  display: block; height: 100%; border-radius: inherit; background: var(--tm-text-muted);
}
.tm-ds .tm-live-page .tm-live-plat__meta {
  display: flex; flex-wrap: wrap; align-items: center;
  gap: 2px var(--tm-space-2);
  font-size: var(--tm-type-caption); line-height: var(--tm-type-caption-lh);
  color: var(--tm-text-secondary); font-variant-numeric: tabular-nums;
}
.tm-ds .tm-live-page .tm-live-plat__meta .tm-cell-pos { color: var(--tm-success-fg); font-weight: var(--tm-weight-semibold); }
.tm-ds .tm-live-page .tm-live-plat__meta .tm-cell-neg { color: var(--tm-danger-fg); font-weight: var(--tm-weight-semibold); }
.tm-ds .tm-live-page .tm-live-plat__share { color: var(--tm-text-primary); font-weight: var(--tm-weight-semibold); }
/* Adet payı ↔ ciro payı ayrışmasının tek kelimelik özeti. */
.tm-ds .tm-live-page .tm-live-plat__note {
  padding: 0 var(--tm-space-2); border-radius: var(--tm-radius-full);
  background: var(--tm-accent-bg); color: var(--tm-accent-fg);
  font-weight: var(--tm-weight-semibold);
}

/* ═══ SİPARİŞ TABLOSU — MOBİL YIĞILMIŞ KART (2026-09-18 görsel iyileştirme) ═══════
   ds-live.css AKTİF .tm-ds bundle'ı tabloyu table-layout:fixed + 8 sabit-genişlik kolonla
   çiziyor (~610px) → ≤560px'te yatay-scroll'da Tutar/Net Kâr/Marj/Durum ekran dışı kalıyordu.
   (Legacy live-dashboard.css'teki kart düzeni bu sayfada INERT — DS bundle kazanıyor.) Hücrelerdeki
   mevcut data-cell attribute'ları etiket olur; #id specificity nth-child sabit-genişlikleri ezer. */
@media (max-width: 560px){
  .tm-ds .tm-live-page .tm-live-orders-card .tm-table-scroll{ overflow: visible; padding: 0; }
  .tm-ds .tm-live-page #tmLiveTable{ table-layout: auto; }
  .tm-ds .tm-live-page #tmLiveTable thead{ display: none; }
  .tm-ds .tm-live-page #tmLiveTable,
  .tm-ds .tm-live-page #tmLiveTable tbody,
  .tm-ds .tm-live-page #tmLiveTable tr,
  .tm-ds .tm-live-page #tmLiveTable td{ display: block; width: auto; }
  .tm-ds .tm-live-page #tmLiveTable tr{
    border:1px solid var(--tm-border,#e5e7eb); border-radius:12px; padding:8px 12px;
    margin-bottom:10px; background:var(--tm-bg-surface,#fff);
  }
  .tm-ds .tm-live-page #tmLiveTable td{
    border:none; padding:5px 0; display:flex; align-items:center; justify-content:space-between;
    gap:12px; text-align:right; white-space:normal; overflow:visible;
  }
  .tm-ds .tm-live-page #tmLiveTable td::before{
    content: attr(data-cell); color:var(--tm-text-muted,#64748b); font-size:11px; font-weight:600;
    text-transform:uppercase; letter-spacing:.03em; text-align:left; flex:0 0 auto;
  }
  .tm-ds .tm-live-page #tmLiveTable td[data-cell="time"]::before{ content:"Saat"; }
  .tm-ds .tm-live-page #tmLiveTable td[data-cell="pill"]::before{ content:"Pazaryeri"; }
  .tm-ds .tm-live-page #tmLiveTable td[data-cell="order"]::before{ content:"Sipariş No"; }
  .tm-ds .tm-live-page #tmLiveTable td[data-cell="product"]::before{ content:"Ürün"; }
  .tm-ds .tm-live-page #tmLiveTable td[data-cell="price"]::before{ content:"Tutar"; }
  .tm-ds .tm-live-page #tmLiveTable td[data-cell="profit"]::before{ content:"Net Kâr"; }
  .tm-ds .tm-live-page #tmLiveTable td[data-cell="margin"]::before{ content:"Marj"; }
  .tm-ds .tm-live-page #tmLiveTable td[data-cell="status"]::before{ content:"Durum"; }
  .tm-ds .tm-live-page #tmLiveTable td[data-cell="product"]{ flex-direction:column; align-items:flex-start; text-align:left; gap:3px; }
  /* 2026-10-05: "Satın al" + "Mağazada aç" eklenince ürün adı sıfıra eziliyordu → kart içinde satıra kırılır. */
  .tm-ds .tm-live-page #tmLiveTable td[data-cell="product"]{ height:auto; }
  .tm-ds .tm-live-page #tmLiveTable td[data-cell="product"] .tm-live-product{ flex-wrap:wrap; row-gap:6px; }
  .tm-ds .tm-live-page #tmLiveTable td[data-cell="product"] .tm-live-product__name{ flex:1 1 60%; max-width:none; }
  .tm-ds .tm-live-page #tmLiveTable td[colspan]{ display:block; text-align:center; }
  .tm-ds .tm-live-page #tmLiveTable td[colspan]::before{ content:""; }
  .tm-ds .tm-live-page #tmLiveTable tr.is-skel td::before{ content:""; }
}

/* ═══ 2026-10-03 KULLANILABİLİRLİK DÜZELTMELERİ (kullanıcı: "görsel olarak tutarlı ama kullanıcı için çok
   kullanışlı değil"). Ölçüm gerçek sayfada (gorsel_sunucu canli-performans, 1440 + 390):
   ① tablo: ürün adı 22ch'te kesiliyordu (1440'ta bile "Bambu Kesme Tahtası B…"), boş alan varken
   ② pazaryeri kartı ~700px, saatlik akış ~490px → sağda ~200px boşluk (grafik boyu: tm-vanilla-dashboard-charts.css)
   ③ mobil sipariş kartı 8 etiketli satır (~450px/sipariş) → 10 sipariş ≈ 4.500px kaydırma
   DS kuralları (token boşluk, !important yok, renk sabiti yok) bu blokta korunur; başka stili EZMESİ gereken
   üç kural (KPI ızgarası, seçici genişliği, kart arka planı) static/css/v2/components/live-dashboard.css'te. ═══ */

/* ① ürün adı kolonun kalanını kullanır */
.tm-ds .tm-live-page .tm-live-product { min-width: 0; }
.tm-ds .tm-live-page .tm-live-product__name { max-width: none; flex: 1 1 auto; min-width: 0; }

/* ② pazaryeri satırları sıkı */
.tm-ds .tm-live-page .tm-live-plat { gap: var(--tm-space-2); padding-top: var(--tm-space-2); }
.tm-ds .tm-live-page .tm-live-plat__row { gap: var(--tm-space-1); }
.tm-ds .tm-live-page .tm-live-plat__bar { height: 4px; }
.tm-ds .tm-live-page .tm-live-plat__meta { flex-wrap: nowrap; white-space: nowrap; overflow: hidden; }

/* ③ mobil */
@media (max-width: 560px){
  .tm-ds .tm-live-page .tm-live-controls { flex-wrap: nowrap; width: 100%; }
  .tm-ds .tm-live-page .tm-live-status { flex: 1 1 auto; min-width: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
  .tm-ds .tm-live-page .tm-live-pulseline { display: grid; grid-template-columns: 1fr 1fr; gap: var(--tm-space-2); width: 100%; }
  .tm-ds .tm-live-page .tm-live-pulseline .tm-live-stat:first-child { grid-column: 1 / -1; }
  .tm-ds .tm-live-page .tm-live-stat { min-width: 0; overflow: hidden; }

  /* Sipariş kartı: saat·pazaryeri·durum / ürün / sipariş no·tutar·kâr·marj */
  /* 2026-10-09: ADET ve AKSİYON hücreleri eklendi → iki yeni alan. `actions` kendi
     satırında ve TAM GENİŞLİK (kullanıcı isteği); `qty` de kendi satırında,
     etiket solda · sayı sağda. Alan adı yazılmayan bir
     hücre ızgaraya "auto-placement" ile girip kartı bozardı — ikisi de adlandırıldı. */
  .tm-ds .tm-live-page #tmLiveTable tr:not(.is-skel){
    display: grid; grid-template-columns: auto minmax(0, 1fr) auto auto auto;
    grid-template-areas: "time pill pill pill status" "product product product product product"
                         "order order order order order"
                         "qty qty price profit margin"
                         "actions actions actions actions actions";
    column-gap: var(--tm-space-3); row-gap: var(--tm-space-1); padding: var(--tm-space-3);
  }
  .tm-ds .tm-live-page #tmLiveTable tr:not(.is-skel) td{ padding: 0; justify-content: flex-start; text-align: left; }
  .tm-ds .tm-live-page #tmLiveTable tr:not(.is-skel) td::before{ content: none; }
  .tm-ds .tm-live-page #tmLiveTable td[data-cell="time"]{ grid-area: time; font-size: 12px; color: var(--tm-text-muted); }
  .tm-ds .tm-live-page #tmLiveTable td[data-cell="pill"]{ grid-area: pill; }
  .tm-ds .tm-live-page #tmLiveTable td[data-cell="status"]{ grid-area: status; justify-content: flex-end; }
  .tm-ds .tm-live-page #tmLiveTable td[data-cell="product"]{ grid-area: product; }
  .tm-ds .tm-live-page #tmLiveTable td[data-cell="product"] .tm-live-product{ width: 100%; }
  .tm-ds .tm-live-page #tmLiveTable td[data-cell="product"] .tm-live-product__name{ white-space: normal; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; }
  .tm-ds .tm-live-page #tmLiveTable td[data-cell="order"]{ grid-area: order; font-size: 11px; color: var(--tm-text-muted); align-self: end; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; display: block; min-width: 0; }
  .tm-ds .tm-live-page #tmLiveTable td[data-cell="price"],
  .tm-ds .tm-live-page #tmLiveTable td[data-cell="profit"],
  .tm-ds .tm-live-page #tmLiveTable td[data-cell="margin"]{ flex-direction: column; align-items: flex-end; text-align: right; font-variant-numeric: tabular-nums; font-size: var(--tm-type-caption); }
  .tm-ds .tm-live-page #tmLiveTable td[data-cell="price"]{ grid-area: price; }
  .tm-ds .tm-live-page #tmLiveTable td[data-cell="profit"]{ grid-area: profit; }
  .tm-ds .tm-live-page #tmLiveTable td[data-cell="margin"]{ grid-area: margin; }
  .tm-ds .tm-live-page #tmLiveTable tr:not(.is-skel) td[data-cell="price"]::before,
  .tm-ds .tm-live-page #tmLiveTable tr:not(.is-skel) td[data-cell="profit"]::before,
  .tm-ds .tm-live-page #tmLiveTable tr:not(.is-skel) td[data-cell="margin"]::before{
    display: block; font-size: var(--tm-type-micro); font-weight: 600; letter-spacing: .03em;
    text-transform: uppercase; color: var(--tm-text-muted);
  }
  .tm-ds .tm-live-page #tmLiveTable tr:not(.is-skel) td[data-cell="price"]::before{ content:"Tutar"; }
  .tm-ds .tm-live-page #tmLiveTable tr:not(.is-skel) td[data-cell="profit"]::before{ content:"Net Kâr"; }
  .tm-ds .tm-live-page #tmLiveTable tr:not(.is-skel) td[data-cell="margin"]::before{ content:"Marj"; }
  /* ADET: diğer üç sayıyla aynı kademe ve aynı etiket biçimi. */
  /* ADET, kartta diğer üç sayıyla AYNI satırda ve AYNI biçimde (etiket üstte, değer altta).
     Önce kendi tam-genişlik satırındaydı; o düzende SİPARİŞ NO iki sütuna sıkışıp kesiliyordu
     (ölçüldü 390px: `order` hücresi taşıyor). Sipariş no tam satıra geri alındı, ADET
     sayı satırına katıldı — ikisi de kesilmiyor. */
  .tm-ds .tm-live-page #tmLiveTable td[data-cell="qty"]{ grid-area: qty; flex-direction: column; align-items: flex-end; text-align: right; font-variant-numeric: tabular-nums; font-size: var(--tm-type-caption); }
  .tm-ds .tm-live-page #tmLiveTable tr:not(.is-skel) td[data-cell="qty"]::before{
    display: block; font-size: var(--tm-type-micro); font-weight: 600; letter-spacing: .03em;
    text-transform: uppercase; color: var(--tm-text-muted); content: "Adet";
  }
  /* AKSİYON: kartın altında tam genişlik; iki düğme eşit pay alır (dokunma hedefi 36px).
     Masaüstündeki "ikon-only" kısaltması burada GEÇERSİZ — mobilde etiket şart,
     tek başına ikonun ne yaptığı hover ipucu olmadan anlaşılmaz. */
  .tm-ds .tm-live-page #tmLiveTable td[data-cell="actions"]{ grid-area: actions; padding-top: var(--tm-space-2); }
  .tm-ds .tm-live-page #tmLiveTable td[data-cell="actions"] .tm-live-rowact{ display: flex; width: 100%; gap: var(--tm-space-2); }
  .tm-ds .tm-live-page #tmLiveTable td[data-cell="actions"] .tm-live-rowact__btn{ flex: 1 1 0; justify-content: center; min-height: 36px; }
  .tm-ds .tm-live-page #tmLiveTable td[data-cell="actions"] .tm-live-rowact__lbl{ display: inline; }
  .tm-ds .tm-live-page #tmLiveTable td[data-cell="actions"] .tm-live-rowact__bos{ display: none; }
  /* Ürün hücresi mobilde: ad 2 satır kutu, kod altında tek satır. */
  .tm-ds .tm-live-page #tmLiveTable td[data-cell="product"] .tm-live-product__txt{ width: 100%; }
}

/* ====================================================================
   2026-10-09 — Canlı Performans düzen + tipografi (kullanıcı isteği)
   ==================================================================== */

/* ① KPI SAYISI ÖLÇEĞE DÖNÜYOR. dashboard-vanilla.css:388 bu sayfaya özel bir
   `clamp(20px, 1.55vw, 26px)` yazıyor; seçici (0,3,0) olduğu için ds-stat-card.css’in
   `.tm-ds .kpi-value` (0,2,0) token kuralını — min-width:1440 medyası dahil — EZİYOR.
   ÖLÇÜLDÜ (1440px): Canlı 22,32px (1,55vw), Genel Bakış ise aynı kart ailesinde 24px.
   Seçici `.tm-live-page`-kapsamlı olduğu için Genel Bakış hiç eşleşmiyor → iki sayfa
   aynı rol için iki farklı boy. Burada (0,4,0) ile token'a geri dönülüyor: <1440 20/28,
   ≥1440 24/32 — yani clamp’in alt ucu zaten buydu, değişen yalnız akışkanlık ve üst uç.
   (ds-tokens.css’deki "5’li destede 24 taşırdı" notu display-sm’i savunur; o not
   <1440 içindir ve token zaten orada 20 diyor.) */
.tm-ds .tm-live-page .tm-live-kpi-grid .kpi-value {
  font-size: var(--tm-type-display-sm);
  line-height: var(--tm-type-display-sm-lh);
}
@media (min-width: 1440px) {
  .tm-ds .tm-live-page .tm-live-kpi-grid .kpi-value {
    font-size: var(--tm-type-display);
    line-height: var(--tm-type-display-lh);
  }
}

/* ② Platform kartı: halka kalan boşluğa büyür (sabit 200px kuralı
   tm-vanilla-dashboard-charts.css’in id’li 140px kuralı tarafından ezildiği için ÖLÜYDÜ
   — ölçüm 2026-10-09: gerçek halka 140×140). Artık iki pakette de aynı davranış.
   `justify-content: space-between` kaldırıldı: halkayı kartın tam ortasına çivileyip
   listeyi dibe iten kural oydu. */
.tm-ds .tm-live-page .tm-dashboard-ch-grid--live > .ch-panel.span-2 .ch-donut-wrap {
  justify-content: center; height: 100%;
}
.tm-ds .tm-live-page .tm-dashboard-ch-grid--live > .ch-panel.span-2 .ch-donut-wrap svg.ch-donut {
  width: auto; height: 100%; max-height: min(240px, 100%); min-height: 0; max-width: 100%;
}
/* Mount’un tabanı kartın doğal yüksekliğini belirler — 110 (bkz. tm-vanilla…css açıklaması). */
.tm-ds .tm-live-page .tm-dashboard-ch-grid--live > .ch-panel.span-2 > .ch-mount {
  flex: 1 1 110px; min-height: 110px; overflow: hidden;
}

/* ③ Yeni parçaların token'lı sürümü (tm-vanilla’daki id’li kurallarla AYNI değer).
   Satır/başlık/yıldız renkleri DS metin kademelerinden gelir, düz hex değil. */
.tm-ds .tm-live-page .tm-live-plat__cols {
  border-bottom-color: var(--tm-border); color: var(--tm-text-muted);
  font-size: var(--tm-type-micro); line-height: var(--tm-type-micro-lh);
}

/* ④ Saatlik Akış özet satırı: ana rakam başlık kademesine çıkar (metin aynı). */
.tm-ds .tm-live-page .tm-live-hourly-stats .tm-live-hourly-stat { display: inline-flex; align-items: baseline; gap: var(--tm-space-1, 4px); }
.tm-ds .tm-live-page .tm-live-hourly-stats .tm-live-hourly-stat.is-ana > strong {
  font-size: var(--tm-type-title); line-height: var(--tm-type-title-lh);
}

/* ⑤ Koyu temada özet şeridinin ARKA PLANI: tm-vanilla-dashboard-charts.css’teki
   `html.dark-mode .tm-live-hourly-panel .tm-live-hourly-meta` (0,3,1) kuralları, DS’in
   `.tm-ds .tm-live-page .tm-live-hourly-meta` (0,3,0) düz-zemin kuralını eziyordu → açık temada
   çerçevesiz bir satır, koyu temada gradyanlı bir kutu görünüyordu (aynı bileşen, iki farklı
   kimlik — ekran görüntüsünde açıkça görülüyor). İkisi de düz zemine çekildi (2026-10-09). */
html.dark-mode .tm-ds .tm-live-page .tm-live-hourly-panel .tm-live-hourly-meta,
body.dark-mode .tm-ds .tm-live-page .tm-live-hourly-panel .tm-live-hourly-meta {
  background: transparent; border: 0; padding: 0; box-shadow: none;
}

/* ====================================================================
   2026-10-09 — "Bugünün Siparişleri" tablosu: ADET sütunu + AKSİYON sütunu +
   iki satırlı ürün hücresi (kullanıcı isteği)
   -------------------------------------------------------------------
   SÜTUN BÜTÇESİ YENİDEN KURULDU. Tablo `table-layout: fixed` + nth-child genişlikler
   ile çiziliyor; iki sütun eklenince ESKİ nth-child numaraları KAYAR (5=Tutar artık
   5=Adet olur) — bu yüzden aşağıdaki blok eski 1-8 kurallarını 1-10 olarak YENİDEN
   yazıyor; yukarıdaki r4/polish kuralları aynı özgüllükte ama DAHA ERKEN olduğu için
   burada eziliyor. Eski genişlik gerekçeleri (Saat 60 "19:16" kesiliyordu · Pazaryeri
   108 "Hepsiburada" kesiliyordu) KORUNDU.
     1 Saat 60 · 2 Pazaryeri 108 · 3 Sipariş No 124 · 4 Ürün auto · 5 Adet 54
     6 Tutar 86 · 7 Net Kâr 80 · 8 Marj 58 · 9 Durum 88 · 10 Aksiyon 168 (<1400: 76)
   ==================================================================== */
.tm-ds .tm-live-page .tm-live-tbl th:nth-child(1),
.tm-ds .tm-live-page .tm-live-tbl td:nth-child(1) { width: 60px; }
.tm-ds .tm-live-page .tm-live-tbl th:nth-child(2),
.tm-ds .tm-live-page .tm-live-tbl td:nth-child(2) { width: 108px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* 2026-10-16: ≥1400'de 108 px "Hepsiburada"yı kesiyordu (84 < 99 px; logo + metin 100 px istiyor).
   Sağ iç boşluk 12 → 4 (komşu sütunun kendi sol boşluğu var) + genişlik 116 → içerik kutusu 100 px.
   8 px esnek ÜRÜN sütunundan gelir. <1400'de ÜRÜN zaten dar (1280: 138), 108 kalır. */
@media (min-width: 1400px) {
  .tm-ds .tm-live-page .tm-live-tbl th:nth-child(2),
  .tm-ds .tm-live-page .tm-live-tbl td:nth-child(2) { width: 116px; padding-right: 4px; }
}
.tm-ds .tm-live-page .tm-live-tbl th:nth-child(3),
.tm-ds .tm-live-page .tm-live-tbl td:nth-child(3) { width: 124px; }
.tm-ds .tm-live-page .tm-live-tbl th:nth-child(4),
.tm-ds .tm-live-page .tm-live-tbl td:nth-child(4) { width: auto; overflow: hidden; }
.tm-ds .tm-live-page .tm-live-tbl th:nth-child(5),
.tm-ds .tm-live-page .tm-live-tbl td:nth-child(5) { width: 48px; }
.tm-ds .tm-live-page .tm-live-tbl th:nth-child(6),
.tm-ds .tm-live-page .tm-live-tbl td:nth-child(6) { width: 86px; }
.tm-ds .tm-live-page .tm-live-tbl th:nth-child(7),
.tm-ds .tm-live-page .tm-live-tbl td:nth-child(7) { width: 86px; }
/* MARJ 68: "-%%22,8" 65px istiyor (ölçüldü 1440) — 60’da son rakam kesiliyordu. */
.tm-ds .tm-live-page .tm-live-tbl th:nth-child(8),
.tm-ds .tm-live-page .tm-live-tbl td:nth-child(8) { width: 68px; }
.tm-ds .tm-live-page .tm-live-tbl th:nth-child(10),
.tm-ds .tm-live-page .tm-live-tbl td:nth-child(10) { width: 84px; }

/* Tutar · Net Kâr · Marj · Adet: sağa hizalı, tabular-nums (rakamlar alt alta tutsun). */
.tm-ds .tm-live-page .tm-live-tbl td[data-cell="qty"],
.tm-ds .tm-live-page .tm-live-tbl th.num { text-align: right; font-variant-numeric: tabular-nums; }
.tm-ds .tm-live-page .tm-live-tbl td[data-cell="qty"] { color: var(--tm-text-secondary); }

/* ÜRÜN hücresi iki satır: ad (1 satır, ellipsis) + barkod/kod (küçük, mono). */
.tm-ds .tm-live-page .tm-live-product__txt { display: flex; flex-direction: column; min-width: 0; flex: 1 1 auto; gap: 1px; }
.tm-ds .tm-live-page .tm-live-product__name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: none; }
.tm-ds .tm-live-page .tm-live-product__kod {
  font-family: var(--tm-font-mono); font-size: var(--tm-type-micro); line-height: var(--tm-type-micro-lh);
  color: var(--tm-text-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.tm-ds .tm-live-page .tm-live-mp-badge {
  display: inline-flex; align-items: center; gap: var(--tm-space-1); flex-shrink: 0;
  height: 20px; padding: 0 var(--tm-space-2); border-radius: var(--tm-radius-control);
  background: var(--tm-bg-subtle); color: var(--tm-text-secondary);
  font-size: var(--tm-type-micro); line-height: var(--tm-type-micro-lh); font-weight: var(--tm-weight-medium);
  white-space: nowrap;
}
.tm-ds .tm-live-page .tm-live-mp-badge [data-lucide] { width: 11px; height: 11px; }
/* 2026-10-16: "+N kalem" rozeti kod satırında (dashboard-canli-init.js). Satır yüksekliği artmasın diye
   rozet 20 → 14 px (kod satırının micro satır yüksekliği); kod kısalır, rozet kısalmaz. */
.tm-ds .tm-live-page .tm-live-product__alt { display: flex; align-items: center; gap: var(--tm-space-2); min-width: 0; }
.tm-ds .tm-live-page .tm-live-product__alt > .tm-live-product__kod { min-width: 0; flex: 0 1 auto; }
.tm-ds .tm-live-page .tm-live-product__alt > .tm-live-mp-badge { height: 14px; padding: 0 var(--tm-space-1); }

/* AKSİYON hücresi: iki düğme sağa hizalı. Satır tıklanınca detay çekmecesi açılıyor;
   düğmelerin kendi işleri var → hücrede imleç varsayılan, satır "pointer" değil. */
.tm-ds .tm-live-page .tm-live-tbl td[data-cell="actions"] { text-align: right; }
.tm-ds .tm-live-page .tm-live-rowact { display: inline-flex; align-items: center; gap: var(--tm-space-2); justify-content: flex-end; }
.tm-ds .tm-live-page .tm-live-rowact__bos { color: var(--tm-text-muted); }
.tm-ds .tm-live-page .tm-live-rowact__btn { flex-shrink: 0; }
.tm-ds .tm-live-page .tm-live-rowact__ic,
.tm-ds .tm-live-page .tm-live-rowact__ext { width: 12px; height: 12px; flex-shrink: 0; }
.tm-ds .tm-live-page .tm-live-rowact__lbl { white-space: nowrap; }

/* <1400px: etiketler düşer, ikon-only kalır — 168px’lik sütun 1280’de ÜrÜN’ü 100px’in
   altına düşürüyordu (ölçüm 2026-10-09). Erişilebilirlik korunur: her iki düğmede de
   `title` + `aria-label` zaten var (dashboard-canli-init.js), etiket yalnız GÖRSEL. */
/* DURUM 88’e geri: 80’e kırpınca "Geçerli" rozeti taşıyordu (ölçüldü, her genişlikte). */
.tm-ds .tm-live-page .tm-live-tbl th:nth-child(9),
.tm-ds .tm-live-page .tm-live-tbl td:nth-child(9) { width: 88px; }
/* ≥1600: iki etiketli düğme + dış-bağlantı ikonu 221px istiyor → 232. */
@media (min-width: 1600px) {
  .tm-ds .tm-live-page .tm-live-tbl th:nth-child(10),
  .tm-ds .tm-live-page .tm-live-tbl td:nth-child(10) { width: 232px; }
}
/* <1400: SİPARİŞ NO 184 → 120. 184, Amazon’un 19 karakterlik numarası içindi (2026-10-05);
   dar ekranda o 64px ÜRÜN ADINDAN çalınıyor (ölçüldü 1280: ad 40px). Numara kesilince
   `title` tam değeri taşır ve satır tıklanınca detay çekmecesi zaten tam numarayı yazıyor. */
@media (max-width: 1399.98px) {
  .tm-ds .tm-live-page .tm-live-tbl th:nth-child(3),
  .tm-ds .tm-live-page .tm-live-tbl td:nth-child(3) { width: 120px; }
}
/* <1180: 10 sütun artık SİĞMİYOR. ÖLÇÜLDÜ (1100, tablo 772px): sabitler 716 → ÜRÜN 56px,
   ad 0px — hücre boş görünüyordu. Burada ezmek yerine KAYDIRMAYA geçiyoruz: sarmalayıcı
   `.tm-table-scroll` zaten `overflow-x:auto` (ui-polish-2026-06-04.css:109), tabloya taban
   genişlik verilir. 2026-09-13’teki "fixed layout" kararı "Durum kesiliyordu" diye alınmıştı;
   taban-genişlikli kaydırmada HİÇBİR ŞEY kesilmiyor, o gerekçe karşılanıyor.
   ≤560px zaten kart düzenine geçiyor (ayrı blok), bu aralık yalnız tablet/dar masaüstü. */
@media (min-width: 560.02px) and (max-width: 1179.98px) {
  .tm-ds .tm-live-page .tm-live-tbl { min-width: 940px; }
}
@media (max-width: 1599.98px) {
  .tm-ds .tm-live-page .tm-live-rowact__lbl,
  .tm-ds .tm-live-page .tm-live-rowact__ext,
  .tm-ds .tm-live-page .tm-live-cost-badge__lbl { display: none; }
  .tm-ds .tm-live-page .tm-live-rowact__btn { padding-left: var(--tm-space-2); padding-right: var(--tm-space-2); }
  .tm-ds .tm-live-page .tm-live-cost-badge { padding: 0 var(--tm-space-1); }
}

/* ═══ 2026-10-10 — YOĞUNLUK + GRAFİK TASARIMI (kullanıcı: "konteynerler, grafikler çok büyük, kaba; KPI ile
   grafik arasında niye boşluk var; grafik ve pasta tasarımlarını iyileştir, daha yoğun ve kullanışlı").
   Ekran görüntüsü incelemesi (1650×935, QA senaryosu) — tespitler:
   ① KPI kartı 160 px, değer 24 px; kart gövdesinin yarısı boş kıvılcım kutusu.
   ② KPI ile grafik satırı arasında 58 px boşluk: dashboard-vanilla.css `.tm-kpi-row{min-height:150px}`
      (kartlar 108'e inince satır 150'de kaldı) + ana ızgara margin-top 16.
   ③ Saatlik Akış: başlık 26 px + alt yazı + 2. satırda legend/istatistik → grafik 130 px aşağıda başlıyor;
      "Bugün toplam" gibi asıl sayı 12 px küçük metin, kullanıcı aramak zorunda.
   ④ Platform kartı: tek dilimli 240 px halka ("4 Sipariş") kartın yarısı; bilgi (satırlar, yıldız) altına itilmiş.
   Çözüm (yalnız bu sayfa; DOM/JS aynı; duman testi canli-duzen-duman-2026-10-09.cjs sözleşmesi korunur):
   KPI 108 px + değer 20 px; boşluk 58 → 12; Saatlik Akış başlığı tek satır + istatistik şeridi "hero"
   (Bugün toplam 20 px, kıyaslar yanında, legend sağda), grafik 260; Platform kartı 2 sütun: halka 120 px
   SOLDA, pazaryeri satırları SAĞINDA, yıldız altta tam genişlik. ═══ */
/* 2026-10-11 (kullanıcı ekran görüntüsü): 16 px'lik kıvılcım kartın alt
   kenarına yapışık, uç noktası kenarda kesik duruyordu. Kart 112 → 120,
   kıvılcım 16 → 24 px; alt metin (`.kpi-vs`) artık çoğunlukla tek ortak
   notta (`#tmLiveKpiNote`) olduğu için kart içi satır sayısı artmadı. */
.tm-ds .tm-live-page { --tm-dash-sparkline-h: 24px; --tm-dash-kpi-h: 120px; }
/* Kıvılcım yüksekliği id-özgüllüklü kuralla sabitlenmiş (tm-vanilla-dashboard-charts.css ≤560 bloğu + DS);
   token tek başına ezilmiyordu → ölçülen 56 px, kart (overflow:hidden) altından kırpılıyordu (QA BLOK-3).
   Kart bütçesi: 12 pad + 24 baş + 58 gövde + 16 kıvılcım = 110 ≤ 112. */
html body .tm-ds .tm-live-page .tm-live-kpi-grid .kpi-chart { height: var(--tm-dash-sparkline-h) !important; }
/* İki grafik kartı AYNI boyda (kullanıcı 2026-09-24) — eski eşitlik saatlik yüksekliğin (450) platform kartının
   doğal boyuna denk gelmesine dayanıyordu; grafik 240'a inince iki kart da satıra GERİLİR (align-self: stretch),
   satır = uzun olanın boyu (zengin veride platform, az veride saatlik). Grafik üstte sabit 240; artan boşluk altta. */
.tm-ds .tm-live-page .tm-dashboard-ch-grid--live > .ch-panel.tm-live-hourly-panel { align-self: stretch; }
html body .tm-ds .tm-live-page .tm-kpi-row { min-height: 0 !important; height: auto !important; margin-bottom: 0 !important; }   /* ölçüldü: satır 150 px'te kalıyordu (kartlar 108) → 42 px ölü boşluk */
html body .tm-ds .tm-live-page .tm-live-main-grid { margin-top: var(--tm-space-3) !important; row-gap: var(--tm-space-3); }
/* ① KPI kartı */
.tm-ds .tm-live-page .tm-live-kpi-grid .kpi-card { padding-top: var(--tm-space-3); }
.tm-ds .tm-live-page .tm-live-kpi-grid .kpi-value { font-size: var(--tm-type-display-sm); line-height: var(--tm-type-display-sm-lh); }
@media (min-width: 1440px) { .tm-ds .tm-live-page .tm-live-kpi-grid .kpi-value { font-size: var(--tm-type-display-sm); line-height: var(--tm-type-display-sm-lh); } }
.tm-ds .tm-live-page .tm-live-kpi-grid .kpi-body { padding-top: 0; }
.tm-ds .tm-live-page .tm-live-kpi-grid .kpi-deltarow { padding-top: 0; min-height: 0; }
.tm-ds .tm-live-page .tm-live-kpi-grid .kpi-deltarow .kpi-vs { font-size: var(--tm-type-micro); line-height: var(--tm-type-micro-lh, 14px); }
/* Grafik kartları ortak: iç pay 12/16, başlık 16 px tek satır, alt yazı küçük */
.tm-ds .tm-live-page .tm-dashboard-ch-grid--live > .ch-panel { padding: var(--tm-space-3) var(--tm-space-4) var(--tm-space-3); }
.tm-ds .tm-live-page .tm-dashboard-ch-grid--live .ch-head { margin-bottom: var(--tm-space-2); align-items: center; }
.tm-ds .tm-live-page .tm-dashboard-ch-grid--live .ch-h3 { font-size: var(--tm-type-heading); line-height: 1.25; font-weight: var(--tm-weight-semibold); }
.tm-ds .tm-live-page .tm-dashboard-ch-grid--live .ch-sub { font-size: var(--tm-type-micro); margin-top: 1px; }
/* ③ Saatlik Akış: istatistik şeridi = hero (asıl sayı büyük, kıyaslar yanında, legend sağda) */
.tm-ds .tm-live-page .tm-live-hourly-meta { flex-wrap: nowrap; align-items: baseline; gap: var(--tm-space-4); margin: 0 0 var(--tm-space-1); padding-bottom: var(--tm-space-1); border-bottom: 1px solid var(--tm-border); }
.tm-ds .tm-live-page .tm-live-hourly-stats { order: 1; margin-left: 0; flex: 1 1 auto; align-items: baseline; gap: var(--tm-space-1) var(--tm-space-4); }
.tm-ds .tm-live-page .tm-live-hourly-legend { order: 2; flex: 0 0 auto; }
.tm-ds .tm-live-page .tm-live-hourly-stat.is-ana { display: inline-flex; align-items: baseline; gap: var(--tm-space-2); }
.tm-ds .tm-live-page .tm-live-hourly-stat.is-ana strong { font-weight: var(--tm-weight-bold); letter-spacing: -0.01em; }
.tm-ds .tm-live-page .tm-dashboard-ch-grid--live .ch-head { margin-bottom: var(--tm-space-1); }
/* ④ Platform kartı (2026-10-10, kullanıcı: "pie chart'ı büyüt, boş yer kalmasın, yerleşimi düzgün yap"):
   halka ÜSTTE ve büyük (160), satır listesi ALTINDA TAM GENİŞLİK. İki sütun denendi (halka solda 150) →
   satır sütunu 156 px'e düşüp 5 adın 4'ü kırpılıyordu (ölçüldü); tek sütunda satırlar ~370 px alıyor,
   kırpma 0 ve halka daha büyük. Satırlar kalan yüksekliği eşit paylaşır → alt boşluk kalmaz. */
.tm-ds .tm-live-page .tm-dashboard-ch-grid--live > .ch-panel.span-2 { display: flex; flex-direction: column; }
/* 2026-10-16 (kullanıcı: "çevresi çok boş, halka çok ince"): halka 160 → 200 px, çizgi 12 → 20.
   Halka kutusu kartın ESNEK parçası (flex 1): satırlar azken artan yükseklik halkanın ÇEVRESİNE
   eşit dağılır, satırları dibe itmez. Satır çoksa Saatlik Akış grafiği bu kartın doğal boyuna
   uzar (tm-vanilla-dashboard-charts.js liveHourlyFitHeight) — iki kart eş boy, ölü alan yok. */
.tm-ds .tm-live-page .tm-dashboard-ch-grid--live > .ch-panel.span-2 > .ch-mount { flex: 1 1 auto; min-height: 200px; display: flex; align-items: center; justify-content: center; margin: var(--tm-space-2) 0 var(--tm-space-4); }
.tm-ds .tm-live-page .tm-dashboard-ch-grid--live > .ch-panel.span-2 .ch-donut-wrap { height: auto; justify-content: center; }
.tm-ds .tm-live-page .tm-dashboard-ch-grid--live > .ch-panel.span-2 .ch-donut-wrap svg.ch-donut { width: 200px; height: 200px; max-height: 200px; }
.tm-ds .tm-live-page .tm-dashboard-ch-grid--live > .ch-panel.span-2 > .tm-live-plat__cols { flex: 0 0 auto; margin: 0; padding: 0 0 var(--tm-space-1); }
.tm-ds .tm-live-page .tm-dashboard-ch-grid--live > .ch-panel.span-2 > .tm-live-plat { flex: 0 0 auto; margin-top: 0; padding-top: 0; border-top: 0; gap: 0; justify-content: flex-start; }
.tm-ds .tm-live-page .tm-live-plat__row { gap: 2px; }
.tm-ds .tm-live-page .tm-live-plat__bar { height: 3px; }
/* ≤1099: GERÇEKTEN tek sütun — halka üstte, liste altında tam genişlik. (Önceki hâli aynı iki-sütun
   şablonunu tekrar yazıyordu → 390 px'te ad/kâr kırpılıyordu; QA ölçümü 2026-10-10.) */
@media (max-width: 1099px) {
  .tm-ds .tm-live-page .tm-dashboard-ch-grid--live > .ch-panel.span-2 .ch-donut-wrap svg.ch-donut { width: 176px; height: 176px; max-height: 176px; }
  .tm-ds .tm-live-page .tm-dashboard-ch-grid--live > .ch-panel.span-2 > .ch-mount { min-height: 176px; }
}

/* ═══ 2026-10-10 — GRAFİK + PLATFORM KARTI GÖRSEL TASARIMI (kullanıcı, tur 3: "grafik kullanışlı değil,
   platform dağılımı kaba duruyor, göze daha güzel görünmeli"). Çizim kodu (tm-charts.js) aynı; yalnız bu
   sayfada SVG/satır stilleri: ince-yuvarlak çizgi, sakin ızgara, okunur eksen, koyu araç ipucu; halka ince
   şerit + sessiz ray; pazaryeri satırları tek düzen (logo · ad · ciro / pay çubuğu · yüzde / adet · kâr). ═══ */
/* Saatlik Akış — çizgi & alan */
.tm-ds .tm-live-page #tmLiveHourlyFlow .ch-area-line { stroke-width: 2.25; stroke-linejoin: round; stroke-linecap: round; }
.tm-ds .tm-live-page #tmLiveHourlyFlow .ch-area-line.is-dashed { stroke: var(--tm-text-muted); stroke-width: 1.5; stroke-dasharray: 3 4; opacity: .85; }
.tm-ds .tm-live-page #tmLiveHourlyFlow .ch-grid-line { stroke: var(--tm-border); stroke-dasharray: none; opacity: .7; }
.tm-ds .tm-live-page #tmLiveHourlyFlow .ch-grid-line.zero { stroke: var(--tm-border-strong); opacity: 1; }
.tm-ds .tm-live-page #tmLiveHourlyFlow .ch-axis-ylabel,
.tm-ds .tm-live-page #tmLiveHourlyFlow .ch-bar-xlabel { font-family: var(--tm-font-sans); font-size: 11px; fill: var(--tm-text-muted); font-variant-numeric: tabular-nums; }
.tm-ds .tm-live-page #tmLiveHourlyFlow .ch-cross { stroke: var(--tm-text-muted); stroke-dasharray: 2 3; opacity: .7; }
.tm-ds .tm-live-page #tmLiveHourlyFlow .ch-cross-dot { stroke: var(--tm-surface); stroke-width: 2; }
.tm-ds .tm-live-page #tmLiveHourlyFlow .ch-live-end-dot { stroke-width: 2.5; }
.tm-ds .tm-live-page #tmLiveHourlyFlow .ch-tip { border-radius: 10px; padding: 8px 10px; box-shadow: 0 8px 24px rgba(2, 12, 34, .28); }
.tm-ds .tm-live-page #tmLiveHourlyFlow .ch-tip-row { font-size: 12px; gap: 8px; }
.tm-ds .tm-live-page .tm-live-hourly-legend__swatch { width: 16px; height: 2.5px; }
.tm-ds .tm-live-page .tm-live-hourly-legend__swatch.is-baseline { height: 0; border-top: 1.5px dashed var(--tm-text-muted); background: transparent; }
/* Platform halkası — ince şerit, sessiz ray, belirgin merkez */
.tm-ds .tm-live-page #tmLivePlatformVanilla svg.ch-donut > circle:first-child { stroke: var(--tm-surface-sunken); stroke-width: 20; }
.tm-ds .tm-live-page #tmLivePlatformVanilla .ch-donut-seg { stroke-width: 20; transition: stroke-width var(--tm-dur-fast) var(--tm-ease), opacity var(--tm-dur-fast) var(--tm-ease); }
.tm-ds .tm-live-page #tmLivePlatformVanilla .ch-donut-seg.dim { opacity: .35; }
/* Kalın çizgide yuvarlak uç (20/2 = 10 birim) dilimler arası 2,2 %'lik aralıktan (~9,8 birim) büyük →
   komşu dilimler birbirine biniyordu (ölçüldü 2026-10-16). Düz uç = aralık gerçekten görünür. */
.tm-ds .tm-live-page #tmLivePlatformVanilla .ch-donut-seg { stroke-linecap: butt; }
/* Vurgulanan dilim kalınlaşır: tm-charts.js bunu `stroke-width` ÖZNİTELİĞİYLE yapıyor, ama yukarıdaki
   CSS değeri özniteliği eziyordu → vurgu bu sayfada hiç görünmüyordu. (r=71 + 24/2 = 83 < 84, kırpılmaz.) */
.tm-ds .tm-live-page #tmLivePlatformVanilla svg.ch-donut:has(.ch-donut-seg.dim) .ch-donut-seg:not(.dim) { stroke-width: 24; }
.tm-ds .tm-live-page #tmLivePlatformVanilla .ch-donut-center-v { font-family: var(--tm-font-sans); font-size: var(--tm-type-display-sm); font-weight: 700; fill: var(--tm-text-primary); letter-spacing: -0.01em; }
.tm-ds .tm-live-page #tmLivePlatformVanilla .ch-donut-center-l { font-family: var(--tm-font-sans); font-size: var(--tm-type-micro); font-weight: 600; fill: var(--tm-text-muted); letter-spacing: .08em; text-transform: uppercase; }
/* Pazaryeri satırları — tek düzen, hairline ayırıcı */
.tm-ds .tm-live-page .tm-live-plat__cols { display: flex; justify-content: space-between; font-size: var(--tm-type-micro); font-weight: var(--tm-weight-semibold); letter-spacing: .08em; text-transform: uppercase; color: var(--tm-text-muted); padding: 0 0 4px; border-bottom: 1px solid var(--tm-border); }
.tm-ds .tm-live-page .tm-dashboard-ch-grid--live > .ch-panel.span-2 > .tm-live-plat { border-top: 0; padding-top: 0; gap: 0; }
.tm-ds .tm-live-page .tm-live-plat__row { display: grid; grid-template-columns: minmax(0, 1fr) auto; grid-template-areas: "head rev" "bar bar" "meta meta"; column-gap: var(--tm-space-3); row-gap: 3px; align-items: center; padding: 6px 0; border-bottom: 1px solid var(--tm-border); }
.tm-ds .tm-live-page .tm-live-plat__row:last-child { border-bottom: 0; }
.tm-ds .tm-live-page .tm-live-plat__head { display: contents; }
.tm-ds .tm-live-page .tm-live-plat__name { grid-area: head; font-size: var(--tm-type-body); line-height: var(--tm-type-body-lh); font-weight: var(--tm-weight-semibold); gap: 7px; min-width: 0; }
.tm-ds .tm-live-page .tm-live-plat__name .tm-pz-logo, .tm-ds .tm-live-page .tm-live-plat__name img { width: 18px; height: 18px; border-radius: 4px; flex: 0 0 auto; }
.tm-ds .tm-live-page .tm-live-plat__rev { grid-area: rev; font-size: var(--tm-type-body); line-height: var(--tm-type-body-lh); }
.tm-ds .tm-live-page .tm-live-plat__bar { grid-area: bar; height: 3px; background: var(--tm-surface-sunken); }
.tm-ds .tm-live-page .tm-live-plat__bar > span { opacity: .9; }
.tm-ds .tm-live-page .tm-live-plat__meta { grid-area: meta; justify-self: start; flex-wrap: wrap; gap: 0 6px; font-size: var(--tm-type-caption); line-height: var(--tm-type-caption-lh); color: var(--tm-text-muted); white-space: normal; min-width: 0; overflow: visible; }
.tm-ds .tm-live-page .tm-live-plat__meta > span + span::before { content: '·'; margin-right: 6px; color: var(--tm-border-strong); }
.tm-ds .tm-live-page .tm-live-plat__meta .tm-live-plat__note::before { content: none; }
.tm-ds .tm-live-page .tm-live-plat__note { font-size: var(--tm-type-micro); padding: 0 6px; line-height: 16px; }
.tm-ds .tm-live-page .tm-live-plat__row.is-top .tm-live-plat__name { color: var(--tm-text-primary); }
/* Bugünün yıldızı — sessiz zemin kartı */

/* Halkanın ORTA YAZILARI fare olaylarını yutmasın: merkeze yakın hover'da dilim vurgusu düşüyordu
   (ölçüldü: center-v elementi pointer'ı kesiyor). Metin zaten bilgi, hedef değil. */
.tm-ds .tm-live-page #tmLivePlatformVanilla .ch-donut-center-v,
.tm-ds .tm-live-page #tmLivePlatformVanilla .ch-donut-center-l { pointer-events: none; }

/* Halka ↔ satır karşılıklı vurgu (2026-10-10, kullanıcı): dilimin üstüne gelince eşleşen pazaryeri
   satırı öne çıkar, ötekiler soluklaşır; satırın üstüne gelince dilim kalınlaşır (JS dispatch). */
.tm-ds .tm-live-page .tm-live-plat__row { transition: background-color var(--tm-dur-fast) var(--tm-ease), opacity var(--tm-dur-fast) var(--tm-ease); border-radius: 6px; }
.tm-ds .tm-live-page .tm-live-plat__row.is-vurgu { background: var(--tm-surface-sunken); opacity: 1; }
.tm-ds .tm-live-page .tm-live-plat__row.is-sonuk { opacity: .42; }
.tm-ds .tm-live-page .tm-live-plat__row.is-vurgu .tm-live-plat__bar > span { opacity: 1; }
.tm-ds .tm-live-page .tm-live-plat__row:hover { background: var(--tm-surface-sunken); }
/* reduced-motion: ds-primitives.css `.tm-ds *` kuralı geçiş süresini 0.001ms'e indirir — ayrı blok yok (PR-1). */

/* =================================================================
   🔴 ÜST ŞERİT SATIR SAYISI İLK ÇİZİMDE SABİT (2026-10-11 — ÖLÇÜLDÜ)
   Kullanıcı: *"sayfa içerikleri kasıyor, sıralı yüklenmiyor"*. Canlı
   Performans CLS = 0,37 (eşik 0,25 "kötü"). Kaynak: şerit ilk çizimde
   iskeletlerle TEK satır (32 px), JS değerleri yazınca çipler genişleyip
   kontroller ikinci satıra düşüyor (72 px) → KPI, grafikler ve sipariş
   tablosu ~1 sn sonra 40 px aşağı kayıyordu (kids.cjs ölçümü: şerit
   32→72, KPI satırı 141→181). Önceki ch-rezervleri ve 72 px min-height
   bu katmanda devreye girmiyordu.
   Artık satır sayısı İÇERİKTEN bağımsız:
     ≥1360 px  → her zaman TEK satır; çipler daralabilir, kontrolleri itemez.
     <1360 px  → nabız çipleri ilk çizimden itibaren kendi satırında,
                 kontroller ikinci satırda (iki satır, sabit).
   ================================================================= */
@media (min-width: 1360px) {
  .tm-ds .tm-live-page .tm-live-header { flex-wrap: nowrap; }
  .tm-ds .tm-live-page .tm-live-header > .tm-live-pulseline {
    flex: 1 1 auto;
    min-width: 0;
    flex-wrap: nowrap;
    overflow: hidden;
  }
  .tm-ds .tm-live-page .tm-live-pulseline > .tm-live-stat { flex: 0 1 auto; min-width: 0; }
  .tm-ds .tm-live-page .tm-live-stat__value,
  #tmLiveLastOrder.tm-live-stat__value,
  #tmLivePace.tm-live-stat__value,
  #tmLiveCancelRate.tm-live-stat__value {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
  }
}
@media (min-width: 768px) and (max-width: 1359.98px) {
  .tm-ds .tm-live-page .tm-live-header > .tm-live-pulseline { flex: 1 1 100%; }
  .tm-ds .tm-live-page .tm-live-header__row--controls-only { margin-inline-start: auto; }
}

/* Ortak kıyas notu — beş kartta tekrar eden alt metnin TEK kopyası (2026-10-11). */
.tm-ds .tm-live-page .tm-live-kpi-note {
  margin: 0 0 var(--tm-space-2);
  font-size: var(--tm-type-caption);
  line-height: var(--tm-type-caption-lh);
  color: var(--tm-text-muted);
}
.tm-ds .tm-live-page .tm-live-kpi-note[hidden] { display: none; }
/* Kıvılcım kartın alt kenarına yapışık çiziliyordu (kart alt payı 0; sıfır
   çizgisi kenardan 3 px yukarıda → kenarlık gibi okunuyor, uç nokta kesik).
   Canlı kartlarında alt pay 10 px; yükseklik 120 px içinde kalır. */
.tm-ds .tm-live-page .tm-live-kpi-grid .kpi-card { padding-bottom: 10px; }

