/* NIL HEARD — the shared surface: the header, and everything a page needs before it starts
 * being itself. Included by the site, the studio, the capture catalog and the workbench
 * index. What a surface adds on top is its own layout; what it must not do is redefine any
 * of this. ui/tokens.css comes first.
 */

*, *::before, *::after { box-sizing: border-box; }

/* THE ROOT SIZE IS THE ONE LEVER. Half of this project's type is set in rem (the site) and
 * half in px (the tools), and the complaint that started this was the same on both: it is
 * too small to read. 17px here lifts every rem-sized thing at once; the px sizes moved up
 * with it, and ui/tokens.css's --t-* scale is where they come from now. */
html { -webkit-text-size-adjust: 100%; font-size: 17px; }
body {
  margin: 0; background: var(--bg); color: var(--fg);
  font: var(--t-body)/1.55 var(--sans);
  -webkit-font-smoothing: antialiased;
}
a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

h1, h2, h3, legend, th, .logname, dt {
  font-family: var(--cond); text-transform: uppercase; letter-spacing: .14em; font-weight: 600;
}
h1 { font-size: 1.5rem; margin: 0 0 .25rem; letter-spacing: .12em; }
h1 a { color: inherit; }
h2 { font-size: .92rem; color: var(--dim); margin: 2.2rem 0 .8rem;
     border-bottom: 1px solid var(--line); padding-bottom: .3rem; }
h2 small, h3 small { font-family: var(--sans); text-transform: none; letter-spacing: 0;
                     font-weight: 400; color: var(--faint); font-size: var(--t-2xs); margin-left: 8px; }
h3 { font-size: .86rem; color: var(--dim); margin: 0 0 .5rem; }

/* DATA IS MONO. A frequency, a UTC minute, a sha, a job id, a seed — anything you would
   compare character by character is set in Martian Mono with tabular figures, so columns
   of numbers line up and two hashes differ visibly. Prose is not.
   The .9em is an OPTICAL correction, not a preference: Martian Mono has a large x-height
   and a wide cell even at wdth 75, so at the same nominal size it reads a step larger than
   the condensed and the sans beside it, and a line of data looked like a different, bigger
   typeface instead of the same voice saying numbers. It was .88em and is now .9em — the
   correction is still there, it is just no longer doing a second job it was never meant to
   do, which was making the smallest text on the page smaller still. */
.mono, code, kbd, pre, .c-utc, .c-f, .c-tier, .c-d {
  font-family: var(--mono); font-variant-numeric: tabular-nums;
  font-size: .9em; letter-spacing: -.005em;
}
.dim { color: var(--dim); }
.faint { color: var(--faint); }
.warn { color: var(--warn); }
kbd { border: 1px solid var(--line2); border-radius: 3px; padding: 0 4px; font-size: .85em; color: var(--dim); }
.skip { position: absolute; left: -999px; top: 0; background: var(--amber); color: var(--on-accent); padding: 4px 8px; z-index: 50; }
.skip:focus { left: 8px; }

/* --- the header, written once ------------------------------------------------------- */
.top {
  --pad-x: 20px; --pad-y: 14px;
  display: flex; align-items: baseline; gap: 22px;
  padding: calc(var(--pad-y) + env(safe-area-inset-top, 0px))
           calc(var(--pad-x) + env(safe-area-inset-right, 0px))
           var(--pad-y)
           calc(var(--pad-x) + env(safe-area-inset-left, 0px));
  border-bottom: 1px solid var(--line); background: var(--panel);
  position: sticky; top: 0; z-index: 20;
}
.brand { display: flex; gap: 14px; align-items: baseline; color: var(--fg); }
.brand:hover { text-decoration: none; }
.artist { font-family: var(--cond); font-weight: 600; letter-spacing: .22em; font-size: 1rem; }
.logname { color: var(--accent); font-size: .82rem; letter-spacing: .28em; }
.top nav { margin-left: auto; display: flex; gap: 18px; font-family: var(--cond);
           text-transform: uppercase; letter-spacing: .14em; font-size: .85rem; }
.top nav a { color: var(--dim); white-space: nowrap; }
.top nav a:hover { color: var(--fg); text-decoration: none; }
.top nav a[aria-current], .top nav a.on { color: var(--accent); border-bottom: 1px solid var(--accent); }
/* A tool's header carries two more things the public site never has: where you are, and
   whether what you did was written down. */
.top .crumb { color: var(--faint); font-size: var(--t-2xs); }
.top .status { font-size: var(--t-2xs); color: var(--dim); }
.top .status.ok { color: var(--keep); }
.top .status.bad { color: var(--kill); }
.top .sp { margin-left: auto; }

