/* Dark is the default; light is a full first-class variant selected by
   data-theme on <html>. Both blocks define the same token names, so every rule
   below reads from whichever is active without a single themed selector. */
:root,
:root[data-theme="dark"] {
  /* "Bento Ops" palette. Deep navy surfaces with a blue primary and a green
     signal accent, replacing the earlier indigo/violet set. Variable names are
     unchanged from that set so every existing rule picks the new values up
     without edits. */
  --bg: #0b1220;
  --panel: #111c2e;
  --panel-2: #16233a;
  --border: #22314b;
  --text: #f1f5f9;
  --muted: #93a3bc;
  --accent: #3b82f6;
  --accent-2: #2563eb;

  /* --accent is a 3.42:1 background for white text, below the 4.5:1 AA floor
     for the 13px labels that sit on it. These two are the same hue darkened to
     clear AA (5.1:1 and 5.8:1) and are used ONLY as a fill behind white text.
     --accent itself is unchanged: as a border, icon, and focus ring on --bg it
     already passes, and darkening it there would dull the whole UI. */
  --accent-solid: #2563eb;
  --accent-solid-2: #1d4ed8;
  --danger: #f87171;
  --danger-bg: #3f1d2b;
  --ok: #10b981;

  /* Semantic status colors. These were repeated as literal hex values across
     the badge, toast, category, and stale-locale rules; they are tokens now so
     a palette change reaches all of them at once. Each -fg is AA against its
     own -bg, not against --bg. */
  --ok-bg: #0d3b2e;
  --ok-border: #1a5c47;
  --ok-fg: #6ee7b7;
  --warn: #f59e0b;
  --warn-bg: #3a2a15;
  --warn-border: #5c4420;
  --warn-fg: #fcd34d;
  --danger-border: #6b2a38;
  --danger-fg: #fca5a5;

  /* Hover fills. Derived from the surface tokens rather than fixed hex so they
     track the palette. */
  --panel-hover: #1c2b45;
  --border-hover: #2e4160;

  --radius: 12px;
  /* Bento Ops leans on a slightly larger corner for cards and panels while
     keeping --radius for controls, so both scales are available. */
  --radius-lg: 18px;
  --shadow: 0 1px 2px rgba(0, 0, 0, 0.4), 0 8px 24px -12px rgba(0, 0, 0, 0.6);
  --glow: 0 0 0 1px rgba(59, 130, 246, 0.25), 0 8px 30px -8px rgba(59, 130, 246, 0.35);

  /* One duration and one curve for the whole UI. Every hover, lift, and state
     change reads from these, so the interface shares a single sense of weight
     instead of each component easing on its own timing. */
  --dur: 200ms;
  --ease: cubic-bezier(0.16, 1, 0.3, 1);

  /* Modal scrim. A token because the two themes need different values: a near
     black wash under a dark UI, a lighter slate wash under a light one. */
  --scrim: rgba(5, 7, 14, 0.72);

  /* The one part of a <select> no stylesheet reaches: the native option popup.
     Declaring the scheme is what makes the browser paint it dark to match. */
  color-scheme: dark;
}

/* Light theme. Same token names, re-valued — no rule below is theme-aware.
   The accents are darkened relative to the dark set because the same hue that
   clears AA on a navy surface fails on white. */
:root[data-theme="light"] {
  --bg: #f4f7fb;
  --panel: #ffffff;
  --panel-2: #f8fafc;
  --border: #e2e8f0;
  --text: #0f172a;
  --muted: #52627a;
  --accent: #2563eb;
  --accent-2: #1d4ed8;

  /* On light surfaces --accent (#2563eb) is already 5.17:1 against white, so
     unlike the dark theme it needs no separate darkened fill. Kept as distinct
     tokens anyway so the white-text-on-accent rules stay correct. */
  --accent-solid: #2563eb;
  --accent-solid-2: #1d4ed8;
  --danger: #dc2626;
  --danger-bg: #fef2f2;
  --ok: #059669;

  /* Each -fg is AA against its own -bg, matching the dark set's contract. */
  --ok-bg: #ecfdf5;
  --ok-border: #a7f3d0;
  --ok-fg: #047857;
  --warn: #b45309;
  --warn-bg: #fffbeb;
  --warn-border: #fde68a;
  --warn-fg: #92400e;
  --danger-border: #fecaca;
  --danger-fg: #b91c1c;

  --panel-hover: #f1f5f9;
  --border-hover: #cbd5e1;

  --shadow: 0 1px 2px rgba(15, 23, 42, 0.06), 0 8px 24px -14px rgba(15, 23, 42, 0.25);
  --glow: 0 0 0 1px rgba(37, 99, 235, 0.18), 0 8px 30px -10px rgba(37, 99, 235, 0.25);
  --scrim: rgba(15, 23, 42, 0.45);

  color-scheme: light;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica,
    Arial, sans-serif;
  background: var(--bg);
  color: var(--text);
  line-height: 1.5;
}

button {
  font: inherit;
  cursor: pointer;
}

a { color: var(--accent); }

/* One focus ring for every interactive element. :focus-visible keeps it off
   pointer clicks, so it only appears for keyboard and assistive navigation.
   The offset ring reads against both --panel and --bg backgrounds. */
/* No border-radius here: the outline already follows each element's own shape,
   and forcing 8px would square off the pill-shaped nav and round the tabs. */
:where(button, a, input, select, textarea, [tabindex]):focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* Skip past the sidebar straight to the view. Off-screen until
   focused, which is the first Tab stop on every page. */
.skip-link {
  position: absolute;
  left: 12px;
  top: -60px;
  z-index: 300;
  padding: 10px 16px;
  background: var(--accent);
  color: white;
  font-weight: 600;
  border-radius: 0 0 10px 10px;
  text-decoration: none;
  transition: top 0.15s ease;
}
/* :focus-visible, not :focus — it is a <button>, so a plain mouse click would
   otherwise slide it into view for a pointer user who cannot use it. */
