/* ==========================================================================
   Where To Deploy — design system
   Desktop-first, responsive down to 320px. No build step, no framework.
   All colour lives in custom properties so the two themes stay in sync.
   ========================================================================== */

:root {
  --bg: #f4f6fa;
  --bg-grid: rgba(15, 23, 42, 0.035);
  --surface: #ffffff;
  --surface-2: #fbfcfe;
  --surface-hover: #f7f9fc;
  --border: #e2e7f0;
  --border-strong: #cbd3e1;
  --text: #0f172a;
  --text-muted: #5a6580;
  --text-faint: #8c96ab;

  --accent: #5b5bd6;
  --accent-hover: #4a4ac4;
  --accent-soft: rgba(91, 91, 214, 0.1);
  --accent-ring: rgba(91, 91, 214, 0.35);

  --available: #0f9d6e;
  --available-soft: rgba(15, 157, 110, 0.12);
  --inuse: #d97706;
  --inuse-soft: rgba(217, 119, 6, 0.13);
  --maintenance: #2563eb;
  --maintenance-soft: rgba(37, 99, 235, 0.12);
  --disabled: #64748b;
  --disabled-soft: rgba(100, 116, 139, 0.12);
  --danger: #dc2626;
  --danger-soft: rgba(220, 38, 38, 0.1);

  /* Client site vs backend service. Chosen to sit apart from every status colour above, because
     the two axes are read at the same time on one card. */
  --client: #0891b2;
  --client-soft: rgba(8, 145, 178, 0.12);
  --backend: #7c3aed;
  --backend-soft: rgba(124, 58, 237, 0.12);

  --shadow-sm: 0 1px 2px rgba(15, 23, 42, 0.06);
  --shadow: 0 2px 8px rgba(15, 23, 42, 0.07), 0 1px 2px rgba(15, 23, 42, 0.04);
  --shadow-lg: 0 12px 36px rgba(15, 23, 42, 0.13), 0 2px 8px rgba(15, 23, 42, 0.06);
  --shadow-glow: 0 0 0 4px var(--accent-ring);

  --radius: 12px;
  --radius-sm: 8px;
  --radius-lg: 18px;

  --font: "Segoe UI", system-ui, -apple-system, "Helvetica Neue", Arial, sans-serif;
  --mono: "Cascadia Mono", "JetBrains Mono", Consolas, "SF Mono", monospace;

  --ease-out: cubic-bezier(0.22, 1, 0.36, 1);
  --ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
  --speed: 220ms;

  --header-h: 60px;
  color-scheme: light;
}

[data-theme="dark"] {
  --bg: #090c13;
  --bg-grid: rgba(255, 255, 255, 0.028);
  --surface: #121722;
  --surface-2: #161c29;
  --surface-hover: #1a2130;
  --border: #232b3b;
  --border-strong: #333f56;
  --text: #e8edf7;
  --text-muted: #9aa5bd;
  --text-faint: #6b7690;

  --accent: #8b8bf0;
  --accent-hover: #a0a0ff;
  --accent-soft: rgba(139, 139, 240, 0.16);
  --accent-ring: rgba(139, 139, 240, 0.35);

  --available: #34d399;
  --available-soft: rgba(52, 211, 153, 0.15);
  --inuse: #fbbf24;
  --inuse-soft: rgba(251, 191, 36, 0.15);
  --maintenance: #60a5fa;
  --maintenance-soft: rgba(96, 165, 250, 0.15);
  --disabled: #94a3b8;
  --disabled-soft: rgba(148, 163, 184, 0.14);
  --danger: #f87171;
  --danger-soft: rgba(248, 113, 113, 0.14);

  --client: #22d3ee;
  --client-soft: rgba(34, 211, 238, 0.15);
  --backend: #c084fc;
  --backend-soft: rgba(192, 132, 252, 0.16);

  --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.4);
  --shadow: 0 2px 10px rgba(0, 0, 0, 0.45);
  --shadow-lg: 0 16px 44px rgba(0, 0, 0, 0.6);

  color-scheme: dark;
}

/* ---- Reset ------------------------------------------------------------- */

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

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

body {
  margin: 0;
  font-family: var(--font);
  font-size: 14.5px;
  line-height: 1.55;
  color: var(--text);
  background-color: var(--bg);
  background-image:
    linear-gradient(var(--bg-grid) 1px, transparent 1px),
    linear-gradient(90deg, var(--bg-grid) 1px, transparent 1px);
  background-size: 44px 44px;
  min-height: 100vh;
  -webkit-font-smoothing: antialiased;
  transition: background-color var(--speed) var(--ease-out), color var(--speed) var(--ease-out);
}

h1, h2, h3, h4 { margin: 0 0 0.4em; line-height: 1.25; font-weight: 650; letter-spacing: -0.015em; }
h1 { font-size: 1.55rem; }
h2 { font-size: 1.2rem; }
h3 { font-size: 1rem; }
p { margin: 0 0 0.8em; }

a { color: var(--accent); text-decoration: none; transition: color 140ms var(--ease-out); }
a:hover { color: var(--accent-hover); text-decoration: underline; }

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

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

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

/* ---- Top progress bar (navigation + fetch feedback) --------------------- */

#progress {
  position: fixed; top: 0; left: 0; height: 2.5px; width: 0;
  background: linear-gradient(90deg, var(--accent), var(--available));
  box-shadow: 0 0 12px var(--accent);
  z-index: 400;
  opacity: 0;
  transition: width 240ms var(--ease-out), opacity 200ms 120ms var(--ease-out);
}
#progress.active { opacity: 1; }

/* ---- Header ------------------------------------------------------------ */

.app-header {
  position: sticky; top: 0; z-index: 90;
  height: var(--header-h);
  display: flex; align-items: center; gap: 18px;
  padding: 0 22px;
  background: color-mix(in srgb, var(--surface) 82%, transparent);
  backdrop-filter: saturate(180%) blur(14px);
  -webkit-backdrop-filter: saturate(180%) blur(14px);
  border-bottom: 1px solid var(--border);
}

.brand {
  display: flex; align-items: center; gap: 10px;
  font-weight: 700; font-size: 0.98rem; letter-spacing: -0.02em;
  color: var(--text); white-space: nowrap;
}
.brand:hover { text-decoration: none; }

