/* Free Trader: black, white and greys; the map is the page, the market a panel over it.
 * Chrome follows the minimal family brief (docs/design/minimal-brief.md). */

@font-face { font-family: "Plex Mono"; font-style: normal; font-weight: 500; font-display: swap; src: url("./fonts/IBMPlexMono-500.woff2") format("woff2"); }
@font-face { font-family: "Plex Sans"; font-style: normal; font-weight: 400; font-display: swap; src: url("./fonts/IBMPlexSans-400.woff2") format("woff2"); }

:root {
  color-scheme: light;
  --bg: #ffffff; --ink: #000000; --text: #111111; --sub: #5e5e5e; --line: #d4d4d4; --guide: #8f8f8f; --frame: #1c1c1c;
  --band: rgba(0, 0, 0, .05); --scrim: rgba(255, 255, 255, .84);
  --mono: "Plex Mono", ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  --sans: "Plex Sans", system-ui, -apple-system, "Segoe UI", sans-serif;
  --top: 44px; --bar: 60px; --rail: 0px;
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) { color-scheme: dark; --bg: #000000; --ink: #ffffff; --text: #ededed; --sub: #a6a6a6; --line: #2f2f2f; --guide: #8f8f8f; --frame: #ededed; --band: rgba(255, 255, 255, .06); --scrim: rgba(0, 0, 0, .8); }
}
:root[data-theme="dark"] { color-scheme: dark; --bg: #000000; --ink: #ffffff; --text: #ededed; --sub: #a6a6a6; --line: #2f2f2f; --guide: #8f8f8f; --frame: #ededed; --band: rgba(255, 255, 255, .06); --scrim: rgba(0, 0, 0, .8); }

*, *::before, *::after { box-sizing: border-box; }
html, body { margin: 0; height: 100%; overflow: hidden; background: var(--bg); color: var(--text); font-family: var(--sans); -webkit-text-size-adjust: 100%; -webkit-tap-highlight-color: transparent; }
.sr-only { position: absolute !important; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0; }
button { font: inherit; color: inherit; }

/* ---------- readout and strip ---------- */
.hud {
  position: fixed; top: max(6px, env(safe-area-inset-top)); left: 50%; transform: translateX(-50%); z-index: 5;
  display: flex; align-items: center; gap: .45em; height: 32px; max-width: calc(100vw - 16px);
  font: 500 13px/1 var(--mono); letter-spacing: .02em; font-variant-numeric: tabular-nums; color: var(--sub); white-space: nowrap;
}
.hud .dot { color: var(--line); }
@media (max-width: 359px) { .hud { font-size: 11px; letter-spacing: 0; gap: .35em; } }
.hud .warn { color: var(--text); }
.strip {
  position: fixed; top: calc(max(6px, env(safe-area-inset-top)) + 32px); left: 16px; right: 16px; z-index: 4; margin: 0;
  text-align: center; font: 400 15px/1.3 var(--sans); color: var(--text); min-height: 1.3em; pointer-events: none;
  transition: opacity .18s;
}
.strip:empty { opacity: 0; }

/* ---------- map: the whole page between the readout and the bar ---------- */
.map {
  position: fixed; top: calc(max(6px, env(safe-area-inset-top)) + 32px + 24px); bottom: calc(var(--bar) + env(safe-area-inset-bottom));
  left: max(8px, env(safe-area-inset-left)); right: max(8px, env(safe-area-inset-right));
  container-type: size; user-select: none; -webkit-user-select: none; touch-action: manipulation;
}
/* Labels hang outside the node field, so the field keeps a margin for them.
 * The ports sit on a hexagon, so the field keeps near its shape on any screen. */
.field { position: absolute; inset: 12px 72px 40px 72px; margin: auto; max-width: calc(115cqh - 60px); max-height: calc(160cqw - 230px); }
#lanes { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; }
#lanes line { stroke: var(--line); stroke-width: 1; vector-effect: non-scaling-stroke; transition: stroke .3s; }
#lanes line.near { stroke: var(--ink); }
#lanes line.closed { stroke-dasharray: 3 4; stroke: var(--guide); }
.lane-label {
  position: absolute; transform: translate(-50%, -50%); padding: 1px 4px; background: var(--bg);
  font: 500 11px/1 var(--mono); font-variant-numeric: tabular-nums; color: var(--sub); pointer-events: none; transition: color .3s;
}
.lane-label.near { color: var(--text); }
.lane-label.closed { text-decoration: line-through; }
.node { position: absolute; width: 10px; height: 10px; margin: -5px 0 0 -5px; border: 1.5px solid var(--guide); background: var(--bg); transition: transform .3s, border-color .3s, opacity .3s; }
.node.near { border-color: var(--text); }
.node.here { opacity: 0; }
.port {
  position: absolute; display: grid; gap: 3px; min-width: 44px; min-height: 44px; padding: 4px 6px;
  border: 0; border-radius: 0; background: none; color: var(--sub); cursor: pointer; touch-action: manipulation;
  font: 500 12px/1.2 var(--mono); letter-spacing: .02em; white-space: nowrap; transition: color .3s;
}
.port[data-side="right"] { transform: translate(8px, -50%); justify-items: start; text-align: left; }
.port[data-side="left"] { transform: translate(calc(-100% - 8px), -50%); justify-items: end; text-align: right; }
.port[data-side="above"] { transform: translate(-50%, calc(-100% - 6px)); justify-items: center; align-content: end; }
.port[data-side="below"] { transform: translate(-50%, 8px); justify-items: center; }
.port[data-side="corner"] { transform: translate(10px, 2px); justify-items: start; text-align: left; }
.port.near { color: var(--text); }
.port.here { color: var(--ink); }
/* your port opens its market: its name is underlined like a link */
.port.here span:first-of-type { text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: 3px; }
.port .sub { color: var(--sub); font-size: 10px; letter-spacing: 0; }
.port .sub:empty, .port .ev:empty { display: none; }
.port .ev { color: var(--text); font-size: 10px; }
.port.job span:first-of-type::before { content: "▸ "; }
.node.pulse { animation: pulse .65s ease-in-out 2; }
@keyframes pulse { 50% { transform: scale(1.8); } }
.ship { position: absolute; left: 0; top: 0; width: 18px; height: 18px; margin: -9px 0 0 -9px; color: var(--ink); pointer-events: none; transition: transform .7s cubic-bezier(.3, .7, .2, 1); }
.ship svg { width: 100%; height: 100%; }
.ship.instant { transition: none; }

/* ---------- market panel: the port's market and jobs, over the map ---------- */
.panel-readout { margin: 0 0 8px; text-align: right; font: 500 13px/1 var(--mono); letter-spacing: .02em; font-variant-numeric: tabular-nums; color: var(--sub); }
.market { width: 100%; border-collapse: collapse; font: 500 13px/1 var(--mono); letter-spacing: .02em; font-variant-numeric: tabular-nums; }
.market th, .market td { padding: 0 6px; height: 44px; text-align: right; font-weight: inherit; white-space: nowrap; }
.market th:first-child, .market td:first-child { text-align: left; padding-left: 4px; }
.market thead th { height: 28px; color: var(--sub); }
.market tbody th { color: var(--text); }
.market td { color: var(--text); }
.market td.have { color: var(--sub); }
.market td.have.has { color: var(--text); }
.market td.up::after { content: " ▲"; } .market td.down::after { content: " ▼"; }
.market .acts { padding: 0; width: 1%; text-align: right; }
.tb {
  appearance: none; display: inline-grid; place-items: center; min-width: 44px; height: 44px; padding: 0 10px; border: 0; border-radius: 0; background: none; color: var(--text);
  font: 500 15px/1 var(--mono); cursor: pointer; touch-action: manipulation; transition: opacity .15s, transform .1s;
}
.tb:active { transform: scale(.94); }
.tb:disabled { opacity: .3; cursor: default; }
.tb.text { font-size: 13px; letter-spacing: .02em; }
@media (max-width: 359px) { .panel .market th, .panel .market td { padding: 0 3px; } .panel .tb { padding: 0; } .panel .sheet-body { padding: 12px; } }
.jobs { display: grid; margin-top: 12px; padding-top: 8px; border-top: 1px solid var(--line); font: 500 13px/1.3 var(--mono); letter-spacing: .02em; font-variant-numeric: tabular-nums; }
.job { display: flex; align-items: center; justify-content: space-between; gap: 8px; min-height: 44px; padding: 2px 0 2px 4px; color: var(--sub); }
.job .what, .job .to { color: var(--text); }
.job .pay, .job .due { font-size: 12px; }
.job .bonus::before { content: "+ "; }
.job.held { color: var(--text); }
.jobs:empty { display: none; }
@media (hover: hover) { .tb:hover:not(:disabled), .port:hover:not(.here) { background: var(--band); } }
.port:disabled { cursor: default; }

/* ---------- corner icons ---------- */
.bar { position: fixed; left: max(6px, env(safe-area-inset-left)); right: max(6px, env(safe-area-inset-right)); bottom: max(6px, env(safe-area-inset-bottom)); z-index: 5; display: flex; justify-content: space-between; align-items: flex-end; pointer-events: none; }
.group { display: flex; gap: 2px; pointer-events: auto; }
.ib { appearance: none; display: grid; place-items: center; width: 48px; height: 48px; padding: 0; border: 0; border-radius: 0; background: none; color: var(--text); cursor: pointer; touch-action: manipulation; transition: opacity .15s, transform .1s; }
.ib svg { width: 24px; height: 24px; }
.ib:active { transform: scale(.94); }
.ib[aria-disabled="true"] { opacity: .32; cursor: default; }
@media (hover: hover) { .ib:hover:not([aria-disabled="true"]) { background: var(--band); } }
.ib:focus-visible, .tb:focus-visible, .port:focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; }