.skip-link:focus-visible { top: 0; }

/* The skip target itself is a region, not a control — focusing it should move
   the reading position, not draw a ring around the whole page. */
.app:focus,
.app:focus-visible { outline: none; }

/* Animation is decoration here — nothing conveys state by motion alone, so it
   can be reduced to near-zero without losing meaning. Spinners keep turning
   (slowly) because a frozen spinner reads as a hung request. */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
  .spinner {
    animation-duration: 1.4s !important;
    animation-iteration-count: infinite !important;
  }
}

/* Shell: fixed-width left rail beside a scrolling content column. */
.shell { display: flex; min-height: 100vh; min-height: 100dvh; }

.sidebar {
  width: 244px;
  flex-shrink: 0;
  position: sticky;
  top: 0;
  height: 100vh;
  height: 100dvh;
  display: flex;
  flex-direction: column;
  gap: 26px;
  padding: 20px 16px;
  border-right: 1px solid var(--border);
  background: color-mix(in srgb, var(--panel) 70%, transparent);
  backdrop-filter: blur(12px);
  z-index: 10;
}

.brand {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 0 6px;
  background: none;
  border: none;
  color: var(--text);
  text-align: left;
}
.brand-mark {
  display: grid;
  place-items: center;
  width: 34px;
  height: 34px;
  flex-shrink: 0;
  background: linear-gradient(135deg, var(--accent), var(--ok));
  color: white;
  font-weight: 800;
  font-size: 16px;
  border-radius: 10px;
  box-shadow: var(--glow);
}
.brand-text {
  font-weight: 700;
  font-size: 15px;
  letter-spacing: -0.02em;
  line-height: 1.2;
}
/* Second line inside the wordmark: smaller, muted, uppercase. */
.brand-text span {
  display: block;
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--muted);
}

.sidenav { display: flex; flex-direction: column; gap: 2px; }
.sidenav-label {
  padding: 0 12px;
  margin-bottom: 8px;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--muted);
}
.sidenav-link {
  display: flex;
  align-items: center;
  gap: 11px;
  width: 100%;
  padding: 9px 12px;
  border: 1px solid transparent;
  border-radius: 10px;
  background: transparent;
  color: var(--muted);
  font-size: 14px;
  font-weight: 500;
  text-align: left;
  transition: color var(--dur) var(--ease), background var(--dur) var(--ease),
    border-color var(--dur) var(--ease);
}
.sidenav-link svg { flex-shrink: 0; }
.sidenav-link:hover { color: var(--text); background: var(--panel-2); }
.sidenav-link.active {
  color: var(--text);
  background: color-mix(in srgb, var(--accent) 14%, transparent);
  border-color: color-mix(in srgb, var(--accent) 32%, transparent);
}
.sidenav-link.active svg { color: var(--accent); }

/* Project group: separated from the workspace group by a rule rather than a
   gap, so the two read as one nav with two sections. */
#project-nav {
  margin-top: 18px;
  padding-top: 18px;
  border-top: 1px solid var(--border);
}
#project-nav[hidden] { display: none; }

/* The group label doubles as the project header: name, or icon + name. */
#project-nav-label {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 10px;
  color: var(--text);
  font-size: 11px;
  letter-spacing: 0.06em;
  /* The name is the project's own, so it keeps its casing. */
  text-transform: none;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
#project-nav-label.has-icon { padding-left: 2px; }
.sidenav-project-icon {
  width: 22px;
  height: 22px;
  flex-shrink: 0;
  border: 1px solid var(--border);
  border-radius: 6px;
  object-fit: cover;
}

/* A disabled rail item is an action that is not available yet (Download before
   anything is translated). Muted and non-interactive, but kept in place so the
   nav does not reflow when it becomes available. */
.sidenav-link:disabled {
  opacity: 0.45;
  cursor: default;
  color: var(--muted);
}
.sidenav-link:disabled:hover {
  background: transparent;
  border-color: transparent;
  color: var(--muted);
}

/* Pinned to the bottom of the rail. */
.sidebar-foot { margin-top: auto; display: flex; flex-direction: column; gap: 10px; }

/* Theme toggle: a two-button segmented control, one button per theme. Two
   explicit buttons rather than one flip-switch so the active theme is readable
   from aria-pressed instead of inferred from an icon. */
.theme-toggle {
  display: inline-flex;
  align-self: stretch;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  overflow: hidden;
  background: var(--panel);
}
.theme-toggle button {
  flex: 1;
  display: grid;
  place-items: center;
  padding: 7px 10px;
  background: transparent;
  border: none;
  color: var(--muted);
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease);
}
.theme-toggle button:hover { background: var(--panel-hover); color: var(--text); }
.theme-toggle button[aria-pressed="true"] {
  background: var(--panel-2);
  color: var(--text);
}
.theme-toggle svg { width: 15px; height: 15px; }

.health {
  padding: 12px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--panel-2);
}
.health-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  font-size: 12px;
}
.health-row + .health-row { margin-top: 8px; }
.health-label { display: flex; align-items: center; gap: 7px; color: var(--muted); }
.health-val { color: var(--text); font-variant-numeric: tabular-nums; }
.health-dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  flex-shrink: 0;
  background: var(--ok);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--ok) 20%, transparent);
}
.health-dot.warn {
  background: var(--warn);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--warn) 20%, transparent);
}
.health-dot.bad {
  background: var(--danger);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--danger) 20%, transparent);
}

/* Under 900px the rail becomes a horizontal bar above the content: same markup,
   no duplicate nav to keep in sync. */
