/* ==========================================================================
   Provisioning Portal
   Hand-written, no framework, no external requests. The Content-Security-Policy
   forbids inline styles, so everything a page needs is in this file.
   ========================================================================== */

/* --------------------------------------------------------------------------
   Tokens
   -------------------------------------------------------------------------- */
:root {
  --bg:            #f6f7f9;
  --surface:       #ffffff;
  --surface-2:     #fbfbfc;
  --surface-sunk:  #f1f2f5;
  --border:        #e2e5ea;
  --border-strong: #cfd4dc;

  --text:          #1a1d23;
  --text-muted:    #656d7b;
  --text-faint:    #8a92a1;

  --accent:        #2f6df6;
  --accent-hover:  #245bd6;
  --accent-soft:   #eaf1fe;
  --accent-text:   #ffffff;

  --ok:            #14804a;
  --ok-soft:       #e6f4ec;
  --warn:          #9a6400;
  --warn-soft:     #fdf3e2;
  --danger:        #c02b2b;
  --danger-soft:   #fdecec;
  --info:          #1f5f8b;
  --info-soft:     #e8f2f9;

  --radius:        10px;
  --radius-sm:     7px;
  --radius-lg:     14px;

  --shadow-sm: 0 1px 2px rgba(16, 24, 40, .05);
  --shadow:    0 1px 3px rgba(16, 24, 40, .08), 0 1px 2px rgba(16, 24, 40, .04);
  --shadow-lg: 0 12px 32px rgba(16, 24, 40, .12);

  --sidebar-w: 244px;

  --scroll-thumb: #c3c9d4;
  --scroll-thumb-hover: #a7afbd;

  --font: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace;
}

@media (prefers-color-scheme: dark) {
  :root {
    --bg:            #0f1115;
    --surface:       #171a21;
    --surface-2:     #1c2029;
    --surface-sunk:  #12151b;
    --border:        #272c37;
    --border-strong: #363d4b;

    --text:          #e7eaf0;
    --text-muted:    #9aa3b2;
    --text-faint:    #6d7686;

    --accent:        #5b8dff;
    --accent-hover:  #7aa2ff;
    --accent-soft:   #1a2440;
    --accent-text:   #0f1115;

    --ok:            #4ade80;
    --ok-soft:       #12251a;
    --warn:          #fbbf49;
    --warn-soft:     #2a2011;
    --danger:        #f87171;
    --danger-soft:   #2c1618;
    --info:          #7dd3fc;
    --info-soft:     #10222c;

    --shadow-sm: 0 1px 2px rgba(0, 0, 0, .4);
    --shadow:    0 1px 3px rgba(0, 0, 0, .5);
    --shadow-lg: 0 12px 32px rgba(0, 0, 0, .6);

    --scroll-thumb: #39404f;
    --scroll-thumb-hover: #4b5466;
  }
}

/* --------------------------------------------------------------------------
   Scrollbars

   A page like this has a lot of things that can outgrow their box - a config
   preview, a 30 row key table, a log with seven columns on a narrow screen -
   and the platform default is a wide grey trough with a raised button in it.
   Several of those on one screen is most of what makes an otherwise tidy page
   look cluttered.

   These are thin, tinted to the surface they sit on, and have no arrows or
   track. Styled rather than hidden: a scroll region with no visible scrollbar
   is a scroll region nobody discovers.
   -------------------------------------------------------------------------- */
* {
  scrollbar-width: thin;
  scrollbar-color: var(--scroll-thumb) transparent;
}

::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-corner { background: transparent; }

::-webkit-scrollbar-thumb {
  background: var(--scroll-thumb);
  border-radius: 8px;
  /* Transparent border, clipped to the padding box, insets the thumb without
     needing a track colour that would have to match five different surfaces. */
  border: 3px solid transparent;
  background-clip: padding-box;
}
::-webkit-scrollbar-thumb:hover { background: var(--scroll-thumb-hover); background-clip: padding-box; }

/* A scroll region the finger flings should not then drag the page behind it. */
.table-wrap, .keyset-scroll, .varref, .modal-body, pre, .textarea, .tabs {
  overscroll-behavior: contain;
}

/* --------------------------------------------------------------------------
   Reset
   -------------------------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  font-family: var(--font);
  font-size: 14px;
  line-height: 1.55;
  color: var(--text);
  background: var(--bg);
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3, h4 { margin: 0 0 .4em; line-height: 1.25; font-weight: 620; letter-spacing: -.011em; }
h1 { font-size: 1.5rem; }
h2 { font-size: 1.18rem; }
h3 { font-size: 1rem; }
h4 { font-size: .875rem; }
p  { margin: 0 0 .8em; }
p:last-child { margin-bottom: 0; }

a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; }

code, pre, .mono { font-family: var(--mono); font-size: .86em; }

code {
  background: var(--surface-sunk);
  border: 1px solid var(--border);
  border-radius: 5px;
  padding: .08em .38em;
  word-break: break-all;
}

pre {
  background: var(--surface-sunk);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 14px 16px;
  overflow: auto;
  margin: 0 0 1em;
  line-height: 1.5;
}
pre code { background: none; border: 0; padding: 0; }

hr { border: 0; border-top: 1px solid var(--border); margin: 22px 0; }

.sr-only {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
}

.skip-link {
  position: absolute; left: -9999px; top: 0; z-index: 100;
  background: var(--accent); color: var(--accent-text);
  padding: 10px 16px; border-radius: 0 0 var(--radius-sm) 0;
}
.skip-link:focus { left: 0; }

:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: 3px;
}

/* --------------------------------------------------------------------------
   Shell
   -------------------------------------------------------------------------- */
.shell { display: flex; min-height: 100vh; }

