/* Trader — read-only observation dashboard.
 * "Kuyu" UI, v4. Zero external runtime deps; Inter Variable + Space Grotesk
 * self-hosted.
 *
 * Design language, in one sentence: a measurement instrument, not an app.
 *   - depth comes from a flat surface ladder and 1px rules, never from glows,
 *     gradients, translucent panels or drop shadows (shadows belong to overlays
 *     only: drawer, scrim, tooltip, status strip);
 *   - data surfaces (panels, tables, KPI grids, banners, charts) are rectilinear;
 *     only CONTROLS (buttons, tabs, tags, inputs) carry a radius;
 *   - teal is brand + interaction only; green/red are P&L only; amber is warn
 *     only; steel blue is a neutral data series and never a status;
 *   - every text token clears WCAG AA on every surface it can land on, and text
 *     is never dimmed with `opacity` (a faded row used to measure 3,05:1).
 *
 * Do NOT remove the following literals — they are asserted by tests:
 *   - class name `sidebar`
 *   - token name `--radius`
 *   - media query `prefers-reduced-motion`
 *   - class name `login-card`
 */

@font-face {
  font-family: "Inter Variable";
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url("/static/fonts/inter-var.woff2") format("woff2-variations"),
       url("/static/fonts/inter-var.woff2") format("woff2");
}

/* Space Grotesk (OFL) — display voice for headings, brand and section rules.
 * Two unicode-range subsets so the Turkish diacritics come from latin-ext. */
