/* K1BTC Station Log — tokens
 * Dark by default. Light values exist only for print.
 * Colour is oklch: two accents share lightness and chroma and differ only in hue,
 * so amber and green read as the same "lamp" at two frequencies — the way a rig's
 * display and its S-meter do.
 */

:root {
  /* ---- surface --------------------------------------------------------- */
  --bg:          oklch(0.170 0.009 135);  /* page. near-black with a faint olive cast */
  --bg-raised:   oklch(0.205 0.009 135);  /* photo placeholder fill, hatch ground */
  --rule:        oklch(0.315 0.010 135);  /* structural: year markers, band cells */
  --rule-soft:   oklch(0.245 0.009 135);  /* the ruled lines of the log book */

  /* ---- ink ------------------------------------------------------------- */
  --fg:          oklch(0.885 0.012 95);   /* body prose */
  --fg-dim:      oklch(0.660 0.011 95);   /* dates, secondary prose */
  /* Measured, not asserted: 0.575 renders 4.38:1 on --bg, which misses the AA
     floor this token is documented to sit on (decisions.md, "do not darken it
     again"). 0.582 is the first step that clears 4.5:1 — 4.52:1. */
  --fg-faint:    oklch(0.582 0.010 95);   /* labels, captions, times, empty state gutter */

  /* ---- accents (2 only) ------------------------------------------------ */
  --amber:       oklch(0.775 0.125 75);   /* section headers, links, callsign mark, 73 */
  --green:       oklch(0.775 0.125 152);  /* QSO data lines, active bands */
  --amber-hover: oklch(0.860 0.130 78);
  --amber-underline: oklch(0.775 0.125 75 / 0.35);
  --green-edge:  oklch(0.775 0.125 152 / 0.40);
  --green-select:oklch(0.775 0.125 152 / 0.28);

  /* ---- type ------------------------------------------------------------ */
  /* One family. No web fonts. A ham's page is monospace because a log is
     column-aligned and a rig's display has no other option. Long prose is kept
     to 64ch and 1.65 line-height, which is what makes mono readable at length. */
  --mono: ui-monospace, "SFMono-Regular", Menlo, Consolas, "DejaVu Sans Mono", monospace;

  --t-body:     15px;   /* log prose */
  --t-data:     14px;   /* station table values, Elsewhere rows */
  --t-date:     13px;   /* gutter date */
  --t-meta:     12px;   /* QSO data line, section headers */
  --t-label:    11px;   /* uppercase labels, times, captions, nav */
  --t-micro:    10px;   /* band-cell mode list */
  --t-callsign: 44px;

  --lh-prose: 1.65;
  --ls-label: 0.12em;
  --ls-head:  0.20em;
  --ls-data:  0.06em;

  /* ---- measure & rhythm ------------------------------------------------ */
  --page-max:   900px;
  --page-pad:   32px;
  --gutter:     12ch;   /* date column. 12ch fits YYYY-MM-DD plus air */
  --gutter-gap: 28px;
  --measure:    64ch;   /* prose line length */
  --entry-pad:  22px;   /* vertical padding inside a log entry */
  --section-gap:64px;
  --navbar-h:   42px;   /* year markers stick directly under the nav bar */

  /* ---- print ----------------------------------------------------------- */
  --print-bg:    #ffffff;
  --print-fg:    #111111;
  --print-dim:   #5b584f;
  --print-rule:  #c9c6bd;
  --print-body:  10pt;
  --print-margin:16mm;
}


/* K1BTC Station Log — layout
 * One file, no JavaScript, no web fonts.
 * Everything is one of four things: a ruled row, a data pair, a band cell, or prose.
 */

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

body {
  background: var(--bg);
  color: var(--fg);
  font-family: var(--mono);
  font-size: var(--t-body);
  line-height: var(--lh-prose);
  -webkit-font-smoothing: antialiased;
  text-wrap: pretty;
}

a { color: var(--amber); text-decoration: none; border-bottom: 1px solid var(--amber-underline); }
a:hover { color: var(--amber-hover); border-bottom-color: currentColor; }
::selection { background: var(--green-select); }

.page { max-width: var(--page-max); margin: 0 auto; padding: 0 var(--page-pad) 96px; }

/* --- nav ---------------------------------------------------------------
 * A 41px bar, sticky, no title and no date. It exists so a 400-entry page
 * is navigable, not to announce anything. */
.nav {
  position: sticky; top: 0; z-index: 5;
  display: flex; justify-content: space-between; align-items: baseline; gap: 24px;
  padding: 11px 0 10px;
  background: var(--bg);
  border-bottom: 1px solid var(--rule-soft);
}
.nav__call { font-size: var(--t-meta); letter-spacing: 0.16em; color: var(--amber); }
.nav__links { display: flex; gap: 20px; font-size: var(--t-label); letter-spacing: var(--ls-label); text-transform: uppercase; }
.nav__links a { color: var(--fg-dim); border-bottom: none; }