.sidebar {
  width: var(--sidebar-w);
  flex: 0 0 var(--sidebar-w);
  background: var(--surface);
  border-right: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  position: sticky;
  top: 0;
  height: 100vh;
}

.brand {
  display: flex; align-items: center; gap: 10px;
  padding: 18px 18px 16px;
  border-bottom: 1px solid var(--border);
}

.brand-mark {
  width: 26px; height: 26px; flex: none;
  border-radius: 7px;
  background: linear-gradient(140deg, var(--accent), #8b5cf6);
  box-shadow: var(--shadow-sm);
}

.brand-name {
  font-weight: 640;
  font-size: .95rem;
  letter-spacing: -.012em;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.nav { flex: 1; overflow-y: auto; padding: 12px 10px; }

.nav-heading {
  font-size: .68rem;
  text-transform: uppercase;
  letter-spacing: .07em;
  color: var(--text-faint);
  font-weight: 620;
  padding: 18px 10px 7px;
}

.nav-link {
  display: flex; align-items: center; gap: 10px;
  padding: 8px 10px;
  border-radius: var(--radius-sm);
  color: var(--text-muted);
  font-weight: 500;
  margin-bottom: 1px;
}
.nav-link:hover { background: var(--surface-sunk); color: var(--text); text-decoration: none; }
.nav-link.is-active { background: var(--accent-soft); color: var(--accent); font-weight: 570; }

.nav-icon {
  width: 16px; height: 16px; flex: none;
  background: currentColor;
  opacity: .85;
  -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat;
  -webkit-mask-position: center; mask-position: center;
  -webkit-mask-size: contain; mask-size: contain;
}

/* Icons are inline SVG data URIs on a mask, so they inherit text colour and
   cost no extra requests (which the CSP would block anyway). */
.i-grid   { -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3' y='3' width='7' height='7'/%3E%3Crect x='14' y='3' width='7' height='7'/%3E%3Crect x='14' y='14' width='7' height='7'/%3E%3Crect x='3' y='14' width='7' height='7'/%3E%3C/svg%3E"); mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3' y='3' width='7' height='7'/%3E%3Crect x='14' y='3' width='7' height='7'/%3E%3Crect x='14' y='14' width='7' height='7'/%3E%3Crect x='3' y='14' width='7' height='7'/%3E%3C/svg%3E"); }
.i-phone  { -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='5' y='2' width='14' height='20' rx='2'/%3E%3Cline x1='12' y1='18' x2='12' y2='18'/%3E%3C/svg%3E"); mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='5' y='2' width='14' height='20' rx='2'/%3E%3Cline x1='12' y1='18' x2='12' y2='18'/%3E%3C/svg%3E"); }
.i-sliders{ -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round'%3E%3Cline x1='4' y1='21' x2='4' y2='14'/%3E%3Cline x1='4' y1='10' x2='4' y2='3'/%3E%3Cline x1='12' y1='21' x2='12' y2='12'/%3E%3Cline x1='12' y1='8' x2='12' y2='3'/%3E%3Cline x1='20' y1='21' x2='20' y2='16'/%3E%3Cline x1='20' y1='12' x2='20' y2='3'/%3E%3Cline x1='1' y1='14' x2='7' y2='14'/%3E%3Cline x1='9' y1='8' x2='15' y2='8'/%3E%3Cline x1='17' y1='16' x2='23' y2='16'/%3E%3C/svg%3E"); mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round'%3E%3Cline x1='4' y1='21' x2='4' y2='14'/%3E%3Cline x1='4' y1='10' x2='4' y2='3'/%3E%3Cline x1='12' y1='21' x2='12' y2='12'/%3E%3Cline x1='12' y1='8' x2='12' y2='3'/%3E%3Cline x1='20' y1='21' x2='20' y2='16'/%3E%3Cline x1='20' y1='12' x2='20' y2='3'/%3E%3Cline x1='1' y1='14' x2='7' y2='14'/%3E%3Cline x1='9' y1='8' x2='15' y2='8'/%3E%3Cline x1='17' y1='16' x2='23' y2='16'/%3E%3C/svg%3E"); }
.i-server { -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='2' y='2' width='20' height='8' rx='2'/%3E%3Crect x='2' y='14' width='20' height='8' rx='2'/%3E%3Cline x1='6' y1='6' x2='6.01' y2='6'/%3E%3Cline x1='6' y1='18' x2='6.01' y2='18'/%3E%3C/svg%3E"); mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='2' y='2' width='20' height='8' rx='2'/%3E%3Crect x='2' y='14' width='20' height='8' rx='2'/%3E%3Cline x1='6' y1='6' x2='6.01' y2='6'/%3E%3Cline x1='6' y1='18' x2='6.01' y2='18'/%3E%3C/svg%3E"); }
.i-file   { -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z'/%3E%3Cpolyline points='14 2 14 8 20 8'/%3E%3C/svg%3E"); mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z'/%3E%3Cpolyline points='14 2 14 8 20 8'/%3E%3C/svg%3E"); }
.i-book   { -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 19.5A2.5 2.5 0 0 1 6.5 17H20'/%3E%3Cpath d='M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z'/%3E%3C/svg%3E"); mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 19.5A2.5 2.5 0 0 1 6.5 17H20'/%3E%3Cpath d='M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z'/%3E%3C/svg%3E"); }
.i-link   { -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71'/%3E%3Cpath d='M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71'/%3E%3C/svg%3E"); mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71'/%3E%3Cpath d='M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71'/%3E%3C/svg%3E"); }
.i-users  { -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2'/%3E%3Ccircle cx='9' cy='7' r='4'/%3E%3Cpath d='M23 21v-2a4 4 0 0 0-3-3.87'/%3E%3Cpath d='M16 3.13a4 4 0 0 1 0 7.75'/%3E%3C/svg%3E"); mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2'/%3E%3Ccircle cx='9' cy='7' r='4'/%3E%3Cpath d='M23 21v-2a4 4 0 0 0-3-3.87'/%3E%3Cpath d='M16 3.13a4 4 0 0 1 0 7.75'/%3E%3C/svg%3E"); }
.i-user   { -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2'/%3E%3Ccircle cx='12' cy='7' r='4'/%3E%3C/svg%3E"); mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2'/%3E%3Ccircle cx='12' cy='7' r='4'/%3E%3C/svg%3E"); }
.i-list   { -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round'%3E%3Cline x1='8' y1='6' x2='21' y2='6'/%3E%3Cline x1='8' y1='12' x2='21' y2='12'/%3E%3Cline x1='8' y1='18' x2='21' y2='18'/%3E%3Cline x1='3' y1='6' x2='3.01' y2='6'/%3E%3Cline x1='3' y1='12' x2='3.01' y2='12'/%3E%3Cline x1='3' y1='18' x2='3.01' y2='18'/%3E%3C/svg%3E"); mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round'%3E%3Cline x1='8' y1='6' x2='21' y2='6'/%3E%3Cline x1='8' y1='12' x2='21' y2='12'/%3E%3Cline x1='8' y1='18' x2='21' y2='18'/%3E%3Cline x1='3' y1='6' x2='3.01' y2='6'/%3E%3Cline x1='3' y1='12' x2='3.01' y2='12'/%3E%3Cline x1='3' y1='18' x2='3.01' y2='18'/%3E%3C/svg%3E"); }
.i-activity { -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='22 12 18 12 15 21 9 3 6 12 2 12'/%3E%3C/svg%3E"); mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='22 12 18 12 15 21 9 3 6 12 2 12'/%3E%3C/svg%3E"); }
.i-clock  { -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpolyline points='12 6 12 12 16 14'/%3E%3C/svg%3E"); mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpolyline points='12 6 12 12 16 14'/%3E%3C/svg%3E"); }
.i-image  { -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3' y='3' width='18' height='18' rx='2'/%3E%3Ccircle cx='8.5' cy='8.5' r='1.5'/%3E%3Cpolyline points='21 15 16 10 5 21'/%3E%3C/svg%3E"); mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3' y='3' width='18' height='18' rx='2'/%3E%3Ccircle cx='8.5' cy='8.5' r='1.5'/%3E%3Cpolyline points='21 15 16 10 5 21'/%3E%3C/svg%3E"); }
.i-menu   { -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round'%3E%3Cline x1='3' y1='12' x2='21' y2='12'/%3E%3Cline x1='3' y1='6' x2='21' y2='6'/%3E%3Cline x1='3' y1='18' x2='21' y2='18'/%3E%3C/svg%3E"); mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round'%3E%3Cline x1='3' y1='12' x2='21' y2='12'/%3E%3Cline x1='3' y1='6' x2='21' y2='6'/%3E%3Cline x1='3' y1='18' x2='21' y2='18'/%3E%3C/svg%3E"); width: 18px; height: 18px; }

.sidebar-foot { border-top: 1px solid var(--border); padding: 12px 10px; }

.user-chip {
  display: flex; align-items: center; gap: 10px;
  padding: 8px 10px; border-radius: var(--radius-sm);
  color: var(--text);
}
.user-chip:hover { background: var(--surface-sunk); text-decoration: none; }

.avatar {
  width: 30px; height: 30px; flex: none;
  border-radius: 50%;
  background: var(--accent-soft); color: var(--accent);
  display: grid; place-items: center;
  font-weight: 640; font-size: .8rem;
}

.user-chip-text { min-width: 0; display: flex; flex-direction: column; line-height: 1.3; }
.user-chip-name { font-weight: 560; font-size: .84rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.user-chip-role { font-size: .72rem; color: var(--text-faint); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.logout-form { margin-top: 6px; }

.main-wrap { flex: 1; min-width: 0; display: flex; flex-direction: column; }

.topbar {
  display: flex; align-items: center; gap: 12px;
  padding: 10px 22px;
  background: var(--surface);
  border-bottom: 1px solid var(--border);
  position: sticky; top: 0; z-index: 20;
  min-height: 54px;
}
.topbar-spacer { flex: 1; }
.menu-toggle { display: none; }

.main { padding: 22px; flex: 1; max-width: 1420px; width: 100%; }

/* --------------------------------------------------------------------------
   Page header
   -------------------------------------------------------------------------- */
.page-head {
  display: flex; align-items: flex-start; gap: 16px;
  flex-wrap: wrap;
  margin-bottom: 18px;
}
.page-head-text { flex: 1; min-width: 240px; }
.page-head h1 { margin-bottom: 2px; }
.page-sub { color: var(--text-muted); margin: 0; }
.page-actions { display: flex; gap: 8px; flex-wrap: wrap; }

/* --------------------------------------------------------------------------
   Cards
   -------------------------------------------------------------------------- */
.card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-sm);
  margin-bottom: 18px;
  overflow: hidden;
}

.card-head {
  padding: 14px 18px;
  border-bottom: 1px solid var(--border);
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
}
.card-head h2, .card-head h3 { margin: 0; flex: 1; min-width: 160px; }
.card-head-actions { display: flex; gap: 8px; flex-wrap: wrap; }

.card-body { padding: 18px; }
.card-body.tight { padding: 0; }
.card-foot {
  padding: 13px 18px;
  border-top: 1px solid var(--border);
  background: var(--surface-2);
  display: flex; gap: 8px; align-items: center; flex-wrap: wrap;
}

.card-note { color: var(--text-muted); font-size: .875rem; }

/* --------------------------------------------------------------------------
   Grid helpers
   -------------------------------------------------------------------------- */
.grid { display: grid; gap: 16px; }
.grid-2 { grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); }
.grid-3 { grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); }
.grid-4 { grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); }

/* --------------------------------------------------------------------------
   Stats
   -------------------------------------------------------------------------- */
.stat {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 16px 18px;
  box-shadow: var(--shadow-sm);
}
.stat-value { font-size: 1.9rem; font-weight: 640; line-height: 1.1; letter-spacing: -.02em; }
.stat-label { color: var(--text-muted); font-size: .82rem; margin-top: 3px; }
.stat-hint { color: var(--text-faint); font-size: .76rem; margin-top: 6px; }
.stat.is-warn .stat-value { color: var(--warn); }
.stat.is-danger .stat-value { color: var(--danger); }

/* --------------------------------------------------------------------------
   Buttons
   -------------------------------------------------------------------------- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 7px;
  padding: 7px 14px;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: var(--text);
  font: inherit; font-weight: 540; font-size: .86rem;
  cursor: pointer;
  white-space: nowrap;
  transition: background .12s ease, border-color .12s ease, opacity .12s ease;
}
.btn:hover { background: var(--surface-sunk); text-decoration: none; }
.btn:disabled, .btn[aria-disabled="true"] { opacity: .55; cursor: not-allowed; }

.btn-primary { background: var(--accent); border-color: var(--accent); color: var(--accent-text); }
.btn-primary:hover { background: var(--accent-hover); border-color: var(--accent-hover); }

.btn-danger { background: var(--danger); border-color: var(--danger); color: #fff; }
.btn-danger:hover { filter: brightness(.93); background: var(--danger); }

.btn-ghost { background: transparent; border-color: transparent; color: var(--text-muted); }
.btn-ghost:hover { background: var(--surface-sunk); color: var(--text); }

.btn-sm { padding: 4px 10px; font-size: .8rem; }
.btn-block { width: 100%; }

.btn-row { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }

/* --------------------------------------------------------------------------
   Forms
   -------------------------------------------------------------------------- */
.field { margin-bottom: 16px; }
.field:last-child { margin-bottom: 0; }

.label {
  display: block;
  font-weight: 560;
  font-size: .82rem;
  margin-bottom: 5px;
}

.hint { color: var(--text-muted); font-size: .8rem; margin-top: 5px; }
.hint-inline { color: var(--text-faint); font-weight: 400; }

.input, .select, .textarea {
  width: 100%;
  padding: 8px 11px;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: var(--text);
  font: inherit;
  font-size: .875rem;
}
.input:focus, .select:focus, .textarea:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft);
}
.input:disabled, .textarea:disabled, .select:disabled {
  background: var(--surface-sunk); color: var(--text-muted); cursor: not-allowed;
}

.input-sm { padding: 5px 8px; font-size: .82rem; }
.input-mono { font-family: var(--mono); font-size: .82rem; }

.textarea { resize: vertical; min-height: 110px; font-family: var(--mono); font-size: .82rem; line-height: 1.5; white-space: pre; overflow-wrap: normal; overflow-x: auto; }

select.select {
  appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath fill='%23888' d='M6 8.5 2.5 5h7z'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 9px center;
  background-size: 11px;
  padding-right: 28px;
}

.check { display: flex; align-items: flex-start; gap: 9px; margin-bottom: 9px; }
.check:last-child { margin-bottom: 0; }
.check input[type="checkbox"], .check input[type="radio"] { margin: 3px 0 0; flex: none; width: 15px; height: 15px; accent-color: var(--accent); }
.check-text { flex: 1; }
.check-label { font-weight: 540; font-size: .86rem; display: block; }
.check-hint { color: var(--text-muted); font-size: .79rem; }

fieldset { border: 0; margin: 0 0 22px; padding: 0; }
fieldset:last-child { margin-bottom: 0; }
legend { font-weight: 620; font-size: .95rem; padding: 0 0 4px; }

.form-section {
  border-top: 1px solid var(--border);
  padding-top: 18px;
  margin-top: 18px;
}
.form-section:first-child { border-top: 0; padding-top: 0; margin-top: 0; }

/* --------------------------------------------------------------------------
   Tables
   -------------------------------------------------------------------------- */
.table-wrap { overflow-x: auto; }

/* Columns worth dropping before the table starts scrolling sideways.
   A seven column log needs about 1200px to lay out, which is more than this
   layout has even on a desktop once the sidebar is accounted for - so the
   choice is not "all the columns or some of them", it is "some of them, or all
   of them behind a horizontal scrollbar". The dropped ones are the widest and
   least scanned; nothing that identifies a row is ever hidden. */
@media (max-width: 1400px) {
  .col-wide { display: none; }
}
@media (max-width: 860px) {
  .col-optional { display: none; }
}

.table { width: 100%; border-collapse: collapse; font-size: .86rem; }
.table th, .table td { padding: 9px 14px; text-align: left; vertical-align: middle; }
.table thead th {
  background: var(--surface-2);
  border-bottom: 1px solid var(--border);
  font-weight: 600; font-size: .76rem;
  text-transform: uppercase; letter-spacing: .045em;
  color: var(--text-muted);
  white-space: nowrap;
}
.table tbody tr { border-bottom: 1px solid var(--border); }
.table tbody tr:last-child { border-bottom: 0; }
.table tbody tr:hover { background: var(--surface-2); }
.table td.num, .table th.num { text-align: right; font-variant-numeric: tabular-nums; }
.table td.actions { text-align: right; white-space: nowrap; }
.table .nowrap { white-space: nowrap; }
.table-fixed { table-layout: fixed; }

.row-muted td { opacity: .55; }

/* --------------------------------------------------------------------------
   Badges, pills, alerts
   -------------------------------------------------------------------------- */
.badge {
  display: inline-block;
  padding: 2px 8px;
  border-radius: 999px;
  font-size: .72rem;
  font-weight: 600;
  letter-spacing: .01em;
  background: var(--surface-sunk);
  color: var(--text-muted);
  border: 1px solid var(--border);
  white-space: nowrap;
}
.badge-ok     { background: var(--ok-soft);     color: var(--ok);     border-color: transparent; }
.badge-warn   { background: var(--warn-soft);   color: var(--warn);   border-color: transparent; }
.badge-danger { background: var(--danger-soft); color: var(--danger); border-color: transparent; }
.badge-info   { background: var(--info-soft);   color: var(--info);   border-color: transparent; }
.badge-accent { background: var(--accent-soft); color: var(--accent); border-color: transparent; }

.pill {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 4px 11px; border-radius: 999px;
  font-size: .79rem; font-weight: 550;
  background: var(--surface-sunk); color: var(--text-muted);
}
.pill-danger { background: var(--danger-soft); color: var(--danger); }
.pill-danger:hover { text-decoration: none; filter: brightness(.97); }

.alert {
  display: flex; align-items: flex-start; gap: 10px;
  padding: 11px 14px;
  border-radius: var(--radius-sm);
  margin-bottom: 10px;
  border: 1px solid transparent;
  font-size: .875rem;
}
.alert-body { flex: 1; }
.alert-close {
  background: none; border: 0; cursor: pointer;
  font-size: 1.15rem; line-height: 1; color: inherit; opacity: .55;
  padding: 0 2px;
}
.alert-close:hover { opacity: 1; }

.alert-success { background: var(--ok-soft);     color: var(--ok);     border-color: color-mix(in srgb, var(--ok) 22%, transparent); }
.alert-error   { background: var(--danger-soft); color: var(--danger); border-color: color-mix(in srgb, var(--danger) 22%, transparent); }
.alert-warning { background: var(--warn-soft);   color: var(--warn);   border-color: color-mix(in srgb, var(--warn) 22%, transparent); }
.alert-info    { background: var(--info-soft);   color: var(--info);   border-color: color-mix(in srgb, var(--info) 22%, transparent); }

.flashes { margin-bottom: 16px; }

.callout {
  border-left: 3px solid var(--accent);
  background: var(--surface-2);
  padding: 12px 16px;
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
  margin-bottom: 16px;
  font-size: .875rem;
}
.callout-warn   { border-left-color: var(--warn); }
.callout-danger { border-left-color: var(--danger); }

/* --------------------------------------------------------------------------
   Health list
   -------------------------------------------------------------------------- */
.health { list-style: none; margin: 0; padding: 0; }
.health li {
  display: flex; align-items: flex-start; gap: 10px;
  padding: 8px 0;
  border-bottom: 1px solid var(--border);
  font-size: .875rem;
}
.health li:last-child { border-bottom: 0; }
.dot { width: 8px; height: 8px; border-radius: 50%; flex: none; margin-top: 6px; }
.dot-ok { background: var(--ok); }
.dot-warn { background: var(--warn); }
.dot-error { background: var(--danger); }

/* --------------------------------------------------------------------------
   Tabs
   -------------------------------------------------------------------------- */
/* A tab strip is navigation, not content. With thirteen profile groups it has
   to scroll, but a visible bar under it reads as a second border and doubles
   the height of the strip - so this is the one place the scrollbar is hidden
   rather than styled. Snap points make it obvious it moves. */
.tabs {
  display: flex; gap: 2px;
  border-bottom: 1px solid var(--border);
  margin-bottom: 18px;
  overflow-x: auto;
  scrollbar-width: none;
  scroll-snap-type: x proximity;
  -webkit-overflow-scrolling: touch;
}
.tabs::-webkit-scrollbar { display: none; }
.tab { scroll-snap-align: start; }
.tab {
  padding: 9px 14px;
  border: 0; background: none;
  font: inherit; font-weight: 540; font-size: .875rem;
  color: var(--text-muted);
  cursor: pointer;
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
  white-space: nowrap;
}
.tab:hover { color: var(--text); }
.tab.is-active { color: var(--accent); border-bottom-color: var(--accent); }

.tab-panel { display: none; }
.tab-panel.is-active { display: block; }

/* --------------------------------------------------------------------------
   Key editor
   -------------------------------------------------------------------------- */
.keytable { width: 100%; border-collapse: collapse; font-size: .82rem; }
.keytable th {
  text-align: left; padding: 7px 8px;
  font-size: .72rem; text-transform: uppercase; letter-spacing: .04em;
  color: var(--text-muted); font-weight: 600;
  border-bottom: 1px solid var(--border);
  background: var(--surface-2);
}
.keytable td { padding: 4px 6px; border-bottom: 1px solid var(--border); vertical-align: middle; }
.keytable tr:last-child td { border-bottom: 0; }
.keytable .key-index {
  width: 34px; text-align: right;
  color: var(--text-faint); font-variant-numeric: tabular-nums;
  font-size: .78rem;
}
.keytable .col-fn { width: 210px; }
.keytable .col-line { width: 74px; }
.keytable .col-extra { width: 150px; }
.keyset-scroll { max-height: 560px; overflow-y: auto; }

.key-hidden { visibility: hidden; }

/* --------------------------------------------------------------------------
   Token display
   -------------------------------------------------------------------------- */
.token-box {
  display: flex; align-items: center; gap: 8px;
  background: var(--surface-sunk);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 9px 12px;
  font-family: var(--mono); font-size: .8rem;
  word-break: break-all;
}
.token-box code { background: none; border: 0; padding: 0; flex: 1; }

/* QR codes are always dark-on-light, in both themes. Inverting one to match a
   dark interface is a real way to make it unreadable: plenty of scanners will
   not attempt an inverted symbol, so the frame keeps its own white ground. */
.qr-frame {
  display: flex; justify-content: center;
  background: #ffffff;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 12px;
  margin: 16px 0;
}
.qr-frame svg { display: block; width: 100%; height: auto; max-width: 240px; }

.secret-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(130px, 1fr));
  gap: 8px; margin: 14px 0;
}
.secret-grid code {
  text-align: center; padding: 8px 4px; font-size: .88rem; letter-spacing: .04em;
}

/* --------------------------------------------------------------------------
   Auth screens
   -------------------------------------------------------------------------- */
.auth-body { background: var(--bg); }
.auth-shell {
  min-height: 100vh;
  display: flex; flex-direction: column;
  align-items: center; justify-content: center;
  padding: 32px 20px;
}
.auth-card {
  width: 100%; max-width: 400px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  padding: 30px;
}
.auth-brand {
  display: flex; align-items: center; gap: 10px;
  justify-content: center; margin-bottom: 22px;
}
.auth-brand .brand-name { font-size: 1.05rem; }
.auth-title { text-align: center; margin-bottom: 4px; }
.auth-sub { text-align: center; color: var(--text-muted); margin-bottom: 22px; font-size: .875rem; }
.auth-lead { text-align: center; color: var(--text-muted); margin: 10px 0 4px; font-size: .875rem; }
.auth-foot { margin-top: 20px; color: var(--text-faint); font-size: .8rem; text-align: center; }

.code-input {
  font-family: var(--mono);
  font-size: 1.5rem;
  letter-spacing: .32em;
  text-align: center;
  padding: 12px;
}

/* --------------------------------------------------------------------------
   Error page
   -------------------------------------------------------------------------- */
.error-page { text-align: center; padding: 12px 0; }
.error-code { font-size: 3rem; font-weight: 700; color: var(--text-faint); line-height: 1; }
.error-title { margin: 10px 0 6px; }
.error-message { color: var(--text-muted); margin-bottom: 22px; }

/* --------------------------------------------------------------------------
   Filters and toolbars
   -------------------------------------------------------------------------- */
.toolbar {
  display: flex; gap: 8px; align-items: center; flex-wrap: wrap;
  padding: 12px 18px;
  border-bottom: 1px solid var(--border);
  background: var(--surface-2);
}
.toolbar .input, .toolbar .select { width: auto; min-width: 150px; }
.toolbar-spacer { flex: 1; }

.empty {
  text-align: center; padding: 44px 20px; color: var(--text-muted);
}
.empty-title { font-weight: 600; color: var(--text); margin-bottom: 5px; }

/* --------------------------------------------------------------------------
   Definition lists
   -------------------------------------------------------------------------- */
.dl { display: grid; grid-template-columns: minmax(120px, max-content) 1fr; gap: 7px 18px; font-size: .875rem; margin: 0; }
.dl dt { color: var(--text-muted); }
.dl dd { margin: 0; }

/* --------------------------------------------------------------------------
   Variable reference
   -------------------------------------------------------------------------- */
.varref { font-size: .8rem; max-height: 520px; overflow-y: auto; }
.varref h4 { margin: 14px 0 5px; font-size: .76rem; text-transform: uppercase; letter-spacing: .05em; color: var(--text-faint); }
.varref h4:first-child { margin-top: 0; }
.varref-item { display: flex; gap: 8px; padding: 3px 0; align-items: baseline; }
.varref-item code { flex: none; }
.varref-item span { color: var(--text-muted); font-size: .76rem; }

/* --------------------------------------------------------------------------
   Modal
   -------------------------------------------------------------------------- */
.modal-backdrop {
  position: fixed; inset: 0;
  background: rgba(10, 12, 16, .55);
  display: none;
  align-items: center; justify-content: center;
  padding: 24px; z-index: 100;
}
.modal-backdrop.is-open { display: flex; }
.modal {
  background: var(--surface);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  max-width: 900px; width: 100%;
  max-height: 88vh;
  display: flex; flex-direction: column;
  overflow: hidden;
}
.modal-head {
  padding: 15px 20px; border-bottom: 1px solid var(--border);
  display: flex; align-items: center; gap: 12px;
}
.modal-head h3 { margin: 0; flex: 1; }
.modal-body { padding: 20px; overflow-y: auto; }
.modal-body pre { max-height: 58vh; margin: 0; }

/* --------------------------------------------------------------------------
   Pagination
   -------------------------------------------------------------------------- */
.pagination { display: flex; gap: 6px; align-items: center; justify-content: center; padding: 14px; flex-wrap: wrap; }
.pagination .current { color: var(--text-muted); font-size: .82rem; }

/* --------------------------------------------------------------------------
   Utilities
   -------------------------------------------------------------------------- */
.muted { color: var(--text-muted); }
.faint { color: var(--text-faint); }
.small { font-size: .8rem; }
.strong { font-weight: 600; }
.right { text-align: right; }
.center { text-align: center; }
.mt-0 { margin-top: 0; }
.mt-1 { margin-top: 8px; }
.mt-2 { margin-top: 16px; }
.mt-3 { margin-top: 24px; }
.mb-0 { margin-bottom: 0; }
.mb-1 { margin-bottom: 8px; }
.mb-2 { margin-bottom: 16px; }
.flex { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; }
.flex-between { display: flex; gap: 10px; align-items: center; justify-content: space-between; flex-wrap: wrap; }
.stack > * + * { margin-top: 12px; }
.truncate { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 100%; }

/* --------------------------------------------------------------------------
   Hover help

   The explanation for a setting lives behind a question mark rather than in a
   paragraph under every field. A form of sixty settings each carrying two
   lines of prose is a form nobody reads; the same sixty settings with the prose
   one hover away is a form people scan in seconds and still learn from.

   Shown on hover AND on keyboard focus, and marked up as a real button with a
   real tooltip, so it is not a mouse-only feature.
   -------------------------------------------------------------------------- */
.label-row { display: flex; align-items: center; gap: 6px; margin-bottom: 5px; }
.label-row .label { margin-bottom: 0; }

.help {
  position: relative;
  flex: none;
  display: inline-flex; align-items: center; justify-content: center;
  width: 15px; height: 15px;
  padding: 0;
  border: 1px solid var(--border-strong, var(--border));
  border-radius: 50%;
  background: transparent;
  color: var(--text-faint);
  font-size: .66rem; font-weight: 700; line-height: 1;
  cursor: help;
}
.help:hover, .help:focus { color: var(--accent); border-color: var(--accent); }

.help-bubble {
  position: absolute;
  bottom: calc(100% + 7px);
  left: 50%;
  transform: translateX(-50%);
  z-index: 40;
  width: max-content;
  max-width: min(320px, 74vw);
  padding: 9px 11px;
  border: 1px solid var(--border);
  border-radius: var(--radius, 8px);
  background: var(--surface);
  box-shadow: var(--shadow-lg);
  color: var(--text-muted);
  font-size: .78rem; font-weight: 400; line-height: 1.45;
  text-align: left;
  white-space: normal;
  cursor: auto;
  /* Hidden from the mouse as well as the eye, so it cannot swallow a click on
     whatever is underneath it. */
  opacity: 0; visibility: hidden;
  transition: opacity .12s ease;
}
/* :focus, not :focus-visible. Tapping a button on a touch screen focuses it but
   does not make it focus-visible, so keying on that alone would leave every
   explanation in the application unreachable on a phone. The cost is that a
   mouse click also pins the bubble open, which is a reasonable thing for a
   click on a question mark to do. */
.help:hover .help-bubble,
.help:focus .help-bubble { opacity: 1; visibility: visible; }

/* Near an edge the bubble would otherwise run off the page. Which side it needs
   depends on where the question mark happens to sit, which only the browser
   knows, so app.js measures and applies one of these. Without JavaScript the
   bubble stays centred and is still perfectly readable - just occasionally
   clipped at the far right of a wide grid. */
.help-bubble.is-right { left: auto; right: -6px; transform: none; }
.help-bubble.is-left  { left: -6px; right: auto; transform: none; }

/* --------------------------------------------------------------------------
   The bubble lifted out of whatever is clipping it

   An absolutely positioned box is clipped by the nearest ancestor that scrolls
   or hides its overflow, and this application is full of them by design: .card
   hides overflow so a long value cannot break the rounded corner, .table-wrap
   and .tabs scroll sideways, .keyset-scroll and .varref scroll down, .modal-body
   scrolls. A question mark on the top row of a card, or anywhere inside a
   scrolling panel, had its explanation sliced off at the panel edge - and the
   nearer the bubble was to something worth explaining, the more likely that
   was, because those are exactly the dense panels.

   No amount of flipping fixes this: the box is *inside* the clip rectangle
   whichever way it points. The only fix is to stop being inside it, so on hover
   app.js switches the bubble to viewport coordinates, where no ancestor's
   overflow applies, and positions it itself.

   left/top come from app.js. The rules here are the ones it should not have to
   set in inline styles.
   -------------------------------------------------------------------------- */
.help-bubble.is-fixed {
  position: fixed;
  right: auto; bottom: auto;
  transform: none;
  /* Above the sticky topbar (20), the mobile sidebar (60) and the modal (100),
     because help exists in all three. */
  z-index: 200;
  /* The viewport is the containing block now, so the bubble can be as wide as
     the screen allows rather than as wide as the column it started in. */
  max-width: min(320px, calc(100vw - 24px));
}

/* A badge with its explanation beside it, for log outcomes where the single
   word in the badge is all the reader gets. */
.badge-help { display: inline-flex; align-items: center; gap: 5px; }

/* --------------------------------------------------------------------------
   File library
   -------------------------------------------------------------------------- */
.asset-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
  gap: 14px;
}

