/* ============================================================================================
   Kairos — the whole visual system, in one stylesheet.

   THE BRIEF, TAKEN LITERALLY
     Simple, fast, clean, light, and serious enough for a town hall. So: no gradients, no drop
     shadows beyond a hairline, no animation that is not a state change, no icon font, no web
     font. The type stack is the operating system's own, which means zero network requests
     before the first paint and text that already looks native on the machines these users
     actually have.

   COLOUR
     One institutional blue, used only for the things a user can act on and for the commune's
     own identity. Everything else is a neutral ramp. Status colour is reserved for status —
     if a screen looks colourful, something has gone wrong.

   LIGHT ONLY, ON PURPOSE
     `color-scheme: light` is declared and there is no dark block. A dark theme is a second
     surface to maintain and to check for contrast, and this product is used in daylight in
     an office, next to printed documents. When it is wanted it can be added; guessing at it
     now would ship two half-tested themes instead of one finished one.

   DENSITY
     These are working screens: a list of eighty calls with deadlines, values and scores. Rows
     are compact and numbers are tabular so columns line up down the page. Nothing here is
     sized for a marketing screenshot.
   ============================================================================================ */

:root {
  /* Neutral ramp — the whole interface, minus the accents below. */
  --bg:        #f6f7f9;
  --surface:   #ffffff;
  --surface-2: #fbfcfd;
  --line:      #e2e6eb;
  --line-strong:#cbd2da;
  --ink:       #16202b;
  --ink-2:     #4a5866;
  --ink-3:     #77848f;

  /* The single accent. Deep, institutional, not a startup blue. */
  --accent:      #1b3a6b;
  --accent-ink:  #ffffff;
  --accent-soft: #eaeff7;
  --accent-line: #c3d0e4;

  /* The navy the sidebar is built from — a darker, denser register than the accent, so the
     rail reads as the institution's frame rather than as a large highlighted element. */
  --navy-900:    #0b1a33;
  --navy-800:    #0f2140;
  --navy-700:    #17305a;
  --navy-line:   rgba(255, 255, 255, .09);
  --navy-ink:    #e8edf6;
  --navy-ink-2:  #9db0cd;
  --navy-ink-3:  #6d84a6;

  --sidebar-w:   264px;

  /* Status. Muted deliberately: these appear as small pills next to dense text, and
     saturated colour at that size reads as an error even when it is good news. */
  --ok:      #1e6b45;  --ok-bg:      #e7f2ec;
  --warn:    #8a5a12;  --warn-bg:    #fbf1de;
  --danger:  #9b2c2c;  --danger-bg:  #fbeaea;
  --info:    #1b4d7a;  --info-bg:    #e8f0f7;
  --muted-bg:#eef1f4;

  --radius: 6px;
  --radius-sm: 4px;
  --gap: 16px;
  --maxw: 1360px;

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

* { box-sizing: border-box; }

/* The `hidden` attribute is a UA-stylesheet rule (`display: none`), and ANY author rule that
   sets display beats it — `#app { display: flex }` alone was enough to keep the whole shell on
   screen while the login gate was showing. This restores the invariant once, for every element,
   rather than leaving each new layout rule to remember it. */
[hidden] { display: none !important; }

html, body {
  margin: 0;
  padding: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--font);
  font-size: 14px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}

/* Numbers must line up in a column of budgets. Everywhere, not just in tables. */
.num, td.num, .money, .score { font-variant-numeric: tabular-nums; }

a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; }
h1, h2, h3, h4 { margin: 0; font-weight: 600; letter-spacing: -0.01em; }
h1 { font-size: 21px; }
h2 { font-size: 16px; }
h3 { font-size: 14px; }
p  { margin: 0 0 10px; }

/* ── Skip link ────────────────────────────────────────────────────────────────────────── */

.skip {
  position: absolute; left: -9999px; top: 0; z-index: 200;
  padding: 10px 16px; background: var(--accent); color: #fff; border-radius: 0 0 6px 0;
}
.skip:focus { left: 0; }

/* ── The sidebar ──────────────────────────────────────────────────────────────────────── */

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

