/* board.css — the feedback board.

   Built entirely on studio.css's custom properties, so light and dark
   are one set of rules rather than two: nothing here names a colour,
   and the four status chips get their tint from the --good/--warn/--busy
   families that the rest of the studio already uses for the same three
   meanings. See the design-token note in studio.css.

   Every class is prefixed bd-. Class names are global in this document —
   there is no bundler and no scoping — and `.card`, `.tabs` and `.vote`
   are all names another page could reasonably want. */

/* ------------------------------------------------------------ the tabs */

.bd-tabs {
  display: flex;
  gap: 4px;
  margin-bottom: 14px;
  border-bottom: 1px solid var(--border);
  padding-bottom: 0;
}

.bd-tabs .bd-tab {
  appearance: none;
  background: none;
  border: 0;
  border-bottom: 2px solid transparent;
  color: var(--text-secondary);
  cursor: pointer;
  font: inherit;
  font-weight: 600;
  padding: 10px 14px;
  margin-bottom: -1px;
}

.bd-tabs .bd-tab:hover { color: var(--text); }

.bd-tabs .bd-tab.on {
  color: var(--accent-ink);
  border-bottom-color: var(--accent);
}

/* --------------------------------------------------------- the filters */

.bd-filters {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
  margin: 0 0 14px;
}

.bd-filter {
  appearance: none;
  background: var(--chip-bg);
  border: 1px solid transparent;
  border-radius: 999px;
  color: var(--text-secondary);
  cursor: pointer;
  font: inherit;
  font-size: 13px;
  padding: 5px 12px;
}

.bd-filter:hover { color: var(--text); }

.bd-filter.on {
  background: var(--accent-soft);
  border-color: var(--accent-line);
  color: var(--accent-ink);
  font-weight: 600;
}

.bd-sep {
  width: 1px;
  height: 18px;
  background: var(--border-2);
  margin: 0 4px;
}

/* ------------------------------------------------- search, sort, paging */

.bd-searchrow {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 0 0 12px;
  flex-wrap: wrap;
}

.bd-search {
  display: flex;
  align-items: center;
  gap: 8px;
  flex: 1 1 240px;
  min-width: 0;
  background: var(--surface-2);
  border: 1px solid var(--border-2);
  border-radius: var(--r-md);
  padding: 0 12px;
  color: var(--text-secondary);
}

.bd-search:focus-within {
  border-color: var(--accent);
  outline: 2px solid var(--ring);
  outline-offset: -1px;
}

.bd-search svg { width: 16px; height: 16px; flex: none; }

.bd-search input {
  appearance: none;
  background: none;
  border: 0;
  color: var(--text);
  font: inherit;
  padding: 10px 0;
  width: 100%;
  min-width: 0;
}

.bd-search input:focus { outline: none; }

/* The native clear affordance is a grey X that does not follow the theme
   and sits at a different size in every browser. The Escape key clears
   the field — see onSearchKey — and that is the behaviour a search input
   is expected to have anyway. */
.bd-search input::-webkit-search-cancel-button { display: none; }

.bd-sorts { display: flex; gap: 6px; flex: none; }

.bd-more {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  margin-top: 14px;
}

.bd-loadmore { min-width: 160px; justify-content: center; }

.bd-count-all {
  color: var(--text-secondary);
  font-size: 12.5px;
  margin: 0;
}

/* The number beside a queue state chip. The brackets are NOT here: as a
   ::before/::after pair they render whether or not there is a count, so
   a chip drawn before its number arrived read "Waiting to be read ()".
   paintControls writes the whole string, brackets included. */
.bd-count { opacity: .7; }
.bd-count:empty { display: none; }

/* A list mid-fetch. Only the rows dim — the controls above stay at full
   contrast because they are still usable, and dimming the box somebody
   is typing into is how a search field looks broken. */
.bd-list[aria-busy="true"] { opacity: .55; transition: opacity .12s ease-out; }

/* ----------------------------------------------------------- the cards */

.bd-list { display: flex; flex-direction: column; gap: 10px; }

.bd-card {
  display: flex;
  gap: 14px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 14px;
  padding: 16px;
  box-shadow: var(--shadow);
}

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

.bd-card h3 {
  margin: 0 0 6px;
  font-size: 16px;
  line-height: 1.35;
}