.brand-mark {
  width: 28px; height: 28px; border-radius: 9px; flex: none;
  display: grid; place-items: center;
  background: linear-gradient(140deg, var(--accent), #9333ea);
  color: #fff; font-size: 14px; font-weight: 800;
  box-shadow: 0 3px 10px var(--accent-ring);
  animation: mark-in 600ms var(--ease-spring) both;
}
@keyframes mark-in {
  from { transform: scale(0.5) rotate(-25deg); opacity: 0; }
  to { transform: none; opacity: 1; }
}

.nav { display: flex; gap: 3px; align-items: center; }

.nav a {
  position: relative;
  padding: 7px 12px; border-radius: var(--radius-sm);
  color: var(--text-muted); font-weight: 550; font-size: 0.875rem;
  transition: color 160ms var(--ease-out), background-color 160ms var(--ease-out);
}
.nav a:hover { color: var(--text); background: var(--surface-hover); text-decoration: none; }
.nav a.active { color: var(--accent); background: var(--accent-soft); }
.nav a.active::after {
  content: ""; position: absolute; left: 12px; right: 12px; bottom: 2px;
  height: 2px; border-radius: 2px; background: var(--accent);
  animation: underline-in 320ms var(--ease-out) both;
}
@keyframes underline-in { from { transform: scaleX(0); } to { transform: scaleX(1); } }

.header-spacer { flex: 1; }

.header-right { display: flex; align-items: center; gap: 8px; }

.user-chip {
  display: flex; align-items: center; gap: 8px;
  padding: 4px 10px 4px 4px; border-radius: 999px;
  border: 1px solid var(--border); background: var(--surface);
  font-size: 0.82rem; font-weight: 550; color: var(--text-muted);
}

.avatar {
  width: 26px; height: 26px; border-radius: 50%; flex: none;
  display: grid; place-items: center;
  background: linear-gradient(140deg, var(--accent), #9333ea);
  color: #fff; font-size: 11px; font-weight: 700;
}

/* ---- Layout ------------------------------------------------------------ */

.page {
  max-width: 1440px; margin: 0 auto;
  padding: 26px 22px 80px;
  animation: page-in 420ms var(--ease-out) both;
}
@keyframes page-in {
  from { opacity: 0; transform: translateY(10px); }
  to { opacity: 1; transform: none; }
}

.page-head {
  display: flex; flex-wrap: wrap; align-items: flex-end;
  justify-content: space-between; gap: 14px; margin-bottom: 20px;
}
.page-head p { color: var(--text-muted); margin: 0; font-size: 0.9rem; }

/* ---- Summary cards ----------------------------------------------------- */

.summary {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(155px, 1fr));
  gap: 12px; margin-bottom: 22px;
}

.stat {
  position: relative; overflow: hidden;
  display: block;
  padding: 15px 16px; border-radius: var(--radius);
  background: var(--surface); border: 1px solid var(--border);
  box-shadow: var(--shadow-sm);
  color: inherit;
  transform: translateY(12px); opacity: 0;
  animation: stat-in 520ms var(--ease-out) forwards;
  animation-delay: calc(var(--i, 0) * 55ms);
  transition: transform 200ms var(--ease-out), box-shadow 200ms var(--ease-out), border-color 200ms var(--ease-out);
}
@keyframes stat-in { to { transform: none; opacity: 1; } }

.stat:hover {
  transform: translateY(-3px); text-decoration: none;
  box-shadow: var(--shadow-lg); border-color: var(--border-strong);
}
.stat.is-active { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent) inset; }

.stat::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(115deg, transparent 35%, rgba(255, 255, 255, 0.42) 50%, transparent 65%);
  transform: translateX(-120%);
  pointer-events: none;
}
.stat:hover::after { animation: shine 750ms var(--ease-out); }
@keyframes shine { to { transform: translateX(120%); } }
[data-theme="dark"] .stat::after {
  background: linear-gradient(115deg, transparent 35%, rgba(255, 255, 255, 0.07) 50%, transparent 65%);
}

.stat-label {
  display: flex; align-items: center; gap: 6px;
  font-size: 0.72rem; font-weight: 650; letter-spacing: 0.07em;
  text-transform: uppercase; color: var(--text-faint);
}
.stat-value { font-size: 1.9rem; font-weight: 700; letter-spacing: -0.03em; font-variant-numeric: tabular-nums; }

.stat .dot { width: 8px; height: 8px; border-radius: 50%; background: currentColor; flex: none; }
.stat.available .dot, .stat.available .stat-value { color: var(--available); }
.stat.inuse .dot, .stat.inuse .stat-value { color: var(--inuse); }
.stat.maintenance .dot, .stat.maintenance .stat-value { color: var(--maintenance); }
.stat.disabled .dot, .stat.disabled .stat-value { color: var(--disabled); }
.stat.mine .dot, .stat.mine .stat-value { color: var(--accent); }

/* ---- The Available tile, as a terminal readout ------------------------- */

/*
   Only this tile. The other five keep the palette, because the row is a status legend before
   it is decoration - a board where every number glows the same green stops telling you
   anything. This is also why the green here is #00FF41 and not var(--available): the palette
   green has to work as a status dot and as text on a light card, and it goes muddy at the low
   alpha the glyphs behind it run at. The two greens sit next to each other on purpose.
*/
.stat.available {
  --matrix: #00ff41;
  --matrix-dim: #00b837;

  /* Also the colour the rain canvas reads, so the glyphs match the number. */
  --rain: #00ff41;

  background:
    radial-gradient(125% 95% at 50% 122%, rgba(0, 255, 65, 0.13), transparent 70%),
    linear-gradient(180deg, rgba(0, 255, 65, 0.035), rgba(0, 0, 0, 0.20)),
    #050805;
  border-color: rgba(0, 255, 65, 0.15);
}
.stat.available:hover { border-color: rgba(0, 255, 65, 0.4); }
.stat.available.is-active {
  border-color: var(--matrix);
  box-shadow: 0 0 0 1px rgba(0, 255, 65, 0.45) inset;
}

/* The default hover shine is white, which flashes hard against a near-black card. */
.stat.available::after {
  background: linear-gradient(115deg, transparent 35%, rgba(0, 255, 65, 0.1) 50%, transparent 65%);
}

/* The canvas is absolutely positioned, so the text has to be lifted above it. */
.stat.available .stat-label,
.stat.available .stat-value { position: relative; z-index: 1; }

.stat.available .stat-label { color: var(--matrix-dim); }
.stat.available .dot {
  background: var(--matrix);
  box-shadow: 0 0 6px rgba(0, 255, 65, 0.7);
}

.stat.available .stat-value {
  color: var(--matrix);
  /* No webfont: font-src is 'self' under the CSP, and a KPI is not worth relaxing it for.
     These are the terminal faces people actually have installed, then the app's own stack. */
  font-family: "JetBrains Mono", "Roboto Mono", ui-monospace, SFMono-Regular, var(--mono);
  font-weight: 700;
  /* Positive tracking, unlike the other tiles: digits should sit apart like a readout. */
  letter-spacing: 0.045em;
  font-variant-numeric: tabular-nums;
  text-shadow:
    0 0 4px rgba(0, 255, 65, 0.8),
    0 0 10px rgba(0, 255, 65, 0.45),
    0 0 20px rgba(0, 255, 65, 0.2);
}

/* A single lock-in pulse when the digits stop. One shot: a number that keeps moving is a
   number nobody can read. */
.stat.available .stat-value.is-resolved { animation: matrix-lock 420ms var(--ease-out) 1; }

@keyframes matrix-lock {
  0% {
    text-shadow:
      0 0 6px rgba(0, 255, 65, 1),
      0 0 16px rgba(0, 255, 65, 0.7),
      0 0 34px rgba(0, 255, 65, 0.4);
  }
  100% {
    text-shadow:
      0 0 4px rgba(0, 255, 65, 0.8),
      0 0 10px rgba(0, 255, 65, 0.45),
      0 0 20px rgba(0, 255, 65, 0.2);
  }
}

