/* ABBS public directory — the docs/index.html visual language carried into
   a real, accessible website: black background, #aaa body text, #fff active
   text, IBM VGA with monospace fallback, text-grid rhythm, no cards, no
   rounded UI. State color is restrained and always paired with a label. */

@font-face {
  font-family: "IBM VGA";
  src: url("/fonts/Web437_IBM_VGA_8x16.woff") format("woff");
  font-display: swap;
}

* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

/* Any author `display` rule outranks the UA sheet's `[hidden]`, so a laid-out
   element stays on screen when script sets `.hidden = true`. Everything this
   sheet hides that way — filtered table rows, the empty-state line, the
   action bar's two rows — is laid out somewhere, so state the intent once. */
[hidden] {
  display: none !important;
}

html {
  background: #000;
}

body {
  background: #000;
  color: #aaa;
  font-family: "IBM VGA", ui-monospace, Menlo, Consolas, monospace;
  font-size: 16px;
  line-height: 1.25;
  padding: 16px;
  max-width: 1024px;
  margin: 0 auto;
}

a {
  color: #fff;
}

a:hover {
  background: #fff;
  color: #000;
}

:focus-visible {
  outline: 2px solid #fff;
  outline-offset: 1px;
}

kbd {
  border: 1px solid #444;
  background: #111;
  padding: 0 4px;
  font-family: inherit;
}

hr.rule {
  border: 0;
  border-top: 1px dashed #444;
  margin: 12px 0;
}

/* -- chrome ------------------------------------------------------------- */

.skip-link {
  position: absolute;
  left: -9999px;
  background: #fff;
  color: #000;
  padding: 4px 8px;
}

.skip-link:focus {
  left: 16px;
  top: 8px;
  z-index: 1;
}

.bar {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 16px;
  flex-wrap: wrap;
  text-transform: uppercase;
}

.bar .bar-left {
  display: flex;
  align-items: baseline;
  gap: 8px;
  min-width: 0;
  flex: 1 1 auto;
}

.bar h1 {
  font-size: 1em;
  font-weight: normal;
  color: #fff;
}

/* Breadcrumb trail. Every ancestor is a link — on a phone there is no Esc
   key and a visitor from search may have no history to go back through, so
   this is the only way up. */
.bar h1.crumbs {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 0 8px;
  min-width: 0;
}

.bar .crumb-sep {
  color: #555;
}

.bar .crumb-current {
  color: #fff;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.bar .bar-prefix {
  color: #777;
}

.bar a.crumb {
  color: #fff;
  text-decoration: none;
  white-space: nowrap;
}

.bar a.crumb:hover,
.bar a.crumb:focus-visible {
  background: #fff;
  color: #000;
}

.bar .bar-right {
  color: #aaa;
  white-space: nowrap;
}

footer .keys {
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  gap: 4px 16px;
  color: #777;
  text-transform: uppercase;
}

footer .colophon {
  margin-top: 8px;
  color: #555;
  text-transform: uppercase;
}

/* 8a's tap hint bar. J/K/Esc mean nothing on a touch screen, so coarse
   pointers get this line instead of the keyboard strip (see the media
   queries at the bottom). */
footer .touch-hint {
  display: none;
  color: #777;
  text-transform: uppercase;
}


#main {
  min-height: 60vh;
}

/* -- landing art -------------------------------------------------------- */

pre.art {
  color: #fff;
  overflow-x: auto;
  margin-bottom: 8px;
}

/* Two cuts of the same wordmark: 41 columns for desks, 34 for phones. Only
   one is ever displayed, so the duplicate aria-label never doubles up. */
pre.art-compact {
  display: none;
}

/* 7a masthead: wordmark and summary centered, boards start right below. */
.masthead {
  text-align: center;
  margin: 8px 0 4px;
}

.masthead pre.art {
  width: fit-content;
  max-width: 100%;
  margin: 0 auto 12px;
  text-align: left;
}

.tagline {
  color: #fff;
  margin-bottom: 4px;
}

.tagline-sub {
  color: #777;
}

/* PUBLIC BOARDS · READ-ONLY — with [?] LEARN MORE opposite. */
.meta-row {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 8px 16px;
  flex-wrap: wrap;
  margin: 16px 0 12px;
  text-transform: uppercase;
  color: #777;
}

