@import url('https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@500;600;700&family=Inter:wght@400;500;600;700&family=IBM+Plex+Mono:wght@400;500;600&display=swap');

:root {
  --bg: #F5F6F8;
  --surface: #FFFFFF;
  --surface-alt: #FAFBFC;
  --ink: #101828;
  --ink-soft: #344054;
  --muted: #667085;
  --border: #E4E7EC;
  --primary: #2554EB;
  --primary-hover: #1B3FC4;
  --primary-soft: #EEF2FF;
  --green: #067647;
  --green-soft: #ECFDF3;
  --red: #D92D20;
  --red-hover: #B42318;
  --red-soft: #FEF3F2;
  --shadow-sm: 0 1px 2px rgba(16, 24, 40, 0.06);
  --shadow-md: 0 2px 8px rgba(16, 24, 40, 0.08);
}

* { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  -webkit-font-smoothing: antialiased;
  padding: 40px 20px 96px;
}

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

/* A plain inline link -- inside a sentence of prose (a "locked page"
   message, an error banner, "Forgot your password?") rather than one
   of this app's own styled components (.page-nav, a building-row
   wrapped in its own link on Directory/Leaderboard, and so on, all of
   which already set their own color/text-decoration and win over
   this on specificity). Without this, a plain <a> falls back to the
   browser's own default blue-and-underlined, which doesn't match
   this app's palette at all -- every plain link in prose should read
   as part of the same design language as everything else on the
   page. */
a {
  color: var(--primary);
  text-decoration: none;
}
a:hover { text-decoration: underline; }

/* Visible keyboard focus for buttons and links -- shown only for
   :focus-visible (keyboard/assistive-tech navigation), not a mouse
   click, so clicking a button doesn't leave an outline sitting on it
   afterward the way a plain :focus rule would. Buttons already get a
   background/border change on hover, but that's not enough on its
   own for someone tabbing through the page with no pointer at all to
   tell which control is about to activate. Inputs and selects
   already have their own, different-looking focus treatment further
   down this file (a border-color change plus a soft box-shadow ring)
   -- deliberately not touched here, so this rule only adds an
   outline for the two element types that currently have no focus
   indicator of their own at all. */
button:focus-visible,
a:focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: 2px;
}

.num {
  font-family: 'IBM Plex Mono', ui-monospace, monospace;
  font-variant-numeric: tabular-nums;
}

/* ---------------- Masthead ---------------- */
header.masthead {
  text-align: center;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 12px;
  box-shadow: var(--shadow-sm);
  padding: 28px 24px 22px;
  margin-bottom: 28px;
}
header.masthead h1 {
  font-family: 'Space Grotesk', 'Inter', sans-serif;
  font-size: 32px;
  font-weight: 700;
  letter-spacing: -0.02em;
  margin: 0;
  color: var(--ink);
}
header.masthead p {
  margin: 6px 0 0;
  font-style: normal;
  color: var(--muted);
  font-size: 14px;
}
.world-clock {
  margin-top: 14px;
  font-size: 12px;
  color: var(--muted);
  font-family: 'IBM Plex Mono', monospace;
}
.page-nav {
  margin-top: 16px;
  display: flex;
  justify-content: center;
  align-items: center;
  gap: 4px;
  flex-wrap: wrap;
}
/* A top-level, ungrouped link -- just Head Office and (added at
   runtime by _addTutorialNavLink in shared.js) Tutorial. Everything
   else lives inside one of the .nav-group dropdowns below, so a
   player choosing among ~16 destinations picks a category first
   rather than scanning one long flat row. */
.page-nav > a {
  font-size: 13px;
  font-weight: 500;
  color: var(--muted);
  text-decoration: none;
  padding: 6px 10px;
  border-radius: 6px;
  border: 1px solid transparent;
  transition: background 0.12s ease, color 0.12s ease;
}
.page-nav > a.current {
  color: var(--primary);
  background: var(--primary-soft);
  pointer-events: none;
}
.page-nav > a:hover { color: var(--primary); background: var(--primary-soft); }

