/* Kanade Client App — dashboard UI.
   Header + left sidebar nav + switchable content views. Design tokens
   are CSS custom properties so light / dark only re-points a handful of
   variables (see the :root / prefers-color-scheme blocks). */

:root {
  --bg: #f4f4f6;
  --panel: #ffffff;
  --panel-2: #f7f7f9;
  --border: #e3e3e8;
  --text: #1a1a1a;
  --muted: #6b6b72;
  --accent: #5b3a8c; /* baton violet */
  --accent-soft: rgba(91, 58, 140, 0.1);
  --ok: #2e7d32;
  --warn: #8a6d00;
  --fail: #b00020;
  --sidebar-w: 188px;
  --radius: 10px;
}

* {
  box-sizing: border-box;
}

/* `[hidden]` must win over the explicit `display` on components like
   .badge / .dash-card / .view (an author `display` otherwise overrides
   the UA `[hidden]{display:none}` rule and leaks "0" badges / empty
   cards). */
[hidden] {
  display: none !important;
}

html,
body {
  height: 100%;
}

body {
  margin: 0;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Yu Gothic UI",
    Meiryo, Roboto, sans-serif;
  background: var(--bg);
  color: var(--text);
  font-size: 14px;
  line-height: 1.5;
}

#app {
  display: flex;
  flex-direction: column;
  height: 100vh;
}

/* ---- Header ---- */
.app-header {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
  height: 48px;
  padding: 0 16px;
  background: var(--panel);
  border-bottom: 1px solid var(--border);
}

.brand {
  display: flex;
  align-items: center;
  gap: 8px;
  font-weight: 700;
  font-size: 15px;
  letter-spacing: 0.02em;
}

/* タクト (baton) mark — the inline SVG sits on transparent; the
   gradient lives on the baton path itself, so no background tile. */
.brand-mark {
  display: block;
  width: 22px;
  height: 22px;
  flex: none;
}

/* Connection status dot + label. */
.conn {
  display: flex;
  align-items: center;
  gap: 7px;
  font-size: 12px;
  color: var(--muted);
}

.conn-dot {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: #9aa;
  box-shadow: 0 0 0 0 transparent;
}

.conn-connected .conn-dot {
  background: #2e9d4f;
  box-shadow: 0 0 0 3px rgba(46, 157, 79, 0.18);
}

.conn-connecting .conn-dot {
  background: #c9a227;
  box-shadow: 0 0 0 3px rgba(201, 162, 39, 0.18);
}

.conn-disconnected .conn-dot {
  background: #c64141;
  box-shadow: 0 0 0 3px rgba(198, 65, 65, 0.18);
  animation: conn-pulse 1.2s ease-in-out infinite;
}

@keyframes conn-pulse {
  50% {
    opacity: 0.4;
  }
}

/* ---- Layout: sidebar + content ---- */
.layout {
  flex: 1 1 auto;
  display: flex;
  min-height: 0;
}

.sidebar {
  flex: 0 0 var(--sidebar-w);
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 12px 10px;
  background: var(--panel);
  border-right: 1px solid var(--border);
  overflow-y: auto;
}

.nav-item {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: 9px 10px;
  font-size: 13.5px;
  font-weight: 500;
  text-align: left;
  color: var(--text);
  background: transparent;
  border: 0;
  border-radius: 8px;
  cursor: pointer;
}

.nav-item:hover {
  background: var(--panel-2);
}

.nav-item.active {
  background: var(--accent-soft);
  color: var(--accent);
}

.nav-item .nav-icon {
  width: 18px;
  height: 18px;
  flex: 0 0 auto;
  color: currentColor;
}