/* --- station -----------------------------------------------------------
 * The only section that is always current, so it goes first and carries the
 * page's one piece of large type: the callsign. Nothing else exceeds 16px. */
.station { padding: 56px 0 8px; }
.callsign { margin: 0; font-size: var(--t-callsign); font-weight: 500; letter-spacing: 0.06em; line-height: 1; }
.standfirst { margin: 14px 0 0; font-size: 13px; color: var(--fg-dim); max-width: 60ch; }

/* Data pairs: 13ch label column, hairline above each row. A rig info screen. */
.facts { display: grid; grid-template-columns: 13ch 1fr; margin: 40px 0 0; font-size: var(--t-data); }
.facts dt {
  padding: 7px 0; border-top: 1px solid var(--rule-soft);
  font-size: var(--t-label); letter-spacing: var(--ls-label); text-transform: uppercase; color: var(--fg-faint);
}
.facts dd { margin: 0; padding: 7px 0; border-top: 1px solid var(--rule-soft); }
.facts dt:last-of-type, .facts dd:last-of-type { border-bottom: 1px solid var(--rule-soft); }

/* Band strip: eleven cells, wrapping. Worked bands are lit green with a solid
 * edge; unworked are dashed and faint. This is a band plan, read left to right
 * low to high, and it stays true whether or not anyone logs anything. */
.bands { margin: 36px 0 0; }
.bands__label { font-size: var(--t-label); letter-spacing: var(--ls-label); text-transform: uppercase; color: var(--fg-faint); margin-bottom: 12px; }
.bands__strip { display: flex; flex-wrap: wrap; gap: 6px; }
.band { min-width: 66px; padding: 7px 9px; text-align: center; border: 1px solid var(--green-edge); }
.band__n { font-size: 13px; color: var(--green); }
.band__m { font-size: var(--t-micro); letter-spacing: var(--ls-data); color: var(--fg-faint); }
.band--off { border: 1px dashed var(--rule); }
.band--off .band__n { color: var(--fg-faint); }

/* --- sections ----------------------------------------------------------- */
.section { padding: var(--section-gap) 0 0; }
.section__head { display: flex; justify-content: space-between; align-items: baseline; gap: 24px; padding-bottom: 10px; }
.section__head h2 { margin: 0; font-size: var(--t-meta); font-weight: 500; letter-spacing: var(--ls-head); text-transform: uppercase; color: var(--amber); }
.section__note { font-size: var(--t-label); letter-spacing: var(--ls-data); color: var(--fg-faint); }

/* --- log ---------------------------------------------------------------
 * The page. Every entry is the same ruled row: date gutter left, contact line
 * and prose right. No cards, no shadows, no per-entry chrome — the cost of an
 * entry is one hairline, which is what makes 400 of them survivable.
 *
 * Recency is deliberately not staged. There is no hero, no "latest", no large
 * date, no relative time. The newest entry is simply the first row under the
 * first year marker, and a six-month gap between it and today reads as a log
 * that hasn't needed writing in, not a site that has stopped. */
.year {
  position: sticky; top: var(--navbar-h); z-index: 4;
  background: var(--bg); border-top: 1px solid var(--rule);
  padding: 6px 0; font-size: var(--t-label); letter-spacing: var(--ls-head); color: var(--fg-faint);
}
.entry, .row {
  display: grid; grid-template-columns: var(--gutter) 1fr; gap: 0 var(--gutter-gap);
  border-top: 1px solid var(--rule-soft);
}
.entry { padding: var(--entry-pad) 0; }
.entry:last-child { border-bottom: 1px solid var(--rule-soft); }
.entry__date { font-size: var(--t-date); color: var(--fg-dim); }
.entry__time { font-size: var(--t-label); color: var(--fg-faint); }
/* The QSO line is the paper log's columns collapsed into one string:
   band · mode · call · frequency · report. Green because it is instrument data. */
.qso { font-size: var(--t-meta); letter-spacing: var(--ls-data); color: var(--green); margin-bottom: 8px; }
.entry p { margin: 0; max-width: var(--measure); }
.entry p + p { margin-top: 14px; }

/* --- contacts table ----------------------------------------------------
 * The full record. Dense, column-aligned, tabular figures. It sits below the
 * written entries: the writing is the page, the table is the evidence. One
 * hairline per row and nothing else per row, which is what lets it hold 1,200
 * rows without becoming a scrolling cost. thead is sticky under the nav and
 * repeats on every printed page. */
