/* AIOR Vision console — dark glass theme.
 *
 * Two rules govern this file.  First, every colour lives in a custom property:
 * the previous revision had 28 literals scattered through it and a retheme
 * missed most of them.  Second, the glass effect must degrade: browsers without
 * backdrop-filter still get an opaque panel, so the console stays readable
 * rather than turning into unreadable translucent text.
 */

@font-face {
  font-family: "Play";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/assets/console/fonts/play-400-latin-ext.woff2") format("woff2");
  /* Turkish needs latin-ext: ç ğ ı İ ö ş ü all live in this range. */
  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;
}
@font-face {
  font-family: "Play";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/assets/console/fonts/play-400-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Play";
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url("/assets/console/fonts/play-700-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;
}
@font-face {
  font-family: "Play";
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url("/assets/console/fonts/play-700-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}

/* Palette, radii, shadows and glass recipe taken verbatim from the AIOR site
 * theme (aior-theme.css) so the console and aior.com are the same product
 * visually.  Light is the base and dark is an override, matching upstream.
 *
 * Theme selection follows the operating system by default and can be pinned
 * from the header.  The pin is expressed as [data-theme] on <html>, which is
 * why every dark rule is written twice: once for the OS preference and once
 * for the explicit choice.  Keeping both means a user who prefers dark at the
 * OS level can still pin light here, which a media query alone cannot do.
 */
:root {
  color-scheme: light dark;

  --bg:        #ffffff;
  --bg-soft:   #f1f4f9;
  --bg-sunken: #e6eaf1;
  --bg-tinted: #ecf0f6;

  --fg:        #0a0e1a;
  --fg-soft:   #1a1f2e;
  --fg-muted:  #6b7280;
  --fg-faint:  #9ca3af;

  --line:        #dde2eb;
  --line-strong: #c4cad3;
  --hair:        rgba(0, 0, 0, .06);

  --accent:      #1da1f2;
  --accent-deep: #0d7fc2;
  --accent-soft: #d8eefd;
  --accent-tint: rgba(29, 161, 242, .10);
  --accent-ring: rgba(29, 161, 242, .35);

  /* aior.com resolves --ok to the accent rather than a green, and its only
     amber is a --warn the console does not need: nothing here is a hazard
     except the physical relay, which is red.  "Needs attention" is therefore a
     quiet neutral chip, not an orange one. */
  --notice: #475569;
  --notice-soft: rgba(71, 85, 105, .10);
  --crit: #dc2626;
  --ok:   var(--accent);

  --glass-bg: color-mix(in srgb, var(--bg) 84%, transparent);
  --glass-border: color-mix(in srgb, #ffffff 52%, var(--line));
  --glass-shadow:
    0 1px 1px rgba(15, 23, 42, .03),
    0 10px 32px -12px rgba(15, 23, 42, .14),
    inset 0 1px 0 rgba(255, 255, 255, .78);
  --glass-rim: inset 0 1px 0 rgba(255, 255, 255, .78);
  --blur: blur(16px) saturate(150%);

  --r-md: 10px;
  --r-lg: 14px;
  --r-xl: 18px;
  --r-2xl: 22px;
  --r-pill: 999px;

  --sh-md: 0 4px 12px rgba(15, 23, 42, .06);
  --sh-lg: 0 12px 28px -4px rgba(15, 23, 42, .10);

  --glow-a: rgba(29, 161, 242, .10);
  --glow-b: rgba(29, 161, 242, .06);
  --row-hover: rgba(15, 23, 42, .035);
  --field-bg: var(--bg);
  --rail: 248px;

  /* Console-local aliases so the rules below read in domain terms. */
  --ink: var(--fg);
  --muted: var(--fg-muted);
  --faint: var(--fg-faint);
  --glass: var(--glass-bg);
  --glass-strong: var(--bg-soft);
  --glass-line: var(--line);
  --glass-line-soft: var(--hair);
  --panel: var(--glass-bg);
  --blue: var(--accent);
  --blue-deep: var(--accent-deep);
  --blue-soft: var(--accent-tint);
  --green: var(--ok);
  --green-soft: var(--accent-tint);
  --amber: var(--notice);
  --amber-soft: var(--notice-soft);
  --red: var(--crit);
  --red-soft: rgba(220, 38, 38, .10);
  --shadow: var(--glass-shadow);
  --radius: var(--r-xl);
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    color-scheme: dark;

    --bg:        #1c1c1c;
    --bg-soft:   #2a2a2a;
    --bg-sunken: #161616;
    --bg-tinted: #2a2a2a;

    --fg:        #f7f8f9;
    --fg-soft:   #d4d6da;
    --fg-muted:  #9aa0aa;
    --fg-faint:  #6b7280;

    --line:        #2a2f38;
    --line-strong: #3a3f48;
    --hair:        rgba(255, 255, 255, .06);

    --accent-soft: rgba(29, 161, 242, .18);
    --accent-tint: rgba(29, 161, 242, .14);
    --accent-ring: rgba(29, 161, 242, .50);

    --notice: #9aa0aa;
    --notice-soft: rgba(154, 160, 170, .14);
    --crit: #ef4444;
    --ok:   var(--accent);

    --glass-bg: color-mix(in srgb, var(--bg-soft) 80%, transparent);
    --glass-border: color-mix(in srgb, #ffffff 11%, var(--line));
    --glass-shadow:
      0 1px 2px rgba(0, 0, 0, .42),
      0 14px 36px -12px rgba(0, 0, 0, .58),
      inset 0 1px 0 rgba(255, 255, 255, .08);
    --glass-rim: inset 0 1px 0 rgba(255, 255, 255, .08);

    --sh-md: 0 4px 14px rgba(0, 0, 0, .45);
    --sh-lg: 0 12px 28px -4px rgba(0, 0, 0, .55);

    --glow-a: rgba(29, 161, 242, .16);
    --glow-b: rgba(29, 161, 242, .10);
    --row-hover: rgba(255, 255, 255, .035);
    --field-bg: rgba(0, 0, 0, .28);

    --glass-strong: color-mix(in srgb, var(--bg-soft) 92%, transparent);
    --green-soft: var(--accent-tint);
    --amber-soft: var(--notice-soft);
    --red-soft: rgba(239, 68, 68, .16);
  }
}

:root[data-theme="dark"] {
  color-scheme: dark;

  --bg:        #1c1c1c;
  --bg-soft:   #2a2a2a;
  --bg-sunken: #161616;
  --bg-tinted: #2a2a2a;

  --fg:        #f7f8f9;
  --fg-soft:   #d4d6da;
  --fg-muted:  #9aa0aa;
  --fg-faint:  #6b7280;

  --line:        #2a2f38;
  --line-strong: #3a3f48;
  --hair:        rgba(255, 255, 255, .06);

  --accent-soft: rgba(29, 161, 242, .18);
  --accent-tint: rgba(29, 161, 242, .14);
  --accent-ring: rgba(29, 161, 242, .50);

  --notice: #9aa0aa;
  --notice-soft: rgba(154, 160, 170, .14);
  --crit: #ef4444;
  --ok:   var(--accent);

  --glass-bg: color-mix(in srgb, var(--bg-soft) 80%, transparent);
  --glass-border: color-mix(in srgb, #ffffff 11%, var(--line));
  --glass-shadow:
    0 1px 2px rgba(0, 0, 0, .42),
    0 14px 36px -12px rgba(0, 0, 0, .58),
    inset 0 1px 0 rgba(255, 255, 255, .08);
  --glass-rim: inset 0 1px 0 rgba(255, 255, 255, .08);

  --sh-md: 0 4px 14px rgba(0, 0, 0, .45);
  --sh-lg: 0 12px 28px -4px rgba(0, 0, 0, .55);

  --glow-a: rgba(29, 161, 242, .16);
  --glow-b: rgba(29, 161, 242, .10);
  --row-hover: rgba(255, 255, 255, .035);
  --field-bg: rgba(0, 0, 0, .28);

  --glass-strong: color-mix(in srgb, var(--bg-soft) 92%, transparent);
  --green-soft: var(--accent-tint);
  --amber-soft: var(--notice-soft);
  --red-soft: rgba(239, 68, 68, .16);
}

* { box-sizing: border-box; }

/* The user-agent rule for [hidden] is display:none at the lowest priority, so
 * any class here that sets display outranks it and the element stays on
 * screen.  That is how view switching appeared to do nothing: .metrics and
 * .grid are display:grid, so those sections ignored being hidden while plain
 * panels obeyed.  One rule, stated once, instead of a per-component patch. */
[hidden] { display: none !important; }

/* clip: hidden'in aksine kaydirma kabi YARATMAZ; mobildeki salinim bundandi. */
html {
  overflow-x: clip;
  /* iOS SAFARI YATAY MODDA YAZIYI KENDILIGINDEN BUYUTUR ve kart icerigi
     kabini asar. Kullanicinin "Safari mobilde kartlar hala tek tip degil"
     sikayetinin en yayginlarindan biri budur. */
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
}

body {
  margin: 0;
  min-height: 100vh;
  max-width: 100%;
  color: var(--ink);
  background:
    radial-gradient(1100px 620px at 12% -8%, var(--glow-a), transparent 62%),
    radial-gradient(900px 560px at 92% 4%, var(--glow-b), transparent 60%),
    var(--bg-sunken);
  background-attachment: fixed;
  font-family: "Play", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  -webkit-font-smoothing: antialiased;
}

button, input, select { font: inherit; }

button {
  border: 0;
  border-radius: 11px;
  padding: .72rem 1.05rem;
  color: #ffffff;
  background: linear-gradient(180deg, var(--blue) 0%, var(--blue-deep) 100%);
  box-shadow: 0 6px 18px color-mix(in srgb, var(--accent) 32%, transparent), var(--glass-rim);
  cursor: pointer;
  font-weight: 700;
  /* Comfortable on a phone without changing the desktop rhythm. */
  min-height: 44px;
}

button:hover { filter: brightness(1.08); }
button:active { transform: translateY(1px); }
button:disabled { cursor: not-allowed; opacity: .45; box-shadow: none; }
button:focus-visible, a:focus-visible { outline: 2px solid var(--blue); outline-offset: 2px; }

/* Shell: a fixed navigation rail beside a scrolling content column.  Below
   1000px the rail leaves the flow and becomes an off-canvas drawer, so the
   same markup serves the desk and the phone. */
.shell { display: grid; grid-template-columns: var(--rail) 1fr; min-height: 100vh; }
.content { min-width: 0; display: flex; flex-direction: column; }

.sidebar {
  position: sticky;
  top: 0;
  align-self: start;
  height: 100vh;
  display: flex;
  flex-direction: column;
  gap: 1.25rem;
  padding: 1.25rem 1rem;
  border-right: 1px solid var(--line);
  background: var(--bg);
  overflow-x: hidden;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
}

.sidebar-brand { display: flex; align-items: center; padding: .35rem .5rem 0; }
.sidebar-brand .brand-home { display: inline-flex; align-items: center; text-decoration: none; }
.sidebar-brand .brand-mark { height: 30px; width: auto; }

.sidebar-foot {
  margin-top: auto;
  display: flex;
  flex-direction: column;
  gap: .5rem;
  padding-top: 1rem;
  border-top: 1px solid var(--line);
}
.sidebar-foot .pill { text-align: center; }

.nav-scrim { display: none; }

/* Signed out there is nothing to navigate to, so the rail and the section
   heading step aside and the sign-in card gets the whole width. */
.shell.signed-out { grid-template-columns: 1fr; }
.shell.signed-out .sidebar,
.shell.signed-out .topbar { display: none; }

.topbar {
  position: sticky;
  top: 0;
  z-index: 15;
  display: flex;
  align-items: center;
  gap: 1rem;
  padding: .95rem clamp(1rem, 3vw, 2.25rem);
  border-bottom: 1px solid var(--line);
  background: color-mix(in srgb, var(--bg) 88%, transparent);
  backdrop-filter: var(--blur);
  -webkit-backdrop-filter: var(--blur);
}
.page-title { min-width: 0; }
.kepenk-bar {
  display: flex;
  flex-wrap: wrap;
  gap: .4rem;
  align-items: center;
  flex: none;
  margin-left: auto;
}
.kepenk-bar form { margin: 0; }
.kepenk-bar button {
  min-height: 38px;
  padding: .35rem .85rem;
  font-weight: 650;
  letter-spacing: .02em;
  border-radius: var(--r-md);
  cursor: pointer;
  -webkit-appearance: none;
  appearance: none;
}
.kepenk-bar .kepenk-ac {
  background: color-mix(in srgb, var(--accent, #0d7fc2) 88%, #0a0e1a);
  color: #fff;
  border: 1px solid color-mix(in srgb, var(--accent, #0d7fc2) 60%, transparent);
}
.kepenk-bar .kepenk-kapa {
  background: color-mix(in srgb, var(--crit, #c44) 80%, #0a0e1a);
  color: #fff;
  border: 1px solid color-mix(in srgb, var(--crit, #c44) 50%, transparent);
}
.page-title h1 { font-size: clamp(1.05rem, 1.8vw, 1.4rem); }

.icon-button {
  display: none;
  flex: none;
  width: 42px;
  height: 42px;
  padding: 0;
  place-items: center;
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  color: var(--ink);
  background: var(--bg-soft);
  box-shadow: none;
  -webkit-appearance: none;
  appearance: none;
  touch-action: manipulation;
}
.icon-button svg { width: 20px; height: 20px; fill: none; stroke: currentColor; stroke-width: 1.9; stroke-linecap: round; }
.icon-button:hover { background: var(--bg-tinted); filter: none; }

.brand { display: flex; align-items: center; gap: 1rem; min-width: 0; }
/* Two supplied variants: the wordmark is white on dark and near-black on
   light, so the theme picks the file rather than trying to tint a bitmap. */
.brand-mark { flex: none; height: 34px; width: auto; }
.brand-dark { display: none; }
.brand-light { display: block; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .brand-dark { display: block; }
  :root:not([data-theme="light"]) .brand-light { display: none; }
}
:root[data-theme="dark"] .brand-dark { display: block; }
:root[data-theme="dark"] .brand-light { display: none; }
.brand-text { min-width: 0; }

h1, h2, p { margin-top: 0; }
h1 { margin-bottom: 0; font-size: clamp(1.1rem, 2.2vw, 1.6rem); letter-spacing: .01em; }
h2 { margin-bottom: 0; font-size: 1.12rem; }

.eyebrow {
  margin-bottom: .3rem;
  color: var(--blue);
  font-size: .68rem;
  font-weight: 700;
  letter-spacing: .16em;
}

main {
  width: min(1480px, 100%);
  padding: 1.5rem clamp(1rem, 3vw, 2.25rem) 4rem;
  margin: 0 auto;
}

.mainnav { display: flex; flex-direction: column; gap: .2rem; }
.mainnav[hidden] { display: none; }

.navlink {
  display: flex;
  align-items: center;
  gap: .75rem;
  width: 100%;
  min-height: 44px;
  padding: .6rem .8rem;
  border: 0;
  border-radius: var(--r-md);
  color: var(--muted);
  background: transparent;
  box-shadow: none;
  font-size: .88rem;
  font-weight: 600;
  text-align: left;
}
.navlink svg {
  flex: none;
  width: 19px;
  height: 19px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.7;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.navlink:hover { color: var(--ink); background: var(--bg-tinted); filter: none; }
.navlink.active {
  color: var(--accent);
  background: var(--accent-tint);
  font-weight: 700;
  box-shadow: inset 2px 0 0 var(--accent);
}
.navlink.active:hover { color: var(--accent); background: var(--accent-tint); }

.status-row { display: flex; flex-wrap: wrap; gap: .55rem; align-items: center; }
/* The search box and its refresh button belong on one line; letting them wrap
   pushed the button onto its own row and split the panel heading in two. */
.filters { display: flex; flex-wrap: nowrap; gap: .55rem; align-items: center; }
.filters > button { flex: none; }
.search { min-width: 15rem; }

/* A list narrowed by a metric click must say so, and offer the way back.
   A filtered table that looks unfiltered reads as missing data. */
.scope-notice {
  display: flex;
  align-items: center;
  gap: .75rem;
  flex-wrap: wrap;
  margin: 0 0 .9rem;
  padding: .6rem .85rem;
  border: 1px solid var(--glass-line);
  border-left: 3px solid var(--accent);
  border-radius: var(--r-md);
  background: var(--bg-soft);
  color: var(--muted);
  font-size: .82rem;
}
.scope-notice[hidden] { display: none; }

.pill {
  border: 1px solid var(--glass-line);
  border-radius: 999px;
  padding: .46rem .8rem;
  font-size: .76rem;
  font-weight: 700;
}
.pill.safe { color: var(--accent); background: var(--accent-tint); border-color: var(--accent-ring); }
.pill.danger { color: var(--crit); background: var(--red-soft); border-color: color-mix(in srgb, var(--crit) 45%, transparent); }
.pill.notice { color: var(--muted); background: var(--notice-soft); border-color: var(--line); }
.pill.neutral { color: var(--muted); background: var(--glass); }

/* SON SATIR DA DOLAR.
   Kullanici (07.09.2026, birebir): "Bos alan garip sekilde tugla cikarilmis gibi
   istatistik vs gormek istemiyorum ... Bosluk alanlari doldur. Simetrik duzenli."
   grid ile son satirda eksik kart kalinca ekranda DELIK goruluyordu. flex ile
   kartlar satiri paylasir: dolu satirlarda dortlu duzen aynen korunur (temel
   genislik %25), eksik son satirda kalan kartlar buyuyup bosluğu doldurur.
   Delik birakmak yerine satiri doldurmak, "eksik tugla" gorunumunu tumden
   ortadan kaldirir. */
.metrics {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem;
  margin-bottom: 1rem;
}
.metrics > * {
  flex: 1 1 calc(25% - .75rem);
  min-width: 13rem;
}

/* Each figure is a button: every one of them answers "which vehicles?", and
   the answer is a list the console already shows.  Making them look like
   cards but behave like links is the wrong half of both. */
.metrics .metric {
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: center;
  gap: .1rem .8rem;
  width: 100%;
  padding: 1rem 1.15rem;
  border: 1px solid var(--glass-line);
  border-radius: var(--radius);
  color: var(--ink);
  background: var(--glass);
  backdrop-filter: var(--blur);
  -webkit-backdrop-filter: var(--blur);
  box-shadow: var(--glass-rim);
  text-align: left;
  cursor: pointer;
}
.metrics .metric:hover {
  border-color: var(--accent-ring);
  background: var(--bg-tinted);
  filter: none;
}
.metrics .metric:active { transform: translateY(1px); }

.metrics span { color: var(--muted); font-size: .84rem; font-weight: 600; }
.metrics strong {
  grid-row: 1 / span 2;
  grid-column: 2;
  align-self: center;
  font-size: 1.75rem;
  font-weight: 700;
  letter-spacing: -.01em;
}
.metrics em {
  grid-column: 1;
  color: var(--faint);
  font-size: .74rem;
  font-style: normal;
  line-height: 1.35;
}
.sayac-panel {
  margin: 0 0 1rem;
  padding: .85rem 1rem;
  max-height: 22rem;
  overflow: auto;
}
.sayac-panel[hidden] { display: none !important; }
.sayac-panel-ust {
  position: sticky;
  top: 0;
  z-index: 2;
  background: var(--bg-soft);
  margin: -.15rem 0 .35rem;
  padding: .15rem 0 .2rem;
}
.sayac-arama {
  width: 100%;
  min-width: 0;
  margin: 0;
}
.sayac-bos { margin: .35rem 0 0; font-size: .85rem; }

/* Operational counters, below the fleet figures and visually quieter. */
.metrics-secondary { margin-bottom: 1.25rem; }
.metric-quiet { padding: .7rem 1rem; }
.metric-quiet strong { font-size: 1.25rem; }

.grid { display: grid; gap: 1rem; }
/* TEK SUTUN. Izgara iki 'track' tanimliyordu ama section'in TEK cocugu var
   (div.grid-col); ikinci track minmax tabani geregi en az 280px yer kaplamaya
   devam ediyor ve 900px ustundeki HER masaustu genisliginde sagda bostu
   (1920px'te 418px, 1440px'te 331px). Veriye bagli degil, yapisaldi: ucluk
   kart bu izgaradan sayfanin en ustune tasinirken sutun sayisi 2'de kalmis.
   position/z-index KORUNUR: .plate-entry-panel'in z-index yigini buna dayaniyor. */
.primary-grid { grid-template-columns: minmax(0, 1fr); position: relative; z-index: 1; }

.panel {
  margin-bottom: 1rem;
  padding: 1.25rem;
  border: 1px solid var(--glass-line);
  border-radius: var(--radius);
  background: var(--glass);
  backdrop-filter: var(--blur);
  -webkit-backdrop-filter: var(--blur);
  box-shadow: var(--shadow), var(--glass-rim);
}

.plate-entry-panel {
  position: relative;
  z-index: 50;
  overflow: visible;
}
.admin-grid { grid-template-columns: 1.2fr .8fr; }

/* BASLIK SATIRI: baslik + rozetler SOLDA toplanir, eylem baglantisi SAGA
   itilir. Eskiden 'space-between' idi ve DORT ogeyi tum genislige esit
   dagitiyordu: genis ekranda rozetler basliktan yuzlerce piksel uzaga
   dusuyor, aralarinda anlamsiz bosluklar kaliyordu (07.09.2026 kullanici
   bildirimi: "hala ustte bosluk alanlar var").
   Iki ogeli basliklarda davranis space-between ile AYNI kalir. */
.panel-heading {
  display: flex;
  align-items: center;
  justify-content: flex-start;
  gap: .6rem;
  /* Wrap the whole filter block onto its own line rather than squeezing the
     search field until its placeholder is cut off. */
  flex-wrap: wrap;
  margin-bottom: 1rem;
}
/* :not(:first-child) SART.
   Flexbox'ta auto margin, justify-content'ten ONCE tum artik alani yutar.
   Baslikta TEK cocuk varsa o cocuk ayni zamanda :last-child'dir; artik alanin
   tamami margin-left'e gider ve SAGA itilen sey eylem baglantisi degil,
   BASLIGIN KENDISI olur. Olculdu: 40 panel basliginin 20'si tek cocuklu. */
.panel-heading > *:last-child:not(:first-child) { margin-left: auto; }
/* Baslik blogu (eyebrow + h2) rozetlerden biraz ayrilsin. */
.panel-heading > div:first-child { margin-right: .4rem; }

.secondary {
  color: var(--ink);
  background: var(--glass-strong);
  border: 1px solid var(--glass-line);
  box-shadow: var(--glass-rim);
}
.secondary:hover { background: var(--bg-tinted); filter: none; }

.plate-suggest-wrap { position: relative; }
.plate-suggest {
  position: absolute;
  z-index: 80;
  left: 0;
  right: 0;
  top: calc(100% + 4px);
  margin: 0;
  padding: .25rem;
  list-style: none;
  max-height: 240px;
  overflow: auto;
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--bg);
  box-shadow: var(--sh-lg);
}
.plate-suggest button {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: .1rem;
  width: 100%;
  min-height: 44px;
  padding: .45rem .65rem;
  color: var(--ink);
  background: transparent;
  box-shadow: none;
  font-weight: 700;
  text-align: left;
}
.plate-suggest button:hover { background: var(--accent-tint); filter: none; }
.plate-suggest .meta { color: var(--muted); font-size: .78rem; font-weight: 500; }

.dir-learn {
  display: flex;
  flex-wrap: wrap;
  gap: .5rem;
  margin: .75rem 0 0;
}
.dir-learn .dir-on { pointer-events: none; }

.danger-outline {
  color: var(--ink);
  background: transparent;
  border: 1px solid var(--line-strong);
  box-shadow: none;
}
.danger-outline:hover { background: var(--bg-tinted); filter: none; }
/* Reserved for the one control that can physically open the barrier. */
.danger-outline.hazard { color: var(--crit); border-color: color-mix(in srgb, var(--crit) 55%, transparent); }
.danger-outline.hazard:hover { background: var(--red-soft); }

.metadata-mode {
  min-height: 160px;
  padding: 1.2rem;
  border: 1px solid var(--accent-ring);
  border-radius: 12px;
  background: linear-gradient(145deg, var(--accent-tint), transparent 70%);
}
.metadata-mode strong { display: block; margin-bottom: .7rem; color: var(--blue); font-size: 1.08rem; }
.metadata-mode p { margin: 0; color: var(--muted); line-height: 1.65; }
.metadata-caption { margin: .75rem 0 0; color: var(--faint); font-size: .84rem; }

.decision-card {
  display: grid;
  place-items: center;
  min-height: 190px;
  padding: 1rem;
  border: 1px solid var(--glass-line);
  border-radius: 12px;
  text-align: center;
}
.decision-card.waiting { background: var(--glass); }
.decision-card.allowed { background: var(--accent-tint); border-color: var(--accent-ring); }
.decision-card.denied { background: var(--red-soft); border-color: color-mix(in srgb, var(--crit) 45%, transparent); }
.decision-card.cikis-serbest { background: color-mix(in srgb, #0e7490 14%, transparent); border-color: color-mix(in srgb, #0e7490 45%, transparent); }
.decision-card.unread { background: var(--notice-soft); border-color: color-mix(in srgb, var(--notice) 45%, transparent); }
.decision-card span { font-size: .72rem; font-weight: 700; letter-spacing: .12em; }
.decision-card strong { font-size: clamp(1.9rem, 4vw, 3.3rem); letter-spacing: .03em; }
.decision-card p { margin-bottom: 0; color: var(--muted); }

.detail-list { margin: 1rem 0 0; }
.detail-list div {
  display: flex;
  justify-content: space-between;
  gap: 1rem;
  padding: .58rem 0;
  border-bottom: 1px solid var(--glass-line-soft);
}
.detail-list dt { color: var(--muted); }
.detail-list dd { margin: 0; font-weight: 700; text-align: right; }

.table-wrap { overflow-x: auto; }
table { width: 100%; border-collapse: collapse; white-space: nowrap; }
th, td {
  padding: .78rem .7rem;
  border-bottom: 1px solid var(--glass-line-soft);
  text-align: left;
  font-size: .86rem;
}
th { color: var(--faint); font-size: .7rem; letter-spacing: .06em; text-transform: uppercase; }
th[data-sort] { cursor: pointer; user-select: none; }
th[data-sort]:hover, th[data-sort]:focus-visible { color: var(--ink); }
/* Reserve the arrow's width on every sortable header so turning sorting on
   and off does not shift the column headings sideways. */
th[data-sort]::after { content: "↕"; margin-left: .35rem; opacity: .3; font-size: .8em; }
th[aria-sort="ascending"]::after { content: "▲"; opacity: 1; }
th[aria-sort="descending"]::after { content: "▼"; opacity: 1; }
th[aria-sort="ascending"], th[aria-sort="descending"] { color: var(--blue); }
tbody tr:hover { background: var(--row-hover); }
td.empty { padding: 2rem; color: var(--muted); text-align: center; }

.tag {
  display: inline-block;
  border-radius: var(--r-pill);
  padding: .27rem .6rem;
  font-size: .72rem;
  font-weight: 700;
  border: 1px solid transparent;
}
.tag.allowed { color: var(--accent); background: var(--accent-tint); border-color: var(--accent-ring); }
.tag.denied { color: var(--red); background: var(--red-soft); border-color: color-mix(in srgb, var(--crit) 40%, transparent); }
.tag.cikis-serbest { color: #0e7490; background: color-mix(in srgb, #0e7490 14%, transparent); border-color: color-mix(in srgb, #0e7490 40%, transparent); }
/* Neutral, not a warning colour: these mark "look at this", not "danger". */
.tag.other { color: var(--muted); background: var(--notice-soft); border-color: var(--line); }

input, select {
  width: 100%;
  min-height: 44px;
  /* iOS Safari input'lara kendi ic golgesini ve yuvarlakligini basar; ayni
     formdaki iki alan farkli gorunur. select BILEREK disarida: appearance
     sifirlanirsa yerel ok kaybolur. */
  -webkit-appearance: none;
  border: 1px solid var(--glass-line);
  border-radius: 10px;
  padding: .68rem .72rem;
  color: var(--ink);
  background: var(--field-bg);
}
/* Onay ve secim kutulari yukaridaki genel `input` kuralindan MUAF olmali.
   Yoksa tam genislikte, 44px yuksekliginde, koyu zeminli bir dikdortgen olarak
   ciziliyorlar ve karanlik panelde GORUNMEZ oluyorlar.
   `.check-row input` bunu zaten sifirliyordu, ama Ayarlar -> Rol gorunurlugu
   tablosundaki kutucuklar o sinifin disinda kaldigi icin gorunmuyordu (31.08.2026).
   Kural tur secicisiyle yazildi: nerede olursa olsun tum onay kutulari duzelir.

   CANLI 02.10.2026 (UX denetimi): eb63300 (06.09) yukaridaki genel kurala
   `-webkit-appearance: none` ekledi ve bu muafiyet onu GERI ALMIYORDU.
   Gorunumu sifirlanmis bir onay kutusunun kendi boyutu yoktur; ustune
   `width:auto` + `border:0` + `padding:0` gelince kutu 0x0 piksele iner.
   Chromium ve WebKit'te panelin TUM onay kutulari gorunmezdi: Daire ve plaka
   386, Rol gorunurlugu 47, Sistem'de bariyer_ajan_acik / direction_calibrated
   / camera_alert_enabled, Bildirimler 5, Siteler as_super, Ayarlar
   rotate_api_token, Loglar logOto. Etikete dokununca durum KOR degisiyordu.
   Yerel gorunum geri aliniyor ve kutuya sabit, dokunulabilir bir boyut
   veriliyor. Eski iOS 'auto' degerini tanimaz; ilk iki satir onun icin. */
input[type="checkbox"] { -webkit-appearance: checkbox; }
input[type="radio"] { -webkit-appearance: radio; }
input[type="checkbox"], input[type="radio"] {
  -webkit-appearance: auto;
  appearance: auto;
  flex: none;
  width: 1.25rem;
  height: 1.25rem;
  min-height: 0;
  padding: 0;
  border: 0;
  background: none;
  accent-color: var(--blue);
  vertical-align: middle;
  cursor: pointer;
}

input::placeholder { color: var(--faint); }
/* The native dark picker list is unreadable on some engines without this. */
select option { color: var(--ink); background: var(--deep); }

input:focus, select:focus {
  outline: 3px solid var(--blue-soft);
  border-color: var(--blue);
}

.form-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: .85rem; }
.form-grid label, .stack-form label { color: var(--muted); font-size: .78rem; font-weight: 700; }
.form-grid input, .form-grid select, .stack-form input, .stack-form select { margin-top: .28rem; }
.wide { grid-column: 1 / -1; }
.form-actions { display: flex; justify-content: flex-end; align-items: center; gap: 1rem; }
.form-actions span { flex: 1; color: var(--muted); }
.stack-form { display: grid; gap: .8rem; }
.check-row { display: flex; align-items: center; gap: .6rem; }
/* Genislik BURADA verilmez: ozgulluk tur kuralina esit ve dosyada sonra
   geldigi icin buradaki `width:auto` kutuyu yeniden 0 genislige indiriyordu. */
.check-row input { margin: 0; }
.help { color: var(--faint); font-size: .8rem; line-height: 1.55; }

/* Notices carry their weight in a left rule rather than a coloured field, so
   the page keeps one accent and does not turn into a traffic light. */
.banner-warning {
  margin: 0 auto 1rem;
  width: min(1480px, calc(100% - 2rem));
  padding: .85rem 1.1rem;
  border: 1px solid var(--glass-line);
  border-left: 3px solid var(--notice);
  border-radius: var(--r-md);
  background: var(--bg-soft);
  color: var(--ink);
  font-size: .85rem;
  line-height: 1.55;
}

.relay-lock {
  margin-top: 1rem;
  padding: 1rem;
  border: 1px solid var(--glass-line);
  border-left: 3px solid var(--notice);
  border-radius: var(--r-md);
  background: var(--bg-soft);
}
/* Turns red only while the relay is actually armed and the gate can open. */
.relay-lock.armed { border-left-color: var(--crit); background: var(--red-soft); }
.relay-lock p { color: var(--muted); font-size: .82rem; }
.search { width: min(360px, 100%); }
.notification-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.compact { margin-bottom: 1rem; }
.test-form { padding-top: .8rem; border-top: 1px solid var(--glass-line-soft); }
.contact-form {
  display: grid;
  grid-template-columns: minmax(180px, 1fr) minmax(220px, 1fr) auto auto auto;
  align-items: end;
  gap: .8rem;
  margin-bottom: 1rem;
}
.contact-form label { color: var(--muted); font-size: .78rem; font-weight: 700; }
.contact-form input { margin-top: .28rem; }
.contact-form .check-row { align-self: center; margin-top: 1.1rem; white-space: nowrap; }
.row-actions { display: flex; gap: .4rem; flex-wrap: wrap; }
/* --- BUTON YUZEYI: YAZI HER ZAMAN MERKEZDE ---------------------------- */
/* Kullanici (06.09.2026): "Cikis butonu yazisi sola kaymis, butonlar guzel,
   yazi merkezde olacak."
   SEBEP: <button> ogesinin tarayici varsayilani text-align:center'dir, ama
   panelin cikis dugmesi bir BAGLANTIDIR: <a class="secondary mini">Cikis</a>.
   .secondary yalnizca RENK veriyordu (satir 608) ve .mini kurali
   'button.mini' diye ELEMAN kapsamliydi -- ikisi de <a>'ya hicbir govde,
   dolgu ya da ortalama vermiyordu. Baglanti satir ici kalip sola yaslaniyordu.
   Artik buton gibi gorunen HER oge ayni govdeyi aliyor. */
button,
.btn,
.mini,
a.secondary,
input[type="submit"],
input[type="button"] {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  min-height: 44px;          /* iOS dokunma hedefi */
  box-sizing: border-box;
}
/* .mini eskiden 36px'ti; iOS'un 44px kuralinin altinda kaliyordu. */
.mini { padding: .4rem .8rem; font-size: .75rem; }
/* Oneri listesi kendi duzenini korur (cok satirli, sola yasli). */
.plate-suggest button { justify-content: flex-start; text-align: left; }
.consent-row { padding: .65rem; border-radius: 10px; background: var(--glass); }

#toast {
  position: fixed;
  right: 1.2rem;
  bottom: 1.2rem;
  z-index: 30;
  max-width: 360px;
  padding: .85rem 1rem;
  border: 1px solid var(--glass-line);
  border-radius: 12px;
  color: var(--ink);
  background: color-mix(in srgb, var(--bg) 94%, transparent);
  backdrop-filter: var(--blur);
  -webkit-backdrop-filter: var(--blur);
  box-shadow: var(--shadow);
  opacity: 0;
  transform: translateY(12px);
  pointer-events: none;
  transition: .2s ease;
}

#toast.show { opacity: 1; transform: translateY(0); }

/* ISLEM SONUCU BILDIRIMI (02.10.2026).
   POST'tan sonra form-position.js operatoru baktigi yere geri kaydiriyor;
   <main>'in basindaki mesaj o an ekranin binlerce piksel ustunde kaliyordu
   (olculdu: y = -12.213 px). Bildirim artik ekrana sabit: kaydirma onu
   etkilemez. Zemin OPAK — yari saydam zeminde alttaki tablo metni okunurdu.
   Ozgulluk iki sinif: admin/index.php'deki gomulu `.flash-msg` kurali
   styles.css'ten SONRA geliyor ve tek sinifla bunu ezerdi. */
.flash-msg.flash-toast {
  position: fixed;
  /* 38: telefon cekmecesinin (40) ve ortusunun (39) ALTINDA (F4). 60 iken
     bildirim acik cekmecenin "Cikis" dugmesini kapatiyordu. Yapiskan ust
     seridin (15) ve icerigin ustunde kalir. */
  z-index: 38;
  left: 50%;
  bottom: calc(1rem + env(safe-area-inset-bottom, 0px));
  transform: translateX(-50%);
  width: min(34rem, calc(100% - 1.5rem));
  max-height: 45vh;
  overflow-y: auto;
  margin: 0;
  display: flex;
  align-items: flex-start;
  gap: .35rem;
  padding: .3rem .3rem .3rem 1rem;
  border: 1px solid var(--accent-ring);
  border-left: 4px solid var(--accent);
  border-radius: var(--r-lg);
  color: var(--fg);
  background: color-mix(in srgb, var(--accent) 7%, var(--bg));
  box-shadow: var(--sh-lg);
}
.flash-msg.flash-toast.err {
  border-color: color-mix(in srgb, var(--crit) 45%, transparent);
  border-left-color: var(--crit);
  background: color-mix(in srgb, var(--crit) 7%, var(--bg));
}
/* Bilgi: hata degil (ornek: elle girilen plaka kaydedildi ama tanimli degil).
   Notr gri-mavi, kirmizi degil; kendiliginden kapanir (F4). */
.flash-msg.flash-toast.bilgi {
  border-color: color-mix(in srgb, var(--notice) 40%, transparent);
  border-left-color: var(--notice);
  background: color-mix(in srgb, var(--notice) 9%, var(--bg));
}
.flash-toast .flash-metin { flex: 1 1 auto; margin: 0; padding: .6rem 0; line-height: 1.45; font-weight: 600; }
.flash-toast .flash-kapat {
  flex: none;
  width: 44px;
  height: 44px;
  min-height: 44px;
  padding: 0;
  border-radius: var(--r-md);
  color: var(--muted);
  background: transparent;
  box-shadow: none;
  font-size: 1.5rem;
  line-height: 1;
}
.flash-toast .flash-kapat:hover { color: var(--fg); background: var(--bg-tinted); filter: none; }

/* Sign-in gate shown until a console session exists. */
.auth-gate {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 70vh;
  padding: clamp(1rem, 4vw, 3.5rem);
}

.auth-gate[hidden] { display: none; }

.auth-card {
  width: min(26rem, 100%);
  padding: 1.9rem;
  border: 1px solid var(--glass-line);
  border-radius: var(--radius);
  background: var(--glass);
  backdrop-filter: var(--blur);
  -webkit-backdrop-filter: var(--blur);
  box-shadow: var(--shadow), var(--glass-rim);
}

.auth-card h2 { margin-bottom: .35rem; }

.form-error {
  margin: 0;
  min-height: 1.2em;
  color: var(--red);
  font-size: .85rem;
  font-weight: 600;
}

#userChip { max-width: 16rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* Commissioning preview: guarded palette, distinct from ordinary panels. */
.live-view {
  margin-top: 1rem;
  padding: 1rem;
  border: 1px solid var(--glass-line);
  border-radius: var(--r-md);
  background: var(--bg-soft);
}

.live-view[hidden] { display: none; }

.live-view-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  margin-bottom: .7rem;
}

.live-view img {
  width: 100%;
  max-height: 360px;
  border-radius: 10px;
  background: #0b0f14;
  object-fit: contain;
}

.live-view img[hidden] { display: none; }

/* Keep the 1 s duration ticker from making the column jitter. */
td.duration { font-variant-numeric: tabular-nums; }

/* Commissioning-mode banner: the console is open because no account exists. */
.setup-banner {
  display: flex;
  flex-direction: column;
  gap: .35rem;
  margin-bottom: 1.25rem;
  padding: .95rem 1.15rem;
  border: 1px solid var(--glass-line);
  border-left: 3px solid var(--accent);
  border-radius: var(--r-md);
  background: var(--bg-soft);
  color: var(--ink);
  font-size: .88rem;
  line-height: 1.55;
}
.setup-banner strong { color: var(--accent); }
.setup-banner span { color: var(--muted); }

.setup-banner[hidden] { display: none; }

/* Lens aiming controls, shown only while a preview session is open. */
.lens-controls {
  display: flex;
  align-items: center;
  gap: .6rem;
  margin: .7rem 0;
  flex-wrap: wrap;
}

.lens-controls[hidden] { display: none; }
.lens-controls > span:first-child { font-weight: 700; font-size: .85rem; }

/* Unit editor.  Everything about one flat -- resident, phone, consent and all
   three plates -- is visible and editable on one surface, replacing a chain of
   window.prompt dialogs that made a two-field change take six confirmations. */
.editor {
  width: min(46rem, calc(100% - 1.5rem));
  max-height: 88vh;
  padding: 0;
  border: 1px solid var(--glass-line);
  border-radius: var(--r-xl);
  color: var(--ink);
  background: var(--bg);
  box-shadow: var(--sh-lg);
  overflow: hidden;
}
.editor::backdrop { background: rgba(0, 0, 0, .55); backdrop-filter: blur(3px); }
.editor[open] { display: flex; flex-direction: column; }
/* ICERIK KAYDIRILABILIR OLMALI.
   .editor 'max-height:88vh' + 'overflow:hidden' tasiyor. Icindeki form/govde
   kaydirilamazsa 88vh'yi asan her sey KIRPILIR ve en altta duran "Kaydet"
   dugmesine hicbir sekilde ulasilamaz (daire duzenleme penceresi: 8 alan +
   6 plaka + onay kutulari). Flex kolonunda 'overflow-y:auto' TEK BASINA
   yetmez: flex ogesi varsayilan olarak icerigin altina KUCULMEZ
   (min-height:auto), bu yuzden min-height:0 sart. */
.editor[open] > form,
.editor[open] > .editor-body { min-height: 0; overflow-y: auto; }

.editor-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 1.1rem 1.25rem;
  border-bottom: 1px solid var(--glass-line);
  background: var(--bg-soft);
}
.editor-head h2 { font-size: 1.15rem; }

.editor-body { padding: 1.25rem; overflow-y: auto; display: grid; gap: 1.5rem; }
.editor-section { display: grid; gap: .75rem; }
.editor-section h3 {
  margin: 0;
  font-size: .78rem;
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--faint);
}
.editor-section h3 .help { text-transform: none; letter-spacing: 0; font-weight: 400; }

.plate-list { display: grid; gap: .6rem; }
.plate-row {
  display: grid;
  grid-template-columns: 1fr auto auto;
  align-items: center;
  gap: .6rem;
  padding: .55rem .65rem;
  border: 1px solid var(--glass-line);
  border-radius: var(--r-md);
  background: var(--bg-soft);
}
.plate-row input { font-weight: 700; letter-spacing: .04em; }
.plate-row .plate-state { font-size: .72rem; white-space: nowrap; }
.plate-empty { color: var(--faint); font-size: .85rem; }
.plate-add { display: grid; grid-template-columns: 1fr auto; gap: .6rem; }

.editor-actions {
  display: flex;
  justify-content: flex-end;
  gap: .6rem;
  padding: 1rem 1.25rem;
  border-top: 1px solid var(--glass-line);
  background: var(--bg-soft);
}
#unitEditorMessage { padding: 0 1.25rem; }

@media (max-width: 700px) {
  .editor { width: calc(100% - 1rem); max-height: 92vh; }
  .plate-row { grid-template-columns: 1fr; }
  .plate-row .row-actions { justify-content: flex-start; }
  .plate-add { grid-template-columns: 1fr; }
}

/* Below this width the rail would eat the content, so it leaves the grid and
   slides in over it instead.  The drawer is translated rather than hidden so
   it animates, and stays keyboard-reachable only while open via [hidden]. */
@media (max-width: 1000px) {
  .shell { grid-template-columns: 1fr; }
  body { background-attachment: scroll; }
  body.nav-open { overflow: hidden; }
  .sidebar {
    position: fixed;
    inset: 0 auto 0 0;
    z-index: 40;
    width: min(280px, 84vw);
    height: 100%;
    height: 100dvh;
    transform: translateX(-102%);
    transition: transform .22s ease;
    box-shadow: var(--sh-lg);
    pointer-events: none;
    padding-top: max(1.25rem, env(safe-area-inset-top));
    padding-bottom: max(1.25rem, env(safe-area-inset-bottom));
  }
  /* JS historically toggled .open on the aside; CSS expected .nav-open on
     .shell.  Both selectors stay so a cache-stale sheet still opens. */
  .shell.nav-open .sidebar,
  .sidebar.open {
    transform: none;
    pointer-events: auto;
  }
  .nav-scrim {
    display: block;
    position: fixed;
    inset: 0;
    z-index: 39;
    background: rgba(0, 0, 0, .45);
  }
  .nav-scrim[hidden] { display: none; }
  .icon-button { display: grid; }
}

/* Kamera-sunucu iletisim satiri: sayfanin en ustunde, 5 sn'de bir sessizce tazelenir. */
.kamera-iletisim {
  margin: 0 0 .75rem;
  font-size: .85rem;
  color: var(--muted, #94a3b8);
}
.kamera-iletisim strong { color: inherit; font-weight: 600; }
.kamera-iletisim[data-durum="online"] strong { color: var(--accent, #0d7fc2); }
.kamera-iletisim[data-durum="offline"] strong { color: #ef4444; }

@media (max-width: 900px) {
  .metrics > * { flex-basis: calc(50% - .5rem); min-width: 10rem; }
  .primary-grid, .admin-grid, .notification-grid { grid-template-columns: 1fr; }
  /* Same operator priority as desktop; photo controls keep their own order. */
  main.akis-durum { display: flex; flex-direction: column; }
  main.akis-durum .primary-grid { display: contents; }
  main.akis-durum .flash-msg { order: -1; }
  /* Telefonda ON/ARKA etiketleme kartin BASINA cikar: fotografa bakip hemen
     isaretlemek icin asagi kaydirmak gerekmesin. Sira: baslik -> plaka rozeti ->
     On/Arka -> fotograf -> ayrintilar -> Giris/Cikis.
     MASAUSTUNDE DEGISMEZ: orada DOM sirasinda kalir, Giris/Cikis'in altinda. */
  .decision-panel { display: flex; flex-direction: column; }
  .decision-panel > .panel-heading { order: -3; }
  .decision-panel > .decision-card { order: -2; }
  .contact-form { grid-template-columns: 1fr 1fr; }
  .status-row { display: none; }
}

/* Phone layout.  Wide tables become one card per row: a seven-column table in
 * a horizontally scrolling strip is unusable on a phone, and the site is meant
 * to be managed from one.  Headers are mirrored into each cell by
 * labelResponsiveTable() in app.js, so a column change cannot desync them. */
@media (max-width: 700px) {
  main { padding: 1rem .75rem 3rem; }
  .banner-warning { width: calc(100% - 1.5rem); }
  .topbar { padding: .8rem .75rem; }
  .page-title h1 { font-size: 1.05rem; }
  .metrics > * { flex-basis: 100%; min-width: 0; }
  .form-grid { grid-template-columns: 1fr; }
  .contact-form { grid-template-columns: 1fr; }
  .contact-form .check-row { margin-top: 0; }
  .wide { grid-column: auto; }
  .panel-heading { align-items: flex-start; flex-direction: column; }
  /* Sutun yonunde margin-left artik ANA eksen degil CAPRAZ eksen margin'idir;
     auto degeri align-items:flex-start'i ezer ve son oge telefonda da sag
     kenara yapisir. Bu yuzden burada sifirlanir. */
  .panel-heading > *:last-child { margin-left: 0; }
  .panel { padding: 1rem; }
  .search { width: 100%; }
  .filters { width: 100%; flex-wrap: wrap; }
  .filters > * { flex: 1 1 auto; }

  /* The table layout algorithm still sizes columns from the cell contents even
     once the rows are blocks, which made the page wider than the phone and
     pushed each label off-screen.  Dropping display:table is what actually
     frees the rows to wrap. */
  table.responsive, table.responsive tbody { display: block; width: 100%; max-width: 100%; }
  table.responsive { white-space: normal; }
  table.responsive thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }
  table.responsive tr {
    display: block;
    margin-bottom: .7rem;
    padding: .35rem .75rem;
    border: 1px solid var(--glass-line);
    border-radius: 12px;
    background: var(--glass);
  }
  table.responsive td {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 1rem;
    padding: .45rem 0;
    border-bottom: 1px solid var(--glass-line-soft);
    text-align: right;
    /* Long values (plates, resident names) must wrap rather than widen the
       card, which is what forced the horizontal scroll before. */
    overflow-wrap: anywhere;
  }
  table.responsive tr td:last-child { border-bottom: 0; }
  table.responsive td::before {
    content: attr(data-label);
    flex: none;
    color: var(--faint);
    font-size: .7rem;
    letter-spacing: .06em;
    text-transform: uppercase;
    text-align: left;
  }
  /* An empty-state row has no header to mirror and must stay full width. */
  table.responsive td.empty { display: block; text-align: center; }
  table.responsive td.empty::before { content: none; }
  table.responsive td.row-actions { justify-content: flex-end; }
  table.responsive td.row-actions::before { content: attr(data-label); }
}

@media (prefers-reduced-motion: reduce) {
  * { animation: none !important; transition: none !important; }
  button:active { transform: none; }
}

/* Without backdrop-filter the translucent panels would sit on the page
   background and lose contrast, so make them opaque instead. */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
    /* '.metrics article' HIC ESLESMIYORDU: metrik kartlari <a>/<div class="metric">
     olarak basiliyor. Yedek kural boylece olu koddu ve backdrop-filter
     desteklemeyen eski iOS Safari'de kartlar saydam kalip kontrasti
     kaybediyordu. */
  .panel, .metrics .metric, .auth-card, .topbar, #toast {
    background: var(--bg);
  }
}


/* ------------------------------------------------------------------ DURUM
   Sağlık ve güvenlik kalemleri. Bunlar SAYI değil DURUM taşır; bu yüzden
   .metric'in rakam boyutunu kullanmazlar ama aynı yüzeyi, yarıçapı ve
   kenarlığı kullanırlar — panel tek bir tasarım dili konuşsun.

   Renk semantiği styles.css'in kendi kuralına uyar: burada fiziksel röle
   dışında tehlike yoktur, "dikkat" turuncu değil sessiz nötr çiptir.
   Durum noktası .tag sınıflarından rengini alır. */
.durum-sorun { list-style: none; margin: 0 0 1rem; padding: 0; display: grid; gap: .5rem; }
.durum-sorun li {
  display: grid; grid-template-columns: auto 1fr; gap: .6rem; align-items: start;
  padding: .6rem .75rem; border: 1px solid var(--glass-line);
  border-radius: var(--radius); background: var(--glass);
}
.durum-sorun strong { display: block; font-size: .92rem; }
.durum-sorun em { display: block; font-style: normal; color: var(--faint); font-size: .8rem; line-height: 1.4; }

.durum-kalem { display: grid; grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr)); gap: .75rem; }
.durum-kalem .dk {
  position: relative; display: block; padding: .75rem .9rem;
  border: 1px solid var(--glass-line); border-radius: var(--radius);
  background: var(--glass); color: var(--ink); text-decoration: none;
}
.durum-kalem a.dk:hover,
.durum-kalem a.dk:focus-visible { border-color: var(--accent-ring); background: var(--bg-tinted); }
.durum-kalem .dk span { display: block; color: var(--muted); font-size: .78rem; font-weight: 600; }
.durum-kalem .dk strong { display: block; font-size: 1rem; margin-top: .15rem; letter-spacing: -.005em; }
.durum-kalem .dk-nokta {
  position: absolute; top: .7rem; right: .75rem;
  width: .5rem; height: .5rem; padding: 0; border-radius: 50%;
  font-size: 0; line-height: 0;
}

/* ------------------------------------------------------------------ LOGLAR
   Canlı olay akışı: sohbet gibi alttan büyür, en yenisi altta. */
.log-arac { display: flex; flex-wrap: wrap; gap: .75rem; align-items: center; margin: .5rem 0 .75rem; }
.log-arac label { display: flex; align-items: center; gap: .35rem; font-size: .85rem; color: var(--muted); }
.log-arac select { padding: .3rem .5rem; }
.log-sayac { margin-left: auto; font-size: .85rem; color: var(--muted); }
.log-akis {
  height: 60vh; min-height: 320px; overflow-y: auto;
  border: 1px solid var(--glass-line); border-radius: var(--radius);
  padding: .5rem .6rem; background: var(--glass);
  font-variant-numeric: tabular-nums;
}
.log-satir { display: flex; gap: .6rem; align-items: baseline; padding: .3rem .4rem; border-radius: calc(var(--radius) / 2); line-height: 1.45; }
.log-satir + .log-satir { margin-top: .1rem; }
.log-satir .t { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: .76rem; color: var(--faint); flex: 0 0 auto; }
.log-satir .rozet {
  flex: 0 0 auto; font-size: .68rem; text-transform: uppercase; letter-spacing: .04em;
  padding: .1rem .4rem; border-radius: 999px; border: 1px solid var(--line); color: var(--muted);
}
.log-satir .m { flex: 1 1 auto; }
.log-satir .m small { display: block; color: var(--faint); font-size: .76rem; margin-top: .1rem; }
.log-satir.s-uyari { background: var(--notice-soft); }
.log-satir.s-hata { background: var(--red-soft); }
.log-satir.yeni { animation: logYeni 1.2s ease-out; }
@keyframes logYeni { from { background: var(--accent-tint); } to {} }
@media (prefers-reduced-motion: reduce) { .log-satir.yeni { animation: none; } }
.log-bos { color: var(--faint); padding: 1rem; text-align: center; }

/* Dar ekran: kartlar tek sutuna insin, sayac satirlari sikismasin. */
@media (max-width: 680px) {
  .durum-kalem { grid-template-columns: 1fr; }
  .log-akis { height: 55vh; }
  .log-sayac { margin-left: 0; width: 100%; }
}

/* Kare önizlemesi: JPEG yüklenene kadar arkada duran zemin. Sabit koyu bir renk
   yazılmıştı; açık temada sayfanın ortasında koyu bir kutu olarak görünüyordu.
   Zemin artık temayla birlikte döner. */
.kare-onizleme {
  display: block;
  width: 100%;
  border-radius: .35rem;
  background: var(--bg-soft);
  border: 1px solid var(--glass-line);
}

/* Dar ekranda geniş tablolar sayfayı yatay kaydırtmasın; kendi kutusunda kaysın.
   .table-wrap zaten var ama panellerdeki çıplak tablolar bunun dışındaydı. */
@media (max-width: 700px) {
  .panel table { display: block; overflow-x: auto; white-space: nowrap; }
  .panel table td, .panel table th { white-space: nowrap; }
  .durum-sorun li { grid-template-columns: 1fr; }
  .metrics, .metrics-secondary { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 420px) {
  .metrics, .metrics-secondary { grid-template-columns: 1fr; }
}

/* Karar kartındaki fotoğraf BAŞKA bir geçişe aitse, bunu resmin ÜSTÜNDE söyle.
   Küçük yazıyla altta söylemek yetmiyordu: kullanıcı kartı "plaka yanlış okundu"
   diye okudu (05.09.2026). Uyarı resmin önünde, göz kaçıramayacağı yerde durur. */
.foto-baska {
  display: flex; flex-wrap: wrap; align-items: center; gap: .4rem;
  margin: .75rem 0 .35rem; padding: .5rem .7rem;
  border: 1px solid var(--line); border-left: 3px solid var(--notice);
  border-radius: var(--radius); background: var(--notice-soft);
  font-size: .85rem; color: var(--ink); line-height: 1.4;
}
.foto-baska[hidden] { display: none !important; }

/* --- EĞİTİM KUYRUĞU (Plaka eğit) -------------------------------------------
   Kareler yan yana taranır: operatör tek ekranda çok kare işaretler. Sabit
   sütun sayısı YOK — kart genişliği taban alınır, dar ekranda kendiliğinden
   tek sütuna iner. Konsolun kendi paleti kullanılır, yeni renk tanımlanmaz. */
.egitim-izgara {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: .75rem;
}
.egitim-kart {
  display: flex;
  flex-direction: column;
  gap: .3rem;
  padding: .6rem;
  border: 1px solid var(--glass-line);
  border-radius: .5rem;
  background: var(--bg-soft);
}
.egitim-kart .kare-onizleme { max-height: 150px; object-fit: cover; }
.unread-heading { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: .75rem; }
.unread-heading h2 { margin: 0; }
.unread-delete-form { margin: 0; }
.unread-delete-form button { min-height: 44px; }
.unread-card-actions { display: flex; justify-content: flex-end; margin-bottom: .5rem; }

/* ---- UC SUTUNLU GECIS KARTI: karar + giris karesi + cikis karesi ----------
   Kullanici istegi: karar solda, iki kameranin ANLIK goruntusu saginda, ayni
   cam (glass) yuzeyde, yuklendigi an gorunsun.
   EN USTE: main.akis-durum zaten flex + order kullaniyor (satir ~1079); kart
   DOM'da yerinde kalir cunku degiskenleri yukarida hesaplaniyor. */
/* EN USTE: uclu kart .primary-grid IZGARASININ ICINDE duruyor (DOM'da orada
   kalmali - degiskenleri yukarida hesaplaniyor). Izgara ogeleri 'order'a
   uyar; tam genislik verip -5 sirasina alarak sayfanin BASINA cikariyoruz.
   'display: contents' KULLANILMADI: o, masaustu izgara duzenini de bozardi. */

.gecis-uclu {
  display: grid;
  grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr) minmax(0, 1fr);
  gap: .85rem;
  margin-bottom: 1rem;
  /* SUTUN YUKSEKLIKLERI ESIT.
     Burasi 'align-items: start' idi: her sutun kendi icerigi kadar yukselirdi.
     Karar sutunu ~1300 px, kamera sutunlari ~700 px oldugu icin saga dogru
     kocaman bir bosluk kaliyordu -- kullanicinin ekran goruntusunde
     isaret ettigi bosluk tam olarak buydu. */
  align-items: stretch;
}
.gecis-uclu > .panel {
  margin-bottom: 0;
  height: 100%;
  /* Cam efekti: arkasi bulanik, kenari isikli. */
  backdrop-filter: blur(14px) saturate(1.25);
  -webkit-backdrop-filter: blur(14px) saturate(1.25);
  background:
    linear-gradient(160deg,
      color-mix(in srgb, currentColor 8%, transparent),
      color-mix(in srgb, currentColor 2%, transparent));
  border: 1px solid color-mix(in srgb, currentColor 16%, transparent);
  box-shadow:
    0 1px 0 color-mix(in srgb, currentColor 12%, transparent) inset,
    0 10px 30px rgb(0 0 0 / .18);
}
/* .gecis-foto-* kurallari ASAGIDA bir kez daha tanimliydi (var(--fg) surumu)
   ve ozdes ozgullukte oldugu icin KAYNAK SIRASI geregi hep o kazaniyordu.
   Buradaki kopya olu koddu; silindi. Iki kopyanin varligi "kartlar birbirinden
   farkli gorunuyor" sikayetinin beslendigi kaymanin ta kendisiydi. */

/* Kamera kartinin altindaki bos alan: kendi Foto cek dugmesi. */
/* Durum kartlarinda deger rengi: digerleriyle AYNI kart, yalniz deger renkli. */
.metric strong.durum-iyi { color: color-mix(in srgb, #22c55e 78%, currentColor); }
.metric strong.durum-kotu { color: color-mix(in srgb, #ef4444 78%, currentColor); }
/* Durum sekmesinde ust serit gizli: ayni dugmeler uc kartta var. */
.kepenk-bar-gizli { display: none !important; }
.gecis-foto-eylem { margin: .5rem 0 0; }
/* OLU ALAN BIRAKMA: kamera karti karar kartiyla ayni yuksekligi paylasir;
   altta kalan bosluga kepenk ve sayaclar yayilir. */
.gecis-uclu > .gecis-foto { display: flex; flex-direction: column; }
.gecis-uclu > .gecis-foto .gecis-sayac { margin-top: auto; padding-top: .6rem; }
.gecis-foto-eylem button { width: 100%; }

/* Dorduncu kutu: kepenk + en cok bakilan sayilar. */
.gecis-kepenk { margin: 0 0 .7rem; }
.gecis-kepenk .kepenk-ac { width: 100%; }
.gecis-sayac { display: flex; flex-direction: column; gap: .35rem; }
.gecis-sayac .dk {
  display: flex; align-items: baseline; justify-content: space-between; gap: .5rem;
  padding: .4rem .55rem; border-radius: .45rem; text-decoration: none;
  background: color-mix(in srgb, currentColor 6%, transparent);
  border: 1px solid color-mix(in srgb, currentColor 10%, transparent);
  color: inherit;
}
.gecis-sayac .dk:hover { background: color-mix(in srgb, currentColor 11%, transparent); }
.gecis-sayac .dk span { font-size: .82rem; opacity: .8; }
.gecis-sayac .dk strong { font-size: 1.05rem; font-variant-numeric: tabular-nums; }

@media (max-width: 1100px) {
  .gecis-uclu { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
  .gecis-uclu > .decision-panel { grid-column: 1 / -1; }
}
@media (max-width: 700px) {
  .gecis-uclu { grid-template-columns: 1fr; }
  .gecis-uclu > .decision-panel { grid-column: auto; }
}
@media (prefers-reduced-motion: reduce) { .gecis-foto-img { transition: none; } }

/* ---- UC SUTUNLU GECIS KARTI: karar + giris karesi + cikis karesi ----------
   Kullanici istegi: karar solda, iki kameranin anlik goruntusu saginda, ayni
   cam (glass) yuzeyde. Dar ekranda alt alta diziler. */
.gecis-uclu {
  display: grid;
  grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr) minmax(0, 1fr);
  gap: .85rem;
  margin-bottom: 1rem;
  /* SUTUN YUKSEKLIKLERI ESIT.
     Burasi 'align-items: start' idi: her sutun kendi icerigi kadar yukselirdi.
     Karar sutunu ~1300 px, kamera sutunlari ~700 px oldugu icin saga dogru
     kocaman bir bosluk kaliyordu -- kullanicinin ekran goruntusunde
     isaret ettigi bosluk tam olarak buydu. */
  align-items: stretch;
}
.gecis-uclu > .panel {
  margin-bottom: 0;
  height: 100%;
  /* Cam efekti: arkasi bulanik, kenari isikli. */
  backdrop-filter: blur(14px) saturate(1.25);
  -webkit-backdrop-filter: blur(14px) saturate(1.25);
  background:
    linear-gradient(160deg,
      color-mix(in srgb, var(--fg, #fff) 7%, transparent),
      color-mix(in srgb, var(--fg, #fff) 2%, transparent));
  border: 1px solid color-mix(in srgb, var(--fg, #fff) 14%, transparent);
  box-shadow:
    0 1px 0 color-mix(in srgb, var(--fg, #fff) 12%, transparent) inset,
    0 10px 30px rgb(0 0 0 / .18);
}
.gecis-foto-govde {
  position: relative;
  border-radius: .6rem;
  overflow: hidden;
  background: color-mix(in srgb, var(--fg, #fff) 5%, transparent);
  aspect-ratio: 16 / 9;
  display: flex;
  align-items: center;
  justify-content: center;
}
.gecis-foto-img {
  width: 100%; height: 100%;
  object-fit: cover;
  display: block;
  /* Kare gelene kadar gorunmez; JS yukleninca acar. */
  opacity: 0;
  transition: opacity .35s ease;
}
.gecis-foto-img.yuklendi { opacity: 1; }
.gecis-foto-bekle {
  position: absolute;
  display: inline-flex; align-items: center; gap: .4rem;
  font-size: .82rem; opacity: .75;
}
.gecis-foto-img.yuklendi ~ .gecis-foto-bekle { display: none; }
.gecis-foto-yas { margin: .4rem 0 0; font-variant-numeric: tabular-nums; }
@media (max-width: 1100px) {
  .gecis-uclu { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
  .gecis-uclu > .decision-panel { grid-column: 1 / -1; }
}
@media (max-width: 700px) {
  .gecis-uclu { grid-template-columns: 1fr; }
  .gecis-uclu > .decision-panel { grid-column: auto; }
}
@media (prefers-reduced-motion: reduce) {
  .gecis-foto-img { transition: none; }
}
/* YUKLENIYOR GOSTERGESI — "Fotograf isteniyor..." cumlesinin yerine.
   Kullanici metin yerine gorsel bir bekleme isareti istedi. */
.yukleniyor {
  display: inline-block; width: .8em; height: .8em; vertical-align: -.08em;
  border: 2px solid currentColor; border-right-color: transparent;
  border-radius: 50%; animation: yukleniyorDon .7s linear infinite;
}
@keyframes yukleniyorDon { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
  .yukleniyor { animation-duration: 2.4s; }
}
.bas-snap-yukleniyor { display: inline-flex; align-items: center; gap: .35rem; font-size: .82rem; opacity: .85; }
/* Plaka goruntusu henuz gelmediginde yanip sonen nokta. */
.foto-bekle-nokta {
  display: inline-block; width: .5em; height: .5em; border-radius: 50%;
  background: currentColor; opacity: .5; margin-right: .35rem;
  animation: fotoBekleYanip 1.4s ease-in-out infinite;
}
@keyframes fotoBekleYanip { 0%,100% { opacity: .25; } 50% { opacity: .8; } }
@media (prefers-reduced-motion: reduce) { .foto-bekle-nokta { animation: none; } }
/* Tanimsiz ama ICERIDE olan arac: ne "izinli" (yesil) ne "red" (kirmizi).
   Operator "bu arac sitede ama kayitli degil" ayrimini bir bakista gormeli. */
.decision-card.misafir-otomatik { border-color: color-mix(in srgb, var(--warn, #d08700) 55%, transparent); }
.tag.misafir-otomatik { background: color-mix(in srgb, var(--warn, #d08700) 20%, transparent); }
/* Eski "tahmin" dugmesi (.aday-tik) 02.10.2026'da .plaka-cip oneri ciplerine
   donustu (asagida, "ONERI CIPLERI"); tahmin artik tek dokunusla kutuya
   yazilip kaydedilmez. */
.egitim-form { display: flex; flex-wrap: wrap; gap: .35rem; align-items: center; }
.egitim-form input[type="text"] { flex: 1 1 8rem; min-width: 0; }
.egitim-form select { flex: 1 1 7rem; min-width: 0; }
.egitim-form button { flex: 0 0 auto; }
@media (max-width: 640px) {
  .egitim-izgara { grid-template-columns: 1fr; }
  .egitim-kart .kare-onizleme { max-height: 210px; }
}

/* --- BASLIK CUBUGU: kepenk + iki foto cek dugmesi -------------------------
   Uc dugme dar ekranda tasmasin. .kepenk-bar zaten flex-wrap; burada yalnizca
   mobilde etiketleri kisaltip dugmeleri esit paya bolerek okunur tutuyoruz.
   Masaustunde tam etiket gorunur. */
@media (max-width: 720px) {
  .kepenk-bar { width: 100%; margin-left: 0; }
  .kepenk-bar form { flex: 1 1 auto; }
  .kepenk-bar button { width: 100%; font-size: .82rem; padding: .35rem .5rem; }
  /* "Giris kamerasi · Foto cek" mobilde uzun kaliyor; ayraci ve ikinci kelimeyi
     gizleyip "Giris · Foto" etkisi veriyoruz — metin degistirmeden. */
  .kepenk-bar .foto-uzun { display: none; }
}

/* --- CIFT ARACLI DAIRE LISTESI: plaka + ne kadardir iceride ----------------
   Plaka tek basina "hangi arac ne kadardir burada" sorusunu yanitlamiyordu.
   Sure plakanin hemen altinda, kucuk ve sessiz; plaka okunakli kalsin. */
.plaka-sure {
  display: inline-flex;
  flex-direction: column;
  align-items: flex-end;
  gap: .1rem;
  margin-left: .45rem;
  vertical-align: top;
}
.plaka-sure em {
  font-style: normal;
  font-size: .74rem;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}
@media (max-width: 720px) {
  .plaka-sure { margin-left: .3rem; }
  .plaka-sure em { font-size: .7rem; }
}
/* 3 gunden uzun "iceride" — cikisi kacirilmis olabilir. Uyari degil, dikkat
   isareti: sayiyi gizlemek yerine yaninda gosteriyoruz. */
.plaka-sure em.sure-supheli { color: var(--warn, #b45309); font-weight: 600; }

/* --- PLAKAYI KIM OKUDU ------------------------------------------------------
   Kamera mi, Raspberry mi, sunucu mu? Renk tek basina anlam tasimaz; etiket
   metni zaten yazili, renk yalnizca tarama kolayligi icin. */
.okuyan {
  display: inline-block; padding: .1rem .4rem; border-radius: .3rem;
  font-size: .72rem; white-space: nowrap; border: 1px solid var(--glass-line);
  background: var(--bg-soft); color: var(--muted);
}
.okuyan-kamera  { color: var(--fg); border-color: var(--accent-ring); }
.okuyan-pi      { color: var(--blue-deep, #1d4ed8); border-color: var(--blue-soft, #bfdbfe); }
.okuyan-sunucu  { color: var(--warn, #b45309); }
.okuyan-ikincil { opacity: .6; }

/* --- BASLIKTAKI ANLIK FOTOGRAF ---------------------------------------------
   "Foto cek" dugmesinin hemen altinda. Kucuk tutuluyor: amac kapida ne oldugunu
   bir bakista gormek, sayfayi kaplamak degil. Gelene kadar hic yer kaplamaz. */
.bas-snap { width: 100%; margin: .4rem 0 0; }
.bas-snap img {
  display: block; max-width: 320px; width: 100%; height: auto;
  border-radius: 10px; border: 1px solid var(--glass-line); background: var(--bg-soft);
}
.bas-snap .help { display: block; margin-top: .2rem; font-size: .74rem; }
@media (max-width: 720px) { .bas-snap img { max-width: 100%; } }

/* ===== MOBIL YATAY TASMA DUZELTMELERI (headless olcum ile dogrulandi) =======
   Dort kok neden vardi; hepsi burada kapatiliyor. 'html{overflow-x:hidden}'
   bunlarin HICBIRINI cozmuyordu - yalnizca gizliyor ve <html>'i kaydirma
   kabina cevirip mobildeki SALINIMI besliyordu. */

/* KOK NEDEN 2: kirilamayan uzun metin. Projede overflow-wrap HIC yoktu;
   sir iceren URL'ler 663 piksellik kirilamaz blok olusturuyordu. */
p, li, dd, dt, figcaption, .help, .detail-list dd, .setup-banner, .banner-warning,
.metric em, .dk span, .egitim-kart .help {
  /* 'anywhere' DEGIL: o, ogenin min-content genisligini TEK KARAKTERE indirir
     ve dar izgara cocugunda "Okuma" yazisi O/k/u/m/a diye alt alta kirilir
     (05.09.2026 ekran goruntusuyle yakalandi). 'break-word' yalniz baska
     care yoksa kelimeyi boler. */
  overflow-wrap: break-word;
}
code, kbd, samp, pre {
  overflow-wrap: anywhere;
  max-width: 100%;
}

/* KOK NEDEN 3: global table{white-space:nowrap} sarmalayicisiz tablolara da
   uygulaniyordu; gizlilik.html 1024 piksele kadar tasiyordu. Nowrap YALNIZ
   yatay kaydirilabilir sarmalayici icindeki tabloya uygulanir. */
table { white-space: normal; }
.table-wrap > table { white-space: nowrap; }
/* Rol gorunurlugu matrisi uzun bolum aciklamalari tasir; tek satira
   kilitlenince onay kutulari ekranin disina itiliyordu (02.10.2026: 918 px
   kapta 1644 px tablo). Aciklama sarilir, rol sutunlari dar ve ortali kalir. */
.table-wrap > table.gorunurluk-matris { white-space: normal; }
@media (min-width: 701px) {
  .gorunurluk-matris th:not(:first-child),
  .gorunurluk-matris td:not(:first-child) { width: 7.5rem; text-align: center; }
}

/* Mobil kart duzenini geri kazandir: .panel table kurallari table.responsive'i
   ozgulluk farkiyla sessizce iptal ediyordu. */
.panel table:not(.responsive) { white-space: inherit; }

/* Arama kutusu dar ekranda panel disina cikiyordu (min-width:15rem = 240px). */
.search { min-width: 0; }

/* Hicbir gorsel/ icerik kabini asmasin. */
img, video, canvas, svg { max-width: 100%; height: auto; }

/* SARMALAYICISIZ TABLO (or. gizlilik.html): kabin ic bosluguyla birlikte
   tasiyordu (tablo 279px + 20px kenar = 299px, 280px ekranda 19px tasma -
   headless olcum). Dar ekranda kendi kutusunda yatay kayar; sayfa kaymaz. */
table { max-width: 100%; }
@media (max-width: 560px) {
  table:not(.responsive) {
    display: block;
    max-width: 100%;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
  }
}

@media (max-width: 720px) {
  /* KOK NEDEN 1: .topbar flex-wrap tasimiyordu. Dugme seridi kaldirildi ama
     baska bir oge eklenirse yine tasmasin diye kural kaliyor. */
  .topbar { flex-wrap: wrap; }
  .kepenk-bar { flex: 1 1 100%; width: auto; min-width: 0; margin-left: 0; }
  /* Izgaralarda minmax(NNNpx,...) dar ekranda tasar. */
  .gecis-uclu, .primary-grid, .admin-grid, .notification-grid, .egitim-izgara {
    grid-template-columns: 1fr;
  }
  .metrics, .metrics-secondary { grid-template-columns: repeat(auto-fit, minmax(0, 1fr)); }
}

/* ===================================================================== */
/* ==================  TEK KART YUZEYI / MOBIL BIRLIK  ================= */
/* ===================================================================== */
/* Kullanici kurali (06.09.2026, birebir): "Mobildeki tum kartlar ayni css ile
   gozukmeli, goruntuleme problemi olanlari duzelt, KARTTAN DISARI YAZI
   TASMAYACAK, KARTLAR IC ICE GIRMEYECEK."

   Uc kok neden olculdu:

   1. KART YUZEYI DAGINIKTI. .panel, .metric, .decision-card, .egitim-kart,
      .durum-kalem .dk ve admin/index.php icindeki SATIR ICI stiller kart
      yuzeyini AYRI AYRI tanimliyordu; kenarlik rengi, yuvarlaklik ve golge
      birbirini tutmuyordu. Asagidaki blok hepsini AYNI degiskenlere baglar.

   2. TASMA: izgara/esnek cocuklarinin varsayilani min-width:auto'dur ve
      icerik kabindan genisse kutuyu ITER. Uzun plaka, uzun sayi, kirilamayan
      baglanti karttan disari tasiyordu. min-width:0 + overflow-wrap birlikte
      kapatir; ikisinden biri tek basina YETMEZ.

   3. IC ICE GIRME: kart icindeki position:absolute katmanlar (.dk-nokta,
      .gecis-foto-bekle, .plate-suggest) konumlanmis bir ata BULAMAZSA en
      yakin konumlanmis atayi -- ya da govdeyi -- referans alir ve baska
      kartlarin ustune biner. Ata artik acikca konumlandirilir. */

:root {
  --kart-kenar: var(--glass-line);
  --kart-yuvarlak: .6rem;
  --kart-ic: .75rem;
  --kart-zemin: var(--bg-soft);
}

/* --- 1) AYNI YUZEY -------------------------------------------------------
   IKI KATMAN AYRILIR, cunku hepsini tek kurala bagladiginda karar kartinin
   ANLAM RENGINI (izin yesili / red kirmizisi / okunamadi sarisi) de silersin:

     a) GEOMETRI (yuvarlaklik, kenarlik kalinligi, ic bosluk) -> HEPSINDE AYNI.
        Kullanicinin "kartlar ayni gorunmeli" dedigi sey budur.
     b) RENK (zemin, kenarlik rengi) -> yalniz NOTR kartlarda ayni; durum
        kartlari kendi anlam rengini korur.

   .panel bilerek DISARIDA: o kartlari TASIYAN kap, kartin kendisi degil.
   Kaba da ayni yuvarlaklik verilirse ic ice iki ayni kutu gorunur. */
.egitim-kart,
.durum-kalem .dk,
.gecis-sayac .dk,
.durum-sorun li,
.metrics .metric,
.decision-card,
.kart,
main .card,
main .glass-panel {
  border-width: 1px;
  border-style: solid;
  border-radius: var(--kart-yuvarlak);
  padding: var(--kart-ic);
  position: relative;          /* icerideki katmanlar disari tasmasin */
  min-width: 0;                /* izgara cocugu kabini asmasin */
  overflow-wrap: break-word;   /* bkz. asagidaki 'ANYWHERE TUZAGI' notu */
}
/* Notr kartlar: ayni zemin, ayni kenarlik rengi. Durum kartlari haric.
   'main .card' ve 'main .glass-panel' admin/index.php'nin GOMULU <style>
   blogunda IKINCI BIR KART YUZEYI olarak tanimliydi (baska yuvarlaklik,
   baska ic bosluk, baska golge). Ayni sayfada iki farkli kart gorunumunun
   kaynagi buydu; artik ayni degiskenlerden besleniyor. */
.egitim-kart,
.durum-kalem .dk,
.gecis-sayac .dk,
.durum-sorun li,
.metrics .metric,
.kart,
main .card,
main .glass-panel {
  border-color: var(--kart-kenar);
  background: var(--kart-zemin);
}
/* .gecis-sayac .dk ve .durum-sorun li KENDI yuvarlakliklarini tasiyordu
   (.45rem ve var(--radius)); ayni ekranda uc farkli kose yaricapi
   gorunuyordu. Ikisi de artik ortak degiskenden besleniyor. */

/* METRIK KARTLARIN BIR KISMI BAGLANTI, BIR KISMI DIV.
   styles.css'te text-decoration sifirlamasi yalniz .brand-home, .dk ve
   .gecis-sayac .dk icin vardi; .metric icin YOKTU. Bu yuzden 'Kayitli arac',
   'Bugun giris' gibi <a class="metric"> kartlarinin TUM metni alti cizili
   gorunurken hemen yanlarindaki <div class="metric"> kartlari duz duruyordu.
   Ayni kartin a/div olmasi gorunumu degistirmemeli. */
.metrics .metric,
.metrics a.metric,
.metrics .metric:hover,
.metrics .metric:focus-visible { text-decoration: none; }

/* --- 2) TASMA: kart icindeki HER metin ogesi kirilabilir olmali. ---------
   Onceki duzeltme yalniz p/li/dd/dt/... listesine veriyordu; strong, span,
   a, td, h3 listede YOKTU ve uzun plaka/sayi tam da onlarin icinde. */
.panel, .kart, .egitim-kart, .metrics .metric, .decision-card,
.durum-kalem .dk, .gecis-foto, .decision-panel {
  min-width: 0;
}
.panel *, .kart *, .egitim-kart *, .metrics .metric *, .decision-card *,
.durum-kalem .dk *, .gecis-foto *, .decision-panel * {
  min-width: 0;
  max-width: 100%;
}
/* --- ANYWHERE TUZAGI (headless olcumle yakalandi, 06.09.2026) -------------
   Ilk yazimda buraya 'overflow-wrap: anywhere' konmustu ve panel ekran
   goruntusunde "Okuma" etiketi HARF HARF alt alta kirildi:  O / k / u / m / a
   Sebep sozdizimsel degil, ic olcumsel: 'anywhere', ogenin MIN-CONTENT
   genisligini TEK KARAKTERE dusurur. Esnek/izgara sutunu min-content'e gore
   daralabildigi icin sutun 1 karaktere cokuyor.
   'break-word' ise min-content'i DEGISTIRMEZ: sutun normal genisligini korur,
   yalnizca kabina sigmayan TEK bir uzun kelime kirilir. Kart ici metin icin
   dogru deger budur.
   'anywhere' sadece kirilma noktasi OLMAYAN uzun jetonlarda (URL, UUID, sir)
   gerekir; onlar asagida ayrica ele alinir. */
.panel :is(p, span, strong, em, a, dt, dd, li, td, th, h1, h2, h3, h4, small, code),
.kart :is(p, span, strong, em, a, dt, dd, li, td, th, h3, h4, small, code),
.egitim-kart :is(p, span, strong, em, a, small, code),
.metrics .metric :is(span, strong, em, small),
.decision-card :is(p, span, strong, em, small),
.durum-kalem .dk :is(span, strong, em, small) {
  overflow-wrap: break-word;
  word-break: normal;          /* once bosluktan kir, mecbur kalirsa harften */
}
/* Kirilma noktasi olmayan uzun jetonlar: burada 'anywhere' GEREKLI. */
code, kbd, samp, pre, .jeton, .uuid { overflow-wrap: anywhere; }

/* Sayilar sutun halinde hizalansin, ama tasmayi tetiklemesin. */
.metrics .metric strong, .durum-kalem .dk strong, .gecis-sayac strong {
  font-variant-numeric: tabular-nums;
  overflow-wrap: break-word;
}

/* Etiket/deger listesi dar ekranda ALT ALTA. Yan yana iken uzun bir etiket
   ile uzun bir deger ayni satirda birbirini eziyor ve etiket sutunu daralip
   okunmaz hale geliyor. */
@media (max-width: 560px) {
  .detail-list div { flex-direction: column; align-items: flex-start; gap: .15rem; }
  .detail-list dd { text-align: left; }
}

/* --- 3) IC ICE GIRME: konumlanmis katmanin atasi HER ZAMAN konumlanmis. -- */
.gecis-foto-govde, .plate-suggest-wrap, .durum-kalem .dk, .egitim-kart {
  position: relative;
}
/* Kart icindeki mutlak katman kabini ASLA asmasin. */
.gecis-foto-govde { overflow: hidden; }

@media (max-width: 720px) {
  /* Tum kart izgaralari TEK SUTUN. Farkli kirilma noktalarinda (640/680/700/
     720/900/1000/1100) dagilmis kurallar burada tek noktaya toplanir. */
  .gecis-uclu, .primary-grid, .admin-grid, .notification-grid,
  .egitim-izgara, .metrics, .metrics-secondary, .durum-kalem {
    grid-template-columns: 1fr;
  }
  .gecis-uclu > .decision-panel { grid-column: auto; }

  /* Satir ici genislik dayatan esnek cocuklar (flex:1 1 320px gibi) dar
     ekranda kabini asar; taban genisligi sifirlanir. */
  .egitim-izgara > *, .panel .row > *, .status-row > * {
    flex-basis: auto;
    min-width: 0;
  }

  /* Kartlar arasinda net bosluk: ust uste binme izlenimi kalmasin. */
  .egitim-kart, .kart, .metrics .metric { margin-bottom: 0; }

  /* Ust seritteki kullanici cipi ellipsis'e guveniyordu; dar ekranda
     kisaltilsin ama TASMASIN. */
  #userChip { max-width: 100%; }
}

/* Dar ekranda satir ici tablolar kendi kutusunda kaysin, SAYFA kaymasin. */
@media (max-width: 720px) {
  .panel table { max-width: 100%; }
}

/* --- TABLO: dar ekranda SATIR KAYDIRMASI acik olmali -------------------
   styles.css:1264'te `@media (max-width:700px) { .panel table { white-space:
   nowrap } }` vardi. Amac tablonun kendi kutusunda yatay kaymasiydi, ama
   nowrap KART DUZENINDEKI tabloyu da (table.responsive) etkiliyor ve uzun
   bir sakin adi hucreye sigmayip karttan disari tasiyordu. Yatay kayma zaten
   overflow-x ile saglaniyor; nowrap'a gerek yok. */
@media (max-width: 720px) {
  .panel table:not(.responsive) { white-space: normal; }
  .panel table:not(.responsive) td,
  .panel table:not(.responsive) th { white-space: normal; overflow-wrap: break-word; }
  /* KART DUZENI EZILMEMELI.
     Burasi 'display: table' diyordu ve seciciligi (.panel table.responsive)
     satir 1128'deki 'table.responsive { display: block }' kuralindan YUKSEK,
     dosyada da SONRA geliyor. Sonuc: 700px altinda .panel icindeki tablolar
     karta DONUSMUYOR, tablo olarak kaliyordu -- kullanicinin "mobilde kartlar
     hala tek tip degil" dedigi durumun bir sebebi. Yalniz kaydirma kabi
     iptali kaliyor, display'e DOKUNULMUYOR. */
  .panel table.responsive { overflow-x: visible; white-space: normal; }
  .panel table.responsive td,
  .panel table.responsive th { white-space: normal; }
}


/* ================  UC SUTUN: SAGLIK KARTLARI SUTUNLARDA  ================ */
/* Kullanici (06.09.2026): "Ekteki istatistik kartlarını diğer fotodaki boşluk
   alana taşı. Yükseklikler aynı olacak, kart yükseklikleri."
   Saglik kartlari 'Sistem durumu' panelinden alinip iki kamera sutununa
   dagitildi; asagidaki kurallar o boslugu doldurur ve kartlari esitler. */
.uclu-durum {
  grid-column: 1 / -1;
  display: flex; flex-wrap: wrap; align-items: center;
  gap: .45rem .7rem;
}
.uclu-durum .help { margin: 0; flex: 1 1 12rem; }

/* Kamera sutunu dikey akar; kart izgarasi KALAN boslugu doldurur. */
.gecis-uclu > .cam-kart { display: flex; flex-direction: column; }

/* Sutun kipi: tek kolon ve TUM KARTLAR AYNI YUKSEKLIK.
   'grid-auto-rows: 1fr' satirlari esit boler, boylece deger bir satir da
   olsa iki satir da olsa kart yuksekligi degismez. */
.durum-kalem--sutun {
  flex: 1 1 auto;
  grid-template-columns: minmax(0, 1fr);
  grid-auto-rows: minmax(3.9rem, 1fr);
  gap: .5rem;
  align-content: stretch;
}
.durum-kalem--sutun .dk {
  display: flex; flex-direction: column; justify-content: center;
  min-height: 3.9rem;
}
/* Sutunlari esitleyen GORUNMEZ hucre: yer kaplar, hicbir sey cizmez.
   'visibility: hidden' secildi cunku 'display: none' izgara satirini
   tamamen kaldirir ve esitleme amaci bozulur. */
.durum-kalem--sutun .dk-bos {
  visibility: hidden;
  border-color: transparent;
  background: none;
}
/* Cikis sutununda "Kepenk Aç" dugmesi yok. Bu gorunmez yer tutucu onun
   yuksekligini ayirir; boylece iki sutunun kart izgarasi ayni yerden baslar,
   ayni yuksekligi paylasir ve kartlar birebir ayni boyda cikar. */
.gecis-kepenk-yer { min-height: 44px; }

/* ---- TIKLANABILIR KART, TIKLANABILIR GORUNSUN --------------------------
   Kullanici: "Çift araçlı daire 4 -> Link yok."  Kart ASLINDA <a href> idi
   ama metrik kartlari <div> ile birebir ayni goruntudeydi: ne imlec, ne ok,
   ne de vurgu vardi. Tiklanabilirlik gorunmuyorsa kullanici icin YOKTUR.
   Kucuk bir ok isareti + hover vurgusu ekleniyor; ok yalniz BAGLANTI olan
   kartta cikar, boylece hangi kartin bir yere goturdugu bakinca anlasilir. */
.metrics a.metric,
.durum-kalem a.dk { cursor: pointer; }
.metrics a.metric::after {
  content: "›";
  position: absolute; right: .6rem; bottom: .35rem;
  font-size: 1.05rem; line-height: 1; color: var(--muted);
  opacity: .55; transition: opacity .15s ease, transform .15s ease;
}
.metrics a.metric:hover::after,
.metrics a.metric:focus-visible::after { opacity: 1; transform: translateX(2px); }
.metrics a.metric:hover,
.metrics a.metric:focus-visible { border-color: var(--accent-ring); background: var(--bg-tinted); }

/* Oncelikli bolum: cift aracli daire tablosu. */
#cift-arac .plate { font-weight: 700; letter-spacing: .01em; }
#cift-arac em { display: block; font-style: normal; font-size: .78rem; margin-top: .1rem; }
#cift-arac .sure-supheli { color: var(--crit, #c44); font-weight: 600; }

/* ---- DAIREYE BAGLA FORMU (liste satirlarinin icinde) -------------------
   Kullanici: "Tanimsiz araclar gozukuyor, daireye bagla butonu nerde?
   Daireye bagla kalici veya misafir olacak secilebilmeli."
   Form satirin icinde durur; dar ekranda alt alta sarar. */
.bagla-form {
  display: flex; flex-wrap: wrap; gap: .3rem; align-items: center;
  justify-content: flex-end; margin: 0;
}
.bagla-form select {
  width: auto; min-width: 7rem; max-width: 13rem;
  min-height: 36px; padding: .3rem .45rem; font-size: .82rem;
}
.bagla-form button { min-height: 36px; padding: .3rem .7rem; font-size: .8rem; }
@media (max-width: 700px) {
  .bagla-form { justify-content: flex-start; }
  .bagla-form select { flex: 1 1 8rem; max-width: none; }
}
/* HUCRE ICI YIGIN — telefonda satir sonu gercekten calissin.
   &lt;=700px'te 'table.responsive td' SATIR yonlu bir flex kabina donusuyor
   (styles.css icindeki @700 blogu). O baglamda:
     - &lt;br&gt; bir flex OGESI olur ve satir kirmaz (satir kirma yalnizca satir ici
       bicimlendirme baglaminda tanimlidir),
     - cocuk uzerindeki 'display:block' de satir sonu uretmez, yalnizca o
       ogenin ic bicimlendirme baglamini belirler,
     - 'gap' iki parcanin ARASINA girer, bitisik yazilmis '2/6' gibi tek bir
       jeton ikiye ayrilir.
   Sarmalayici hucrede tek 'deger' ogesi birakir ve yigin ONUN ICINDE calisir;
   ::before ile basilan sutun etiketi de solda kalmaya devam eder.
   Masaustunde gorunum degismez: sutun yonlu kutu hucreyi doldurur ve metin
   hizasi hucrenin kendi text-align'ini izler. */
.hucre-yigin { display: flex; flex-direction: column; gap: .15rem; }
/* Kesir tek jeton: parcalarinin arasina bosluk girmesin, satir da kirilmasin. */
.yuva-kesir { white-space: nowrap; }
@media (max-width: 700px) {
  .hucre-yigin { align-items: flex-end; }
}

/* SATIR EYLEMLERI TEK SIRADA.
   .bagla-form blok seviyesinde bir flex kabidir; yaninda baska bir form
   durdugunda o form ALT SATIRA duser, hucre yuksekligi buyur ve dugme
   hizadan cikar (07.09.2026 kullanici bildirimi: "Cikisini isle butonu
   gozukmuyor, alta kaymis"). Ortak kap ikisini ayni sirada tutar ve yer
   gercekten yetmezse duzgunce sarar. */
.satir-eylem {
  display: flex;
  flex-wrap: wrap;
  gap: .3rem;
  align-items: center;
  justify-content: flex-end;
}
.satir-eylem > form { margin: 0; }
.satir-eylem .bagla-form { flex: 0 1 auto; }
.satir-eylem-hucre { text-align: right; }
/* Dar ekranda dugmeler tablo kenarindan tasmasin. */
@media (max-width: 700px) {
  .satir-eylem { justify-content: flex-start; }
}

#bosta-araclar .plate { font-weight: 700; }
#bosta-araclar em { font-style: normal; }
#bosta-araclar .sure-supheli { color: var(--crit, #c44); font-weight: 600; }

/* ---- GECISIN TUM KARELERI (her kamera icin ayri) -----------------------
   Kullanici: "Önce çıkış, sonra giriş kamerası okudu -> okunamayan görüntü
   nerde?"  O gecisde okunamayan kare yoktu; sorun panelin yalnizca SECILEN
   kareyi gostermesiydi. Iki kamera karesi de artik yan yana duruyor ve
   hangisinin secildigi isaretli. */
.gecis-kareler {
  display: flex; flex-wrap: wrap; gap: .5rem;
  margin: .5rem 0 0;
}
.gecis-kareler .gk {
  margin: 0; min-width: 0; flex: 1 1 9rem;
  border: 1px solid var(--kart-kenar); border-radius: var(--kart-yuvarlak);
  padding: .35rem; background: var(--kart-zemin);
}
.gecis-kareler .gk-secili { border-color: var(--accent-ring); }
.gecis-kareler .gk img {
  display: block; width: 100%; height: auto; max-height: 84px;
  object-fit: contain; border-radius: 6px;
}
.gecis-kareler .gk figcaption {
  margin-top: .25rem; font-size: .72rem; color: var(--muted);
  overflow-wrap: break-word;
}
.gecis-kareler .gk figcaption strong { color: var(--ink); font-size: .74rem; }
/* TELEFONDA DA TEK KOLON.
   Once burada 'repeat(auto-fit, minmax(9.5rem,1fr))' + 'auto' satir vardi.
   Dar kolonda deger iki satira sariyor ve satir yuksekligi ICERIGE gore
   buyuyordu: headless olcumde 390 px'te kartlar 62 ile 79 px arasinda
   degisiyordu (FARK=17). Kullanicinin sikayeti tam olarak buydu --
   "Safari mobilde istatistik kartlari hala tek tip degil".
   Tek kolonda deger tek satira sigiyor ve 1fr tum satirlari esitliyor. */

/* The single gate action stays in the sticky header, including narrow screens. */
.header-gate { margin: 0 0 0 auto; flex: 0 0 auto; }
.header-gate button { min-height: 44px; white-space: nowrap; }
@media (max-width: 420px) {
  .topbar { gap: .5rem; }
  .topbar .page-title { flex: 1 1 90px; }
  .header-gate button { padding: .5rem .65rem; }
}

/* Seven calendar days, two bars per day. No remote chart library or animation. */
.weekly-movements {
  --weekly-entry: var(--accent);
  --weekly-exit: var(--fg-muted);
  --weekly-plot-height: 220px;
  --weekly-label-height: 48px;
  min-width: 0;
}
.weekly-movements .panel-heading { align-items: center; flex-wrap: wrap; }
.weekly-totals { display: flex; gap: 1.25rem; flex-wrap: wrap; margin-left: auto; color: var(--fg-muted); font-size: .85rem; }
.weekly-totals strong { color: var(--fg); font-size: 1.3rem; font-variant-numeric: tabular-nums; }
.weekly-legend { display: flex; gap: 1.25rem; margin: 1rem 0 1.75rem; font-size: .85rem; }
.weekly-legend > span { display: inline-flex; align-items: center; gap: .45rem; }
.weekly-key { display: inline-block; width: .9rem; height: .9rem; border-radius: 3px; }
.weekly-entry { background: var(--weekly-entry); }
.weekly-exit { background-color: var(--weekly-exit); background-image: repeating-linear-gradient(135deg, var(--weekly-exit) 0 4px, color-mix(in srgb, var(--weekly-exit) 72%, var(--bg)) 4px 6px); }
.weekly-movements figure { margin: 0; }
.weekly-movements-chart { display: grid; grid-template-columns: 3.4rem minmax(0, 1fr); gap: .5rem; }
.weekly-axis { position: relative; height: var(--weekly-plot-height); color: var(--fg-muted); font-size: .75rem; font-variant-numeric: tabular-nums; }
.weekly-axis > span { position: absolute; right: 0; transform: translateY(50%); }
.weekly-columns { position: relative; display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); gap: .75rem; }
.weekly-grid { position: absolute; inset: 0 0 var(--weekly-label-height); pointer-events: none; }
.weekly-grid > i { position: absolute; inset-inline: 0; border-top: 1px solid var(--line); }
.weekly-day { min-width: 0; position: relative; }
.weekly-bars { display: flex; justify-content: center; align-items: flex-end; gap: .3rem; height: var(--weekly-plot-height); }
.weekly-bar { position: relative; flex: 0 1 28px; width: 40%; max-width: 28px; border-radius: 4px 4px 0 0; }
.weekly-bar > span { position: absolute; bottom: calc(100% + 5px); left: 50%; transform: translateX(-50%); color: var(--fg); font-size: .75rem; line-height: 1; font-variant-numeric: tabular-nums; white-space: nowrap; }
/* Large exact values remain in bar titles and the table without colliding. */
.weekly-bar > .weekly-large-value { display: none; }
.weekly-zero { background: none; }
.weekly-zero > span { color: var(--fg-muted); }
.weekly-day-label { display: flex; flex-direction: column; justify-content: center; align-items: center; height: var(--weekly-label-height); line-height: 1.4; font-size: .8rem; }
.weekly-day-label > span { color: var(--fg-muted); font-size: .75rem; }
.weekly-today .weekly-day-label > span { color: var(--accent-deep); font-weight: 700; }
.weekly-movements figcaption { margin: .6rem 0 0; }
.weekly-table { margin-top: 1rem; border-top: 1px solid var(--line); }
.weekly-table summary { cursor: pointer; padding: .9rem 0; font-size: .9rem; min-height: 44px; }
.weekly-table summary:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
.weekly-table table { width: 100%; table-layout: fixed; }
.weekly-table th:not(:first-child), .weekly-table td { text-align: right; font-variant-numeric: tabular-nums; }
.weekly-table-caption { text-align: left; color: var(--fg-muted); font-size: .8rem; padding-bottom: .5rem; }
@media (max-width: 600px) {
  .weekly-movements { --weekly-plot-height: 175px; }
  .weekly-totals { margin-left: 0; gap: 1rem; }
  .weekly-totals strong { font-size: 1.1rem; }
  .weekly-movements-chart { grid-template-columns: 2.5rem minmax(0, 1fr); gap: .35rem; }
  .weekly-columns { gap: .3rem; }
  .weekly-bars { gap: 3px; }
  .weekly-bar > span { font-size: .6rem; }
  .weekly-day-label { font-size: .65rem; }
  .weekly-day-label > span { font-size: .65rem; }
  .weekly-table th, .weekly-table td { padding: .6rem .3rem; font-size: .8rem; }
}

/* Misafir satirinda daire secimi (22.09.2026: ustteki "Yeni misafir" karti
   kaldirildi). Ozet .secondary.mini dugme govdesini alir; acilinca form satirin
   eylem kabinda tam genislige yayilir. */
.satir-daire-sec > summary { cursor: pointer; list-style: none; }
.satir-daire-sec > summary::-webkit-details-marker { display: none; }
.satir-daire-sec[open] { flex-basis: 100%; }
.satir-daire-sec[open] > summary { margin-bottom: .35rem; }
.satir-daire-sec .bagla-form { justify-content: flex-end; }

/* Evidence remains visible without turning uncertain sightings into passages. */
.quality-checks { display: grid; grid-template-columns: repeat(auto-fit,minmax(min(100%,240px),1fr)); gap: .75rem; margin: 1rem 0; }
.quality-check { border: 1px solid var(--line); border-radius: 12px; padding: .75rem 1rem; min-width: 0; }
.quality-check[open] { grid-column: 1 / -1; }
.quality-check summary { cursor: pointer; min-height: 44px; display: grid; grid-template-columns: minmax(0,1fr) max-content; align-items: start; gap: .65rem; }
.quality-check summary strong { margin-left: auto; font-size: 1.15rem; font-variant-numeric: tabular-nums; }
.quality-check summary .help { grid-column: 1 / -1; margin: 0; }
.quality-check summary:focus-visible { outline: 2px solid var(--accent); outline-offset: 4px; }
.quality-warning { border-left: 3px solid #bc840f; padding: .5rem .8rem; background: color-mix(in srgb,#bc840f 8%,var(--bg)); }
.quality-table-scroll { max-width: 100%; overflow-x: auto; max-height: 420px; overflow-y: auto; }
.quality-table-scroll table { width: 100%; min-width: 610px; table-layout: auto; }
.quality-table-scroll th { position: sticky; top: 0; background: var(--bg); }
.quality-table-scroll td { font-variant-numeric: tabular-nums; }
.movement-quality .weekly-table { margin-bottom: 1rem; }

/* ===================== PLAKA YAZISI (02.10.2026) =========================
   UX denetimi (font-o0.png): konsolun yazi tipi Play, O harfini ve 0 rakamini
   neredeyse AYNI ciziyor. Bekci okunamayan kareyi etiketlerken ya da elle
   plaka girerken ikisini ayiramiyordu; 152 bekleyen kayit O/0, I/1 karismasi
   tasiyordu. Plakanin GORUNDUGU ve YAZILDIGI her yer tek aralikli, sifiri
   cizgili yazi tipiyle cizilir (iOS/macOS SF Mono ve Menlo, Windows Consolas
   sifiri zaten cizgili cizer; slashed-zero ozelligi destekleyen digerlerinde
   acilir). Android'in yerlesik tek aralikli yazi tipinde cizgi olmayabilir:
   orada TR plakasindaki obek bolmesi ayrimi tasir — harf obegi HEP ortadadir
   ("16 BOS 153": ortadaki O harftir, yandaki 0 rakamdir). Obekler
   DashboardView::plakaHtml ve panel-ui.js'te ayni kaliptan uretilir. */
:root {
  --font-plaka: ui-monospace, "SF Mono", SFMono-Regular, Menlo, Consolas, "Roboto Mono",
    "Noto Sans Mono", "DejaVu Sans Mono", "Liberation Mono", monospace;
}
.plate,
.plaka-cip,
#son-gecis-plaka,
#son-anpr-olay,
#occupancyBody > tr > td:first-child,
.quality-table-scroll td:first-child,
.plate-suggest strong,
#manualPlate,
input.plaka-giris,
input[name="plate"]:not([type="hidden"]),
input[name^="plate"]:not([type="hidden"]) {
  font-family: var(--font-plaka);
  font-variant-numeric: slashed-zero;
  letter-spacing: .02em;
}
.plate { white-space: nowrap; }
/* Obekler arasi bosluk GORSEL: araya bosluk karakteri konmaz, kopyalanan ve
   aranan metin ham plaka olarak kalir. */
.plaka-tr > span + span { margin-left: .32em; }
/* Plaka kutularina yazilan kucuk harf ekranda buyuk gorunur; sunucu zaten
   normalizePlate ile buyutur. */
#manualPlate, input.plaka-giris { text-transform: uppercase; }
#manualPlate::placeholder, input.plaka-giris::placeholder { text-transform: none; }

/* Ekranda gorunmeyen ama ekran okuyucu ve form icin var olan oge. */
.gorunmez {
  position: absolute !important;
  width: 1px; height: 1px; min-height: 0;
  margin: -1px; padding: 0; border: 0;
  overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%);
  white-space: nowrap; box-shadow: none;
}

/* ===================== ELLE PLAKA (02.10.2026) ============================
   Anlik durumun EN USTUNDE (UX denetimi U7: kutu telefonda y=12.355 px'teydi).
   Masaustunde tek satir: plaka + Giris + Cikis (+ Otomatik). Telefonda plaka
   tam genislik, altinda iki esit yon dugmesi. Yazi 20 px: iOS 16 px altindaki
   kutuya odaklaninca sayfayi buyutur. z-index 10: oneriler alttaki kartlarin
   USTUNE acilir ama yapiskan ust seridin (15) altinda kalir; .plate-entry-panel'in
   50'si seridin ustune binerdi. */
.plate-entry-panel.elle-plaka { z-index: 10; padding-top: 1rem; padding-bottom: .9rem; scroll-margin-top: 6rem; }
.elle-ust { display: flex; flex-wrap: wrap; align-items: baseline; gap: .2rem .8rem; margin-bottom: .65rem; }
.elle-ust h2 { font-size: 1.05rem; }
.elle-ust .help { margin: 0; }
.elle-plaka-form { position: relative; display: flex; flex-wrap: wrap; align-items: stretch; gap: .6rem; }
/* KAYITLI PLAKA ONERISI formun EN ALTINDA acilir (F1): yon dugmelerini ve
   onizlemeyi hicbir genislikte ortmez. Mutlak konum: acilip kapanmasi
   formdaki hicbir dugmeyi yerinden oynatmaz. */
.elle-plaka-form > .plate-suggest { top: calc(100% + 4px); }
.elle-plaka-alan { flex: 1 1 14rem; min-width: 0; }
.elle-plaka-form #manualPlate {
  max-width: none;
  min-height: 52px;
  font-size: 1.25rem;
  font-weight: 700;
}
.elle-yon { display: flex; flex: 0 1 auto; gap: .6rem; }
.elle-yon .yon-dugme { min-height: 52px; min-width: 7.5rem; font-size: 1.05rem; }
.elle-yon .yon-oto { min-height: 52px; font-size: .85rem; font-weight: 650; }
.plaka-onizleme { flex: 1 1 100%; margin: 0; min-height: 1.2em; font-size: .88rem; color: var(--muted); line-height: 1.5; }
.plaka-onizleme:empty { min-height: 0; }
.plaka-onizleme .plate { color: var(--fg); font-weight: 700; font-size: 1rem; }
.plaka-onizleme.hata { color: var(--crit); }
@media (max-width: 700px) {
  .elle-yon { flex: 1 1 100%; display: grid; grid-template-columns: 1fr 1fr; }
  .elle-yon .yon-dugme { min-width: 0; }
  .elle-yon .yon-oto { grid-column: 1 / -1; min-height: 44px; }
}

/* ============ OKUNAMAYAN ETIKETI: ONERI CIPLERI (02.10.2026) ============
   Kutu artik bos gelir (U4); oneriler dokunulan ciplerdir ve kutuyu yalniz
   DOLDURUR. Kesik kenar "henuz secilmedi" der; dokunma hedefi 44 px. */
.plaka-oneri { display: flex; flex-wrap: wrap; align-items: center; gap: .4rem; margin: .35rem 0 .5rem; }
.plaka-oneri > .help { flex: 1 1 100%; margin: 0; font-size: .78rem; }
.plaka-cip {
  display: inline-flex;
  flex-direction: column;
  align-items: flex-start;
  justify-content: center;
  gap: .05rem;
  min-height: 44px;
  padding: .3rem .65rem;
  border: 1px dashed var(--accent-ring);
  border-radius: var(--r-md);
  color: var(--fg);
  background: var(--bg);
  box-shadow: none;
  font-weight: 700;
  text-align: left;
}
.plaka-cip:hover, .plaka-cip:focus-visible { border-style: solid; background: var(--accent-tint); filter: none; }
.plaka-cip .plate { font-size: 1rem; }
.plaka-cip small {
  font-family: "Play", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  font-size: .7rem;
  font-weight: 600;
  letter-spacing: 0;
  color: var(--muted);
}
.plaka-onizleme .plaka-cip { margin: .25rem .35rem 0 0; vertical-align: middle; }
.plaka-tahmin-bilgi { margin: 0 0 .35rem; font-size: .8rem; }
.egitim-form .plaka-onizleme { flex: 1 1 100%; }
/* Diger kameranin olcumu uzak ya da kayitli plaka birebir degil: kirmizi kesik
   kenar "fotografla karsilastir" der; yine de dokunulabilir. */
.plaka-cip.plaka-cip-dikkat { border-color: color-mix(in srgb, var(--crit) 55%, transparent); }
.plaka-cip.plaka-cip-dikkat small { color: var(--crit); }