.asset-card {
  border: 1px solid var(--border);
  border-radius: var(--radius, 8px);
  background: var(--surface);
  overflow: hidden;
  display: flex; flex-direction: column;
}

.asset-thumb {
  height: 120px;
  display: flex; align-items: center; justify-content: center;
  background: var(--surface-sunk);
  border-bottom: 1px solid var(--border);
  overflow: hidden;
}
.asset-thumb img { max-width: 100%; max-height: 100%; object-fit: contain; }
.asset-thumb .asset-ext {
  font-family: var(--mono);
  font-size: .9rem;
  font-weight: 600;
  color: var(--text-faint);
  text-transform: uppercase;
}

.asset-meta { padding: 10px 12px; flex: 1; }
.asset-name { font-weight: 560; font-size: .85rem; overflow-wrap: anywhere; }
.asset-facts { color: var(--text-faint); font-size: .74rem; margin-top: 3px; }
.asset-foot {
  padding: 8px 12px;
  border-top: 1px solid var(--border);
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
}

.file-input {
  width: 100%;
  padding: 9px 11px;
  border: 1px dashed var(--border-strong, var(--border));
  border-radius: var(--radius, 8px);
  background: var(--surface-sunk);
  font-size: .84rem;
}

/* --------------------------------------------------------------------------
   Per-phone overrides

   A row that is inheriting from the profile is deliberately quieter than one
   that has been overridden, so "what has actually been changed on this phone"
   is answerable at a glance rather than by reading every value.
   -------------------------------------------------------------------------- */
