/* headlines_row.css — THE ONE DEFINITION of a headLines board row.
 *
 * WHY THIS FILE EXISTS (Karl, 2026-09-14). Ben asked (web lane) for the front
 * page's top three to be "cloned rows from the headLines page. We want people to
 * get their first taste of the game there." The first cut HAND-COPIED the row
 * markup and CSS into index.html — a lookalike, not a clone — and it drifted the
 * same week: the board grew the marquee for over-long titles (Ben: "make the
 * headlines slowly crawl right if collapsed on iPhone") and a fixed-width slot
 * cell; the front page kept the old shape and got neither. A copy is measured
 * against the copy, so a hand-copy is a copy that will lie.
 *
 * The row is therefore extracted to ONE definition, loaded by BOTH pages via
 *
 *     <link rel="stylesheet" href="/headlines_row.css">
 *     <script src="/headlines_row.js"></script>
 *
 * A change to the row is now one edit both surfaces inherit — the same "one
 * shape, one edit" rule the feed's feed_data() already follows. If the front
 * page ever stops matching the board, that is a fact about THIS file, not about
 * a forgotten paste.
 *
 * Requires the host to serve static .css — verified live 2026-09-14
 * (200 text/css). Row markup is generated by headlines_row.js (hlRowHtml).
 */
/* The rows container: both pages wrap their rows in `.hl-rows` so stripe
   parity is deterministic — row 1 is row 1 on either surface, whatever the
   page puts around it. */