/*
   The rain behind the number. No opacity cap here any more: the "available" profile is itself
   dim enough now that capping it a second time only made this tile inconsistent with the
   available cards below it, and gave two knobs to turn for one effect.
*/
.stat.available .card-rain {
  -webkit-mask-image: linear-gradient(to bottom, transparent, rgba(0, 0, 0, 0.55) 40%, #000);
  mask-image: linear-gradient(to bottom, transparent, rgba(0, 0, 0, 0.55) 40%, #000);
}

@media (prefers-reduced-motion: reduce) {
  .stat.available .stat-value.is-resolved { animation: none; }
}

/* ---- Toolbar ----------------------------------------------------------- */

.toolbar {
  display: flex; flex-wrap: wrap; gap: 10px; align-items: center;
  margin-bottom: 18px;
}

.search {
  position: relative; flex: 1 1 300px; min-width: 220px;
}
.search input {
  width: 100%; padding: 10px 38px 10px 36px;
  border-radius: var(--radius); border: 1px solid var(--border);
  background: var(--surface); color: var(--text);
  font-size: 0.9rem; font-family: inherit;
  transition: border-color 160ms var(--ease-out), box-shadow 160ms var(--ease-out);
}
.search input:focus { outline: none; border-color: var(--accent); box-shadow: var(--shadow-glow); }
.search .icon {
  position: absolute; left: 12px; top: 50%; transform: translateY(-50%);
  color: var(--text-faint); pointer-events: none; display: flex;
}
.search kbd {
  position: absolute; right: 10px; top: 50%; transform: translateY(-50%);
  padding: 2px 6px; border-radius: 5px; font-size: 0.68rem;
  border: 1px solid var(--border); background: var(--surface-2); color: var(--text-faint);
}

.chips { display: flex; flex-wrap: wrap; gap: 6px; }

.chip {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 7px 13px; border-radius: 999px;
  border: 1px solid var(--border); background: var(--surface);
  color: var(--text-muted); font-size: 0.82rem; font-weight: 560;
  cursor: pointer; white-space: nowrap;
  transition: all 170ms var(--ease-out);
}
.chip:hover { border-color: var(--border-strong); color: var(--text); transform: translateY(-1px); text-decoration: none; }
.chip.active { background: var(--accent); border-color: var(--accent); color: #fff; box-shadow: 0 3px 10px var(--accent-ring); }
.chip .count {
  padding: 0 6px; border-radius: 999px; font-size: 0.72rem;
  background: var(--surface-hover); color: var(--text-faint);
}
.chip.active .count { background: rgba(255, 255, 255, 0.22); color: #fff; }

/* ---- Buttons ----------------------------------------------------------- */

.btn {
  position: relative; overflow: hidden;
  display: inline-flex; align-items: center; justify-content: center; gap: 7px;
  padding: 9px 16px; border-radius: var(--radius-sm);
  border: 1px solid var(--border); background: var(--surface); color: var(--text);
  font: inherit; font-size: 0.875rem; font-weight: 580;
  cursor: pointer; white-space: nowrap; text-decoration: none;
  transition: transform 130ms var(--ease-out), box-shadow 170ms var(--ease-out),
              background-color 170ms var(--ease-out), border-color 170ms var(--ease-out);
}
.btn:hover { background: var(--surface-hover); border-color: var(--border-strong); text-decoration: none; }
.btn:active { transform: scale(0.97); }
.btn:disabled, .btn[aria-disabled="true"] { opacity: 0.55; cursor: not-allowed; transform: none; }

.btn-primary {
  background: var(--accent); border-color: var(--accent); color: #fff;
  box-shadow: 0 3px 12px var(--accent-ring);
}
.btn-primary:hover { background: var(--accent-hover); border-color: var(--accent-hover); box-shadow: 0 6px 18px var(--accent-ring); }

.btn-claim {
  background: var(--available); border-color: var(--available); color: #fff;
  box-shadow: 0 3px 12px rgba(15, 157, 110, 0.32);
}
.btn-claim:hover { filter: brightness(1.08); box-shadow: 0 6px 20px rgba(15, 157, 110, 0.4); }

.btn-danger { color: var(--danger); border-color: color-mix(in srgb, var(--danger) 35%, var(--border)); }
.btn-danger:hover { background: var(--danger-soft); border-color: var(--danger); }

.btn-sm { padding: 6px 11px; font-size: 0.8rem; }
.btn-block { width: 100%; }

/* Click ripple, positioned by JS via CSSOM */
.ripple {
  position: absolute; border-radius: 50%; pointer-events: none;
  background: currentColor; opacity: 0.28;
  transform: scale(0);
  animation: ripple 560ms var(--ease-out) forwards;
}
@keyframes ripple { to { transform: scale(2.6); opacity: 0; } }

/* ---- Server type: client site vs backend service ------------------------ */

/* A pill, not a badge: the badge slot on a card belongs to the status, and these two facts must
   stay visually distinct or the card reads as having two statuses. */
.kind {
  display: inline-flex; align-items: center;
  padding: 1px 7px; border-radius: 5px;
  font-size: 0.68rem; font-weight: 700; letter-spacing: 0.04em;
  text-transform: uppercase; white-space: nowrap;
}
.kind.kind-client { color: var(--client); background: var(--client-soft); }
.kind.kind-backend { color: var(--backend); background: var(--backend-soft); }

/* The two type chips. Their own modifiers rather than the .kind-* pill classes above: a chip
   already owns its colours, and reusing the pill's would repaint the active state's white text
   onto a matching background. */
.kind-chips { margin-top: 12px; }
.chip.chip-client { color: var(--client); }
.chip.chip-backend { color: var(--backend); }
.chip.chip-client.active {
  color: #fff; background: var(--client); border-color: var(--client);
  box-shadow: 0 3px 10px var(--client-soft);
}
.chip.chip-backend.active {
  color: #fff; background: var(--backend); border-color: var(--backend);
  box-shadow: 0 3px 10px var(--backend-soft);
}

/* ---- Domain grid ------------------------------------------------------- */

.board-group > .grid { margin-top: 10px; }

.group-head {
  display: flex; align-items: center; gap: 9px;
  margin: 0; font-size: 0.92rem; font-weight: 640; color: var(--text-muted);
}
.group-head::after {
  content: ""; flex: 1; height: 1px; background: var(--border);
}
.group-head .count {
  order: 3;
  padding: 1px 7px; border-radius: 999px;
  font-size: 0.72rem; font-weight: 700;
  background: var(--surface-hover); color: var(--text-faint);
  border: 1px solid var(--border);
}

.grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(340px, 1fr));
  gap: 14px;
}

.card {
  position: relative; overflow: hidden;
  display: flex; flex-direction: column;
  border-radius: var(--radius-lg);
  background: var(--surface); border: 1px solid var(--border);
  box-shadow: var(--shadow-sm);
  transform: translateY(14px); opacity: 0;
  animation: card-in 460ms var(--ease-out) forwards;
  animation-delay: calc(var(--i, 0) * 38ms);
  transition: transform 230ms var(--ease-out), box-shadow 230ms var(--ease-out), border-color 230ms var(--ease-out);
}
@keyframes card-in { to { transform: none; opacity: 1; } }

.card:hover { transform: translateY(-4px); box-shadow: var(--shadow-lg); border-color: var(--border-strong); }

/* Status is carried by a left rail so it is legible without relying on colour alone. */
.card::before {
  content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 4px; z-index: 2;
  background: var(--rail, var(--disabled));
  transition: width 200ms var(--ease-out);
}
.card:hover::before { width: 6px; }

.card.status-available { --rail: var(--available); }
.card.status-inuse { --rail: var(--inuse); }
.card.status-maintenance { --rail: var(--maintenance); }
.card.status-disabled { --rail: var(--disabled); }

/* The rain takes its colour from the rail, except where something below overrides it. */
.card { --rain: var(--rail); }

/* A free domain rains the film's green, #00FF41, rather than the palette's. The two are not
   interchangeable: --available is picked to read as a status dot and as text on a light card,
   and it goes muddy at the low alpha the glyphs run at. This colour only ever ends up in the
   canvas, so it never has to pass a contrast check against body text.

   The rail, the badge, the summary dot and the filter chip all keep var(--available), so the
   legend still matches the board. This is the whole reason --rain exists apart from --rail. */
.card.status-available { --rain: #00ff41; }

/* A domain taken for a monday.com task at Level "Bug" reads red rather than amber, all the
   way through: rail, badge and the rain behind them. The badge still says "In use" — that is
   what the domain is — but nothing about the card looks like ordinary feature work.

   Both class pairs are needed: .card.status-inuse ties with .card.is-bug on specificity, and
   leaving source order to break the tie is the kind of thing a later edit quietly reverses. */
.card.status-inuse.is-bug { --rail: var(--danger); }
.card.status-inuse.is-bug .badge.inuse {
  color: var(--danger); background: var(--danger-soft);
}
.card.is-mine { border-color: color-mix(in srgb, var(--accent) 45%, var(--border)); }
.card.hidden-by-filter { display: none; }

/* ---- Matrix rain ------------------------------------------------------- */

/* The canvas is injected by app.js rather than by Razor: with scripting off, or
   under reduced motion, the card simply never gets one. */
.card-rain {
  position: absolute; inset: 0; width: 100%; height: 100%;
  z-index: 0; pointer-events: none;
  opacity: 0;
  transition: opacity 700ms var(--ease-out);
  /* Hold the glyphs off the domain name and let them gather further down. */
  -webkit-mask-image: linear-gradient(to bottom, transparent, rgba(0, 0, 0, 0.45) 34%, #000 66%);
  mask-image: linear-gradient(to bottom, transparent, rgba(0, 0, 0, 0.45) 34%, #000 66%);
}
.card-rain.on { opacity: 1; }

/* Card content rides above the rain; the status rail stays above both. */
.card > .card-head,
.card > .card-body,
.card > .card-foot { position: relative; z-index: 1; }

.card-head {
  display: flex; align-items: flex-start; gap: 10px;
  padding: 15px 16px 10px 19px;
}

.card-title { flex: 1; min-width: 0; }

.card-name {
  display: flex; align-items: center; gap: 7px;
  font-size: 1.02rem; font-weight: 680; letter-spacing: -0.02em;
  color: var(--text); word-break: break-all;
}
.card-name a { color: inherit; }
.card-name a:hover { color: var(--accent); text-decoration: none; }

.card-sub {
  font-size: 0.795rem; color: var(--text-faint);
  display: flex; flex-wrap: wrap; gap: 4px 9px; margin-top: 2px;
}

.card-body { padding: 4px 16px 12px 19px; flex: 1; }
.card-foot {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  padding: 11px 16px 13px 19px;
  border-top: 1px solid var(--border);
  background: var(--surface-2);
}

/* ---- Status badge ------------------------------------------------------ */

.badge {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 4px 10px 4px 8px; border-radius: 999px;
  font-size: 0.72rem; font-weight: 700; letter-spacing: 0.05em;
  text-transform: uppercase; white-space: nowrap; flex: none;
}
.badge .dot { width: 6px; height: 6px; border-radius: 50%; background: currentColor; flex: none; }

.badge.available { color: var(--available); background: var(--available-soft); }
.badge.inuse { color: var(--inuse); background: var(--inuse-soft); }
.badge.maintenance { color: var(--maintenance); background: var(--maintenance-soft); }
.badge.disabled { color: var(--disabled); background: var(--disabled-soft); }

/* A live pulse marks the domains someone is actively holding. */
.badge.available .dot { animation: pulse 2.4s var(--ease-out) infinite; }
@keyframes pulse {
  0%, 100% { box-shadow: 0 0 0 0 currentColor; opacity: 1; }
  70% { box-shadow: 0 0 0 5px transparent; opacity: 0.75; }
}

.tag {
  display: inline-flex; align-items: center;
  padding: 2px 8px; border-radius: 6px;
  font-size: 0.72rem; font-weight: 560;
  background: var(--surface-hover); color: var(--text-muted);
  border: 1px solid var(--border);
}
.tag.mine { background: var(--accent-soft); color: var(--accent); border-color: transparent; }
.tag.stale { background: var(--inuse-soft); color: var(--inuse); border-color: transparent; }

/* ---- Field rows -------------------------------------------------------- */

.facts { display: grid; grid-template-columns: auto 1fr; gap: 5px 12px; font-size: 0.83rem; }
.facts dt { color: var(--text-faint); white-space: nowrap; }
.facts dd { margin: 0; color: var(--text); min-width: 0; overflow-wrap: anywhere; }

/* ---- Monday task line -------------------------------------------------- */

/* Unresolved it is just a link. Resolved, it becomes two lines: what the task is
   called, then its status and who has it. */
.task.is-resolved { display: block; line-height: 1.35; }
.task-title { display: block; font-weight: 560; }
.task-meta {
  display: flex; flex-wrap: wrap; align-items: center; gap: 3px 8px;
  margin-top: 2px; font-size: 0.76rem; color: var(--text-faint);
}
.task-status {
  padding: 1px 7px; border-radius: 999px;
  background: var(--accent-soft); color: var(--accent);
  font-weight: 560; letter-spacing: 0.01em;
}
.task-who::before { content: "·"; margin-right: 8px; color: var(--border-strong); }
.task-board::before { content: "·"; margin-right: 8px; color: var(--border-strong); }
.task.is-resolved:hover .task-title { text-decoration: underline; }
.task.is-resolved:hover { text-decoration: none; }

.owner {
  display: flex; align-items: center; gap: 8px;
  padding: 9px 11px; border-radius: var(--radius-sm);
  background: var(--inuse-soft); margin-bottom: 10px;
}
.owner .avatar { width: 24px; height: 24px; font-size: 10px; }
.owner-name { font-weight: 640; font-size: 0.86rem; }
.owner-meta { font-size: 0.75rem; color: var(--text-muted); }

.copyable {
  display: inline-flex; align-items: center; gap: 5px;
  font-family: var(--mono); font-size: 0.79rem;
  padding: 1px 5px; border-radius: 5px;
  background: var(--surface-hover); border: 1px solid var(--border);
  cursor: pointer; color: var(--text-muted);
  transition: all 150ms var(--ease-out);
  max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.copyable:hover { color: var(--text); border-color: var(--accent); background: var(--accent-soft); }
.copyable.copied { color: var(--available); border-color: var(--available); background: var(--available-soft); }
.copyable svg { flex: none; }

.fav {
  display: grid; place-items: center; flex: none;
  width: 30px; height: 30px; border-radius: 50%;
  border: 1px solid transparent; background: none; cursor: pointer;
  color: var(--text-faint);
  transition: all 170ms var(--ease-out);
}
.fav:hover { background: var(--surface-hover); color: var(--inuse); transform: scale(1.12); }
.fav.on { color: var(--inuse); }
.fav.on svg { fill: currentColor; }
.fav.just-toggled { animation: pop 420ms var(--ease-spring); }
@keyframes pop { 40% { transform: scale(1.35) rotate(12deg); } }

/* ---- Empty state ------------------------------------------------------- */

.empty {
  grid-column: 1 / -1;
  display: flex; flex-direction: column; align-items: center; gap: 8px;
  padding: 64px 20px; text-align: center;
  color: var(--text-muted);
  border: 1px dashed var(--border-strong); border-radius: var(--radius-lg);
  animation: page-in 400ms var(--ease-out) both;
}
.empty .glyph { font-size: 2.4rem; opacity: 0.55; }

/* ---- Panels, tables, forms --------------------------------------------- */

.panel {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius-lg); box-shadow: var(--shadow-sm);
  margin-bottom: 16px; overflow: hidden;
}
.panel-head {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 14px 18px; border-bottom: 1px solid var(--border);
  background: var(--surface-2);
}
.panel-head h2, .panel-head h3 { margin: 0; }
.panel-body { padding: 18px; }

.table-wrap { overflow-x: auto; }
table { width: 100%; border-collapse: collapse; font-size: 0.86rem; }
thead th {
  position: sticky; top: 0; z-index: 1;
  text-align: left; padding: 10px 14px;
  font-size: 0.72rem; font-weight: 680; letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--text-faint); background: var(--surface-2);
  border-bottom: 1px solid var(--border); white-space: nowrap;
}
tbody td { padding: 11px 14px; border-bottom: 1px solid var(--border); vertical-align: middle; }
tbody tr { transition: background-color 140ms var(--ease-out); }
tbody tr:hover { background: var(--surface-hover); }
tbody tr:last-child td { border-bottom: none; }

.form-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 14px; }

.field { display: flex; flex-direction: column; gap: 5px; min-width: 0; }
.field.wide { grid-column: 1 / -1; }
.field label { font-size: 0.79rem; font-weight: 620; color: var(--text-muted); }
.field .hint { font-size: 0.75rem; color: var(--text-faint); }

input[type="text"], input[type="password"], input[type="email"], input[type="url"],
input[type="number"], input[type="date"], input[type="search"], select, textarea {
  width: 100%; padding: 9px 11px;
  border-radius: var(--radius-sm); border: 1px solid var(--border);
  background: var(--surface); color: var(--text);
  font-family: inherit; font-size: 0.9rem;
  transition: border-color 150ms var(--ease-out), box-shadow 150ms var(--ease-out);
}
textarea { resize: vertical; min-height: 90px; font-family: var(--mono); font-size: 0.85rem; line-height: 1.6; }

input:focus, select:focus, textarea:focus {
  outline: none; border-color: var(--accent); box-shadow: var(--shadow-glow);
}
input::placeholder, textarea::placeholder { color: var(--text-faint); }

.check { display: flex; align-items: center; gap: 8px; font-size: 0.87rem; color: var(--text-muted); }
.check input { width: auto; }

.form-actions { display: flex; gap: 10px; flex-wrap: wrap; margin-top: 18px; }

.validation {
  padding: 10px 13px; border-radius: var(--radius-sm);
  background: var(--danger-soft); color: var(--danger);
  border: 1px solid color-mix(in srgb, var(--danger) 28%, transparent);
  font-size: 0.85rem; margin-bottom: 14px;
  animation: shake 420ms var(--ease-out);
}
@keyframes shake {
  10%, 90% { transform: translateX(-2px); }
  30%, 70% { transform: translateX(4px); }
  50% { transform: translateX(-4px); }
}
.field-error { color: var(--danger); font-size: 0.77rem; }

/* ---- Modal ------------------------------------------------------------- */

dialog.modal {
  padding: 0; border: none; max-width: 620px; width: calc(100% - 32px);
  border-radius: var(--radius-lg); background: var(--surface); color: var(--text);
  box-shadow: var(--shadow-lg);
}
dialog.modal::backdrop {
  background: rgba(9, 12, 19, 0.55);
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
}
dialog.modal[open] { animation: modal-in 320ms var(--ease-spring); }
dialog.modal[open]::backdrop { animation: fade-in 240ms var(--ease-out); }
dialog.modal.closing { animation: modal-out 170ms var(--ease-out) forwards; }

@keyframes modal-in {
  from { opacity: 0; transform: translateY(18px) scale(0.94); }
  to { opacity: 1; transform: none; }
}
@keyframes modal-out {
  to { opacity: 0; transform: translateY(8px) scale(0.97); }
}
@keyframes fade-in { from { opacity: 0; } to { opacity: 1; } }

.modal-head {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 16px 20px; border-bottom: 1px solid var(--border);
}
.modal-body { padding: 20px; max-height: 65vh; overflow-y: auto; }
.modal-foot {
  display: flex; justify-content: flex-end; gap: 10px;
  padding: 14px 20px; border-top: 1px solid var(--border); background: var(--surface-2);
}
.modal-close {
  border: none; background: none; cursor: pointer; color: var(--text-faint);
  font-size: 1.3rem; line-height: 1; padding: 4px 8px; border-radius: 6px;
  transition: all 150ms var(--ease-out);
}
.modal-close:hover { background: var(--surface-hover); color: var(--text); transform: rotate(90deg); }

/* ---- Toasts ------------------------------------------------------------ */

#toasts {
  position: fixed; bottom: 22px; right: 22px; z-index: 500;
  display: flex; flex-direction: column-reverse; gap: 10px;
  max-width: min(400px, calc(100vw - 32px));
}

.toast {
  display: flex; align-items: flex-start; gap: 10px;
  padding: 12px 15px; border-radius: var(--radius);
  background: var(--surface); border: 1px solid var(--border);
  box-shadow: var(--shadow-lg); font-size: 0.87rem;
  animation: toast-in 380ms var(--ease-spring);
  border-left: 3px solid var(--accent);
}
.toast.leaving { animation: toast-out 240ms var(--ease-out) forwards; }
.toast.success { border-left-color: var(--available); }
.toast.error { border-left-color: var(--danger); }
.toast.info { border-left-color: var(--maintenance); }
.toast .toast-icon { flex: none; margin-top: 1px; }
.toast.success .toast-icon { color: var(--available); }
.toast.error .toast-icon { color: var(--danger); }
.toast.info .toast-icon { color: var(--maintenance); }

@keyframes toast-in {
  from { opacity: 0; transform: translateX(90px) scale(0.9); }
  to { opacity: 1; transform: none; }
}
@keyframes toast-out {
  to { opacity: 0; transform: translateX(40px) scale(0.94); }
}

/* ---- Timeline ---------------------------------------------------------- */

.timeline { list-style: none; margin: 0; padding: 0 0 0 22px; position: relative; }
.timeline::before {
  content: ""; position: absolute; left: 5px; top: 6px; bottom: 6px;
  width: 2px; background: var(--border);
}
.timeline li {
  position: relative; padding: 0 0 16px 4px;
  animation: page-in 400ms var(--ease-out) both;
  animation-delay: calc(var(--i, 0) * 45ms);
}
.timeline li::before {
  content: ""; position: absolute; left: -21px; top: 6px;
  width: 10px; height: 10px; border-radius: 50%;
  background: var(--surface); border: 2px solid var(--accent);
}
.timeline li.claim::before { border-color: var(--inuse); }
.timeline li.release::before { border-color: var(--available); }
.timeline .when { font-size: 0.75rem; color: var(--text-faint); font-variant-numeric: tabular-nums; }
.timeline .what { font-size: 0.88rem; }
.timeline .extra { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 4px; }

/* ---- Markdown output --------------------------------------------------- */

.md { font-size: 0.9rem; line-height: 1.7; }
.md h3, .md h4, .md h5 { margin: 1.2em 0 0.4em; }
.md h3 { font-size: 1.05rem; }
.md h4 { font-size: 0.96rem; }
.md h5 { font-size: 0.9rem; color: var(--text-muted); }
.md pre {
  background: var(--surface-2); border: 1px solid var(--border);
  border-radius: var(--radius-sm); padding: 12px 14px; overflow-x: auto;
}
.md code { background: var(--surface-hover); padding: 1px 5px; border-radius: 4px; }
.md pre code { background: none; padding: 0; }
.md blockquote {
  margin: 0.8em 0; padding: 6px 14px;
  border-left: 3px solid var(--accent); background: var(--accent-soft);
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0; color: var(--text-muted);
}
.md ul, .md ol { padding-left: 22px; }
.md hr { border: none; border-top: 1px solid var(--border); margin: 1.2em 0; }
.md table { margin: 0.8em 0; }

/* ---- Login ------------------------------------------------------------- */

.login-shell {
  min-height: 100vh; display: grid; place-items: center; padding: 24px;
  position: relative; overflow: hidden;
}

/* Slow-drifting aurora behind the sign-in card. Purely decorative. */
.login-shell::before,
.login-shell::after {
  content: ""; position: absolute; border-radius: 50%;
  filter: blur(90px); opacity: 0.5; pointer-events: none;
}
.login-shell::before {
  width: 460px; height: 460px; top: -160px; left: -120px;
  background: radial-gradient(circle, var(--accent), transparent 70%);
  animation: drift 18s ease-in-out infinite alternate;
}
.login-shell::after {
  width: 400px; height: 400px; bottom: -140px; right: -100px;
  background: radial-gradient(circle, #9333ea, transparent 70%);
  animation: drift 22s ease-in-out infinite alternate-reverse;
}
@keyframes drift {
  to { transform: translate(70px, 50px) scale(1.16); }
}

.login-card {
  position: relative; z-index: 1;
  width: 100%; max-width: 400px;
  padding: 32px; border-radius: 22px;
  background: color-mix(in srgb, var(--surface) 92%, transparent);
  backdrop-filter: blur(16px); -webkit-backdrop-filter: blur(16px);
  border: 1px solid var(--border); box-shadow: var(--shadow-lg);
  animation: login-in 620ms var(--ease-spring) both;
}
@keyframes login-in {
  from { opacity: 0; transform: translateY(26px) scale(0.95); }
  to { opacity: 1; transform: none; }
}

.login-card .brand-mark { width: 44px; height: 44px; border-radius: 14px; font-size: 20px; margin-bottom: 16px; }
.login-card h1 { font-size: 1.35rem; margin-bottom: 4px; }
.login-card .lede { color: var(--text-muted); font-size: 0.87rem; margin-bottom: 22px; }
.login-card .field { margin-bottom: 14px; }
.login-note { margin-top: 18px; font-size: 0.78rem; color: var(--text-faint); text-align: center; }

/* ---- Command palette --------------------------------------------------- */

dialog.palette {
  padding: 0; border: none; margin-top: 12vh;
  width: min(560px, calc(100% - 32px));
  border-radius: var(--radius-lg); background: var(--surface);
  box-shadow: var(--shadow-lg); color: var(--text);
}
dialog.palette::backdrop { background: rgba(9, 12, 19, 0.5); backdrop-filter: blur(3px); }
dialog.palette[open] { animation: modal-in 260ms var(--ease-spring); }

.palette input {
  border: none; border-bottom: 1px solid var(--border); border-radius: 0;
  padding: 15px 18px; font-size: 0.98rem; background: none;
}
.palette input:focus { box-shadow: none; border-color: var(--border); }
.palette ul { list-style: none; margin: 0; padding: 6px; max-height: 320px; overflow-y: auto; }
.palette li {
  display: flex; align-items: center; gap: 10px;
  padding: 9px 12px; border-radius: var(--radius-sm); cursor: pointer;
  font-size: 0.88rem;
}
.palette li[aria-selected="true"] { background: var(--accent-soft); color: var(--accent); }
.palette li .meta { margin-left: auto; font-size: 0.75rem; color: var(--text-faint); }
.palette .none { padding: 22px; text-align: center; color: var(--text-faint); font-size: 0.87rem; }

/* ---- Misc -------------------------------------------------------------- */

.icon-btn {
  display: grid; place-items: center; width: 34px; height: 34px;
  border-radius: var(--radius-sm); border: 1px solid var(--border);
  background: var(--surface); color: var(--text-muted); cursor: pointer;
  transition: all 170ms var(--ease-out);
}
.icon-btn:hover { color: var(--text); border-color: var(--border-strong); transform: translateY(-1px); }
.icon-btn svg { transition: transform 400ms var(--ease-spring); }
.icon-btn:hover svg { transform: rotate(22deg); }

.row { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.spacer { flex: 1; }
.muted { color: var(--text-muted); }
.faint { color: var(--text-faint); }
.small { font-size: 0.8rem; }
.mono { font-family: var(--mono); }
.nowrap { white-space: nowrap; }
.mt { margin-top: 16px; }
.mb0 { margin-bottom: 0; }

.pagination { display: flex; gap: 6px; align-items: center; justify-content: center; padding: 14px; }

/* ---- Responsive --------------------------------------------------------

   Desktop-first, checked down to 320px. Three things drive the breakpoints:
   the domain grid collapsing to one column, the header running out of room,
   and the admin tables becoming unreadable as tables.
   ------------------------------------------------------------------------ */

/* Nothing may cause a horizontal scrollbar on the page itself. Wide content
   (tables, code blocks) scrolls inside its own container instead. */
html,
body { max-width: 100%; overflow-x: hidden; }

/* Honour the notch and the home indicator in mobile Safari. */
.app-header {
  padding-left: max(22px, env(safe-area-inset-left));
  padding-right: max(22px, env(safe-area-inset-right));
}
.page {
  padding-left: max(22px, env(safe-area-inset-left));
  padding-right: max(22px, env(safe-area-inset-right));
  padding-bottom: calc(80px + env(safe-area-inset-bottom));
}

@media (max-width: 1100px) {
  .summary { grid-template-columns: repeat(3, 1fr); }
}

@media (max-width: 900px) {
  .page { padding-top: 18px; }
  .grid { grid-template-columns: 1fr; }
  .stat-value { font-size: 1.6rem; }

  /* The header can no longer hold nav + identity + actions on one line, so the
     nav moves to its own scrollable strip underneath. */
  .app-header { height: auto; flex-wrap: wrap; gap: 10px; padding-top: 10px; padding-bottom: 0; }
  .header-spacer { display: none; }
  .brand { flex: 1; }

  .nav {
    order: 10;
    width: 100%;
    margin: 4px 0 0;
    padding: 0 0 8px;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
  }
  .nav::-webkit-scrollbar { display: none; }
  .nav a { white-space: nowrap; }
  .nav a.active::after { bottom: -2px; }

  .user-chip { padding: 4px; }
  .user-chip .who { display: none; }
}

@media (max-width: 680px) {
  .summary { grid-template-columns: repeat(2, 1fr); }

  .page-head { align-items: stretch; }
  .page-head .row { width: 100%; }
  .page-head .row .btn { flex: 1 1 auto; justify-content: center; }

  /* Filters stack rather than squeezing into unusable widths. */
  .toolbar { flex-direction: column; align-items: stretch; }
  .toolbar .search { flex: none; width: 100%; min-width: 0; }
  .toolbar select,
  .toolbar .btn { width: 100%; }

  /* Tables become one card per row. Each cell carries its column name via
     data-label, so the data stays labelled instead of becoming an anonymous
     list of values. */
  .table-wrap table thead { display: none; }
  .table-wrap table,
  .table-wrap tbody,
  .table-wrap tr,
  .table-wrap td { display: block; width: 100%; }

  .table-wrap tr {
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--surface);
    margin-bottom: 10px;
    padding: 4px 2px;
  }
  .table-wrap tr:hover { background: var(--surface); }

  .table-wrap td {
    display: flex;
    align-items: baseline;
    gap: 12px;
    padding: 7px 13px;
    border-bottom: none;
    white-space: normal;
  }
  .table-wrap td::before {
    content: attr(data-label);
    flex: 0 0 40%;
    font-size: 0.72rem;
    font-weight: 680;
    letter-spacing: 0.05em;
    text-transform: uppercase;
    color: var(--text-faint);
  }

  /* The actions column has no label, so its button gets the full width. */
  .table-wrap td[data-label=""]::before { display: none; }
  .table-wrap td[data-label=""] { padding-top: 10px; }
  .table-wrap td[data-label=""] .btn { width: 100%; justify-content: center; }
  .table-wrap td[colspan] { text-align: left; }
  .table-wrap td[colspan]::before { display: none; }
}

@media (max-width: 560px) {
  /* 16px minimum on touch inputs: anything smaller makes iOS Safari zoom on focus. */
  input,
  select,
  textarea { font-size: 16px; }

  .search kbd { display: none; }
  .brand span { display: none; }

  #toasts {
    left: 14px;
    right: 14px;
    bottom: calc(14px + env(safe-area-inset-bottom));
    max-width: none;
  }

  .page {
    padding-left: max(14px, env(safe-area-inset-left));
    padding-right: max(14px, env(safe-area-inset-right));
  }
  .app-header {
    padding-left: max(14px, env(safe-area-inset-left));
    padding-right: max(14px, env(safe-area-inset-right));
  }

  h1 { font-size: 1.3rem; }
  .summary { gap: 8px; }
  .stat { padding: 12px 13px; }
  .stat-value { font-size: 1.45rem; }

  /* Comfortable thumb targets — 44px is the usual accessibility floor. */
  .btn { min-height: 44px; padding: 10px 16px; }
  .btn-sm { min-height: 38px; }
  .chip { min-height: 38px; }
  .fav { width: 40px; height: 40px; }
  .icon-btn { width: 40px; height: 40px; }

  .card-head,
  .card-body,
  .card-foot { padding-left: 15px; padding-right: 13px; }
  .card-foot .btn { flex: 1 1 auto; justify-content: center; }

  /* Long paths and URLs wrap instead of widening the card. */
  .facts { grid-template-columns: 1fr; gap: 2px 0; }
  .facts dt { margin-top: 6px; }
  .copyable { max-width: 100%; white-space: normal; word-break: break-all; text-align: left; }

  /* Dialogs behave as bottom sheets: reachable with a thumb, and they survive
     the on-screen keyboard appearing (dvh, with vh as the older fallback). */
  dialog.modal {
    width: 100%;
    max-width: none;
    margin: 0;
    position: fixed;
    inset: auto 0 0 0;
    border-radius: var(--radius-lg) var(--radius-lg) 0 0;
    max-height: 92vh;
    max-height: 92dvh;
  }
  dialog.modal[open] { animation: sheet-in 300ms var(--ease-out); }
  dialog.modal.closing { animation: sheet-out 190ms var(--ease-out) forwards; }

  .modal-body { max-height: none; padding: 16px; }
  .modal-foot { padding-bottom: calc(14px + env(safe-area-inset-bottom)); }
  .modal-foot .btn { flex: 1 1 auto; justify-content: center; }
  .form-grid { grid-template-columns: 1fr; }

  dialog.palette { margin-top: 6vh; width: calc(100% - 20px); }

  .timeline { padding-left: 18px; }
  .panel-head { flex-wrap: wrap; gap: 6px; }
  .panel-body { padding: 14px; }
}

@keyframes sheet-in {
  from { opacity: 0; transform: translateY(100%); }
  to { opacity: 1; transform: none; }
}
@keyframes sheet-out {
  to { opacity: 0; transform: translateY(100%); }
}

@media (max-width: 380px) {
  .page-head .row { flex-direction: column; align-items: stretch; }
  .card-name { font-size: 0.95rem; }
}

/* Landscape phones have a very short viewport; give dialogs room to scroll. */
@media (max-height: 480px) and (orientation: landscape) {
  dialog.modal { max-height: 96vh; max-height: 96dvh; }
  .modal-body { max-height: 60vh; overflow-y: auto; }
}

/* Touch devices: drop the hover-lift, which sticks after a tap, and the blue
   tap flash. */
@media (hover: none) {
  .card:hover { transform: none; box-shadow: var(--shadow-sm); }
  .card:hover::before { width: 4px; }
  .stat:hover { transform: none; box-shadow: var(--shadow-sm); }
  .stat:hover::after { animation: none; }
  .chip:hover { transform: none; }
  .btn:hover { background: var(--surface); }
  .btn-primary:hover { background: var(--accent); }

  * { -webkit-tap-highlight-color: transparent; }
  body { overscroll-behavior-y: none; }
}

/* ---- Motion preferences ------------------------------------------------ */

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
  }
  .card,
  .stat,
  .timeline li { opacity: 1; transform: none; }
  .card-rain { display: none; }
}