.override {
  display: flex; align-items: flex-start; gap: 11px;
  /* A stripe down the left of anything this phone has taken over, so "what did
     I actually change here" is answerable by scanning rather than by reading
     every value. */
  border-left: 2px solid transparent;
  padding-left: 9px;
  margin-left: -11px;
}
.override:not(.is-inherited) { border-left-color: var(--accent); }
.override-body { flex: 1; min-width: 0; }

/* Lines up with the field's own label row, and with the checkbox of a boolean
   setting, which sits at the same offset - so one value serves both and there
   is no :has() to depend on. */
.override-toggle { flex: none; margin-top: 2px; }

/* Deliberately NOT a checkbox.
   A boolean setting is itself a checkbox, so a square tick box beside it gives
   two identical controls in a row with nothing to say which is which - one
   means "does this phone decide for itself", the other means "on or off". This
   one is a filled circle instead, so the two are never confused at a glance. */
.override-toggle input {
  appearance: none; -webkit-appearance: none;
  width: 17px; height: 17px; margin: 0;
  border: 2px solid var(--border-strong);
  border-radius: 50%;
  background: var(--surface);
  cursor: pointer;
  display: block;
  position: relative;
}
.override-toggle input:hover { border-color: var(--accent); }
.override-toggle input:checked { border-color: var(--accent); background: var(--accent); }
.override-toggle input:checked::after {
  content: '';
  position: absolute; inset: 3px;
  border-radius: 50%;
  background: var(--accent-text);
}
.override.is-inherited .override-body { opacity: .55; }
.override.is-inherited .override-body input,
.override.is-inherited .override-body select,
.override.is-inherited .override-body textarea { pointer-events: none; }
.inherit-note { color: var(--text-faint); font-size: .76rem; margin-top: 5px; }