/* A grouped dropdown in the top nav (Company, Conglomerate, Country,
   Profile, Settings) -- see _initNavGroups in shared.js for the
   click-to-open/close-on-outside-click behavior, the same pattern
   toggleNotificationPanel already uses for this app's one other
   popover, rather than a CSS-only :hover reveal (which doesn't work
   on a touchscreen at all). class="current" on the group itself
   (set by _highlightCurrentNavLink in shared.js, alongside the
   matching link inside it) highlights the toggle button whenever the
   page you're on lives in that group, even while its menu is closed. */
.nav-group { position: relative; }
.nav-group-toggle {
  font: inherit;
  font-size: 13px;
  font-weight: 500;
  color: var(--muted);
  background: none;
  border: 1px solid transparent;
  border-radius: 6px;
  padding: 6px 10px;
  cursor: pointer;
  transition: background 0.12s ease, color 0.12s ease;
}
.nav-group-toggle::after {
  content: '\25BE';
  display: inline-block;
  margin-left: 4px;
  font-size: 10px;
}
.nav-group.current > .nav-group-toggle,
.nav-group-toggle:hover,
.nav-group-toggle:focus-visible {
  color: var(--primary);
  background: var(--primary-soft);
}
/* `display:none` is set inline in the HTML (and toggled directly by
   _initNavGroups, the same style.display convention
   toggleNotificationPanel already uses) -- this rule only supplies
   the OPEN layout, never the show/hide itself. */
.nav-group-menu {
  position: absolute;
  top: calc(100% + 8px);
  left: 50%;
  transform: translateX(-50%);
  flex-direction: column;
  gap: 2px;
  min-width: 180px;
  padding: 6px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 10px;
  box-shadow: var(--shadow-md);
  z-index: 50;
}
.nav-group-menu a {
  display: block;
  font-size: 13px;
  font-weight: 500;
  color: var(--muted);
  text-decoration: none;
  padding: 7px 10px;
  border-radius: 6px;
  white-space: nowrap;
}
.nav-group-menu a.current {
  color: var(--primary);
  background: var(--primary-soft);
  pointer-events: none;
}
.nav-group-menu a:hover { color: var(--primary); background: var(--primary-soft); }

.auth-bar {
  margin-top: 14px;
  display: flex;
  justify-content: center;
  align-items: center;
  gap: 10px;
  font-size: 13px;
  color: var(--muted);
}

/* ---------------- Notification bell (in the auth bar, every page) ---------------- */
.notification-bell-wrap { position: relative; display: inline-block; }
.notification-bell-btn {
  position: relative;
  padding: 4px 10px;
  font-size: 13px;
}
.notification-badge {
  position: absolute;
  top: -6px;
  right: -6px;
  min-width: 16px;
  height: 16px;
  padding: 0 4px;
  border-radius: 8px;
  background: var(--red);
  color: #fff;
  font-size: 10px;
  font-weight: 700;
  line-height: 16px;
  text-align: center;
}
.notification-panel {
  position: absolute;
  top: calc(100% + 8px);
  right: 0;
  width: 320px;
  max-height: 400px;
  overflow-y: auto;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 10px;
  box-shadow: var(--shadow-md);
  z-index: 50;
  text-align: left;
}
.notification-panel-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 10px 14px;
  border-bottom: 1px solid var(--border);
  font-size: 12px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--muted);
}
.notification-item {
  padding: 10px 14px;
  border-bottom: 1px solid var(--border);
  font-size: 13px;
  color: var(--ink);
  cursor: pointer;
}
.notification-item:last-child { border-bottom: none; }
.notification-item:hover { background: var(--surface-alt); }
.notification-item.unread { background: var(--primary-soft); }
.notification-item-row {
  display: flex;
  align-items: flex-start;
  gap: 8px;
}
.notification-item-message { flex: 1; }
.notification-delete-btn {
  flex-shrink: 0;
  width: 20px;
  height: 20px;
  line-height: 18px;
  padding: 0;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: var(--surface);
  color: var(--muted);
  font-size: 14px;
  text-align: center;
  cursor: pointer;
}
.notification-delete-btn:hover {
  background: var(--red-soft);
  border-color: var(--red);
  color: var(--red);
}
.notification-item .notification-time {
  display: block;
  margin-top: 3px;
  font-size: 11px;
  color: var(--muted);
}
.notification-empty {
  padding: 20px 14px;
  text-align: center;
  font-size: 13px;
  color: var(--muted);
}

