/* One font (Arial) at one size everywhere — no breakpoint changes it, and
   the SITE ANALYST header is the only thing set larger. Square boxes and
   hairline rules — the page reads
   like a drawing sheet's title block rather than a website. Colour does the
   work of hierarchy: yellow marks what is chosen or what to press, the tinted
   first column names each row of options. */

:root {
  --bg:    #ffffff;
  --ink:   #000000;
  --line:  #000000;
  --hi:    #ffff70;   /* selected option, primary button */
  --on-hi: #000000;   /* the highlight stays light in both themes, so what
                         sits on it stays dark — never --ink */
  --head:  #c6e7cf;   /* the options table's label column */
  --muted: #5a5a5a;
  --err:   #c0392b;
  --font: Arial, Helvetica, "Helvetica Neue", sans-serif;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --bg: #111111; --ink: #f2f2f2; --line: #f2f2f2;
    --hi: #d8d84a; --head: #3f6b4c; --muted: #a9a9a9; --err: #f08b7d;
    /* --on-hi is deliberately not redefined: the highlight is light here too. */
  }
}

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

body {
  background: var(--bg);
  color: var(--ink);
  font-family: var(--font);
  font-size: 17px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  padding: 2.6rem 1.5rem 3rem;
}

.page { max-width: 760px; margin: 0 auto; }

a { color: inherit; }

/* ---- masthead ----------------------------------------------------------- */
.name {
  /* About twice the body text, as on the reference — it was three times,
     which made the masthead the loudest thing on a page of small print. */
  font-size: 2.3rem; font-weight: 400; line-height: 1.05;
  letter-spacing: -.01em; margin-bottom: 4.7rem;
}
.lead { margin-bottom: 1.9rem; }

/* ---- address bar -------------------------------------------------------- */
/* Input and button are one rectangle split in two: the button carries the
   left rule so the pair never shows a doubled line between them. */
.bar { display: flex; border: 1px solid var(--line); margin-bottom: 4.15rem; }
.entry { position: relative; flex: 1; min-width: 0; display: flex; }

.bar input {
  font: inherit; color: var(--ink); background: transparent;
  border: 0; width: 100%; padding: .75rem 1rem;
}
.bar input:focus { outline: 0; }
.bar input::placeholder { color: var(--muted); }
.bar:focus-within { box-shadow: 0 0 0 1px var(--line); }

.go {
  flex: none; font: inherit; font-weight: 700; letter-spacing: .02em;
  color: var(--on-hi); background: var(--hi);
  border: 0; border-left: 1px solid var(--line);
  /* One column of the options table, so the bar and the table share edges. */
  flex: 0 0 25%;
  padding: .75rem 1rem; cursor: pointer;
}
.go:hover { filter: brightness(.95); }
.go:disabled { background: transparent; color: var(--muted); cursor: wait; }

/* ---- options table ------------------------------------------------------ */
/* Cells carry their own right and bottom rule and the table carries the top
   and left, so no line is ever drawn twice. */
.opts { border-top: 1px solid var(--line); border-left: 1px solid var(--line); }
.row { display: flex; }
/* [hidden] sets display:none, but an explicit display wins over it — so the
   hidden state has to be spelled out for a flex row. */
.row[hidden] { display: none; }