.nav-label {
  flex: 1 1 auto;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.nav-count {
  font-size: 12px;
}

.nav-badge {
  flex: 0 0 auto;
}

.nav-sep {
  height: 1px;
  margin: 8px 6px;
  background: var(--border);
}

.nav-error {
  padding: 8px 10px;
  font-size: 12px;
}

/* Client build version pinned to the sidebar foot. `margin-top: auto`
   pushes it below the nav items in the flex column; dim + small so it's
   an unobtrusive "what's running" readout (mirrors the SPA sidebar).
   Starts `hidden` in the markup and is revealed by main.ts once filled
   (robust against an HTML formatter breaking a `:empty` rule). */
.sidebar-version {
  /* `margin-top: auto` drops it to the bottom when the nav doesn't fill
     the column; `position: sticky; bottom: 0` keeps it pinned to the
     viewport bottom if the nav ever overflows and scrolls (the job
     categories are injected, so the count isn't fixed). The panel
     background stops scrolling nav items showing through. */
  margin-top: auto;
  position: sticky;
  bottom: 0;
  padding: 8px 10px 2px;
  background: var(--panel);
  font-size: 10px;
  color: var(--muted);
  opacity: 0.7;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.content {
  flex: 1 1 auto;
  min-width: 0;
  padding: 20px 24px;
  overflow-y: auto;
}

.view-title {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 16px;
  font-weight: 700;
  margin: 0 0 14px;
}

.view[hidden] {
  display: none;
}

/* ---- Dashboard cards ---- */
.dash-cards {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: 12px;
}

.dash-card {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 16px;
  text-align: left;
  background: var(--panel);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  cursor: pointer;
}

.dash-card-static {
  cursor: default;
}

button.dash-card:hover {
  border-color: var(--accent);
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.06);
}

.dash-icon {
  width: 26px;
  height: 26px;
  flex: 0 0 auto;
  color: var(--accent);
}

.dash-card-body {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.dash-card-label {
  font-size: 12px;
  color: var(--muted);
}

.dash-card-value {
  font-size: 16px;
  font-weight: 700;
}

.dash-card.ok .dash-card-value {
  color: var(--ok);
}
.dash-card.warn .dash-card-value {
  color: var(--warn);
}
.dash-card.fail .dash-card-value {
  color: var(--fail);
}

/* ---- Health checks (#290) ---- */
ul.checks {
  list-style: none;
  margin: 4px 0 0;
  padding: 0;
}

.check-row {
  display: flex;
  align-items: baseline;
  gap: 8px;
  padding: 10px 0;
  border-top: 1px solid var(--border);
}

.check-row:first-child {
  border-top: 0;
}

.check-icon {
  flex: 0 0 auto;
}

.check-name {
  font-weight: 500;
}

.check-detail {
  flex: 1 1 auto;
  color: var(--muted);
}

.fix-btn {
  margin-left: auto;
  padding: 4px 10px;
  font-size: 13px;
}

.fix-btn[disabled] {
  opacity: 0.5;
  cursor: not-allowed;
}

.status-warn .check-name {
  color: var(--warn);
}
.status-fail .check-name {
  color: var(--fail);
}
.status-unknown .check-name {
  color: var(--muted);
}

/* ---- Job list (#291) ---- */
.job-row {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 10px;
  padding: 12px 0;
  border-top: 1px solid var(--border);
}

.job-row:first-child {
  border-top: 0;
}

.job-icon {
  width: 22px;
  height: 22px;
  flex: 0 0 auto;
  color: var(--accent);
  object-fit: contain;
}

.job-name {
  font-weight: 500;
}

.job-desc {
  flex: 1 1 100%;
  margin-left: 32px;
  color: var(--muted);
  font-size: 13px;
}

.job-run-btn {
  margin-left: auto;
  padding: 5px 16px;
  font-size: 13px;
}

/* ---- Run status panel (#291) ---- */
.runs-panel {
  margin-top: 20px;
  padding-top: 16px;
  border-top: 1px solid var(--border);
}

.runs-panel[hidden] {
  display: none;
}

.run-row {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 8px;
  padding: 8px 0;
  border-top: 1px solid var(--border);
}

.run-row:first-child {
  border-top: 0;
}

.run-icon {
  flex: 0 0 auto;
}

.run-name {
  font-weight: 500;
}

.run-status {
  flex: 1 1 auto;
}

.kill-btn {
  margin-left: auto;
  padding: 4px 10px;
  font-size: 13px;
}

.run-output {
  flex: 1 0 100%;
  margin: 4px 0 0;
  padding: 8px;
  max-height: 160px;
  overflow: auto;
  background: var(--panel-2);
  border: 1px solid var(--border);
  border-radius: 6px;
  font-size: 12px;
  white-space: pre-wrap;
  overflow-wrap: break-word;
}

.run-row.status-completed .run-status {
  color: var(--ok);
}
.run-row.status-failed .run-status,
.run-row.status-killed .run-status {
  color: var(--fail);
}

/* ---- Notifications (#102) ---- */
.badge {
  display: inline-block;
  min-width: 18px;
  padding: 0 6px;
  font-size: 11px;
  font-weight: 700;
  line-height: 18px;
  text-align: center;
  color: #fff;
  background: var(--fail);
  border-radius: 999px;
  vertical-align: middle;
}

.notif-row {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  padding: 12px 0;
  border-top: 1px solid var(--border);
}

.notif-row:first-child {
  border-top: 0;
}

.notif-icon {
  flex: 0 0 auto;
  line-height: 1.4;
}

.notif-main {
  flex: 1 1 auto;
  min-width: 0;
}

.notif-head {
  display: flex;
  align-items: baseline;
  gap: 8px;
}

/* The title row is the click target that expands/collapses the body. */
.notif-toggle {
  cursor: pointer;
  user-select: none;
}

/* Unread marker — a small dot before the title; cleared once read/acked. */
.notif-dot {
  flex: 0 0 auto;
  align-self: center;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--accent);
}

.notif-row.priority-warn .notif-dot {
  background: var(--warn);
}

.notif-row.priority-emergency .notif-dot {
  background: var(--fail);
}

.notif-title {
  font-weight: 600;
}

.notif-prio {
  font-size: 12px;
}

/* Chevron pushed to the right of the title row; rotates when expanded. */
.notif-chevron {
  margin-left: auto;
  flex: 0 0 auto;
  align-self: center;
  font-size: 12px;
  color: var(--muted);
  transition: transform 0.15s ease;
}

.notif-row.expanded .notif-chevron {
  transform: rotate(90deg);
}

/* Body + meta collapse away until the row is expanded. */
.notif-collapse {
  display: none;
}

.notif-row.expanded .notif-collapse {
  display: block;
}

.notif-text {
  margin: 2px 0 0;
  white-space: pre-wrap;
  overflow-wrap: break-word;
}

.notif-meta {
  margin: 4px 0 0;
  font-size: 12px;
}

.notif-row.acked {
  opacity: 0.6;
}

.notif-row.priority-warn .notif-title {
  color: var(--warn);
}

.notif-row.priority-emergency .notif-title {
  color: var(--fail);
}

.notif-row.notif-flash {
  animation: notif-flash 2s ease-out;
}

@keyframes notif-flash {
  0%,
  40% {
    background: rgba(176, 0, 32, 0.18);
  }
  100% {
    background: transparent;
  }
}

.notif-ack-btn {
  flex: 0 0 auto;
  padding: 4px 12px;
  font-size: 13px;
}

.notif-acked {
  flex: 0 0 auto;
  font-size: 12px;
}

/* All notifications surface as native OS toasts (#102/#635) — no in-app
   toast or blocking-modal styles live here anymore. */

/* ---- Shared ---- */
.muted {
  color: var(--muted);
}

.error {
  color: var(--fail);
}

button {
  padding: 6px 14px;
  font-size: 14px;
  background: var(--accent);
  color: #fff;
  border: 0;
  border-radius: 6px;
  cursor: pointer;
}

button:hover {
  background: #4a2f73;
}

/* Reset for the structural buttons that aren't "primary" actions. */
.nav-item,
.dash-card {
  background: transparent;
}

button.nav-item:hover,
button.dash-card:hover {
  background: var(--panel-2);
}

button.nav-item.active:hover {
  background: var(--accent-soft);
}

/* ---- Dark theme ---- */
@media (prefers-color-scheme: dark) {
  :root {
    --bg: #17171a;
    --panel: #1f1f23;
    --panel-2: #26262b;
    --border: #33333a;
    --text: #f0f0f2;
    --muted: #a2a2ab;
    --accent: #b89be0;
    --accent-soft: rgba(184, 155, 224, 0.16);
    --ok: #7cc47f;
    --warn: #e0b341;
    --fail: #ff6b6b;
  }

  button:hover {
    background: #9f7fd0;
  }

  .badge {
    background: #b00020;
  }
}