@media print {
  .app-header,
  .toolbar,
  .card-foot,
  .card-rain,
  #toasts,
  .btn { display: none !important; }
  body { background: #fff; }
  .card { break-inside: avoid; box-shadow: none; }
}

/* ---- Comments ---------------------------------------------------------- */

.comment {
  display: flex; gap: 11px; align-items: flex-start;
  padding: 12px 0; border-top: 1px solid var(--border);
  animation: page-in 320ms var(--ease-out) both;
}
.comment:first-child { border-top: none; }
.comment .avatar { width: 30px; height: 30px; font-size: 12px; margin-top: 2px; }
.comment-body { flex: 1; min-width: 0; }

/* Edit and delete sit at the far end of the meta line and stay quiet until the comment is
   hovered or something inside it has focus. They are always reachable by keyboard: the
   focus-within rule brings them back for anyone tabbing through the thread. */
.comment-actions {
  margin-left: auto; display: flex; gap: 9px;
  opacity: 0; transition: opacity 140ms var(--ease-out);
}
.comment:hover .comment-actions,
.comment:focus-within .comment-actions { opacity: 1; }

.link-btn {
  background: none; border: none; padding: 0; cursor: pointer;
  font: inherit; color: var(--text-faint); text-decoration: underline;
  text-underline-offset: 2px;
}
.link-btn:hover { color: var(--accent); }
.link-btn.danger:hover { color: var(--danger); }
.link-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 3px; }