.bd-card p {
  margin: 0 0 10px;
  color: var(--text-secondary);
  line-height: 1.55;
  /* Reports arrive with newlines in them and they carry the reproduction
     steps, which are the only part that makes a bug actionable. */
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

.bd-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
}

.bd-when { color: var(--text-secondary); font-size: 12px; }

/* Quiet on purpose: it is a handle for the few people who will ever
   quote it, not a thing to read. Monospace so a number pasted into a
   message keeps its shape, and pushed to the end of the meta row. */
.bd-ref {
  color: var(--text-secondary);
  font: 500 11.5px/1 ui-monospace, Consolas, monospace;
  opacity: .65;
  user-select: all;
}

/* The push to the end of the row belongs to the meta row and not to the
   reference itself. Unscoped, `margin-left:auto` followed the span into
   the merged notice's prose, where it broke "folded into #14 along with
   its votes" across three lines around the number. */
.bd-meta .bd-ref { margin-left: auto; }

/* The reference is a button now, so it has to be un-buttoned back to
   the quiet label it looks like. It stays a <button> and not an <a>
   because it filters this page rather than going anywhere — the address
   bar is updated afterwards so the link is copyable, but nothing is
   navigated, and an <a> would promise otherwise to a screen reader. */
.bd-reflink {
  appearance: none;
  background: none;
  border: 0;
  cursor: pointer;
  padding: 0;
}

.bd-reflink:hover, .bd-reflink:focus-visible {
  opacity: 1;
  color: var(--accent-ink);
  text-decoration: underline;
}

/* The one-post view says so, and says how to get out. A bar rather than
   a line of text: somebody who followed a link needs to know the board
   has more on it than the single card under this. */
.bd-focus {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 10px;
  background: var(--tint);
  border: 1px solid var(--accent-line);
  border-radius: var(--r-md);
  color: var(--text);
  font-size: 13.5px;
  margin: 0 0 14px;
  padding: 10px 14px;
}

/* And inside a sentence it is a word, so it takes the line's rhythm
   rather than the meta row's tighter one. The `font:` shorthand above
   sets line-height to 1, which is right for a chip-height row and wrong
   inside prose — an inline box a third of the paragraph's leading makes
   the line it lands on sit differently from the ones around it. */
.bd-asshown .bd-ref {
  opacity: 1;
  font-size: 12.5px;
  line-height: inherit;
}

/* ----------------------------------------------------------- the chips */

.bd-chip {
  border-radius: 999px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .02em;
  padding: 3px 9px;
  text-transform: uppercase;
  border: 1px solid transparent;
}

/* Bug keeps a colour because it is the one piece of metadata worth
   spotting from across the list. Idea is an OUTLINE and not the accent
   it used to be: the accent now belongs to the `investigating` status,
   and two indigo chips side by side on the same card made the pair
   unreadable — the one that changes should be the one that is coloured. */
.bd-chip.k-bug   { background: var(--fail-bg); color: var(--fail-fg);
                   border-color: var(--fail-br); }
.bd-chip.k-idea  { background: transparent; color: var(--text-secondary);
                   border-color: var(--border-2); }

/* Four statuses across the four token families studio.css actually has.
   There is no distinct blue here to give "investigating" — `--blue` is an
   alias for `--accent` (studio.css:127) — so it takes the accent, which
   is the right weight anyway: it is the one status that means somebody is
   at the keyboard right now. */
.bd-chip.s-open          { background: var(--chip-bg); color: var(--text-secondary);
                           border-color: var(--border-2); }
.bd-chip.s-investigating { background: var(--accent-soft); color: var(--accent-ink);
                           border-color: var(--accent-line); }
.bd-chip.s-planned       { background: var(--busy-bg); color: var(--busy-fg);
                           border-color: var(--busy-br); }
.bd-chip.s-fixed         { background: var(--good-bg); color: var(--good-fg);
                           border-color: var(--good-br); }

.bd-chip.st-pending    { background: var(--busy-bg); color: var(--busy-fg);
                         border-color: var(--busy-br); }
/* The one state that is waiting on the READER rather than on us, so it
   takes the accent — the same weight the board gives `investigating`,
   and for the same reason: somebody has to do something. */
.bd-chip.st-needs_info { background: var(--accent-soft); color: var(--accent-ink);
                         border-color: var(--accent-line); }
.bd-chip.st-published  { background: var(--good-bg); color: var(--good-fg);
                         border-color: var(--good-br); }