.hl-rows { display: flex; flex-direction: column; }
.hl-rows > .hl-row:first-child { border-top: none; }
  .hl-row {
    padding: 0.45rem 0.7rem;
  }
  .hl-row {
    display: flex;
    flex-direction: column;
    gap: 0.28rem;
    min-height: 3.1rem;
    justify-content: center;
  }
  .hl-top {
    display: flex; align-items: center; gap: 0.6rem;
    min-width: 0;
  }
  .hl-top .hl-act { margin-left: auto; }   /* actions pinned right */
  @media (max-width: 520px) {
    .hl-top { gap: 0.4rem; }
    .hl-rank { display: none; }
    .hl-slots { letter-spacing: 0.06rem; font-size: 0.85rem; }
    .hl-meta { font-size: 0.64rem; }
    .act-btn { padding: 0.45rem 0.55rem; min-width: 2.1rem; font-size: 0.85rem; }
  }
  .hl-row { border-top: 1px solid var(--line); font-size: 0.92rem; }
  .hl-rows > .hl-row:nth-child(odd) { background: rgba(255,255,255,0.014); }
  .hl-rows > .hl-row:hover { background: rgba(120,200,255,0.05); }
  .hl-rank {
    font-family: ui-monospace, monospace;
    color: var(--muted); font-size: 0.82rem; text-align: right;
    min-width: 1.1rem; flex: 0 0 auto;
  }
  .hl-rows > .hl-row:nth-child(-n+4) .hl-rank { color: var(--accent2); font-weight: 700; }
  .hl-slots { font-size: 0.92rem; white-space: nowrap; flex: 0 0 auto; }
  /* a fixed-width, centred cell per slot: alignment is structural, never a bet
     on emoji metrics (Ben, 2026-09-14 — the empty bullet drifted the columns) */
  .slot {
    display: inline-block; width: 1.35em; text-align: center;
    font-size: 0.95rem; line-height: 1.2;
  }
  .slot-open { opacity: 0.28; }   /* reserved, dimmed — not an answer yet */
  .hl-hp {
    font-family: ui-monospace, monospace;
    font-variant-numeric: tabular-nums;
    font-size: 0.9rem; font-weight: 600; color: var(--accent2);
    text-align: right; white-space: nowrap;
  }
  .hl-hp small { color: var(--muted); font-weight: 400; font-size: 0.72rem; }
  .hl-bot {
    display: flex; align-items: baseline; gap: 0.6rem; min-width: 0;
  }
  .hl-bot .hl-title { flex: 1 1 auto; }
  .hl-bot .hl-meta { flex: 0 0 auto; }
  .hl-bot .row-note { flex: 1 1 100%; }
  .hl-title { width: 100%; min-width: 0; overflow: hidden; }
  /* THE VERBATIM SOURCE TITLE BENEATH THE AUTHORED LINE (2026-09-17). The
     authored line is a DISPLAY choice; the plain fact is the board's promise
     (headline_author rule 4) and must stay on screen beside it. A block child
     of the title cell, so it wraps naturally under the crawl — it does NOT
     participate in the marquee, which measures only the anchor's text. */
  .hl-title .hl-src {
    display: block; margin-top: 0.12rem;
    font-family: ui-monospace, monospace; font-size: 0.66rem;
    color: var(--muted); letter-spacing: 0.02em; line-height: 1.35;
    white-space: normal; overflow: hidden; text-overflow: ellipsis;
  }
  /* MARQUEE (Ben, 2026-09-14): on an iPhone a long headline is truncated, so the
     tail is unreadable. Rows whose title overflows get a slow right-crawl that
     reveals the whole string and loops. Only overflowing rows animate (JS adds
     .crawl), so short titles are perfectly still — a screen full of moving text
     would be worse than a truncation. Respects prefers-reduced-motion. */
  .hl-title a { position: relative; }
  /* JS sets --crawl to the EXACT overflow distance (negative px) only on rows
     that overflow. The animation moves by that distance, pauses at the far end
     so the tail is readable, then returns. Duration is set per row so speed is
     constant (a long string takes longer, it does not move faster). */
  .hl-title.crawl a {
    white-space: nowrap;
    animation-name: hl-crawl;
    animation-timing-function: linear;
    animation-iteration-count: infinite;
    animation-duration: var(--crawl-dur, 14s);
  }
  .hl-title.crawl a:hover { animation-play-state: paused; }
  /* WRAP-AROUND (Ben, 2026-09-17: "Can we make the headLines animation wrap
     around?"). The old keyframes were a there-and-back PEEK: slide out to reveal
     the tail, pause, slide back to the start, repeat. That reads as a nervous
     twitch — the eye tracks a string that returns to where it began, and on a
     screen of 37 moving rows the board feels restless rather than readable.

     A wrap is a LOOP: the string scrolls fully off one edge and the same string
     re-enters from the other, so there is no "return" and no visible seam at the
     start. The trick is to duplicate the text with a gap: the track translates by
     exactly -(string width + gap), and at that instant the copy sits precisely
     where the original began — so the loop point is mathematically invisible.
     JS sets --crawl (one copy's overflow distance) and --crawl-w
     (string + gap, the true period). */
  @keyframes hl-crawl {
    from { transform: translateX(0); }
    to   { transform: translateX(calc(-1 * var(--crawl-w, var(--crawl, 0px)))); }
  }
  @media (prefers-reduced-motion: reduce) {
    .hl-title.crawl a { animation: none; }
  }
  .hl-title a {
    display: block; white-space: nowrap;
    overflow: hidden; text-overflow: ellipsis;   /* static: clip + … */
    color: var(--fg); font-weight: 600;
    transition: color .12s;
  }
  /* WHEN CRAWLING (Ben, 2026-09-14): the anchor must be its FULL natural width
     and must NOT ellipsize, or the animation just slides the "…" along and the
     tail never appears (exactly what Ben saw: "moving but not showing the full
     headline"). The CELL keeps overflow:hidden so the strip stays clipped; the
     anchor inside grows to max-content and translates to reveal the rest. */
  .hl-title.crawl { overflow: hidden; }
  .hl-title.crawl a {
    display: inline-block;
    width: max-content;
    overflow: visible;
    text-overflow: clip;
  }
  /* THE LOOP COPY, generated in CSS — no DOM node.
     A seamless wrap needs the text to appear twice: with one copy the string
     scrolls off the left and blank space enters from the right, so any "loop"
     is a visible snap. The obvious implementation is an inline duplicate
     <span aria-hidden="true">, and it is the wrong one — measured live, it makes
     the anchor 1085px wide inside a 245px cell, which an element-bounds probe
     reads as a layout overflow (render_check offenders went 0 -> 38) even though
     the cell clips it and the page never scrolls. aria-hidden does not help: a
     bounds probe measures BOXES, not semantics.
     `content: attr(data-crawl-copy)` produces the identical visual with no node:
     nothing for a probe to find, nothing for a screen reader to say, and no
     attribute whose support a tool can decline. The JS sets the attribute;
     unsetting it removes the copy with the class. */
  .hl-title.crawl a::after {
    content: attr(data-crawl-copy);
    padding-left: 48px;   /* the gap the loop travels across */
  }
  .hl-title a:hover { color: var(--accent2); text-decoration: underline; }
  .hl-title a:visited { color: #9a8fb8; }
  .hl-title a:visited:hover { color: var(--accent2); }
  .hl-meta {
    font-family: ui-monospace, monospace; color: var(--muted);
    font-size: 0.7rem; letter-spacing: 0.02em;
    white-space: nowrap; flex: 0 0 auto;
  }
  .hl-act { display: flex; gap: 0.35rem; flex: 0 0 auto; }
  .act-btn {
    font-family: ui-monospace, monospace;
    font-size: 0.9rem; line-height: 1;
    background: rgba(255,255,255,0.03);
    border: 1px solid var(--line);
    border-radius: 7px;
    color: var(--fg);
    padding: 0.5rem 0.66rem;
    min-width: 2.3rem;
    cursor: pointer;
    transition: background .12s, border-color .12s, color .12s, transform .06s;
  }
  .act-btn:hover { border-color: var(--accent2); color: var(--accent2);
                   background: rgba(120,200,255,0.08); }
  .act-btn:active { transform: translateY(1px); }
  .act-btn.down:hover { border-color: #e06c75; color: #e06c75;
                        background: rgba(224,108,117,0.08); }
  .act-btn:disabled { opacity: 0.4; cursor: default; }
  .row-note {
    display: none;                 /* only shown once an action reports */
    font-family: ui-monospace, monospace;
    font-size: 0.68rem;
    color: var(--accent2);
    letter-spacing: 0.02em;
    margin-top: 0.12rem;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  }
  .row-note:not(:empty) { display: block; }
  .row-note.err { color: #e06c75; }
  @media (max-width: 600px) {
    .hl-hp { min-width: 2.2rem; }
  }

/* THE BOARD HEADER (2026-09-14, found live: Ben read "#conceptshpactions" — the
   header markup used classes whose CSS was never moved into this shared sheet,
   so it rendered as inline run-together text). The rows are TWO-LINE cards now
   (a strip + a full-width title), so the header is a single thin STRIP LABEL
   above them, not a column header for a row that no longer exists. */
.board-head {
  display: flex; align-items: center; gap: 0.6rem;
  padding: 0.4rem 0.7rem;
  font-family: ui-monospace, monospace;
  font-size: 0.62rem; text-transform: uppercase; letter-spacing: 0.12em;
  color: var(--muted);
  background: rgba(255,255,255,0.03);
  border-bottom: 1px solid var(--line);
}
.board-head .hl-head-rank { text-align: right; min-width: 1.1rem; }
.board-head .hl-head-actions { margin-left: auto; }
@media (max-width: 520px) { .board-head .hl-head-rank { display: none; } }

/* WALLET ATTRIBUTION CHIP (Ben, 2026-09-14): the submitting wallet abbreviated
   (Xy..2Q), tapping opens Solscan at the transaction. Small, monospace, muted. */
.hl-wallet {
  flex: 0 0 auto; font-size: 0.68rem; color: var(--muted);
  border: 1px solid var(--line); border-radius: 5px; padding: 0.1rem 0.35rem;
  text-decoration: none; white-space: nowrap;
}
.hl-wallet:hover { color: var(--accent2); border-color: var(--accent2); }