/* ---------------- Auth page ---------------- */
.auth-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 12px;
  box-shadow: var(--shadow-sm);
  padding: 28px 30px;
  max-width: 380px;
  margin: 0 auto;
}
.auth-tabs {
  display: flex;
  gap: 6px;
  margin-bottom: 20px;
  background: var(--surface-alt);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 3px;
}
.auth-tabs button {
  flex: 1;
  border-radius: 6px;
}
.auth-tabs button.inactive {
  background: transparent;
  color: var(--muted);
  border-color: transparent;
}
.auth-form {
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.auth-form label {
  font-size: 13px;
  font-weight: 500;
  color: var(--ink-soft);
  display: block;
  margin-bottom: 4px;
}
.auth-form input {
  width: 100%;
}
.auth-form button[type=submit] {
  margin-top: 6px;
}

/* ---------------- Section rhythm ---------------- */
section { margin-bottom: 24px; }

h2.ledger-heading {
  font-family: 'Space Grotesk', 'Inter', sans-serif;
  font-size: 12px;
  font-weight: 600;
  color: var(--muted);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  margin: 0 0 12px;
  padding-bottom: 10px;
  border-bottom: 1px solid var(--border);
}

/* ---------------- Company bar ---------------- */
.company-bar {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  align-items: center;
}

select, input[type=text], input[type=number], input[type=email], input[type=password] {
  font-family: 'Inter', sans-serif;
  font-size: 14px;
  background: var(--surface);
  border: 1px solid var(--border);
  color: var(--ink);
  padding: 9px 12px;
  border-radius: 8px;
}
select:focus, input:focus {
  outline: none;
  border-color: var(--primary);
  box-shadow: 0 0 0 3px var(--primary-soft);
}
select { min-width: 220px; }
input[type=number] {
  width: 56px;
  font-family: 'IBM Plex Mono', monospace;
  text-align: right;
  padding: 9px 8px;
}

button {
  font-family: 'Inter', sans-serif;
  font-size: 14px;
  font-weight: 600;
  border: 1px solid var(--ink);
  background: var(--ink);
  color: #FFFFFF;
  padding: 9px 18px;
  border-radius: 8px;
  cursor: pointer;
  transition: background 0.12s ease, border-color 0.12s ease, transform 0.08s ease;
}
button:hover { background: var(--ink-soft); border-color: var(--ink-soft); }
button:active { transform: translateY(1px); }
button.stamp {
  background: var(--primary);
  border-color: var(--primary);
  color: #FFFFFF;
}
button.stamp:hover { background: var(--primary-hover); border-color: var(--primary-hover); }
button:disabled {
  opacity: 0.4;
  cursor: not-allowed;
}
button.quiet {
  background: transparent;
  color: var(--ink-soft);
  border-color: var(--border);
}
button.quiet:hover { background: var(--surface-alt); }
button.sell {
  background: transparent;
  color: var(--red);
  border-color: var(--red);
}
button.sell:hover { background: var(--red-soft); }
/* Solid, not outlined like .sell above -- reserved for the one
   action in this game that's actually irreversible (deleting a
   company and its account together, see settings.html), so it reads
   as more severe than an ordinary sell/cancel action at a glance. */
button.danger {
  background: var(--red);
  border-color: var(--red);
  color: #FFFFFF;
}
button.danger:hover { background: var(--red-hover); border-color: var(--red-hover); }

/* ---------------- Balance ---------------- */
.balance {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 12px;
  box-shadow: var(--shadow-sm);
  padding: 22px 24px;
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 10px;
}
.balance .label {
  font-size: 12px;
  font-weight: 600;
  color: var(--muted);
  letter-spacing: 0.06em;
  text-transform: uppercase;
}
.balance .figure {
  font-family: 'Space Grotesk', 'Inter', sans-serif;
  font-size: 32px;
  font-weight: 700;
  color: var(--ink);
}
.balance .company-name {
  font-style: normal;
  font-weight: 600;
  font-size: 15px;
  color: var(--ink-soft);
}

.stat-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 12px;
  box-shadow: var(--shadow-sm);
  padding: 4px 20px;
}