.bd-chip.st-declined   { background: var(--chip-bg); color: var(--text-secondary);
                         border-color: var(--border-2); }
.bd-chip.st-merged     { background: var(--chip-bg); color: var(--text-secondary);
                         border-color: var(--border-2); }

/* ---------------------------------------------------- tags and answers */

.bd-tags { display: flex; flex-wrap: wrap; gap: 6px; margin: 0 0 10px; }

.bd-tag {
  background: var(--chip-bg);
  border-radius: 6px;
  color: var(--text-secondary);
  font-size: 11.5px;
  padding: 3px 8px;
}

.bd-tag::before { content: "#"; opacity: .5; }

/* A question needs to look unanswered. The ordinary reply block is a
   quiet aside; this one carries the accent on its rule so it reads as
   something still open rather than as a closing remark. */
.bd-reply.bd-asking {
  background: var(--accent-soft);
  border-left-color: var(--accent);
}

.bd-answer {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin-top: 10px;
}

/* The unread count on the rail's Feedback button. Absolutely placed so
   it cannot change the row's height — `.snav button` is a type selector
   and every rail row shares its metrics, so a badge that took part in
   the layout would shift the whole column. */
.bd-raildot {
  position: absolute;
  top: 50%;
  right: 12px;
  transform: translateY(-50%);
  background: var(--accent);
  color: var(--on-accent);
  border-radius: 999px;
  font: 700 10.5px/1 inherit;
  min-width: 17px;
  padding: 3px 5px;
  text-align: center;
}

/* The row has to be a positioning context for the badge above, and it
   is not one by default. Scoped to the button that carries a badge so
   no other rail row's layout is touched. */
#tab_board { position: relative; }

/* ------------------------------------------------------------ the vote */

.bd-vote {
  appearance: none;
  background: var(--surface-2);
  border: 1px solid var(--border-2);
  border-radius: 12px;
  color: var(--text-secondary);
  cursor: pointer;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  font: inherit;
  font-weight: 700;
  min-width: 52px;
  padding: 8px 6px;
  height: fit-content;
}

.bd-vote svg { width: 16px; height: 16px; }

.bd-vote:hover:not(:disabled) {
  border-color: var(--accent-line);
  color: var(--accent-ink);
}

.bd-vote.on {
  background: var(--accent-soft);
  border-color: var(--accent-line);
  color: var(--accent-ink);
}

.bd-vote:disabled { opacity: .6; cursor: default; }

/* ------------------------------------------------------ official reply */

.bd-reply, .bd-asshown {
  background: var(--tint);
  border-left: 3px solid var(--accent);
  border-radius: 0 8px 8px 0;
  margin-top: 10px;
  padding: 10px 12px;
}

.bd-reply b, .bd-asshown b {
  color: var(--accent-ink);
  display: block;
  font-size: 12px;
  margin-bottom: 4px;
  text-transform: uppercase;
  letter-spacing: .03em;
}

.bd-reply p, .bd-asshown p { margin: 0; color: var(--text); }

/* ------------------------------------------------------------ the form */

.bd-head .bd-open { margin-top: 6px; }

/* What stands where the form would be for somebody with no account.
   Reading the board is open to everybody and posting is not, so this is
   the only place on the public page where the difference shows — and it
   is drawn as an offer rather than as a refusal, which is why the
   sentence under the button is about what an account buys them and not
   about what they may not do.

   .bd-primary is an <a> here and a <button> everywhere else, so the two
   properties a link needs and a button does not are set on it: the
   underline off, and inline-flex, because a link is inline by default
   and the padding would otherwise bleed through the line above. */
.bd-guest { margin-top: 6px; }

.bd-guest .bd-primary {
  display: inline-flex;
  align-items: center;
  text-decoration: none;
}

/* The hint's own rule pulls itself up 6px to sit against the field it
   annotates inside .bd-form's gap. There is no field above it here, so
   the pull is cancelled and it gets ordinary space instead. */
.bd-guest .bd-hint { margin: 10px 0 0; max-width: 52ch; }

.bd-form {
  display: flex;
  flex-direction: column;
  gap: 12px;
  margin-top: 14px;
}

.bd-lab {
  display: flex;
  flex-direction: column;
  gap: 5px;
  font-size: 13px;
  font-weight: 600;
  flex: 1;
  min-width: 0;
}