@font-face {
  font-family: "Space Grotesk";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("/static/fonts/space-grotesk-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
                 U+02DC, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212,
                 U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Space Grotesk";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("/static/fonts/space-grotesk-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
                 U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF,
                 U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

:root {
  /* ---- surfaces ----------------------------------------------------------
     A four-step ladder. Every step is ~0,6 L darker than the one above; none of
     them carries a gradient, and none of them is translucent except --topbar-bg
     (which is translucent nowhere: even the top bar is solid now, because a
     blurred bar over 2-second DOM swaps reads as a glitch, not as depth). */
  --bg: #080c10;            /* page — equals the test-locked PWA theme colour */
  --bg-deep: #06090d;       /* table heads, code, inputs, bubbles — the well */
  --surface: #0e141b;       /* panels, cells, rows */
  --surface-2: #131b23;     /* nested / raised: hover, controls, chips */
  --surface-3: #19222c;     /* active hover */
  --surface-row-hover: #141d26; /* table row hover: keeps --ink-3 above 4,5:1 */
  --rail-bg: #0c1117;

  /* ---- rules -------------------------------------------------------------
     Rules are the ONLY depth device. They are decorative (1,33:1 … 2,2:1) and
     therefore never relied on for a WCAG 1.4.11 boundary: anything that must be
     perceivable as a boundary uses a solid fill instead. */
  --rule: rgba(200, 216, 232, 0.13);   /* 1,33:1 on --surface — cell dividers */
  --rule-strong: rgba(200, 216, 232, 0.24); /* 1,84:1 — component edges */
  --rule-firm: rgba(200, 216, 232, 0.34);    /* 2,5:1 — sticky edges, gutters */
  --rule-soft: rgba(200, 216, 232, 0.07);    /* 1,15:1 — inside-row hairlines */

  /* ---- text --------------------------------------------------------------
     Measured contrast pairs (this is the ladder's contract, not a wish):
       --ink     15,99:1 on --surface   primary copy, values
       --ink-2    8,64:1 on --surface   secondary copy
       --ink-3    5,19:1 on --surface   labels, micro-caps, tertiary  (AA)
     --ink-3 is the token that used to be #6a7686 at 3,98:1. Nothing below is
     allowed to be dimmed a second time with opacity. */
  --ink: #e9eff6;
  --ink-2: #a3b3c4;
  --ink-3: #7d8996;
  --ink-value: #f4f8fc;

  /* ---- brand -------------------------------------------------------------
     Teal is the instrument's signature: brand mark, current selection, focus,
     links. It is deliberately NOT green, because green below means money. */
  --accent: #2fd4b5;           /* 9,88:1 on --surface */
  --accent-ink: #7cead7;       /* 12,87:1 — accent used as TEXT */
  --accent-weak: rgba(47, 212, 181, 0.12);
  --accent-rule: rgba(47, 212, 181, 0.42);

  /* ---- semantics ---------------------------------------------------------
     Two tokens per family: a FILL (LEDs, bars, spines — needs 3:1 as a UI
     component) and an INK (text — needs 4,5:1). Never use the fill for text:
     --down measured 4,06:1 on the old lighter surfaces. */
  --up: #35b96c;        /* 7,32:1 */
  --up-ink: #79dfa4;    /* 11,37:1 */
  --down: #ec5b5f;      /* 5,49:1 */
  --down-ink: #ff9ea1;  /* 9,39:1 */
  --down-weak: rgba(236, 91, 95, 0.13);
  --down-rule: rgba(236, 91, 95, 0.46);
  --warn: #dd8f26;      /* 7,08:1 */
  --warn-ink: #f7c274;  /* 11,39:1 */
  --warn-weak: rgba(221, 143, 38, 0.13);
  --warn-rule: rgba(221, 143, 38, 0.46);
  /* neutral data series: allocation slices, idle bars. NEVER a status colour. */
  --series: #6ea8dc;    /* 7,31:1 */
  /* the SAFE half of a safety reading: legible on purpose. A safety fact that
     needs a magnifier is not a safety fact. */
  --safe-ink: #d5e0ec;  /* 13,84:1 */

  /* ---- geometry ----------------------------------------------------------
     Data surfaces are square. The radius scale exists for controls only, which
     is what kills the old "auto-fit block with two square corners" bug: there is
     nothing on a data grid left to round. */
  --radius: 0px;             /* data surfaces (panels, tables, KPI grids, banners) */
  --radius-sm: 4px;          /* controls: buttons, tabs, tags, inputs, nav links */

  /* spacing: 4px base, eight named steps */
  --sp-1: 4px;
  --sp-2: 8px;
  --sp-3: 12px;
  --sp-4: 16px;
  --sp-5: 20px;
  --sp-6: 24px;
  --sp-7: 32px;
  --sp-8: 44px;

  /* type ramp — monotonic at every breakpoint (the old ramp went 29→20→18→20) */
  --fs-2xs: 11px;
  --fs-xs: 12px;
  --fs-sm: 13px;
  --fs-base: 13.5px;
  --fs-md: 15px;
  --fs-lg: 17px;
  --fs-2xl: 26px;
  --fs-kpi: 24px;
  --fs-kpi-lg: 28px;
  --lh-tight: 1.15;
  --lh-snug: 1.45;
  --lh: 1.6;

  /* structure */
  --rail-w: 76px;
  --rail-wide: 256px;
  --topbar-h: 54px;
  --content-max: 1560px;
  --pad-x: var(--sp-6);
  --tap: 44px;

  /* stacking: one scale, no 60/61 strays. Tooltips outrank the chrome because a
     hint is the only thing that can legitimately interrupt a status reading. */
  --z-th: 3;
  --z-th-key: 4;
  --z-topbar: 15;
  --z-scrim: 18;
  --z-rail: 20;
  --z-aux: 22;
  --z-tip: 30;

  /* movement — transform/opacity only, and nothing survives reduced motion */
  --ease: cubic-bezier(.4, 0, .2, 1);
  --ease-out: cubic-bezier(.16, 1, .3, 1);
  --dur-1: 110ms;
  --dur-2: 170ms;
  --dur-rail: 190ms;

  --font-ui: "Inter Variable", "Inter", system-ui, -apple-system, "Segoe UI", Roboto,
             "Helvetica Neue", Arial, sans-serif;
  --font-display: "Space Grotesk", "Inter Variable", system-ui, sans-serif;
  --font-mono: ui-monospace, "SF Mono", "Cascadia Mono", "JetBrains Mono", Menlo, Consolas, monospace;

  --ring: 0 0 0 2px var(--bg), 0 0 0 4px var(--accent);
  --overlay-shadow: 0 24px 64px -24px rgba(0, 0, 0, 0.9);
}

/* ============== base ============== */

*, *::before, *::after { box-sizing: border-box; }
html, body { height: 100%; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--font-ui);
  font-size: var(--fs-base);
  font-feature-settings: "cv02", "cv03", "cv04", "ss01";
  font-optical-sizing: auto;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

h1, h2, h3, h4 {
  font-family: var(--font-display);
  font-weight: 600;
  letter-spacing: -0.015em;
  margin: 0;
}

a { color: var(--accent-ink); text-decoration: none; transition: color var(--dur-1) var(--ease); }
a:hover { color: var(--ink); }

a:focus-visible, button:focus-visible, input:focus-visible, summary:focus-visible,
[tabindex]:focus-visible {
  outline: none;
  box-shadow: var(--ring);
  border-radius: var(--radius-sm);
}

/* İçeriğe atlama bağı: odaklanana kadar görünmez, odakta sol üstte gerçek bir bağ
   olur (WCAG 2.4.1; bağımsız UI denetimi 2026-09-12). */
.skip {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 120;
}
.skip:focus {
  left: var(--sp-3);
  top: var(--sp-3);
  padding: 8px 12px;
  background: var(--surface);
  color: var(--ink);
  border: 1px solid var(--rule-strong);
  border-radius: var(--radius-sm);
}

::selection { background: rgba(47, 212, 181, 0.32); color: #04120f; }

.muted { color: var(--ink-2); }
.dim { color: var(--ink-3); }
.sym { font-weight: 600; color: var(--ink-value); letter-spacing: 0.01em; }
.warn-text { color: var(--warn-ink); }
.pos { color: var(--up-ink); }
.neg { color: var(--down-ink); }
.zero { color: var(--ink-2); }

.mono {
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  color: var(--ink-2);
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.01em;
}

/* Every glyph that is a number, whether it is read as a value or as a label. Column
   alignment is a legibility feature here: proportional digits ruin it the moment two
   rows are read one under the other on a narrow screen. */
.num, .tnum, .kpi-value, .kpi-sub, .kv b, .decision-age, .chain-fact, .bar-pct,
td.num, th.num, .clocks, .feed-ts {
  font-variant-numeric: tabular-nums;
}

/* Filtrelenen satırlar `hidden` niteliğini kullanır. UA stilinin burada ezilme
   ihtimali var: panelin satırlarının çoğu `display: flex/grid` ile çiziliyor ve
   özel bir `display` kuralı, `[hidden] { display: none }` varsayılanını susturur.
   Bu tek satır olmadan "filtre çalışıyor ama satırlar görünüyor" olur. */
[hidden] { display: none !important; }

/* Text a sighted reader never sees but a screen reader must. Used by the live
   region strategy: the top bar is no longer one giant `role="status"`. */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* ============== app shell ============== */

.layout { display: flex; min-height: 100vh; min-height: 100dvh; }
body.nav-locked { overflow: hidden; }

.main { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.nav-scrim, .nav-toggle { display: none; }
/* Durum perdesi masaüstünde yoktur: satır içi panelde perde anlamsızdır, akışta bir
   düğme bırakmak içeriği 20px aşağı itiyor ve ekran okuyucuya hayalet bir "kapat"
   düğmesi duyuruyordu (bağımsız doğrulama N1, 2026-09-12). ≤1089 bloğu görünür kılar. */
.aux-scrim { display: none; }
.show-narrow { display: none; }

.sidebar {
  width: var(--rail-wide);
  flex: 0 0 var(--rail-wide);
  background: var(--rail-bg);
  border-right: 1px solid var(--rule);
  display: flex;
  flex-direction: column;
  position: sticky;
  top: 0;
  height: 100vh;
  height: 100dvh;
  z-index: var(--z-rail);
  overflow-x: hidden;
}

/* ---- the rail: everything text collapses, everything icon survives ----
   Labels ride `max-width` (not `display`), so opening/closing animates in one
   place and screen readers keep the accessible names (they come from
   aria-label, never from the collapsing text node). */
.sidebar .nav-label {
  max-width: 0;
  opacity: 0;
  overflow: hidden;
  white-space: nowrap;
  transition: max-width var(--dur-rail) var(--ease), opacity var(--dur-1) var(--ease);
}
.sidebar .rail-foot .nav-label { display: none; }

/* Brand marks live on the login page only since 2026-09-10 — the panel's own rail
   carries no logo, so nothing here is shared with the app shell. */
.brand-mark {
  display: flex; align-items: center; gap: 10px;
  font-family: var(--font-display);
  font-size: var(--fs-md); font-weight: 600; color: var(--ink-value); letter-spacing: 0.005em;
}
/* The brand glyph: a solid square of accent ink. One deliberate mark, no glow. */
.brand-mark svg {
  color: #04120f;
  width: 30px; height: 30px;
  padding: 7px;
  box-sizing: border-box;
  background: var(--accent);
  border: 1px solid var(--accent);
  border-radius: var(--radius-sm);
  flex: 0 0 30px;
}
.brand-word { font-weight: 650; }
.brand-sub {
  font-size: var(--fs-2xs);
  color: var(--ink-3);
  text-transform: uppercase;
  letter-spacing: 0.14em;
  font-weight: 500;
}

/* The rail starts with the nav list: no header above it, so the list carries the
   top gutter itself. */
.nav {
  display: flex;
  flex-direction: column;
  padding: 12px 10px 12px;
  gap: 1px;
  overflow-y: auto;
  overflow-x: hidden;
  flex: 1;
}
.nav-group { margin-top: 16px; padding: 0 8px 6px; }
.nav-group:first-child { margin-top: 4px; }
.nav-group-label {
  font-size: var(--fs-2xs);
  color: var(--ink-3);
  text-transform: uppercase;
  letter-spacing: 0.16em;
  font-weight: 600;
  white-space: nowrap;
}
.nav a {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 11px;
  min-height: 38px;
  padding: 7px 0;
  color: var(--ink-2);
  font-size: var(--fs-base);
  font-weight: 500;
  border-radius: var(--radius-sm);
  border-left: 2px solid transparent;
  position: relative;
  transition: background var(--dur-1) var(--ease), color var(--dur-1) var(--ease),
              border-color var(--dur-1) var(--ease), padding var(--dur-rail) var(--ease);
}
.nav a svg { color: var(--ink-3); flex: 0 0 17px; transition: color var(--dur-1) var(--ease); }
.nav a:hover { background: var(--surface-2); color: var(--ink); }
.nav a:hover svg { color: var(--ink-2); }
.nav a.active {
  background: var(--surface-2);
  color: var(--ink-value);
  font-weight: 600;
  border-left-color: var(--accent);
}
.nav a.active svg { color: var(--accent); }

/* rail foot: the pin control lives at the bottom of the nav list */
.rail-foot { padding: 0 10px 6px; }
.rail-toggle {
  width: 100%;
  display: flex; align-items: center; justify-content: center; gap: 11px;
  min-height: 34px;
  padding: 6px 0;
  font: inherit;
  font-size: var(--fs-sm);
  color: var(--ink-3);
  background: transparent;
  border: 1px solid var(--rule-strong);
  border-radius: var(--radius-sm);
  cursor: pointer;
  transition: background var(--dur-1) var(--ease), color var(--dur-1) var(--ease);
}
.rail-toggle svg { flex: 0 0 15px; transition: transform var(--dur-rail) var(--ease); }
.rail-toggle:hover { color: var(--ink); background: var(--surface-2); }
body.rail-pinned .rail-toggle svg { transform: rotate(180deg); }

/* Telefon çekmecesindeki "Sistem durumu" kapısı; yalnız ≤760'ta görünür (aşağıda). */
.side-status { display: none; }

.side-foot {
  border-top: 1px solid var(--rule);
  padding: 12px 12px 14px;
  display: flex; flex-direction: column; gap: 9px;
  align-items: center;
}
.side-foot .chip-label,
.side-foot .mode-switch,
.side-foot .side-meta,
.side-foot .pwa-btn > span,
.side-foot .logout-btn > span { display: none; }
#core-chip { padding: 8px 10px; width: 100%; justify-content: center; }
#core-chip .ic { flex: 0 0 12px; }
#core-chip.crit .ic-on,
#core-chip.down .ic-on { display: none; }
#core-chip.ok .ic-off { display: none; }
.side-meta {
  font-size: var(--fs-2xs);
  color: var(--ink-3);
  line-height: 1.55;
  display: flex; flex-direction: column; gap: 1px;
  font-variant-numeric: tabular-nums;
}

/* ---- top bar: solid, one rule, no blur ---- */
.topbar {
  min-height: var(--topbar-h);
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  padding: var(--sp-2) var(--sp-5);
  background: var(--surface);
  border-bottom: 1px solid var(--rule-strong);
  position: sticky;
  top: 0;
  z-index: var(--z-topbar);
  flex-wrap: wrap;
}
.topbar-group { display: flex; align-items: center; gap: 6px; min-width: 0; }
.topbar-group + .topbar-group,
.topbar-aux > .topbar-group:first-child,
.topbar-aux > .topbar-mode-narrow + .topbar-group,
.topbar-aux > .topbar-spacer + .topbar-group { padding-left: var(--sp-2); border-left: 1px solid var(--rule-soft); }
.topbar-spacer { flex: 1; }
/* Secondary status: `display: contents` on desktop so the wrapper costs zero
   layout; below the touch breakpoint it becomes a tap-to-open strip. */
.topbar-aux { display: contents; }
.topbar .aux-toggle, .topbar-mode-narrow { display: none; }
.clocks {
  color: var(--ink-2);
  font-size: var(--fs-sm);
  letter-spacing: 0.02em;
  white-space: nowrap;
  padding: 4px 10px;
  border: 1px solid var(--rule);
  border-radius: var(--radius-sm);
  font-variant-numeric: tabular-nums;
}
.clock-sep { color: var(--ink-3); margin: 0 6px; }

.content {
  flex: 1;
  padding: var(--sp-6) var(--pad-x) var(--sp-7);
  max-width: var(--content-max);
  width: 100%;
  margin: 0 auto;
  min-width: 0;
}

/* chrome-level banners live OUTSIDE #page-content so the fragment swap can
   never erase them; .chrome-wrap aligns them with the content column */
.chrome-wrap {
  max-width: var(--content-max);
  margin: var(--sp-4) auto 0;
  padding: 0 var(--pad-x);
}

/* The phone target bar. Hidden everywhere else: on a desk the rail already carries all
   14 destinations and a second bar would be decoration. Rules that turn it on live in
   the mobile section at the end of this file, together with every other phone rule. */
.tabbar { display: none; }

.foot {
  padding: 14px var(--pad-x) 18px;
  color: var(--ink-3);
  font-size: var(--fs-xs);
  border-top: 1px solid var(--rule);
  letter-spacing: 0.02em;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
}
.foot b { color: var(--ink-2); font-weight: 600; }
.foot-sep { color: var(--rule-firm); }
.foot a { color: var(--accent-ink); }
.foot a:hover { text-decoration: underline; }

.page-head {
  display: flex;
  align-items: baseline;
  gap: var(--sp-4);
  margin-bottom: var(--sp-5);
  padding-bottom: var(--sp-3);
  border-bottom: 1px solid var(--rule);
  flex-wrap: wrap;
}
.page-head h1 {
  font-size: var(--fs-2xl);
  font-weight: 650;
  letter-spacing: -0.03em;
  color: var(--ink-value);
  margin: 0;
}
.page-head .muted { font-size: var(--fs-sm); color: var(--ink-2); }
.page-head-spacer { flex: 1; }

/* ============== tags — one pill ==============
   `badge`, `chip` and `pill` used to be three components wearing the same face.
   One definition remains; only `.chip` survives as an alias, because
   dashboard.js toggles `ok`/`crit`/`down` on #core-chip. All markup writes `.tag`. */

.tag, .chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: var(--fs-2xs);
  font-weight: 600;
  padding: 3px 8px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--rule-strong);
  background: var(--surface-2);
  color: var(--ink-2);
  white-space: nowrap;
  line-height: 1.5;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  font-variant-numeric: tabular-nums;
}
.tag svg, .chip svg { width: 12px; height: 12px; flex: 0 0 12px; }
.tag b, .chip b { color: var(--ink-value); font-weight: 600; }

/* ---- THE COLOUR CONTRACT (also promised to the operator on /guide) ----
   green = you made money, red = you lost money. Nothing else.
   So `.ok` is deliberately NOT green: a healthy component is *quiet*, a sick one
   is amber or red. That is "normalse sessiz, anormalse bağırır" expressed in the
   only colour language this panel has, and it stops green from meaning both
   "kârdasın" and "her şey yolunda" on the same screen. The same rule retires the
   green/red ALIŞ/SATIŞ pills: direction is not P&L, so direction gets a glyph.
   `.chip` survives as the one historical name, because dashboard.js writes
   `ok`/`crit`/`down` onto #core-chip; every template writes `.tag`. */
.tag.ok, .chip.ok {
  color: var(--ink); background: var(--surface-2); border-color: var(--rule-firm);
}
.tag.warn, .chip.warn {
  color: var(--warn-ink); background: var(--warn-weak); border-color: var(--warn-rule);
}
.tag.crit, .chip.crit {
  color: var(--down-ink); background: var(--down-weak); border-color: var(--down-rule);
}
.tag.info, .chip.info {
  color: var(--accent-ink); background: var(--accent-weak); border-color: var(--accent-rule);
}
.tag.down, .chip.down, .chip.zero {
  color: var(--ink-2); background: var(--surface-2); border-color: var(--rule);
}
.tag.mode { color: var(--ink-value); background: var(--surface-3); border-color: var(--rule-strong); }
/* CANLI — gerçek para hareket halinde. Bağırmak bu rozetin işi; koyu mürekkep
   kırmızı zeminde 5,54:1, açık metin 2,60:1 kalıyordu. */
.tag.live {
  color: #2a0507; background: var(--down); border-color: var(--down-ink);
  font-weight: 700; letter-spacing: 0.08em;
}
/* direction, not outcome: the glyph carries the meaning, not the colour */
.tag.buy { color: var(--ink); background: var(--surface-2); border-color: var(--rule-firm); }
.tag.sell { color: var(--ink-2); background: var(--surface); border-color: var(--rule); }

/* A tag that FILTERS (symbol chips, state chips rendered as links). */
a.tag:hover { color: var(--ink-value); border-color: var(--rule-firm); background: var(--surface-3); }

.chips { display: flex; gap: 6px; flex-wrap: wrap; margin: 6px 0 10px; }
.chips.big :is(.tag, .chip) { font-size: var(--fs-sm); padding: 5px 10px; text-transform: none; letter-spacing: 0; }

/* ============== banners — one alert, one family ==============
   `.banner` is also emitted by dashboard.js when the poll is refused, so the
   markup contract is: a `.banner.<tone>[role]` box containing a `<span>`. */

.banner {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  padding: 11px 14px;
  border-radius: var(--radius);
  border: 1px solid var(--rule);
  border-left: 3px solid var(--ink-3);
  background: var(--surface);
  color: var(--ink-2);
  font-size: var(--fs-base);
  margin-bottom: var(--sp-3);
  line-height: var(--lh);
}
.banner svg { flex: 0 0 16px; margin-top: 3px; width: 16px; height: 16px; }
.banner > span { min-width: 0; }
.banner b { color: var(--ink); font-weight: 650; }
.banner.crit { border-left-color: var(--down); background: var(--down-weak); border-color: var(--down-rule); color: var(--down-ink); }
.banner.crit b { color: #ffc9ca; }
.banner.warn { border-left-color: var(--warn); background: var(--warn-weak); border-color: var(--warn-rule); color: var(--warn-ink); }
.banner.warn b { color: #ffd9a8; }
.banner.ok   { border-left-color: var(--rule-firm); background: var(--surface-2); border-color: var(--rule-strong); color: var(--ink); }
.banner.ok b { color: var(--ink-value); }
.banner.info { border-left-color: var(--accent); background: var(--accent-weak); border-color: var(--accent-rule); color: var(--accent-ink); }
.banner.info b { color: var(--ink-value); }
.banner a { text-decoration: underline; }

/* ============== KPI clusters & grid ============== */

.kpi-cluster { margin-bottom: var(--sp-5); }
.cluster-label {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 0 0 8px 2px;
  font-family: var(--font-display);
  font-size: var(--fs-2xs);
  font-weight: 700;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.cluster-label::after {
  content: "";
  flex: 1;
  height: 1px;
  background: var(--rule);
}
.cluster-label svg { width: 13px; height: 13px; color: var(--accent); }

/* The KPI grid is a ruled block, not a card pile: 1px gutters drawn by the gap
   over a rule-coloured background, square corners, one depth level shared with
   .panel. No radius on the edge cells => the two-square-corner bug of the old
   rounded auto-fit block cannot recur. */
.kpis {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(184px, 1fr));
  gap: 1px;
  background: var(--rule);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  margin-bottom: var(--sp-4);
}
.kpis.featured { grid-template-columns: repeat(auto-fit, minmax(232px, 1fr)); }
.kpis.compact  { grid-template-columns: repeat(auto-fit, minmax(152px, 1fr)); }

.kpi {
  background: var(--surface);
  padding: 12px 16px 14px;
  min-height: 84px;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: 2px;
  position: relative;
  transition: background var(--dur-1) var(--ease);
}
.kpi:hover { background: var(--surface-2); }
.kpi.featured { min-height: 112px; padding: 14px 16px 16px; }
.kpi-label {
  font-size: var(--fs-2xs);
  color: var(--ink-3);
  text-transform: uppercase;
  letter-spacing: 0.14em;
  font-weight: 600;
}
.kpi-value {
  font-size: var(--fs-kpi);
  font-weight: 650;
  letter-spacing: -0.032em;
  color: var(--ink-value);
  margin-top: 5px;
  line-height: var(--lh-tight);
  font-variant-numeric: tabular-nums;
  overflow-wrap: anywhere;
}
.kpi.featured .kpi-value { font-size: var(--fs-kpi-lg); }
.kpi-value.pos { color: var(--up-ink); }
.kpi-value.neg { color: var(--down-ink); }
.kpi-value.zero { color: var(--ink-2); }
.kpi-value.warn { color: var(--warn-ink); }
.kpi-value.ok { color: var(--ink-value); }
.kpi-value.crit { color: var(--down-ink); }
/* bilinmiyor: ölçüm yokluğu ne 'güvenli' ne 'sıfır'dır (operatör kararı 2026-09-12) */
.kpi-value.unknown { color: var(--warn-ink); }
.kpi-sub { font-size: var(--fs-sm); color: var(--ink-3); margin-top: 3px; }

/* A KPI that carries a safety reading gets a left spine: peripheral vision reads
   the spine before the eye reads the word. The spine is graphite, not green —
   "nothing is wrong" must not borrow the colour of "you earned money". */
.kpi.is-safe { box-shadow: inset 3px 0 0 var(--rule-firm); }
.kpi.is-warn { box-shadow: inset 3px 0 0 var(--warn); }
.kpi.is-unknown { box-shadow: inset 3px 0 0 var(--warn); }
.kpi.is-crit { box-shadow: inset 3px 0 0 var(--down); background: var(--down-weak); }
/* Odak halkası gölgeyle çizilir; güvenlik şeridi de gölgedir ve sonra geldiği için
   halkayı siliyordu — şeritli hücre ve aktif sekmede işaret outline ile geri gelir
   (bağımsız UI denetimi 2026-09-12; outline forced-colors'ta da yaşar). */
.kpi.is-safe:focus-visible,
.kpi.is-warn:focus-visible,
.kpi.is-unknown:focus-visible,
.kpi.is-crit:focus-visible,
.tabbar .active:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: -2px;
}

/* ============== panels ============== */

.panel {
  background: var(--surface);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  padding: var(--sp-4) var(--sp-5) var(--sp-5);
  margin-bottom: var(--sp-4);
  min-width: 0;
}
.panel.flush { padding: 0; }
.panel.flush > :first-child { border-top-left-radius: 0; border-top-right-radius: 0; }
.panel.flush > :last-child { border-bottom-left-radius: 0; border-bottom-right-radius: 0; }
.panel.flush h2 { padding: 14px 18px 0; margin-bottom: 8px; }

.panel h2,
.panel h3 {
  font-family: var(--font-display);
  font-size: var(--fs-2xs);
  text-transform: uppercase;
  letter-spacing: 0.16em;
  color: var(--ink-2);
  margin: 0 0 12px;
  font-weight: 600;
  display: flex;
  align-items: center;
  gap: 8px;
}
/* The panel title is a RULE LABEL: the title text, then a hairline that runs to
   the right edge. It replaces the 22px icon chip (four competing recipes). */
.panel h2::after,
.panel h3::after {
  content: "";
  flex: 1;
  height: 1px;
  background: var(--rule);
  margin-left: 4px;
}
.panel h2 svg,
.panel h3 svg { color: var(--accent); width: 14px; height: 14px; flex: 0 0 14px; }
body.coach-on .panel h2,
body.coach-on .panel h3 { flex-wrap: wrap; }
.panel h2.mt-4,
.panel h3.mt-4 { margin-top: var(--sp-4); }
.panel h2 .panel-help svg,
.panel h3 .panel-help svg { width: 13px; height: 13px; color: inherit; }

.panel-head {
  display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3);
  min-height: 48px; padding: 12px 18px; margin-bottom: 0; border-bottom: 1px solid var(--rule);
}
.panel-head h2 { margin: 0; min-width: 0; }
.panel-head h2::after { display: none; }
/* Eylem bağlantıları sıkışıp iki satıra kırılmamalı: uzun yardım metni h2'nin
   max-content'ini şişiriyordu (bağımsız doğrulayıcı N1, 2026-09-13). */
.panel-head-actions { display: flex; align-items: center; gap: 6px; font-size: var(--fs-sm); flex: 0 0 auto; }
/* Başlık metni + iki ikon tek flex öğesi; h2 grameri (8px boşluk, dikey ortalama)
   içeride aynen sürer — sarılırsa metin kendi içinde sarar, ⓘ kopmaz. */
.panel-title { display: flex; align-items: center; gap: 8px; min-width: 0; }
.panel-head-actions a, .panel-foot a { color: var(--accent-ink); }
.panel-head-actions a:hover, .panel-foot a:hover { text-decoration: underline; }

.panel-foot {
  margin-top: var(--sp-3);
  padding-top: 10px;
  border-top: 1px solid var(--rule-soft);
  font-size: var(--fs-sm);
  color: var(--ink-2);
}
.panel-foot a, .content a { color: var(--accent-ink); text-decoration: none; }
.panel-foot a:hover, .content a:hover { text-decoration: underline; }

/* Gutters inside a flush panel. One class, restyled once — never an inline
   `style="padding:…18px…"` per page, which is how a phone gutter used to cost a
   change in every template. Compound selectors so they win over `.chart-wrap`,
   `.feed` and `.panel-foot` regardless of source order. */
.panel-inset { padding: 0 18px var(--sp-4); }
.panel-inset.is-first { padding-top: var(--sp-4); }
.chart-wrap.panel-chart { padding: 8px 18px 16px; }
ul.panel-feed { padding: 12px 18px 4px; }
.panel-foot.bare { margin: 0; padding: var(--sp-3) 18px; border-top: 1px solid var(--rule); }

/* a panel whose subject is itself abnormal */
.panel.is-crit { border-color: var(--down-rule); }
.panel.is-warn { border-color: var(--warn-rule); }

.grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-4); }
.grid-sidebar { display: grid; grid-template-columns: minmax(0, 1.55fr) minmax(0, 1fr); gap: var(--sp-4); }