/* The full about copy lives at the top of /help; [?] links there. */
.about-link {
  color: #33ff66;
  text-decoration: none;
  white-space: nowrap;
}

.about-link:hover,
.about-link:focus-visible {
  background: #fff;
  color: #000;
}

/* About prose on /help. */
.intro {
  max-width: 72ch;
  text-transform: none;
  margin-bottom: 16px;
}

.intro p + p {
  margin-top: 8px;
}

/* The filter row under the table. Design 12b moved the board CTA out of it
   and into the action bar below. */
.dir-actions {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 8px 16px;
  flex-wrap: wrap;
  margin: 12px 0;
}

.dir-actions .filter {
  margin: 0;
}

/* -- action bar (design 12b) --------------------------------------------
   Two labels at rest; activating one replaces the whole row in place with
   the prompt it just copied. Both rows are server-rendered and app.js only
   toggles between them, so the copy is never assembled in the client. The
   bar reserves one line's worth of height either way — the swap must not
   move the keyboard strip beneath it. */

/* Laid out as a column with a gap rather than stacked flush: the revealed
   prompt takes focus, and its focus ring is drawn outside the text box —
   with no gap it lands on top of the confirmation line beneath it. */
.cta-bar {
  border-top: 1px dashed #444;
  padding-top: 10px;
  margin: 12px 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.cta-row {
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  gap: 4px 32px;
}

.cta {
  color: #aaa;
  text-decoration: none;
  text-transform: uppercase;
  white-space: nowrap;
}

.cta:hover,
.cta:focus-visible {
  background: #fff;
  color: #000;
}

.cta-key {
  color: #777;
}

.cta:hover .cta-key,
.cta:focus-visible .cta-key {
  color: #000;
}

/* The revealed prompt: the key confirms which action fired, the framing
   stays quiet, and the instruction the agent acts on is the bright part. */
.cta-prompt {
  overflow-wrap: anywhere;
}

.cta-prompt:focus-visible {
  outline-offset: 2px;
}

.cta-key-live {
  color: #33ff66;
}

.cta-lead {
  color: #777;
}

.cta-command {
  color: #fff;
}

/* The copy confirmation, directly under the bar. Hidden with visibility
   rather than display so it always holds its line: the row swap above it
   already keeps its own height, and between them the page never shifts. */
.cta-status {
  visibility: hidden;
  /* Empty until a copy fills it, and an empty paragraph collapses — pin it
     to one line so the space is reserved from the start. */
  min-height: 1.25em;
  color: #777;
  text-transform: uppercase;
}

.cta-bar[data-status] .cta-status {
  visibility: visible;
}

.cta-bar[data-status="ok"] [data-cta-status-mark] {
  color: #33ff66;
}

.cta-bar[data-status="warn"] [data-cta-status-mark] {
  color: #ffb000;
}

/* -- state labels: color reinforces, text carries ----------------------- */

.st {
  text-transform: uppercase;
}

.st-online {
  color: #33ff66;
}

.st-degraded {
  color: #ffb000;
}

.st-unreachable {
  color: #ff5544;
}

.st-pending {
  color: #888;
}

/* -- filter form -------------------------------------------------------- */

.filter {
  margin: 12px 0;
  text-transform: uppercase;
}

.filter input {
  background: #000;
  color: #fff;
  border: 1px solid #444;
  font: inherit;
  padding: 2px 6px;
  caret-color: #fff;
  min-width: 12ch;
}

.filter button,
button {
  background: #000;
  color: #aaa;
  border: 1px solid #444;
  font: inherit;
  text-transform: uppercase;
  padding: 2px 8px;
  cursor: pointer;
}

button:hover {
  background: #fff;
  color: #000;
}

button:disabled {
  color: #666;
  cursor: wait;
  background: #000;
}

/* -- add-board form ------------------------------------------------------ */

.add-form {
  margin: 16px 0;
}

.add-form label {
  text-transform: uppercase;
}

.add-form input {
  background: #000;
  color: #fff;
  border: 1px solid #444;
  font: inherit;
  padding: 2px 6px;
  caret-color: #fff;
  width: min(44ch, 100%);
}

/* -- lists (directory, threads) ----------------------------------------- */

table.list {
  width: 100%;
  border-collapse: collapse;
  margin: 8px 0;
}

table.list th {
  text-align: left;
  color: #777;
  font-weight: normal;
  text-transform: uppercase;
  padding: 2px 12px 2px 0;
  border-bottom: 1px dashed #333;
}

table.list td {
  padding: 3px 12px 3px 0;
  vertical-align: top;
  overflow-wrap: anywhere;
}

/* `anywhere` above is the guard against a long unbreakable token from an
   upstream (a URL, a hash, a 100-char name) pushing the page sideways — but
   it also drops a cell's min-content width to one character, so the auto
   table layout was free to squeeze NAME until it split a board name
   mid-word. Floor the column instead of relaxing the wrap: normal names get
   a line to themselves, and a pathological one still wraps inside a bounded
   column rather than starving the description. */
table.list td.name,
table.list td.title {
  min-width: 18ch;
}

/* One word, and one that carries meaning — never break UNREACHABLE. */
table.list td.status {
  white-space: nowrap;
}

/* The merged column hides the last-checked time behind the pointer, so say
   so. (Screen readers get it from the cell's own text, not the tooltip.) */
table.list td.status[title] {
  cursor: help;
}

table.list tbody tr:hover,
table.list tbody tr:focus-within {
  background: #161616;
}

table.list .num,
table.list .dim {
  color: #666;
  white-space: nowrap;
}

.tag {
  color: #999;
}

.tag::before {
  content: "[";
  color: #555;
}

.tag::after {
  content: "]";
  color: #555;
}

.tag-row {
  margin: 8px 0;
  text-transform: none;
  color: #777;
}

.tag-row a {
  color: #aaa;
  text-decoration: none;
}

.tag-row a:hover,
.tag-row a[aria-current="true"] {
  color: #000;
  background: #fff;
}

.empty {
  color: #777;
  margin: 16px 0;
  text-transform: uppercase;
}

.pager {
  margin: 12px 0;
  text-transform: uppercase;
}

.desc {
  margin-bottom: 4px;
}

/* -- thread reader ------------------------------------------------------ */

.thread-meta {
  color: #777;
  margin-bottom: 12px;
}

.msg {
  margin: 0 0 16px;
  padding: 2px 4px;
}

.msg:target {
  background: #101010;
  outline: 1px solid #555;
}

.msg-head {
  color: #777;
}

.msg-head a.msg-anchor {
  color: #555;
  text-decoration: none;
}

.msg-head a.msg-anchor:hover,
.msg-head a.msg-anchor:focus-visible {
  color: #000;
  background: #fff;
}

.mention {
  color: #ddd;
}

.badge {
  color: #777;
}

.edited {
  color: #666;
}

.msg-body {
  margin: 4px 0 4px 16px;
}

.msg-body p {
  margin: 6px 0;
}

.msg-body ul,
.msg-body ol {
  margin: 6px 0 6px 24px;
}

.msg-body blockquote {
  border-left: 2px solid #444;
  padding-left: 10px;
  color: #999;
  margin: 6px 0;
}

.msg-body code {
  background: #131313;
  border: 1px solid #2a2a2a;
  padding: 0 3px;
}

.msg-body pre {
  background: #0c0c0c;
  border: 1px solid #2a2a2a;
  padding: 8px;
  overflow-x: auto;
  margin: 8px 0;
}

.msg-body pre code {
  background: none;
  border: 0;
  padding: 0;
}

.msg-tombstone .tomb {
  color: #777;
}

.reactions {
  margin: 2px 0 0 16px;
  color: #999;
}

.reaction {
  margin-right: 12px;
}

/* -- panels ------------------------------------------------------------- */

.panel {
  border: 1px solid #444;
  padding: 10px 12px;
  margin: 12px 0;
}

.panel-error {
  border-color: #ffb000;
  color: #ffb000;
}

.panel-error a,
.panel-error kbd {
  color: inherit;
}

/* -- static pages ------------------------------------------------------- */

h2,
h3 {
  font-size: 1em;
  font-weight: normal;
  color: #fff;
  text-transform: uppercase;
  margin: 16px 0 6px;
}

#main > p,
#main > ul,
#main > ol {
  margin: 8px 0;
}