/* --------------------------------------------------------------------------
   Responsive
   -------------------------------------------------------------------------- */
@media (max-width: 900px) {
  .sidebar {
    position: fixed; inset: 0 auto 0 0; z-index: 60;
    transform: translateX(-100%);
    transition: transform .18s ease;
    box-shadow: var(--shadow-lg);
  }
  .sidebar.is-open { transform: translateX(0); }
  .menu-toggle { display: inline-flex; }
  .main { padding: 16px; }
  .topbar { padding: 10px 16px; }

  /* A fixed-height scroll box inside a page that already scrolls is the worst
     of both: two scrollbars, and a cramped window onto the thing you came to
     read. On a narrow screen let the page be long instead. */
  .keyset-scroll, .varref { max-height: none; overflow-y: visible; }
}

@media (max-width: 640px) {
  .main { padding: 12px; }
  .topbar { padding: 8px 12px; }

  h1 { font-size: 1.28rem; }
  h2 { font-size: 1.06rem; }

  .card { border-radius: var(--radius-sm); }
  .card-body, .card-head, .card-foot { padding: 14px; }

  .page-head { gap: 10px; margin-bottom: 14px; }
  .page-actions { width: 100%; }
  /* Full-width actions beat three buttons crammed onto one line, and they are
     a great deal easier to hit. */
  .page-actions .btn,
  .page-actions form,
  .page-actions form .btn { flex: 1 1 auto; justify-content: center; }

  .grid { gap: 12px; }
  .grid-2, .grid-3, .grid-4 { grid-template-columns: 1fr; }

  /* A control smaller than about 16px makes iOS zoom the whole page on focus,
     which then leaves the layout scrolled sideways. */
  .input, .select, .textarea { font-size: 16px; }
  .input-sm, .select.input-sm { font-size: 16px; padding: 7px 10px; }

  .toolbar { flex-direction: column; align-items: stretch; }
  .toolbar .input, .toolbar .select, .toolbar .btn { width: 100%; min-width: 0; }

  .btn { padding: 8px 12px; }
  .btn-sm { padding: 6px 10px; }

  .table { font-size: .82rem; }
  .table th, .table td { padding: 8px 10px; }

  .dl { grid-template-columns: 1fr; gap: 2px 0; }
  .dl dt { margin-top: 8px; }
  .dl dt:first-child { margin-top: 0; }

  .asset-grid { grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); gap: 10px; }
  .asset-thumb { height: 92px; }

  /* Edge to edge, because 24px of backdrop either side of a config preview on
     a 360px screen is 24px of preview nobody can read. */
  .modal-backdrop { padding: 0; align-items: flex-end; }
  .modal { max-width: none; max-height: 92vh; border-radius: var(--radius-lg) var(--radius-lg) 0 0; }
  .modal-body { padding: 14px; }
  .modal-body pre { max-height: none; }

  .flex-between { align-items: stretch; }
  .flex-between > form { width: 100%; }
  .flex-between > form > .btn { width: 100%; }

  .override { gap: 8px; }
  .keytable .col-fn, .keytable .col-line, .keytable .col-extra { width: auto; }

  /* The token boxes hold a 32 character string; wrapping beats a scrollbar. */
  .token-box { flex-wrap: wrap; }
  .token-box code { overflow-wrap: anywhere; }
}

/* Somebody who has asked their system to stop moving things means it. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
    scroll-behavior: auto !important;
  }
}

@media print {
  .sidebar, .topbar, .page-actions, .card-foot, .btn { display: none !important; }
  body { background: #fff; }
  .card { box-shadow: none; border-color: #ccc; }
}