/* ---------------- Storage bar ---------------- */
.storage-bar-track {
  height: 8px;
  background: var(--border);
  border-radius: 4px;
  overflow: hidden;
  margin: 6px 0 4px;
}
.storage-bar-fill {
  height: 100%;
  background: var(--primary);
  border-radius: 4px;
  transition: width 0.2s ease;
}
.storage-bar-fill.full {
  background: var(--red);
}
.storage-label {
  display: flex;
  justify-content: space-between;
  font-size: 12px;
  color: var(--muted);
  font-family: 'IBM Plex Mono', monospace;
}

/* ---------------- Two column rows ---------------- */
.two-col {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 20px;
}
@media (max-width: 620px) {
  .two-col { grid-template-columns: 1fr; }
}
.two-col > div {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 12px;
  box-shadow: var(--shadow-sm);
  padding: 18px 20px;
}

.ledger-row {
  display: flex;
  justify-content: space-between;
  padding: 8px 2px;
  border-bottom: 1px solid var(--border);
  font-size: 14px;
}
.ledger-row:last-child { border-bottom: none; }
.ledger-row .amount { color: var(--green); font-weight: 600; }
.ledger-row .amount.negative { color: var(--red); }
.ledger-row .amount.zero { color: var(--muted); }

/* ---------------- Data table (genuine multi-column tables, e.g.
   Forecast's theoretical resource changes -- everywhere else in this
   app that shows a list of figures is a single value per row, which
   .ledger-row/.building-row already cover; this is for the rarer case
   of several numeric columns that actually need their own header) ---------------- */
.data-table {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 12px;
  box-shadow: var(--shadow-sm);
  padding: 4px 20px;
  overflow-x: auto;
}
.data-table table {
  width: 100%;
  border-collapse: collapse;
  font-size: 14px;
}
.data-table th {
  text-align: right;
  font-size: 11px;
  font-weight: 600;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.03em;
  padding: 10px 4px;
  border-bottom: 1px solid var(--border);
  white-space: nowrap;
}
.data-table th:first-child { text-align: left; }
.data-table td {
  text-align: right;
  padding: 8px 4px;
  border-bottom: 1px solid var(--border);
}
.data-table td:first-child {
  text-align: left;
  text-transform: capitalize;
  font-weight: 500;
}
.data-table tr:last-child td { border-bottom: none; }
.data-table .num { font-family: 'IBM Plex Mono', ui-monospace, monospace; font-variant-numeric: tabular-nums; }
.data-table .amount { color: var(--green); font-weight: 600; }
.data-table .amount.negative { color: var(--red); }
.data-table .amount.zero { color: var(--muted); }

.empty-note {
  color: var(--muted);
  font-style: normal;
  font-size: 13px;
  padding: 6px 2px;
}

/* ---------------- Compact bid/offer tables (the Market page's
   Your bids/Your offers/Bids/Offers lists) -- same visual language as
   .data-table's own table/th/td rules above, but without that
   component's own card chrome (background/border/shadow/padding):
   these tables already sit inside an already-carded container
   (#myBids/#myListings/#marketBids/#marketListings, or the .two-col
   column itself), so a second nested card border would just look like
   an accidental box inside a box. Exists so a page of active bids and
   offers reads as a dense, scannable book instead of a tall stack of
   one-row-per-card .building-rows. ---------------- */
.trade-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 13px;
}
.trade-table th {
  text-align: left;
  font-size: 11px;
  font-weight: 600;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.03em;
  padding: 8px 6px;
  border-bottom: 1px solid var(--border);
  white-space: nowrap;
}
.trade-table td {
  padding: 8px 6px;
  border-bottom: 1px solid var(--border);
  vertical-align: middle;
  text-transform: capitalize;
}
.trade-table tr:last-child td { border-bottom: none; }
.trade-table th.num, .trade-table td.num {
  text-align: right;
  font-family: 'IBM Plex Mono', ui-monospace, monospace;
  font-variant-numeric: tabular-nums;
  text-transform: none;
}
.trade-table td a { text-transform: none; }
.trade-table input[type="number"] {
  width: 68px;
  padding: 4px 6px;
}

/* ---------------- Buildings for sale / building rows ---------------- */
/* These list containers sit directly in a plain <section> (unlike
   #inventoryList/#buildingsOwnedList, which are already inside a
   carded .two-col column) so they get their own card treatment here. */