@media (max-width: 900px) {
  .shell { flex-direction: column; }
  .sidebar {
    width: auto;
    height: auto;
    position: sticky;
    top: 0;
    flex-direction: row;
    align-items: center;
    gap: 14px;
    padding: 10px 14px;
    border-right: none;
    border-bottom: 1px solid var(--border);
  }
  .brand-text span { display: none; }
  .sidenav {
    flex-direction: row;
    gap: 4px;
    margin-left: auto;
    overflow-x: auto;
    scrollbar-width: none;
  }
  .sidenav::-webkit-scrollbar { display: none; }
  .sidenav-label { display: none; }
  .sidenav-link { white-space: nowrap; }
  /* The rail is a horizontal bar here. The health panel is too wide for it, but
     the theme toggle stays: it is the only control in the foot the user needs
     at this width. margin-top:auto is meaningless in a row, so it is reset. */
  .sidebar-foot { flex-direction: row; margin-top: 0; }
  .health { display: none; }
}
@media (max-width: 560px) {
  .sidenav-link span { display: none; }
  .sidenav-link { padding: 9px; }
}

/* Layout */
/* The content column owns the width cap and padding now that the rail sits
   beside it; the slots themselves just fill it. min-width:0 keeps wide children
   (tables, canvases) from forcing the flex row wider than the viewport. */
/* The content column fills the space beside the rail. The old 1400px cap and
   auto margins came from the topbar layout, where content had to be centred in
   the full viewport; with a fixed rail on the left, centring what remains just
   leaves dead space against the right edge. */
.app {
  flex: 1;
  min-width: 0;
  padding: 24px 32px 64px;
}
.app-slot[hidden] { display: none; }

@media (max-width: 900px) {
  .app { padding: 18px 16px 60px; }
}
.page-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  margin-bottom: 22px;
  flex-wrap: wrap;
}
.page-head h1 { margin: 0; font-size: 24px; }
.page-head p { margin: 4px 0 0; color: var(--muted); }
.head-actions { display: flex; align-items: center; gap: 10px; }

/* Buttons */
.btn {
  border: 1px solid var(--border);
  background: var(--panel-2);
  color: var(--text);
  padding: 9px 14px;
  border-radius: 10px;
  font-weight: 500;
  /* Bento Ops uses one easing curve for every transition so controls, cards,
     and panels all decelerate identically. */
  transition: transform var(--dur) var(--ease), background var(--dur) var(--ease),
    border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease);
}
.btn:hover { background: var(--panel-hover); border-color: var(--border-hover); }
/* Scale rather than translate: the button keeps its footprint, so a row of
   controls cannot shift when one is pressed. */
.btn:active { transform: scale(0.97); }
.btn.primary {
  background: linear-gradient(135deg, var(--accent-solid), var(--accent-solid-2));
  border-color: transparent;
  color: white;
  font-weight: 600;
  box-shadow: var(--glow);
}
/* Re-declares the gradient so the .btn:hover flat background cannot win. */
.btn.primary:hover {
  filter: brightness(1.12);
  background: linear-gradient(135deg, var(--accent-solid), var(--accent-solid-2));
  border-color: transparent;
}

/* Modal */
.modal-backdrop {
  position: fixed;
  inset: 0;
  z-index: 50;
  display: grid;
  place-items: center;
  padding: 20px;
  background: var(--scrim);
  backdrop-filter: blur(6px);
}
.modal {
  width: min(620px, 100%);
  max-height: min(720px, calc(100vh - 40px));
  overflow: auto;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 20px;
}
.modal h3 { margin: 0 0 8px; font-size: 18px; }
.modal p { margin: 0 0 14px; color: var(--muted); }
.modal ul {
  margin: 0 0 18px;
  padding-left: 20px;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.modal li { color: var(--text); }
.modal-actions {
  display: flex;
  justify-content: flex-end;
  gap: 10px;
  flex-wrap: wrap;
}
/* Prompt modal field */
.prompt-field {
  display: flex;
  flex-direction: column;
  gap: 6px;
  margin: 0 0 6px;
}
.prompt-label {
  font-size: 12px;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.4px;
}
.prompt-field .input { width: 100%; min-width: 0; }
.prompt-error {
  margin: 0 0 14px;
  color: var(--danger);
  font-size: 13px;
}
.prompt-error[hidden] { display: none; }

.btn.danger {
  background: var(--danger-bg);
  border-color: var(--danger-border);
  color: var(--danger);
}
.btn.ghost { background: transparent; }
.btn.small { padding: 6px 10px; font-size: 13px; border-radius: 8px; }
.btn:disabled { opacity: 0.5; cursor: default; }

/* Cards grid */
.grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
  gap: 16px;
}
.card {
  background: var(--panel);
  border: 1px solid var(--border);
  /* Cards and panels take the larger bento corner; controls keep --radius. */
  border-radius: var(--radius-lg);
  padding: 18px;
}
.project-card {
  display: flex;
  flex-direction: column;
  gap: 10px;
  cursor: pointer;
  transition: transform var(--dur) var(--ease), border-color var(--dur) var(--ease),
    box-shadow var(--dur) var(--ease);
}
.project-card:hover {
  border-color: color-mix(in srgb, var(--accent) 45%, transparent);
  transform: translateY(-2px);
  box-shadow: var(--shadow);
}
.project-card h3 { margin: 0; font-size: 18px; }
.project-card .meta { color: var(--muted); font-size: 13px; }
.project-card .stats { display: flex; gap: 14px; font-size: 13px; color: var(--muted); }
.project-card .stats b { color: var(--text); }

/* Delete is irreversible and the whole card is the open target, so it stays
   dimmed until the card is hovered or something inside it holds focus. It is
   never removed from the layout or the tab order — only de-emphasised. */
.project-card .card-actions {
  margin-top: 6px;
  opacity: 0;
  transition: opacity 0.15s ease;
}
.project-card:hover .card-actions,
.project-card:focus-within .card-actions { opacity: 1; }