.rowhead, .cell, .cell-empty {
  /* All four sides, not just the two that draw: a <button> keeps the
     browser's 2px outset border on any side left unspecified, which drew
     every cell's top and left rule at double width in grey. */
  border: 0 solid var(--line);
  border-right-width: 1px;
  border-bottom-width: 1px;
  padding: .6rem 1rem;
  font-weight: 700; letter-spacing: .02em; text-transform: uppercase;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.rowhead { flex: 0 0 25%; background: var(--head); }
.cells { flex: 1; display: flex; min-width: 0; }
.cell, .cell-empty { flex: 1 1 0; min-width: 0; }

.cell {
  font-family: inherit; font-size: inherit; text-align: left;
  color: var(--ink); background: transparent; cursor: pointer;
}
.cell:hover { background: rgba(0,0,0,.05); }
.cell[aria-pressed="true"] { background: var(--hi); color: var(--on-hi); }
.cell[aria-pressed="true"]:hover { background: var(--hi); filter: brightness(.95); }
.cell:focus-visible { outline: 2px solid var(--line); outline-offset: -3px; }

/* ---- suggestions -------------------------------------------------------- */
#suggest {
  position: absolute; left: -1px; right: -1px; top: calc(100% + 1px);
  z-index: 10; list-style: none; background: var(--bg);
  border: 1px solid var(--line); max-height: 17rem; overflow-y: auto;
  display: none;
}
#suggest.open { display: block; }
#suggest li { padding: .4rem 1rem; cursor: pointer;
              white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
#suggest li:hover, #suggest li.active { background: var(--hi); color: var(--on-hi); }

/* ---- output ------------------------------------------------------------- */
#out { margin-top: .9rem; border: 1px solid var(--line); padding: 1rem 1.2rem;
       min-height: 11rem; }
#queue { text-transform: uppercase; font-weight: 700; }
#log { white-space: pre-wrap; max-height: 16rem; overflow-y: auto; }
.errline { color: var(--err); }

/* ---- bottom actions ----------------------------------------------------- */
.actions { display: flex; justify-content: space-between; align-items: flex-start;
           gap: 1rem; margin-top: .9rem; }
#links { display: flex; }
.btn {
  display: inline-block; border: 1px solid var(--line); padding: .45rem 1.4rem;
  font-weight: 700; letter-spacing: .02em; text-transform: uppercase;
  text-decoration: none; color: var(--ink); background: transparent;
  white-space: nowrap;
}
#links .btn + .btn { border-left: 0; }
.btn:hover { background: rgba(0,0,0,.05); }
.btn.primary { background: var(--hi); color: var(--on-hi); }
.btn.primary:hover { background: var(--hi); filter: brightness(.95); }

footer { margin-top: 3rem; color: var(--muted); }
footer a { color: inherit; }

/* ---- hover preview ------------------------------------------------------ */
#preview {
  position: fixed; z-index: 30; pointer-events: none; display: none;
  border: 1px solid var(--line); background: var(--bg);
  padding: 5px; width: min(46vw, 560px);
}
#preview.on { display: block; }
#preview img { display: block; width: 100%; height: auto; }
#preview .cap { padding: .35rem .2rem 0; }

@media (max-width: 700px) {
  body { padding: 1.6rem 1rem 2.5rem; }
  .name { margin-bottom: 2.2rem; }
  .bar { margin-bottom: 2rem; }
  .rowhead { flex: 0 0 30%; }
  .rowhead, .cell, .cell-empty { padding: .5rem .6rem; }
  .go { padding: .75rem 1rem; }
  .actions { flex-direction: column; align-items: stretch; }
  .actions .btn { text-align: center; }
  #preview { width: 92vw; }
}

/* On a phone the label column would leave the options too narrow to hold
   their words — SUMMARY and NEUTRAL both clip — so the label becomes a strip
   above its own row of options and each option gets the full width. */
@media (max-width: 560px) {
  .row { flex-direction: column; }
  .rowhead { flex: none; }
  /* the site sheet offers six scales; they have to share one phone width */
  .cell, .cell-empty { padding: .5rem .35rem; letter-spacing: 0; }
}

/* ---- about page --------------------------------------------------------- */
/* The same hairline table as the options, but the second column carries
   sentences, so it wraps and the row grows to fit. */
.masthead { display: flex; justify-content: space-between; align-items: flex-start;
            gap: 1rem; margin-bottom: 2.6rem; }
.masthead .name { margin-bottom: 0; }
.name a { text-decoration: none; }

h2 { font-size: 1em; font-weight: 700; text-transform: uppercase;
     letter-spacing: .02em; margin: 2.6rem 0 .8rem; }