/* The inline editor replaces the comment text in place, so the thread does not jump. */
.comment-edit { display: flex; flex-direction: column; gap: 7px; margin-top: 4px; }
.comment-edit textarea {
  width: 100%; min-height: 68px; resize: vertical;
  font: inherit; line-height: 1.5;
}
.comment-edit-actions { display: flex; gap: 7px; }
.comment-meta {
  display: flex; flex-wrap: wrap; align-items: center; gap: 7px;
  font-size: 0.8rem; margin-bottom: 3px;
}
.comment-text {
  margin: 0; font-size: 0.9rem; line-height: 1.6;
  white-space: pre-wrap;          /* keep the author's line breaks */
  overflow-wrap: anywhere;        /* a pasted URL must not widen the panel */
}

/* ---- Activity feed ----------------------------------------------------- */

.feed-panel { margin-top: 22px; }

.feed { list-style: none; margin: 0; padding: 0 0 0 20px; position: relative; }
.feed::before {
  content: ""; position: absolute; left: 4px; top: 10px; bottom: 10px;
  width: 2px; border-radius: 2px;
  background: linear-gradient(var(--border), transparent);
}

.feed-item {
  position: relative;
  display: flex; gap: 10px;
  padding: 9px 0;
  animation: feed-in 460ms var(--ease-out) both;
  animation-delay: calc(var(--i, 0) * 45ms);
}
@keyframes feed-in {
  from { opacity: 0; transform: translateX(-10px); }
  to { opacity: 1; transform: none; }
}