/* --- controls ------------------------------------------------------------------------ */
button, .btn {
  font: inherit; font-family: var(--cond); text-transform: uppercase; letter-spacing: .1em;
  font-size: var(--t-2xs); color: var(--fg); background: var(--panel2);
  border: 1px solid var(--line2); border-radius: var(--r); padding: 5px 11px; cursor: pointer;
}
button:hover:not(:disabled), .btn:hover { border-color: var(--accent); color: var(--accent); }
button:disabled { opacity: .4; cursor: not-allowed; }
/* `.btn` is the same control drawn on an <a>: a link that leaves the page (the studio's
   "log ↗" into the capture catalog) is an anchor, not a button, and must still look like
   one rather than growing a second style beside it. */
button.small, .btn.small { padding: 2px 7px; font-size: var(--t-3xs); }
button.ghost, .btn.ghost { background: transparent; }
button.on, .btn.on { border-color: var(--accent); color: var(--accent); }
.btn { display: inline-block; text-decoration: none; }

input, select, textarea {
  font: inherit; font-size: var(--t-xs); color: var(--fg); background: var(--field);
  border: 1px solid var(--line2); border-radius: var(--r); padding: 5px 8px;
}
input:focus, select:focus, textarea:focus { border-color: var(--accent); outline: none; }
input::placeholder, textarea::placeholder { color: var(--faint); }
textarea { width: 100%; resize: vertical; font-family: inherit; }
/* Identifiers are typed the way they are spoken — A1 — and normalised on the way in. */
input.id { font-family: var(--mono); text-transform: lowercase; }
label.chk { display: inline-flex; align-items: center; gap: 6px; font-size: var(--t-2xs);
            color: var(--dim); cursor: pointer; }
label.chk input { accent-color: var(--amber); }

/* The one volume control (ui/volume.js). Above 100% is a real boost and says so. */
.vol { display: inline-flex; align-items: center; gap: 7px; color: var(--dim);
       font-size: var(--t-2xs); white-space: nowrap; }
.vol input[type=range] { width: 104px; accent-color: var(--amber); }
.vol b { color: var(--fg); font-weight: 400; font-variant-numeric: tabular-nums;
         min-width: 34px; text-align: right; }
.vol.boost b { color: var(--accent); }

/* The one theme switch (ui/theme.js). Three settings, because "follow the system" is a
   real answer and not the absence of one — a laptop that turns light at sunrise should
   take the console with it unless someone has said otherwise. Which one is in force is on
   the control, never in a tooltip. */
.theme { display: inline-flex; border: 1px solid var(--line2); border-radius: var(--r);
         overflow: hidden; }
.theme button { border: 0; border-radius: 0; background: transparent; padding: 4px 8px;
                font-size: var(--t-3xs); letter-spacing: .08em; color: var(--dim);
                min-height: 0; }
.theme button + button { border-left: 1px solid var(--line2); }
.theme button:hover:not(:disabled) { color: var(--fg); background: var(--hover); }
.theme button[aria-pressed="true"] { background: var(--amber); color: var(--on-accent); }

/* --- the small typed things ---------------------------------------------------------- */
.badge {
  display: inline-block; padding: 0 6px; font-size: var(--t-3xs); border: 1px solid var(--line2);
  border-radius: 3px; color: var(--dim); letter-spacing: .06em; white-space: nowrap;
}
.badge.gold { border-color: var(--accent); color: var(--accent); }
.badge.love { border-color: var(--love); color: var(--love); }
.badge.keep { border-color: var(--keep); color: var(--keep); }
.badge.meh  { color: var(--meh); }
.badge.kill { border-color: var(--kill); color: var(--kill); }
.tag { display: inline-block; padding: 0 5px; font-size: var(--t-3xs); letter-spacing: .08em;
       border: 1px solid var(--line2); border-radius: 2px; color: var(--dim); }
/* A content label names the class analyze.py assigned, so it is data and stays mono —
   but it is a chip in a narrow cell and may never wrap onto two lines. The fills do not
   follow the theme (tokens.css says why), so neither does the ink on them: the three dark
   ones carry --label-lift and the rest carry --on-accent, in both themes. */
.lbl { display: inline-block; padding: 0 6px; border-radius: 2px; font-size: .82em;
       color: var(--on-accent); font-family: var(--mono); letter-spacing: 0; white-space: nowrap; }