/* key-value rows */
.kv {
  display: flex;
  justify-content: space-between;
  gap: var(--sp-3);
  padding: 7px 0;
  border-bottom: 1px solid var(--rule-soft);
  font-size: var(--fs-base);
}
.kv:last-child { border-bottom: none; }
.kv span { color: var(--ink-2); }
.kv b {
  font-weight: 600;
  color: var(--ink-value);
  font-variant-numeric: tabular-nums;
  text-align: right;
  word-break: break-word;
  max-width: 65%;
}
.kv-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: 0 var(--sp-5);
}
/* an unmapped settings key stays on the page, but says so: a settings screen
   that quietly drops what it cannot translate is worse than an ugly marker */
.kv.unknown {
  border-left: 2px solid var(--warn-rule);
  background: var(--warn-weak);
  padding-left: var(--sp-2);
  margin-left: calc(var(--sp-2) * -1);
}
.kv.unknown span::after {
  content: "?";
  display: inline-grid;
  place-items: center;
  width: 13px;
  height: 13px;
  margin-left: 6px;
  border: 1px solid var(--warn-rule);
  color: var(--warn-ink);
  font-size: var(--fs-2xs);
  font-weight: 700;
  vertical-align: 1px;
}

/* ============== tables ============== */

.table-wrap { display: block; max-height: 72vh; overscroll-behavior: contain; position: relative; }
/* Scrolling requires clipping; when there is nothing to scroll, let tooltip
   bubbles out of the box instead. */
.table-wrap.clips { overflow: auto; }

table {
  width: 100%;
  border-collapse: separate;
  border-spacing: 0;
  font-size: var(--fs-base);
  font-variant-numeric: tabular-nums;
}
th {
  text-align: left;
  font-size: var(--fs-2xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--ink-3);
  padding: 10px 14px;
  border-bottom: 1px solid var(--rule-strong);
  background: var(--bg-deep);
  position: sticky;
  top: 0;
  z-index: var(--z-th);
  white-space: nowrap;
}
td {
  padding: 9px 14px;
  border-bottom: 1px solid var(--rule-soft);
  color: var(--ink);
  line-height: var(--lh-snug);
  vertical-align: middle;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
td.wrap { white-space: normal; min-width: 220px; max-width: 460px; }
tbody tr:last-child td { border-bottom: none; }
tbody tr { transition: background var(--dur-1) var(--ease); }
tbody tr:hover { background: var(--surface-row-hover); }
th.num, td.num { text-align: right; }
.panel.flush table th:first-child, .panel.flush table td:first-child { padding-left: 18px; }
.panel.flush table th:last-child,  .panel.flush table td:last-child  { padding-right: 18px; }

/* totals row: the arithmetic a table always owed you */
tfoot td {
  border-top: 1px solid var(--rule-strong);
  border-bottom: none;
  background: var(--bg-deep);
  color: var(--ink-value);
  font-weight: 650;
  position: sticky;
  bottom: 0;
}
tfoot td .tsum-k { color: var(--ink-3); font-weight: 600; font-size: var(--fs-2xs); text-transform: uppercase; letter-spacing: 0.1em; }

/* Horizontal overflow affordance. The old `.is-scrolling::after` label was
   absolutely positioned INSIDE the scroller, so it scrolled away with the
   content — and the "kaydır →" hint therefore disappeared exactly when the user
   started scrolling, i.e. precisely when it was true. A background pinned to the
   scroller's own box (`background-attachment: scroll`, not `local`) cannot move:
   the fade states the same fact and cannot lie about it. */
.table-wrap.is-scrolling {
  background-image: linear-gradient(to right, transparent, rgba(6, 9, 13, 0.92));
  background-repeat: no-repeat;
  background-size: 44px 100%;
  background-position: right top;
  background-attachment: scroll;
}

/* sticky key column */
table.kkey th:first-child, table.kkey td:first-child {
  position: sticky;
  left: 0;
  z-index: var(--z-th-key);
  background: var(--surface);
  box-shadow: inset -1px 0 0 var(--rule);
}
table.kkey th:first-child { background: var(--bg-deep); }
table.kkey tbody tr:hover td:first-child { background: var(--surface-row-hover); }

/* ============== bars, meters, age gauges ============== */

.bar {
  display: block;
  height: 6px;
  background: var(--surface-3);
  border-radius: 0;
  min-width: 70px;
  position: relative;
  box-shadow: inset 0 0 0 1px var(--rule);
}
/* `display: block` is load-bearing: the bar is a <span>, and an inline box
   ignores width/height — every fill in the panel silently rendered as a 0×0 box
   until this was said out loud. */
.bar-fill { display: block; height: 100%; background: var(--series); }
.bar-fill.pos { background: var(--up); }
.bar-fill.neg { background: var(--down); }
.bar-fill.warn { background: var(--warn); }
.bar-fill.series { background: var(--series); }
.bar-pct { font-size: var(--fs-xs); }
.bar-cell { display: flex; align-items: center; gap: var(--sp-2); min-width: 132px; }
.bar-cell .bar { flex: 1; }
/* Tek seferlik kolon genişliği: eski hâli th üzerinde inline style'dı; panelin
   tek layout inline stili buydu. */
.col-oran { width: 24%; }

/* stacked allocation bar — "where is my money" as one honest line */
.meter { display: flex; height: 14px; border: 1px solid var(--rule-strong); background: var(--bg-deep); overflow: hidden; }
/* Allocation slices are neutral by contract: graphite for idle cash, steel for
   exposure at market risk, amber only when the cap is exceeded. Green would say
   "kâr ettin", teal would say "brand", and neither is a fact about the split. */
.meter-seg { height: 100%; min-width: 0; }
.meter-seg.cash { background: var(--rule-firm); }
.meter-seg.pos- { background: var(--series); }
.meter-seg.over { background: var(--warn); }
.meter-legend { display: flex; flex-wrap: wrap; gap: var(--sp-3); margin-top: var(--sp-2); font-size: var(--fs-xs); color: var(--ink-2); }
.meter-legend span { display: inline-flex; align-items: center; gap: 6px; }
.meter-legend i { width: 9px; height: 9px; flex: 0 0 9px; background: var(--ink-3); }
.meter-legend i.cash { background: var(--rule-firm); }
.meter-legend i.pos- { background: var(--series); }
.meter-legend i.over { background: var(--warn); }

/* data-freshness gauge: one measured age, three thresholds. Not a sparkline —
   the payload holds one sample per symbol and a fake history would be a lie.
   Nominal is graphite: a fresh feed is not a profit. */
.age { display: inline-flex; align-items: center; gap: var(--sp-2); justify-content: flex-end; }
.age-bar { width: 46px; height: 6px; flex: 0 0 46px; background: var(--surface-3); box-shadow: inset 0 0 0 1px var(--rule); }
.age-bar i { display: block; height: 100%; background: var(--rule-firm); }
.age.warn .age-bar i { background: var(--warn); }
.age.crit .age-bar i { background: var(--down); }

/* severity meter (incidents): 4 notches, filled to the severity */
.sev { display: inline-flex; gap: 3px; align-items: center; }
.sev i { width: 10px; height: 4px; background: var(--surface-3); box-shadow: inset 0 0 0 1px var(--rule); }
.sev.info i:nth-child(1) { background: var(--series); }
.sev.warn i:nth-child(-n+2) { background: var(--warn); }
.sev.crit i:nth-child(-n+3) { background: var(--down); }
.sev.crit i:nth-child(4) { background: var(--down); }

/* ============== filters & ranges — ruled tabs, not a pill box ==============
   These are NAVIGATION links (GET query strings), so they are marked up as a
   labelled group of links with aria-current. The old `role="tablist"` + plain
   `<a>` + `aria-current="true"` combination was not a valid ARIA pattern. */

/* ---------- page search (istemci taraflı filtre) ----------
   Uzun salt-okunur listeler için: /guide terimleri, /settings anahtarları. Sunucuya
   soru sorulmaz; sayfaya çoktan basılmış satırlar süzülür. */
.page-search {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  margin: 0 0 var(--sp-4);
}
.page-search-input {
  flex: 1 1 auto;
  min-width: 0;
  min-height: var(--tap);
  padding: 8px 12px;
  font: inherit;
  color: var(--ink-value);
  background: var(--bg-deep);
  border: 1px solid var(--rule-strong);
  border-radius: var(--radius-sm);
}
.page-search-input:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 1px var(--accent);
}
.page-search-input::placeholder { color: var(--ink-3); }
.page-search-count {
  flex: 0 0 auto;
  color: var(--ink-3);
  font-size: var(--fs-xs);
  font-variant-numeric: tabular-nums;
}

.filters, .ranges {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: var(--sp-1);
  margin: 0 0 var(--sp-4);
  padding: 0 0 0;
  border-bottom: 1px solid var(--rule);
  width: auto;
  max-width: 100%;
}
.filters a, .ranges a {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 7px 11px;
  font-size: var(--fs-xs);
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-2);
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
  transition: color var(--dur-1) var(--ease), border-color var(--dur-1) var(--ease),
              background var(--dur-1) var(--ease);
}
.filters a:hover, .ranges a:hover { color: var(--ink); background: var(--surface-2); }
.filters a.active, .ranges a.active {
  color: var(--ink-value);
  border-bottom-color: var(--accent);
  background: transparent;
}
.filters a[aria-pressed="true"], .ranges a[aria-pressed="true"] {
  color: var(--ink-value);
  border-bottom-color: var(--accent);
}

/* Secondary filter row: the twelve raw order states, folded away because twelve
   links outrank the six group tabs they belong under. Open it, and the raw code
   sits beside its Turkish name — an unknown code must show itself untranslated. */
.states {
  margin: calc(var(--sp-3) * -1) 0 var(--sp-4);
  border: 0;
}
.states summary {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  min-height: 32px;
  padding: 4px 8px 4px 0;
  cursor: pointer;
  list-style: none;
  font-size: var(--fs-xs);
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-3);
}
.states summary::-webkit-details-marker { display: none; }
.states summary:hover { color: var(--ink); }
.states summary svg { flex: 0 0 13px; }
.states summary .dim { margin-left: var(--sp-2); text-transform: none; letter-spacing: 0; font-weight: 450; }
.states[open] summary { color: var(--ink-2); }
.states .chips { margin: var(--sp-1) 0 var(--sp-3); }
.states .tag { text-transform: none; letter-spacing: 0; }
.states .tag .mono { font-size: var(--fs-2xs); letter-spacing: 0; }
/* "this state occurs in the list below" is a footnote, not a second status:
   it gets a dot, never a second colour that would fight the state's own tone */
.states .tag.instate::after {
  content: "";
  width: 5px;
  height: 5px;
  flex: 0 0 5px;
  background: currentColor;
  border-radius: 50%;
}
.filter-note {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2);
  margin: 0 0 var(--sp-3);
  font-size: var(--fs-sm);
  color: var(--ink-2);
}
.filter-note b { color: var(--ink-value); }
.filter-clear {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 3px 8px;
  border: 1px solid var(--rule-strong);
  border-radius: var(--radius-sm);
  font-size: var(--fs-2xs);
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-2);
}
.filter-clear:hover { color: var(--ink); border-color: var(--rule-firm); background: var(--surface-2); }

/* ============== feeds / timelines ============== */

.feed, .timeline { list-style: none; margin: 0; padding: 0; }
.feed li, .timeline li {
  display: flex;
  gap: 10px;
  padding: 8px 12px;
  border-left: 3px solid var(--rule-strong);
  background: var(--surface-2);
  margin-bottom: 2px;
  font-size: var(--fs-base);
  line-height: var(--lh-snug);
  align-items: baseline;
  transition: background var(--dur-1) var(--ease), border-left-color var(--dur-1) var(--ease);
}
.feed li:hover, .timeline li:hover { background: var(--surface-3); }
.feed li.good, .timeline li.tl-fill { border-left-color: var(--series); }
.feed li.bad { border-left-color: var(--down); }
/* a lifecycle row is not a loss: the transition rail stays graphite and lets the
   word (REDDEDİLDİ, İPTAL) carry the meaning. Only real incidents shout. */
.timeline li.tl-state { border-left-color: var(--rule-firm); }
.feed li.warn { border-left-color: var(--warn); }
.feed li.info { border-left-color: var(--series); }
/* the old `.feed li.dim { opacity: .55 }` measured 3,05:1 — unreadable in
   sunlight, which is the primary use case. Quiet now means a smaller step on
   the same AA-safe text ladder, never a lower alpha. */
.feed li.dim { color: var(--ink-3); background: var(--surface); }
.feed li.dim .feed-ts { color: var(--ink-3); }
.feed-ts {
  display: inline-block; min-width: 92px; color: var(--ink-3); font-size: var(--fs-sm);
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
}
.tl-order { border-left-color: var(--rule-strong); }
/* the connector a lifecycle list always wanted: time on a rail, event beside it */
.timeline { position: relative; }
.timeline li > span:last-child { min-width: 0; }

/* ============== decision chain cards (Kararlar) ==============
   One card per journaled candidate. The SUMMARY is the whole answer — result plus
   the reason it stopped — so the operator gets it on a phone without opening
   anything; the body is the evidence. Same recipe as `.panel`: surface fill, one
   1px edge, hairline dividers. No shadow, no glow: nothing on this page may
   compete with the two safety LEDs in the topbar. */

.decision-list { display: flex; flex-direction: column; gap: 2px; }
.decision { border: 1px solid var(--rule); background: var(--surface); }
.decision > summary {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--sp-2);
  min-height: 40px; padding: 8px 12px; cursor: pointer; list-style: none;
  font-size: var(--fs-sm); line-height: var(--lh-snug);
}
.decision > summary::-webkit-details-marker { display: none; }
.decision > summary:hover { background: var(--surface-row-hover); }
.decision > summary:focus-visible { outline: none; box-shadow: inset 0 0 0 2px var(--accent); }
.decision[open] > summary { border-bottom: 1px solid var(--rule-firm); background: var(--surface-2); }
.decision > summary .tag { flex: 0 0 auto; }
/* the sentence absorbs whatever width is left, and only it is allowed to shrink */
.decision-why { flex: 1 1 220px; min-width: 0; }
.decision-age { flex: 0 0 auto; margin-left: auto; font-size: var(--fs-2xs); }

