/* Paper and ink are the chart's, verbatim — CHART_PAPER and CHART_INK in
   map.js. Keep them in step: the canvas sits inside these panels, and any
   drift between the two whites shows up as a seam around the map.
   There is nothing between them. Where the panel used to reach for a grey it
   now reaches for a smaller size, uppercase, or a rule underneath. */
:root {
  --paper: #f4ede4;
  --ink: #3a3530;

  /* Blue is SHIP_COLOR in map.js, and it means the same thing here: the ship,
     its name and its hold. Orange is the station it's docked at. Station
     squares on the map also carry a muted per-type colour, below —
     deliberately quieter than these two so ship/docked stay the bold
     signals. */
  --blue: #3b82f6;
  --orange: #f97316;
  --red: #ef4444;
  --green: #22c55e;

  /* Station-type colours. The only definition of these four — map.js reads
     them via getComputedStyle() into STATION_TYPE_COLORS once at load, so
     the map square and the galactic market's icon always match. */
  --type-extraction: #b7791f;
  --type-refinery: #9a3412;
  --type-agriculture: #6b8e4e;
  --type-industrial: #57616b;

  /* Star-type colours. The only definition of these three — map.js reads
     them via getComputedStyle() into STAR_TYPE_COLORS once at load, the same
     way STATION_TYPE_COLORS reads --type-* above. */
  --star-yellow: #eab308;
  --star-red: #dc2626;
  --star-blue: #0ea5e9;

  --font-serif: Georgia, 'Times New Roman', serif;
  --font-mono: 'Courier New', ui-monospace, Menlo, Consolas, monospace;

  /* A 0.5px hairline everywhere. The 1px weight only ever closes a region. */
  --rule: 0.5px solid var(--ink);
  --rule-major: 1px solid var(--ink);
  --transition-fast: all 0.15s;
}

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

body {
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font-serif);
  /* dvh tracks the mobile browser's collapsing URL bar; vh does not, and the
     market ends up clipped below the fold. vh first as the fallback. */
  height: 100vh;
  height: 100dvh;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  font-size: 13px;
}

/* Every row the header takes is a row the map and market don't get, so it
   stays as tight as it can while still wrapping instead of overflowing. */
header {
  background: var(--paper);
  flex-shrink: 0;
}

/* Capped and centred exactly like #leftColumn below it, so the header —
   including its closing rule — lines up with the map and market column
   instead of spanning the full window. */
#headerInner {
  display: flex;
  flex-direction: column;
  gap: 4px;
  width: 100%;
  max-width: 480px;
  margin: 0 auto;
  padding: 5px 10px;
  border-bottom: var(--rule-major);
}

#headerTop {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  flex-wrap: wrap;
  gap: 4px 10px;
}

/* Set like the chart's own title (drawTitle in map.js): ink, uppercase,
   tracked, sitting in the top margin. */
header h1 {
  font-size: 14px;
  color: var(--ink);
  text-transform: uppercase;
  letter-spacing: 1px
}

#statusLeft,
#statusRight {
  display: flex;
  gap: 4px 10px;
  font-size: 11px;
  align-items: center;
  flex-wrap: wrap
}

/* Pins Ship/Credits/Cargo against the header's right edge, opposite the
   title — and pulls the cargo block (see #cargoStat below) along with it. */
#statusRight {
  justify-content: flex-end;
}

#statusLeft span,
#statusRight span {
  white-space: nowrap
}

/* Bold is what separates a value from its label now that both are ink. */
#statusLeft b,
#statusRight b {
  font-weight: bold
}

#shipName {
  color: var(--blue)
}

#locName {
  color: var(--orange)
}

/* Map over market, in one column capped narrow enough to stay readable.
   Design floor is 360px. */
main {
  flex: 1;
  display: flex;
  flex-direction: column;
  min-height: 0;
  gap: 0;
}