#buildingActivity, #resourceForecast, #myListings, #marketListings, #breakdownList, #warehouseUpgradeRow, #historyList, #historyChartContainer, #priceHistoryChartContainer, #buildingsTable, #resourcesTable, #bsBuildingsBreakdown, #bsResourcesBreakdown, #bsBondsBreakdown {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 12px;
  box-shadow: var(--shadow-sm);
  padding: 4px 20px;
}
.building-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 14px;
  padding: 14px 2px;
  border-bottom: 1px solid var(--border);
  flex-wrap: wrap;
}
.building-row:last-child { border-bottom: none; }
.building-info { flex: 1; min-width: 220px; }
.building-name {
  font-weight: 600;
  font-size: 15px;
  text-transform: capitalize;
  color: var(--ink);
}
.building-flow {
  font-size: 13px;
  color: var(--muted);
  margin-top: 2px;
}
.building-note {
  font-size: 12px;
  color: var(--red);
  margin-top: 4px;
  font-style: normal;
}
.building-cost {
  font-family: 'IBM Plex Mono', monospace;
  font-size: 14px;
  color: var(--ink-soft);
  min-width: 70px;
}
.building-controls {
  display: flex;
  gap: 8px;
  align-items: center;
}

/* ---------------- Building slot cards (Operations page) ---------------- */
.building-slots-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: 14px;
}
.slot-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 12px;
  box-shadow: var(--shadow-sm);
  padding: 16px;
  display: flex;
  flex-direction: column;
  min-height: 148px;
}
.slot-card .building-name { margin-bottom: 2px; }
.slot-card .building-flow { flex: 1; }
.slot-card.vacant {
  background: var(--surface-alt);
  border-style: dashed;
}
/* A MOTHBALLED slot: still owned, still on the grid, but shut down --
   producing nothing, paying no upkeep and employing nobody (see
   renderFilledSlotCard in operations.html). Muted and dashed like a
   vacant plot, because at a glance across fifty cards "this one isn't
   running" is the thing that has to read instantly; the badge says
   which KIND of not-running it is. */
.slot-card.mothballed {
  background: var(--surface-alt);
  border-style: dashed;
}
.slot-card.mothballed .building-name,
.slot-card.mothballed .building-flow {
  color: var(--muted);
}
.slot-mothball-badge {
  display: inline-block;
  margin-left: 6px;
  padding: 1px 7px;
  border-radius: 999px;
  background: var(--muted);
  color: #fff;
  font-size: 11px;
  font-weight: 700;
  text-transform: none;
  letter-spacing: 0;
  vertical-align: middle;
}
.slot-card .vacant-label {
  color: var(--muted);
  font-style: italic;
  text-transform: none;
}
.slot-level-badge {
  display: inline-block;
  font-size: 11px;
  font-weight: 700;
  text-transform: none;
  color: var(--primary);
  background: var(--primary-soft);
  border-radius: 6px;
  padding: 1px 7px;
  margin-left: 6px;
  vertical-align: middle;
  font-family: 'IBM Plex Mono', monospace;
}
.slot-card select {
  margin: 8px 0 4px;
  width: 100%;
  min-width: 0;
}
.slot-card-action {
  margin-top: 12px;
  padding-top: 12px;
  border-top: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.slot-card.vacant .slot-card-action {
  border-top: 1px dashed var(--border);
}

/* ---------------- Building picker (Operations page's "Choose a
   building" panel for a vacant slot -- see buildingPickerOverlay in
   operations.html) ---------------- */
.picker-overlay {
  position: fixed;
  inset: 0;
  background: rgba(16, 24, 40, 0.45);
  display: flex;
  align-items: flex-start;
  justify-content: center;
  padding: 48px 20px;
  z-index: 100;
}
.picker-panel {
  background: var(--surface);
  border-radius: 12px;
  box-shadow: var(--shadow-md);
  width: 100%;
  max-width: 640px;
  max-height: calc(100vh - 96px);
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
.picker-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 16px 20px;
  border-bottom: 1px solid var(--border);
}
.picker-header h3 {
  margin: 0;
  font-family: 'Space Grotesk', 'Inter', sans-serif;
  font-size: 18px;
  color: var(--ink);
}
.picker-close {
  background: transparent;
  border: none;
  color: var(--muted);
  font-size: 22px;
  line-height: 1;
  padding: 2px 8px;
  border-radius: 6px;
}
.picker-close:hover { color: var(--ink); background: var(--surface-alt); }
.picker-filters {
  display: flex;
  gap: 8px;
  padding: 14px 20px;
  border-bottom: 1px solid var(--border);
  flex-wrap: wrap;
}
.picker-filters input[type=text] { flex: 1; min-width: 160px; }
.picker-filters select { min-width: 160px; }
.picker-list {
  overflow-y: auto;
  padding: 4px 20px;
}
/* Each match is a full-width <button>, not a <div onclick>, so the
   list stays keyboard- and screen-reader-navigable -- the generic
   `button` rule earlier in this file gives every button a solid
   dark background/border by default, which reads wrong for a plain
   list row, so every one of those is explicitly undone here rather
   than relying on a new, one-off button variant. */
.picker-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 14px;
  width: 100%;
  padding: 12px 2px;
  border: none;
  border-bottom: 1px solid var(--border);
  border-radius: 0;
  background: none;
  color: inherit;
  font: inherit;
  text-align: left;
  cursor: pointer;
}
.picker-row:last-child { border-bottom: none; }
/* Why a row is in the results when its own NAME didn't match the search
   -- "produces steel", "consumes grain", or the industry it's in (see
   matchPickerBuilding in operations.html). Deliberately not
   .building-note, which is the red "this won't run" warning used on the
   Forecast page: this is an explanation, not a caution. */