.qsos { padding-top: 56px; }
.qsos h3 { margin: 0; font-size: var(--t-label); font-weight: 500; letter-spacing: var(--ls-head); text-transform: uppercase; color: var(--fg-faint); }
.qsos__foot { margin: 14px 0 0; font-size: var(--t-label); color: var(--fg-faint); max-width: var(--measure); }
.qsotable { width: 100%; border-collapse: collapse; font-size: var(--t-meta); font-variant-numeric: tabular-nums; }
.qsotable th {
  text-align: left; font-weight: 500; padding: 7px 12px 7px 0;
  font-size: var(--t-micro); letter-spacing: var(--ls-label); text-transform: uppercase;
  color: var(--fg-faint); background: var(--bg);
  border-bottom: 1px solid var(--rule);
  position: sticky; top: var(--navbar-h); z-index: 3;
}
.qsotable td { padding: 5px 12px 5px 0; border-bottom: 1px solid var(--rule-soft); color: var(--fg-dim); white-space: nowrap; vertical-align: baseline; }
.qsotable td:nth-child(3) { color: var(--fg); }            /* the callsign */
.qsotable td:last-child { color: var(--green); padding-right: 0; text-align: right; }
/* The year row's lone td is also :last-child, so it loses to the QSL-column
   rule above unless it is scoped tighter. */
.qsotable tr.qso-year td {
  color: var(--fg-faint); letter-spacing: var(--ls-head); font-size: var(--t-micro);
  text-align: left; padding: 16px 12px 5px 0;
  border-bottom: 1px solid var(--rule);
}

.photo { margin: 18px 0 0; max-width: 520px; }
/* The markup is <img src="...svg">, not an inline <svg>: this selector has to
   name img or it matches nothing, the width/height attributes win, and a 520px
   photo drags a 375px phone sideways — the same failure §9 fixes for the table.
   layout-rules.md §4.3: "Image fills width, height auto". */
.photo img, .photo svg { display: block; width: 100%; height: auto; }
.photo figcaption { margin-top: 8px; font-size: var(--t-label); color: var(--fg-faint); }

/* --- notes -------------------------------------------------------------
 * Empty by default and designed that way. The empty state uses the same ruled
 * row as everything else, with an em dash in the date gutter: a line left blank
 * on purpose in a book that has lines. It never says "coming soon" and never
 * shows a spinner, an icon, or a dashed drop zone — it states the rate. */
.note { padding: 26px 0; border-bottom: 1px solid var(--rule-soft); }
.note h3 { margin: 0 0 12px; font-size: 16px; font-weight: 500; letter-spacing: 0.02em; }
.note p { margin: 0 0 14px; }
.note p:last-child { margin-bottom: 0; }
.note__body { max-width: var(--measure); }
.empty { padding: var(--entry-pad) 0; border-bottom: 1px solid var(--rule-soft); }
.empty__mark { font-size: var(--t-date); color: var(--fg-faint); }
.empty p { margin: 0; max-width: var(--measure); color: var(--fg-dim); }
/* Same sibling rule as .entry p + p, and load-bearing for the same reason:
   without it a two-paragraph empty state runs together. The generated page
   wraps the empty state's prose so the grid still gets one child. */
.empty p + p { margin-top: 14px; }

/* --- elsewhere ---------------------------------------------------------- */
.row { padding: 14px 0; font-size: var(--t-data); }
.row:last-of-type { border-bottom: 1px solid var(--rule-soft); }
.row__label { font-size: var(--t-label); letter-spacing: var(--ls-label); text-transform: uppercase; color: var(--fg-faint); padding-top: 2px; }
.row__aside { color: var(--fg-faint); }

.foot { padding: 56px 0 0; display: flex; justify-content: space-between; align-items: baseline; gap: 24px; font-size: var(--t-label); color: var(--fg-faint); }
.foot__73 { letter-spacing: var(--ls-head); color: var(--amber); }

/* --- narrow ------------------------------------------------------------
 * Below 620px the gutter cannot hold a date and a time side by side with
 * 64ch of prose, so the row unstacks: date and time become one baseline pair
 * above the entry. Nothing else changes. */
@media (max-width: 620px) {
  .page { padding: 0 20px 72px; }
  .entry, .row, .facts { grid-template-columns: 1fr; gap: 6px 0; }
  .entry__gutter, .row { display: flex; gap: 12px; align-items: baseline; flex-wrap: wrap; }
  .entry__gutter { display: flex; }
  .callsign { font-size: 34px; }
  .facts dt { border-top: 1px solid var(--rule-soft); padding-bottom: 0; }
  .facts dd { border-top: none; padding-top: 2px; }

  /* The contacts table is 8 nowrap columns and ~414px of min-content, which a
     375px phone cannot hold; unhandled it drags the whole body sideways. Freq
     and RST go: Date, UTC, Call, Band, Mode and QSL are what answer "did we
     work?", which is why anyone reaches this page from a phone. Both are still
     in the printed and desktop table. */
  .qsotable th:nth-child(6), .qsotable td:nth-child(6),
  .qsotable th:nth-child(7), .qsotable td:nth-child(7) { display: none; }
  .qsotable th, .qsotable td { padding-right: 9px; }
  .qsotable th:first-child, .qsotable td:first-child { padding-right: 11px; }
}

