/* Seki Labs: fonts, tokens, the masthead, the pages and the search widget.
   The board (canvas.board) draws itself from the modules in /assets/board/;
   search.js builds the widget's bar, list panel and live region inside
   [data-search]. */

/* Redaction 20, the more worn cut, sets the wordmark and page titles;
   Redaction 10 sets running text and the search's page names. Redaction has
   no bold italic, so that one is synthesised. */
@font-face {
  font-family: "Redaction 20";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/assets/fonts/redaction-20-latin.woff2") format("woff2");
}
@font-face {
  font-family: "Redaction 10";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/assets/fonts/redaction-10-latin.woff2") format("woff2");
}
@font-face {
  font-family: "Redaction 10";
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url("/assets/fonts/redaction-10-italic-latin.woff2") format("woff2");
}
@font-face {
  font-family: "Redaction 10";
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url("/assets/fonts/redaction-10-bold-latin.woff2") format("woff2");
}
@font-face {
  font-family: "DM Mono";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/assets/fonts/dm-mono-latin.woff2") format("woff2");
}

:root {
  color-scheme: light;
  --text: #000;
  --surface: #fff;
  --menu: #fff;
  --muted: #636363;   /* 4.5:1 or more on #fff and the selected row */
  --selected: rgba(0, 0, 0, .05);
  --rule: #000;       /* the search's square edge */
  --focus: #767676;   /* 3:1 or more against the page */
  --serif: "Redaction 10", "Iowan Old Style", Georgia, serif;
  --display: "Redaction 20", "Iowan Old Style", Georgia, serif;
  --mono: "DM Mono", ui-monospace, "SFMono-Regular", Menlo, monospace;
  --header: 68px;
  --edge: 24px;
  --control-h: 30px;
  --mono-size: 12px;
  --mark-size: 26px;
  --bar-w: min(320px, calc(100vw - 2 * var(--edge)));
}
@media (min-width: 1360px) {
  :root { --edge: 36px; }
}
@media (max-width: 599px) {
  :root {
    --edge: 16px;
    --control-h: 34px;
    --mono-size: 14px;
    --mark-size: 21px;
  }
}

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

html {
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
}
body {
  margin: 0;
  background: var(--surface);
  color: var(--text);
  font-family: var(--serif);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  -webkit-tap-highlight-color: transparent;
}

/* Home: one screen, never a scroll. Two rules, because a selector list that
   contains :has() is dropped whole by a browser without it. */
.home {
  height: 100vh;
  height: 100dvh;
  overflow: hidden;
  overscroll-behavior: none;
}
html:has(> body.home) {
  height: 100vh;
  height: 100dvh;
  overflow: hidden;
  overscroll-behavior: none;
}
.board {
  position: fixed;
  inset: 0;
  z-index: 0;
  display: block;
  width: 100%;
  height: 100%;
  pointer-events: none;
}
/* A live stone takes a click: board/pointer.js sets the class while a mouse
   or pen is over one. */
.home.on-stone { cursor: pointer; }

/* Masthead: the wordmark, centred in a 68px band. */
.masthead {
  position: absolute;
  inset: 0 0 auto;
  z-index: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  height: calc(var(--header) + env(safe-area-inset-top, 0px));
  padding-top: env(safe-area-inset-top, 0px);
}
.mark {
  margin: 0;
  font: 400 var(--mark-size)/1 var(--display);
  letter-spacing: -0.01em;
  white-space: nowrap;
}
.mark a, a.mark {
  color: inherit;
  text-decoration: none;
}
.masthead a:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 4px;
  border-radius: 2px;
}

/* Every page but home (build.mjs writes them from copy.md, and the 404):
   an ordinary document under the masthead. */
.content {
  box-sizing: content-box;
  max-width: 36rem;
  margin: 0 auto;
  overflow-wrap: break-word;
  padding:
    calc(var(--header) + env(safe-area-inset-top, 0px) + 48px)
    clamp(16px, 4vw, 24px)
    calc(var(--edge) + var(--control-h) + 48px + env(safe-area-inset-bottom, 0px));
}
.page-title {
  margin: 0;
  font: 400 20px/1.3 var(--display);
}
.content p {
  margin: 1em 0 0;
  font: 400 17px/1.6 var(--serif);
  text-wrap: pretty;
}
.page-title + p { margin-top: 24px; }
.content a {
  color: inherit;
  text-decoration-line: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.2em;
}
.content a:hover { text-decoration-thickness: 2px; }
.content a:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 2px;
  border-radius: 2px;
}