/* Coarse pointers get no hover, so the reveal would strand the button. */
@media (hover: none) {
  .project-card .card-actions { opacity: 1; }
}

/* Empty state */
.empty {
  border: 1px dashed var(--border);
  border-radius: var(--radius-lg);
  padding: 48px 24px;
  text-align: center;
  color: var(--muted);
  background: color-mix(in srgb, var(--panel) 45%, transparent);
}
.empty h3 { color: var(--text); margin: 0 0 6px; }

/* Sections */
.section {
  /* Slightly translucent so the page background reads through the stack of
     panels, which is what gives the bento layout its sense of depth. */
  background: color-mix(in srgb, var(--panel) 88%, transparent);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  padding: 20px;
  margin-bottom: 22px;
}
.section-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 14px;
}
.section-head h2 { margin: 0; font-size: 17px; }
/* Secondary explanatory text, used inside headings, empty states and toolbars. */
.hint { color: var(--muted); font-size: 13px; }

/* Collapsible section heading: the whole row is the click target, matching the
   .collapse-toggle rows. Controls inside [data-no-toggle] stay clickable. */
.section-head.collapsible { cursor: pointer; }
.section-head.collapsible:hover h2 { color: var(--accent); }
.section-head.collapsible [data-no-toggle] { cursor: default; }
/* Actions hug the chevron, which keeps a fixed slot at the right edge so it
   doesn't shift column when the action buttons show or hide. */
.head-actions {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-left: auto;
  margin-right: 14px;
}

/* The disclosure marker, shared by every collapsible: sits at the far right. */
.chev {
  color: var(--muted);
  font-size: 12px;
  width: 12px;
  flex-shrink: 0;
}

/* Forms */
.row { display: flex; gap: 10px; flex-wrap: wrap; }
.input, textarea.input {
  flex: 1;
  min-width: 200px;
  background: var(--panel-2);
  border: 1px solid var(--border);
  color: var(--text);
  padding: 10px 12px;
  border-radius: 10px;
  outline: none;
}
/* Focus ring is a soft accent glow rather than a hard outline, matching the
   primary button's treatment. */
.input:focus { border-color: var(--accent); box-shadow: var(--glow); }
textarea.input { resize: vertical; font-family: inherit; }

/* Every <select> on every page, whether or not it carries .input. The native
   control can't be themed, so the arrow is dropped and redrawn as a background
   chevron; the right padding keeps the longest option clear of it. */
select {
  appearance: none;
  -webkit-appearance: none;
  background-color: var(--panel-2);
  background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' fill='none' stroke='%239aa0bd' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M1 1.5 6 6.5 11 1.5'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 12px center;
  border: 1px solid var(--border);
  border-radius: 10px;
  color: var(--text);
  font: inherit;
  padding: 10px 34px 10px 12px;
  outline: none;
  cursor: pointer;
}
select:hover:not(:disabled) { border-color: var(--border-hover); }
select:focus { border-color: var(--accent); box-shadow: var(--glow); }
select:disabled { opacity: 0.55; cursor: not-allowed; }

/* Sized variants keep their own padding, minus the room the chevron needs. */
select.input { padding: 10px 34px 10px 12px; }
select.input.small { padding: 6px 30px 6px 10px; background-position: right 10px center; }

/* Feature list */
.feature-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 8px; }
.feature-item {
  display: flex;
  align-items: center;
  gap: 10px;
  background: var(--panel-2);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 8px 10px;
}
.feature-item .drag { color: var(--muted); }
.feature-item input {
  flex: 1;
  background: transparent;
  border: none;
  color: var(--text);
  outline: none;
  font: inherit;
}

/* Competitor cards */
.tabs.competitor-store-tabs { margin-bottom: 18px; }
.competitors { display: flex; flex-direction: column; gap: 18px; }
.competitor {
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  overflow: hidden;
}
.competitor-head {
  display: flex;
  gap: 16px;
  padding: 18px;
  align-items: flex-start;
}
.competitor-icon {
  width: 72px;
  height: 72px;
  border-radius: 16px;
  border: 1px solid var(--border);
  object-fit: cover;
  flex-shrink: 0;
  background: var(--panel-2);
}
.competitor-icon.placeholder {
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--muted);
  font-size: 11px;
  text-align: center;
}
.competitor-title-block { flex: 1; min-width: 0; }
.competitor-title-block h3 { margin: 0 0 4px; font-size: 18px; }
.competitor-short { color: var(--muted); margin: 0 0 8px; }
.badges { display: flex; gap: 8px; flex-wrap: wrap; }
.badge {
  background: var(--panel-2);
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: 3px 10px;
  font-size: 12px;
  color: var(--muted);
}
.badge b { color: var(--text); }
.competitor-actions { display: flex; gap: 8px; flex-shrink: 0; }

/* Screenshots strip */
.shots {
  display: flex;
  gap: 10px;
  overflow-x: auto;
  padding: 0 18px 16px;
}
.collapse-body .shots { padding-top: 4px; }
.shots img {
  height: 220px;
  border-radius: 10px;
  border: 1px solid var(--border);
  cursor: pointer;
  transition: transform 0.1s ease;
}
.shots img:hover { transform: scale(1.02); }

/* Collapsible sections (screenshots, long description, generation inputs).
   The whole row is the click target and the chevron sits at the far right;
   .section-head.collapsible mirrors this for section-level headings. */
.collapse-wrap { border-top: 1px solid var(--border); }
.collapse-toggle {
  width: 100%;
  text-align: left;
  background: none;
  border: none;
  color: var(--text);
  padding: 14px 18px;
  font-weight: 600;
  display: flex;
  justify-content: space-between;
  align-items: center;
  cursor: pointer;
}
.collapse-toggle:hover { color: var(--accent); }
.longdesc-body {
  padding: 0 18px 18px;
  color: var(--muted);
  white-space: pre-wrap;
}
.longdesc-body a { word-break: break-all; }

