/* Linehaul - uses the site's existing tokens from style.css, adds only what the game needs. */

/* .wrap has no width rule anywhere in style.css, so on a wide monitor the page ran the full
   width of the screen. Constrained and centred here rather than in the global stylesheet, which
   other pages rely on as-is. */
.lh {
  max-width: 1560px;
  margin: 0 auto;
  padding: 0 18px 40px;
}

.lhIntro { margin: 22px 0 10px; }
.lhEyebrow {
  margin: 0; font-size: .82rem; text-transform: uppercase; letter-spacing: .14em;
  color: var(--accent2); font-weight: 700;
}
.lh h1 { margin: 6px 0 8px; }
.lhLede { max-width: 78ch; color: var(--muted); }
.lhLede strong { color: var(--text); }
.muted { color: var(--muted); }

/* Shown only when the game failed to start. It has to be legible without any of the rest of the
   page working, so it leans on nothing but its own rules. */
.lhBroken {
  margin: 22px 0; padding: 18px 20px; border-radius: 10px;
  background: rgba(255, 107, 129, .10); border: 1px solid rgba(255, 107, 129, .45);
  color: #ffd9df;
}
.lhBroken h2 { margin: 0 0 8px; font-size: 1.1rem; color: #ff8fa3; }
.lhBroken p { margin: 8px 0; max-width: 70ch; }
.lhBrokenWhy code {
  display: block; white-space: pre-wrap; word-break: break-word;
  font-size: .8rem; line-height: 1.45; color: #ffb9c6;
  padding: 9px 11px; border-radius: 6px; background: rgba(0, 0, 0, .35);
  max-height: 180px; overflow: auto;
}

.lhFlash {
  margin: 10px 0; padding: 10px 14px; border-radius: 8px;
  background: rgba(255, 211, 110, .10); border: 1px solid rgba(255, 211, 110, .34);
  color: var(--warn); font-size: .92rem;
}

/* ---------- status ---------- */
.lhHud, .lhGauges {
  display: grid; gap: 12px; margin: 16px 0;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
}
.hudItem, .gauge {
  background: rgba(11, 18, 36, .55); border: 1px solid rgba(255, 255, 255, .07);
  border-radius: 8px; padding: 12px 14px; display: flex; flex-direction: column; gap: 3px;
}
.hudLabel { font-size: .74rem; text-transform: uppercase; letter-spacing: .1em; color: var(--muted); }
.hudItem strong, .gauge strong { font-size: 1.12rem; }
.hudItem .muted, .gauge .muted { font-size: .82rem; }

.bar { height: 8px; border-radius: 999px; background: rgba(255, 255, 255, .08); overflow: hidden; margin: 4px 0 2px; }
.barFill { display: block; height: 100%; background: var(--accent2); transition: width 220ms ease; }
.barFill.barWarn { background: var(--warn); }

/* ---------- layout ----------
   The board is landscape now (1400x1090 - the mainland is about 4,080 km across and 3,030 km
   down), so the map takes the full width of the page rather than a column, and the planner has
   moved into the Drive tab underneath it. In a 520px column this board would render at about a
   third scale with the town names down near four pixels: readable enough to decorate, not enough
   to plan on. */
.lhCols, .lhRow { display: grid; gap: 18px; grid-template-columns: 1fr; align-items: start; margin: 18px 0; }
/* The map needs room. At a 520px column the board renders at 0.6 scale and the town names come
   out around 7px - present, but not readable, which makes the map decoration rather than the
   instrument you plan on. */
@media (min-width: 1000px) { .lhCols { grid-template-columns: minmax(0, 520px) minmax(0, 1fr); } }
@media (min-width: 1360px) { .lhCols { grid-template-columns: minmax(0, 700px) minmax(0, 1fr); } }
@media (min-width: 1600px) { .lhCols { grid-template-columns: minmax(0, 790px) minmax(0, 1fr); } }
/* The tabs hold the route cards, which are the densest thing in the game, so they get the
   room and the make-up list takes what it needs. */
@media (min-width: 860px)  { .lhRow  { grid-template-columns: minmax(0, 330px) minmax(0, 1fr); } }
.lhMapRow { margin: 18px 0; }
.lhMapRow .lhPanel { margin: 0; }

.lhPanel {
  background: linear-gradient(180deg, rgba(11, 18, 36, .78), rgba(10, 15, 31, .62));
  border: 1px solid rgba(255, 255, 255, .08); border-radius: var(--radius);
  box-shadow: var(--shadow); padding: 18px; margin: 18px 0;
}
.lhCols .lhPanel, .lhRow .lhPanel { margin: 0; }
.lhPanel h2 { margin: 0 0 10px; font-size: 1.08rem; }
.lhDepotNote { font-size: .84rem; margin: 12px 0 0; max-width: 52ch; }
.lhHireNote { font-size: .82rem; margin: 0 0 10px; max-width: 70ch; }

/* Buying an amount of fuel rather than a tankful. Sits with the other pump controls rather than
   in a dialog - it is a decision made at the bowser, not a settings screen. */
.fuelBuy { display: inline-flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.fuelBuy label { display: inline-flex; align-items: center; gap: 6px; font-size: .8rem;
  color: var(--muted); }
.fuelBuy input {
  width: 92px; padding: 7px 8px; border-radius: 6px; font: inherit;
  border: 1px solid rgba(255,255,255,.14); background: rgba(6,11,24,.8); color: var(--text);
}
.fuelBuy .muted { font-size: .8rem; }

/* The expense sheet. Three columns - what it is, what it came to, and what that is per day.
   The rate column is the one that changes decisions, so it is never allowed to wrap away. */
.sheet { margin-top: 10px; border: 1px solid rgba(255,255,255,.08); border-radius: 8px;
  overflow: hidden; }
.sheetHead { display: grid; grid-template-columns: var(--sheetCols); gap: 12px;
  padding: 7px 12px; font-size: .74rem; letter-spacing: .08em; text-transform: uppercase;
  color: var(--muted); background: rgba(255,255,255,.04); }
.sheetRow { display: grid; grid-template-columns: var(--sheetCols); gap: 12px; align-items: baseline;
  padding: 8px 12px; border-top: 1px solid rgba(255,255,255,.05); font-size: .88rem; }
.sheetName { display: flex; flex-direction: column; gap: 2px; }
.sheetName .muted { font-size: .76rem; }
.sheetAmt { font-variant-numeric: tabular-nums; min-width: 88px; text-align: right; }
.sheetRate { font-variant-numeric: tabular-nums; min-width: 82px; text-align: right; font-size: .78rem; }
/* Name, then the three trailing windows, then all time and the per-day rate. One variable so
   the header and the rows can never drift apart, and so the narrow screens below can drop a
   column by redefining it rather than by hiding cells and hoping the grid keeps up. */
.sheet { --sheetCols: 1fr auto auto auto auto auto; }
.sheetWin { font-variant-numeric: tabular-nums; min-width: 76px; text-align: right;
  font-size: .78rem; }
.sheetHead .sheetWin, .sheetHead .sheetAmt, .sheetHead .sheetRate { font-size: .74rem;
  opacity: .75; }
/* A phone gets the week and all time; a tablet gets the month as well. The year column is the
   first to go - it is the one a glance needs least. */
@media (max-width: 1100px) { .sheet { --sheetCols: 1fr auto auto auto auto; }
  .sheetWider { display: none; } }
@media (max-width: 820px) { .sheet { --sheetCols: 1fr auto auto auto; }
  .sheetWide { display: none; } }
@media (max-width: 560px) { .sheet { --sheetCols: 1fr auto auto; } .sheetRate { display: none; } }
.sheetIn .sheetAmt { color: var(--accent2); }
.sheetOut .sheetAmt { color: #ffb9c6; }
.sheetTotal { font-weight: 700; background: rgba(255,255,255,.03); }
.sheetNet { font-weight: 700; background: rgba(255,255,255,.06); font-size: .95rem; }
/* Per figure, not per row: the bottom line can be up over a week and down over a career, and
   both have to be able to say so on the same line. */
/* What a trailer is holding, said plainly enough to read down a list of six of them. */
.trailerLaden { font-size: .82rem; color: var(--accent2); }
/* The roads standing between you and where you want to go, each with the way round it. */
.permitOffer { margin-top: 10px; }
.permitLeg { display: flex; flex-wrap: wrap; gap: 8px; align-items: baseline;
  justify-content: space-between; padding: 8px 10px; margin-bottom: 6px;
  border: 1px solid rgba(255,255,255,.08); border-radius: 6px;
  background: rgba(255,255,255,.02); font-size: .84rem; }
.sheetUp { color: var(--accent2); }
.sheetDown { color: var(--danger); }
.sheetGood .sheetAmt { color: var(--accent2); }
.sheetBad .sheetAmt { color: var(--danger); }

/* The waypoints, in the panel rather than only in the strip above the map. */
.viaLine { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; margin: 0 0 10px;
  padding: 8px 12px; border-radius: 8px; font-size: .86rem;
  background: rgba(255, 193, 94, .12); border: 1px solid rgba(255, 193, 94, .4); }
.viaLine strong { color: #ffd98b; }

/* ---------- account ---------- */
.lhAccount { padding: 12px 16px; }
.lhAccountRow { display: flex; flex-wrap: wrap; gap: 12px; align-items: center;
  justify-content: space-between; }
.lhAccountState { font-size: .9rem; }
.lhAccountState strong { color: var(--accent2); }
/* Every yard you own, wherever you are standing. */
.yardList { display: flex; flex-direction: column; gap: .4rem; margin: .4rem 0 .8rem; }
.yardRow { display: flex; gap: .8rem; align-items: center; justify-content: space-between;
  background: rgba(255,255,255,.03); border: 1px solid rgba(255,255,255,.08);
  border-radius: 10px; padding: .55rem .7rem; }
.yardHere { border-color: rgba(124, 244, 199, .35); }
.yardHere strong { color: var(--accent2); }

/* The order book. The one where you are standing is the one you can act on, so it is lit. */
.lhOrders { list-style: none; margin: .3rem 0 .7rem; padding: 0; font-size: .9rem;
  color: var(--muted); display: flex; flex-direction: column; gap: .25rem; }
.lhOrders strong { color: var(--text); font-weight: 600; }
.lhOrderHere { color: var(--accent2); }
.lhOrderHere strong { color: var(--accent2); }

/* The season. Amber when it is dry where you are standing, because that is the one time the
   line is telling you something you can act on right now. */
.lhSeason { margin: .3rem 0 .6rem; font-size: .9rem; color: var(--muted); }
.lhSeasonDry { color: var(--warn); }

/* The shed and the tank, side by side - you decide whether to sell by looking at both at once. */
.storeGrid { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: .8rem; margin: .6rem 0; }
.storeBin { background: rgba(255,255,255,.03); border: 1px solid rgba(255,255,255,.08);
  border-radius: 10px; padding: .7rem .8rem; display: flex; flex-direction: column; gap: .3rem; }
.storeBin strong { font-size: 1rem; }
.storeBin .bar { margin: .15rem 0 .2rem; }
.storeActs { flex-wrap: wrap; gap: .5rem; }
.storeActs .muted { align-self: center; font-size: .88rem; }

.lhShare { display: inline-flex; align-items: center; gap: .4rem; font-size: .86rem;
  color: var(--muted); cursor: pointer; margin-right: .2rem; }
.lhShare input { cursor: pointer; }
.lhAccount .actions { margin: 0; }
.lhAccountForm { display: flex; flex-wrap: wrap; gap: 8px; align-items: flex-end; margin-top: 10px; }
.lhAccountForm label { display: flex; flex-direction: column; gap: 4px; font-size: .78rem;
  color: var(--muted); }
.lhAccountForm input { padding: 7px 9px; border-radius: 6px; min-width: 190px;
  border: 1px solid rgba(255,255,255,.14); background: rgba(6,11,24,.8); color: var(--text); }
#accountNote { font-size: .82rem; margin: 8px 0 0; max-width: 78ch; }
/* The recovery code is the only way back into an account. It is shown once and it has to look
   like something you write down, not like a status message you scroll past. */
.lhRecovery { margin-top: 10px; padding: 12px 14px; border-radius: 8px;
  background: rgba(255, 193, 94, .12); border: 1px solid rgba(255, 193, 94, .45); }
.lhRecovery code { display: block; margin: 6px 0; font-size: 1.15rem; letter-spacing: .06em;
  color: #ffd98b; user-select: all; }
.lhConflict { margin-top: 10px; padding: 12px 14px; border-radius: 8px;
  background: rgba(74, 163, 255, .12); border: 1px solid rgba(74, 163, 255, .45); }
.lhConflict .actions { margin-top: 8px; }

/* ---------- map ---------- */
.lhMapKey { font-size: .84rem; }
.keyRow { display: flex; flex-wrap: wrap; gap: 4px 14px; align-items: center; margin-top: 6px; }
.keyDot { width: 9px; height: 9px; border-radius: 50%; display: inline-block; margin-right: 2px; }
.keyHere { background: var(--accent2); }
.keyDest { background: #4aa3ff; }
.keyMetro { background: var(--danger); }
.keyAssembly { background: var(--warn); }
.keyFuel { background: #c58cff; }

/* Fit the whole country on the screen at once. Width first, but capped by what is left of the
   viewport height, so Perth and Cairns are both on screen without scrolling for them - the map is
   only useful as one picture. The max-width is the height cap expressed as a width, which is what
   keeps the aspect honest while the height is what actually binds. */
/* Zoom controls sit above the map rather than floating on it: the map is the thing being read,
   and a control overlapping Queensland is a control in the way. */
.mapTools { display: flex; align-items: center; gap: 10px; margin: 0 0 8px; min-height: 28px; }
.mapTools .muted { font-size: .8rem; }
.btnSmall { padding: 4px 10px; font-size: .8rem; }
.mapTools { flex-wrap: wrap; }
/* The click-mode switch says what it is doing, and looks different while it is doing the less
   usual of the two - a mode you cannot see is a mode you forget you are in. */
.lhModeVia { background: rgba(197, 140, 255, .22); border-color: rgba(197, 140, 255, .5); }
#mapMode:disabled { opacity: .8; cursor: default; }
/* A town the player has put on the route themselves. */
/* NOT the fuel-stop purple. These were the same colour, so the dot the map drew for a planned
   fuel stop looked exactly like the dot it draws for a town you chose - and the feature read as
   broken because the map appeared to be marking somewhere you had not clicked. A waypoint is
   amber and wears a ring; a fuel stop is purple and wears a halo. */
.town.townVia circle { fill: #ffc15e; stroke: #fff; stroke-width: 2.2;
  vector-effect: non-scaling-stroke; }
/* A town can be both - you pinned it AND the fuel plan wants to stop there, which is common
   because the sensible places to route through are the sensible places to buy diesel. Amber
   centre for your choice, purple halo for the fuel: both readable at once rather than one
   silently painting over the other, which is what was happening. */
.town.townVia.townFuel circle { fill: #ffc15e; stroke: rgba(197, 140, 255, .55); stroke-width: 5; }
/* A station is a property, not a town - drawn smaller and in the colour of the country. */
.townStation circle { fill: rgba(212, 176, 116, .85); }
.townStation text { fill: #d9c29a; }

/* Your drivers. Drawn as a truck-ish box rather than another dot, because a dot on a map of dots
   is one more thing to decode - and coloured by whether they are earning, idle, or stuck. */
/* Every measurement here is a scaled variable, not a number: the group is translated into
   place and the contents are drawn around 0,0, so the whole marker keeps its size on screen as
   you zoom and the name stays beside the truck rather than drifting off it. */
.drvMark .drvBox { fill: var(--accent2); stroke: rgba(0,0,0,.55); stroke-width: 1;
  vector-effect: non-scaling-stroke;
  width: var(--lhTruckW, 13px); height: var(--lhTruckH, 7px);
  x: calc(var(--lhTruckW, 13px) / -2); y: calc(var(--lhTruckH, 7px) / -2); }
.drvMark text { fill: var(--accent2); font-size: var(--lhLabel, 13px);
  font-family: system-ui, sans-serif; font-weight: 700; pointer-events: none;
  /* A transform, not x/y: CSS geometry properties apply to rect and circle but NOT to text, so
     an x here is quietly ignored and the name lands on top of the truck. */
  transform: translate(calc(var(--lhTruckW, 13px) / 2 + var(--lhLabel, 13px) * .34),
                       calc(var(--lhLabel, 13px) * .34)); }
.drvMark .drvHalo { fill: none; stroke: var(--accent2); stroke-opacity: .28; stroke-width: 8;
  vector-effect: non-scaling-stroke; r: var(--lhR, 4.5px); }
.drvMark { cursor: default; }

/* Another player: the same shape as one of your drivers, in a colour that is plainly not yours,
   and dimmer - their business is not the subject of this map. */
.plrMark .drvBox { fill: #8fa6ff; stroke: rgba(0,0,0,.55); stroke-width: 1;
  vector-effect: non-scaling-stroke; opacity: .85;
  width: var(--lhTruckW, 13px); height: var(--lhTruckH, 7px);
  x: calc(var(--lhTruckW, 13px) / -2); y: calc(var(--lhTruckH, 7px) / -2); }
.plrMark text { fill: #8fa6ff; font-size: var(--lhLabel, 13px); font-weight: 700;
  font-family: system-ui, sans-serif; pointer-events: none; opacity: .9;
  transform: translate(calc(var(--lhTruckW, 13px) / 2 + var(--lhLabel, 13px) * .34),
                       calc(var(--lhLabel, 13px) * .34)); }
.plrMark .drvHalo { fill: none; stroke: #8fa6ff; stroke-opacity: .2; stroke-width: 8;
  vector-effect: non-scaling-stroke; r: var(--lhR, 4.5px); }
/* Idle is amber, stuck is red - a driver on full wages with nowhere to load should be the thing
   your eye lands on. */
.drvIdle .drvBox, .drvIdle text { fill: var(--warn); }
.drvIdle .drvHalo { stroke: var(--warn); }
.drvStuck .drvBox, .drvStuck text { fill: var(--danger); }
.drvStuck .drvHalo { stroke: var(--danger); stroke-opacity: .45; }
.townVia text { fill: #ffd98b; font-weight: 700; }
.keyVia { background: #ffc15e; }

.mapWrap { width: 100%; display: flex; justify-content: center; }
/* An SVG is text to the browser, so press-and-drag over it selects town names and paints the map
   blue while you pan. Nothing on this map is worth selecting. */
#map, #map text { user-select: none; -webkit-user-select: none; }
/* Panning only does something once you are zoomed in, so the hand only appears then. */
#map.mapNear { cursor: grab; touch-action: none; }
#map.mapNear:active { cursor: grabbing; }
/* Three bands of place, so the map shows what is worth reading at the distance you are reading it
   from. Zoomed right out only the towns you plan around; closer in the roadhouses; closer again
   the cattle stations, which are a shed and a set of yards and matter only when you are going
   to one. */
#map.mapFar .townMinor text,
#map.mapFar .townStation text,
#map.mapMid .townStation text { display: none; }
#map.mapFar .townStation circle { r: 2.5; }
/* Take a height and fill the width. The viewBox is built to match whatever shape this ends up
   being (viewAspect in game.js), so there is never a letterbox - zooming in buys more country
   rather than more empty panel. */
#map {
  width: 100%;
  height: min(72vh, 780px);
  display: block;
}
@supports (height: 100dvh) {
  #map { height: min(72dvh, 780px); }
}
/* Zoomed out is the exception: Australia is 1.28 wide to 1 tall, so on a wide panel the whole
   country would sit in the middle of it with a third of the width empty either side. In that one
   state the element takes the country's own proportions and the country fills it. */
#map.mapOut {
  max-width: calc(min(72vh, 780px) * 1400 / 1090);
  margin: 0 auto;
}
@supports (height: 100dvh) {
  #map.mapOut { max-width: calc(min(72dvh, 780px) * 1400 / 1090); }
}
/* On a phone a tall map is more use than a wide one - the country is landscape but the screen is
   not, and the alternative is a stamp. */
@media (max-width: 859px) {
  #map { height: 62vh; }
  #map.mapOut { max-width: 100%; }
}

/* While a run is being planned or driven the map is a working instrument rather than an atlas,
   so it comes down to half the screen and sticks there - you compare the route cards against the
   road, and scrolling the cards used to take the map away entirely. It stays readable at that
   size because it is framed on the run rather than on the continent. */
@media (min-width: 860px) {
  .lhOnRun .lhMapRow {
    position: sticky; top: 8px; z-index: 4;
    background: var(--bg, #070c18); padding-bottom: 6px;
  }
  /* While a run is on, the map stays under half the screen WHATEVER the zoom. Letting the
     fitted country go full size to keep it readable traded one problem for a worse one: 780px of
     map above a sticky panel leaves almost nothing for the route cards, and the cards are the
     thing being decided between. The whole country at this size is a glance, not a reading - and
     the default is framed on the run, which is readable. */
  .lhOnRun #map { height: 42vh; }
  .lhOnRun #map.mapOut { max-width: calc(42vh * 1400 / 1090); }
  /* Everything around the map gets out of the way too: once a run is on, the panel is competing
     with the route cards for the same screen, and the sentence explaining how to read the map has
     already done its job. The colour key stays - that is reference, not instruction. */
  .lhOnRun .lhMapPanel { padding: 10px 14px; }
  .lhOnRun .lhMapPanel > h2 { display: none; }
  .lhOnRun .lhMapKey { font-size: 0; margin: 0 0 4px; }
  .lhOnRun .lhMapKey .keyRow { font-size: .8rem; margin-top: 0; }
  .lhOnRun .mapTools { margin-bottom: 4px; min-height: 0; }
}

/* fill:none matters - a polyline without it paints the area its bends enclose, which on
   the Eyre bowing round the Bight is most of South Australia. */
/* Land. Faint enough to read the roads straight through, present enough that the shape of the
   country is obvious at a glance. */
.coast {
  fill: rgba(120, 165, 235, .055);
  stroke: rgba(140, 185, 255, .22);
  stroke-width: 1.2;
  stroke-linejoin: round;
}

/* non-scaling-stroke is the whole of it: the road keeps its width on screen however far the map
   is zoomed, exactly as the labels and the dots now do. Without it a highway at seven times zoom
   is fourteen pixels wide and the map stops looking like a map. */
.road { stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; fill: none;
  vector-effect: non-scaling-stroke; }
.roadLegal { stroke: rgba(124, 244, 199, .42); }
/* Blocked roads stay visible but recede - you need to see the network you cannot use, because
   that is the information you are planning around. */
.roadBlocked { stroke: rgba(255, 255, 255, .09); stroke-dasharray: 4 6; }
/* The route under consideration. This is the point of having a map at all: seeing the Newell
   light up against the Pacific settles the argument faster than any table of numbers. */
.roadHot { stroke: #4aa3ff; stroke-width: 4.5; filter: drop-shadow(0 0 5px rgba(74, 163, 255, .55)); }
/* A closed road has to shout. It is the one piece of map state that invalidates a plan you have
   already committed to, and the player needs to see WHY the re-route button lit up. */
.roadShut { stroke: var(--danger); stroke-width: 3.5; stroke-dasharray: 2 5; }

/* Sized from the same variable the labels use, so a town is the same size on screen at any zoom
   and does not become a blob beside its own name. */
.town circle { fill: rgba(159, 176, 209, .8); r: var(--lhR, 4.5px); }
.townMetro circle { r: var(--lhRmetro, 6.5px); }
/* Sized from a variable the zoom sets, so a name is the same size on screen however far in you
   are. It was fixed in board units, which magnified it along with the map until a town name
   covered the road it belonged to. */
.town text { fill: #9fb0d1; font-size: var(--lhLabel, 13px); font-family: system-ui, sans-serif;
  pointer-events: none; }
.town circle { transform-box: fill-box; transform-origin: center; }
.town { cursor: pointer; }
.town:hover circle { fill: #fff; }
.town:hover text { fill: var(--text); }
.townMetro circle { fill: var(--danger); }
.townMetro text { fill: #ffb9c6; font-weight: 600; }
.townAssembly circle { fill: var(--warn); }
.townFuel circle { fill: #c58cff; stroke: rgba(197, 140, 255, .3); stroke-width: 5;
  vector-effect: non-scaling-stroke; }
.townDest circle { fill: #4aa3ff; stroke: rgba(74, 163, 255, .32); stroke-width: 6; }
.townDest text { fill: #cfe3ff; font-weight: 700; }
.townHere circle { fill: var(--accent2); stroke: rgba(124, 244, 199, .32); stroke-width: 7; }
.townHere text { fill: var(--text); font-weight: 700; }

/* ---------- the route planner ---------- */
.lhField { display: flex; flex-direction: column; gap: 5px; margin-bottom: 14px; }
.lhField select {
  font: inherit; color: var(--text); padding: 9px 11px; border-radius: 8px;
  background: rgba(6, 10, 20, .75); border: 1px solid rgba(255, 255, 255, .16);
}
.lhField select:focus-visible { outline: 2px solid var(--accent2); outline-offset: 1px; }

/* The right-hand column is wide on a desktop; route cards running single file down it wasted
   most of it and pushed the fourth option below the fold. */
.routeList { display: grid; gap: 10px; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); }
.routeList > p { grid-column: 1 / -1; margin: 0 0 2px; }
.route {
  padding: 12px 14px; border-radius: 8px; cursor: pointer;
  background: rgba(6, 10, 20, .5); border: 1px solid rgba(255, 255, 255, .09);
  display: flex; flex-direction: column; gap: 6px;
}
.route:hover { border-color: rgba(74, 163, 255, .45); }
.routeActive { border-color: rgba(74, 163, 255, .75); background: rgba(74, 163, 255, .10); }
.routeDead { cursor: default; opacity: .75; border-style: dashed; }
.routeDead:hover { border-color: rgba(255, 255, 255, .09); }

.rHead { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; }
.rHead strong { font-size: 1.05rem; }
.rBadge {
  font-size: .7rem; text-transform: uppercase; letter-spacing: .08em; font-weight: 700;
  padding: 2px 7px; border-radius: 999px;
  background: rgba(124, 244, 199, .14); color: var(--accent2);
  border: 1px solid rgba(124, 244, 199, .3);
}
.rNet { margin-left: auto; font-weight: 700; color: var(--accent2); }
.rNetBad { color: var(--danger); }
.rVia { font-size: .86rem; color: var(--muted); }
.rRough { color: var(--warn); }
.rNums { display: flex; flex-wrap: wrap; gap: 4px 16px; font-size: .88rem; }
/* The fuel plan is the answer to half the puzzle, so it gets its own emphasis rather than being
   another grey line among the numbers. */
.rFuel {
  font-size: .84rem; color: #d3c2ef; padding: 7px 9px; border-radius: 6px;
  background: rgba(197, 140, 255, .10); border: 1px solid rgba(197, 140, 255, .22);
}
.rWhy { font-size: .86rem; color: var(--warn); }
.rDrops { font-size: .84rem; color: #9ecbff; }
/* Wear is a liability, not an expense - so it reads as a note rather than another cost line. */
.rWear {
  font-size: .8rem; color: #c8b48a; padding: 6px 9px; border-radius: 6px;
  background: rgba(255, 211, 110, .07); border: 1px solid rgba(255, 211, 110, .18);
}
.lhNoRoute {
  padding: 12px 14px; border-radius: 8px; font-size: .92rem;
  background: rgba(255, 211, 110, .09); border: 1px solid rgba(255, 211, 110, .3);
}
.lhNoRoute strong { color: var(--warn); }

/* ---------- on the road ---------- */
.tripHead {
  display: grid; gap: 10px; margin-bottom: 12px;
  grid-template-columns: repeat(auto-fit, minmax(130px, 1fr));
}
.tripHead > div { display: flex; flex-direction: column; gap: 2px; }
.tripHead strong { font-size: 1.02rem; }
.tripHead .muted { font-size: .82rem; }

.tripHere {
  padding: 9px 12px; border-radius: 8px; margin-bottom: 10px;
  background: rgba(124, 244, 199, .08); border: 1px solid rgba(124, 244, 199, .26);
}
.tripHere strong { color: var(--accent2); }

.tripNext {
  padding: 10px 12px; border-radius: 8px; margin-bottom: 10px;
  background: rgba(6, 10, 20, .55); border: 1px solid rgba(255, 255, 255, .1);
}
.tripNext .hudLabel { display: block; margin-bottom: 3px; }
/* You cannot drive this leg. Say so loudly and permanently - a flash message fades while the
   player is still reading it, and then the disabled button has no explanation. */
.tripBlocked { border-color: rgba(255, 107, 129, .45); background: rgba(255, 107, 129, .08); }

.tripActions { margin: 12px 0 4px; }
.tripActions .btn { font-size: .88rem; }

.lhSubhead {
  margin: 18px 0 8px; font-size: .82rem; text-transform: uppercase; letter-spacing: .12em;
  color: var(--muted);
}

/* ---------- tabs ---------- */
/* The seven places. Square-ish and solid against the pill-shaped screens below them, so the two
   rows read as two different questions - which part of the business, then which screen of it -
   rather than as one long strip of eleven things. */
.lhSections { display: flex; flex-wrap: wrap; gap: 4px; margin-bottom: 8px;
  border-bottom: 1px solid rgba(255,255,255,.08); padding-bottom: 8px; }
.lhSection {
  font: inherit; font-size: .9rem; cursor: pointer; padding: 8px 14px; border-radius: 7px;
  color: var(--muted); background: transparent; border: 1px solid transparent;
}
.lhSection:hover { color: var(--text); background: rgba(74, 163, 255, .12); }
.lhSectionOn {
  color: var(--text); font-weight: 700; background: rgba(74, 163, 255, .16);
  border-color: rgba(74, 163, 255, .35);
}
/* A section with one screen has nothing to choose, so the row goes entirely rather than sitting
   there with a single button in it pretending to be a choice. */
.lhTabs[hidden] { display: none; }
.lhTabs { display: flex; flex-wrap: wrap; gap: 4px; margin-bottom: 14px; }
.lhTab {
  font: inherit; font-size: .84rem; cursor: pointer; padding: 7px 12px; border-radius: 999px;
  color: var(--muted); background: transparent; border: 1px solid rgba(255, 255, 255, .12);
}
.lhTab:hover { color: var(--text); background: rgba(74, 163, 255, .14); }
.lhTabOn {
  color: var(--accent2); border-color: rgba(124, 244, 199, .45);
  background: rgba(124, 244, 199, .10); font-weight: 700;
}

.bankRows {
  display: grid; gap: 10px; margin-bottom: 12px;
  grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
}
.bankRows > div { display: flex; flex-direction: column; gap: 2px; }
.bankRows strong { font-size: 1.05rem; }
.bankRows .muted { font-size: .8rem; }

/* A service item that is nearly gone should look it, in the list as well as on its bar. */
.cfgWorn { border-color: rgba(255, 211, 110, .4); background: rgba(255, 211, 110, .06); }
.cfg .bar { margin: 5px 0 4px; }

/* The cost breakdown needed a key. Someone reading "Running $271" has no way to know whether it
   is tyres, wages or rego, and guessed wrong is worse than not shown. */
.rLegend {
  font-size: .76rem; color: #8fa6c9; line-height: 1.45;
  padding-top: 6px; border-top: 1px solid rgba(255, 255, 255, .06);
}

/* ---------- the fleet ---------- */
.fleetRow {
  display: flex; gap: 10px; align-items: flex-start; flex-wrap: wrap;
  padding: 10px 12px; border-radius: 8px; margin-bottom: 8px;
  background: rgba(6, 10, 20, .5); border: 1px solid rgba(255, 255, 255, .08);
}
.fleetMine { border-color: rgba(124, 244, 199, .4); background: rgba(124, 244, 199, .07); }
.fleetMain { display: flex; flex-direction: column; gap: 2px; flex: 1 1 220px; min-width: 0; }
.fleetMain strong { font-size: .98rem; }
.fleetMain span { font-size: .8rem; }
.fleetActs { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; }
.fleetActs .btn { font-size: .8rem; padding: 6px 10px; }

/* ---------- drivers ---------- */
/* An idle driver is the most expensive thing in the game, so an idle driver looks wrong. */
.driverIdle { border-color: rgba(255, 107, 129, .4); background: rgba(255, 107, 129, .06); }
.fleetActs .drvPick {
  font: inherit; font-size: .8rem; color: var(--text); padding: 5px 8px; border-radius: 7px;
  background: rgba(6, 10, 20, .8); border: 1px solid rgba(255, 255, 255, .16); max-width: 190px;
}

/* ---------- rego ---------- */
.regoBox {
  padding: 10px 12px; border-radius: 8px; margin-bottom: 12px; font-size: .88rem;
  background: rgba(6, 10, 20, .5); border: 1px solid rgba(255, 255, 255, .1);
}
.regoBox.regoSoon { border-color: rgba(255, 211, 110, .4); background: rgba(255, 211, 110, .07); }
.regoBox.regoLate { border-color: rgba(255, 107, 129, .5); background: rgba(255, 107, 129, .08); }
span.regoSoon { color: var(--warn); font-size: .8rem; }
span.regoLate { color: var(--danger); font-weight: 600; font-size: .8rem; }

/* ---------- lane direction ---------- */
.loadLane { font-size: .8rem; }
.laneUp { color: var(--accent2); }
.laneDown { color: var(--warn); }

/* ---------- make-up ---------- */
.cfgList { display: grid; gap: 8px; }
.cfg {
  text-align: left; display: flex; flex-direction: column; gap: 2px; cursor: pointer;
  padding: 10px 12px; border-radius: 8px; font: inherit; color: var(--text);
  background: rgba(6, 10, 20, .5); border: 1px solid rgba(255, 255, 255, .09);
}
.cfg strong { color: var(--text); font-size: .98rem; }
.cfg span { font-size: .82rem; color: var(--muted); }
.cfg .cfgAccess { color: #8fa6c9; }
.cfg:hover:not(:disabled) { background: rgba(74, 163, 255, .14); }
.cfgActive { border-color: rgba(124, 244, 199, .5); background: rgba(124, 244, 199, .08); }
.cfgActive strong { color: var(--accent2); }
/* A combination you cannot afford yet still has to be READABLE - it is the thing you are saving
   up for, so it needs to sell itself. Dim the frame, never the words. Opacity .45 on the whole
   element made these invisible. */
.cfgLocked { cursor: not-allowed; background: rgba(6, 10, 20, .28); border-style: dashed; }
.cfgLocked strong { color: #c3cfe6; }
.cfgLocked span { color: #7f90ad; }
.cfgNeed { color: var(--warn) !important; }

/* The upgrade tree. A branch is a column of cards stepping to the right as the prerequisites
   stack up, with a rail down the left so the chain reads as one - the depth is the whole point,
   and a flat list of eight buttons said nothing about which of them needs which. */
.upTree { display: grid; gap: 6px; }
.upTree .lhSubhead { margin-top: 14px; }
.upBranch { position: relative; }
.upBranch::before {
  content: ""; position: absolute; left: 7px; top: 10px; bottom: 10px; width: 2px;
  background: linear-gradient(rgba(74, 163, 255, .38), rgba(74, 163, 255, .06)); border-radius: 2px;
}
.upNode { position: relative; }
.upNode::before {
  content: ""; position: absolute; left: -13px; top: 17px; width: 11px; height: 2px;
  background: rgba(74, 163, 255, .38);
}
.upDepth0 { margin-left: 20px; }
.upDepth1 { margin-left: 40px; }
.upDepth2 { margin-left: 60px; }
.upDepth1::before, .upDepth2::before { left: -33px; width: 31px; }
.upDepth2::before { left: -53px; width: 51px; }
.upTruck { margin-bottom: 4px; }

@media (max-width: 560px) {
  .upDepth0, .upDepth1, .upDepth2 { margin-left: 16px; }
  .upDepth1::before, .upDepth2::before { left: -9px; width: 7px; }
}

.actions { display: flex; flex-wrap: wrap; gap: 8px; }
.actions .btn { font-size: .88rem; color: var(--text); border-color: rgba(255, 255, 255, .16); }
.actions .btn:disabled { opacity: .55; cursor: not-allowed; }
.actions .btnGhost { background: rgba(28, 40, 66, .75); }
.actions .btnGhost:hover { background: rgba(74, 163, 255, .24); }

/* ---------- the load board ---------- */
.loadList { display: grid; gap: 10px; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); }
.load {
  padding: 12px 14px; border-radius: 8px;
  background: rgba(6, 10, 20, .5); border: 1px solid rgba(255, 255, 255, .08);
  display: flex; flex-direction: column; gap: 6px;
}
.loadHead { display: flex; align-items: baseline; gap: 8px; }
.loadPay { margin-left: auto; color: var(--accent2); font-weight: 700; }
.loadStatus { font-size: .84rem; }
.loadOk .loadStatus { color: var(--muted); }
.loadUrgent { border-color: rgba(255, 211, 110, .3); }
.loadUrgent .loadStatus { color: var(--warn); }
.loadPicked { border-color: rgba(74, 163, 255, .7); background: rgba(74, 163, 255, .10); }
/* A load you cannot take is left on the board on purpose: the refusal explains which combination
   would fit, which is how the network rules get taught. */
.loadBlocked { opacity: .82; border-color: rgba(255, 211, 110, .22); }
.loadBlocked .loadStatus { color: var(--warn); }
.btnRun { align-self: flex-start; margin-top: 2px; }

/* Freight waiting up the road reads as a different kind of thing from the board at your feet -
   it is an addition to a run you have already decided on, not a run of its own. */
.loadSection {
  grid-column: 1 / -1; margin: 14px 0 0; font-size: .86rem;
  padding-top: 12px; border-top: 1px solid rgba(255, 255, 255, .08);
}
.loadEnroute { border-color: rgba(74, 163, 255, .28); background: rgba(74, 163, 255, .06); }
.loadEnroute .loadStatus { color: #9ecbff; }
.loadUnits { color: var(--warn); }

/* Freight that is somewhere else reads differently again: it is a proposal to change the run,
   not an addition to it. */
.loadAway { border-color: rgba(197, 140, 255, .3); background: rgba(197, 140, 255, .06); }
.loadAway .loadStatus { color: #d3c2ef; }
.rCollect { font-size: .84rem; color: #d3c2ef; }

/* The number that decides it: what the job leaves after the driving it drags you through. */
.loadNet { font-size: .86rem; font-weight: 700; color: var(--accent2); }
.loadNetBad { color: var(--danger); }
.loadPoor { opacity: .85; border-color: rgba(255, 107, 129, .3); }

/* What is on the truck and what is still owed to somebody up the road. */
.manifest { display: grid; gap: 6px; margin-bottom: 12px; }
.manifestRow {
  display: flex; gap: 10px; align-items: center; flex-wrap: wrap;
  padding: 8px 11px; border-radius: 7px;
  background: rgba(6, 10, 20, .5); border: 1px solid rgba(255, 255, 255, .08);
}
.manifestRow > div:first-child { flex: 1 1 180px; min-width: 0; }
.manifestRow strong { font-size: .92rem; }
.manifestRow span, .manifestRow > div:nth-child(2) { font-size: .8rem; }
.manifestRow .btn { font-size: .78rem; padding: 5px 9px; }
/* A consignment you have agreed to collect but have not got yet is the thing that quietly
   reshapes a route, so it says so rather than sitting in the list looking like cargo. */
.manifestWait { color: var(--warn); }

.logList { list-style: none; margin: 0; padding: 0; display: grid; gap: 6px; font-size: .9rem; max-height: 320px; overflow-y: auto; }
.logList li { padding-bottom: 6px; border-bottom: 1px solid rgba(255, 255, 255, .05); }

.lhFootnote { font-size: .82rem; max-width: 90ch; }

/* The mown bar sits above the baled one: the gap between them is the windrow, which is
   the hay a storm would take. Deliberately a different colour from progress - it is not
   progress, it is exposure. */
.barCut { background: linear-gradient(90deg, #8a6d2f, #c9a227); opacity: .75; }

/* ---- the dashboard ----------------------------------------------------------
   The first page written against the seam: it is drawn by dash.js, which lives outside the
   game's closure. The styling lives here with everything else because it is one game and one
   look, not because the two files know about each other. */
.dashFigs { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 10px; margin: 10px 0 18px; }
.dashFig { display: flex; flex-direction: column; gap: 3px; padding: 10px 12px;
  border: 1px solid rgba(255,255,255,.08); border-radius: 8px; background: rgba(255,255,255,.02); }
.dashFig strong { font-size: 1.15rem; font-variant-numeric: tabular-nums; }
.dashFig .muted { font-size: .76rem; }
.dashGood strong { color: var(--accent2); }
.dashBad strong { color: var(--danger); }

.dashNotes { display: flex; flex-direction: column; gap: 6px; }
/* A note is a door, so it is a button and it looks like one you can press. The stripe down the
   left is the only thing carrying urgency - colour alone, at this size, is not enough to read. */
.dashNote { display: flex; gap: 12px; align-items: baseline; justify-content: space-between;
  width: 100%; text-align: left; padding: 9px 12px 9px 14px; cursor: pointer;
  border: 1px solid rgba(255,255,255,.08); border-left: 3px solid rgba(255,255,255,.25);
  border-radius: 6px; background: rgba(255,255,255,.03); color: inherit; font: inherit; }
.dashNote:hover { background: rgba(255,255,255,.07); }
.dashNoteText { flex: 1 1 auto; }
.dashNoteGo { flex: 0 0 auto; font-size: .78rem; white-space: nowrap; }
.dashNote-stopped { border-left-color: var(--danger); }
.dashNote-money   { border-left-color: #ffb9c6; }
.dashNote-crop    { border-left-color: #ffd479; }
.dashNote-people  { border-left-color: #9fd0ff; }
.dashNote-gear    { border-left-color: rgba(255,255,255,.35); }
.dashNote-idle    { border-left-color: rgba(255,255,255,.25); }
@media (max-width: 560px) {
  .dashNote { flex-direction: column; gap: 3px; }
}