/* Search. Closed, the widget is the pill; open, it is the bar, with the list
   panel floating above it. Each is a white box with square corners and a
   1px edge. .search always has the footprint of what is shown (pill or bar)
   so the board can keep its stones clear of it. */
.search {
  position: fixed;
  left: 0;
  right: 0;
  bottom: calc(var(--edge) + max(env(safe-area-inset-bottom, 0px), var(--kb, 0px)));
  z-index: 2;
  width: max-content;
  height: var(--control-h);
  margin-inline: auto;
  font: 400 var(--mono-size)/1.25 var(--mono);
  letter-spacing: .02em;
}
.search.is-open { width: var(--bar-w); }

.search-pill {
  position: relative;
  z-index: 1;
  display: block;
  width: max-content;
  height: var(--control-h);
  margin: 0 auto;
  padding: 0 12px;
  border: 0;
  background: none;
  color: var(--text);
  font: inherit;
  letter-spacing: inherit;
  white-space: nowrap;
  cursor: pointer;
}
/* The pill's surface sits on a pseudo-element so it can vanish under the bar
   without a transition flashing at either end of the morph. Hovered, its
   edge doubles inward; pressed, it takes the selected row's tint. */
.search-pill::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  border: 1px solid var(--rule);
  background: var(--menu);
  transition: box-shadow .15s ease;
}
.search-pill:hover::before,
.search-pill:focus-visible::before { box-shadow: inset 0 0 0 1px var(--rule); }
.search-pill:active::before { background: var(--selected); }
.search-pill:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 2px;
}
.search.is-active .search-pill::before { visibility: hidden; }
.search.is-open .search-pill { pointer-events: none; }

.search-bar {
  position: absolute;
  bottom: 0;
  left: 50%;
  z-index: 0;
  display: flex;
  align-items: center;
  gap: 12px;
  width: var(--bar-w);
  height: var(--control-h);
  margin-left: calc(var(--bar-w) / -2);
  padding: 0 12px;
  background: var(--menu);
}
/* The bar's edge lies inside the morph's clip (search.js sets --dx), so the
   whole box opens out from the pill's footprint. */
.search-bar::after {
  content: "";
  position: absolute;
  inset: 0 var(--dx, 0px);
  border: 1px solid var(--rule);
  pointer-events: none;
}
.search-input {
  flex: 1 1 auto;
  min-width: 0;
  height: 100%;
  margin: 0;
  padding: 0;
  border: 0;
  border-radius: 0;
  outline: 0;
  background: transparent;
  color: var(--text);
  font: inherit;
  letter-spacing: inherit;
  caret-color: var(--text);
  -webkit-appearance: none;
  appearance: none;
}
.search-input::placeholder {
  color: var(--muted);
  opacity: 1;
}
.search-hint {
  flex: none;
  color: var(--muted);
}

.search-panel {
  position: absolute;
  bottom: calc(100% + 8px);
  left: 50%;
  width: var(--bar-w);
  margin-left: calc(var(--bar-w) / -2);
  padding: 4px;
  border: 1px solid var(--rule);
  background: var(--menu);
}
.search-bar[hidden],
.search-panel[hidden],
.search-list[hidden],
.search-empty[hidden] { display: none; }
/* --room: what search.js measures is left above the bar (a landscape phone
   with its keyboard up); past that the list scrolls. */
.search-list {
  max-height: min(50vh, 20rem, var(--room, 20rem));
  margin: 0;
  padding: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  list-style: none;
}
.search-option {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 16px;
  padding: 7px 10px 8px;
  cursor: pointer;
}
/* The active option: the pale fill, and a bar in the text colour on its left
   edge, which is what reaches 3:1. */
.search-option[aria-selected="true"] {
  background: var(--selected);
  box-shadow: inset 2px 0 0 var(--text);
}
.search-label {
  font: 400 16px/1.25 var(--serif);
  letter-spacing: 0;
}
.search-path { color: var(--muted); }
.search-empty {
  margin: 0;
  padding: 8px 10px;
  color: var(--muted);
}

/* Touch: no keys to name, and no zoom on focus. */
@media (hover: none) and (pointer: coarse) {
  .search-input { font-size: 16px; }
  .search-hint { display: none; }
  .search-pill > span { display: none; }
}
@media (pointer: coarse) {
  .search-option {
    min-height: 44px;
    padding-block: 12px;
  }
}

/* Forced colours drop every background: the controls keep their edges, in
   system colours, and the active option gets one. */
@media (forced-colors: active) {
  .search-option[aria-selected="true"] { outline: 2px solid Highlight; outline-offset: -2px; }
  .search-pill:focus-visible { outline: 2px solid Highlight; }
}

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}