.competitor-promo {
  margin: 10px 0;
  color: var(--muted);
  line-height: 1.5;
}

.locale-row {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  margin: 0 18px 14px;
}
.input.small {
  flex: 0 0 auto;
  min-width: 190px;
  padding: 6px 10px;
  font-size: 13px;
}

.warn {
  margin: 0 18px 14px;
  padding: 8px 12px;
  background: var(--warn-bg);
  border: 1px solid var(--warn-border);
  color: var(--warn-fg);
  border-radius: 8px;
  font-size: 13px;
}

.link-row { padding: 0 18px 16px; font-size: 13px; color: var(--muted); }
.link-row a { word-break: break-all; }

.hidden { display: none !important; }

/* Toasts */
.toasts {
  position: fixed;
  bottom: 20px;
  right: 20px;
  display: flex;
  flex-direction: column;
  gap: 10px;
  z-index: 100;
}
.toast {
  background: var(--panel-2);
  border: 1px solid var(--border);
  padding: 12px 16px;
  border-radius: 10px;
  box-shadow: var(--shadow);
  max-width: 340px;
  animation: slidein 0.2s ease;
}
.toast.error { border-color: var(--danger-border); color: var(--danger-fg); }
.toast.ok { border-color: var(--ok-border); color: var(--ok-fg); }
@keyframes slidein {
  from { transform: translateY(8px); opacity: 0; }
  to { transform: translateY(0); opacity: 1; }
}

/* Lightbox */
.lightbox {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.85);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 200;
  padding: 40px;
}
.lightbox img { max-width: 100%; max-height: 100%; border-radius: 10px; }
.lightbox-close {
  position: absolute;
  top: 18px;
  right: 24px;
  background: none;
  border: none;
  color: white;
  font-size: 40px;
  line-height: 1;
}

/* Spinner */
.spinner {
  width: 16px;
  height: 16px;
  border: 2px solid rgba(255, 255, 255, 0.35);
  border-top-color: white;
  border-radius: 50%;
  display: inline-block;
  animation: spin 0.7s linear infinite;
  vertical-align: -2px;
  margin-right: 6px;
}
@keyframes spin { to { transform: rotate(360deg); } }

.loading-block { text-align: center; padding: 60px; color: var(--muted); }

/* Tabs */
/* Seven project tabs overflow well before mobile width. They scroll sideways
   rather than wrapping, so the row stays one line and the active tab can be
   scrolled to; the mask hints that there is more past the right edge. */
.tabs {
  display: flex;
  gap: 4px;
  margin-bottom: 22px;
  border-bottom: 1px solid var(--border);
  overflow-x: auto;
  scrollbar-width: none;
}
.tabs::-webkit-scrollbar { display: none; }
.tab {
  background: none;
  border: none;
  border-bottom: 2px solid transparent;
  color: var(--muted);
  padding: 10px 16px;
  font-weight: 600;
  margin-bottom: -1px;
  white-space: nowrap;
  flex-shrink: 0;
  transition: color var(--dur) var(--ease), background var(--dur) var(--ease),
    border-color var(--dur) var(--ease);
}
/* The ring would be clipped by the scroll container at the default offset. */
.tab:focus-visible { outline-offset: -3px; }
/* Rounds only the top corners: the tab sits on the .tabs bottom rule, so a
   fully rounded fill would float off that line. */
.tab:hover {
  color: var(--text);
  background: color-mix(in srgb, var(--panel-2) 70%, transparent);
  border-radius: 8px 8px 0 0;
}
.tab.active {
  color: var(--text);
  border-bottom-color: var(--accent);
  background: color-mix(in srgb, var(--accent) 12%, transparent);
  border-radius: 8px 8px 0 0;
}

/* Metadata sub-tabs (Content / Keywords) — tighter than the top-level tabs. */
.subtabs { margin-top: 4px; }

/* Metadata panels */
.meta-panel .versions { display: flex; flex-direction: column; gap: 8px; }
.meta-title-tools {
  display: flex;
  gap: 10px;
  margin: 0 0 14px;
  align-items: center;
}
.meta-title-tools .input { flex: 1; }
.meta-title-tools.stacked { align-items: flex-end; }
.meta-title-tools.stacked textarea.input { resize: vertical; }

/* One compact row: char count, the copy itself, then the actions. */
.version-card {
  display: flex;
  align-items: center;
  gap: 10px;
  background: var(--panel-2);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 6px 10px;
}
.version-card.selected {
  border-color: var(--ok);
  background: rgba(45, 200, 140, 0.08);
  box-shadow: 0 0 0 1px var(--ok) inset;
}
.version-actions { display: flex; gap: 6px; flex-shrink: 0; }
.section-head-actions { display: flex; gap: 8px; align-items: center; }
.version-check {
  flex-shrink: 0;
  width: 16px;
  height: 16px;
  accent-color: var(--danger);
  cursor: pointer;
}
/* Release Notes keeps the taller stacked card. */
.version-card:has(.version-head) { display: block; padding: 14px; }
.version-head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 12px;
  margin-bottom: 10px;
  flex-wrap: wrap;
}
.version-meta { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.version-date { font-size: 12px; color: var(--muted); }
.selected-badge { background: var(--ok-bg); border-color: var(--ok-border); color: var(--ok-fg); }
.version-card:has(.version-head) .meta-text {
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 12px;
  max-height: none;
}
.version-count {
  font-size: 12px;
  font-variant-numeric: tabular-nums;
  flex-shrink: 0;
  min-width: 56px;
}

.count-ok { color: var(--ok); font-weight: 600; }
.count-over { color: var(--danger); font-weight: 600; }

.meta-text {
  flex: 1;
  min-width: 0;
  white-space: pre-wrap;
  color: var(--text);
  line-height: 1.45;
  max-height: 4.4em;
  overflow: hidden;
}
/* Long-form rows: single clamped line that opens the full-text modal. */
.meta-text-clamp {
  display: block;
  width: 100%;
  max-height: none;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  text-align: left;
  font: inherit;
  background: none;
  border: 0;
  padding: 0;
  cursor: pointer;
}
.meta-text-clamp:hover { color: var(--accent); }

.text-modal { width: min(820px, 100%); }
.text-modal-body {
  white-space: pre-wrap;
  line-height: 1.6;
  color: var(--text);
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 14px;
  margin: 0 0 16px;
  max-height: min(60vh, 520px);
  overflow-y: auto;
}

/* Release Notes — hand-written copy composer above the version list */
.release-compose { display: flex; flex-direction: column; gap: 8px; margin-bottom: 16px; }
.release-textarea {
  width: 100%;
  resize: vertical;
  min-height: 120px;
  font: inherit;
  line-height: 1.55;
}
.release-compose-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}