.feed-dot {
  position: absolute; left: -20px; top: 14px;
  width: 9px; height: 9px; border-radius: 50%;
  background: var(--surface);
  border: 2px solid var(--disabled);
}
.feed-item.claimed .feed-dot { border-color: var(--inuse); }
.feed-item.released .feed-dot { border-color: var(--available); }
.feed-item.deployed .feed-dot { border-color: var(--accent); }
.feed-item.commented .feed-dot { border-color: var(--maintenance); }
.feed-item.statuschanged .feed-dot { border-color: var(--disabled); }

.feed-content { min-width: 0; flex: 1; }
.feed-text { font-size: 0.88rem; }
.feed-text a { color: var(--text); }
.feed-text a:hover { color: var(--accent); text-decoration: none; }
.feed-detail {
  font-size: 0.82rem; color: var(--text-muted); margin-top: 1px;
  overflow-wrap: anywhere;
}
.feed-when { font-size: 0.74rem; color: var(--text-faint); margin-top: 2px; }

/* ---- Comment count on a card ------------------------------------------- */

.comment-count {
  display: inline-flex; align-items: center; gap: 3px;
  margin-left: 6px; padding: 1px 6px 1px 5px;
  border-radius: 999px; font-size: 0.72rem; font-weight: 650;
  background: var(--maintenance-soft); color: var(--maintenance);
}