.decision-body { padding: var(--sp-3) var(--sp-3) var(--sp-4); }
.decision-body .timeline li { align-items: flex-start; }
.decision-body .timeline li:last-child { margin-bottom: 0; }
.chain-body { display: flex; flex-direction: column; gap: var(--sp-1); min-width: 0; }
.chain-title {
  font-size: var(--fs-xs); font-weight: 700; letter-spacing: 0.06em;
  text-transform: uppercase; color: var(--ink-2);
}
.chain-text { color: var(--ink); }
.chain-facts { display: flex; flex-wrap: wrap; gap: var(--sp-1) var(--sp-4); }
.chain-fact { font-size: var(--fs-xs); color: var(--ink-3); }
.chain-fact i { font-style: normal; }
.chain-fact b {
  color: var(--ink-value); font-weight: 600;
  font-variant-numeric: tabular-nums; margin-left: 3px;
}
.decision-orders { margin-top: var(--sp-3); display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); }
.decision-rounds { margin-top: var(--sp-3); }
.decision-rounds .chain-title { display: block; margin-bottom: var(--sp-1); }

/* tighter chip pack for inside a table cell (higher-timeframe badges): the default
   .chips gap is tuned for a filter row and made the symbol column jump two lines */
.chips-tight { gap: 2px; margin-top: 2px; }
.chips-tight .tag { font-size: var(--fs-2xs); padding: 1px 5px; letter-spacing: 0.02em; }

/* ============== operator card: copyable commands ==============
   The panel runs nothing; it shows what to type on the box. The block is therefore
   a selectable surface, not a decorative code sample: `user-select: all` makes one
   click grab the whole command, which on a phone is the difference between using it
   and giving up. */
.cmd-list { display: flex; flex-direction: column; gap: var(--sp-3); margin-top: var(--sp-2); }
.cmd { border: 1px solid var(--rule); background: var(--surface-2); padding: var(--sp-3); }
.cmd-head { font-size: var(--fs-sm); font-weight: 700; color: var(--ink-value); }
.cmd-blurb { font-size: var(--fs-xs); margin-top: 2px; }
.cmd-body {
  margin: var(--sp-2) 0 0; padding: var(--sp-2);
  background: var(--surface); border-left: 3px solid var(--rule-firm);
  font-family: var(--font-mono); font-size: var(--fs-2xs); line-height: var(--lh-snug);
  color: var(--ink-2); overflow-x: auto; white-space: pre-wrap; word-break: break-all;
  user-select: all; -webkit-user-select: all;
}
.cmd-body:focus-visible { outline: none; border-left-color: var(--accent); color: var(--ink); }
code { font-family: var(--font-mono); font-size: 0.92em; color: var(--ink-value); }

/* chain-step tones: the rail answers "did this step help, or is this where it died" */
.timeline li.tl-good { border-left-color: var(--up); }
.timeline li.tl-bad { border-left-color: var(--down); }
.timeline li.tl-warn { border-left-color: var(--warn); }
.timeline li.tl-info { border-left-color: var(--rule-firm); }

@media (max-width: 560px) {
  /* on a phone the summary wraps to two lines; the age then sits under the
     sentence instead of floating alone on the right edge */
  .decision-age { margin-left: 0; }
}

/* ============== empty / note ============== */

.empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  padding: 30px 20px;
  color: var(--ink-2);
  border: 1px solid var(--rule);
  background: var(--bg-deep);
  text-align: center;
  font-size: var(--fs-base);
}
.empty svg {
  color: var(--ink-3);
  width: 20px; height: 20px;
  margin-bottom: 4px;
}
.empty-title { color: var(--ink-value); font-weight: 600; font-size: var(--fs-md); font-family: var(--font-display); }
.empty-hint { font-size: var(--fs-sm); color: var(--ink-3); max-width: 62ch; line-height: var(--lh); }

.note { margin-top: 10px; font-size: var(--fs-sm); color: var(--ink-3); line-height: var(--lh); }

/* ============== charts ============== */
/* The server emits the SVG and hard-codes its stroke/fill as *presentation
   attributes*, which any CSS rule outranks — so the palette below is the palette
   you see, with no change to the Python generator. */

.chart-wrap { overflow-x: auto; padding: 2px 0; }
/* `max-height` SABİT bir tavan + `preserveAspectRatio: xMidYMid meet` ikilisi, grafik
   910px'ten geniş olunca içeriği ortalar (letterbox) ve hover eşlemesini kaydırıyordu.
   Grafik artık kendi oranında büyür; kutusu ile çizimi her zaman aynı olur. */
.chart { width: 100%; height: auto; display: block; }
.chart-grid { stroke: var(--rule); stroke-width: 1; stroke-dasharray: 2 3; }
.chart-axis {
  fill: var(--ink-3);
  font-size: var(--fs-2xs);
  font-family: var(--font-ui);
  font-variant-numeric: tabular-nums;
}
.chart-last {
  fill: var(--ink-value);
  font-size: var(--fs-xs);
  font-weight: 650;
  font-family: var(--font-ui);
  font-variant-numeric: tabular-nums;
}
/* Grafik "gerçekler" şeridi: hover gerekmeden seriyi okur. Sunucu-render; JS kapalıyken
   de görünür, ekran okuyucu aynı sayıları okur. Mobilde sarar, taşmaz. */
.chart-block { min-width: 0; }
.chart-facts {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--sp-1) var(--sp-3);
  padding: 0 0 var(--sp-2);
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  color: var(--ink-2);
  font-variant-numeric: tabular-nums;
}
.chart-facts .cf-arrow, .chart-facts .cf-sep, .chart-facts .cf-meta { color: var(--ink-3); }
.chart-facts .cf-delta { font-weight: 600; }
.chart-note {
  margin: 0 0 var(--sp-2);
  font-size: var(--fs-xs);
  color: var(--warn-ink);
}
/* Grafik hover katmanı: dikey kılavuz + nokta + balon. Hepsi #page-content DIŞINDA,
   bu yüzden 2 sn'lik poll onları silmez; pointer-events yok, hover'ı kendileri yemez. */
.chart-cursor {
  position: fixed;
  z-index: 30;
  width: 0;
  pointer-events: none;
}
/* Çizgi ::before ile çizilir: kutudaki `border-left`, abspos nokta işaretini
   padding-box'a göre sabit +1px kaydırıyordu (bağımsız ölçüm 2026-09-13). */
.chart-cursor::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  border-left: 1px dashed var(--rule-strong);
}
.chart-cursor i {
  position: absolute;
  left: 0;
  top: 0;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--ink-value);
  box-shadow: 0 0 0 2px var(--surface);
  /* JS `left/top`u mutlak verir; nokta işareti kendi merkezinden hizalanır (kılavuz
     imleci takip eder, nokta en yakın gerçek örneğe oturur — ayrı x olabilirler). */
  transform: translate(-50%, -50%);
}
.chart-tip {
  position: fixed;
  z-index: 31;
  display: flex;
  flex-direction: column;
  gap: 2px;
  max-width: calc(100vw - 16px);
  padding: var(--sp-2) var(--sp-3);
  background: var(--surface-2);
  border: 1px solid var(--rule-strong);
  border-radius: var(--radius-sm);
  box-shadow: var(--overlay-shadow);
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  font-variant-numeric: tabular-nums;
  color: var(--ink);
  pointer-events: none;
}
.chart-tip .ct-time { color: var(--ink-3); }
.chart-tip .ct-value { font-weight: 650; }
.chart-tip .ct-delta { font-weight: 600; }
.chart-tip .ct-delta.pos { color: var(--up-ink); }
.chart-tip .ct-delta.neg { color: var(--down-ink); }
.chart-tip .ct-delta.zero { color: var(--ink-2); }
/* per-series colouring, decided by the template wrapper, not by the generator.
   NAV is steel: a level line is not a profit. Drawdown is red because a
   drawdown IS a loss — that is the one curve allowed to borrow the P&L colour.
   Every selector is anchored to `svg.chart`: an unscoped `circle` also matched
   the info glyph inside the panel title and painted it in series colours. */
.chart-nav svg.chart polyline { stroke: var(--series); stroke-width: 2; }
.chart-nav svg.chart polygon { fill: var(--series); opacity: 0.14; }
.chart-nav svg.chart circle { fill: var(--series); stroke: var(--surface); }
.chart-dd svg.chart polyline { stroke: var(--down); stroke-width: 2; }
.chart-dd svg.chart polygon { fill: var(--down); opacity: 0.14; }
.chart-dd svg.chart circle { fill: var(--down); stroke: var(--surface); }

/* "no chart yet" — the same box family as .empty, so an honest absence never
   looks like a broken one */
.chart-hollow {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  margin: 4px 18px 16px;
  padding: 16px 18px;
  border: 1px solid var(--rule);
  background: var(--bg-deep);
  color: var(--ink-3);
  font-size: var(--fs-sm);
  line-height: var(--lh);
  max-width: 720px;
}
.chart-hollow svg { flex: 0 0 20px; color: var(--ink-3); margin-top: 2px; }
.chart-hollow b { color: var(--ink-2); font-weight: 600; }

/* ============== tooltips (pure CSS: survives the fragment refresh) ==============
   Attribute-driven because the poll replaces #page-content every ~2 s; anything
   bound with addEventListener would detach. Touch has no hover, so below the
   `hover: none` block the SAME bubble opens on :focus — every trigger already
   carries tabindex="0". No piece of information may live behind hover alone. */

.gterm,
[data-tip] {
  position: relative;
  cursor: help;
}

.gterm {
  text-decoration: underline dotted var(--rule-firm);
  text-underline-offset: 3px;
  text-decoration-thickness: 1px;
}
.gterm:hover,
.gterm:focus,
.gterm:focus-visible { text-decoration-color: var(--accent); color: var(--ink-value); }

[data-tip]::after {
  content: attr(data-tip);
  position: absolute;
  left: 50%;
  bottom: calc(100% + 8px);
  transform: translateX(-50%) translateY(2px);
  z-index: var(--z-tip);
  min-width: 160px;
  max-width: min(360px, calc(100vw - 32px));
  padding: 9px 12px;
  background: var(--bg-deep);
  color: var(--ink);
  border: 1px solid var(--rule-strong);
  border-radius: var(--radius-sm);
  box-shadow: var(--overlay-shadow);
  font-family: var(--font-ui);
  font-size: var(--fs-sm);
  font-weight: 450;
  line-height: var(--lh);
  letter-spacing: 0;
  text-align: left;
  text-transform: none;
  white-space: pre-line;
  /* Hidden with `display`, not `visibility`: a laid-out-but-invisible bubble
     extends the scrollable area, which produced 5-20px of whole-page horizontal
     scroll on every viewport. `allow-discrete` keeps the fade. */
  display: none;
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--dur-2) var(--ease), transform var(--dur-2) var(--ease),
              display var(--dur-2) allow-discrete;
}

[data-tip]:hover::after,
[data-tip]:focus-visible::after,
[data-tip]:focus::after {
  display: block;
  opacity: 1;
}
[data-tip]:hover::after,
[data-tip]:focus::after,
[data-tip]:focus-visible::after { transform: translateX(-50%) translateY(0); }

@starting-style {
  [data-tip]:hover::after,
  [data-tip]:focus::after,
  [data-tip]:focus-visible::after { opacity: 0; }
}

/* Sticky table headers clip overflow, so tips in a header open downward. */
th[data-tip]::after {
  bottom: auto;
  top: calc(100% + 6px);
  transform: translateX(-50%) translateY(-2px);
}
th[data-tip]:hover::after, th[data-tip]:focus::after, th[data-tip]:focus-visible::after { transform: translateX(-50%) translateY(0); }

/* Anything pinned near the top edge would push an upward bubble out of the
   viewport (observed on the KPI row), so these open downward too. */
.topbar [data-tip]::after,
.kpi[data-tip]::after,
.cluster-label [data-tip]::after,
.page-head [data-tip]::after {
  bottom: auto;
  top: calc(100% + 6px);
  transform: translateX(-50%) translateY(-2px);
}
.topbar [data-tip]:hover::after, .topbar [data-tip]:focus::after, .topbar [data-tip]:focus-visible::after,
.kpi[data-tip]:hover::after, .kpi[data-tip]:focus::after, .kpi[data-tip]:focus-visible::after,
.cluster-label [data-tip]:hover::after, .cluster-label [data-tip]:focus::after, .cluster-label [data-tip]:focus-visible::after,
.page-head [data-tip]:hover::after, .page-head [data-tip]:focus::after, .page-head [data-tip]:focus-visible::after {
  transform: translateX(-50%) translateY(0);
}
/* KPI cards are wide: anchor to the card's own left edge so a hint on the first
   card cannot hang off the left side of the screen. */
.kpi[data-tip]::after { left: 16px; transform: translateY(-2px); }
.kpi[data-tip]:hover::after, .kpi[data-tip]:focus::after, .kpi[data-tip]:focus-visible::after { transform: translateY(0); }
.rail-toggle[data-tip]::after { left: 8px; transform: translateY(-2px); }
.rail-toggle[data-tip]:hover::after, .rail-toggle[data-tip]:focus::after, .rail-toggle[data-tip]:focus-visible::after { transform: translateY(0); }

/* Right-most columns would overflow the viewport. */
[data-tip].tip-left::after { left: auto; right: 0; transform: none; }
[data-tip].tip-left:hover::after, [data-tip].tip-left:focus::after, [data-tip].tip-left:focus-visible::after { transform: none; }

/* ============== inline explanation lines (Rehberli mode) ==============
   `coach-on` is put on <body> by dashboard.js from the cookie; CSS then reveals
   what the server already rendered. Two consequences: it costs no script, and it
   works on touch, where a bubble that needs hover is simply dead. */

.kpi-plain {
  margin-top: 6px;
  font-size: var(--fs-sm);
  line-height: var(--lh-snug);
  color: var(--ink-2);
  display: none;
  padding-top: 6px;
  border-top: 1px solid var(--rule-soft);
}
body.coach-on .kpi-plain { display: block; }

/* panel help text, printed under the header instead of hidden in a bubble */
.panel-help {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  /* Ölçüldü: 14x13px'lik hedef (bağımsız UI denetimi 2026-09-12). WCAG 2.5.8 için
     en az 24x24 dokunma alanı; görsel ikon 13px kalır, hedef büyür. */
  min-width: 24px;
  min-height: 24px;
  margin-left: 2px;
  color: var(--ink-3);
}
.panel-help:hover, .panel-help:focus, .panel-help:focus-visible { color: var(--accent-ink); }
.panel-help svg { width: 13px; height: 13px; }
/* Panel ⓘ balonu: yalnız gövde rengi panel gramerine uyar; konum/ölçü/gizleme
   `[data-tip]::after`'dan gelir. Koç modda metin gerçek bir satır (.panel-help-text)
   olduğu için balon tamamen kapanır. */