.sidebar {
  position: fixed; inset: 0 auto 0 0; z-index: 60;
  display: flex; flex-direction: column;
  width: var(--sidebar-w); padding: 20px 14px 14px;
  background: var(--navy-800);
  color: var(--navy-ink);
  border-right: 1px solid var(--navy-900);
}

.shell {
  flex: 1; min-width: 0;
  margin-left: var(--sidebar-w);
  display: flex; flex-direction: column;
}

/* ── The institutional block ──────────────────────────────────────────────────────────── */

.crest {
  display: flex; align-items: center; gap: 12px;
  padding: 4px 6px 18px;
  color: inherit;
  border-bottom: 1px solid var(--navy-line);
  margin-bottom: 14px;
}
.crest:hover { text-decoration: none; }

/* A municipal coat of arms is drawn for white paper. Dropping one straight onto navy loses
   its outlines and half its charges, so it sits on a light plate — which is also how a crest
   appears on real letterhead. */
.crest-plate {
  flex: none;
  display: grid; place-items: center;
  width: 60px; height: 60px; padding: 6px;
  background: #fff; border-radius: 6px;
  box-shadow: 0 1px 0 rgba(0, 0, 0, .28);
}
#org-logo { max-width: 100%; max-height: 100%; object-fit: contain; display: block; }

/* Shown until a crest is uploaded: the commune's initials, set like a seal rather than like
   a placeholder, so a new tenant does not look broken on its first day. */
.crest-fallback {
  font-size: 19px; font-weight: 700; letter-spacing: .02em; color: var(--navy-800);
}