.picker-match-reason {
  font-size: 12px;
  color: var(--muted);
  margin-top: 2px;
  font-style: italic;
}

.picker-row:hover { background: var(--surface-alt); }
.picker-row:active { transform: none; }

/* ---------------- Calculated-value tooltips ---------------- */
/* A small hover/focus "pop-up bubble" attached to any on-screen figure
   that's actually computed from a formula rather than read straight
   off the server as a plain stored value -- see calcTip() in
   shared.js for how these get built (one <span class="calc-tip"> per
   figure, wrapping both the figure itself and its own hidden
   .calc-tip-bubble). A dotted underline plus `cursor: help` is the
   same "there's more here" affordance a native title="" attribute
   would give for free, but styled to match this app's own
   palette/typography instead of the browser's own plain, slow-to-
   appear default tooltip, and with a deliberately generous
   max-width/line-height since a formula is often a full short
   equation, not a one-word label.
   `tabindex="0"` on .calc-tip (set in calcTip() itself, not here) is
   what makes :focus below reachable by keyboard, not just a mouse --
   this app has no other way to "hover" without one. */
.calc-tip {
  position: relative;
  display: inline-block;
  border-bottom: 1px dotted var(--muted);
  cursor: help;
}
.calc-tip-bubble {
  display: none;
  position: absolute;
  left: 50%;
  bottom: calc(100% + 9px);
  transform: translateX(-50%);
  width: max-content;
  min-width: 200px;
  max-width: 300px;
  padding: 9px 11px;
  background: var(--ink);
  color: #fff;
  font-family: 'IBM Plex Mono', ui-monospace, monospace;
  font-size: 12px;
  line-height: 1.6;
  font-weight: 400;
  text-transform: none;
  letter-spacing: normal;
  border-radius: 8px;
  box-shadow: var(--shadow-md);
  z-index: 60;
  white-space: normal;
  text-align: left;
  pointer-events: none;
}
/* The small triangle pointing from the bubble down at the figure it
   describes -- a plain CSS-border triangle, the same technique
   .notification-panel and every other popover in this app that needs
   one would use, just not needed anywhere else yet. */
.calc-tip-bubble::after {
  content: '';
  position: absolute;
  top: 100%;
  left: 50%;
  transform: translateX(-50%);
  border: 5px solid transparent;
  border-top-color: var(--ink);
}
.calc-tip:hover .calc-tip-bubble,
.calc-tip:focus .calc-tip-bubble,
.calc-tip:focus-within .calc-tip-bubble {
  display: block;
}
/* Bubble contents are plain sentences/labels as often as they're a
   monospaced equation (see calcTip() callers), so the equation-only
   assumption above is loosened per-line by this modifier rather than
   forcing every caller's explanatory text into monospace too. */
.calc-tip-bubble .calc-tip-note {
  display: block;
  margin-top: 6px;
  font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  color: #D0D5DD;
  font-size: 11px;
  line-height: 1.5;
}