/* ---- Live updates ------------------------------------------------------ */

/* Applied by the poller when a card's status or owner changed underneath you. */
.card.just-changed {
  animation: card-changed 1900ms var(--ease-out);
}
@keyframes card-changed {
  0% { box-shadow: 0 0 0 0 var(--accent-ring), var(--shadow-sm); }
  18% { box-shadow: 0 0 0 7px var(--accent-ring), var(--shadow-lg); }
  100% { box-shadow: 0 0 0 0 transparent, var(--shadow-sm); }
}

.badge.swapping { animation: badge-swap 460ms var(--ease-spring); }
@keyframes badge-swap {
  0% { transform: scale(1); }
  45% { transform: scale(0.82); opacity: 0.5; }
  100% { transform: scale(1); opacity: 1; }
}

/* Small live indicator in the toolbar so the polling is visible, not spooky. */
.live-dot {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 0.74rem; color: var(--text-faint);
}
.live-dot::before {
  content: ""; width: 7px; height: 7px; border-radius: 50%;
  background: var(--available);
  animation: live-pulse 2.6s var(--ease-out) infinite;
}
@keyframes live-pulse {
  0%, 100% { opacity: 1; box-shadow: 0 0 0 0 var(--available); }
  60% { opacity: 0.45; box-shadow: 0 0 0 5px transparent; }
}