/* Keyword table (merged, scored, per-row select/delete) */
.kw-table { display: flex; flex-direction: column; gap: 6px; }
.kw-row {
  display: grid;
  grid-template-columns: 1fr 130px auto;
  gap: 10px;
  align-items: center;
  padding: 8px 12px;
  /* --panel-2, matching the rows on the home page: list items sit on the
     raised surface, not the page background. */
  background: var(--panel-2);
  border: 1px solid var(--border);
  border-radius: 10px;
  transition: border-color var(--dur) var(--ease), background var(--dur) var(--ease);
}
.kw-row:hover { border-color: var(--border-hover); background: var(--panel-hover); }
.kw-row.selected {
  border-color: color-mix(in srgb, var(--ok) 45%, transparent);
  background: color-mix(in srgb, var(--ok) 10%, var(--panel-2));
}
.kw-row.kw-blocked .kw-word { opacity: 0.55; }

/* Add-your-own-keyword form */
.kw-add { display: flex; gap: 8px; margin: 0 0 12px; }
.kw-add .input { flex: 1; }
.kw-add select.input { flex: 0 0 150px; }

/* "custom" tag on user-added keywords */
.kw-manual {
  margin-left: 8px;
  padding: 1px 6px;
  border-radius: 999px;
  border: 1px solid var(--border);
  color: var(--muted);
  font-size: 11px;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.4px;
}

/* Live budget for the 100-char App Store keywords field */
.kw-budget { display: block; margin-top: 4px; }
.kw-budget.full { color: var(--ok); }
.kw-budget.over { color: var(--danger); }
.kw-header {
  background: transparent;
  border: none;
  padding: 4px 12px;
  font-size: 12px;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.4px;
}
.kw-word { font-weight: 600; color: var(--text); word-break: break-word; }
.kw-cat { display: flex; }
.kw-actions { display: flex; gap: 6px; justify-content: flex-end; }

/* Category badge (one word: core, opportunity, traffic, …) */
.cat-badge {
  display: inline-block;
  padding: 3px 10px;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 600;
  text-transform: capitalize;
  border: 1px solid var(--border);
  cursor: help;
}
.cat-low { background: var(--danger-bg); color: var(--danger-fg); border-color: var(--danger-border); }
.cat-mid { background: var(--warn-bg); color: var(--warn-fg); border-color: var(--warn-border); }
.cat-high { background: var(--ok-bg); color: var(--ok-fg); border-color: var(--ok-border); }

@media (max-width: 720px) {
  .kw-row {
    grid-template-columns: 1fr auto;
    gap: 8px;
  }
  .kw-header { display: none; }
  .kw-actions { grid-column: 1 / -1; justify-content: flex-start; }
}

/* App Images page */
.img-panel { margin-bottom: 18px; }
.img-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  gap: 16px;
  padding: 4px 18px 18px;
}
.img-card {
  border: 1px solid var(--border);
  border-radius: 12px;
  overflow: hidden;
  background: var(--panel-2);
}
.img-card.selected { border-color: var(--ok-border); box-shadow: 0 0 0 2px var(--ok-border); }
.img-thumb {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 12px;
  background: repeating-conic-gradient(var(--panel-2) 0% 25%, var(--panel) 0% 50%) 50% / 20px 20px;
}
.img-thumb img {
  max-width: 100%;
  max-height: 200px;
  cursor: pointer;
  border-radius: 6px;
}
.img-card.img-icon .img-thumb img { max-height: 128px; border-radius: 22%; }
.img-card-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 8px 12px;
  border-top: 1px solid var(--border);
  flex-wrap: wrap;
}
.img-dims { font-size: 12px; color: var(--muted); }
.img-dims b { color: var(--ok-fg); }
.img-card-actions { display: flex; gap: 6px; }

/* ---------- Dashboard (store listing preview) ---------- */
/* The platform tabs already carry the gap below them, so the toolbar aligns the
   locale picker to their baseline rather than adding a margin of its own. */
.dash-toolbar {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
}
.dash-toolbar .row { align-items: center; gap: 8px; }

.dash-store {
  width: 100%;
  display: flex;
  flex-direction: column;
  gap: 18px;
}

/* Empty / missing-data placeholder */
.dash-empty {
  padding: 16px;
  border: 1px dashed var(--border);
  border-radius: var(--radius);
  background: color-mix(in srgb, var(--panel) 45%, transparent);
  color: var(--muted);
  font-size: 14px;
  text-align: center;
  background: var(--panel-2);
}

/* Feature graphic (Android, 1024x500) */
.dash-feature {
  width: min(100%, 560px);
}
.dash-feature img {
  width: 100%;
  aspect-ratio: 1024 / 500;
  object-fit: cover;
  display: block;
  border-radius: var(--radius);
  border: 1px solid var(--border);
}