.panel-help::after { color: var(--ink-2); }
/* The inline hint is a flex item inside the title row; unless it is allowed to
   take a whole line of its own and wrap as normal text, a long hint widens the
   title, the panel, the content column and finally the whole document (measured
   +42px of page-level horizontal scroll on a 320px phone in Rehberli mode).
   `help` is a REAL sibling element (not the icon's ::after): in Rehberli mode the
   info icon must stay on the title line while only the text drops below it
   (operator report 2026-09-13: the icon sat alone on the second line). */
.panel-help-text { display: none; }
body.coach-on .panel-help { color: var(--accent-ink); }
/* Rehberli modda metin zaten satır olarak görünür; ikonun hover balonu üstüne
   binmesin (önceki `display:inline` kuralı bu işi yapıyordu). */
body.coach-on .panel-help::after { display: none; }
body.coach-on .panel-help-text {
  display: block;
  flex: 1 1 100%;
  order: 9;
  margin-top: 6px;
  font-family: var(--font-ui);
  font-size: var(--fs-sm);
  font-weight: 450;
  letter-spacing: 0;
  text-transform: none;
  line-height: var(--lh);
  color: var(--ink-2);
}


/* ============== "what am I reading" intro ============== */

.intro {
  margin: 0 0 var(--sp-5);
  border: 1px solid var(--rule);
  border-left: 3px solid var(--accent-rule);
  background: var(--surface);
}
.intro summary {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 9px 14px;
  cursor: pointer;
  list-style: none;
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--ink-2);
  user-select: none;
}
.intro summary::-webkit-details-marker { display: none; }
.intro summary svg { color: var(--accent); flex: 0 0 15px; }
.intro summary:hover { color: var(--ink-value); background: var(--surface-2); }
.intro[open] summary { color: var(--ink-value); border-bottom: 1px solid var(--rule-soft); }
.intro-lead {
  margin: 12px 16px 4px;
  font-size: var(--fs-base);
  line-height: var(--lh);
  color: var(--ink);
  max-width: 92ch;
}
.intro-points {
  margin: 8px 16px 14px;
  padding-left: 18px;
  font-size: var(--fs-sm);
  line-height: var(--lh);
  color: var(--ink-2);
  max-width: 96ch;
}
.intro-points li { margin-bottom: 4px; }
.intro-points strong { color: var(--ink); font-weight: 600; }
body.coach-on .intro { border-left-color: var(--accent); }
body.coach-on .intro[open] { background: var(--surface-2); }

/* ============== status strip (top bar) ==============
   The safety reading is the loudest thing on the screen when it is NOT the good
   news, and still perfectly legible when it is. The old `.status-led.zero` — the
   exact class that renders `EMİR KAPALI` — sat at 3,98:1 with no border and no
   fill: the single most important fact on the panel was its faintest pixel. */

.status-led {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 5px 10px 5px 8px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--rule-strong);
  background: var(--surface-2);
  font-size: var(--fs-2xs);
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--safe-ink);
  white-space: nowrap;
}
.status-led .led {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: currentColor;
  flex: 0 0 8px;
}
.status-led .led-key { color: var(--ink-2); font-weight: 600; }
.status-led b { font-weight: 700; }
/* disarmed: hollow dot, high-contrast ink. Calm, but never invisible. */
.status-led.zero .led {
  background: transparent;
  box-shadow: inset 0 0 0 2px currentColor;
}
/* Healthy is QUIET: no fill, no colour, a hairline of steel. The eye should land
   on the amber and the red first. `.zero` is the disarmed safety reading — calm
   but unmistakably legible (13,84:1), because "EMİR KAPALI" is the answer the
   operator came here for, not a footnote to it. */