/* ---------------- Messages ---------------- */
.banner {
  padding: 12px 16px;
  border-radius: 8px;
  font-size: 14px;
  margin-bottom: 16px;
  border: 1px solid transparent;
}
.banner.error {
  background: var(--red-soft);
  border-color: #FDA29B;
  color: var(--red-hover);
}
.banner.ok {
  background: var(--green-soft);
  border-color: #A6F4C5;
  color: var(--green);
}

.empty-state {
  text-align: center;
  color: var(--muted);
  font-style: normal;
  padding: 40px 10px;
  background: var(--surface);
  border: 1px dashed var(--border);
  border-radius: 12px;
}

footer {
  text-align: center;
  margin-top: 40px;
  color: var(--muted);
  font-size: 12px;
}

/* ---------------------------------------------------------------------
   Achievements (achievements.html, and the public profile's copy):
   locked cards are greyed out, unlocked ones are shown in full colour.
   --------------------------------------------------------------------- */
.achievement-summary {
  display: flex;
  gap: 24px;
  flex-wrap: wrap;
  font-size: 13px;
  color: var(--muted);
}
.achievement-summary strong { color: var(--ink); font-size: 18px; font-family: 'Space Grotesk', sans-serif; }
.achievement-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: 12px;
  margin-top: 8px;
}
.achievement-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-left: 4px solid var(--green);
  border-radius: 10px;
  padding: 12px 14px;
  box-shadow: var(--shadow-sm);
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.achievement-card .achievement-head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 8px;
}
.achievement-card .achievement-name {
  font-family: 'Space Grotesk', sans-serif;
  font-weight: 600;
  font-size: 15px;
  color: var(--ink);
}
.achievement-card .achievement-bonus {
  font-family: 'IBM Plex Mono', monospace;
  font-size: 13px;
  font-weight: 600;
  color: var(--green);
  white-space: nowrap;
}
.achievement-card .achievement-description { font-size: 13px; color: var(--ink-soft); }
.achievement-card .achievement-status { font-size: 12px; color: var(--green); font-weight: 500; }
.achievement-card.locked {
  border-left-color: var(--border);
  background: var(--surface-alt);
  opacity: 0.55;
  filter: grayscale(1);
  box-shadow: none;
}
.achievement-card.locked .achievement-status { color: var(--muted); font-weight: 400; }
.achievement-progress-track {
  height: 5px;
  background: var(--border);
  border-radius: 3px;
  overflow: hidden;
}
.achievement-progress-fill { height: 100%; background: var(--primary); }
/* ---------------- Tutorial (tutorial.html, plus the coach strip and
   "show me" highlight shared.js adds to other pages) ---------------- */
.tutorial-coach {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 10px 14px;
  background: var(--primary-soft);
  border: 1px solid #C7D2FE;
  border-radius: 10px;
  padding: 10px 14px;
  margin-bottom: 16px;
  font-size: 14px;
}
.tutorial-coach-label {
  color: var(--primary);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}