/* ---------- wide: more room for labels ---------- */
@media (min-width: 820px) and (min-height: 501px) {
  .map { left: max(24px, env(safe-area-inset-left)); right: max(24px, env(safe-area-inset-right)); }
  .field { inset: 24px 110px 48px 110px; }
  .port { font-size: 13px; }
}
/* Landscape phones: the bar becomes a right rail. */
@media (max-height: 500px) and (orientation: landscape) {
  .map { top: calc(max(6px, env(safe-area-inset-top)) + 32px + 22px); bottom: max(8px, env(safe-area-inset-bottom)); right: calc(64px + env(safe-area-inset-right)); }
  .field { inset: 10px 80px 36px 80px; }
  .bar { left: auto; right: 0; top: 0; bottom: 0; width: calc(64px + env(safe-area-inset-right)); flex-direction: column; justify-content: space-between; align-items: center; padding: env(safe-area-inset-top) env(safe-area-inset-right) env(safe-area-inset-bottom) 0; }
  .group { flex-direction: column; }
  .strip { left: 80px; right: 80px; }
}

/* ---------- sheets ----------
 * The minimal family sheet (docs/design/minimal-brief.md, Notan's sheet).
 * This block is byte-identical in every game that uses it; game-specific
 * help content goes below it. */
dialog.sheet { width: min(32rem, calc(100vw - 16px)); max-width: none; max-height: calc(100dvh - 16px - env(safe-area-inset-top) - env(safe-area-inset-bottom)); height: fit-content; padding: 0; margin: auto; border: 1px solid var(--frame); border-radius: 0; background: var(--bg); color: var(--text); overflow: hidden; }
dialog.sheet[open] { display: block; }
dialog.sheet::backdrop { background: var(--scrim); }
.sheet-in { max-height: calc(100dvh - 18px - env(safe-area-inset-top) - env(safe-area-inset-bottom)); display: flex; flex-direction: column; min-height: 0; width: 100%; font: 400 16px/1.45 var(--sans); }
.sheet-head { display: flex; flex: none; align-items: center; justify-content: space-between; gap: 12px; padding: 8px 16px; border-bottom: 1px solid var(--line); }
.sheet-head form { margin: 0; }
.sheet h2 { margin: 0; font: 500 16px/1.3 var(--mono); }
.sheet-x { display: grid; place-items: center; width: 44px; height: 44px; padding: 0; border: 0; border-radius: 0; background: none; color: var(--text); cursor: pointer; }
.sheet-x svg { width: 24px; height: 24px; }
.sheet-body { min-height: 0; overflow: auto; overscroll-behavior: contain; padding: 20px 24px; scroll-padding: 12px; }
.sheet p { margin: 0 0 16px; max-width: 60ch; }
.sheet h3 { margin: 0 0 8px; font: 500 1em/1.4 var(--sans); }
.sheet section + section { border-top: 1px solid var(--line); margin-top: 20px; padding-top: 20px; }
.text-action { appearance: none; min-width: 44px; min-height: 44px; padding: 8px 12px; border: 1px solid var(--line); border-radius: 0; background: none; color: var(--text); font: 500 16px/1.3 var(--mono); cursor: pointer; touch-action: manipulation; }
.text-action:disabled { opacity: .45; cursor: default; }
@media (hover: hover) { .text-action:hover:not(:disabled) { background: var(--band); } }
.sheet :is(button, a):focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; }
/* Settings: plain rows, a label on the left and a value or an action on the right. */
.setting-row { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 8px 16px; min-height: 44px; }
.setting-row + .setting-row { margin-top: 8px; }
.setting-row > :last-child { margin-left: auto; }
.row-actions { display: flex; flex-wrap: wrap; gap: 4px; }
.setting-value { padding: 0 13px; font: 500 16px/1.3 var(--mono); font-variant-numeric: tabular-nums; color: var(--sub); }
/* Help: controls at a glance, one per line. */
.controls { margin: 16px 0 0; padding-top: 12px; border-top: 1px solid var(--line); display: grid; gap: 6px; }
/* A line reads as one sentence and wraps as one, never splitting the key from what it does. */
.controls dt, .controls dd { display: inline; }
.controls dt { color: var(--text); }
.controls dt::after { content: " \2014"; margin-right: .3em; color: var(--sub); }
.controls dd { margin: 0; color: var(--sub); }
.controls dt > :is(svg, span) { vertical-align: -3px; }
/* Lessons: a heading with a count, a task, the practice, feedback, Back and Next. */
.lesson { padding-top: 4px; }
.lesson-heading { display: flex; justify-content: space-between; align-items: baseline; gap: 12px; }
.lesson-count { color: var(--sub); white-space: nowrap; }
.lesson-task { margin: 0 0 16px; }
.lesson-feedback { margin: 8px 0 10px; color: var(--sub); text-align: center; }
.lesson-nav { display: flex; justify-content: space-between; flex-wrap: wrap; gap: 8px; }
/* A sheet never changes height while it is open: every text that can change
 * sits in one grid cell with all of its alternatives, the others hidden. */
