/* ==========================================================================
   LogPose — issues.

   Same stream as the logs page, one weight heavier. A log line is one of ten
   thousand and earns 7px of padding; an issue is one of perhaps ten this week,
   was written by a person, and carries a decision — so the row is taller, the
   message is the first thing the eye lands on, and the automatic context sits
   under it in a quieter second line instead of in columns of its own.

   Two colour families are added here and nowhere else:
     · kind     — what the person said it was (bug / idea / stuck)
     · status + priority — what *we* decided about it
   Both resolve through [data-tone], the same mechanism severity already uses,
   so no component needs to know the difference.
   ========================================================================== */

:root {
  /* Kind: the reporter's own framing. Deliberately quieter than severity — a
     user calling something broken is a claim, not a measurement. */
  --k-bug:   oklch(54% 0.150 25);
  --k-idea:  oklch(52% 0.120 275);
  --k-help:  oklch(52% 0.110 230);
  --k-other: oklch(52% 0.020 265);

  /* Status: the lifecycle. New is the accent because it is the only state that
     asks something of you; done and rejected are grey because a closed issue
     should stop competing for attention the moment it closes. */
  --st-new:         oklch(52% 0.098 195);
  --st-todo:        oklch(56% 0.075 265);
  --st-in_progress: oklch(58% 0.140 72);
  --st-testing:     oklch(52% 0.130 305);
  --st-ready:       oklch(50% 0.120 160);
  --st-done:        oklch(55% 0.020 265);
  --st-rejected:    oklch(60% 0.018 265);

  /* Priority: one ladder, one hue family, four stops. */
  --pr-urgent: oklch(52% 0.200 22);
  --pr-high:   oklch(57% 0.150 45);
  --pr-medium: oklch(58% 0.100 90);
  --pr-low:    oklch(58% 0.045 230);
  --pr-none:   oklch(62% 0.018 265);
}

:root[data-theme="dark"] {
  --k-bug:   oklch(72% 0.150 25);
  --k-idea:  oklch(74% 0.110 275);
  --k-help:  oklch(74% 0.100 230);
  --k-other: oklch(70% 0.020 265);

  --st-new:         oklch(76% 0.105 195);
  --st-todo:        oklch(72% 0.060 265);
  --st-in_progress: oklch(81% 0.135 82);
  --st-testing:     oklch(74% 0.120 305);
  --st-ready:       oklch(72% 0.120 160);
  --st-done:        oklch(62% 0.020 265);
  --st-rejected:    oklch(56% 0.018 265);

  --pr-urgent: oklch(70% 0.180 22);
  --pr-high:   oklch(75% 0.135 45);
  --pr-medium: oklch(78% 0.100 90);
  --pr-low:    oklch(72% 0.045 230);
  --pr-none:   oklch(56% 0.018 265);
}

[data-tone="k-bug"]   { --tone: var(--k-bug); }
[data-tone="k-idea"]  { --tone: var(--k-idea); }
[data-tone="k-help"]  { --tone: var(--k-help); }
[data-tone="k-other"] { --tone: var(--k-other); }

[data-tone="new"]         { --tone: var(--st-new); }
[data-tone="todo"]        { --tone: var(--st-todo); }
[data-tone="in_progress"] { --tone: var(--st-in_progress); }
[data-tone="testing"]     { --tone: var(--st-testing); }
[data-tone="ready"]       { --tone: var(--st-ready); }
[data-tone="done"]        { --tone: var(--st-done); }
[data-tone="rejected"]    { --tone: var(--st-rejected); }
/* The status-group filter options borrow the same tones. */
[data-tone="st-new"]      { --tone: var(--st-new); }
[data-tone="st-todo"]     { --tone: var(--st-todo); }
[data-tone="st-progress"] { --tone: var(--st-in_progress); }
[data-tone="st-done"]     { --tone: var(--st-done); }

[data-tone="pr-urgent"] { --tone: var(--pr-urgent); }
[data-tone="pr-high"]   { --tone: var(--pr-high); }
[data-tone="pr-medium"] { --tone: var(--pr-medium); }
[data-tone="pr-low"]    { --tone: var(--pr-low); }
[data-tone="pr-none"]   { --tone: var(--pr-none); }