.status-led.ok   { color: var(--ink); border-color: var(--rule-firm); background: var(--surface-2); }
.status-led.warn { color: var(--warn-ink); border-color: var(--warn-rule); background: var(--warn-weak); }
.status-led.crit { color: var(--down-ink); border-color: var(--down-rule); background: var(--down-weak); }
/* order writes ENABLED: money may move. Amber by default, red in LIVE. */
.status-led.armed { color: #2b1a03; border-color: var(--warn-ink); background: var(--warn); }
.status-led.armed .led-key, .status-led.armed b { color: #2b1a03; }
.status-led.armed .led { background: #2b1a03; }
.status-led.armed-live { color: #2a0507; border-color: var(--down-ink); background: var(--down); }
.status-led.armed-live .led-key, .status-led.armed-live b { color: #2a0507; }
.status-led.armed-live .led { background: #2a0507; }
.status-led.ok .led { animation: led-pulse 2.6s ease-in-out infinite; }
@keyframes led-pulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(163, 179, 196, 0.5); }
  50%      { box-shadow: 0 0 0 5px rgba(163, 179, 196, 0); }
}
/* one place to decide how many things may shout at once: the aggregate health,
   and at most one page-level banner */
.topbar .status-led.crit + .status-led.crit { animation: none; }

/* Coach/expert preference switch in the rail foot. */
.mode-switch {
  display: flex;
  gap: 2px;
  width: 100%;
  padding: 2px;
  background: var(--bg-deep);
  border: 1px solid var(--rule);
  border-radius: var(--radius-sm);
}
.mode-switch button {
  flex: 1;
  padding: 4px 6px;
  font: inherit;
  font-size: var(--fs-2xs);
  font-weight: 600;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--ink-3);
  background: transparent;
  border: 0;
  border-radius: 3px;
  cursor: pointer;
  transition: background var(--dur-1) var(--ease), color var(--dur-1) var(--ease);
}
.mode-switch button:hover { color: var(--ink); }
.mode-switch button[aria-pressed="true"] {
  background: var(--accent);
  color: #04120f;
}

/* ============== rail navigation (desktop) ==============
   Collapsed icon strip. Hover or keyboard focus widens it INTO the content gutter
   as an overlay: moving the mouse must never move the page. The pin button makes
   the wide state permanent; that choice lives in localStorage (dashboard.js) and
   adds `body.rail-pinned`. */

.sidebar .nav-group-label { display: none; }
.sidebar .nav-group { margin: 10px 16px 2px; padding: 0; }
.sidebar .nav-group::before { content: ""; display: block; height: 1px; background: var(--rule); }
/* the group rule divided the brand from the list; with no brand there is nothing
   above the first group to divide, and a 1px line 12px from the viewport corner
   just reads as a rendering fault */
.sidebar .nav-group:first-child { margin-top: 2px; }
.sidebar .nav-group:first-child::before { display: none; }

@media (min-width: 1090px) {
  .layout { display: block; }
  .main { margin-left: var(--rail-w); }

  .sidebar {
    position: fixed;
    top: 0;
    left: 0;
    bottom: 0;
    width: var(--rail-w);
    flex: none;
    transition: width var(--dur-rail) var(--ease), box-shadow var(--dur-rail) var(--ease);
  }
  body.rail-pinned .sidebar { width: var(--rail-wide); }
  .sidebar:hover,
  .sidebar:focus-within {
    width: var(--rail-wide);
    box-shadow: var(--overlay-shadow);
    border-right-color: var(--rule-strong);
  }

  .sidebar:hover .nav-label, .sidebar:focus-within .nav-label, body.rail-pinned .sidebar .nav-label {
    max-width: 220px;
    opacity: 1;
  }
  .sidebar .rail-foot .nav-label { display: none; }
  .sidebar:hover .rail-foot .nav-label, .sidebar:focus-within .rail-foot .nav-label,
  body.rail-pinned .sidebar .rail-foot .nav-label { display: inline; }

  .sidebar:hover .side-foot .chip-label, .sidebar:focus-within .side-foot .chip-label,
  body.rail-pinned .sidebar .side-foot .chip-label,
  .sidebar:hover .side-foot .pwa-btn > span, .sidebar:focus-within .side-foot .pwa-btn > span,
  body.rail-pinned .sidebar .side-foot .pwa-btn > span,
  .sidebar:hover .side-foot .logout-btn > span, .sidebar:focus-within .side-foot .logout-btn > span,
  body.rail-pinned .sidebar .side-foot .logout-btn > span { display: inline; }
  .sidebar:hover .side-foot .mode-switch, .sidebar:focus-within .side-foot .mode-switch,
  body.rail-pinned .sidebar .side-foot .mode-switch,
  .sidebar:hover .side-foot .side-meta, .sidebar:focus-within .side-foot .side-meta,
  body.rail-pinned .sidebar .side-foot .side-meta { display: flex; }

  .sidebar:hover .nav a, .sidebar:focus-within .nav a, body.rail-pinned .sidebar .nav a {
    justify-content: flex-start;
    padding: 7px 12px;
  }
  .sidebar:hover .side-foot, .sidebar:focus-within .side-foot, body.rail-pinned .sidebar .side-foot {
    align-items: stretch;
  }
  .sidebar:hover .nav-group, .sidebar:focus-within .nav-group, body.rail-pinned .sidebar .nav-group {
    margin: 14px 0 0;
    padding: 0 8px 5px;
  }
  .sidebar:hover .nav-group::before, .sidebar:focus-within .nav-group::before,
  body.rail-pinned .sidebar .nav-group::before { display: none; }
  .sidebar:hover .nav-group-label, .sidebar:focus-within .nav-group-label,
  body.rail-pinned .sidebar .nav-group-label { display: block; }

  body.rail-pinned .main { margin-left: var(--rail-wide); }
}

/* ============== responsive ==============
 * Four steps, few on purpose. Phone is a first-class layout, not a squeeze:
 *   1440  wide monitor — the content column stops growing, the table density stays
 *   1089  touch layout — drawer nav (always wide/labelled), one-row status bar,
 *         unconditional table scroller, 44px targets. (Was 1024: measured 2026-09-12,
 *         the 1025–1089 band wrapped the desktop bar onto TWO rows (83px), clipped
 *         anchor targets by 13px and produced a content column 85px NARROWER than the
 *         tablet layout it replaced — 3+1 orphan KPI rows. The boundary moved to where
 *         the desktop bar actually fits on one row.)
 *    760  phone — gutter, type ramp, single-column grids, legible chart scale
 *    480  small phone — terse status chips, one-up KPIs
 */

@media (min-width: 1441px) {
  :root { --pad-x: var(--sp-7); }
}

@media (max-width: 1440px) {
  :root { --pad-x: var(--sp-5); }
  .content { padding: var(--sp-5) var(--pad-x) var(--sp-6); }
  .topbar { padding: 6px var(--sp-4); }
  .grid-sidebar { grid-template-columns: minmax(0, 1.3fr) minmax(0, 1fr); }
}

@media (max-width: 1089px) {
  :root { --topbar-h: 54px; }

  /* the drawer supersedes the rail: ALWAYS wide and labelled, so every collapse
     rule above is undone here (the rail query cannot overlap — it starts at 1090) */
  .sidebar .nav-label { max-width: 220px; opacity: 1; }
  .side-foot .chip-label, .side-foot .pwa-btn > span, .side-foot .logout-btn > span { display: inline; }
  .side-foot .mode-switch, .side-foot .side-meta { display: flex; }
  .side-foot { align-items: stretch; }
  .rail-foot { display: none; }
  .sidebar .nav-group { margin: var(--sp-4) 0 0; padding: 0 8px 5px; }
  .sidebar .nav-group:first-child { margin-top: var(--sp-2); }
  .sidebar .nav-group::before { display: none; }
  .sidebar .nav-group-label { display: block; }
  .kpis { grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); }

  /* ---- drawer navigation ---------------------------------------------------
     The scrim sits BELOW the panel (--z-scrim < --z-rail): a scrim above the
     panel swallows every tap and the open menu can only ever close itself.
     `visibility` keeps the closed panel out of the tab order. */
  .sidebar {
    position: fixed;
    top: 0;
    left: 0;
    height: 100dvh;
    width: min(280px, calc(100vw - 88px));
    flex-basis: auto;
    transform: translateX(-102%);
    visibility: hidden;
    box-shadow: var(--overlay-shadow);
    overscroll-behavior: contain;
    transition: transform var(--dur-2) var(--ease), visibility 0s linear var(--dur-2);
  }
  .layout.nav-open .sidebar {
    transform: translateX(0);
    visibility: visible;
    transition: transform var(--dur-2) var(--ease-out);
  }
  .nav-scrim {
    display: block;
    position: fixed;
    inset: 0;
    z-index: var(--z-scrim);
    opacity: 0;
    pointer-events: none;
    border: 0;
    background: rgba(3, 5, 8, 0.72);
    transition: opacity var(--dur-2) var(--ease);
  }
  .layout.nav-open .nav-scrim { opacity: 1; pointer-events: auto; }
  /* Durum paneli perdesi: içeriği örter, alt barı (z 15) ve paneli (z 22) örtmez —
     dışa dokunuş paneli kapatır ve alttaki öğeyi ÇALIŞTIRMAZ (tap-through ölçüldü
     2026-09-12). Masaüstünde panel satır içi olduğu için perde yok. */
  .aux-scrim {
    display: block;
    position: fixed;
    inset: 0;
    z-index: 14;
    opacity: 0;
    pointer-events: none;
    border: 0;
    background: rgba(3, 5, 8, 0.55);
    transition: opacity var(--dur-2) var(--ease);
  }
  body.aux-scrim-on .aux-scrim { opacity: 1; pointer-events: auto; }
  .nav-toggle {
    width: var(--tap);
    height: var(--tap);
    flex: 0 0 var(--tap);
    display: inline-grid;
    place-items: center;
    border: 1px solid var(--rule-strong);
    border-radius: var(--radius-sm);
    padding: 0;
    color: var(--ink-2);
    background: var(--surface-2);
    cursor: pointer;
    transition: background var(--dur-1) var(--ease), color var(--dur-1) var(--ease);
  }
  .nav-toggle:hover { color: var(--ink-value); background: var(--surface-3); }

  /* the drawer is the primary navigation on touch: comfortable targets */
  .nav { padding: var(--sp-2) var(--sp-3) var(--sp-4); gap: 2px; }
  .nav a { min-height: var(--tap); padding: 10px 12px; font-size: var(--fs-base); justify-content: flex-start; }
  .nav-group { margin-top: var(--sp-4); }
  .nav-group-label { font-size: var(--fs-xs); }
  .side-foot {
    padding: var(--sp-3) var(--sp-4) calc(var(--sp-4) + env(safe-area-inset-bottom));
    gap: var(--sp-3);
  }
  .mode-switch button { min-height: var(--tap); font-size: var(--fs-sm); }
  .side-meta { font-size: var(--fs-xs); }

  /* ---- one-row status bar ---------------------------------------------------
     Groups must not shrink: when they did, they collapsed to 0 and spilled the
     LEDs over 2-3 extra rows (a 75-111px sticky header on phones). The bar is one
     fixed row; everything secondary lives in the strip under it.
     A PHONE gives this bar up entirely (operator decision 2026-09-11): the rules that
     switch it off live in the phone section at the end of this file, next to the
     bottom bar that replaced it. */
  .topbar {
    height: var(--topbar-h);
    min-height: var(--topbar-h);
    align-items: center;
    flex-wrap: nowrap;
    gap: var(--sp-2);
    padding: 0 var(--pad-x);
  }
  .topbar-group { flex: 0 0 auto; }
  .topbar-group + .topbar-group,
  .topbar-aux > .topbar-group:first-child,
  .topbar-aux > .topbar-mode-narrow + .topbar-group,
  .topbar-aux > .topbar-spacer + .topbar-group { padding-left: 0; border-left: none; }
  .topbar-spacer { display: none; }
  .topbar-aux {
    display: none;
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    flex-direction: column;
    align-items: flex-start;
    gap: var(--sp-2);
    padding: var(--sp-3) var(--pad-x) var(--sp-4);
    background: var(--surface);
    border-bottom: 1px solid var(--rule-strong);
    box-shadow: var(--overlay-shadow);
    z-index: var(--z-aux);
  }
  .topbar.aux-open .topbar-aux { display: flex; }
  .topbar-aux > .topbar-group { min-height: 28px; flex-wrap: wrap; }
  .topbar .aux-toggle {
    display: inline-flex;
    align-items: center;
    margin-left: auto;
    min-height: 36px;
    flex: 0 0 auto;
    cursor: pointer;
    font-family: var(--font-ui);
  }
  /* `inline-flex` yutan bir şey: " UTC" ve " yerel" metin düğümleri kendi flex öğeleri
     olur ve öğenin başındaki boşluk çizgi sınırında silinir - sonuç telefonda
     "14:15:48UTC". Boşluk artık gap'ten gelir. */
  .clocks { display: inline-flex; align-items: center; white-space: nowrap; gap: 4px; }
  /* nokta kendi kenar boşluğunu taşıyordu; artık aralığı `gap` veriyor - çift pay olmasın */
  .clocks .clock-sep { margin: 0; }

  .content { padding: var(--sp-4) var(--pad-x) var(--sp-6); }

  /* ---- tables ---------------------------------------------------------------
     The scroller is unconditional on touch layouts: gating it on a class that
     only dashboard.js adds meant that, before the script ran (or with the script
     blocked), a wide table widened the whole document — measured 470px of
     page-level horizontal scroll on /markets at 375px. */
  .table-wrap { overflow-x: auto; max-height: none; -webkit-overflow-scrolling: touch; }
  /* Dokunmatik düzende iç kaydırma yok (max-height: none), bu yüzden sticky th hiç
     yapışmıyordu: ölü kural kaldırıldı (ölçüm 2026-09-12: sayfa kaydırılınca th -1007px).
     Sticky başlık yalnız >1089'da, tablo kendi yüksekliğinde kayarken çalışır. */
  .kv-grid { grid-template-columns: 1fr; }
  .grid-2, .grid-sidebar { grid-template-columns: 1fr; }

  /* ---- touch targets -------------------------------------------------------
     Padding (not font-size) does the growing, so the visual rhythm holds. */
  .filters a, .ranges a { min-height: var(--tap); padding: 10px 13px; }
  .intro summary { min-height: var(--tap); }
  .states summary { min-height: var(--tap); }
  .settings-index a { min-height: 38px; padding: 8px 11px; }
  .panel-head-actions a, .panel-foot a {
    display: inline-flex;
    align-items: center;
    min-height: 40px;
    padding: 0 6px;
    margin: -6px 0;
  }
  .foot a { display: inline-flex; align-items: center; min-height: 44px; padding: 0 4px; }
  .gloss-meta a { display: inline-flex; align-items: center; min-height: 44px; }
  .tag, .chip { padding: 5px 9px; }
}

@media (max-width: 760px) {
  /* ---- gutter + type ramp ---------------------------------------------------
     The desktop micro-letter ramp is legible on a desk monitor and not on a phone
     held at arm's length in sunlight. Only these tokens are re-declared, inside a
     query, so every desktop keeps the original scale. The KPI ramp stays
     monotonic: 26 → 22 → 20. */
  :root {
    --pad-x: var(--sp-4);
    /* The floor is 12px, not 11.5px. Measured on the deployed panel at 390x844, EVERY
       page carried text below 12px - 36 on /overview, 42 on /orders, 48 on /settings -
       and the single largest group was `.tag` (101 instances on /orders), i.e. the
       status pills the operator reads most. The fix is the floor itself; nothing below
       12px survives on a phone.
       The rest of the ramp is the DESKTOP scale plus one step at most (base 13,5 ->
       14, sm 13 -> 13): the 2026-09 revision had inflated every phone token by 8-22%
       (base 15,5, nav 16,5) and the operator read that as "the panel shouts on a
       phone". Legibility on glass is bought by the 12px FLOOR and the 44px tap
       target, not by scaling body copy up past the desktop ramp. */
    --fs-2xs: 12px;
    --fs-xs: 12.5px;
    --fs-sm: 13px;
    --fs-base: 14px;
    --fs-md: 15px;
    --fs-lg: 16.5px;
    --fs-2xl: 20px;
    --fs-kpi: 22px;
    --fs-kpi-lg: 24px;
  }

  /* Micro-caps are the panel's label voice and its least legible one on glass. The
     desktop tracking (0.10-0.18em) is tuned for a monitor at desk distance; on a phone
     it is what makes "GERÇEKLEŞMEMİŞ K/Z" unreadable. Halving the tracking pays back
     most of the width the raised floor costs - the labels stay capitals, because the
     case is what separates a label from a value in this system. */
  .kpi-label,
  .cluster-label,
  .nav-group-label,
  .status-led .led-key,
  th,
  tfoot td .tsum-k {
    letter-spacing: 0.08em;
  }

  /* A form field under 16px makes iOS Safari zoom the whole page on focus and then
     leave it zoomed - the single most reported "panel broke" complaint on phones.
     `font: inherit` on the input was inheriting 15px. */

  /* Tap targets are squares, not bands: --tap was applied to height only, which is how
     the DURUM button survived at 27x36 on every single page. The phone's DURUM lives in
     the bottom bar now, and `.tabbar button` gives it --tap of height and 20% of the
     screen in width, so the square is paid for by the bar itself. */
  .panel-head-actions a,
  .panel-foot a {
    min-height: var(--tap);
  }
  .filters a,
  .ranges a,
  a.tag,
  .chips a.chip {
    min-height: var(--tap);
    /* width too: the time-range chips measured 38-41px wide at 44px tall. A target is a
       square you hit with a pad, not a band you aim at. */
    min-width: var(--tap);
    justify-content: center;
    display: inline-flex;
    align-items: center;
  }

  .hide-narrow { display: none; }
  .show-narrow { display: inline; }

  /* ---- hedef barı (base.html'deki .tabbar) --------------------------------
     Telefonda gezinme, parmağın erişebildiği alt kenarda olur; 14 hedeflik bir
     listeyi üst soldaki çekmeceye gömmek erişimi iki dokunuşa çıkarıyordu.
     Katman: --z-topbar (15) < --z-scrim (18) < --z-rail (20), yani çekmece açıldığında
     bar perde altında kalır, çekmecenin üstüne çıkmaz.
     Görünür işaret tek bir 2px accent çizgisi + yüzey tonu; panelde gölge/glow
     yalnızca overlay'lerindir (bkz. renk sözleşmesi).
     Sekmeler arasında `gap: 1px` + kural zemini vardı ve beş hedefi ayrı kutular
     gibi gösteriyordu (operatör geri bildirimi: "aralarındaki boşluklar"). Bar artık
     bitişik tek yüzey; ayrımı yalnızca aktif tonu ve accent çizgisi taşır. Üst
     hairline içerik ayrımı için duruyor.
     BAR YANA KAYAR: her sekme ekranın %20'si, yani görünen beşli eskisiyle birebir
     aynı; altıncısı (Durum) sağ kenarın dışında bekler ve bar sola kaydırılınca çıkar
     (operatör kararı 2026-09-11: üst şerit tamamen kalktı). Snap yarım görünür sekme
     bırakmaz; kaydırma çubuğu da gösterilmez - burada bir şeyin saklı olduğu okla
     değil, parmakla anlaşılır. */
  .tabbar {
    display: flex;
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: var(--z-topbar);
    align-items: stretch;
    gap: 0;
    background: var(--rail-bg);
    border-top: 1px solid var(--rule-strong);
    padding-bottom: env(safe-area-inset-bottom);
    /* yatay çentik/ev göstergesi: bar ve panel kenarlarını güvenli alana çek
       (viewport-fit=cover ile env canlanır; düz tarayıcıda 0'dır) */
    padding-left: env(safe-area-inset-left);
    padding-right: env(safe-area-inset-right);
    overflow-x: auto;
    overflow-y: hidden;
    scroll-snap-type: x proximity;
    scrollbar-width: none;
  }
  .tabbar::-webkit-scrollbar { display: none; }
  .tabbar a,
  .tabbar button {
    flex: 0 0 20%;
    min-width: 0;
    min-height: var(--tap);
    scroll-snap-align: end;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 3px;
    padding: 7px 2px 6px;
    border: 0;
    background: var(--rail-bg);
    color: var(--ink-3);
    font: inherit;
    font-size: var(--fs-2xs);
    letter-spacing: 0.02em;
    text-decoration: none;
    cursor: pointer;
  }
  .tabbar svg { width: 18px; height: 18px; }
  .tabbar .active {
    color: var(--accent-ink);
    background: var(--surface-2);
    box-shadow: inset 0 2px 0 var(--accent);
  }
  /* Durum sekmesi: panel kapalıyken emniyet tonunu taşır (amber/kırmızı), açıkken de
     bir sayfa sekmesi gibi accent çizgisiyle durur - hangi kapıyı açtığı belli olsun. */
  .tabbar-status.warn { color: var(--warn-ink); }
  .tabbar-status.crit { color: var(--down-ink); }
  .tabbar-status[aria-expanded="true"] {
    color: var(--accent-ink);
    background: var(--surface-2);
    box-shadow: inset 0 2px 0 var(--accent);
  }
  .tabbar a:active,
  .tabbar button:active { background: var(--surface-3); }
  /* bar sabit olduğu için son satır onun altında kalırdı: pay, ölçülen bar yüksekliği
     + nefes payıdır. Eskiden sabit 64px'ti ve ölçülen 53px'e karşı ~19px ölü boşluk
     bırakıyordu (bağımsız UI denetimi 2026-09-12); fallback, env'i kendi içerir. */
  .foot { padding-bottom: calc(var(--sp-4) + var(--tabbar-h, calc(53px + env(safe-area-inset-bottom)))); }

  /* ---- üst şerit telefonda YOK (operatör kararı 2026-09-11) ------------------
     ☰ ve DURUM üstten gidiyor: menü alt bardaki Diğer'den, durum alt bardaki Durum
     sekmesinden açılıyor. `display: none` kullanılamazdı: #topbar-aux bu başlığın
     ÇOCUĞU ve telefonda alttan yükselen panelin ta kendisi - gizli bir ata onu da
     götürürdü. `display: contents` başlığın kutusunu siler ve çocukları .main'in
     sütun akışına düşürür, o yüzden geri kalan her grup burada tek tek susturulur.
     `.topbar.aux-open` sınıfı JS'te başlığa yazılmaya devam eder: kutusu olmayan bir
     öğede de seçici çalışır. */
  .topbar { display: contents; }
  .topbar-primary,
  .topbar .aux-toggle { display: none; }
  /* Durum paneli: alt bardan yükselen tabaka. Barın tam üstüne oturur; barın yüksekliği
     içerikten geldiği için tahmin edilmez, dashboard.js ölçüp --tabbar-h'a yazar (56px
     fallback'i JS yokken de paneli barın üstünde tutar). Böylece Durum sekmesi görünür
     kalır ve bir daha dokununca paneli kapatır. */
  .topbar-aux {
    position: fixed;
    top: auto;
    bottom: var(--tabbar-h, calc(53px + env(safe-area-inset-bottom)));
    left: 0;
    right: 0;
    max-height: min(60dvh, 460px);
    overflow-y: auto;
    overscroll-behavior: contain;
    padding: var(--sp-4) calc(var(--pad-x) + env(safe-area-inset-right)) var(--sp-4) calc(var(--pad-x) + env(safe-area-inset-left));
    border-top: 1px solid var(--rule-strong);
    border-bottom: 0;
    box-shadow: 0 -16px 40px rgba(3, 5, 8, 0.62);
  }
  /* çalışma modunu taşıyacak bir üst şerit kalmadı: TEST AĞI / CANLI panele iner */
  .topbar-mode-narrow { display: flex; }

  /* ---- çekmece sağdan (operatör kararı 2026-09-11) ---------------------------
     Telefonda çekmeceyi açan tek kapı alt barın SAĞ köşesindeki Diğer'dir: üstteki ☰
     kalktığı için perdeyi kaldırtan düğme orada duruyor. Parmağın bastığı yerden
     doğmayan bir panel bar ile nedensellik kuramaz, o yüzden çekmece yön değiştirdi.
     Açık durumu `.layout.nav-open .sidebar` (≤1089, daha yüksek özgünlük) çevirir. */
  .sidebar {
    left: auto;
    right: 0;
    transform: translateX(102%);
    border-right: 0;
    border-left: 1px solid var(--rule);
    padding-right: env(safe-area-inset-right);
  }
  /* içerik ve footer yatay güvenli alana çekilir (çentikli yatay kullanım) */
  .main { padding-left: env(safe-area-inset-left); padding-right: env(safe-area-inset-right); }
  /* Çekmecedeki durum kapısı: alt bardaki Durum sekmesi sağda saklı olduğundan,
     gezinmeye gelen operatör paneli burada da bulur (44px hedef). */
  .side-status {
    display: flex;
    align-items: center;
    gap: 8px;
    width: 100%;
    min-height: var(--tap);
    padding: 10px 12px;
    font: inherit;
    font-size: var(--fs-base);
    color: var(--ink-2);
    background: var(--surface-2);
    border: 1px solid var(--rule-strong);
    border-radius: var(--radius-sm);
    cursor: pointer;
  }
  .side-status:active { background: var(--surface-3); }

  /* LEDs must never shrink: a clipped status word is worse than a tight row */
  .status-led, .tag { flex: 0 0 auto; }
  .status-led { padding: 4px 8px 4px 7px; gap: 5px; letter-spacing: 0.03em; }
  .clocks { padding: 3px 8px; }

  /* Density, not decoration. Measured on /overview at 390px: 15 KPI cells filled
     1.921px of the 3.578px standing between the top of the page and the first table -
     54% of everything above the data. None of it was required by the data: the values
     are "YOK", "AÇIK", "%-23,00", "1 emir", "0,00 USDT". The height came from
     min-height floors plus 28px of vertical padding per cell, so both go. */
  .kpis, .kpis.featured, .kpis.compact { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .kpi { min-height: 0; padding: var(--sp-2) var(--sp-3) var(--sp-3); }
  .kpi.featured { min-height: 0; padding: var(--sp-2) var(--sp-3) var(--sp-3); }
  .kpi-value { margin-top: 4px; }
  .kpis { margin-bottom: var(--sp-3); }
  .kpi-cluster { margin-bottom: var(--sp-3); }
  .cluster-label { margin-bottom: 6px; }
  /* Banners carry safety sentences (drawdown breaker, foreign inventory census) that
     may not be hidden or truncated, so the only thing given up here is padding. The
     line-height stays at 1,5x: WCAG 1.4.12 outranks the page-length budget. */
  .banner { padding: 10px 12px; gap: 8px; }

  .page-head { gap: var(--sp-2) var(--sp-4); margin-bottom: var(--sp-4); }
  .panel { padding: var(--sp-3) var(--sp-4); }
  .panel.flush h2 { padding: var(--sp-3) 14px 0; }
  .panel-inset { padding: 0 var(--sp-3) var(--sp-4); }
  .chart-wrap.panel-chart { padding: var(--sp-2) var(--sp-3) var(--sp-4); }
  ul.panel-feed { padding: var(--sp-3) var(--sp-3) var(--sp-1); }
  .panel-foot.bare { padding: var(--sp-3) var(--sp-4); }
  .chart-hollow { margin-left: 14px; margin-right: 14px; }
  .panel-head { min-height: 0; padding: var(--sp-3) var(--sp-4); align-items: flex-start; }
  .panel-head h2 { min-width: 0; flex-wrap: wrap; }

  th, td { padding: 8px 10px; }
  .panel.flush table th:first-child, .panel.flush table td:first-child { padding-left: 14px; }
  .panel.flush table th:last-child,  .panel.flush table td:last-child  { padding-right: 14px; }
  td.wrap { min-width: 190px; max-width: none; }
  tfoot td { position: static; }

  /* ---- kart düzeni (.cards) ----------------------------------------------
     dashboard.js işaretler: 760px altında ve dört veya daha fazla kolonu olan
     tablolarda. Amaç yana kaydırmayı bitirmek - /markets'te tablo ekranın 3,7
     katıydı, yani tek bir satırı okumak üç ekran yatay swipe demekti.

     Kartın ilk satırı kimlik + anahtar değer (thead'de .p-key ile işaretli
     kolon), altındaki her satır bir kolon: etiket solda, değer sağda. Değerler
     hiçbir yerde yinelenmez; her hücre DOM'da bir kez durur, yalnızca biçimi
     değişir. Etiketin kaynağı kolon başlığının kendisi olduğu için başlık ile
     etiket biribirinden kopamaz. */
  /* Kart kuralı fade kuralından SONRA gelmeli: markScrollable düz tabloyu ölçüp
     `is-scrolling` yazarken kart düzeni henüz uygulanmamış olursa, kaydırılamayan
     listede kalıcı "kaydır" gradyanı kalıyor (ölçüldü 2026-09-12: sw==cw iken
     sağ kenar gradyanı). Sıra dashboard.js'te cards→scroll; gradyan burada da
     kesilir. */
  .table-wrap.cards { overflow: visible; max-height: none; background-image: none; }
  .table-wrap.cards table { display: block; width: 100%; }
  .table-wrap.cards thead { display: none; }
  .table-wrap.cards tbody { display: block; }
  .table-wrap.cards tbody tr {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 4px 10px;
    padding: 10px 12px;
    border-bottom: 1px solid var(--rule);
  }
  .table-wrap.cards tbody td { display: block; padding: 0; min-width: 0; }
  /* kkey'in yapışkan ilk kolonu kartta anlamsız: arka plan ve iç gölge sızmasın */
  .table-wrap.cards tbody td:first-child,
  .table-wrap.cards thead th:first-child {
    position: static;
    left: auto;
    box-shadow: none;
    background: transparent;
  }
  /* Baslik satiri: kimlik solda, anahtar deger sagda. order: negatif, cunku esnek
     dizim DOM sirasini izler ve /orders'ta sembol DOM'da ikinci hucredir - kartın
     ilk satiri DOM sirasiyla degil, anlam sirasiyla yazilmali. */
  .table-wrap.cards tbody td[data-id] {
    order: -2;
    flex: 1 1 auto;
    color: var(--ink-value);
    font-weight: 650;
  }
  .table-wrap.cards tbody td[data-key] {
    order: -1;
    flex: 0 0 auto;
    font-size: var(--fs-md);
    font-weight: 650;
    text-align: right;
  }
  .table-wrap.cards tbody td:not([data-id]):not([data-key]):not([colspan]) {
    flex: 1 1 100%;
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    align-items: baseline;
    gap: 14px;
    min-width: 0;
    overflow-wrap: anywhere;
    padding-top: 4px;
    border-top: 1px solid var(--rule-soft);
    color: var(--ink-2);
  }
  /* Hücre etiketle değerini aynı satıra sığdıramayınca satır kendi kutusuna taşırıyordu
     (canlıda ölçüldü: /incidents 12px, /markets 24px belge taşması; hücre 353/322).
     Etiket pseudo-elemanı `flex: 0 0 auto` olduğu için küçülmüyor, ham metin düğümü de
     flex öğesi olarak kırılmıyordu. `flex-wrap: wrap` etiketi değerin altına indirir;
     taşmayı kesmenin `overflow: clip`'ten farkı, ipucu balonlarını da kırpmaması. */
  .age {
    min-width: 0;
  }
  .age-bar {
    flex: 0 1 34px;
    width: auto;
    min-width: 18px;
  }
  .table-wrap.cards tbody td:not([data-id]):not([data-key]):not([colspan])::before {
    content: attr(data-label);
    flex: 0 0 auto;
    color: var(--ink-3);
    font-size: var(--fs-xs);
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
  }
  .table-wrap.cards tbody td[colspan] { flex: 1 1 100%; }

  /* Satir ici linkler (emir ID, karar zinciri) masada 16px'lik metin parcalaridir;
     /orders'taki 117 dokunma ihlalinin 100'u bunlardi. Kart duzeninde her link kendi
     etiketli satirinda duruyor, o yuzden dokunma alani satirin kendisi olur: 44px
     yukseklik + metnin cevresinde tampon. Ucostan bedava degil - kart basina bir satir
     boyu - ama "basilabilir" demek icin 20px yetmiyordu. */
  .table-wrap.cards tbody td:has(a) { align-items: center; }
  .table-wrap.cards tbody td a {
    min-height: 44px;
    display: inline-flex;
    align-items: center;
    padding: 0 6px;
    margin: 0 -6px;
    border-radius: var(--radius-sm);
  }

  /* ---- toplam satırı ----
     Masaüstünde bu satır kolonlara hizalı bir toplam şerididir; kart düzeninde sekiz
     yığılmış kutuya çöküyordu (ölçüldü: boş hücreler dahil sekiz satır, etiket yok).
     Burada da üst satırlarla aynı dil kullanılır: etiket solda, toplam sağda. Boş
     hücreler gösterilmez - Adet ve Ort. Maliyet için toplam yoktur. Bir toplam, hangi
     kolona ait olduğu okunmuyorsa cevap değildir, sadece sayıdır. */
  .table-wrap.cards tfoot { display: block; border-top: 1px solid var(--rule-strong); }
  .table-wrap.cards tfoot tr {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 3px 10px;
    padding: 8px 12px 10px;
  }
  .table-wrap.cards tfoot td {
    display: block;
    min-width: 0;
    padding: 0;
    position: static;
    background: none;
    box-shadow: none;
  }
  .table-wrap.cards tfoot td:empty { display: none; }
  .table-wrap.cards tfoot td:first-child,
  .table-wrap.cards tfoot td[colspan] {
    flex: 1 1 100%;
    color: var(--ink-3);
  }
  .table-wrap.cards tfoot td:not(:first-child):not([colspan]) {
    flex: 1 1 100%;
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 14px;
    color: var(--ink-value);
    font-weight: 650;
  }
  .table-wrap.cards tfoot td:not(:first-child):not([colspan])::before {
    content: attr(data-label);
    color: var(--ink-3);
    font-size: var(--fs-xs);
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
  }

  .filters { gap: 2px; }
  .filters a, .ranges a { font-size: var(--fs-sm); padding: 8px 8px; }
  /* .guide-flow li'nin mobil padding'i buradan kaldırıldı: üst-seviye tanım dosyada
   * sonra geldiği için kural hiç uygulanmıyordu. Telefon override'ları dosya sonunda
   * (test_web_mobile bu sınıfın tamamını kilitler). */

  /* key/value rows: let the pair wrap instead of cutting a Turkish word in half */
  .kv { flex-wrap: wrap; gap: 2px var(--sp-3); }
  .kv span { min-width: 0; flex: 1 1 auto; }
  .kv b { min-width: 0; max-width: none; flex: 0 1 auto; overflow-wrap: anywhere; }
  .chips .chip, .chips .tag { max-width: 100%; white-space: normal; overflow-wrap: anywhere; }

  /* charts: the SVG scales its whole coordinate system, so a fitted-to-phone
     318x84 chart rendered its 11px axis text at 5px. Hold a legible scale and let
     the existing scroll box do the rest. */
  .chart-wrap { padding: var(--sp-2) var(--sp-3) var(--sp-4); }
  .chart { width: max(100%, 560px); }
  .chart-axis { font-size: var(--fs-sm); }
  .chart-last { font-size: var(--fs-base); }

  /* Tips would overflow a phone: span nearly the full width, pinned to the
     trigger's own left edge (`.tip-left` still wins on specificity). */
  [data-tip]::after {
    left: 0;
    right: auto;
    transform: none;
    min-width: 0;
    max-width: calc(100vw - 32px);
    font-size: var(--fs-sm);
  }
  [data-tip]:hover::after, [data-tip]:focus::after, [data-tip]:focus-visible::after { transform: none; }
  .kpi[data-tip]::after { left: 12px; }
  .empty { padding: var(--sp-6) var(--sp-4); }
  .meter { height: 12px; }
}

/* ---- kısa yatay dokunmatik (telefon yatayı + küçük tablet yatayı) -------------
   Kırılım yalnız genişlikti: 844x390'da telefon modeli tamamen kayboluyor, üst
   şerit + soldan çekmece geri geliyor ve tek elle gezinme imkânsızlaşıyordu
   (ölçüldü 2026-09-12). Bu pencerede 44px'lik ikon barı geri gelir; kart modu JS'te
   genişlik tabanlı kaldığı için tablolar tablo kalır. Kapsam bilerek dar: dokunmatik
   olmayan kısa masaüstü pencereleri etkilenmez. */
@media (min-width: 761px) and (max-width: 1089px) and (max-height: 500px) and (orientation: landscape) and (pointer: coarse) {
  .tabbar {
    display: flex;
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: var(--z-topbar);
    align-items: stretch;
    gap: 0;
    background: var(--rail-bg);
    border-top: 1px solid var(--rule-strong);
    padding-bottom: env(safe-area-inset-bottom);
    padding-left: env(safe-area-inset-left);
    padding-right: env(safe-area-inset-right);
    overflow-x: auto;
    overflow-y: hidden;
    scrollbar-width: none;
  }
  .tabbar::-webkit-scrollbar { display: none; }
  .tabbar a,
  .tabbar button {
    flex: 0 0 20%;
    min-height: var(--tap);
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 4px 0;
    border: 0;
    background: var(--rail-bg);
    color: var(--ink-3);
    font: inherit;
    font-size: var(--fs-2xs);
    text-decoration: none;
    cursor: pointer;
  }
  .tabbar svg { width: 18px; height: 18px; }
  /* etiket görsel olarak kırpılır ama display:none onu ekran okuyucudan da siler */
  .tabbar a span,
  .tabbar button span {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }
  .tabbar .active,
  .tabbar-status[aria-expanded="true"] {
    color: var(--accent-ink);
    background: var(--surface-2);
    box-shadow: inset 0 2px 0 var(--accent);
  }
  .tabbar-status.warn { color: var(--warn-ink); }
  .tabbar-status.crit { color: var(--down-ink); }
  .topbar-aux { bottom: var(--tabbar-h, calc(45px + env(safe-area-inset-bottom))); }
  .foot { padding-bottom: calc(var(--sp-3) + var(--tabbar-h, calc(45px + env(safe-area-inset-bottom)))); }
}

/* 320-480px. Üst şerit 760px'te zaten kalktı, o yüzden burada ona dokunan tek bir
   kural kalmadı (kalsaydı kutusu olmayan bir öğeye yazılmış ölü bir kural olurdu).
   Burada ter döken şey durum panelinin yoğunluğu ve KPI ızgarası: `wrap` panelde
   durur, beklenmedik uzunlukta bir rozet (LIVE) belgeyi genişletmez. */
@media (max-width: 480px) {
  :root { --fs-kpi: 20px; --fs-kpi-lg: 22px; --fs-2xl: 19px; }

  /* panelin LED'leri en dar camda da tam kelimesini korur: ödün veren şey padding  */
  .status-led { padding: 4px 7px 4px 6px; gap: 4px; }
  .status-led .led { width: 7px; height: 7px; flex: 0 0 7px; }
  /* Phone width: still two columns. Collapsing to one column at 480px is what turned
     15 short numbers into a 1.5-screen scroll. A cell at ~172px fits every value the
     panel produces; long text verdicts ("HENÜZ ÖLÇÜLMEDİ") wrap inside the cell, which
     is what a cell is for. */
  .kpis, .kpis.featured, .kpis.compact { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .kpis.compact .kpi:not(.featured) { min-height: 62px; }
  .feed li, .timeline li { padding: var(--sp-2) 10px; }
  .feed-ts { min-width: 74px; }
  /* .gloss-row / .guide-flow override'lari buradan kaldirildi: ayni seciciler dosyanin
   * ilerisinde ( rehber bolumunde) yeniden tanimlandigi icin buradaki kural hic
   * uygulanmiyordu. Telefon override'lari artik dosya sonunda. */
}

/* ============== touch: no hover means no hover-only information ============== */

@media (hover: none) {
  /* tap focuses a tabindex="0" trigger; :focus-visible deliberately does NOT
     match a tap, so the hint would never open. This is the whole fix for 114
     `data-tip` hints that were unreachable on ~60% of the panel's usage. */
  [data-tip]:focus::after { display: block; opacity: 1; }
  .gterm, [data-tip] { cursor: pointer; }
  /* Rehberli modda metin zaten satır olarak görünür; bu kural aynı özgüllükte ve
     dosyada daha sonra geldiği için dokunmatikte ⓘ odağı ikinci bir balon açıyordu
     (ölçüm 2026-09-13). Koç modda balon her koşulda kapalı kalsın. */
  body.coach-on .panel-help::after { display: none; }
}

/* ============== accessibility media queries ============== */

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    transition-delay: 0s !important;
    scroll-behavior: auto !important;
  }
  .status-led.ok .led { animation: none; }
  .sidebar, .sidebar .nav-label { transition: none; }
}

/* Windows High Contrast / Forced Colors: the panel's meaning lives in 1px rules
   and in fill colours, both of which the OS strips. Every status therefore keeps
   a TEXT label in the DOM (never colour alone) and systems colours take over here. */
@media (forced-colors: active) {
  .tag, .chip, .status-led, .banner, .panel, .kpis, .kpi, .table-wrap,
  .filters a, .ranges a, .empty, .chart-hollow, .intro, .bar, .meter, .clocks,
  .nav a, .nav a.active, .login-card, .login-submit, .logout-btn, .pwa-btn {
    border: 1px solid CanvasText;
    background: Canvas;
    color: CanvasText;
    box-shadow: none;
  }
  .status-led .led { forced-color-adjust: none; }
  .bar-fill, .meter-seg, .age-bar i, .sev i { forced-color-adjust: none; }
  .status-led.armed, .status-led.armed-live, .tag.live {
    background: Highlight;
    color: HighlightText;
    border-color: HighlightText;
  }
  .nav a.active { outline: 2px solid Highlight; outline-offset: -2px; }
  .tabbar .active { outline: 2px solid Highlight; outline-offset: -2px; }
  /* şerit gölgeyle çizilir; forced-colors gölgeyi siler → kenarlıkla geri gelir */
  .kpi.is-safe, .kpi.is-warn, .kpi.is-unknown, .kpi.is-crit { border-left: 3px solid Highlight; }
  a:focus-visible, button:focus-visible, [tabindex]:focus-visible { outline: 2px solid Highlight; }
  .filters a.active, .ranges a.active { border-bottom: 3px solid Highlight; }
}

/* prefers-contrast: more — lift the whole ladder rather than the accents, so
   quiet data stays quiet but never below the reader's floor. */
@media (prefers-contrast: more) {
  :root {
    --ink: #ffffff;
    --ink-2: #ccd8e4;
    --ink-3: #a8b6c5;
    --rule: rgba(220, 234, 246, 0.32);
    --rule-strong: rgba(220, 234, 246, 0.5);
    --rule-soft: rgba(220, 234, 246, 0.18);
    --rule-firm: rgba(220, 234, 246, 0.6);
    --surface: #0d1319;
    --bg-deep: #000205;
  }
  .feed li.dim { color: var(--ink-2); }
}

/* Print: the panel is a report. One column, no chrome, no sticky anything. */
@media print {
  :root { --pad-x: 0; }
  body { background: #fff; color: #000; }
  .sidebar, .nav-scrim, .topbar, .foot, .rail-foot, .mode-switch, .pwa-btn,
  .logout-form, .intro summary svg { display: none !important; }
  .main { margin-left: 0; }
  .content { max-width: none; padding: 0; }
  .panel, .kpis, .kpi, .banner, .empty, .chart-hollow, .intro {
    border-color: #999;
    background: #fff;
    color: #000;
    box-shadow: none;
    break-inside: avoid;
  }
  .kpi-value, .page-head h1, .sym, td, .kv b { color: #000; }
  .muted, .dim, .kpi-label, .kpi-sub, th, .empty-hint, .note { color: #333; }
  .table-wrap { max-height: none; overflow: visible; }
  .table-wrap::after { display: none; }
  th, tfoot td { position: static; background: #eee; color: #000; }
  a { color: #000; text-decoration: none; }
  [data-tip]::after { display: none !important; }
}

/* ============== guide page ============== */

.guide-flow { margin: 0; padding: 0; list-style: none; counter-reset: step; }
.guide-flow li {
  display: grid;
  grid-template-columns: 26px 128px 1fr;
  align-items: baseline;
  gap: 12px;
  padding: 10px 0;
  border-bottom: 1px solid var(--rule-soft);
  font-size: var(--fs-base);
}
.guide-flow li:last-child { border-bottom: none; }
.guide-flow li::before {
  counter-increment: step;
  content: counter(step);
  width: 22px;
  height: 22px;
  display: grid;
  place-items: center;
  border: 1px solid var(--accent-rule);
  background: var(--accent-weak);
  color: var(--accent-ink);
  font-size: var(--fs-2xs);
  font-weight: 700;
}
.guide-flow b { color: var(--ink-value); font-weight: 600; }
.guide-flow span { color: var(--ink-2); line-height: var(--lh); }
.guide-flow em { color: var(--ink); font-style: normal; font-weight: 600; }

.gloss { margin: 0; }
.gloss-row {
  display: grid;
  grid-template-columns: 210px 1fr;
  gap: var(--sp-4);
  padding: 11px 0;
  border-bottom: 1px solid var(--rule-soft);
}
.gloss-row:last-child { border-bottom: none; }
.gloss dt {
  font-family: var(--font-display);
  font-weight: 650;
  color: var(--ink-value);
  font-size: var(--fs-md);
  letter-spacing: -0.01em;
}
.gloss dd { margin: 0; }
.gloss dd > p { margin: 0; font-size: var(--fs-base); line-height: var(--lh); color: var(--ink-2); }
.gloss dd > .gloss-why { margin-top: 3px; color: var(--ink-3); font-size: var(--fs-sm); }
.gloss dd > .gloss-meta {
  margin-top: 5px;
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
  align-items: center;
  font-size: var(--fs-xs);
}
.gloss-meta code {
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  color: var(--ink-3);
  background: var(--bg-deep);
  border: 1px solid var(--rule-soft);
  padding: 1px 6px;
}
.gloss-meta a { font-size: var(--fs-xs); }

/* ============== scrollbars ============== */

* { scrollbar-width: thin; scrollbar-color: var(--rule-strong) transparent; }
*::-webkit-scrollbar { width: 10px; height: 10px; }
*::-webkit-scrollbar-thumb {
  background: var(--rule-strong);
  border: 2px solid transparent;
  background-clip: content-box;
}
*::-webkit-scrollbar-thumb:hover { background-color: rgba(220, 234, 246, 0.32); background-clip: content-box; }
*::-webkit-scrollbar-track { background: transparent; }

/* ============== login page ============== */
/* The one screen that renders BEFORE the session gate. It is a standalone page
   (templates/login.html), so nothing here shares a selector with the in-panel
   layout, and the desktop panel is unaffected by this section. */

.login-body {
  display: block;
  background: var(--bg);
}
.login-wrap {
  min-height: 100dvh;
  display: grid;
  place-items: center;
  padding: var(--sp-6) var(--sp-4);
}
.login-card {
  position: relative;
  width: min(420px, 100%);
  background: var(--surface);
  border: 1px solid var(--rule-strong);
  padding: var(--sp-7) var(--sp-6) var(--sp-6);
}
/* the card's own accent rule: a solid 3px bar, top-left aligned — an instrument
   bezel, not a glow that fades out of existence at the edges */
.login-card::before {
  content: "";
  position: absolute;
  top: -1px; left: -1px; width: 76px; height: 3px;
  background: var(--accent);
}
.login-head { display: flex; flex-direction: column; gap: 4px; margin-bottom: var(--sp-5); }
.login-head .brand-mark svg { width: 34px; height: 34px; padding: 8px; }
.login-head .brand-mark { font-size: var(--fs-lg); }
.login-head .brand-sub { margin-left: 44px; }
.login-title {
  margin: 0 0 var(--sp-4);
  font-family: var(--font-display);
  font-size: var(--fs-lg);
  font-weight: 600;
  letter-spacing: -0.02em;
  color: var(--ink-value);
}
.login-error { margin-bottom: var(--sp-4); }
.login-form { display: flex; flex-direction: column; gap: var(--sp-3); }
.login-field { display: flex; flex-direction: column; gap: 6px; }
.login-label {
  font-size: var(--fs-2xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--ink-3);
}
.login-form input {
  min-height: var(--tap);
  padding: 8px 12px;
  font: inherit;
  color: var(--ink-value);
  background: var(--bg-deep);
  border: 1px solid var(--rule-strong);
  border-radius: var(--radius-sm);
  transition: border-color var(--dur-1) var(--ease), box-shadow var(--dur-1) var(--ease);
}
.login-form input:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 1px var(--accent);
}
.login-submit {
  margin-top: var(--sp-2);
  min-height: var(--tap);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 8px 16px;
  font: inherit;
  font-weight: 650;
  letter-spacing: 0.02em;
  color: #04120f;
  background: var(--accent);
  border: 1px solid var(--accent);
  border-radius: var(--radius-sm);
  cursor: pointer;
  transition: background var(--dur-1) var(--ease), transform var(--dur-1) var(--ease);
}
.login-submit:hover { background: var(--accent-ink); }
.login-submit:active { transform: translateY(1px); }
.login-submit:focus-visible { outline: none; box-shadow: var(--ring); }
.login-submit svg { flex: 0 0 16px; }
.login-note {
  margin: var(--sp-4) 0 0;
  font-size: var(--fs-sm);
  color: var(--ink-2);
  line-height: var(--lh);
  padding-top: var(--sp-3);
  border-top: 1px solid var(--rule);
}
.login-note b { color: var(--ink); }

/* ============== logout (rail / drawer foot) ============== */
.logout-form { display: flex; width: 100%; }
.logout-btn {
  flex: 1;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  min-height: 36px;
  padding: 6px 10px;
  font: inherit;
  font-size: var(--fs-sm);
  font-weight: 500;
  color: var(--ink-2);
  background: var(--surface-2);
  border: 1px solid var(--rule);
  border-radius: var(--radius-sm);
  cursor: pointer;
  transition: background var(--dur-1) var(--ease), color var(--dur-1) var(--ease),
    border-color var(--dur-1) var(--ease);
}
.logout-btn:hover { background: var(--surface-3); color: var(--ink); border-color: var(--rule-strong); }
.logout-btn:focus-visible { outline: none; box-shadow: var(--ring); }
.logout-btn svg { flex: 0 0 16px; }

/* ============== PWA install (rail / drawer foot) ============== */
/* Hidden until the browser offers installation (dashboard.js); styled like the
   logout button so the foot reads as one group of quiet actions. */
.pwa-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  width: 100%;
  margin-bottom: 8px;
  min-height: 36px;
  padding: 6px 10px;
  font: inherit;
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--accent-ink);
  background: var(--surface-2);
  border: 1px solid var(--accent-rule);
  border-radius: var(--radius-sm);
  cursor: pointer;
  transition: background var(--dur-1) var(--ease), color var(--dur-1) var(--ease),
    border-color var(--dur-1) var(--ease);
}
.pwa-btn[hidden] { display: none; }
.pwa-btn:hover { background: var(--accent-weak); border-color: var(--accent); }
.pwa-btn:focus-visible { outline: none; box-shadow: var(--ring); }
.pwa-btn svg { flex: 0 0 16px; }

/* "girişe dön": the link the frozen (401) poll banner offers the operator */
.banner-goto {
  color: var(--accent-ink);
  font-weight: 600;
  white-space: nowrap;
  text-decoration: underline;
}

/* ============== settings anchors ============== */
/* The settings page is thirteen kv walls; the only cure that costs no script is
   an index that jumps, plus a marked "this one can cost money" section. */
.settings-index {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-bottom: var(--sp-5);
  padding-bottom: var(--sp-3);
  border-bottom: 1px solid var(--rule);
}
.settings-index a {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 5px 9px;
  border: 1px solid var(--rule);
  border-radius: var(--radius-sm);
  font-size: var(--fs-2xs);
  font-weight: 600;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--ink-2);
}
.settings-index a:hover { color: var(--ink-value); background: var(--surface-2); border-color: var(--rule-strong); }
.settings-index a.key { color: var(--warn-ink); border-color: var(--warn-rule); background: var(--warn-weak); }
/* Çapa payı barın GERÇEK yüksekliğinden: etiketler uzayınca bar iki satıra kırılıyor
   (83px) ve sabit 54px pay başlığın 29px'ini barın altında bırakıyordu (ölçüm
   2026-09-12). `--topbar-measured` yalnız burada kullanılır; bar kendi ölçümüne
   kilitlenmesin diye düzene yazılmaz. Telefon bloğu bunu sıfırlar (üst şerit yok). */
.panel[id] { scroll-margin-top: calc(var(--topbar-measured, var(--topbar-h)) + var(--sp-4)); }
.risk-flag {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  margin-left: 8px;
  padding: 2px 7px;
  border: 1px solid var(--warn-rule);
  background: var(--warn-weak);
  color: var(--warn-ink);
  border-radius: var(--radius-sm);
  font-family: var(--font-ui);
  font-size: var(--fs-2xs);
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}
.risk-flag svg { width: 12px; height: 12px; }

@media (max-width: 1089px) {
  .login-wrap { padding: var(--sp-4); }
  .logout-btn, .pwa-btn { min-height: var(--tap); }
}
@media (max-width: 480px) {
  .login-wrap { padding: var(--sp-3); }
  .login-card { padding: var(--sp-6) var(--sp-5) var(--sp-5); }
}

/* ========================= telefon override'lari (dosya sonu) =========================
   Bu blok BILEREK dosyanin en sonunda duruyor. Eşit özgünlükte iki kuraldan dosyada
   sonra gelen kazanır; bu yüzünden `.gloss-row`'un tek kolonluk mobil kuralı yazıldığı
   günden beri ölü koddu - rehber bölümündeki üst-seviye `210px 1fr` tanımı onu eziyordu
   - ve /guide'da belgenin 61px yana taşmasına yol açıyordu (390px'te ölçüldü: `dd`
   hücresi 259..441 px'e taşıyordu). Bileşim bölümlerinden SONRA yazilmayan mobil
   override calismaz; yeni telefon kurali buraya eklenir.
   Tarayici: ayni secici hem burada hem ileride tanimlaniyorsa kural ölüdür. */
@media (max-width: 760px) {
  /* Terim rehberi tek kolona iner. Iki kolonda kalsaydi 390px'te açıklama hücresi
     ~90px'e düşer, Türkçe cümle okunamaz hale gelirdi. */
  .gloss-row {
    grid-template-columns: 1fr;
    gap: var(--sp-2);
  }
  /* Izgara cocugunun varsayilan `min-width: auto`'su, kirilmayan en uzun parcanin
     genisligini izgaraya dayatir: `bot_capital_limit_usdt` gibi tek kelime mobilde
     belgenin kendisini genişletiyordu. */
  .gloss-row dt,
  .gloss-row dd {
    min-width: 0;
  }
  .gloss-meta code {
    overflow-wrap: anywhere;
  }
  /* Adim listesi: baslik + aciklama tek sütuna iner, numara rozeti yerinde kalir */
  .guide-flow li {
    grid-template-columns: 26px 1fr;
  }
  .guide-flow li > span {
    grid-column: 2;
  }
  .settings-index a {
    min-height: var(--tap);
  }
  /* Giriş etiketi: giriş sayfasının bileşim tanımı dosyada bu bloğun ilerisinde
     duruyor, o yüzden takip düzeltmesi burada olmak zorunda. */
  .login-label {
    letter-spacing: 0.08em;
  }
  /* 16px'in altındaki alan yazısı iOS'ta odakta sayfa yakınlaştırmasına yol açar ve
     Zoom bir kez gelince bir daha gitmez. `font: inherit` girdiye 15px veriyordu; bu
     kural da bileşim tanımının ilerisinde durmak zorunda, çünkü `font` kısaltması
     `font-size`'ı ezer (test_web_mobile bunu shorthand bilgisiyle tarıyor). */
  .login-form input,
  .filters input,
  .cmd-body input,
  .page-search-input {
    font-size: 16px;
  }
  /* Adım listesi satır aralığı (mobil padding üst-seviye tanımca gölgeleniyordu) */
  .guide-flow li {
    padding: var(--sp-3) 0;
  }
  /* Arama kutusu klavyenin üstünde kalsın: filtrelenmiş uzun listede aşağı
     kaydıran operatör sayacı ve kutuyu kaybetmesin. `top` sıfır: telefonda üst şerit
     yok (2026-09-11), kutu ekranın kendi kenarına yapışır. */
  .page-search {
    position: sticky;
    top: 0;
    z-index: var(--z-th);
    background: var(--bg);
    padding: var(--sp-2) 0;
    margin-bottom: var(--sp-2);
  }
  /* Çapa sıçraması: `--topbar-h` payı artık havada kalacak bir şerit içindi. */
  .panel[id] {
    scroll-margin-top: var(--sp-4);
  }
}