/* --- print -------------------------------------------------------------
 * Hams print things: a page for the shack wall, a log to take portable.
 * Paper is the light theme. Ink goes black, rules go grey, the nav disappears,
 * link targets are printed after the link text, and no entry breaks across a
 * page. Photo placeholders drop to 45% so they don't eat toner. */
@media print {
  @page { margin: var(--print-margin); }
  /* Paper is the light theme, and two things have to be said out loud for it to
     actually be light. The page declares color-scheme: dark, so the UA paints a
     dark canvas unless print takes it back — #111 ink on that is black on black.
     And the universal reset below is !important, which beats body's plain
     background and throws away the white page it is printed on; html and body
     have to re-assert it at equal weight. Verified by printing, not by reading:
     without these two rules the whole page prints unreadable whenever the
     browser is asked to include background graphics. */
  :root { color-scheme: light; }
  body { background: var(--print-bg); color: var(--print-fg); font-size: var(--print-body); line-height: 1.5; }
  * { background-color: transparent !important; box-shadow: none !important; }
  html, body { background-color: var(--print-bg) !important; }
  .page { max-width: none; padding: 0; }
  .nav { display: none; }
  .year { position: static; border-top-color: var(--print-rule); color: var(--print-dim); }
  .entry, .row, .note, .empty { break-inside: avoid; border-color: var(--print-rule); }
  .facts dt, .facts dd { border-color: var(--print-rule); }
  /* The closing hairlines are set by higher-specificity screen rules than the
     two above and would otherwise print in the dark-theme rule colour — a heavy
     near-black line where the sheet wants a grey one. Same collision as the
     colour rules below. Every screen selector that carries a border and outranks
     a plain element+class is named here:
       .facts dt:last-of-type / dd:last-of-type  (0,2,1)  the facts block's base
       .row:last-of-type                         (0,2,0)  last Elsewhere row,
                                                          and the empty state,
                                                          which is a .row too
       .entry:last-child                         (0,2,0)  the log's last entry
                                                          when no table follows
       .qsotable tr.qso-year td                  (0,2,2)  the year rules in the
                                                          contacts table */
  .facts dt:last-of-type, .facts dd:last-of-type,
  .row:last-of-type,
  .entry:last-child { border-color: var(--print-rule); }
  .qsotable tr.qso-year td { border-color: var(--print-rule); }
  .qso, .band__n { color: var(--print-fg); }
  .band { border-color: var(--print-rule); }
  .entry__date, .entry__time, .row__label, .row__aside, .section__note,
  .bands__label, .band__m, .empty__mark, .empty p, .standfirst, .foot,
  .facts dt, .photo figcaption { color: var(--print-dim); }
  .callsign, .section__head h2, .foot__73 { color: var(--print-fg); }
  a { color: var(--print-fg); border-bottom: none; }
  a[href]::after { content: " — " attr(href); color: var(--print-dim); }
  .photo { opacity: 0.45; }
  .qsotable th { position: static; font-size: 8pt; color: var(--print-dim); border-color: var(--print-rule); }
  .qsotable td { font-size: 8.5pt; border-color: var(--print-rule); color: var(--print-fg); }
  .qsotable tr { break-inside: avoid; }
  .qsotable tr.qso-year td { color: var(--print-dim); }
  /* Three screen rules outrank the print rules above on specificity and drag
     dark-theme inks onto paper. Measured on a printed page, not inferred:
       .qsotable td:nth-child(3)  (0,2,1) beats .qsotable td (0,1,1), so the CALL
                                  column — the column the visitor came for —
                                  printed at 1.4:1, near-white on white;
       .qsotable td:last-child    same, and printed green at 1.9:1, which §10
                                  says accents must not do on paper;
       .band--off .band__n        (0,2,0) beats .band__n (0,1,0), leaking a
                                  dark-theme ink into the strip.
     This is the collision decisions.md item 7 records for the year row. Fix by
     raising the print rule, never by weakening the screen one — the screen
     needs all three. */
  .qsotable td:nth-child(3) { color: var(--print-fg); }
  .qsotable td:last-child { color: var(--print-fg); }
  .band--off .band__n { color: var(--print-dim); }
  .qsos h3, .qsos__foot { color: var(--print-dim); }
}