#leftColumn {
  flex: 1;
  display: flex;
  flex-direction: column;
  min-height: 0;
  width: 100%;
  max-width: 480px;
  margin: 0 auto;
}

/* Square, so the square canvas fills it exactly and leaves no empty bands
   above and below. Shrink stays enabled so a short window squeezes the map
   rather than pushing the market off screen. */
#mapWrap {
  flex: 0 1 auto;
  aspect-ratio: 1;
  min-height: 0;
  position: relative;
  overflow: hidden;
  /* The chart is drawn on opaque white paper, so the canvas covers this
     entirely. It only shows in the bands beside the canvas when the box is
     not square, and matching it keeps those invisible. A starfield used to
     sit here and none of it was ever visible. */
  background: var(--paper);
  display: flex;
  align-items: center;
  justify-content: center;
}

/* No max-width/max-height here: resizeCanvas() already sizes the canvas to
   fit its box, and a CSS clamp on top of that made the rendered size differ
   from the size the click hit-test measures against, which silently broke
   travel on small windows. No border either — resizeCanvas() measures this
   box, so framing it would resize the whole chart to buy a line the tab row
   above already draws. */
canvas {
  display: block;
}

#marketPanel {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
  background: var(--paper);
  border-top: var(--rule-major);
}

/* Only the table scrolls, so the station header and cargo strip stay put. */
#marketScroll,
#shipyardScroll,
#galacticScroll,
#routeScroll {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
}

/* Tabs, not stacked panels: the panel is the same height at every station, so
   nothing below it shifts when a yard appears. The map row above the canvas is
   the same control and shares every rule — one row of tabs, drawn twice.
   Both rows sit above what they control, so both close with the same rule. */
#panelTabs,
#mapTabs {
  display: flex;
  gap: 4px;
  padding: 4px 10px 0;
  border-bottom: var(--rule);
}

/* Only needs the flex-sizing override — #mapWrap's aspect-ratio would
   otherwise squeeze this row inside #leftColumn's flex column. Padding is
   inherited from the shared rule above: 0 on the bottom is what keeps the
   buttons flush against the border-bottom, so the active tab's cut lands on
   it correctly. */
#mapTabs {
  flex: 0 0 auto;
}

#panelTabs button,
#mapTabs button {
  flex: 1;
  min-height: 30px;
  /* Sits down onto the row's rule so the two lines are one line. */
  margin-bottom: -1px;
}

/* The selected tab cuts a gap in that line rather than being drawn over it —
   the same move drawOrbitArc() makes for a body sitting on its orbit. */
#panelTabs button.active,
#mapTabs button.active {
  border: var(--rule-major);
  border-bottom-color: var(--paper);
}

/* A tab with no station behind it. Dimmed, not disabled: it still takes the
   press and stays selected, it just has nothing to show until you land. */
#panelTabs button.unavailable {
  opacity: 0.3;
}

/* The commodity picker is the whole of this tab's interaction, so it gets the
   full width. */
#galacticCommodity {
  width: calc(100% - 12px);
  margin: 6px;
  padding: 4px 6px;
  border: var(--rule);
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font-mono);
  font-size: 12px;
}

/* The system a station is in, under its name in the galactic price list. Its
   own line rather than a second column, so the price column keeps the width it
   needs to stay scannable. */
.rowSub {
  display: block;
  font-size: 10px;
}

/* These are the --type-* custom properties defined above — the same ones
   map.js reads via getComputedStyle() into STATION_TYPE_COLORS for
   drawStationBody() to fill the station square with. Keep the two in step,
   the way CHART_PAPER/CHART_INK track --paper/--ink above. */
.stationIcon {
  display: inline-block;
  width: 9px;
  height: 9px;
  margin-right: 5px;
  border: var(--rule);
  vertical-align: middle;
}

.stationIcon.type-extraction { background: var(--type-extraction); }
.stationIcon.type-refinery { background: var(--type-refinery); }
.stationIcon.type-agriculture { background: var(--type-agriculture); }
.stationIcon.type-industrial { background: var(--type-industrial); }