/* ---- Claim celebration -------------------------------------------------- */

.confetti-piece {
  position: fixed; top: 0; left: 0;
  width: 8px; height: 8px; border-radius: 1px;
  pointer-events: none; z-index: 600;
  will-change: transform, opacity;
}

@media (prefers-reduced-motion: reduce) {
  .feed-item { opacity: 1; transform: none; }
  .card.just-changed { animation: none; box-shadow: 0 0 0 2px var(--accent); }
  .live-dot::before { animation: none; }
  .confetti-piece { display: none; }
}

/* ---- Last comment on a card --------------------------------------------
   Reads as a quote, not as another fact row: the card's job is still status
   first, owner second. It sits below the facts, muted until hovered.
   ------------------------------------------------------------------------ */

.card-comment {
  position: relative;
  display: flex; gap: 9px; align-items: flex-start;
  margin-top: 12px; padding: 9px 11px 9px 10px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border);
  border-left: 3px solid color-mix(in srgb, var(--maintenance) 55%, var(--border));
  background: var(--surface-2);
  color: var(--text-muted);
  text-decoration: none;
  overflow: hidden;
  transition: border-color 180ms var(--ease-out), background-color 180ms var(--ease-out),
              transform 180ms var(--ease-out);
}

.card-comment:hover {
  text-decoration: none;
  background: var(--surface-hover);
  border-left-color: var(--maintenance);
  border-color: var(--border-strong);
  transform: translateX(2px);
}

/* A slow sheen on hover, matching the summary cards. Decorative only. */
.card-comment::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(115deg, transparent 40%, rgba(255, 255, 255, 0.05) 50%, transparent 60%);
  transform: translateX(-120%);
  pointer-events: none;
}
.card-comment:hover::after { animation: shine 900ms var(--ease-out); }

.card-comment-quote {
  flex: none; display: flex; margin-top: 1px;
  color: var(--maintenance);
  transition: transform 260ms var(--ease-spring);
}
.card-comment:hover .card-comment-quote { transform: scale(1.15) rotate(-6deg); }

.card-comment-body { min-width: 0; flex: 1; }

.card-comment-meta {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: 6px;
  font-size: 0.75rem; margin-bottom: 2px;
}
.card-comment-meta strong { color: var(--text); font-weight: 640; }

.card-comment-more {
  padding: 0 6px; border-radius: 999px;
  font-size: 0.68rem; font-weight: 650;
  background: var(--maintenance-soft); color: var(--maintenance);
}

.card-comment-text {
  display: -webkit-box;
  -webkit-line-clamp: 2;          /* two lines keeps every card the same height */
  line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  font-size: 0.83rem; line-height: 1.45;
  color: var(--text-muted);
  overflow-wrap: anywhere;
}
.card-comment:hover .card-comment-text { color: var(--text); }

/* Posted in the last hour: a quiet pulse on the rail, so "something just
   happened here" is visible while scanning without shouting. */
.card-comment.is-fresh {
  border-left-color: var(--maintenance);
  animation: comment-fresh 3.4s var(--ease-out) infinite;
}
@keyframes comment-fresh {
  0%, 100% { box-shadow: -3px 0 0 0 transparent; }
  50% { box-shadow: -3px 0 10px -2px var(--maintenance); }
}

/* Live poller swapped the text underneath you. */
.card-comment.just-updated { animation: comment-arrived 900ms var(--ease-spring); }
@keyframes comment-arrived {
  0% { transform: translateY(-6px) scale(0.98); opacity: 0.4; }
  60% { transform: translateY(0) scale(1.01); opacity: 1; }
  100% { transform: none; }
}

@media (prefers-reduced-motion: reduce) {
  .card-comment,
  .card-comment:hover { transform: none; }
  .card-comment.is-fresh { animation: none; }
  .card-comment.just-updated { animation: none; }
  .card-comment:hover .card-comment-quote { transform: none; }
}
