/* ═══════════════════════════════════════════
   CrescoDB Design System — theme.css
   Shared across all pages
═══════════════════════════════════════════ */
/* Self-hosted webfonts.

   These used to be an @import from fonts.googleapis.com, which the dashboard's
   OWN Content-Security-Policy blocked twice over: style-src has no
   fonts.googleapis.com, and font-src is 'self' data:, so even a stylesheet that
   loaded could not have fetched the files. Every user of the hosted dashboard
   was reading it in fallback system fonts.

   Serving them from /app keeps `default-src 'self'` intact — widening the CSP
   for a third-party CDN would spend the exact property the policy exists for —
   and removes a render-blocking request to someone else's origin.

   DM Sans and DM Mono are SIL Open Font License 1.1. Subset to latin +
   latin-ext, which is what the shipped Google CSS served anyway. */
@font-face {
  font-family: 'DM Mono';
  font-style: normal;
  font-weight: 300;
  font-display: swap;
  src: url('../fonts/DMMono-300-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: 'DM Mono';
  font-style: normal;
  font-weight: 300;
  font-display: swap;
  src: url('../fonts/DMMono-300-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: 'DM Mono';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('../fonts/DMMono-400-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: 'DM Mono';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('../fonts/DMMono-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: 'DM Mono';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('../fonts/DMMono-500-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: 'DM Mono';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('../fonts/DMMono-500-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: 'DM Sans';
  font-style: normal;
  font-weight: 300;
  font-display: swap;
  src: url('../fonts/DMSans-300-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: 'DM Sans';
  font-style: normal;
  font-weight: 300;
  font-display: swap;
  src: url('../fonts/DMSans-300-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: 'DM Sans';
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url('../fonts/DMSans-400i-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: 'DM Sans';
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url('../fonts/DMSans-400i-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: 'DM Sans';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('../fonts/DMSans-400-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: 'DM Sans';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('../fonts/DMSans-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: 'DM Sans';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('../fonts/DMSans-500-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: 'DM Sans';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('../fonts/DMSans-500-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: 'DM Sans';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url('../fonts/DMSans-600-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: 'DM Sans';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url('../fonts/DMSans-600-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: 'DM Sans';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url('../fonts/DMSans-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: 'DM Sans';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url('../fonts/DMSans-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;
}

:root {
  /* Onyx / carbon-black + lime — Resend-style: near-black neutrals, subtle
     white-alpha borders (the soft glow edge), lime as the primary accent. */
  --bg:        #0a0a0c;
  --surface:   #121214;
  --surface2:  #18181b;
  --surface3:  #222226;
  --border:    #ffffff14;
  --border2:   #ffffff26;
  --accent:    #bef264;   /* lime */
  --accent2:   #34d399;   /* mint/teal — success */
  --accent3:   #ff5470;   /* red — danger */
  --accent4:   #ffb547;   /* amber — warn */
  --txt:       #f4f4f6;
  /* Lifted Oct 2026: #a1a1aa / #6b6b76 left the small print at 3.8:1. */
  --txt2:      #b1b1ba;
  --txt3:      #8a8a96;
  /* Fills are kept apart from the text accent (as on the website): the accent
     the user picks is a good button in both themes, but on white it is
     unreadable as text, so main.js darkens --accent there and leaves
     --accent-fill alone. */
  --accent-fill: #bef264;
  --accent-fill-hover: #d2f96e;
  --on-accent: #0b0b0d;
  /* The one shadow: menus, dialogs, drawers. Nothing else floats. */
  --pop: 0 8px 24px rgba(0,0,0,.4);
  /* Flat, Oct 2026 ("think Coolify"): small, consistent corners. */
  --r:         6px;
  --r-sm:      4px;
  --r-xs:      3px;
  color-scheme: dark;     /* scrollbars and form controls match */
  --sidebar:   248px;
  --topbar:    56px;
}

/* Light theme — toggled via html[data-theme="light"] (Settings → Appearance).
   Accent stays user-configurable (set inline by the accent picker). */
[data-theme="light"] {
  --bg:        #f7f8f5;
  --surface:   #ffffff;
  --surface2:  #f1f3ec;
  --surface3:  #e7ebdd;
  --border:    #e4e6dd;
  --border2:   #d4d8c7;
  --accent:    #4d7c0f;   /* darker lime — readable on white */
  /* Status colours at their dark-theme brightness were 1.7-2.4:1 on white. */
  --accent2:   #047857;
  --accent3:   #c81e45;
  --accent4:   #a15c07;
  --txt:       #14140f;
  --txt2:      #4a4b41;
  --txt3:      #66675c;   /* was #8c8d80, 3.3:1 on this background */
  color-scheme: light;
  --pop: 0 6px 20px rgba(20,20,30,.10);
}

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

body {
  font-family: 'DM Sans', sans-serif;
  background: var(--bg); color: var(--txt);
  display: flex; overflow: hidden; font-size: 14px;
}
/* Film grain — the same material as the marketing site, dialled down further
   because this is a tool you stare at all day, not a page you scroll once.
   pointer-events:none so it can never intercept a click. */
body::after {
  content: ''; position: fixed; inset: 0; z-index: 9999; pointer-events: none; opacity: .022;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* Scrollbars — BOTH APIs on purpose.
   Chromium ignores the ::-webkit-scrollbar pseudo-elements the moment an element
   also specifies the standard `scrollbar-width`/`scrollbar-color` (and Firefox
   never supported the pseudo-elements at all), so styling only one of them left
   some panes — the AI conversation rail, the sidebar nav — falling back to the
   chunky native bar while everything else looked custom. Declaring the standard
   properties globally makes every scroll area agree across engines. */
* { scrollbar-width: thin; scrollbar-color: var(--border2) transparent; }
::-webkit-scrollbar { width: 5px; height: 5px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: var(--border2); border-radius: 10px; }
::-webkit-scrollbar-thumb:hover { background: var(--txt3); }
::-webkit-scrollbar-corner { background: transparent; }

.glow {
  position: fixed; pointer-events: none; border-radius: 50%;
  filter: blur(80px); opacity: .05; z-index: 0;
}

/* ── SIDEBAR ── */
.sidebar {
  width: var(--sidebar); min-width: var(--sidebar); height: 100vh;
  background: var(--surface); border-right: 1px solid var(--border);
  display: flex; flex-direction: column; z-index: 10; flex-shrink: 0;
}
.sidebar-logo {
  display: flex; align-items: center; gap: 12px;
  padding: 20px 20px 16px; border-bottom: 1px solid var(--border); flex-shrink: 0;
}
.logo-icon {
  width: 36px; height: 36px; flex-shrink: 0;
  /* The real CrescoDB mark, rendered as a mask so it follows the live --accent
     (incl. a user's custom accent). The literal "C" in the markup is hidden. */
  background: var(--accent-fill); color: transparent; font-size: 0;
  -webkit-mask: url('../img/favicon.svg') center/contain no-repeat;
  mask: url('../img/favicon.svg') center/contain no-repeat;
}
.logo-text strong { font-size: 15px; font-weight: 700; color: var(--txt); letter-spacing: -.3px; display: block; }
.logo-text span   { font-size: 11px; color: var(--txt3); font-family: 'DM Mono', monospace; }
.sidebar-section  { padding: 16px 12px 8px; }
.sidebar-label {
  font-size: 10px; font-weight: 600; text-transform: uppercase;
  letter-spacing: 1px; color: var(--txt3); padding: 0 8px 8px;
}
.nav-item {
  display: flex; align-items: center; gap: 10px; padding: 10px 12px;
  border-radius: var(--r-sm); cursor: pointer; color: var(--txt2);
  font-size: 13.5px; font-weight: 500; transition: all .18s;
  margin-bottom: 2px; position: relative; text-decoration: none;
}
.nav-item:hover  { background: var(--surface2); color: var(--txt); }
.nav-item.active { background: var(--surface3); color: var(--accent); }
.nav-item.active::before {
  content: ''; position: absolute; left: 0; top: 50%; transform: translateY(-50%);
  width: 3px; height: 20px; background: var(--accent); border-radius: 0 3px 3px 0;
}
.nav-icon { width: 16px; height: 16px; flex-shrink: 0; opacity: .85; }
.nav-item.active .nav-icon { opacity: 1; }
.nav-badge {
  margin-left: auto; background: var(--surface3); color: var(--txt3);
  font-size: 10px; font-family: 'DM Mono', monospace;
  padding: 2px 6px; border-radius:var(--r-sm); border: 1px solid var(--border);
}
.nav-item.active .nav-badge { background: var(--surface3); color: var(--accent); border-color: var(--border2); }
/* Nav sections scroll; the bottom block (project + log out) is always pinned
   on-screen. Thin scrollbar so it doesn't look heavy. */
.sidebar-nav { flex: 1; overflow-y: auto; min-height: 0; scrollbar-width: thin; }
.sidebar-bottom { margin-top: auto; border-top: 1px solid var(--border); padding: 14px 12px; flex-shrink: 0; }
.db-status {
  display: flex; align-items: center; gap: 10px; padding: 10px 12px;
  background: var(--surface2); border-radius: var(--r-sm); border: 1px solid var(--border);
}
.db-dot { width: 6px; height: 6px; border-radius: 50%; background: var(--accent2); flex-shrink: 0; }
.db-name { font-size: 12.5px; font-weight: 600; color: var(--txt); }
.db-sub  { font-size: 10px; color: var(--txt3); font-family: 'DM Mono', monospace; }
.sidebar-logout {
  display: flex; align-items: center; justify-content: center; gap: 8px; width: 100%;
  margin-top: 10px; padding: 9px 12px; font-size: 12.5px; font-weight: 600;
  color: var(--txt3); background: transparent; border: 1px solid var(--border);
  border-radius: var(--r-sm); cursor: pointer; transition: color .15s, border-color .15s, background .15s;
}
.sidebar-logout:hover { color: var(--accent3); border-color: var(--accent3); background: rgba(255,84,112,.07); }

/* ── COLLAPSIBLE SIDEBAR ──────────────────────────────────────────────────
   Shrinks the rail to icons and hands ~184px back to the page, which is the
   difference between a table being readable on a 13" laptop and not. The
   preference persists (nav.js applies it before the sidebar is built, so there
   is no flash of the wide rail on load).

   Desktop only. Below 820px the sidebar is already an off-canvas drawer, so a
   second control doing the same job would just be confusing. */
.sidebar-collapse {
  margin-left: auto; flex-shrink: 0;
  width: 28px; height: 28px; display: inline-flex; align-items: center; justify-content: center;
  background: none; border: 1px solid var(--border); border-radius: var(--r-sm);
  color: var(--txt3); cursor: pointer; padding: 0;
  transition: color .15s, border-color .15s;
}
.sidebar-collapse:hover { color: var(--txt); border-color: var(--border2); }
.sidebar-collapse svg { width: 14px; height: 14px; }

@media (min-width: 821px) {
  html.sidebar-collapsed .sidebar { width: 64px; min-width: 64px; }
  /* Everything that is words rather than a glyph. The icons stay; `title`
     carries the label, which nav.js sets on every item. */
  html.sidebar-collapsed .logo-text,
  html.sidebar-collapsed .sidebar-label,
  html.sidebar-collapsed .nav-text,
  html.sidebar-collapsed .nav-badge,
  html.sidebar-collapsed .db-status > div:not(.db-dot) { display: none; }

  /* Centre what is left, and keep the touch target the same height so the rail
     does not visibly reflow when it collapses. */
  html.sidebar-collapsed .sidebar-logo { padding: 20px 0 16px; justify-content: center; gap: 0; }
  html.sidebar-collapsed .sidebar-collapse { margin-left: 0; }
  html.sidebar-collapsed .logo-icon { display: none; }
  html.sidebar-collapsed .sidebar-section { padding: 12px 8px 6px; }
  html.sidebar-collapsed .nav-item { justify-content: center; padding: 10px 0; gap: 0; }
  html.sidebar-collapsed .sidebar-bottom { padding: 12px 8px; }
  html.sidebar-collapsed .db-status { justify-content: center; padding: 10px 0; }
  html.sidebar-collapsed .sidebar-logout { padding: 9px 0; }
  /* The active marker is the only thing left distinguishing the current page,
     so it stays — but flush to the rail edge rather than floating. */
  html.sidebar-collapsed .nav-item.active::before { left: 0; }
}

/* ── MAIN + TOPBAR ── */
.main { flex: 1; display: flex; flex-direction: column; overflow: hidden; min-width: 0; }
.topbar {
  height: var(--topbar); min-height: var(--topbar); border-bottom: 1px solid var(--border);
  display: flex; align-items: center; padding: 0 24px; gap: 12px;
  background: var(--surface); flex-shrink: 0; z-index: 5;
}
.search-box {
  display: flex; align-items: center; gap: 10px; background: var(--surface2);
  border: 1px solid var(--border); border-radius: var(--r-sm);
  padding: 0 14px; height: 36px; flex: 0 0 340px; transition: border-color .18s;
}
.search-box:focus-within { border-color: var(--accent); }
.search-box input { background: none; border: none; outline: none; color: var(--txt); font-family: 'DM Sans', sans-serif; font-size: 13px; width: 100%; height: 100%; }
.search-box { cursor: text; } /* the whole box is the tap target, not just the 17px line of text */
.search-box input::placeholder { color: var(--txt3); }
.kbd { font-family: 'DM Mono', monospace; font-size: 10px; color: var(--txt3); background: var(--surface3); border: 1px solid var(--border2); border-radius: 4px; padding: 1px 5px; flex-shrink: 0; }
.topbar-right { margin-left: auto; display: flex; align-items: center; gap: 10px; }
.content { flex: 1; overflow-y: auto; padding: 28px; position: relative; z-index: 1; }

/* ── BUTTONS ── */
.btn { height: 36px; padding: 0 16px; border-radius: var(--r-sm); font-family: 'DM Sans', sans-serif; font-size: 13px; font-weight: 600; cursor: pointer; border: none; display: inline-flex; align-items: center; gap: 7px; transition: all .18s; white-space: nowrap; text-decoration: none; }
/* No coloured halo. A button that emits light is a toy affordance; contrast is
   what makes a primary action read as primary. */
.btn-primary { background: var(--accent-fill); color: var(--on-accent); }
.btn-primary:hover { background: var(--accent-fill-hover); }
.btn-ghost   { background: transparent; color: var(--txt2); border: 1px solid var(--border); }
.btn-ghost:hover { border-color: var(--border2); color: var(--txt); }
.btn-outline { background: transparent; color: var(--accent); border: 1px solid var(--border); }
.btn-outline:hover { background: var(--surface3); }
.btn-danger  { background: rgba(255,77,106,.1); color: var(--accent3); border: 1px solid rgba(255,77,106,.3); }
.btn-danger:hover  { background: rgba(255,77,106,.2); }
.btn-success { background: rgba(52,211,153,.1); color: var(--accent2); border: 1px solid rgba(52,211,153,.3); }
.btn-success:hover { background: rgba(52,211,153,.2); }
.btn-sm { height: 30px; padding: 0 12px; font-size: 12px; }

.icon-btn { width: 36px; height: 36px; border-radius: var(--r-sm); border: 1px solid var(--border); background: var(--surface2); cursor: pointer; display: flex; align-items: center; justify-content: center; color: var(--txt2); transition: all .18s; }
.icon-btn:hover { border-color: var(--border2); color: var(--txt); }
/* Flat neutral, not a lime→mint gradient. Gradient avatars are decoration on a
   surface that only needs to identify you. */
.avatar { width: 32px; height: 32px; border-radius: 50%; background: var(--surface3); display: flex; align-items: center; justify-content: center; font-size: 12px; font-weight: 600; color: var(--txt2); cursor: pointer; border: 1px solid var(--border2); flex-shrink: 0; }
.acct-link { display: block; padding: 11px 14px; font-size: 13px; color: var(--txt); text-decoration: none; cursor: pointer; border-top: 1px solid var(--border); }
.acct-link:hover { background: var(--surface2); }
.avatar img, .profile-av-big img { width: 100%; height: 100%; border-radius: 50%; object-fit: cover; display: block; }

/* Compact mode (Settings → Appearance) — tighter density across the dashboard */
body.compact .settings-card { padding: 15px; margin-bottom: 11px; }
body.compact .setting-row { padding: 9px 0; }
body.compact table td, body.compact table th { padding-top: 5px; padding-bottom: 5px; }
body.compact .nav-item { padding-top: 6px; padding-bottom: 6px; }
body.compact .card { padding: 14px; }

/* segmented currency toggle (₦ / $) — dashboard Billing */
/* Squared off to match the rest of the system — a capsule segmented control was
   the last rounded-pill shape left in the dashboard. */
.cur-toggle { display: inline-flex; background: var(--surface2); border: 1px solid var(--border); border-radius: var(--r-sm); padding: 3px; gap: 2px; }
.cur-opt { border: none; background: transparent; color: var(--txt2); font-family: inherit; font-weight: 600; font-size: 13px; padding: 6px 16px; border-radius: var(--r-xs); cursor: pointer; transition: background .15s, color .15s; }
.cur-opt:hover { color: var(--txt); }
.cur-opt.active { background: var(--accent-fill); color: var(--on-accent); }

/* ── HELPERS ── */
.page-title { font-size: 22px; font-weight: 700; letter-spacing: -.4px; }
.page-sub   { font-size: 13px; color: var(--txt2); margin-top: 3px; }
.card { background: var(--surface); border: 1px solid var(--border); border-radius: var(--r); padding: 20px 22px; transition: border-color .2s; }
.card:hover { border-color: var(--border2); }
.section-header { display: flex; align-items: center; justify-content: space-between; margin: 24px 0 14px; }
.section-title { font-size: 15px; font-weight: 600; }
.section-link  { font-size: 12px; color: var(--accent); cursor: pointer; font-weight: 500; }
.tab-bar { display: flex; gap: 2px; border-bottom: 1px solid var(--border); }
.tab { padding: 9px 16px; font-size: 13px; font-weight: 500; color: var(--txt3); cursor: pointer; border-bottom: 2px solid transparent; transition: all .15s; margin-bottom: -1px; }
.tab:hover { color: var(--txt2); }
.tab.active { color: var(--accent); border-bottom-color: var(--accent); }

/* ── STATUS LABELS (formerly capsule "badges") ──
   Retired the rounded capsule: a coloured dot plus flat coloured type says the
   same thing with less furniture, and capsule chips are the visual signature of
   template output. Redefined at the CLASS level so every existing .badge call
   site inherits the flat treatment without being rewritten. Matches .cl-status,
   which the Cloud screens already use. */
/* ── INLINE ACTION ICONS ──
   Row-level controls (delete a row, drop a column, "needs a token") used to be
   emoji — 🗑 and 🔒 — i.e. another vendor's coloured artwork sitting in a data
   table at whatever weight that OS happened to ship. They're drawn icons now,
   and these rules put them on the text baseline and give them a hit area, which
   an emoji glyph got for free and an inline <svg> does not. */
.row-del, .col-del { display: inline-flex; align-items: center; justify-content: center; width: 22px; height: 22px; border-radius: var(--r-xs); transition: color .15s, background .15s; }
.row-del:hover, .col-del:hover { color: var(--accent3) !important; background: var(--surface2); }
.row-del svg, .col-del svg { width: 14px; height: 14px; }

.badge { display: inline-flex; align-items: center; gap: 6px; padding: 0; border: 0; background: none; border-radius: 0; font-size: 11px; font-weight: 700; font-family: 'DM Mono', monospace; letter-spacing: .4px; text-transform: uppercase; }
.badge::before { content: ''; width: 6px; height: 6px; border-radius: 50%; background: currentColor; flex: none; }
.b-green  { color: var(--accent2); }
.b-yellow { color: var(--accent4); }
.b-red    { color: var(--accent3); }
.b-purple { color: var(--accent);  }
/* Markup that already renders its own dot (migrations) — hide the generated one. */
.badge .b-dot { display: none; }

/* ── METHOD LABELS ──
   Five tinted, bordered, differently-coloured boxes was the single loudest
   source of "rainbow" in the API views. Method colour-coding IS a real
   convention (Postman/Swagger/Stripe docs), so the signal is kept — but as
   DESATURATED TEXT with no box: no background, no border. Only DELETE stays
   distinctly warm, because it's the one that's actually destructive. */
.method { font-family: 'DM Mono', monospace; font-size: 10.5px; font-weight: 700; padding: 4px 0; flex-shrink: 0; width: 54px; text-align: left; letter-spacing: .6px; background: none; border: 0; }
.m-get    { color: #8fb8a0; }  /* muted sage  */
.m-post   { color: #a5b4c8; }  /* cool grey-blue */
.m-put    { color: #c9a882; }  /* muted tan   */
.m-patch  { color: #c9a882; }
.m-delete { color: #cf8b96; }  /* muted rose — the destructive one */

/* ── TYPE LABELS ──
   Was five tinted boxes in five unrelated hues (`.c-int` managed a LIME
   background with PURPLE text). A column's type is reference information, not a
   status — it doesn't need to compete with the data. All neutral now. */
.chip { font-family: 'DM Mono', monospace; font-size: 9.5px; font-weight: 600; padding: 2px 6px; border-radius: 3px; letter-spacing: .5px; background: var(--surface2); color: var(--txt3); border: 1px solid var(--border); }
.c-int, .c-text, .c-bool, .c-uuid, .c-date { background: var(--surface2); color: var(--txt3); }

/* ── CODE ── */
.code-block { background: var(--surface2); border-radius: var(--r-sm); padding: 16px 18px; font-family: 'DM Mono', monospace; font-size: 12px; line-height: 1.75; overflow-x: auto; color: var(--txt); border: 1px solid var(--border); }
.code-label { font-size: 10px; font-weight: 700; text-transform: uppercase; letter-spacing: 1px; color: var(--txt3); margin-bottom: 8px; font-family: 'DM Mono', monospace; display: flex; align-items: center; justify-content: space-between; }
.copy-btn { font-size: 10px; color: var(--accent); cursor: pointer; display: flex; align-items: center; gap: 4px; }
.copy-btn:hover { color: #a097fd; }

/* ── SYNTAX ──
   Was TEN highly-saturated hues (lime, mint, spring green, amber, hot pink,
   cornflower…) — code lit up like a Christmas tree and nothing read as more
   important than anything else. Now ONE low-saturation family of four, the
   register every serious editor theme settles on (GitHub Dimmed, Vercel,
   Supabase): cool grey-blue keywords, sage types, olive strings, tan numbers.
   Punctuation and comments recede into the greys. */
.sk{color:#a5b4c8;font-weight:600}   /* keyword    */
.st{color:#8fb8a0}                   /* type       */
.ss{color:#a3b899}                   /* string     */
.sf{color:#c9a882}                   /* number     */
.sc{color:var(--txt3);font-style:italic}
.sb{color:var(--txt2)}               /* punctuation */
.jk{color:#a5b4c8} .jv{color:#a3b899} .jn{color:#c9a882} .jb{color:var(--txt2)}

/* ── FORMS ── */
.form-label { font-size: 12px; font-weight: 600; color: var(--txt2); margin-bottom: 7px; display: block; }
.form-sub   { font-size: 11px; color: var(--txt3); margin-top: 5px; }
.form-input { width: 100%; background: var(--surface2); border: 1px solid var(--border); border-radius: var(--r-sm); padding: 10px 14px; font-family: 'DM Sans', sans-serif; font-size: 13px; color: var(--txt); outline: none; transition: border-color .18s; }
.form-input:focus { border-color: var(--accent); }
.form-input::placeholder { color: var(--txt3); }
.form-mono { font-family: 'DM Mono', monospace !important; font-size: 12px !important; }
select.form-input option { background: var(--surface2); }

/* ── TOGGLE ── */
.toggle { position: relative; width: 40px; height: 22px; flex-shrink: 0; }
.toggle input { opacity: 0; width: 0; height: 0; position: absolute; }
.toggle-track { position: absolute; inset: 0; background: var(--surface3); border-radius: 11px; cursor: pointer; transition: .25s; border: 1px solid var(--border2); }
.toggle input:checked ~ .toggle-track { background: var(--accent-fill); border-color: var(--accent-fill); }
.toggle-track::before { content: ''; position: absolute; left: 3px; top: 50%; transform: translateY(-50%); width: 14px; height: 14px; border-radius: 50%; background: #fff; transition: .25s; box-shadow: none; }
.toggle input:checked ~ .toggle-track::before { left: 21px; }

/* ── DATA TABLE ── */
.data-table-wrap { background: var(--surface); border: 1px solid var(--border); border-radius: var(--r); overflow: hidden; }
table { width: 100%; border-collapse: collapse; }
thead tr { background: var(--surface2); }
th { padding: 11px 16px; text-align: left; font-size: 11px; font-weight: 600; color: var(--txt3); text-transform: uppercase; letter-spacing: .6px; border-bottom: 1px solid var(--border); white-space: nowrap; }
.col-hdr { display: flex; align-items: center; gap: 7px; }
tbody tr { border-bottom: 1px solid var(--border); transition: background .12s; cursor: pointer; }
tbody tr:last-child { border-bottom: none; }
tbody tr:hover { background: var(--surface2); }
td { padding: 12px 16px; font-size: 13px; color: var(--txt); }
.td-id   { font-family: 'DM Mono', monospace; color: var(--accent); font-size: 12px; }
.td-mono { font-family: 'DM Mono', monospace; font-size: 12px; }
.td-null { color: var(--txt3); font-style: italic; font-family: 'DM Mono', monospace; font-size: 12px; }
.bool-pill { display: inline-flex; align-items: center; gap: 5px; font-family: 'DM Mono', monospace; font-size: 12px; }
.bool-dot  { width: 6px; height: 6px; border-radius: 50%; }
.bt .bool-dot { background: var(--accent2); } .bt { color: var(--accent2); }
.bf .bool-dot { background: var(--accent3); } .bf { color: var(--txt3); }
.tbl-footer { display: flex; align-items: center; justify-content: space-between; padding: 12px 16px; border-top: 1px solid var(--border); background: var(--surface2); font-size: 12px; color: var(--txt3); }
.pager { display: flex; gap: 6px; }
.pg-btn { width: 28px; height: 28px; border-radius: var(--r-xs); border: 1px solid var(--border); background: var(--surface); display: flex; align-items: center; justify-content: center; cursor: pointer; color: var(--txt2); font-size: 13px; transition: all .15s; }
.pg-btn:hover, .pg-btn.cur { border-color: var(--accent); color: var(--accent); background: var(--surface3); }
.checkbox-cell { width: 15px; height: 15px; border-radius: 4px; border: 1.5px solid var(--border2); cursor: pointer; display: block; }

code { font-family: 'DM Mono', monospace; background: var(--surface3); padding: 1px 6px; border-radius: 4px; font-size: 12px; color: var(--accent); }

@keyframes pulse  { 0%,100%{opacity:1} 50%{opacity:.4} }
@keyframes fadeIn { from{opacity:0;transform:translateY(8px)} to{opacity:1;transform:translateY(0)} }
.fi   { animation: fadeIn .22s ease forwards; }
.fi-1 { animation: fadeIn .22s .05s ease both; }
.fi-2 { animation: fadeIn .22s .10s ease both; }
.fi-3 { animation: fadeIn .22s .15s ease both; }
/* ── RESPONSIVE (phones + small tablets) ─────────────────────────────────────
   The dashboard is desktop-first; below 820px the sidebar becomes an
   off-canvas drawer (hamburger in the topbar toggles body.nav-open — wired in
   components/nav.js) and the fixed-width search stretches instead. */
.nav-toggle {
  display: none; align-items: center; justify-content: center;
  width: 36px; height: 36px; flex-shrink: 0; color: var(--txt2);
  background: var(--surface2); border: 1px solid var(--border);
  border-radius: var(--r-sm); cursor: pointer;
}
.nav-toggle:hover { color: var(--txt); border-color: var(--txt3); }

@media (max-width: 820px) {
  .nav-toggle { display: flex; }
  .sidebar {
    position: fixed; left: 0; top: 0; bottom: 0; height: 100dvh;
    transform: translateX(-105%); transition: transform .22s ease;
    box-shadow: var(--pop);
  }
  body.nav-open .sidebar { transform: translateX(0); }
  .topbar { padding: 0 12px; gap: 8px; flex-wrap: nowrap; }
  /* The search wrapper carries an inline flex-basis of 340px — stretch it. */
  .topbar-search { flex: 1 1 auto !important; min-width: 0; }
  .kbd { display: none; }
  .content { padding: 14px; }
  /* Wide data tables scroll inside themselves instead of pushing the page. */
  .content table { display: block; overflow-x: auto; }
}

@media (max-width: 640px) {
  .page-title { font-size: 18px; }
  .content { padding: 12px; }
  /* Project switcher: keep the name, drop the mono URL to save width. */
  #projBtn span.mono, #projBtn span[style*="DM Mono"] { display: none; }
}

@media (max-width: 640px) {
  /* Topbar space budget on phones: drop the Docs icon, ellipsize the project
     name, and guarantee the search box a usable width. */
  .icon-btn[title="Docs"] { display: none; }
  #projBtn { max-width: 140px; }
  #projBtnName { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 88px; }
  .topbar-search { min-width: 120px; }
}

@media (max-width: 380px) {
  /* Ultra-narrow (320-class) screens: the 640px budget still overflows by
     ~40px — tighten every fixed-width piece so the row fits without pushing
     the avatar off-screen. */
  .topbar { gap: 6px; padding: 0 10px; }
  #projBtn { max-width: 96px; padding: 6px 8px !important; }
  #projBtnName { max-width: 52px; }
  .topbar-search { min-width: 0; }
  .topbar-search .search-box { padding: 6px 8px; }
  .topbar-right { gap: 6px !important; }
  .avatar { width: 28px; height: 28px; }
}

/* ── In-page rail drawer (phones) ─────────────────────────────────────────────
   Tool pages (Tables, SQL, API, Settings, AI) keep a side rail — a table list,
   settings sections, endpoints, suggestions. On phones that rail becomes a
   SECOND off-canvas drawer opened by an IN-FLOW toggle bar above the layout
   (injected by components/nav.js), instead of squeezing everything into one
   long column. In flow means it pushes content down and can never sit on top
   of information — the floating-pill approach it replaces could. */
.rail-toggle { display: none; }

@media (max-width: 820px) {
  /* Scrim behind whichever drawer is open; tap it to close (nav.js). */
  body.nav-open::after, body.rail-open::after {
    content: ''; position: fixed; inset: 0; background: rgba(0,0,0,.45); z-index: 34;
  }
  .sidebar { z-index: 50; }

  .page-rail {
    position: fixed !important; top: 0; bottom: 0; left: 0; height: 100dvh;
    width: min(320px, 85vw) !important; min-width: 0 !important; max-width: 85vw !important;
    z-index: 40; transform: translateX(-105%); transition: transform .22s ease;
    background: var(--surface); border-right: 1px solid var(--border);
    overflow-y: auto; box-shadow: var(--pop);
  }
  body.rail-open .page-rail { transform: translateX(0); }

  .rail-toggle {
    display: flex; align-items: center; gap: 9px;
    min-height: 44px; padding: 10px 14px; margin: 10px 12px;
    background: var(--surface); color: var(--txt);
    border: 1px solid var(--border); border-radius: var(--r-sm); cursor: pointer;
    font-family: 'DM Sans', sans-serif; font-size: 13px; font-weight: 600;
  }
  .rail-toggle:active { background: var(--surface2); }
  .rail-toggle .rt-chev { margin-left: auto; color: var(--txt3); }
  /* The tool-page layouts hard-code height:calc(100vh - topbar) for desktop;
     with the bar now in flow above them that math overshoots the viewport, so
     the layout flexes into whatever .main has left instead. (+ * is exact: the
     bar is inserted immediately before the layout element.) */
  .rail-toggle + * { height: auto !important; flex: 1 !important; min-height: 0 !important; }
}

@media (max-width: 640px) {
  /* Page-local stat strips (realtime, logs, migrations, users, dashboard):
     4-across becomes 2-across on phones — readable without clipping. */
  .rt-stats, .log-stats, .mig-stats, .acc-grid, .stat-grid, .qa-grid {
    grid-template-columns: repeat(2, 1fr) !important;
  }
  /* An ODD number of cards in a 2-across grid leaves the last one stranded at
     half width on its own row, which reads as a layout bug rather than a
     design. The dashboard's stat strip is exactly this case: 3 cards → 2 + 1
     orphan. Span the leftover so the block closes properly. No effect on the
     4-card strips, where nothing is left over. */
  .rt-stats > :last-child:nth-child(odd),
  .log-stats > :last-child:nth-child(odd),
  .mig-stats > :last-child:nth-child(odd),
  .acc-grid > :last-child:nth-child(odd),
  .stat-grid > :last-child:nth-child(odd),
  .qa-grid > :last-child:nth-child(odd) { grid-column: 1 / -1; }
}

@media (max-width: 640px) {
  /* Tool-page content panes keep desktop-sized padding otherwise — on a phone
     that wastes ~60px and makes headings sit off the card grid. */
  .settings-content { padding: 18px 14px; }
  .api-detail-hdr { padding: 14px; }
  .api-detail-body { padding: 16px 14px; }
}

@media (max-width: 640px) {
  /* Tables page: the action toolbar (View API / Rename / Drop / Add) is wider
     than a phone — let the header wrap instead of clipping the buttons. */
  .table-content > :first-child, .tc-hdr, .table-hdr { flex-wrap: wrap; row-gap: 8px; }
  .table-actions { margin-left: 0; flex-wrap: wrap; row-gap: 8px; }
}

/* ── CLOUD (Servers / Deployments) ────────────────────────────────────────────
   Status is a calm dot + a flat, colored label — never a chip-pill. Commands and
   build logs render in a real monospace terminal. Shared by cloud.html and
   app.html so the Cloud screens read as one product. */
.cl-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--txt3); flex-shrink: 0; display: inline-block; }
/* Status dots carry meaning, so they keep their colour — but not the glow.
   `busy` keeps its pulse because it encodes ongoing work; `live` is a steady
   state and doesn't need to throb at you. */
.cl-dot.live { background: var(--accent2); }
.cl-dot.busy { background: var(--accent4); animation: pulse 1.1s infinite; }
.cl-dot.off  { background: var(--txt3); }
.cl-dot.err  { background: var(--accent3); }
.cl-status { display: inline-flex; align-items: center; gap: 8px; font-size: 12.5px; font-weight: 600; }
/* First letter only: capitalize turned "waiting for first report" into Title Case. */
.cl-status .lbl { display: inline-block; letter-spacing: .1px; }
.cl-status .lbl::first-letter { text-transform: uppercase; }
/* Capitalize suits one-word states ("live", "offline"). A written sentence has
   its own capitalisation and Title Casing It Reads As A Machine Wrote It. */
.cl-status.plain .lbl { text-transform: none; }
.stx-live { color: var(--accent2); } .stx-busy { color: var(--accent4); } .stx-off { color: var(--txt3); } .stx-err { color: var(--accent3); }

.cl-term {
  background: #0c0c0e; border: 1px solid var(--border); border-radius: var(--r-sm);
  font-family: 'DM Mono', monospace; font-size: 12px; line-height: 1.7; color: #d7d7db;
  padding: 14px 16px; overflow: auto; white-space: pre-wrap; word-break: break-word;
}
.cl-term .prompt { color: var(--accent); }
.cl-copy {
  display: inline-flex; align-items: center; gap: 6px; font-size: 11px; font-weight: 600;
  color: var(--accent); cursor: pointer; user-select: none;
}
.cl-copy:hover { color: #d2f96e; }

.cl-meta-row { display: flex; justify-content: space-between; gap: 12px; font-size: 12px; padding: 7px 0; border-top: 1px solid var(--border); }
.cl-meta-row:first-child { border-top: none; }
.cl-meta-row .k { color: var(--txt3); white-space: nowrap; }
.cl-meta-row .v { color: var(--txt2); font-family: 'DM Mono', monospace; text-align: right; word-break: break-all; }
.cl-empty { text-align: center; padding: 54px 24px; }
.cl-empty .cl-empty-icon { color: var(--txt3); margin-bottom: 16px; display: inline-flex; }
.cl-empty h3 { font-size: 16px; font-weight: 700; margin-bottom: 8px; }
.cl-empty p { font-size: 13px; color: var(--txt2); max-width: 420px; margin: 0 auto 20px; line-height: 1.6; }

/* Multi-step wizard / detail overlay (server connect, new deploy) */
.cl-overlay { position: fixed; inset: 0; background: rgba(0,0,0,.55); z-index: 11000; display: flex; align-items: center; justify-content: center; padding: 20px; }
.cl-modal { background: var(--surface); border: 1px solid var(--border); border-radius: var(--r); width: 560px; max-width: 96vw; max-height: 92vh; overflow: auto; box-shadow: var(--pop); }
.cl-modal-hd { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; padding: 20px 22px 14px; border-bottom: 1px solid var(--border); }
.cl-modal-hd h2 { font-size: 16px; font-weight: 700; }
.cl-modal-hd p { font-size: 12.5px; color: var(--txt3); margin-top: 3px; }
.cl-modal-bd { padding: 20px 22px; }
.cl-modal-ft { display: flex; gap: 8px; justify-content: flex-end; padding: 14px 22px 20px; }
.cl-x { cursor: pointer; color: var(--txt3); background: none; border: none; padding: 4px; line-height: 0; border-radius: var(--r-xs); }
.cl-x:hover { color: var(--txt); background: var(--surface2); }

/* Deploy progress stepper — dots joined by a line, filled as status advances */
.cl-steps { display: flex; align-items: center; gap: 0; margin: 4px 0 22px; }
.cl-step { display: flex; align-items: center; gap: 9px; flex: 0 0 auto; }
.cl-step .sd { width: 10px; height: 10px; border-radius: 50%; background: var(--surface3); border: 1px solid var(--border2); flex-shrink: 0; }
.cl-step .sl { font-size: 12px; color: var(--txt3); font-weight: 600; }
.cl-step.done .sd { background: var(--accent2); border-color: var(--accent2); } .cl-step.done .sl { color: var(--txt2); }
.cl-step.now  .sd { background: var(--accent4); border-color: var(--accent4); animation: pulse 1.1s infinite; } .cl-step.now .sl { color: var(--accent4); }
.cl-step.fail .sd { background: var(--accent3); border-color: var(--accent3); } .cl-step.fail .sl { color: var(--accent3); }
.cl-step-line { flex: 1 1 auto; height: 1px; background: var(--border); margin: 0 10px; min-width: 16px; }
.cl-step-line.done { background: var(--accent2); }

/* Inner side-menu (nested nav inside the single "Cloud" sidebar link) — same
   shape as the Settings rail, so the two read as one product. Used by cloud.html
   (Apps / Servers) and app.html (an app's Overview / Deployments / Environment /
   Domains / Logs / Database / Settings). */
.cl-layout { display: flex; flex: 1; overflow: hidden; height: calc(100vh - var(--topbar)); }
.cl-rail { width: 216px; min-width: 216px; border-right: 1px solid var(--border); padding: 18px 12px; overflow-y: auto; background: var(--surface); }
.cl-rail-lbl { font-size: 10px; font-weight: 700; text-transform: uppercase; letter-spacing: 1px; color: var(--txt3); padding: 0 8px 8px; margin-top: 18px; }
.cl-rail-lbl:first-child { margin-top: 0; }
.cl-rail-item { display: flex; align-items: center; gap: 10px; padding: 9px 12px; border-radius: var(--r-sm); cursor: pointer; color: var(--txt2); font-size: 13px; font-weight: 500; transition: all .15s; margin-bottom: 2px; text-decoration: none; }
.cl-rail-item:hover { background: var(--surface2); color: var(--txt); }
.cl-rail-item.active { background: var(--surface3); color: var(--accent); }
.cl-rail-item .rico { width: 15px; height: 15px; flex-shrink: 0; opacity: .9; }
.cl-rail-back { display: inline-flex; align-items: center; gap: 7px; font-size: 12px; color: var(--txt3); text-decoration: none; padding: 4px 8px 12px; }
.cl-rail-back:hover { color: var(--txt); }
.cl-pane { flex: 1; overflow-y: auto; padding: 26px 30px; min-width: 0; }
.cl-section { display: none; } .cl-section.active { display: block; animation: fadeIn .2s ease; }

/* Env editor rows + generic "backend lands next" notice */
.env-row { display: grid; grid-template-columns: 1fr 1.4fr auto; gap: 10px; align-items: center; margin-bottom: 8px; }
.env-row .form-input { margin: 0; }
.env-del { cursor: pointer; color: var(--txt3); background: none; border: 1px solid var(--border); border-radius: var(--r-xs); width: 34px; height: 38px; display: flex; align-items: center; justify-content: center; flex-shrink: 0; }
.env-del:hover { color: var(--accent3); border-color: var(--accent3); }
.env-locked { font-size: 10px; font-family: 'DM Mono', monospace; color: var(--txt3); align-self: center; }
.cl-notice { display: flex; gap: 10px; align-items: flex-start; background: rgba(255,181,71,.06); border: 1px solid rgba(255,181,71,.22); border-radius: var(--r-sm); padding: 12px 14px; font-size: 12.5px; color: var(--txt2); line-height: 1.55; margin-bottom: 18px; }
.cl-notice .dotwarn { width: 7px; height: 7px; border-radius: 50%; background: var(--accent4); margin-top: 5px; flex-shrink: 0; }

/* ── Vitals: meters, stat grids, record tables, the help affordance ──────────
   Flat by construction (see the no-pills rule): hairline rules, mono figures,
   and colour ONLY where it means something — a meter past 75% / 90%. Nothing
   here is a capsule, a chip or a tinted decorative surface. */

/* A labelled 4px bar. Neutral until the reading is genuinely worth looking at,
   so a healthy box is quiet and a full disk is not. */
.vt-meter { margin-bottom: 13px; }
.vt-meter:last-child { margin-bottom: 0; }
.vt-meter .vm-hd { display: flex; justify-content: space-between; align-items: baseline; gap: 12px; font-size: 12px; margin-bottom: 5px; }
.vt-meter .vm-k { color: var(--txt2); }
.vt-meter .vm-v { color: var(--txt3); font-family: 'DM Mono', monospace; font-size: 11.5px; text-align: right; }
/* 2px, not a radius token: at 4px tall any token radius rounds the ends into a
   capsule, which is the one shape the design rule forbids outright. */
.vt-meter .vm-bar { height: 4px; background: var(--surface3); border-radius: 2px; overflow: hidden; }
.vt-meter .vm-fill { height: 100%; background: var(--txt2); transition: width .3s ease; }
.vt-meter.warn .vm-fill { background: var(--accent4); }
.vt-meter.crit .vm-fill { background: var(--accent3); }
.vt-meter.crit .vm-v { color: var(--accent3); }

/* Big-figure readouts (CPU · memory · disk at a glance). Auto-fit so it degrades
   from four across to one on a phone without a breakpoint per count. */
.vt-figs { display: grid; grid-template-columns: repeat(auto-fit, minmax(118px, 1fr)); gap: 1px; background: var(--border); border: 1px solid var(--border); border-radius: var(--r-sm); overflow: hidden; margin-bottom: 16px; }
.vt-fig { background: var(--surface); padding: 13px 15px; min-width: 0; }
.vt-fig .vf-k { font-size: 10px; font-weight: 700; text-transform: uppercase; letter-spacing: .7px; color: var(--txt3); margin-bottom: 6px; }
.vt-fig .vf-v { font-size: 19px; font-weight: 600; font-family: 'DM Mono', monospace; letter-spacing: -.4px; line-height: 1.15; }
.vt-fig .vf-s { font-size: 11px; color: var(--txt3); margin-top: 3px; font-family: 'DM Mono', monospace; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.vt-fig.warn .vf-v { color: var(--accent4); } .vt-fig.crit .vf-v { color: var(--accent3); }

/* Section label inside a vitals card. Flat caps + a lime rule — the same
   `.kicker` idiom the marketing site uses, never an enclosing shape. */
.vt-lbl { display: flex; align-items: center; gap: 9px; font-size: 10px; font-weight: 700; text-transform: uppercase; letter-spacing: .9px; color: var(--txt3); margin: 20px 0 10px; }
.vt-lbl::before { content: ''; width: 18px; height: 1px; background: var(--accent); flex: 0 0 auto; }
.vt-lbl:first-child { margin-top: 0; }

/* A row of facts that are one line each (kernel, arch, boot time…). */
.vt-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 0 22px; }

/* The DNS record a customer copies into their registrar. A real table, because
   that is what the registrar's own form looks like. */
.vt-rec { border: 1px solid var(--border); border-radius: var(--r-sm); overflow: hidden; }
.vt-rec-row { display: grid; grid-template-columns: 74px 1fr; gap: 0; border-top: 1px solid var(--border); }
.vt-rec-row:first-child { border-top: none; }
.vt-rec-k { padding: 10px 14px; font-size: 11px; font-weight: 600; color: var(--txt3); background: var(--surface2); display: flex; align-items: center; }
.vt-rec-v { padding: 10px 14px; font-family: 'DM Mono', monospace; font-size: 12.5px; color: var(--txt); display: flex; align-items: center; justify-content: space-between; gap: 12px; word-break: break-all; }
.vt-rec-v .cl-copy { flex: 0 0 auto; }

/* "Lost?" — a hairline-ringed question mark beside a heading. A circle, like the
   avatar and the terminal traffic-lights: an icon, not a badge. */
.vt-help {
  display: inline-flex; align-items: center; justify-content: center; flex: 0 0 auto;
  width: 15px; height: 15px; border-radius: 50%; border: 1px solid var(--border2);
  color: var(--txt3); font-size: 9.5px; font-weight: 700; line-height: 1;
  cursor: pointer; user-select: none; padding: 0; background: none; vertical-align: middle;
  margin-left: 7px; transition: color .15s, border-color .15s;
}
.vt-help:hover { color: var(--accent); border-color: var(--accent); }
/* Help body copy — readable prose measure inside the modal, with real spacing. */
.vt-help-bd p { font-size: 13px; color: var(--txt2); line-height: 1.75; margin-bottom: 13px; }
.vt-help-bd p:last-child { margin-bottom: 0; }
.vt-help-bd strong { color: var(--txt); font-weight: 600; }
.vt-help-bd code { font-family: 'DM Mono', monospace; font-size: 12px; color: var(--accent); background: var(--surface2); padding: 1px 5px; border-radius: var(--r-xs); }
.vt-help-bd ol, .vt-help-bd ul { margin: 0 0 13px 18px; }
.vt-help-bd li { font-size: 13px; color: var(--txt2); line-height: 1.7; margin-bottom: 7px; }
.vt-help-bd .vt-lbl { margin-top: 18px; }

@media (max-width: 640px) {
  .env-row { grid-template-columns: 1fr; }
  .cl-pane { padding: 18px 14px; }
  .vt-rec-row { grid-template-columns: 62px 1fr; }
  .vt-fig .vf-v { font-size: 17px; }
}

@media (max-width: 640px) {
  /* Page headers (Logs, Migrations, Realtime, Storage, Projects): the title block
     and the action buttons shared one row, so on a phone the subtitle was squeezed
     into a column one or two words wide. Give the title the full line and let the
     buttons wrap underneath it. */
  .content > .fi:has(> div > .page-title) { flex-wrap: wrap; row-gap: 12px; }
  .content > .fi:has(> div > .page-title) > :first-child { flex: 1 1 100%; min-width: 0; }
  .content > .fi:has(> div > .page-title) > :last-child { flex-wrap: wrap; }
  /* Two-column forms (Settings > Profile) become one column: two inputs side by
     side at 170px each clipped the email and the timezone. */
  [style*="grid-template-columns:1fr 1fr"]:has(> div > .form-label) { grid-template-columns: 1fr !important; }
}

/* ── FLAT ──────────────────────────────────────────────────────────────────
   Oct 2026, The Saint: "make the app flat, think Coolify, remove all the pop".
   A tool you look at all day: surfaces are told apart by borders, not by
   shadow, grain or glow, and nothing moves unless you moved it. Menus and
   dialogs keep one small shadow, because they really are on top. */
body::after { display: none; }                 /* film grain */
.glow { display: none; }
.fi, .fi-1, .fi-2, .fi-3, .cl-section.active { animation: none !important; }
.card, .stat-card, .settings-card, .cl-card, .mon-card, .al-table, .mon-table { box-shadow: none !important; }
.card:hover, .stat-card:hover, .cl-card:hover { transform: none !important; }

@media (prefers-reduced-motion: reduce) { *, *::before, *::after { transition: none !important; animation: none !important; } }

/* Zip deploy drop zone. */
.zip-drop { display: flex; flex-direction: column; align-items: center; gap: 6px; padding: 22px 16px; border: 1px dashed var(--border2); border-radius: var(--r-sm); background: var(--surface2); cursor: pointer; text-align: center; color: var(--txt2); }
.zip-drop:hover, .zip-drop:focus-visible, .zip-drop.over { border-color: var(--accent); color: var(--txt); outline: none; }
.zip-drop.has { border-style: solid; }
.zip-drop .zd-ic { color: var(--txt3); }
.zip-drop .zd-t { font-size: 13px; font-weight: 500; color: var(--txt); word-break: break-all; }
.zip-drop .zd-t u { text-underline-offset: 2px; }
.zip-drop .zd-s { font-size: 11.5px; color: var(--txt3); }
.zip-checks { margin-top: 8px; border: 1px solid var(--border); border-radius: var(--r-sm); padding: 4px 12px 10px; background: var(--surface2); color: var(--txt); }
.zip-checks .zc-h { font-size: 10.5px; text-transform: uppercase; letter-spacing: .6px; color: var(--txt3); font-weight: 600; margin: 10px 0 6px; }
.zip-checks .zc-row { display: grid; grid-template-columns: 64px 1fr; gap: 10px; padding: 6px 0; border-top: 1px solid var(--border); }
.zip-checks .zc-row:first-of-type { border-top: none; }
.zip-checks .zc-sev { font-size: 10.5px; font-weight: 600; text-transform: uppercase; letter-spacing: .5px; color: var(--accent4); padding-top: 2px; }
.zip-checks .zc-sev.critical { color: var(--accent3); }
.zip-checks .zc-t { font-size: 12.5px; color: var(--txt); }
.zip-checks .zc-d { font-size: 12px; color: var(--txt2); margin-top: 2px; }
.zip-checks .mono { font-family: 'DM Mono', monospace; }
/* Partitions */
.pt-bar { display: flex; height: 10px; border-radius: var(--r-xs); background: var(--surface3); overflow: hidden; }
.pt-bar span { display: block; height: 100%; }
.pt-bar .pt-a, .pt-legend i.pt-a { background: var(--accent-fill); }
.pt-bar .pt-o, .pt-legend i.pt-o { background: var(--txt2); }
/* Kept free for the system: amber stripes, held back and not for allocating.
   Free to allocate is the open track itself, so the two never look alike. */
.pt-bar .pt-r, .pt-legend i.pt-r { background: repeating-linear-gradient(135deg, var(--accent4) 0 3px, transparent 3px 6px); box-shadow: inset 0 0 0 1px var(--accent4); }
.pt-legend { display: flex; flex-wrap: wrap; gap: 6px 16px; font-size: 11.5px; color: var(--txt2); margin: 8px 0 16px; }
.pt-legend i { display: inline-block; width: 9px; height: 9px; border-radius: 2px; background: var(--surface3); box-shadow: inset 0 0 0 1px var(--border2); margin-right: 6px; vertical-align: -1px; }
.pt-list { border: 1px solid var(--border); border-radius: var(--r-sm); }
.pt-row { display: flex; align-items: center; gap: 12px; padding: 11px 14px; border-top: 1px solid var(--border); }
.pt-row:first-child { border-top: none; }
.pt-main { flex: 1; min-width: 0; }
.pt-name { font-family: 'DM Mono', monospace; font-size: 13px; color: var(--txt); }
.pt-sub { font-size: 12px; color: var(--txt2); margin-top: 2px; }
.pt-mini { height: 4px; background: var(--surface3); border-radius: 2px; margin-top: 6px; overflow: hidden; }
.pt-mini span { display: block; height: 100%; background: var(--txt2); }
.pt-warn { font-family: 'DM Sans', sans-serif; font-size: 11px; font-weight: 600; color: var(--accent4); margin-left: 6px; }
.pt-acts { display: flex; gap: 6px; flex-shrink: 0; }
.pt-empty { padding: 16px; font-size: 12.5px; color: var(--txt3); }
.pt-new { margin-top: 18px; }
.pt-h { font-size: 10.5px; text-transform: uppercase; letter-spacing: .6px; color: var(--txt3); font-weight: 600; margin-bottom: 10px; }
.pt-note { font-size: 12px; color: var(--txt3); line-height: 1.6; margin-top: 16px; }
.pt-src { max-height: 260px; overflow: auto; font-family: 'DM Mono', monospace; font-size: 11.5px; background: var(--surface2); border: 1px solid var(--border); border-radius: var(--r-xs); padding: 10px; margin-top: 8px; color: var(--txt2); white-space: pre; }
.dep-tabs { display: flex; gap: 0; border-bottom: 1px solid var(--border); margin: -4px 0 16px; }
.dep-tabs button { background: none; border: none; border-bottom: 2px solid transparent; padding: 8px 14px; font: inherit; font-size: 13px; color: var(--txt2); cursor: pointer; margin-bottom: -1px; }
.dep-tabs button.on { color: var(--txt); border-bottom-color: var(--accent); font-weight: 600; }

/* Theme switch in the top bar: shows the theme you are in. */
#themeBtn .ic-sun { display: none; }
[data-theme="light"] #themeBtn .ic-sun { display: block; }
[data-theme="light"] #themeBtn .ic-moon { display: none; }


/* Section tabs for pages that share one sidebar entry (nav.js FAMILIES):
   Tables / Diagram / Migrations and Monitoring / Incidents / Alerts. */
.fam-tabs { display:flex; gap:2px; flex:none; padding:0 28px; border-bottom:1px solid var(--border); background:var(--bg); overflow-x:auto; scrollbar-width:none; position:relative; z-index:2; }
.fam-tabs::-webkit-scrollbar { display:none; }
.fam-tab { padding:12px 16px 11px; font-size:13px; font-weight:500; color:var(--txt3); text-decoration:none; border-bottom:2px solid transparent; margin-bottom:-1px; white-space:nowrap; transition:color .15s, border-color .15s; }
.fam-tab:hover { color:var(--txt); }
.fam-tab.active { color:var(--txt); border-bottom-color:var(--accent); }

/* ── RESPONSIVE SYSTEM (Oct 2026 rework) ─────────────────────────────────────
   The rules, from the platform guidance (Apple HIG 44pt, Material 48dp, WCAG
   2.5.5/2.5.8) and the audit of every page at 390, 768 and 1024px:
     • a touch target is at least 44px tall for navigation and tabs, 40px for
       buttons, with room between neighbours;
     • form fields are 16px on touch screens, or iOS zooms the page on focus;
     • breakpoints sit where the content breaks: 1100 (wide tool layouts
       tighten), 820 (sidebar becomes a drawer), 600 (phones);
     • nothing the page marks hidden is ever shown by a later display rule. */
[hidden] { display: none !important; }

/* Touch screens of any width: bigger targets, no zoom-on-focus. */
@media (pointer: coarse) {
  .btn { min-height: 40px; }
  .btn-sm { min-height: 36px; }
  .icon-btn, .nav-toggle { width: 40px; height: 40px; }
  .nav-item { min-height: 44px; }
  .tab, .fam-tab, .snav-item { min-height: 44px; display: inline-flex; align-items: center; }
  .snav-item { display: flex; }
  input:not([type=checkbox]):not([type=radio]):not([type=range]), select, textarea,
  .form-input, .search-box input { font-size: 16px !important; }
  .pl-actions .btn, .ai-actions .btn { min-height: 40px; }
}

/* Wide tool layouts on small laptops and tablets in landscape. */
@media (max-width: 1100px) {
  .content { padding: 22px; }
  .topbar-search { flex-basis: 260px !important; }
}

/* Tablets and below: the sidebar is a drawer (rules above); tighten the shell. */
@media (max-width: 820px) {
  .content { padding: 16px; }
  .page-title { font-size: 20px; }
  .fam-tabs { padding: 0 12px; }
  .fam-tab { padding-left: 12px; padding-right: 12px; }
  /* The Overview's three job cards stay three across while they fit. */
  .jobs-row { grid-template-columns: repeat(3, minmax(0, 1fr)) !important; gap: 10px !important; }
  .job-card { padding: 16px !important; }
  .job-v { font-size: 22px !important; }
  .job-v.quiet { font-size: 14px !important; }
}

/* Phones. */
@media (max-width: 600px) {
  .content { padding: 14px 12px 28px; }
  .page-title { font-size: 19px; letter-spacing: -.2px; }
  .page-sub { font-size: 12.5px; }

  /* Top bar: menu · project · search (icon, expands on tap) · bell · theme · you. */
  .topbar { padding: 0 10px; gap: 6px; }
  .topbar-right { gap: 6px !important; }
  .icon-btn[title="Docs"] { display: none; }
  #projSwitch { flex: 1 1 auto; min-width: 0; }
  #projBtn { max-width: 100% !important; }
  #projBtnName { max-width: none !important; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .topbar-search { flex: 0 0 40px !important; min-width: 0 !important; position: static !important; }
  .topbar-search .search-box { width: 40px !important; height: 40px; padding: 0; justify-content: center; position: relative; }
  .topbar-search .search-box input { position: absolute; inset: 0; opacity: 0; cursor: pointer; }
  .topbar-search:focus-within { position: absolute !important; left: 8px; right: 8px; top: 10px; z-index: 30; flex: none !important; }
  .topbar-search:focus-within .search-box { width: 100% !important; padding: 0 12px; justify-content: flex-start; background: var(--surface); }
  .topbar-search:focus-within .search-box input { position: static; opacity: 1; cursor: text; }
  .topbar { position: relative; }

  /* Overview cards: one column, each a compact row (label · value · link). */
  .jobs-row { grid-template-columns: 1fr !important; gap: 8px !important; }
  .job-card { display: grid !important; grid-template-columns: 1fr auto; grid-template-areas: "k go" "v v" "s s"; padding: 14px 16px !important; row-gap: 4px; }
  .job-k { grid-area: k; }
  .job-go { grid-area: go; margin-top: 0 !important; font-size: 12px; }
  .job-v { grid-area: v; margin-top: 2px !important; font-size: 20px !important; }
  .job-s { grid-area: s; margin-top: 0 !important; }

  /* Checklist and the Move panel. */
  .fr-hdr, .fr-step { padding-left: 14px !important; padding-right: 14px !important; }
  .fr-code { font-size: 11px !important; }
  .pm { padding: 16px !important; }
  .pm-actions { width: 100%; }
  .pm-actions .btn { flex: 1; justify-content: center; }

  /* Section tabs scroll sideways rather than squeeze. */
  .fam-tabs { padding: 0 8px; }

  /* AI page: one header row on a phone. The conversation list (toggle next to
     Chat) has its own New chat, so the pane bar would only repeat it. */
  .pane-bar { display: none !important; }
  .ai-input-hint { display: none; }

  /* Dialogs use the full width with breathing room. */
  [style*="max-width:94vw"], [style*="max-width:92vw"], [style*="max-width:90vw"] { max-width: calc(100vw - 24px) !important; }
}

/* Small controls get a larger tap area on touch screens without changing how
   they look: an invisible margin of touch around the "?" help dots, roomier
   message tools, bigger checkboxes. */
@media (pointer: coarse) {
  .vt-help { position: relative; }
  .vt-help::after { content: ''; position: absolute; inset: -14px; }
  .msg-tool { min-height: 36px; padding-left: 8px; padding-right: 8px; }
  .fr-hide, .fr-copy, .convo-new { min-height: 36px; padding-left: 10px; padding-right: 10px; }
  input[type=checkbox], input[type=radio] { width: 20px; height: 20px; }
  .section-link { display: inline-flex; align-items: center; min-height: 36px; }
  #themeBtn { width: 40px !important; height: 40px !important; }
  .sidebar-collapse { width: 40px; height: 40px; }
  .tab { min-width: 44px; justify-content: center; }
  .mon-tablelink { min-height: 36px; display: inline-flex; align-items: center; }
  .conv-toggle { min-width: 40px; min-height: 40px; }
  .kv-on { position: relative; }
  .kv-on::after { content: ''; position: absolute; inset: -12px; }
  .cl-copy { min-height: 36px; display: inline-flex; align-items: center; }
}

@media (max-width: 600px) {
  /* Tables with form fields in their cells (Alerts → Channels, Rules) become
     stacked rows on a phone: every cell full width, the header row hidden
     (each cell already says what it is). */
  .al-table table, .al-table tbody, .al-table tr, .al-table td { display: block; width: 100%; }
  .al-table thead { display: none; }
  .al-table tr { border-top: 1px solid var(--border); padding: 10px 14px; }
  .al-table tr:first-child { border-top: none; }
  .al-table td { border-top: none !important; padding: 3px 0 !important; white-space: normal !important; text-align: left !important; }
  .al-table td.k { font-size: 13.5px; }
  .al-inline { flex-wrap: wrap; gap: 8px; }
  .al-inline .form-input { flex: 1 1 100%; min-width: 0; }

  /* Figure strips (Monitoring, app pages): two across, quieter numbers. */
  .vt-figs { grid-template-columns: repeat(2, minmax(0, 1fr)) !important; }
  .vt-fig .vf-v { font-size: 17px !important; line-height: 1.2; }
}

/* Settings grids (Monitoring checks, server settings): a label, its field and
   its note need about 280px; fewer, wider columns instead of squeezed ones. */
.srv-grid { grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)) !important; }
@media (max-width: 600px) {
  .srv-grid { grid-template-columns: 1fr !important; }
  .srv-f .in select, .srv-f .in input { max-width: 100%; }
}
/* Tablets: the project switcher keeps the name on one line; the address is
   one tap away in its menu. */
@media (max-width: 820px) {
  #projBtn span.mono, #projBtn span[style*="DM Mono"] { display: none; }
  #projBtn, #projBtnName { white-space: nowrap; }
  #projBtnName { overflow: hidden; text-overflow: ellipsis; max-width: 180px; }
}

/* Deploy dialog (Overview → Put it online). */
.dp-f { display: grid; gap: 6px; font-size: 12.5px; color: var(--txt2); border: none; padding: 0; margin: 0; min-width: 0; }
.dp-f legend { padding: 0; margin-bottom: 6px; }
.dp-hint { display: block; font-size: 11.5px; color: var(--txt3); line-height: 1.5; }
.dp-db { display: grid; gap: 8px; }
.dp-opt { display: flex; gap: 10px; align-items: flex-start; padding: 10px 12px; border: 1px solid var(--border); border-radius: var(--r-sm); cursor: pointer; font-size: 13px; color: var(--txt); line-height: 1.45; }
.dp-opt input { margin-top: 3px; accent-color: var(--accent); flex-shrink: 0; }
.dp-opt strong { font-weight: 600; }
.dp-sub { margin-left: 24px; border-style: dashed; }
@media (max-width: 600px) { .dp-sub { margin-left: 12px; } }

/* App → Overview → Connect your code. */
.cn-card { margin-top: 16px; }
.cn-row { display: flex; align-items: center; gap: 10px 12px; flex-wrap: wrap; padding: 6px 0; font-size: 12.5px; }
.cn-row .k { color: var(--txt3); width: 84px; flex-shrink: 0; }
.cn-val { font-family: 'DM Mono', monospace; font-size: 12.5px; color: var(--txt); background: var(--surface2); border: 1px solid var(--border); border-radius: var(--r-xs); padding: 5px 9px; min-width: 0; overflow-wrap: anywhere; flex: 1 1 260px; }
.cn-code { margin: 8px 0 2px; padding: 12px 14px; background: var(--surface2); border: 1px solid var(--border); border-radius: var(--r-sm); font: 12px/1.6 'DM Mono', monospace; color: var(--txt); overflow-x: auto; white-space: pre; }
.cn-key { border-top: 1px solid var(--border); margin-top: 10px; padding-top: 12px; }
@media (max-width: 600px) { .cn-row .k { width: 100%; } }