/* Two buttons in a third column is more than the trade table carries, and at
   360px the station names need the room back. They keep the 32px target and
   give up the padding around it. */
#galacticBody .cellActions button {
  padding: 3px 4px;
  margin-left: 2px;
}

/* The route picker and its two icons on one line: the list takes what is left
   after them, the way the commodity picker takes the whole width of its tab. */
#routeBar {
  display: flex;
  gap: 4px;
  margin: 6px;
}

#routePicker {
  flex: 1;
  min-width: 0;
  padding: 4px 6px;
  border: var(--rule);
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font-mono);
  font-size: 12px;
}

/* Square, because they are one glyph each — except while ✖ is armed and reads
   SURE?, which is the whole of the confirmation and needs the width to say so. */
#routeAdd,
#routeDelete {
  min-height: 32px;
  min-width: 32px;
}

#routeLoopRow {
  display: block;
  margin: 0 6px 6px;
  font-size: 11px;
  cursor: pointer;
}

/* Only on screen while a new route is being named. */
#routeNameStrip {
  display: none;
  gap: 4px;
  margin: 0 6px 6px;
}

#routeNameStrip.showing {
  display: flex;
}

#routeName {
  flex: 1;
  min-width: 0;
  padding: 4px 6px;
  border: var(--rule);
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font-mono);
  font-size: 12px;
}

#routeNameOk {
  min-height: 32px;
}

/* One step per row, spaced apart the way the shipyard's hulls are. */
.routeStep {
  padding: 6px 10px;
  font-size: 11px;
}

.stepHead {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 8px;
}

.stepBtns button {
  min-height: 32px;
  padding: 3px 6px;
  margin-left: 2px;
}

/* A step already traded. Struck through and nothing else — the same mark a tab
   with nothing behind it wears, and the first row without it is the one the
   status bar is naming. */
.routeStep.done .stepHead,
.routeStep.done .rowSub {
  text-decoration: line-through;
}

/* Says the list is empty, or finished. Centred so it reads as a state of the
   list rather than as another row in it. */
.routeNote {
  padding: 10px;
  font-size: 11px;
  text-align: center;
}

.yardRow {
  padding: 8px 10px;
}

.yardHead {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 8px;
}

/* Buy is tapped as deliberately as a trade button, so it gets the same target. */
.yardHead button {
  min-height: 32px;
}

.yardStats,
.yardCost {
  font-size: 10px;
  margin-top: 3px;
}

/* Orange marks a material the yard cannot cover — the thing to go and haul in. */
.yardMat.short {
  color: var(--orange);
}

/* Station name, type and description were three stacked bordered strips; at
   360px that chrome cost more height than the table it introduced. */
#stationHeader {
  padding: 6px 10px;
  border-bottom: var(--rule);
  flex-shrink: 0;
}

#stationHeader h2 {
  font-size: 14px;
  color: var(--orange);
  letter-spacing: 1px;
  display: inline
}

#stationHeader .meta {
  font-size: 11px;
  display: inline;
  margin-left: 6px
}

/* An outlined box, because a station is the one square on the chart and
   everything natural there is round. */
#stationHeader .meta .faction {
  display: inline-block;
  padding: 1px 6px;
  border: var(--rule);
  font-size: 10px;
  margin-left: 4px;
}

#stationHeader .meta .standing {
  margin-left: 4px;
  font-size: 10px;
}

#stationDesc {
  font-size: 11px;
  margin-top: 2px
}

table {
  width: 100%;
  border-collapse: collapse;
  font-size: 12px
}

th,
td {
  padding: 3px 6px;
  text-align: left
}

/* Numbers are right-aligned so they compare down the column at a glance, and
   nothing in these cells may wrap — a wrapped row doubles in height. */
.cellBuy,
.cellSell,
.cellStock,
.cellPrice,
.cellActions {
  text-align: right;
  white-space: nowrap
}