.lbl-voice { background: var(--voice); } .lbl-keyed-tone { background: var(--keyed); }
.lbl-morse { background: var(--morse); } .lbl-carrier { background: var(--carrier); }
.lbl-data { background: var(--data); } .lbl-noise { background: var(--noise); color: var(--label-lift); }
.lbl-mixed { background: var(--mixed); color: var(--label-lift); }
.lbl-silence { background: var(--silence); color: var(--label-lift); }

/* --- the containers ------------------------------------------------------------------ */
.card { border: 1px solid var(--line); background: var(--panel); border-radius: 6px; padding: 12px 14px; }
.card.gold { border-color: var(--accent); }
/* `tr.row` is a table row on the Reception Log and a flex container everywhere else. A
   shared stylesheet may not reach into a surface and break it, so this one excludes the
   element it cannot mean. Found by the site's capture table collapsing into a stack the
   first time ui/ was adopted. */
.row:not(tr) { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.row:not(tr) .sp { margin-left: auto; }
.grid2 { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }
.grid3 { display: grid; grid-template-columns: repeat(3, 1fr); gap: 14px; }
.empty { color: var(--faint); border: 1px dashed var(--line2); border-radius: 6px;
         padding: 18px; text-align: center; font-size: var(--t-xs); }

table { border-collapse: collapse; width: 100%; }
th { text-align: left; font-size: var(--t-3xs); color: var(--dim); font-weight: 600;
     border-bottom: 1px solid var(--line2); padding: 5px 8px; white-space: nowrap; }
td { padding: 5px 8px; border-bottom: 1px solid var(--line); vertical-align: top; }

footer.foot { border-top: 1px solid var(--line); margin-top: 32px;
              padding: 14px calc(20px + env(safe-area-inset-right, 0px))
                       calc(14px + env(safe-area-inset-bottom, 0px))
                       calc(20px + env(safe-area-inset-left, 0px));
              color: var(--faint); font-size: var(--t-2xs); }

@media (max-width: 760px) {
  .grid2, .grid3 { grid-template-columns: 1fr; }
  .top { --pad-x: 14px; --pad-y: 10px; gap: 12px; flex-wrap: wrap; }
  .top .crumb { display: none; }
  /* Six links do not fit across an iPhone SE. The header already wraps; the nav inside
     it has to as well, or one link hangs off the edge and takes the page with it. */
  .top nav { gap: 12px; row-gap: 6px; font-size: .78rem; flex-wrap: wrap; }
}

/* --- touch, and the shape of the screen -----------------------------------------------
 * A phone is not a narrow desktop. Three things break there that no `max-width` fixes,
 * and all three are solved once, here, because every surface shares this header, this
 * footer and these controls.
 *
 * THE NOTCH AND THE HOME INDICATOR. `viewport-fit=cover` — and iOS standalone mode, which
 * covers whether you ask or not — extends the page under the status bar and the home
 * indicator. The insets above are ADDED to the padding rather than replacing it, so a
 * screen without a notch, which is every desktop and where `env()` resolves to 0, looks
 * exactly as it did. The `, 0px` fallback is for a browser that does not know `env()` at
 * all: without it the whole declaration is dropped and the padding goes with it.
 *
 * TOUCH TARGETS. 12 px type in a 5 px box is a 22 px target. Apple and Google both say
 * 44. The question to ask is `(pointer: coarse)`, not the viewport width: a tablet in
 * landscape is wide and still operated with a thumb, and a small desktop window is narrow
 * and still has a mouse.
 *
 * THE FOCUS ZOOM. Safari on iOS zooms the page when a text field with type under 16 px
 * takes focus — and does not zoom back out afterwards, so one tap on a search box leaves
 * the reader scrolling a page one and a half times too wide. 16 px on touch is the entire
 * fix; there is no other one that does not disable pinch-zoom, which we will not do. */
@media (pointer: coarse) {
  button, .btn, select { min-height: 44px; }
  button.small, .btn.small { min-height: 40px; }
  /* `:not()` is not decoration: a surface's own `input { font-size: .85rem }` has the
     same specificity as a bare `input` here and, being loaded later, would win and bring
     the zoom back. This selector outranks it and stays one definition. */
  input:not([type=checkbox]):not([type=radio]), select, textarea { font-size: 16px; }
  input[type=checkbox], input[type=radio] { min-width: 22px; min-height: 22px; }
  input[type=range] { min-height: 32px; }
  /* The nav is the one place a 44 px box would look wrong — the header would double in
     height — so the targets are spaced instead of enlarged. */
  .top nav { gap: 20px; }
  .top nav a { padding: 6px 0; }
  /* ...and the theme switch, for the same reason: three segments at 44 px would be a
     second header. It is a 34 px target, spaced, and that is deliberate. */
  .theme button { min-height: 34px; padding: 4px 11px; }
}