.stack { display: grid; }
.sheet .stack > * { grid-area: 1 / 1; margin: 0; }
.stack > .alt { visibility: hidden; }
.sheet-foot { border-top: 1px solid var(--line); padding-top: 12px; margin-top: 20px; }
.foot-btn { display: inline-flex; align-items: center; min-height: 44px; font: 400 16px/1.4 var(--sans); color: var(--sub); text-underline-offset: 3px; }
@media (max-width: 480px) { .sheet-body { padding: 16px; } .sheet-head { padding: 8px 12px; } }
/* ---------- end sheets ---------- */
/* Free Trader's lesson: a two-port map and a one-row market, the same parts as the game. */
.practice { display: grid; gap: 8px; }
.practice-map { position: relative; height: 96px; }
.practice-map svg { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; }
.practice-map line { stroke: var(--ink); stroke-width: 1; vector-effect: non-scaling-stroke; }
.practice .market { border-top: 1px solid var(--line); }
.practice-readout { margin: 0; text-align: right; font: 500 13px/1 var(--mono); letter-spacing: .02em; font-variant-numeric: tabular-nums; color: var(--sub); }

@media (prefers-reduced-motion: reduce) { *, *::before, *::after { transition: none !important; animation: none !important; } }
@media (forced-colors: active) { :root { --ink: CanvasText; --text: CanvasText; --bg: Canvas; --line: GrayText; --guide: GrayText; --frame: CanvasText; --sub: GrayText; } .port i, .ship { forced-color-adjust: none; } }