/* Trade buttons are the one control a phone player taps repeatedly, so they
   get a real touch target. */
.cellActions button {
  margin-left: 3px;
  min-height: 32px;
  padding: 3px 6px
}

/* Fixed to the longest label ("Sell 256") so Buy and Sell line up regardless
   of quantity, instead of tracking the digit count. content-box so the 8ch
   measures the text area alone, not the padding .cellActions button adds. */
.buyBtn,
.sellBtn {
  box-sizing: content-box;
  min-width: 8ch;
}

.held {
  color: var(--orange)
}

/* Smaller and uppercase is the whole of what marks a column head apart from
   the numbers under it, plus the rule the th/td pair already draws. */
th {
  font-weight: normal;
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 1px
}

tr.flash-up td {
  animation: flashUp 0.6s ease
}

tr.flash-down td {
  animation: flashDown 0.6s ease
}

/* The one tint left on a panel surface. It is gone in 0.6s and it is the only
   thing on screen reporting a change rather than a state. */
@keyframes flashUp {
  0% {
    background: rgba(34, 197, 94, 0.12)
  }

  100% {
    background: transparent
  }
}

@keyframes flashDown {
  0% {
    background: rgba(239, 68, 68, 0.12)
  }

  100% {
    background: transparent
  }
}

/* Paper with an outline, bolding its label on hover rather than filling. */
button {
  font-family: var(--font-mono);
  background: var(--paper);
  border: var(--rule);
  color: var(--ink);
  padding: 3px 8px;
  cursor: pointer;
  font-size: 12px;
  transition: var(--transition-fast);
}

/* text-shadow instead of font-weight: bold Courier New's bold glyphs are
   wider than its regular ones, so a real weight change grows the box on
   hover and snaps it back on hover-out. This thickens the strokes without
   touching font metrics, so nothing resizes. */
button:hover:not(:disabled) {
  text-shadow: 0 0 6px currentColor;
}

/* Dimming the whole control is what's left to say "not now" without a grey. */
button:disabled {
  opacity: 0.3;
  cursor: not-allowed
}

button.danger,
button.success {
  color: var(--accent);
  border-color: var(--accent);
}

button.danger:hover,
button.success:hover {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--paper);
}

button.danger {
  --accent: var(--red);
}

button.success {
  --accent: var(--green);
}

/* The item list (Mixed holds only) sits below at its own width — it can run
   longer than the label line and isn't part of the bar's width match below. */
#cargoStat {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  font-size: 11px;
}

/* Grid, not flex: a grid track's auto width is computed from its cells'
   max-content size while correctly ignoring percentage-width descendants, so
   #cargoBar's 100% reliably matches the label line's width instead of the
   browser falling back to filling the row (which is what a flex column with
   an auto-width parent did here). */
#cargoBarWrap {
  display: grid;
  justify-items: end;
}

#cargoBar {
  display: flex;
  width: 100%;
  height: 6px;
  margin: 2px 0;
  background: var(--paper);
  border: var(--rule);
  overflow: hidden
}

/* The hold is the ship's, so it is filled in the ship's colour. Flat ink read
   too harsh at this small a size. */
#cargoBar .seg {
  height: 100%;
  transition: width 0.3s ease;
  min-width: 0;
  background: var(--blue)
}

/* One fill colour for every commodity, so neighbours need a seam to stay
   countable. The seam before the empty segment marks where the cargo ends. */
#cargoBar .seg+.seg {
  border-left: 1px solid var(--paper)
}

#cargoBar .seg.empty {
  flex: 1;
  background: transparent
}

/* Only shown for Mixed holds — see renderCargo() — where the label alone
   doesn't say what's held and there's no hover tooltip to check on a touch
   screen. Visibility is toggled in JS rather than defaulted here since it's
   a per-render decision. */
#cargoList {
  font-size: 10px;
}

::-webkit-scrollbar {
  width: 6px
}

::-webkit-scrollbar-thumb {
  background: var(--ink)
}