/* Icon + title header */
.dash-head {
  display: flex;
  align-items: center;
  gap: 16px;
}
.dash-icon {
  width: 72px;
  height: 72px;
  border-radius: 18px;
  object-fit: cover;
  border: 1px solid var(--border);
  flex-shrink: 0;
}
.dash-zoomable {
  cursor: zoom-in;
}
.dash-icon.placeholder {
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 11px;
  color: var(--muted);
  background: var(--panel-2);
}
.dash-head-text { flex: 1; min-width: 0; }
.dash-title { margin: 0; font-size: 22px; }
.dash-subtitle { margin: 2px 0 0; font-size: 14px; color: var(--muted, #888); }
.dash-ios .dash-icon { border-radius: 22%; }

/* Screenshots horizontal scrollview */
.dash-shots {
  display: flex;
  gap: 12px;
  overflow-x: auto;
  padding-bottom: 8px;
  scroll-snap-type: x mandatory;
}
.dash-shots img {
  height: 340px;
  border-radius: var(--radius);
  border: 1px solid var(--border);
  cursor: zoom-in;
  scroll-snap-align: start;
  flex-shrink: 0;
}

/* Short / promo description */
.dash-shortdesc {
  font-size: 15px;
  color: var(--text);
}

/* Collapsible long description */
.dash-longdesc-toggle {
  background: var(--panel-2);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 10px 14px;
  width: 100%;
  text-align: left;
  display: flex;
  justify-content: space-between;
  align-items: center;
}
.dash-longdesc-body {
  margin-top: 10px;
  padding: 14px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  white-space: pre-wrap;
  font-size: 14px;
  color: var(--muted);
}

.dash-section-label {
  font-weight: 600;
  font-size: 14px;
  color: var(--muted);
}
.dash-keywords { display: flex; flex-wrap: wrap; gap: 6px; }

/* ---------- Localization ---------- */

.loc-rows { display: flex; flex-direction: column; gap: 10px; }

.loc-row {
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--panel-2);
  overflow: hidden;
}
.loc-row.expanded { border-color: var(--accent-2); }

.loc-row-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 10px 14px;
}
.loc-row-actions { display: flex; align-items: center; gap: 8px; }

/* The whole left side of the row toggles it, so it has to look like a button
   without inheriting one's chrome. */
.loc-toggle {
  display: flex;
  align-items: baseline;
  gap: 10px;
  flex: 1;
  min-width: 0;
  padding: 0;
  background: none;
  border: 0;
  color: var(--text);
  font: inherit;
  text-align: left;
  cursor: pointer;
}
.loc-toggle:hover .loc-name { color: var(--accent); }
.loc-caret { color: var(--muted); width: 12px; }
.loc-name { font-weight: 600; }
.loc-codes { color: var(--muted); font-size: 12px; }
.loc-codes code {
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 5px;
  padding: 1px 5px;
}

.loc-badge {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 3px 10px;
  border-radius: 999px;
  font-size: 12px;
  white-space: nowrap;
}
.loc-badge.ok { background: rgba(70, 209, 158, 0.12); color: var(--ok); }
.loc-badge.stale { background: var(--warn-bg); color: var(--warn-fg); }
.loc-badge.busy { background: var(--panel); color: var(--muted); }

.loc-errors { margin: 0 14px 12px; }

.loc-fields {
  display: flex;
  flex-direction: column;
  gap: 1px;
  background: var(--border);
  border-top: 1px solid var(--border);
}
.loc-field { background: var(--panel); padding: 14px; }
/* A stale field's source moved after it was translated: mark the field itself,
   not just the row, so an expanded locale shows which ones need attention. */
.loc-field.stale { border-left: 3px solid var(--warn-fg); padding-left: 11px; }

.loc-field-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 10px;
}
.loc-field-head h4 { margin: 0 0 2px; font-size: 14px; }

/* Source and translation sit side by side so a claim added or dropped in
   translation is visible without scrolling between them. */
.loc-field-body {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 14px;
}
@media (max-width: 900px) {
  .loc-field-body { grid-template-columns: 1fr; }
}
.loc-col { min-width: 0; display: flex; flex-direction: column; gap: 6px; }
.loc-col-label {
  color: var(--muted);
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

/* Both columns of a field share one fixed height and scroll inside it, so a
   4000-character source can't stretch the row past its translation — the two
   stay aligned and comparable. `--loc-box` is the height of that shared track;
   a long description gets a taller one. */
.loc-field-body { --loc-box: 84px; }
.loc-field-body.long { --loc-box: 300px; }

.loc-text,
.loc-col textarea {
  height: var(--loc-box);
  padding: 10px;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 8px;
  font: inherit;
  font-size: 13px;
  overflow-y: auto;
}
.loc-text {
  margin: 0;
  color: var(--muted);
  white-space: pre-wrap;
  word-break: break-word;
}
.loc-col textarea {
  width: 100%;
  color: var(--text);
  resize: vertical;
}
.loc-col textarea:focus { outline: none; border-color: var(--accent); box-shadow: var(--glow); }

.loc-field-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}
.loc-count { color: var(--muted); font-size: 12px; }
/* Over the store's hard limit: the field cannot be saved in this state. */
.loc-count.over { color: var(--danger); font-weight: 600; }

.loc-chips { display: flex; flex-wrap: wrap; gap: 6px; }
/* These are keyword tokens, not the status pills the home page uses. They share
   the .chip class, so the properties that pill sets — muted color, 600 weight —
   are reset here rather than left to leak in by inheritance. */
.loc-chips .chip {
  padding: 3px 9px;
  background: var(--panel-2);
  border: 1px solid var(--border);
  border-radius: 999px;
  font-size: 12px;
  font-weight: 400;
  color: var(--text);
}
/* Past the 100-character App Store keywords field; kept visible because the
   list is still the model's ranking, and the user may want to reorder it. */