/* ------------------------------------------------------------- row layout */
.row-grid--issues {
  grid-template-columns:
    var(--col-time, 96px)
    var(--col-kind, 128px)
    var(--col-service, 150px)
    minmax(0, 1fr)
    var(--col-priority, 118px)
    var(--col-status, 128px);
  align-items: start;
}
.stream-head .row-grid--issues { align-items: center; }

.issue-row { padding: 12px 10px; align-items: center; }
.issue-row .cell-time,
.issue-row .cell-kind,
.issue-row .cell-service,
.issue-row .cell-priority,
.issue-row .cell-status { align-self: center; }
.cell-priority, .cell-status { justify-self: start; }

/* The message is the row: full weight, two lines, everything else in orbit. */
.cell-issue { min-width: 0; display: flex; flex-direction: column; gap: 5px; }
.issue-msg {
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2;
  overflow: hidden;
  font-size: var(--fs-md); color: var(--fg-strong);
  line-height: 1.45; overflow-wrap: anywhere;
}
.issue-meta {
  display: flex; flex-wrap: wrap; align-items: center; gap: 4px 12px;
  font-size: var(--fs-2xs); color: var(--fg-faint);
}
.meta-bit { display: inline-flex; align-items: center; gap: 5px; min-width: 0; max-width: 34ch; }
.meta-bit > span, .meta-bit { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.meta-bit .lucide { width: 12px; height: 12px; flex: none; opacity: 0.8; }
.meta-bit.tone-bad { color: var(--bad); }

/* An urgent issue earns a wash, the same way an error line does on the logs
   page — and loses it the moment it closes, whatever its priority was. */
.issue-row[data-priority="urgent"]:not([data-status="done"]):not([data-status="rejected"]) {
  background: color-mix(in oklab, var(--pr-urgent) 5%, transparent);
}
.issue-row[data-priority="urgent"]:not([data-status="done"]):not([data-status="rejected"]):hover {
  background: color-mix(in oklab, var(--pr-urgent) 10%, transparent);
}

/* Closed work recedes rather than disappearing: still readable, still
   searchable, visibly finished. Hover restores it in full, because the one
   time you look at a closed issue you are looking at it properly. */
.issue-row[data-status="done"],
.issue-row[data-status="rejected"] { opacity: 0.5; }
.issue-row[data-status="done"]:hover,
.issue-row[data-status="rejected"]:hover { opacity: 1; }
.issue-row[data-status="done"] .issue-msg { text-decoration: line-through; text-decoration-thickness: 1px; }

.tag-kind { text-transform: none; letter-spacing: 0; font-weight: 600; }
.tag-untriaged { opacity: 0.75; }

@media (max-width: 1240px) {
  :root { --col-kind: 42px; --col-priority: 40px; --col-service: 120px; }
  /* Below this width the badges keep their icon and drop their word: the icon
     already carries the tone, and the label is repeated in the drawer. */
  .row-grid--issues .tag span { display: none; }
  .row-grid--issues .tag { padding: 0 7px; }
  .row-grid--issues .tag.has-icon { gap: 0; }
}

@media (max-width: 860px) {
  .row-grid--issues {
    grid-template-columns: auto auto minmax(0, 1fr) auto auto;
  }
  .issue-row .cell-service { display: none; }
  .issue-row .cell-issue { grid-column: 1 / -1; margin-top: 7px; }
}

/* =========================================================== issue drawer */
.drawer-id { font-size: var(--fs-2xs); max-width: 16ch; overflow: hidden; text-overflow: ellipsis; }
@media (max-width: 860px) { .drawer-id { display: none; } }

/* Triage sits in its own well at the top of the panel so the writable region is
   unmistakably separate from the evidence below it. */
.triage {
  padding: 13px 14px 14px;
  margin-bottom: 18px;
  background: var(--bg-sunken);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
}
.triage-row { display: flex; flex-wrap: wrap; align-items: flex-end; gap: 10px; }
.triage-field { display: flex; flex-direction: column; gap: 6px; flex: 1 1 150px; min-width: 0; }
.triage-field .select-wrap, .triage-field .select { width: 100%; }
.triage-notes { margin-top: 12px; }
.triage-notes .block-head { margin-bottom: 6px; }
.triage-hint { font-size: var(--fs-2xs); }

.textarea {
  width: 100%; height: auto; min-height: 56px; padding: 9px 11px;
  resize: vertical; line-height: 1.5;
  font-family: inherit;
}

/* Save state: a word that appears and fades, never a toast. The drawer is the
   thing you are looking at; feedback belongs in it. */
.triage-state {
  flex: none; align-self: center;
  font-size: var(--fs-2xs); font-weight: 600;
  letter-spacing: 0.04em; text-transform: uppercase;
  color: var(--ok);
  opacity: 0; transform: translateY(2px);
  transition: opacity var(--t-base) var(--ease-out), transform var(--t-base) var(--ease-out);
}
.triage-state.is-on { opacity: 1; transform: translateY(0); }
.triage-state.is-bad { color: var(--bad); }

.section-head--drawer { margin: 22px 0 8px; }
.section-head--drawer h2 { font-size: var(--fs-sm); }

/* ------------------------------------------------------------ attachments */
.attachments { display: flex; flex-direction: column; gap: 8px; }
.attachment {
  display: flex; align-items: center; gap: 10px;
  padding: 9px 11px;
  background: var(--bg-sunken); border: 1px solid var(--line);
  border-radius: var(--r-lg);
  font-size: var(--fs-xs); color: var(--fg-muted);
  min-width: 0;
}
.attachment .lucide { width: 15px; height: 15px; color: var(--fg-faint); flex: none; }
.attachment-main { display: flex; flex-direction: column; flex: 1; min-width: 0; gap: 1px; }
.attachment-key {
  font-family: var(--font-mono); font-size: var(--fs-2xs);
  color: var(--fg); overflow-wrap: anywhere;
}
/* The full bucket/key, one size down and muted: the filename is what you
   read, the path is what you'd copy or hand to someone with AWS access. */
.attachment-path {
  font-family: var(--font-mono); font-size: var(--fs-2xs);
  color: var(--fg-faint); overflow-wrap: anywhere;
}
.attachment-size { flex: none; font-variant-numeric: tabular-nums; }

/* An attachment LogPose can actually render is rendered: a screenshot is the
   single most useful thing in an issue and asking someone to go and fetch it
   from a bucket is how it goes unlooked-at. When the project only sends a key
   (a private bucket, which is the normal case), the key is shown with a copy
   button instead — honest about what it is rather than a broken image. */
.attachment-shot {
  display: block; width: 100%; margin-top: 4px;
  border: 1px solid var(--line); border-radius: var(--r-lg);
  background: var(--bg-sunken);
}

/* --------------------------------------------------------- dashboard tiles */
/* The issue counters live in the same stat strip as the log counters, so the
   landing page answers "is anything on fire" in one row. */
.stat.tone-attention .stat-value { color: var(--st-new); }
.stat.tone-attention .stat-label .lucide { color: var(--st-new); }
.stat.tone-urgent .stat-value { color: var(--pr-urgent); }
.stat.tone-urgent .stat-label .lucide { color: var(--pr-urgent); }

/* Status breakdown: a single row of labelled counts, not a chart. Seven numbers
   do not need axes. */
.status-strip {
  display: flex; flex-wrap: wrap; gap: 8px;
  margin-bottom: 8px;
}
.status-pill {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 7px 13px 7px 11px;
  border: 1px solid var(--line); border-radius: var(--r-pill);
  background: var(--bg-surface);
  color: var(--fg-muted);
  font-size: var(--fs-xs); font-weight: 550;
  transition: background-color var(--t-fast) var(--ease-out),
              border-color var(--t-fast) var(--ease-out),
              color var(--t-fast) var(--ease-out);
}
a.status-pill:hover {
  text-decoration: none;
  color: var(--tone, var(--fg-strong));
  border-color: color-mix(in oklab, var(--tone, var(--accent)) 45%, var(--line));
  background: color-mix(in oklab, var(--tone, var(--accent)) 8%, var(--bg-surface));
}
.status-pill .lucide { width: 14px; height: 14px; color: var(--tone, var(--fg-faint)); }
.status-pill .count {
  font-variant-numeric: tabular-nums; font-weight: 650;
  color: var(--fg-strong);
}
.status-pill.is-zero { opacity: 0.5; }