.tutorial-coach-open { margin-left: auto; font-weight: 600; }
.tutorial-coach button { padding: 4px 10px; font-size: 12px; }
.tutorial-highlight {
  outline: 3px solid var(--primary);
  outline-offset: 6px;
  border-radius: 12px;
}
.tutorial-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 12px;
  box-shadow: var(--shadow-sm);
  padding: 20px 24px;
}
.tutorial-card h3 {
  font-family: 'Space Grotesk', 'Inter', sans-serif;
  font-size: 20px;
  margin: 0 0 12px;
}
.tutorial-card p { line-height: 1.6; margin: 0 0 10px; color: var(--ink-soft); }
.tutorial-rewards {
  margin: 14px 0;
  padding: 10px 14px;
  background: var(--surface-alt);
  border: 1px solid var(--border);
  border-radius: 8px;
  font-size: 13px;
}
.tutorial-rewards div + div { margin-top: 4px; }
.tutorial-reward-earned { color: var(--green); font-weight: 600; }
.tutorial-actions { display: flex; flex-wrap: wrap; gap: 10px; align-items: center; margin-top: 16px; }
a.tutorial-action {
  display: inline-block;
  background: var(--primary);
  color: #FFFFFF;
  font-weight: 600;
  font-size: 14px;
  padding: 9px 18px;
  border-radius: 8px;
}
a.tutorial-action:hover { background: var(--primary-hover); text-decoration: none; }
.tutorial-wait {
  margin: 14px 0;
  padding: 14px 16px;
  border: 1px dashed #C7D2FE;
  border-radius: 8px;
  background: var(--primary-soft);
}
.tutorial-countdown {
  font-family: 'IBM Plex Mono', ui-monospace, monospace;
  font-size: 24px;
  font-weight: 600;
  color: var(--ink);
}
.tutorial-preview { margin-top: 10px; font-size: 13px; color: var(--ink-soft); line-height: 1.6; }
.tutorial-steps { list-style: none; margin: 0; padding: 0; }
.tutorial-steps li {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 9px 2px;
  border-bottom: 1px solid var(--border);
  font-size: 14px;
}
.tutorial-steps li.upcoming { color: var(--muted); }
.tutorial-steps li.current { font-weight: 600; }
.tutorial-step-marker {
  flex-shrink: 0;
  width: 24px;
  height: 24px;
  border-radius: 50%;
  border: 1px solid var(--border);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 12px;
}
.tutorial-steps li.done .tutorial-step-marker { background: var(--green-soft); border-color: #A6F4C5; color: var(--green); }
.tutorial-steps li.current .tutorial-step-marker { background: var(--primary); border-color: var(--primary); color: #FFFFFF; }
.tutorial-topic + .tutorial-topic { margin-top: 12px; }
.tutorial-topic.read { opacity: 0.7; }

/* ---------------- Touch and small-screen sizing ----------------
   Measured on a 375x812 viewport before this existed: the top nav's
   links and dropdown toggles rendered 30px tall (one at 17px), 10-13
   controls a page under 32px, against the 44px that touch guidance
   asks for -- on the single most-used control in the app, on all 25
   pages. And 35 leaf elements on the Head Office page computed under
   12px, most of them the explanatory notes under each figure, which
   is the text a new player most needs and the hardest size to read it
   at.

   Both are scoped to the breakpoint rather than changed outright: the
   desktop sizes are deliberate and dense, and a pointer can hit a
   30px target perfectly well. This only widens things where the input
   is a fingertip.

   620px matches .two-col's own breakpoint above rather than inventing
   a second one, so the layout has one place where "narrow" begins. */
@media (max-width: 620px) {
  /* 44px total height: 13px text on a ~18px line, plus 13px of padding
     each side. Hit area only -- the visual weight is unchanged. */
  .page-nav > a,
  .nav-group-toggle {
    padding: 13px 12px;
    min-height: 44px;
    display: inline-flex;
    align-items: center;
  }
  .nav-group-menu a {
    padding: 12px 14px;
    min-height: 44px;
    display: flex;
    align-items: center;
  }

  /* The other standalone controls a thumb actually goes for: the
     notification bell (27px), the tutorial coach's "Open tutorial"
     (17px) and its "Hide" (23px).

     Inline links inside a sentence are deliberately NOT included --
     "Buy or sell buildings", "Manage your conglomerate" and the like
     sit in running prose, and padding them to 44px would break the
     line box they live in. The rule is for controls that stand on
     their own, not every anchor on the page. */
  .notification-bell-btn,
  button.quiet,
  .tutorial-coach-open {
    min-height: 44px;
    padding-top: 10px;
    padding-bottom: 10px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
  }

  /* Floor PROSE at 12px on a phone -- text a player reads, rather than
     everything under 12px. Measured on the Head Office page at 375px,
     35 leaf elements computed under 12px, and looking at what they
     actually were changed the fix:

       notification-time      20  timestamps -- prose, floored below
       slot-level-badge       12  "Lv 3" chips
       notification-badge      1  the bell's unread count
       tutorial-coach-label    1  "TUTORIAL - STEP 8 OF 10" -- floored

     The badges are deliberately left alone. A count bubble and a level
     chip are glanced at, not read, and 11px is a normal size for one;
     enlarging them would push the layout around for no reading
     benefit. Flooring everything under 12px would have been the easy
     rule and the wrong one. */
  body { font-size: 15px; }
  /* Matching .notification-item .notification-time's own specificity
     (line ~301) -- a media query adds none of its own, so a bare
     .notification-time here loses to it and silently does nothing. */
  .notification-item .notification-time,
  .tutorial-coach-label,
  .calc-tip-note,
  .empty-note,
  .tick-footer,
  small { font-size: 12px; }
}