.crest-text { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.crest-text strong {
  font-size: 15px; font-weight: 600; line-height: 1.25; color: #fff;
  /* Two lines, then ellipsis: "Unione dei Comuni della Bassa Romagna" must not be cut to
     "Unione dei…" in the one place a user checks they are in the right tenant. */
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.crest-text small {
  font-size: 11px; letter-spacing: .06em; text-transform: uppercase; color: var(--navy-ink-3);
}

/* ── Sidebar navigation ───────────────────────────────────────────────────────────────── */

.sidenav { display: flex; flex-direction: column; gap: 2px; flex: 1; overflow-y: auto; }
.sidenav a {
  display: flex; align-items: center; gap: 11px;
  padding: 10px 12px; border-radius: 6px;
  color: var(--navy-ink-2); font-size: 14px; font-weight: 500;
  border-left: 3px solid transparent;
}
.sidenav a:hover { background: rgba(255, 255, 255, .06); color: #fff; text-decoration: none; }
.sidenav a.active {
  background: var(--navy-700); color: #fff; border-left-color: #fff;
}
.sidenav a.active .navicon { opacity: 1; }
.navicon { flex: none; width: 18px; height: 18px; opacity: .75; }

/* ── Sidebar foot ─────────────────────────────────────────────────────────────────────── */

.sidebar-foot {
  padding-top: 14px; border-top: 1px solid var(--navy-line);
  display: flex; flex-direction: column; gap: 12px;
}

.flags { display: flex; align-items: center; gap: 8px; padding: 0 6px; }
.flag {
  display: block; border-radius: 2px;
  /* A hairline so a white band does not bleed into the navy behind it. */
  box-shadow: 0 0 0 1px rgba(255, 255, 255, .22);
}

.langswitch { display: flex; gap: 4px; padding: 0 6px; }
.langswitch button {
  flex: 1; padding: 5px 8px;
  border: 1px solid var(--navy-line); border-radius: 4px;
  background: none; color: var(--navy-ink-2);
  font: inherit; font-size: 12px; font-weight: 600; cursor: pointer;
}
.langswitch button:hover { color: #fff; border-color: rgba(255, 255, 255, .3); }
.langswitch button[aria-pressed="true"] {
  background: var(--navy-700); color: #fff; border-color: transparent;
}

.usermenu { position: relative; }
.userbtn {
  position: relative;
  display: flex; align-items: center; gap: 10px; width: 100%;
  padding: 8px; border: 0; border-radius: 6px;
  background: rgba(255, 255, 255, .05); color: var(--navy-ink);
  font: inherit; cursor: pointer; text-align: left;
}
.userbtn:hover { background: rgba(255, 255, 255, .1); }
.userbtn-text { display: flex; flex-direction: column; min-width: 0; }
.username { font-size: 13px; font-weight: 500; color: #fff;
            overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.userrole { font-size: 11px; color: var(--navy-ink-3); }

.avatar {
  flex: none;
  display: grid; place-items: center;
  width: 30px; height: 30px; border-radius: 50%;
  background: var(--accent); color: #fff;
  font-size: 11px; font-weight: 700; overflow: hidden;
}
.avatar img { width: 100%; height: 100%; object-fit: cover; }

.notif-dot {
  position: absolute; top: 4px; right: 6px;
  min-width: 17px; height: 17px; padding: 0 4px;
  border-radius: 9px; background: #d14343; color: #fff;
  font-size: 10px; font-weight: 700; line-height: 17px; text-align: center;
}

.dropdown {
  position: absolute; left: 0; right: 0; bottom: calc(100% + 6px); z-index: 70;
  padding: 4px;
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius); box-shadow: 0 6px 24px rgba(11, 26, 51, .3);
}
.dropdown a, .dropdown button {
  display: block; width: 100%; padding: 8px 10px; text-align: left;
  border: 0; background: none; border-radius: var(--radius-sm);
  color: var(--ink); font: inherit; font-size: 13px; cursor: pointer;
}
.dropdown a:hover, .dropdown button:hover { background: var(--muted-bg); text-decoration: none; }

/* ── Mobile ───────────────────────────────────────────────────────────────────────────── */

.mobilebar { display: none; }
.scrim { position: fixed; inset: 0; z-index: 55; background: rgba(11, 26, 51, .45); }

@media (max-width: 940px) {
  .sidebar { transform: translateX(-100%); transition: transform .18s ease; }
  .sidebar.open { transform: none; }
  .shell { margin-left: 0; }
  .mobilebar {
    display: flex; align-items: center; gap: 12px;
    height: 52px; padding: 0 12px; position: sticky; top: 0; z-index: 40;
    background: var(--navy-800); color: #fff;
  }
  .mobilebar .iconbtn { color: #fff; }
  #mobile-title { font-weight: 600; }
}
@media (min-width: 941px) { .scrim { display: none !important; } }

/* ── Layout ───────────────────────────────────────────────────────────────────────────── */

main { max-width: 1360px; margin: 0 auto; padding: 24px 26px 64px; outline: none; width: 100%; }

.page-head {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: 16px; margin-bottom: 18px; flex-wrap: wrap;
}
.page-head .sub { color: var(--ink-3); font-size: 13px; margin-top: 2px; }
.page-actions { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }

.grid { display: grid; gap: var(--gap); }
.grid.cols-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.grid.cols-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.grid.cols-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
.grid.detail { grid-template-columns: minmax(0, 1fr) 330px; align-items: start; }

@media (max-width: 1180px) {
  .grid.detail, .grid.cols-3, .grid.cols-4 { grid-template-columns: 1fr; }
}
@media (max-width: 720px) {
  .grid.cols-2 { grid-template-columns: 1fr; }
  main { padding: 16px 14px 48px; }
}

.card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
}
.card > header {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 12px 16px; border-bottom: 1px solid var(--line);
}
.card > header h2 { font-size: 13px; text-transform: uppercase;
                    letter-spacing: .04em; color: var(--ink-2); }
.card .body { padding: 16px; }
.card .body.flush { padding: 0; }

.iconbtn {
  position: relative;
  display: grid; place-items: center;
  width: 32px; height: 32px;
  border: 1px solid transparent; border-radius: var(--radius-sm);
  background: none; color: var(--ink-2); cursor: pointer;
}
.iconbtn:hover { background: var(--muted-bg); }

/* ── Statistics tiles ─────────────────────────────────────────────────────────────────── */

.stat {
  padding: 14px 16px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
}
.stat .k { font-size: 11px; text-transform: uppercase; letter-spacing: .05em; color: var(--ink-3); }
.stat .v { font-size: 26px; font-weight: 600; letter-spacing: -0.02em;
           font-variant-numeric: tabular-nums; margin-top: 4px; }
.stat .n { font-size: 12px; color: var(--ink-3); }
.stat a { color: inherit; }

/* ── Tables ───────────────────────────────────────────────────────────────────────────── */

.table-wrap { overflow-x: auto; }
table { width: 100%; border-collapse: collapse; font-size: 13px; }

/* NOT position:sticky, deliberately.
   `.table-wrap` sets overflow-x:auto, and CSS computes the other axis to `auto` as well —
   which makes the wrap a scroll container, so a sticky <thead> anchors to the WRAP rather
   than to the viewport. With a `top` offset it then floats over the first row and swallows
   its clicks; with top:0 it never sticks to anything the user is actually scrolling. Long
   lists here are paginated ("Carica altre") rather than infinitely scrolled, so a static
   header costs almost nothing and removes the whole failure mode. */
thead th {
  padding: 9px 12px; text-align: left; white-space: nowrap;
  background: var(--surface-2); border-bottom: 1px solid var(--line);
  font-size: 11px; font-weight: 600; text-transform: uppercase;
  letter-spacing: .04em; color: var(--ink-3);
}
tbody td { padding: 10px 12px; border-bottom: 1px solid var(--line); vertical-align: top; }
tbody tr:last-child td { border-bottom: 0; }
tbody tr.clickable { cursor: pointer; }
tbody tr.clickable:hover { background: var(--surface-2); }
td.num, th.num { text-align: right; }
td.tight { white-space: nowrap; }
.cell-title { font-weight: 500; color: var(--ink); display: block; }
.cell-sub { color: var(--ink-3); font-size: 12px; margin-top: 2px; display: block; }

/* ── Score, pills, badges ─────────────────────────────────────────────────────────────── */

/* The relevance score is the single most-scanned number in the product. It is a filled chip
   rather than plain text so the eye can rank a column of eighty rows without reading them. */
.score {
  display: inline-block; min-width: 38px; padding: 2px 7px;
  border-radius: var(--radius-sm); text-align: center;
  font-weight: 600; font-size: 12px;
}
.score.s-high { background: var(--ok-bg);     color: var(--ok); }
.score.s-mid  { background: var(--info-bg);   color: var(--info); }
.score.s-low  { background: var(--muted-bg);  color: var(--ink-3); }

.pill {
  display: inline-block; padding: 2px 8px; border-radius: 10px;
  font-size: 11px; font-weight: 600; letter-spacing: .02em; white-space: nowrap;
  background: var(--muted-bg); color: var(--ink-2);
}
.pill.ok     { background: var(--ok-bg);     color: var(--ok); }
.pill.warn   { background: var(--warn-bg);   color: var(--warn); }
.pill.danger { background: var(--danger-bg); color: var(--danger); }
.pill.info   { background: var(--info-bg);   color: var(--info); }

/* A deadline is the one number that changes meaning as it shrinks, so it is coloured by
   urgency rather than by category. */
.deadline.soon   { color: var(--warn);   font-weight: 600; }
.deadline.urgent { color: var(--danger); font-weight: 600; }
.deadline.past   { color: var(--ink-3);  text-decoration: line-through; }

/* ── Controls ─────────────────────────────────────────────────────────────────────────── */

.btn {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 7px 14px;
  border: 1px solid var(--line-strong); border-radius: var(--radius-sm);
  background: var(--surface); color: var(--ink);
  font: inherit; font-size: 13px; font-weight: 500; cursor: pointer;
}
.btn:hover { background: var(--surface-2); }
.btn:disabled { opacity: .5; cursor: not-allowed; }
.btn.primary { background: var(--accent); border-color: var(--accent); color: var(--accent-ink); }
.btn.primary:hover { background: #16305a; }
.btn.danger { color: var(--danger); border-color: #e3bcbc; }
.btn.small { padding: 4px 9px; font-size: 12px; }
.btn.link { border: 0; background: none; color: var(--accent); padding: 4px 6px; }

input[type=text], input[type=email], input[type=password], input[type=number],
input[type=date], input[type=search], select, textarea {
  width: 100%; padding: 7px 10px;
  border: 1px solid var(--line-strong); border-radius: var(--radius-sm);
  background: var(--surface); color: var(--ink);
  font: inherit; font-size: 13px;
}
input:focus, select:focus, textarea:focus {
  outline: 2px solid var(--accent-line); outline-offset: -1px; border-color: var(--accent);
}
textarea { resize: vertical; min-height: 76px; line-height: 1.55; }
label { display: block; font-size: 12px; font-weight: 600; color: var(--ink-2); margin-bottom: 4px; }
.field { margin-bottom: 12px; }
.field .hint { font-size: 11px; color: var(--ink-3); margin-top: 3px; }

.filters {
  display: flex; gap: 8px; flex-wrap: wrap; align-items: center;
  padding: 12px 16px; background: var(--surface);
  border: 1px solid var(--line); border-radius: var(--radius); margin-bottom: 14px;
}
.filters input[type=search] { flex: 1 1 220px; min-width: 180px; }
.filters select, .filters input[type=date] { width: auto; min-width: 130px; }

/* ── Detail panels ────────────────────────────────────────────────────────────────────── */

.kv { display: grid; grid-template-columns: 150px minmax(0, 1fr); gap: 7px 14px; font-size: 13px; }
.kv dt { color: var(--ink-3); }
.kv dd { margin: 0; word-break: break-word; }

.tabs { display: flex; gap: 2px; border-bottom: 1px solid var(--line); margin-bottom: 16px; }
.tabs button {
  padding: 8px 14px; border: 0; border-bottom: 2px solid transparent;
  background: none; color: var(--ink-2); font: inherit; font-weight: 500; cursor: pointer;
}
.tabs button:hover { color: var(--ink); }
.tabs button.active { color: var(--accent); border-bottom-color: var(--accent); }
.tabs .count { color: var(--ink-3); font-weight: 400; }

.prose { font-size: 14px; line-height: 1.65; white-space: pre-wrap; word-break: break-word; }
.prose.clamped { max-height: 340px; overflow: hidden; position: relative; }
.prose.clamped::after {
  content: ""; position: absolute; inset: auto 0 0 0; height: 60px;
  background: linear-gradient(to bottom, rgba(255,255,255,0), var(--surface));
}

/* ── Comments and files ───────────────────────────────────────────────────────────────── */

.comment { display: flex; gap: 10px; padding: 12px 0; border-bottom: 1px solid var(--line); }
.comment:last-child { border-bottom: 0; }
.comment.reply { margin-left: 34px; }
.comment .who { font-weight: 600; font-size: 13px; }
.comment .when { color: var(--ink-3); font-size: 11px; margin-left: 6px; }
.comment .text { white-space: pre-wrap; margin-top: 2px; }
.comment .acts { margin-top: 4px; }

.filerow {
  display: flex; align-items: center; gap: 10px;
  padding: 9px 0; border-bottom: 1px solid var(--line);
}
.filerow:last-child { border-bottom: 0; }
.filerow .meta { flex: 1; min-width: 0; }
.filerow .name { font-weight: 500; overflow: hidden;
                 text-overflow: ellipsis; white-space: nowrap; display: block; }
.filerow .sub  { font-size: 11px; color: var(--ink-3); }

.dropzone {
  padding: 14px; border: 1px dashed var(--line-strong); border-radius: var(--radius);
  text-align: center; color: var(--ink-3); font-size: 13px; cursor: pointer;
}
.dropzone.over { border-color: var(--accent); background: var(--accent-soft); color: var(--accent); }

/* ── Login ────────────────────────────────────────────────────────────────────────────── */

/* The photograph is dimmed almost to a texture, not used as an image. Two reasons: a login
   screen has to hold white body text at AA contrast wherever the photo happens to be light,
   and this is the front door of a public administration — it should read as institutional,
   not as a travel page. The solid navy underneath is not a fallback detail: it is what the
   screen looks like on a ministry network that blocks the image host, and it still looks
   finished. */
.login-wrap {
  min-height: 100vh;
  display: grid; place-items: center; padding: 24px;
  background-color: var(--navy-900);
  background-image:
    linear-gradient(rgba(9, 20, 39, .84), rgba(9, 20, 39, .92)),
    url('https://images.unsplash.com/photo-1718260775649-b925159be5a0?q=80&w=1470');
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
  color: var(--navy-ink);
}

.login-inner { width: 100%; max-width: 420px; }

/* The badge, at a size that carries. It is the platform's mark on a screen that has nothing
   else on it, so at 22px it looked like a favicon that had wandered in. */
.login-badge { display: flex; align-items: center; gap: 14px; margin-bottom: 8px; }
.login-badge svg { flex: none; }
.login-badge .wordmark {
  font-size: 30px; font-weight: 600; letter-spacing: -0.02em; color: #fff; line-height: 1;
}
.login-kicker {
  font-size: 11px; letter-spacing: .14em; text-transform: uppercase;
  color: var(--navy-ink-3); margin-bottom: 26px;
}

.login-card {
  padding: 26px;
  background: var(--surface);
  border-radius: 10px;
  box-shadow: 0 18px 48px rgba(4, 12, 26, .5);
  color: var(--ink);
}
.login-card .tagline { color: var(--ink-3); font-size: 13px; margin-bottom: 20px; }
.login-card .btn { width: 100%; justify-content: center; margin-top: 6px; }

.login-foot {
  margin-top: 16px; text-align: center; font-size: 12px;
}
.login-foot a { color: var(--accent); }

/* Below the card: the same institutional pair as the sidebar, so the flags are the first and
   last thing a user sees, and the language control, because it has to be reachable BEFORE
   there is a session to remember a preference in. */
.login-institutional {
  display: flex; align-items: center; justify-content: space-between; gap: 16px;
  margin-top: 22px; padding-top: 18px;
  border-top: 1px solid rgba(255, 255, 255, .14);
}
.login-institutional .flags { padding: 0; }
.login-institutional .langswitch { padding: 0; }
.login-institutional .langswitch button { min-width: 62px; }

/* ── Feedback ─────────────────────────────────────────────────────────────────────────── */

.alert {
  padding: 9px 12px; border-radius: var(--radius-sm); font-size: 13px; margin-bottom: 12px;
  border: 1px solid transparent;
}
.alert.error { background: var(--danger-bg); color: var(--danger); border-color: #eecfcf; }
.alert.info  { background: var(--info-bg);   color: var(--info);   border-color: var(--accent-line); }
.alert.warn  { background: var(--warn-bg);   color: var(--warn);   border-color: #ecd9b4; }

.empty { padding: 40px 20px; text-align: center; color: var(--ink-3); }
.empty strong { display: block; color: var(--ink-2); margin-bottom: 4px; font-weight: 600; }

/* Skeleton rows rather than a spinner: the page keeps its shape while it loads, so nothing
   jumps when the data lands. */
.skel { background: var(--muted-bg); border-radius: 3px; height: 12px; animation: pulse 1.1s infinite; }
@keyframes pulse { 0%,100% { opacity: 1 } 50% { opacity: .45 } }

.toast-host { position: fixed; right: 16px; bottom: 16px; z-index: 100;
              display: flex; flex-direction: column; gap: 8px; }
.toast {
  padding: 10px 14px; border-radius: var(--radius);
  background: var(--ink); color: #fff; font-size: 13px;
  box-shadow: 0 6px 20px rgba(22,32,43,.22); max-width: 340px;
}
.toast.error { background: var(--danger); }

.modal-back {
  position: fixed; inset: 0; z-index: 90;
  display: grid; place-items: center; padding: 20px;
  background: rgba(22,32,43,.38);
}
.modal {
  width: 100%; max-width: 560px; max-height: 88vh; overflow: auto;
  background: var(--surface); border-radius: 8px;
}
.modal > header, .modal > footer {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 14px 18px;
}
.modal > header { border-bottom: 1px solid var(--line); }
.modal > footer { border-top: 1px solid var(--line); justify-content: flex-end; }
.modal .body { padding: 18px; }

.muted { color: var(--ink-3); }
.small { font-size: 12px; }
.mono  { font-family: var(--mono); font-size: 12px; }
.right { text-align: right; }
.row   { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.stack > * + * { margin-top: 12px; }
.nowrap { white-space: nowrap; }
.hidden { display: none !important; }

@media print {
  .topbar, .filters, .page-actions, .tabs, .toast-host { display: none !important; }
  main { max-width: none; padding: 0; }
  .card { border: 0; }
}