.bd-lab input[type="text"], .bd-lab textarea, .bd-lab select {
  background: var(--surface-2);
  border: 1px solid var(--border-2);
  border-radius: 10px;
  color: var(--text);
  font: inherit;
  font-weight: 400;
  padding: 9px 11px;
  width: 100%;
}

.bd-lab textarea { resize: vertical; line-height: 1.5; }

.bd-lab input:focus, .bd-lab textarea:focus, .bd-lab select:focus {
  border-color: var(--accent);
  outline: 2px solid var(--ring);
  outline-offset: -1px;
}

/* The label's caption and its "optional" marker on one line. `.bd-lab`
   is a flex column, so a bare span beside the text became a row of its
   own and pushed the word onto its own line under the heading. */
.bd-labtop { display: flex; align-items: baseline; gap: 6px; }

.bd-opt {
  color: var(--text-secondary);
  font-weight: 400;
  font-style: normal;
  /* studio.css uppercases form labels; the marker is an aside and reads
     as shouting in the same case. */
  text-transform: none;
}

.bd-row { display: flex; gap: 12px; flex-wrap: wrap; }
.bd-narrow { flex: 0 0 150px; }

.bd-kindpick { display: flex; gap: 16px; font-size: 14px; }
.bd-kindpick label { display: flex; align-items: center; gap: 6px; cursor: pointer; }

.bd-check {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 13px;
  color: var(--text-secondary);
}

.bd-check code {
  background: var(--chip-bg);
  border-radius: 5px;
  padding: 2px 6px;
  font-size: 12px;
  /* studio.css uppercases form labels, and this is the one place a
     label contains a literal string that is about to be stored — the
     browser and screen size being offered. Shouting it also misreports
     it: what is shown has to be what gets sent. */
  text-transform: none;
}

.bd-note {
  color: var(--text-secondary);
  font-size: 13px;
  line-height: 1.5;
  margin: 0;
}

/* Sits tight under the field it belongs to, which is what distinguishes
   it from .bd-note — that one is about the whole form, this one is about
   the box directly above it. The negative margin pulls it inside the
   form's own 12px gap so the pair reads as one unit. */
.bd-hint {
  color: var(--text-secondary);
  font-size: 12.5px;
  line-height: 1.45;
  margin: -6px 0 0;
}

.bd-actions { display: flex; gap: 8px; flex-wrap: wrap; }

/* The filled action, scoped the way compilations.css, flow.css and
   pro.css each scope their own. There is deliberately no global
   `.primary` in this codebase — `button.go` is the hero CTA and carries
   a 24px top margin and a 30px shadow, which is right for Generate and
   far too loud for a Send button inside a form. This is `button.ghost`'s
   proportions with the accent filled in, so the pair sit level. */
.bd-primary {
  appearance: none;
  background: var(--cta);
  border: 1px solid transparent;
  border-radius: var(--r-md);
  color: var(--on-accent);
  cursor: pointer;
  font: inherit;
  font-size: 13.5px;
  font-weight: 600;
  padding: 10px 18px;
  width: max-content;
  transition: all .3s ease-out;
}

.bd-primary:hover:not(:disabled) {
  filter: brightness(1.06);
  transform: translateY(-1px);
}

.bd-primary:disabled { opacity: .45; cursor: default; transform: none; }

.bd-err {
  background: var(--fail-bg);
  border: 1px solid var(--fail-br);
  border-radius: 10px;
  color: var(--fail-fg);
  margin: 0;
  padding: 10px 12px;
}

.bd-empty {
  color: var(--text-secondary);
  padding: 28px 4px;
  text-align: center;
}

/* ----------------------------------------------------------- the queue */

.bd-queue .bd-raw {
  background: var(--surface-2);
  border-radius: 8px;
  padding: 10px 12px;
  color: var(--text);
}

.bd-ctx {
  color: var(--text-secondary);
  font-size: 12px;
  margin: 0 0 10px;
}

.bd-modform {
  border-top: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin-top: 12px;
  padding-top: 12px;
}

.bd-danger { color: var(--fail-fg); }
.bd-danger:hover { border-color: var(--fail-br); background: var(--fail-bg); }

/* ------------------------------------------------------------- narrow */

@media (max-width: 640px) {
  .bd-card { padding: 13px; gap: 10px; }
  .bd-vote { min-width: 44px; padding: 6px 4px; }
  .bd-row { flex-direction: column; }
  .bd-narrow { flex: 1; }
}