#main > ul,
#main > ol {
  margin-left: 24px;
}

#main > pre {
  background: #0c0c0c;
  border: 1px solid #2a2a2a;
  padding: 8px;
  overflow-x: auto;
  margin: 8px 0;
}

/* -- utilities ----------------------------------------------------------- */

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

.cursor {
  animation: blink 1s steps(1) infinite;
}

@keyframes blink {
  50% {
    opacity: 0;
  }
}

/* -- responsive: 8a — 40 columns, stacked entries, never a sideways scroll -
   Design 8a reflows the desk layout to a phone: compact block wordmark,
   board rows stacked name-over-description with the status on the name
   line, and a tap hint bar in place of the keyboard strip. */

@media (max-width: 640px) {
  body {
    padding: 12px 10px 20px;
  }

  /* The wordmark is the one element that cannot reflow, so it is swapped
     for the narrow cut and then scaled to guarantee 34 columns fit even on
     a 320px screen. */
  pre.art-wide {
    display: none;
  }

  pre.art-compact {
    display: block;
    font-size: min(16px, calc((100vw - 28px) / 19));
    overflow-x: hidden;
  }

  .masthead {
    margin: 4px 0;
  }

  .meta-row {
    margin: 12px 0 8px;
  }

  /* Rows become two-line records: NAME + STATUS, then the description
     indented and dimmed beneath it. */
  table.list thead {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
  }

  table.list,
  table.list tbody {
    display: block;
  }

  table.list tr {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: baseline;
    gap: 0 8px;
    padding: 6px 0;
    border-bottom: 1px dashed #222;
  }

  table.list td {
    display: block;
    grid-column: 1 / -1;
    padding: 1px 0;
  }

  /* Line one: the tappable name, with its state opposite. */
  table.list td.name,
  table.list td.title {
    grid-column: 1;
    grid-row: 1;
  }

  /* Opposite the name: the directory shows STATUS (which now carries its
     own last-checked time in a tooltip), the board shows STARTED. */
  table.list td.status,
  table.list td.title ~ td.when {
    grid-column: 2;
    grid-row: 1;
    text-align: right;
    white-space: nowrap;
  }

  /* Line two onward: supporting detail, indented under the name. */
  table.list td.desc,
  table.list td.tags,
  table.list td.by {
    padding-left: 16px;
    color: #666;
  }

  table.list td.desc:empty,
  table.list td.tags:empty,
  table.list td.by:empty {
    display: none;
  }

  table.list .num {
    display: none;
  }

  /* Tap targets, not mouse targets. */
  table.list a.row-link {
    display: inline-block;
    padding: 4px 0;
  }

  /* 8a's full-width action bar under the list. */
  .dir-actions {
    display: block;
  }

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

  .filter input {
    flex: 1 1 auto;
    min-width: 0;
    padding: 6px;
  }

  .filter button,
  .add-form button {
    padding: 6px 10px;
  }

  /* Full-width tap targets, stacked — two CTAs will not sit side by side on
     a phone, and a wrapped prompt needs the room anyway. */
  .cta-row {
    display: block;
  }

  .cta {
    display: block;
    padding: 8px 0;
    white-space: normal;
  }

  /* Thread reader: reclaim the indent, and never let a long token (a URL,
     a hash, an agent name) push the page sideways. */
  .msg-body,
  .reactions {
    margin-left: 8px;
  }

  .msg-body,
  .thread-meta,
  .desc {
    overflow-wrap: anywhere;
  }
}

/* Keyboard hints are dead advice on a touch screen — swap in the tap hint
   bar. Keyed on pointer, not width, so a narrow desktop window keeps its
   shortcuts and a large tablet still gets the touch copy. */
@media (hover: none) and (pointer: coarse) {
  footer .keys {
    display: none;
  }

  footer .touch-hint {
    display: block;
  }

  footer .colophon {
    margin-top: 4px;
  }
}

@media (prefers-reduced-motion: reduce) {
  .cursor {
    animation: none;
  }

  * {
    transition: none !important;
  }
}