/* One grid rather than a stack of independent rows, so `grid-auto-rows: 1fr`
   can size every row to the tallest one: the boxes all come out the same
   height and a short entry simply gets more room around it. `display:
   contents` dissolves the row wrappers so the cells are the grid's own items.
   The cells still stretch — the label column's fill has to reach the rules —
   so each one centres its own text instead. */
/* Every box on the page is the same height, across all three tables. CSS can
   equalise rows within one grid but not between separate ones, so the height
   is stated instead of derived: the tallest entry on the page runs to --rows
   lines, and every row is given that. Written in lines rather than pixels so
   it follows the type — and as a minimum, so a longer entry added later grows
   its row rather than being clipped. The trailing 1px is the cell's own
   bottom border, which sits inside its border-box height. Measured: the
   tallest entry is three lines from about 740px up, four below that, where
   the longest paragraph is pushed onto another line. */
.deftable {
  --rows: 3;
  --cell-pad-y: .6rem;
  display: grid;
  /* Wide enough for OPENSTREETMAP, the longest label, to stay on one line. */
  grid-template-columns: 28% 1fr;
  grid-auto-rows: minmax(calc(var(--rows) * 1.5em + 2 * var(--cell-pad-y) + 1px), auto);
  border-top: 1px solid var(--line);
  border-left: 1px solid var(--line);
}
.deftable .row { display: contents; }
.deftable .k, .deftable .v {
  border-right: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
  padding: var(--cell-pad-y) 1rem;
  min-width: 0; overflow-wrap: anywhere;
}
.deftable .k {
  background: var(--head);
  font-weight: 700; text-transform: uppercase; letter-spacing: .02em;
}

/* Just above the padding breakpoint the type is still full size while the
   page is narrow, and the longest paragraph takes a fourth line — so the
   four-line band reaches higher than that breakpoint does. It has to sit
   after the rule it overrides: both are one class deep, so source order
   decides. Measured at this type size: three lines from about 760px up,
   four down to 600, five below that until the table stacks. */
@media (max-width: 760px) {
  .deftable { --rows: 4; }
}
@media (max-width: 600px) {
  .deftable { --rows: 5; }
}

@media (max-width: 700px) {
  .deftable { grid-template-columns: 34% 1fr; --cell-pad-y: .5rem; }
  .deftable .k, .deftable .v { padding: var(--cell-pad-y) .6rem; }
}

/* On a phone a label column wide enough for OPENSTREETMAP leaves the
   sentences in a gutter, and matching every box to the tallest one costs
   screens of empty space. The label becomes a strip above its own text, the
   way the options table does, and rows go back to fitting their content. */
@media (max-width: 560px) {
  /* Stacked, so a label strip and a paragraph are different kinds of box and
     a shared height would only add empty screens. */
  .deftable { grid-template-columns: 1fr; grid-auto-rows: auto; }
  /* The button cannot wrap its own words, so beside the title it pushes the
     page wider than the screen; below the title it simply fits. */
  .masthead { flex-direction: column; align-items: stretch; }
  .masthead .btn { text-align: center; }
}

/* Narrowest phones: six scale options cannot share 288px without clipping
   "auto", so the row wraps onto a second line of cells instead. */
@media (max-width: 380px) {
  /* At one type size for every screen, SUMMARY no longer fits a third of a
     320px phone. Take the room out of the margins rather than the type. */
  body { padding-left: .6rem; padding-right: .6rem; }
  .cells { flex-wrap: wrap; }
  .cell, .cell-empty { flex: 1 0 30%; padding: .5rem .3rem; }
}

/* Narrower than any phone but the folded ones: two options to a line. */
@media (max-width: 315px) {
  .cell, .cell-empty { flex: 1 0 45%; }
}

/* A note in the suggestion list — searching, no match, or what to type.
   Reads as guidance, not as something to pick. */
#suggest li.hint { color: var(--muted); cursor: default; }
#suggest li.hint:hover { background: transparent; color: var(--muted); }