.loc-chips .chip.dropped {
  color: var(--muted);
  border-style: dashed;
  text-decoration: line-through;
}

/* A bulk translation runs on the server for minutes; the bar and the per-row
   badges are the only sign of what it is doing. */
.loc-progress {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-bottom: 14px;
}
.loc-progress-bar {
  flex: 1;
  height: 6px;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 999px;
  overflow: hidden;
}
.loc-progress-bar span {
  display: block;
  height: 100%;
  background: var(--accent);
  transition: width 0.3s ease;
}
.loc-progress .hint { white-space: nowrap; }

.loc-badge.queued { background: var(--panel); color: var(--muted); }

/* The language a bulk run is on, and the ones still waiting for it. */
.loc-row.working { border-color: var(--accent-2); }
.loc-row.working .loc-toggle[disabled] { cursor: default; opacity: 0.7; }

/* ---------- Projects home (bento) ---------- */
/* 12-column bento. The hero spans the full width; projects and activity split
   8/4 beneath it and stack under 1100px. */
.bento {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  gap: 16px;
}
.tile {
  padding: 20px;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: color-mix(in srgb, var(--panel) 88%, transparent);
}
.tile.hero { grid-column: span 12; }
.tile.projects-tile { grid-column: span 12; }

.tile-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 16px;
}
.tile-title {
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted);
}

.hero-h { margin: 0 0 6px; font-size: 24px; font-weight: 700; letter-spacing: -0.03em; }
.hero-sub { margin: 0; color: var(--muted); max-width: 60ch; }

.metrics {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 14px;
  margin-top: 22px;
}
.metric {
  position: relative;
  overflow: hidden;
  padding: 14px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--panel-2);
}
/* Accent underline: a hairline rather than a fill, so four of them in a row
   read as one set instead of four competing blocks. */
.metric::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 2px;
  opacity: 0.55;
  background: linear-gradient(90deg, var(--accent), transparent);
}
.metric.accent::after { background: linear-gradient(90deg, var(--ok), transparent); }
.metric.warn::after { background: linear-gradient(90deg, var(--warn), transparent); }
.metric-label {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--muted);
}
.metric-val {
  margin-top: 6px;
  font-size: 28px;
  font-weight: 600;
  letter-spacing: -0.03em;
  font-variant-numeric: tabular-nums;
}

/* Project rows */
.proj-list { display: flex; flex-direction: column; gap: 12px; }
.proj-row {
  display: grid;
  grid-template-columns: 42px 1fr auto;
  gap: 16px;
  align-items: center;
  padding: 12px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--panel-2);
  cursor: pointer;
  transition: transform var(--dur) var(--ease), border-color var(--dur) var(--ease),
    box-shadow var(--dur) var(--ease);
}
.proj-row:hover {
  transform: translateY(-2px);
  border-color: color-mix(in srgb, var(--accent) 45%, transparent);
  box-shadow: var(--shadow);
}
/* Hue comes from the project id (see projectHue in app.js), so a project keeps
   the same tile color across reloads without storing one. */
.proj-mark {
  display: grid;
  place-items: center;
  width: 42px;
  height: 42px;
  border-radius: 11px;
  font-size: 15px;
  font-weight: 700;
  color: white;
  background: linear-gradient(135deg, hsl(var(--h) 65% 52%), hsl(calc(var(--h) + 34) 60% 44%));
}
.proj-mark-img {
  object-fit: cover;
  border: 1px solid var(--border);
  /* The gradient fallback paints its own background; a real icon must not. */
  background: var(--panel);
}
.proj-body { min-width: 0; }
.proj-name {
  font-size: 14.5px;
  font-weight: 600;
  letter-spacing: -0.01em;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.proj-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  margin-top: 3px;
  font-size: 12px;
  color: var(--muted);
}
.proj-right { display: flex; align-items: center; gap: 14px; }

/* Delete stays dimmed until the row is hovered or holds focus — same rule the
   old card grid used, kept because delete is irreversible. */
.proj-delete { opacity: 0; transition: opacity var(--dur) var(--ease); }
.proj-row:hover .proj-delete,
.proj-row:focus-within .proj-delete { opacity: 1; }
@media (hover: none) {
  .proj-delete { opacity: 1; }
}

.bar { width: 92px; }
.bar-track { height: 5px; border-radius: 3px; background: var(--border); overflow: hidden; }
.bar-fill { height: 100%; border-radius: 3px; background: linear-gradient(90deg, var(--accent), var(--ok)); }
.bar-label {
  margin-top: 5px;
  font-size: 10.5px;
  color: var(--muted);
  text-align: right;
  font-variant-numeric: tabular-nums;
}

.chip {
  padding: 3px 9px;
  border: 1px solid var(--border);
  border-radius: 20px;
  font-size: 11px;
  font-weight: 600;
  color: var(--muted);
  white-space: nowrap;
}
.chip.live {
  color: var(--accent);
  border-color: color-mix(in srgb, var(--accent) 40%, transparent);
  background: color-mix(in srgb, var(--accent) 12%, transparent);
}
.chip.ok {
  color: var(--ok-fg);
  border-color: color-mix(in srgb, var(--ok) 40%, transparent);
  background: color-mix(in srgb, var(--ok) 12%, transparent);
}
.chip.stale {
  color: var(--warn-fg);
  border-color: color-mix(in srgb, var(--warn) 40%, transparent);
  background: color-mix(in srgb, var(--warn) 12%, transparent);
}

@media (max-width: 1100px) {
  .metrics { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 620px) {
  .metrics { grid-template-columns: 1fr; }
  .proj-row { grid-template-columns: 38px 1fr; }
  .proj-right { grid-column: 1 / -1; justify-content: space-between; }
}
