/* Procyon Sector — navigable map.
 *
 * Visual language follows the Scum & Villainy sourcebook: black ink on white
 * paper. High-contrast comic inking — solid spot blacks, hard contours,
 * hatching for tone, NO gradients and no soft shadows. The sector map in the
 * book is a line-art blueprint, so that is what this is.
 *
 * Three zoom levels share one stage: sector -> system -> location.
 */

:root {
  /* Shared by the location index and the faction list — one set of values so
     the two columns stay visually identical. Tuned so the index's 30 rows fit
     between the header and the footer without scrolling. */
  --menu-font: .74vmin;
  --menu-pad-y: .35vmin;
  --menu-pad-x: .64vmin;
  --menu-gap: .56vmin;
  --menu-w: 13.5vmin;

  --paper:     #f4f1e9;   /* aged newsprint, not pure white */
  --ink:       #10100e;
  --ink-soft:  #45443f;
  --ink-faint: #8d8b83;
  --rule:      #10100e;
  --accent:    #b0201c;   /* the single spot colour, used sparingly */
  --font:      'Segoe UI', system-ui, -apple-system, sans-serif;
  --mono:      ui-monospace, 'SFMono-Regular', Menlo, monospace;
  --ease:      cubic-bezier(.65, .02, .25, 1);
  --dur:       1100ms;
}

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

html, body {
  height: 100%;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font);
  overflow: hidden;
  -webkit-font-smoothing: antialiased;
}

/* ---------------------------------------------------------------- viewport */

#viewport { position: fixed; inset: 0; }

/* The single SVG. Everything is inside it; the camera is its viewBox. */
#world {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  display: block;
  /* --detail rises 0 -> 1 as the camera closes on a system; --sector is its
     inverse. Both are written by applyCam(). */
  --detail: 0;
  --sector: 1;
  --txt: 1;   /* camera-span / system-span, keeps chart text legible */
}

/* ------------------------------------------------------------ paper ground */

.stars { position: absolute; inset: 0; pointer-events: none; }
.stars-1 {
  background-image:
    radial-gradient(.8px .8px at 20% 30%, rgba(16,16,14,.16) 50%, transparent 51%),
    radial-gradient(.7px .7px at 70% 60%, rgba(16,16,14,.13) 50%, transparent 51%),
    radial-gradient(.9px .9px at 45% 80%, rgba(16,16,14,.10) 50%, transparent 51%);
  background-size: 190px 190px, 140px 140px, 260px 260px;
  opacity: .8;
}
.stars-2 {
  background: radial-gradient(ellipse 78% 74% at 50% 50%, transparent 62%, rgba(16,16,14,.07) 100%);
}
.stars-3 { display: none; }

.nebula { position: absolute; inset: 0; pointer-events: none; }
.nebula.has-image { background-size: cover;
  background-position: center; opacity: .18; filter: grayscale(1) contrast(1.5);
  mix-blend-mode: multiply; }

/* ------------------------------------------------------------------- lanes */

.lane {
  fill: none;
  stroke: var(--ink);
  stroke-width: 1.4;
  vector-effect: non-scaling-stroke;
  stroke-dasharray: 2 3.4;
  stroke-linecap: round;
  opacity: .5;
  animation: lane-crawl 6s linear infinite;
}
.lane-open     { stroke: var(--ink); }
.lane-core     { stroke: var(--ink); stroke-dasharray: 2 2.4; }
.lane-unstable { stroke: var(--accent); stroke-dasharray: 3.4 3; opacity: .65; }
.lane-sealed   { stroke: var(--ink-faint); stroke-dasharray: 1 4; animation: none; opacity: .4; }
.lane-active   { opacity: 1; stroke-width: 2.4; }
@keyframes lane-crawl { to { stroke-dashoffset: -10.8; } }

/* Lane captions belong to the sector reading; they fade as you close in. */
.lane-label {
  fill: var(--ink);
  font-family: var(--mono);
  font-size: calc(1.4px * var(--txt));
  font-weight: 700;
  letter-spacing: calc(.12px * var(--txt));
  text-anchor: middle;
  text-transform: uppercase;
  opacity: var(--sector);
  transition: opacity 400ms var(--ease);
  paint-order: stroke;
  stroke: var(--paper); stroke-width: calc(.5px * var(--txt)); stroke-linejoin: round;
  pointer-events: none;
}

/* ----------------------------------------------------------------- systems */

/* Star and name plate are always readable. */
.o-star-halo { fill: var(--paper); }
.o-star-body { fill: var(--ink); stroke: var(--ink); stroke-width: 1;
               vector-effect: non-scaling-stroke; }
.sys-star-g { cursor: pointer; }
.sys-star-g:hover .o-star-body { stroke-width: 4; }

.sys-name {
  fill: var(--ink);
  font-family: var(--mono);
  font-size: calc(2.8px * var(--txt)); font-weight: 700;
  /* Name sits well above the star, further up than the tag. */
  transform: translateY(calc(-5.5px * var(--txt)));
  letter-spacing: calc(.55px * var(--txt));
  text-anchor: middle;
  text-transform: uppercase;
  paint-order: stroke;
  stroke: var(--paper); stroke-width: calc(.9px * var(--txt)); stroke-linejoin: round;
  pointer-events: none;
}
.sys-tag {
  fill: var(--ink-soft);
  font-family: var(--mono);
  font-size: calc(1.35px * var(--txt));
  /* Tag sits between name and star, offset down from the name. */
  transform: translateY(calc(-2.5px * var(--txt)));
  letter-spacing: calc(.2px * var(--txt));
  text-anchor: middle;
  text-transform: uppercase;
  opacity: var(--sector);
  transition: opacity 400ms var(--ease);
  paint-order: stroke;
  stroke: var(--paper); stroke-width: calc(.5px * var(--txt)); stroke-linejoin: round;
  pointer-events: none;
}

/* Orbits, bodies and gates only exist once the camera is close. Fading them
   by opacity means no scene swap — the same nodes are always present. */
.sys-detail,
.orbit-layer .o-body {
  opacity: var(--detail);
  transition: opacity 500ms var(--ease);
  pointer-events: var(--detail-pe, none);
}
body.in-system .sys-detail,
body.in-system .orbit-layer .o-body { pointer-events: auto; }
/* Star and its clickable hit target stay fully visible + interactive. */
.orbit-layer .sys-star-g { opacity: 1; pointer-events: auto; }

.o-ring {
  fill: none; stroke: var(--ink); stroke-width: 1;
  vector-effect: non-scaling-stroke; opacity: .5;
}
.o-ring-faint { stroke-dasharray: 3 3.4; opacity: .34; }
/* Asteroid belt: heavy dashed ring on its orbit — the visualisation IS the body. */
.o-belt-ring {
  stroke-width: 2.4;
  stroke-dasharray: 1 2 4 2;
  opacity: .85;
}
.o-moon-ring  { opacity: .28; stroke-dasharray: 1.6 2.4; }

.o-body { cursor: pointer; }
.o-globe { stroke: var(--ink); stroke-width: 1.4; vector-effect: non-scaling-stroke; }
.o-nostroke { stroke: none; }
.o-term  { fill: var(--ink); opacity: .92; stroke: none; pointer-events: none; }
.o-nebula { stroke-dasharray: 3 2.6; }
.o-ring-body { fill: none; stroke: var(--ink); stroke-width: 1.2;
               vector-effect: non-scaling-stroke; }
.o-art { opacity: .95; filter: grayscale(1) contrast(1.9); }
.o-hit { fill: transparent; stroke: none; }
.o-body:hover .o-globe { stroke-width: 3; }

.o-label {
  fill: var(--ink); font-family: var(--mono);
  font-size: 1.5px; font-weight: 700; letter-spacing: .16px;
  text-anchor: middle; text-transform: uppercase;
  paint-order: stroke; stroke: var(--paper); stroke-width: .55px;
  stroke-linejoin: round; pointer-events: none;
}
.o-label-sm { font-size: 1.2px; }
.o-tag {
  fill: var(--ink-soft); font-family: var(--mono);
  font-size: 1.1px; letter-spacing: .09px;
  text-anchor: middle; text-transform: uppercase;
  paint-order: stroke; stroke: var(--paper); stroke-width: .42px;
  stroke-linejoin: round; pointer-events: none;
}

/* Gateways: the printed map's target reticle, on the system rim. */
.o-gate-ring { fill: none; stroke: var(--ink); stroke-width: 1.4;
               vector-effect: non-scaling-stroke; }
.o-gate-hair { stroke: var(--ink); stroke-width: 1; vector-effect: non-scaling-stroke; }
.o-gate-pip  { fill: var(--ink); }
.o-gate-label {
  fill: var(--ink); font-family: var(--mono);
  font-size: 1.35px; font-weight: 700; letter-spacing: .2px;
  text-anchor: middle; text-transform: uppercase;
  paint-order: stroke; stroke: var(--paper); stroke-width: .5px;
  stroke-linejoin: round; pointer-events: none;
}
.o-gate-image { filter: grayscale(1) contrast(1.6); pointer-events: none; }
.o-gate-linked { cursor: pointer; }
.o-gate-linked:hover .o-gate-ring { stroke-width: 3; }
.o-gate-linked:hover .o-gate-image { filter: grayscale(1) contrast(1.9) drop-shadow(0 0 3px var(--ink)); }
.o-gate-unstable .o-gate-ring { stroke: var(--accent); stroke-dasharray: 3 2.4; }
.o-gate-unstable .o-gate-pip  { fill: var(--accent); }
.o-gate-unstable .o-gate-label { fill: var(--accent); }
.o-gate-sealed .o-gate-ring { stroke-dasharray: 1.4 3; opacity: .55; }
.o-gate-sealed .o-gate-hair, .o-gate-sealed .o-gate-pip { opacity: .45; }
.o-gate-core .o-gate-ring { stroke-width: 2.4; }


/* When a body has real art loaded, hide the CSS-drawn fallback shape,
   fake terminator, and gas-giant ring — the image is the truth now.
   Keep the contour ring around the limb so the disc still reads on paper. */
.o-body.has-art .o-globe { fill: none; }
.o-body.has-art .o-term  { display: none; }
.o-body.has-art .o-ring-body { display: none; }
.o-body.has-art .o-nostroke { display: none; }



/* ---------------------------------------------------------- location view */

#location-view {
  position: fixed; inset: 0;
  opacity: 0; pointer-events: none;
  background: var(--paper);
  /* Overlaps the tail of the dive zoom, so the chart is still rushing in as
     the surface view resolves. */
  transition: opacity 760ms cubic-bezier(.3, 0, .2, 1);
  z-index: 40;
}
#location-view.active { opacity: 1; pointer-events: auto; }

/* Art is pushed toward inked line work to match the book plates. */
.loc-image {
  position: absolute; inset: 0;
  background-size: cover; background-position: center;
  filter: grayscale(1) contrast(1.75) brightness(1.06);
  transform: scale(1.06);
  transition: transform 12s linear;
}
#location-view.active .loc-image { transform: scale(1); }
.loc-image::after {
  content: ''; position: absolute; inset: 0;
  background: linear-gradient(180deg,
    rgba(244,241,233,.55) 0%, rgba(244,241,233,.06) 30%,
    rgba(244,241,233,.72) 70%, rgba(244,241,233,.97) 100%);
}

/* The body FLOWS below a fixed backdrop rather than pinning to the bottom:
   with the sourcebook details inline the text can be long, and the view
   scrolls on every width. Tail padding keeps the last lines clear of the
   corner buttons. */
.loc-body {
  position: relative; z-index: 1;
  margin: 52vh 5vmin 0 22vmin;
  padding: 4vmin 5vmin 12vmin;
  max-width: 64rem;
}
#location-view.active { overflow-y: auto; }
#location-view .loc-image { position: fixed; }
.loc-kicker {
  display: inline-block; padding: .2vmin .6vmin;
  font-family: var(--mono); font-size: 1vmin; font-weight: 700;
  letter-spacing: .3em; text-transform: uppercase;
  color: var(--paper); background: var(--ink);
}
.loc-title {
  font-family: var(--mono);
  font-size: 5.6vmin; font-weight: 700; letter-spacing: .02em;
  text-transform: uppercase;
  margin: .8vmin 0 1.2vmin;
  border-bottom: max(2px, .3vmin) solid var(--ink);
  display: inline-block; padding-bottom: .4vmin;
}
.loc-text { font-size: 1.8vmin; line-height: 1.6; color: var(--ink); max-width: 46rem; }
.loc-link {
  display: inline-block; margin-top: 2.4vmin;
  font-family: var(--mono); font-size: 1.15vmin; font-weight: 700;
  letter-spacing: .18em; text-transform: uppercase;
  color: var(--paper); background: var(--ink);
  padding: .9vmin 1.8vmin; text-decoration: none;
  border: max(1px, .14vmin) solid var(--ink);
  transition: background 200ms, color 200ms;
}
.loc-link:hover { background: var(--paper); color: var(--ink); }

/* Placeholder: a drafting hatch, in keeping with the blueprint look. */
.loc-placeholder {
  position: absolute; inset: 0;
  display: grid; place-items: center;
  font-family: var(--mono); font-size: 1.25vmin; font-weight: 700;
  letter-spacing: .24em; text-transform: uppercase; color: var(--ink-faint);
  background:
    repeating-linear-gradient(45deg,
      transparent 0 2.4vmin, rgba(16,16,14,.06) 2.4vmin 4.8vmin);
}

/* -------------------------------------------------------------------- HUD */

#hud { position: fixed; inset: 0; pointer-events: none; z-index: 50; }

.hud-top {
  position: absolute; top: 0; left: 0; right: 0;
  padding: 2.2vmin 3vmin 1.6vmin;
  display: flex; align-items: baseline; gap: 1.4vmin;
  border-bottom: max(1px, .16vmin) solid var(--ink);
  background: var(--paper);
}
.hud-title {
  font-family: var(--mono); font-size: 1.7vmin; font-weight: 700;
  letter-spacing: .4em; text-transform: uppercase;
}
.hud-sub {
  font-family: var(--mono); font-size: 1vmin;
  letter-spacing: .16em; color: var(--ink-soft); text-transform: uppercase;
}

#breadcrumb {
  /* Sits left of the SV/EN/debug/About row; the clearance has to cover all
     four of those buttons, not just the language ones. */
  position: absolute; top: 2vmin; right: 26vmin;
  display: flex; gap: .4vmin; align-items: center;
  pointer-events: auto;
}
.crumb {
  /* Same metrics as the header buttons so the whole top row reads level. */
  font-family: var(--mono); font-size: .85vmin; font-weight: 700;
  letter-spacing: .12em; text-transform: uppercase;
  color: var(--ink); cursor: pointer;
  border: max(1px, .14vmin) solid var(--ink);
  padding: .45vmin .75vmin;
  background: var(--paper);
  transition: background 180ms, color 180ms;
}
.crumb:hover, .crumb.current { background: var(--ink); color: var(--paper); }
.crumb-sep { color: var(--ink-faint); }

/* No container: the labels sit straight on the map like the faction pills,
   each its own box. Only the boxes take pointer events, so the map stays
   draggable through the gaps between them. */
#index {
  /* Same top edge and box metrics as the panel column once opposite it. */
  position: fixed; left: 3vmin; top: 12vmin;
  pointer-events: none;
  display: flex; flex-direction: column; align-items: stretch;
  gap: var(--menu-gap);
  width: var(--menu-w);
  z-index: 15;
}
/* The head and items are <button>/<span>; clear the UA defaults so they
   inherit the panel's ink-on-paper treatment. */
.index-head, .index-item {
  pointer-events: auto;
  appearance: none; -webkit-appearance: none;
  font: inherit; line-height: 1.25;
  border-radius: 0;
}

/* The index mirrors the faction sidebar: the system name is a solid black
   chip that doubles as the system-view link, and each location below it is
   its own outlined white box. */
.index-group {
  display: flex; flex-direction: column; align-items: stretch;
  gap: var(--menu-gap);
}
.index-group + .index-group { margin-top: .9vmin; }
.index-head {
  font-family: var(--mono); font-size: var(--menu-font); font-weight: 700;
  letter-spacing: .24em; text-transform: uppercase;
  color: var(--paper); background: var(--ink);
  border: max(1px, .12vmin) solid var(--ink);
  padding: var(--menu-pad-y) var(--menu-pad-x);
  text-align: left; cursor: pointer;
  transition: background 160ms, color 160ms;
}
.index-head:hover { background: var(--paper); color: var(--ink); }
.index-item {
  /* Same metrics as .faction-pill so the two columns read as a matched pair. */
  display: block;
  font-family: var(--mono); font-size: var(--menu-font); font-weight: 700;
  letter-spacing: .1em; text-transform: uppercase;
  color: var(--ink); background: var(--paper);
  border: max(1px, .12vmin) solid var(--ink);
  padding: var(--menu-pad-y) var(--menu-pad-x);
  text-align: left; cursor: pointer;
  transition: background 160ms, color 160ms;
}
.index-item:hover { background: var(--ink); color: var(--paper); }


@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
  }
}

@media (max-width: 760px) {
  #index { display: none; }
  .loc-title { font-size: 8vmin; }
  .loc-text  { font-size: 3.2vmin; }
  .system-name { font-size: 3vmin; }
}


/* Language switcher — three small ink buttons in the header. */
#lang-switch {
  position: absolute; top: 2vmin; right: 3vmin;
  display: flex; gap: .3vmin;
  pointer-events: auto;
  z-index: 60;
}
#lang-switch button {
  font-family: var(--mono);
  font-size: .85vmin; font-weight: 700;
  letter-spacing: .12em; text-transform: uppercase;
  color: var(--ink); background: var(--paper);
  border: max(1px, .14vmin) solid var(--ink);
  padding: .45vmin .75vmin; cursor: pointer;
  min-width: 3.4vmin;
  transition: background 160ms, color 160ms;
}
#lang-switch button:hover { background: var(--ink); color: var(--paper); }
#lang-switch button.current { background: var(--ink); color: var(--paper); }

/* The hamburger exists only for phones; the mobile block reveals it. */
#menu-btn[hidden] { display: none; }
/* Likewise the menu copy of Import/Export — the desktop has the corner one. */
#share-btn-menu { display: none; }

/* About sits in the same row as the language buttons and inherits their
   styling from #lang-switch button; it just needs a little separation and
   must not take the .current highlight. */
#about-btn { margin-left: .9vmin; }
#about-panel[hidden] { display: none; }
.about-links { margin: .4rem 0 1.05rem; padding-left: 1.4rem; }
.about-links li { margin: 0 0 .3rem; }
.about-links a { color: var(--ink); text-decoration: underline; }
.about-links a:hover { background: var(--ink); color: var(--paper); }


/* Location "Details" button — sits alongside the article link. */
.loc-actions { display: flex; gap: 1.4vmin; align-items: center; margin-top: 2vmin; }
.loc-info-btn {
  font-family: var(--mono); font-size: 1.15vmin; font-weight: 700;
  letter-spacing: .18em; text-transform: uppercase;
  color: var(--ink); background: transparent;
  border: max(1px, .14vmin) solid var(--ink);
  padding: .9vmin 1.8vmin; cursor: pointer;
}
.loc-info-btn:hover { background: var(--ink); color: var(--paper); }

/* Lore overlay: a centred cream-paper card over the surface. */
.loc-info-panel {
  position: fixed; inset: 0;
  display: grid; place-items: center;
  background: rgba(16, 16, 14, .55);
  z-index: 60;
  animation: loc-info-fade 260ms var(--ease);
}
.loc-info-panel[hidden] { display: none; }
@keyframes loc-info-fade { from { opacity: 0; } to { opacity: 1; } }
.loc-info-content {
  background: var(--paper);
  color: var(--ink);
  padding: 5vmin 5.5vmin 4vmin;
  border: max(1px, .16vmin) solid var(--ink);
  max-width: 46rem; max-height: 78vh;
  overflow-y: auto;
  box-shadow: 0 0 4vmin rgba(16,16,14,.4);
  font-size: 1.8vmin; line-height: 1.6;
  scrollbar-width: thin;
  scrollbar-color: var(--ink) var(--paper);
}
.loc-info-content p { margin: 0 0 1.05rem; }
.loc-info-content p:last-child { margin-bottom: 0; }
.loc-info-close {
  position: absolute; top: 3vmin; right: 3vmin;
  width: 4vmin; height: 4vmin;
  font-family: var(--mono); font-size: 2.4vmin; font-weight: 700;
  color: var(--paper); background: var(--ink);
  border: max(1px, .14vmin) solid var(--ink);
  cursor: pointer; z-index: 61;
  display: grid; place-items: center;
  line-height: 1;
}
.loc-info-close:hover { background: var(--paper); color: var(--ink); }


.factions-title {
  font-family: var(--mono); font-size: var(--menu-font); font-weight: 700;
  letter-spacing: .24em; text-transform: uppercase;
  color: var(--paper); background: var(--ink);
  border: max(1px, .12vmin) solid var(--ink);
  padding: var(--menu-pad-y) var(--menu-pad-x);
  margin-bottom: .2vmin;
}
.faction-pill {
  font-family: var(--mono); font-size: var(--menu-font); font-weight: 700;
  letter-spacing: .1em; text-transform: uppercase;
  color: var(--ink); background: var(--paper);
  border: max(1px, .12vmin) solid var(--ink);
  padding: var(--menu-pad-y) var(--menu-pad-x);
  text-align: left; cursor: pointer;
  transition: background 160ms, color 160ms;
}
.faction-pill:hover { background: var(--ink); color: var(--paper); }

/* Faction info panel — overlay showing the selected faction's blurb. */
.faction-info-panel {
  position: fixed; inset: 0;
  display: grid; place-items: center;
  background: rgba(16,16,14,.55);
  z-index: 55;
  animation: loc-info-fade 260ms var(--ease);
}
.faction-info-panel[hidden] { display: none; }
.faction-info-content {
  background: var(--paper);
  color: var(--ink);
  padding: 4vmin 4.5vmin 3vmin;
  border: max(1px, .16vmin) solid var(--ink);
  max-width: 34rem;
  box-shadow: 0 0 4vmin rgba(16,16,14,.4);
  font-size: 1.8vmin; line-height: 1.6;
}
.faction-info-content h3 {
  font-family: var(--mono); font-size: 1.6vmin; font-weight: 700;
  letter-spacing: .12em; text-transform: uppercase;
  margin: 0 0 1.5vmin;
  padding-bottom: .6vmin;
  border-bottom: max(1px, .16vmin) solid var(--ink);
}
.faction-info-content p { margin: 0; }

/* A full faction article is much longer than the one-line blurb this panel
   originally held, so it scrolls within the viewport and sets its sections
   off with small mono headings. */
.faction-info-content {
  max-height: 78vh;
  overflow-y: auto;
}
.faction-meta {
  font-family: var(--mono); font-size: 1.3vmin;
  letter-spacing: .1em; text-transform: uppercase;
  opacity: .62; margin: -.8vmin 0 1.4vmin;
}
.faction-intro { margin: 0 0 1.8vmin; font-style: italic; }
.faction-sec { margin: 0 0 1.6vmin; }
.faction-sec:last-child { margin-bottom: 0; }
.faction-sec h4 {
  font-family: var(--mono); font-size: 1.25vmin; font-weight: 700;
  letter-spacing: .14em; text-transform: uppercase;
  opacity: .68; margin: 0 0 .4vmin;
}
.faction-sec p { margin: 0 0 .5vmin; }
.faction-sec ul { margin: 0; padding-left: 2.2vmin; }
.faction-sec li { margin: 0 0 .4vmin; }

/* Cross-links to the other systems a faction operates in. */
.faction-links { border-top: max(1px,.14vmin) solid rgba(16,16,14,.25);
                 padding-top: 1.2vmin; }
.faction-elsewhere {
  font-family: var(--mono); font-size: 1.35vmin; letter-spacing: .1em;
  text-transform: uppercase;
  background: none; color: var(--ink); cursor: pointer;
  border: max(1px, .14vmin) solid var(--ink);
  padding: .5vmin 1.1vmin; margin: 0 .6vmin .6vmin 0;
}
.faction-elsewhere:hover { background: var(--ink); color: var(--paper); }

/* Sector-wide factions are listed under their own heading at the bottom. */
.factions-subtitle {
  font-family: var(--mono); font-size: var(--menu-font); font-weight: 700;
  letter-spacing: .14em; text-transform: uppercase;
  opacity: .55; margin: .9vmin 0 0;
}

/* Notables list inside a body's details panel. */
.loc-info-content ul { margin: .4vmin 0 0; padding-left: 2.2vmin; }
.loc-info-content li { margin: 0 0 .5vmin; }
.faction-info-close {
  position: absolute; top: 3vmin; right: 3vmin;
  width: 4vmin; height: 4vmin;
  font-family: var(--mono); font-size: 2.4vmin; font-weight: 700;
  color: var(--paper); background: var(--ink);
  border: max(1px, .14vmin) solid var(--ink);
  cursor: pointer;
  display: grid; place-items: center; line-height: 1;
}
.faction-info-close:hover { background: var(--paper); color: var(--ink); }

/* Details panel now gets a title heading */
.loc-info-content h3 {
  font-family: var(--mono); font-size: 1.6vmin; font-weight: 700;
  letter-spacing: .12em; text-transform: uppercase;
  margin: 0 0 1.5vmin;
  padding-bottom: .6vmin;
  border-bottom: max(1px, .16vmin) solid var(--ink);
}

/* Narrow screens: stack factions horizontally at the top instead */
@media (max-width: 760px) {
  .loc-factions {
    position: static; flex-direction: row; flex-wrap: wrap;
    max-width: none; padding: 2vmin;
  }
}

/* ---------------------------------------------------------- player fleet */
/* Player vessels reuse the canon ship indicator and art treatment; only the
   label and the selection affordances mark them out as yours. */
.o-label-fleet {
  font-size: 1.35px; letter-spacing: .2px;
  fill: var(--ink); font-style: italic;
}
/* A vessel's own orbit, drawn like the canon rings but fainter — it is the
   player's addition to the chart, not part of the surveyed system. */
.o-ring-fleet { opacity: .3; stroke-dasharray: 2 2.6; }
.o-fleet.is-selected .o-ring-fleet { opacity: .62; stroke-dasharray: none; }

/* Selection reuses the body hover treatment — a slightly heavier marker —
   rather than inventing a second visual language for the same idea. */
.o-fleet.is-selected .o-globe { stroke-width: 3; }
/* While a destination is awaited the whole chart takes a crosshair, and the
   bodies that can be parked at lift slightly so they read as targets. */
#world.is-targeting { cursor: crosshair; }
#world.is-targeting .o-body .o-globe { stroke-width: 2.2; }
#world.is-targeting .o-fleet { pointer-events: none; }

/* ------------------------------------------------------------ fleet panel */
.fleet-content { max-width: 34rem; }
.fleet-hint {
  font-family: var(--mono); font-size: 1.3vmin; color: var(--ink-soft);
  text-transform: uppercase; letter-spacing: .1em; margin: 0 0 1.4vmin;
}
.fleet-empty { color: var(--ink-soft); font-style: italic; }
.fleet-row {
  border: max(1px, .12vmin) solid var(--ink);
  padding: 1.2vmin 1.4vmin; margin: 0 0 1.1vmin;
  display: flex; flex-direction: column; gap: .7vmin;
}
.fleet-row-top { display: flex; gap: .6vmin; align-items: center; }
.fleet-name {
  flex: 1; font-family: var(--mono); font-size: 1.6vmin; font-weight: 700;
  letter-spacing: .08em; text-transform: uppercase;
  color: var(--ink); background: transparent;
  border: 0; border-bottom: max(1px, .1vmin) solid transparent; padding: .2vmin 0;
}
.fleet-name:hover, .fleet-name:focus {
  border-bottom-color: var(--ink); outline: none;
}
.fleet-x {
  width: 2.6vmin; height: 2.6vmin; flex: none; line-height: 1;
  font-family: var(--mono); font-size: 1.8vmin; font-weight: 700;
  color: var(--ink); background: transparent;
  border: max(1px, .1vmin) solid var(--ink); cursor: pointer;
}
.fleet-x:hover { background: var(--ink); color: var(--paper); }
.fleet-where {
  font-family: var(--mono); font-size: 1.2vmin; letter-spacing: .09em;
  text-transform: uppercase; color: var(--ink-soft);
}
.fleet-unplaced { font-style: italic; }
/* An anchor pointing at a body that is no longer in the sector data. The ship
   is kept, not dropped, so the stale placement has to be visible. */
.fleet-orphan { color: #a4442e; }
.fleet-row-controls { display: flex; gap: .6vmin; }
.fleet-place { flex: 2; min-width: 0; }
.fleet-sprite { flex: 1; min-width: 0; }
.fleet-place, .fleet-sprite {
  font-family: var(--mono); font-size: 1.25vmin;
  color: var(--ink); background: var(--paper);
  border: max(1px, .1vmin) solid var(--ink); padding: .45vmin .5vmin;
}
.fleet-row-actions { display: flex; gap: .6vmin; }
.fleet-go {
  font-family: var(--mono); font-size: 1.15vmin; font-weight: 700;
  letter-spacing: .14em; text-transform: uppercase;
  color: var(--ink); background: transparent;
  border: max(1px, .1vmin) solid var(--ink);
  padding: .55vmin 1.2vmin; cursor: pointer;
}
.fleet-go:hover:not([disabled]) { background: var(--ink); color: var(--paper); }
.fleet-go[disabled] { opacity: .35; cursor: default; }
#fleet-add { margin-top: .6vmin; }

/* Player controls sit bottom-right, opposite the sector's own chrome, so what
   belongs to the campaign is visually separate from what belongs to the map.
   Buttons inherit #lang-switch's styling; only placement and size differ. */
#player-switch {
  position: fixed; bottom: 2.2vmin; right: 3vmin;
  display: flex; gap: .5vmin;
  pointer-events: auto;
  z-index: 60;
}
#player-switch button {
  font-family: var(--mono);
  font-size: 1.05vmin; font-weight: 700;
  letter-spacing: .16em; text-transform: uppercase;
  color: var(--ink); background: var(--paper);
  border: max(1px, .14vmin) solid var(--ink);
  padding: .7vmin 1.4vmin; cursor: pointer;
  transition: background 160ms, color 160ms;
}
#player-switch button:hover { background: var(--ink); color: var(--paper); }
#crew-panel[hidden], #fleet-panel[hidden] { display: none; }

/* ----------------------------------------------------------------- sheets */
/* The panels grow when a sheet is open — a sheet needs room a roster does not. */
#crew-panel .fleet-content, #fleet-panel .fleet-content { max-width: 44rem; }
#crew-sheet, #fleet-sheet { display: block; }
#crew-sheet[hidden], #fleet-sheet[hidden] { display: none; }

.sheet-head { display: flex; align-items: center; gap: 1vmin; margin: 0 0 1.4vmin; }
.sheet-back {
  font-family: var(--mono); font-size: 1.15vmin; font-weight: 700;
  letter-spacing: .14em; text-transform: uppercase;
  color: var(--ink); background: transparent;
  border: max(1px, .12vmin) solid var(--ink);
  padding: .5vmin 1vmin; cursor: pointer; flex: none;
}
.sheet-back:hover { background: var(--ink); color: var(--paper); }
.sheet-name {
  flex: 1; min-width: 0;
  font-family: var(--mono); font-size: 2vmin; font-weight: 700;
  letter-spacing: .1em; text-transform: uppercase;
  color: var(--ink); background: transparent;
  border: 0; border-bottom: max(1px, .12vmin) solid var(--ink);
  padding: .3vmin 0;
}
.sheet-name:focus { outline: none; background: rgba(16,16,14,.05); }

.sheet-section { border-top: max(1px, .1vmin) solid var(--ink); margin: 0 0 .4vmin; }
.sheet-section-title {
  font-family: var(--mono); font-size: 1.2vmin; font-weight: 700;
  letter-spacing: .2em; text-transform: uppercase;
  padding: .9vmin 0; cursor: pointer; list-style: none;
}
.sheet-section-title::-webkit-details-marker { display: none; }
.sheet-section-title::before { content: '▾ '; }
.sheet-section:not([open]) .sheet-section-title::before { content: '▸ '; }
.sheet-section-body { padding: 0 0 1.4vmin; }

.sheet-grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr));
  gap: .8vmin 1.2vmin;
}
.sheet-field { display: flex; flex-direction: column; gap: .25vmin; }
.sheet-field-label {
  font-family: var(--mono); font-size: 1vmin; letter-spacing: .14em;
  text-transform: uppercase; color: var(--ink-soft);
}
.sheet-field-input, .sheet-harm-slot, .sheet-extra-key, .sheet-extra-val,
.sheet-clock-name, .sheet-note-title, .sheet-note-body {
  font-family: var(--mono); font-size: 1.35vmin;
  color: var(--ink); background: var(--paper);
  border: max(1px, .1vmin) solid var(--ink);
  padding: .45vmin .6vmin; width: 100%; box-sizing: border-box;
}
.sheet-field-static {
  font-family: var(--mono); font-size: 1.35vmin; padding: .45vmin 0;
  color: var(--ink-soft);
}
.sheet-hint {
  font-family: var(--mono); font-size: 1.05vmin; color: var(--ink-soft);
  margin: .8vmin 0 0;
}
.sheet-sub {
  font-family: var(--mono); font-size: 1.1vmin; font-weight: 700;
  letter-spacing: .16em; text-transform: uppercase;
  margin: 1.2vmin 0 .5vmin; color: var(--ink-soft);
}

/* Dots and tracks. Both are click-to-set, click-again-to-clear. */
.sheet-dots { display: flex; align-items: center; gap: .8vmin; margin: .3vmin 0; }
.sheet-dots-label, .sheet-track-label {
  font-family: var(--mono); font-size: 1.1vmin; letter-spacing: .1em;
  text-transform: uppercase; min-width: 7.5rem;
}
.sheet-dots-row, .sheet-track-row { display: flex; gap: .35vmin; }
.sheet-dot {
  width: 1.5vmin; height: 1.5vmin; padding: 0; cursor: pointer;
  border: max(1px, .12vmin) solid var(--ink); border-radius: 50%;
  background: var(--paper);
}
.sheet-dot.is-on { background: var(--ink); }
.sheet-track { display: flex; align-items: center; gap: .8vmin; margin: .5vmin 0; }
.sheet-pip {
  width: 1.3vmin; height: 1.8vmin; padding: 0; cursor: pointer;
  border: max(1px, .12vmin) solid var(--ink); background: var(--paper);
}
.sheet-pip.is-on { background: var(--ink); }
.sheet-track-stress .sheet-pip.is-on { background: #a4442e; border-color: #a4442e; }
.sheet-track-xp .sheet-pip { height: 1.3vmin; }

.sheet-attrs {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
  gap: 1.4vmin;
}
.sheet-attr-name {
  font-family: var(--mono); font-size: 1.15vmin; font-weight: 700;
  letter-spacing: .18em; text-transform: uppercase;
  margin: 0 0 .5vmin; padding-bottom: .3vmin;
  border-bottom: max(1px, .1vmin) solid var(--ink);
}

.sheet-harm-row { display: flex; align-items: center; gap: .6vmin; margin: .4vmin 0; }
.sheet-harm-level {
  font-family: var(--mono); font-weight: 700; font-size: 1.2vmin;
  width: 1.6vmin; flex: none; text-align: center;
}

.sheet-picks {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
  gap: .2vmin .8vmin;
}
.sheet-pick { display: flex; align-items: center; gap: .5vmin; cursor: pointer; }
.sheet-pick-label { font-family: var(--mono); font-size: 1.2vmin; }
.sheet-picks-note {
  grid-column: 1 / -1;
  font-family: var(--mono); font-size: 1.02vmin; font-style: italic;
  color: var(--ink-soft); margin: .6vmin 0 0;
}

/* Clocks: a segmented disc plus its name and size. */
.sheet-clocks { display: flex; flex-wrap: wrap; gap: 1.2vmin; align-items: flex-start; }
.sheet-clock {
  display: flex; gap: .8vmin; align-items: flex-start;
  border: max(1px, .1vmin) solid var(--ink); padding: .8vmin; min-width: 15rem;
}
.sheet-clock-face { width: 6vmin; height: 6vmin; flex: none; }
.sheet-clock-seg {
  fill: var(--paper); stroke: var(--ink); stroke-width: 1.2; cursor: pointer;
}
.sheet-clock-seg.is-on { fill: var(--ink); }
.sheet-clock-side { display: flex; flex-direction: column; gap: .4vmin; flex: 1; min-width: 0; }
.sheet-clock-controls { display: flex; gap: .4vmin; }
.sheet-clock-size {
  font-family: var(--mono); font-size: 1.1vmin; flex: 1;
  color: var(--ink); background: var(--paper);
  border: max(1px, .1vmin) solid var(--ink); padding: .3vmin;
}
.sheet-clock-count {
  font-family: var(--mono); font-size: 1vmin; color: var(--ink-soft);
  letter-spacing: .1em;
}

.sheet-note { border: max(1px, .1vmin) solid var(--ink); padding: .8vmin; margin: 0 0 .8vmin; }
.sheet-note-head { display: flex; gap: .5vmin; margin: 0 0 .5vmin; }
.sheet-note-body { resize: vertical; }

/* Images attach to notes, portraits and anything else that takes one. */
.sheet-images { display: flex; flex-wrap: wrap; gap: .6vmin; margin: .6vmin 0 0; }
.sheet-image { position: relative; width: 7vmin; height: 7vmin; }
.sheet-image img {
  width: 100%; height: 100%; object-fit: cover;
  border: max(1px, .1vmin) solid var(--ink);
  filter: grayscale(1) contrast(1.15);
}
.sheet-image.is-missing::after {
  content: '?'; position: absolute; inset: 0;
  display: grid; place-items: center;
  font-family: var(--mono); border: max(1px, .1vmin) dashed var(--ink);
}
.sheet-image-x { position: absolute; top: -.4vmin; right: -.4vmin; }
.sheet-image-add {
  width: 7vmin; height: 7vmin; display: grid; place-items: center;
  border: max(1px, .1vmin) dashed var(--ink); cursor: pointer;
  font-family: var(--mono); font-size: 2.4vmin; color: var(--ink-soft);
}
.sheet-image-add:hover { color: var(--ink); border-style: solid; }
.sheet-image-add input { display: none; }

.sheet-x {
  width: 2.2vmin; height: 2.2vmin; flex: none; line-height: 1; padding: 0;
  font-family: var(--mono); font-size: 1.5vmin; font-weight: 700;
  color: var(--ink); background: var(--paper);
  border: max(1px, .1vmin) solid var(--ink); cursor: pointer;
}
.sheet-x:hover { background: var(--ink); color: var(--paper); }
.sheet-add {
  font-family: var(--mono); font-size: 1.1vmin; font-weight: 700;
  letter-spacing: .14em; text-transform: uppercase;
  color: var(--ink); background: transparent;
  border: max(1px, .1vmin) dashed var(--ink);
  padding: .6vmin 1.2vmin; cursor: pointer; margin: .4vmin 0 0;
}
.sheet-add:hover { border-style: solid; background: var(--ink); color: var(--paper); }

.sheet-system { display: flex; align-items: center; gap: .8vmin; }
.sheet-system.is-damaged .sheet-dots-label { text-decoration: line-through; }
.sheet-damage {
  font-family: var(--mono); font-size: .95vmin; letter-spacing: .1em;
  text-transform: uppercase; cursor: pointer;
  color: var(--ink-soft); background: transparent;
  border: max(1px, .1vmin) solid var(--ink-soft); padding: .2vmin .6vmin;
}
.sheet-damage.is-on { background: #a4442e; border-color: #a4442e; color: var(--paper); }

.sheet-extra-row { display: flex; gap: .5vmin; margin: 0 0 .5vmin; }
.sheet-extra-key { flex: 1; }
.sheet-extra-val { flex: 2; }
.sheet-portrait { margin: 1vmin 0 0; }

/* The roster's way into a sheet. */
.crew-open {
  flex: 1; text-align: left; cursor: pointer;
  font-family: var(--mono); font-size: 1.6vmin; font-weight: 700;
  letter-spacing: .08em; text-transform: uppercase;
  color: var(--ink); background: transparent; border: 0;
  border-bottom: max(1px, .1vmin) solid transparent; padding: .2vmin 0;
}
.crew-open:hover { border-bottom-color: var(--ink); }

/* ------------------------------------------------------------ place notes */
/* Player notes sit below the canon text and are visibly the player's — a
   dashed rule and a quieter heading, so nothing here reads as sourcebook. */
.loc-notes {
  margin: 2.4vmin 0 0; padding: 1.6vmin 0 0;
  border-top: max(1px, .12vmin) dashed var(--ink);
}
.loc-notes-title {
  font-family: var(--mono); font-size: 1.1vmin; font-weight: 700;
  letter-spacing: .2em; text-transform: uppercase;
  color: var(--ink-soft); margin: 0 0 1vmin;
}
/* A place that carries notes is ticked on the chart, so the player's own
   writing can be found again without hunting. */
.o-note-badge {
  fill: var(--ink); font-size: 2.6px; text-anchor: middle;
  paint-order: stroke; stroke: var(--paper); stroke-width: .8px;
  stroke-linejoin: round; pointer-events: none;
  opacity: var(--detail, 1);
}

/* ------------------------------------------------------------------ share */
.share-list { margin: 1.2vmin 0; max-height: 40vh; overflow-y: auto; }
.share-row {
  display: flex; align-items: center; gap: .7vmin;
  padding: .5vmin 0; border-bottom: max(1px, .08vmin) solid rgba(16,16,14,.15);
}
.share-row-all .share-label { font-weight: bold; }
.share-kind {
  font-family: var(--mono); font-size: .95vmin; letter-spacing: .12em;
  text-transform: uppercase; color: var(--ink-soft);
  min-width: 7rem; flex: none;
}
.share-label {
  font-family: var(--mono); font-size: 1.25vmin; flex: 1;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.share-status {
  font-family: var(--mono); font-size: .95vmin; letter-spacing: .1em;
  text-transform: uppercase; padding: .2vmin .6vmin; flex: none;
  border: max(1px, .1vmin) solid currentColor;
}
.share-status-new       { color: #2e6a3f; }
.share-status-conflict  { color: #a4442e; }
.share-status-identical { color: var(--ink-soft); }
.share-pick {
  font-family: var(--mono); font-size: 1.1vmin; flex: none;
  color: var(--ink); background: var(--paper);
  border: max(1px, .1vmin) solid var(--ink); padding: .3vmin;
}
.share-meter { margin: 1vmin 0; }
.share-size {
  font-family: var(--mono); font-size: 1.15vmin; letter-spacing: .1em;
  text-transform: uppercase; margin: 0;
}
.share-warn  { color: #a4442e; font-family: var(--mono); font-size: 1.1vmin; }
.share-ok    { color: #2e6a3f; font-family: var(--mono); font-size: 1.1vmin; }
.share-error { color: #a4442e; font-family: var(--mono); font-size: 1.3vmin; }
.share-actions { display: flex; flex-wrap: wrap; gap: .8vmin; margin: 1.4vmin 0 0; }
.loc-info-btn.is-primary { background: var(--ink); color: var(--paper); }
.loc-info-btn.is-primary:hover { background: var(--paper); color: var(--ink); }

/* The import affordance, kept beside export so both directions are one panel. */
.share-receive {
  display: flex; align-items: center; gap: .8vmin; flex-wrap: wrap;
  margin: 1.8vmin 0 0; padding: 1.2vmin 0 0;
  border-top: max(1px, .1vmin) dashed var(--ink);
}
.share-receive-text {
  font-family: var(--mono); font-size: 1.15vmin; color: var(--ink-soft);
}
.share-pick-file { cursor: pointer; }
.share-pick-file input { display: none; }

/* Portrait chooser: shipped art and the player's own, one selected. */
.sheet-portraits {
  display: flex; flex-wrap: wrap; gap: .6vmin; margin: .5vmin 0 0;
}
.sheet-portrait-opt {
  position: relative; width: 7vmin; height: 7vmin; cursor: pointer;
  border: max(1px, .12vmin) solid var(--ink);
}
.sheet-portrait-opt img {
  width: 100%; height: 100%; object-fit: cover; display: block;
  filter: grayscale(1) contrast(1.15);
  opacity: .5; transition: opacity 140ms;
}
.sheet-portrait-opt:hover img { opacity: .85; }
/* The chosen one is full strength and ringed, so the selection reads at a
   glance in a row that will grow long. */
.sheet-portrait-opt.is-on { outline: max(2px, .3vmin) solid var(--ink); }
.sheet-portrait-opt.is-on img { opacity: 1; }

/* Portrait: the current picture, and the chooser behind it. */
.sheet-portrait-field { display: flex; align-items: center; gap: 1vmin; }
.sheet-portrait-current {
  width: 10vmin; height: 10vmin; padding: 0; cursor: pointer;
  border: max(1px, .14vmin) solid var(--ink);
  background: var(--paper); display: grid; place-items: center;
}
.sheet-portrait-current img {
  width: 100%; height: 100%; object-fit: cover; display: block;
  filter: grayscale(1) contrast(1.15);
}
.sheet-portrait-current:hover { outline: max(2px, .25vmin) solid var(--ink); }
.sheet-portrait-empty {
  font-family: var(--mono); font-size: 3vmin; color: var(--ink-soft);
}
.sheet-portrait-hint {
  font-family: var(--mono); font-size: 1vmin; letter-spacing: .1em;
  text-transform: uppercase; color: var(--ink-soft);
}

/* The chooser sits above the sheet's own panel. */
.portrait-modal {
  position: fixed; inset: 0; z-index: 80;
  display: grid; place-items: center;
  background: rgba(16, 16, 14, .55);
}
.portrait-modal-box {
  background: var(--paper); color: var(--ink);
  border: max(1px, .16vmin) solid var(--ink);
  padding: 2.4vmin; max-width: 52rem; max-height: 80vh; overflow-y: auto;
  box-shadow: 0 0 4vmin rgba(16,16,14,.4);
}
.portrait-modal-head {
  display: flex; align-items: center; justify-content: space-between;
  gap: 1vmin; margin: 0 0 1.4vmin;
}
.portrait-modal-head h3 {
  font-family: var(--mono); font-size: 1.5vmin; font-weight: 700;
  letter-spacing: .2em; text-transform: uppercase; margin: 0;
}
.portrait-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(11vmin, 1fr));
  gap: 1vmin;
}
.portrait-opt {
  padding: 0; cursor: pointer; aspect-ratio: 1;
  border: max(1px, .12vmin) solid var(--ink); background: var(--paper);
}
.portrait-opt img {
  width: 100%; height: 100%; object-fit: cover; display: block;
  filter: grayscale(1) contrast(1.15);
  opacity: .78; transition: opacity 140ms;
}
.portrait-opt:hover img { opacity: 1; }
.portrait-opt.is-on { outline: max(2px, .3vmin) solid var(--ink); }
.portrait-opt.is-on img { opacity: 1; }
.portrait-modal-actions { display: flex; gap: .8vmin; margin: 1.6vmin 0 0; }
.portrait-modal-actions input[type=file] { display: none; }
.portrait-modal-actions label { cursor: pointer; }

/* ------------------------------------------------------------------ mobile */
/* The whole interface is sized in vmin, which on a tall phone is the NARROW
   edge — so a control that reads well on a laptop lands at six or eight
   pixels here. Nothing structural is wrong: the sheet already fits, the grids
   already collapse, and nothing scrolls sideways. What follows is almost
   entirely about making things big enough to touch.
   44px is the usual floor for a tap target. */
@media (max-width: 760px) {
  /* Sector chrome ------------------------------------------------------- */
  /* One slim row: title left, hamburger right. The language buttons fold
     behind the hamburger so the crumbs — the actual navigation — own the top
     of the screen instead of a row of settings. */
  .hud-top {
    position: static; align-items: center; justify-content: space-between;
    padding: 2.2vmin 3vmin;
  }
  .hud-title { font-size: 4.4vmin; }
  .hud-sub   { display: none; }        /* the subtitle is the first thing to go */
  #menu-btn {
    display: block; pointer-events: auto;
    font-size: 5vmin; line-height: 1; padding: 1.6vmin 2.4vmin;
    color: var(--ink); background: var(--paper);
    border: max(1px, .14vmin) solid var(--ink); cursor: pointer;
  }
  #menu-btn[hidden] { display: block; }   /* the hidden attr is for desktop */
  #lang-switch { display: none; }
  #lang-switch.open {
    display: flex; flex-direction: column; gap: 1vmin;
    position: fixed; top: 13vmin; right: 3vmin; width: 46vmin;
    padding: 2vmin; background: var(--paper);
    border: max(1px, .14vmin) solid var(--ink);
    box-shadow: 0 0 4vmin rgba(16,16,14,.35); z-index: 70;
  }
  #lang-switch.open button {
    font-size: 3.2vmin; padding: 2.8vmin 1vmin; min-width: 0;
  }
  #about-btn { margin-left: 0; }

  #player-switch { left: 3vmin; right: 3vmin; bottom: 3vmin; gap: 1.4vmin; }
  /* Import/Export moves into the hamburger on a phone; the corner keeps the
     two panels a session actually lives in. */
  #player-switch #share-btn { display: none; }
  #lang-switch.open #share-btn-menu { display: block; }
  #player-switch button {
    flex: 1; font-size: 2.8vmin; padding: 3vmin 1vmin; letter-spacing: .08em;
  }

  #breadcrumb { font-size: 3vmin; }
  .crumb { padding: 1.4vmin 1vmin; }

  /* Panels take the screen. A centred card with margins wastes width that a
     sheet badly needs. */
  .loc-info-content, #crew-panel .fleet-content, #fleet-panel .fleet-content {
    max-width: none; width: 100vw; max-height: 100vh; height: 100vh;
    padding: 14vmin 4vmin 6vmin; border: 0; font-size: 3.4vmin;
  }
  .loc-info-close { width: 11vmin; height: 11vmin; font-size: 5vmin;
                    top: 2.5vmin; right: 2.5vmin; }

  /* Sheets --------------------------------------------------------------- */
  .sheet-name { font-size: 5vmin; padding: 1.5vmin 0; }
  .sheet-back { font-size: 3vmin; padding: 2vmin 2.6vmin; }
  .sheet-section-title { font-size: 3.2vmin; padding: 3vmin 0; }
  .sheet-field-label, .sheet-dots-label, .sheet-track-label { font-size: 2.6vmin; }
  .sheet-field-input, .sheet-harm-slot, .sheet-note-title, .sheet-note-body,
  .sheet-clock-name, .sheet-extra-key, .sheet-extra-val, .sheet-clock-size {
    font-size: 3.4vmin; padding: 2.4vmin 2vmin;
  }
  .sheet-sub, .sheet-hint, .sheet-picks-note { font-size: 2.8vmin; }
  .sheet-attr-name { font-size: 3vmin; }

  /* The dots and pips are the real problem: 6px is untappable. Grown well
     past the floor, and given room to breathe so neighbours are not hit by
     mistake. */
  .sheet-dots, .sheet-track { gap: 2vmin; flex-wrap: wrap; }
  .sheet-dots-label, .sheet-track-label { min-width: 100%; }
  /* 44px is the floor for a finger. These are sized in absolute units rather
     than vmin because the requirement is physical, not proportional — a dot
     must be tappable on a 360px phone as much as on a 430px one. */
  .sheet-dots-row, .sheet-track-row { gap: 8px; flex-wrap: wrap; }
  .sheet-dot { width: 40px; height: 40px; flex: none; }
  /* Tracks run to nine pips; at a tappable width that is wider than a phone,
     so they wrap rather than pushing the sheet sideways. */
  .sheet-pip { width: 30px; height: 40px; flex: none; }
  .sheet-track-xp .sheet-pip { height: 30px; }
  .sheet-dots, .sheet-track { max-width: 100%; }
  .sheet-condition, .sheet-kit, .sheet-attrs, .sheet-systems { max-width: 100%; }

  .sheet-pick { padding: 1.4vmin 0; }
  .sheet-pick-label { font-size: 3.2vmin; }
  .sheet-pick input[type=checkbox] { width: 26px; height: 26px; }
  .sheet-pick { min-height: 44px; align-items: center; }

  .sheet-x { width: 8vmin; height: 8vmin; font-size: 4vmin; }
  .sheet-add { font-size: 3vmin; padding: 2.4vmin 3vmin; }
  .sheet-damage { font-size: 2.4vmin; padding: 1.4vmin 2vmin; }

  .sheet-harm-row { flex-wrap: wrap; }
  .sheet-harm-slot { flex: 1 1 100%; }
  .sheet-system { flex-wrap: wrap; }
  .sheet-clock { min-width: 100%; }
  .sheet-clock-face { width: 18vmin; height: 18vmin; }
  .sheet-images, .sheet-image, .sheet-image-add { }
  .sheet-image, .sheet-image-add { width: 20vmin; height: 20vmin; }
  .sheet-portrait-current { width: 26vmin; height: 26vmin; }
  .sheet-portrait-hint { font-size: 2.6vmin; }

  /* Rosters and the fleet list ------------------------------------------- */
  .crew-open { font-size: 4vmin; padding: 2vmin 0; }
  .fleet-row { padding: 3vmin; }
  .fleet-x { width: 9vmin; height: 9vmin; font-size: 4.5vmin; }
  .fleet-where { font-size: 2.6vmin; }
  .fleet-place, .fleet-sprite { font-size: 3vmin; padding: 2.4vmin 1.6vmin; }
  .fleet-go, .loc-info-btn { font-size: 3vmin; padding: 2.6vmin 3.4vmin; }
  .fleet-hint { font-size: 2.8vmin; }
  .fleet-row-controls { flex-direction: column; }

  /* Portrait chooser ----------------------------------------------------- */
  .portrait-modal-box {
    max-width: none; width: 100vw; height: 100vh; max-height: 100vh;
    padding: 5vmin 4vmin;
  }
  .portrait-grid { grid-template-columns: repeat(auto-fill, minmax(26vmin, 1fr)); }
  .portrait-modal-head h3 { font-size: 4vmin; }

  /* Share ---------------------------------------------------------------- */
  .share-row { flex-wrap: wrap; padding: 2vmin 0; }
  .share-kind { font-size: 2.4vmin; min-width: 0; }
  .share-label { font-size: 3vmin; flex: 1 1 60%; }
  .share-status { font-size: 2.4vmin; padding: 1vmin 1.6vmin; }
  .share-pick { font-size: 2.8vmin; padding: 1.6vmin; flex: 1 1 100%; }
  .share-row input[type=checkbox] { width: 26px; height: 26px; }
  .share-size, .share-warn, .share-ok, .share-receive-text { font-size: 2.8vmin; }
  .share-actions { flex-direction: column; }
  .share-actions .loc-info-btn { width: 100%; text-align: center; }
  .share-list { max-height: 46vh; }

  /* Location view -------------------------------------------------------- */
  .loc-notes-title { font-size: 2.8vmin; }
  .loc-actions { flex-wrap: wrap; }

}

/* Orders for the selected vessel — shown only while one is selected. */
#ship-actions {
  position: fixed; bottom: 6vmin; left: 50%; transform: translateX(-50%);
  display: flex; gap: .8vmin; z-index: 55; pointer-events: auto;
}
#ship-actions[hidden] { display: none; }
#ship-actions button {
  font-family: var(--mono); font-size: 1.15vmin; font-weight: 700;
  letter-spacing: .16em; text-transform: uppercase;
  color: var(--paper); background: var(--ink);
  border: max(1px, .14vmin) solid var(--ink);
  padding: 1vmin 2vmin; cursor: pointer;
}
#ship-actions button:hover { background: var(--paper); color: var(--ink); }
#ship-actions button[hidden] { display: none; }
@media (max-width: 760px) {
  /* Above the player buttons and the hint, where a thumb can reach it. */
  #ship-actions { bottom: 22vmin; left: 3vmin; right: 3vmin;
                  transform: none; }
  #ship-actions button { flex: 1; font-size: 3vmin; padding: 3.2vmin 1vmin; }
}

/* The way back from a surface view. Esc always worked, but it was invisible
   and a phone has no such key. Top-left, mirroring the close buttons. */
.loc-back {
  position: absolute; top: 3vmin; left: 3vmin;
  width: 4vmin; height: 4vmin;
  font-family: var(--mono); font-size: 2.4vmin; font-weight: 700;
  color: var(--paper); background: var(--ink);
  border: max(1px, .14vmin) solid var(--ink);
  cursor: pointer; z-index: 45;
  display: grid; place-items: center; line-height: 1;
}
.loc-back:hover { background: var(--paper); color: var(--ink); }

@media (max-width: 760px) {
  /* The surface view's text was PINNED to the bottom, which is the band the
     fixed hint and player buttons own — so the blurb, Läs mer and the notes
     rendered behind them. The view scrolls instead: art as a fixed backdrop,
     text flowing over it, with enough tail padding to clear the chrome. */
  #location-view.active { overflow-y: auto; }
  #location-view .loc-image { position: fixed; }
  .loc-body {
    /* Relative, not static: the backdrop image is position:fixed, and a
       static body paints UNDERNEATH a positioned sibling — the art's white
       fade sat exactly over the text and hid every word of it. The full
       margin shorthand matters: the desktop rule indents 22vmin left, which
       on a phone would eat a fifth of the width. */
    position: relative; z-index: 1; margin: 52vh 0 0;
    padding: 4vmin 4vmin 34vmin; max-width: none;
  }
  /* On a phone the system back gesture does this job (see js/nav.js); the
     button stays for desktop, which has no such gesture. */
  .loc-back { display: none; }

  /* The crumbs were absolutely placed for the desktop header row and landed
     tiny on top of the stacked mobile title. The header goes static so the
     crumbs flow naturally below it, whatever height the wrapped rows come
     to — they are the back navigation and have to be reachable. */
  #breadcrumb {
    position: static; margin: 2vmin 3vmin 0; flex-wrap: wrap; gap: 1vmin;
  }
  .crumb { font-size: 3vmin; padding: 2.2vmin 2.8vmin; }
  .crumb-sep { font-size: 3vmin; }

  /* While a surface view is open the vessel order bar says nothing useful,
     and sat on top of the text. */
  body:has(#location-view.active) #ship-actions { display: none; }

}

/* ----------------------------------------------------------- stakeholders */
.stakeholder-pills { display: flex; flex-wrap: wrap; gap: .6vmin; margin: 0 0 1vmin; }
.stakeholder-pills .faction-pill { flex: 0 1 auto; }
#stakeholders-list .factions-title { margin: 1.2vmin 0 .6vmin; }
#stakeholder-detail[hidden] { display: none; }
.stakeholder-canon { max-height: none; overflow: visible; box-shadow: none;
                     border: 0; padding: 1vmin 0; font-size: inherit; }

/* Contact chips on a character sheet. */
.sheet-contacts { display: flex; flex-wrap: wrap; gap: .6vmin; align-items: center; }
.sheet-contact {
  display: inline-flex; align-items: center; gap: .4vmin;
  border: max(1px, .1vmin) solid var(--ink); padding: .3vmin .3vmin .3vmin 1vmin;
}
.sheet-contact-name {
  font-family: var(--mono); font-size: 1.3vmin; font-weight: 700;
  letter-spacing: .06em; color: var(--ink); background: none;
  border: 0; cursor: pointer; padding: .4vmin 0;
}
.sheet-contact-name:hover:not([disabled]) { text-decoration: underline; }
.sheet-contact-name[disabled] { color: var(--ink-soft); cursor: default; }
.sheet-contact-add { flex: 1 1 14rem; }
@media (max-width: 760px) {
  .sheet-contact-name { font-size: 3vmin; padding: 1.6vmin 0; }
}

/* Contact rows: name, standing, remove — and the finder beneath them. */
.sheet-contact {
  display: flex; align-items: center; gap: .8vmin; width: 100%;
  padding: .4vmin .4vmin .4vmin 1vmin;
}
.sheet-contact .sheet-disposition { margin-left: auto; }
.sheet-disposition-sel { width: auto; }
.sheet-contact-addrow { display: flex; gap: .6vmin; width: 100%; margin-top: .6vmin; }
.sheet-contact-add { flex: 1; }
/* Same dashed add-button as clocks and notes; it sits inline with the
   search field, so the sheet-add top margin goes. */
.sheet-contact-create { flex: none; margin: 0; }
.sheet-contact-create[disabled] { opacity: .4; cursor: default; }
.sheet-contact-create[disabled]:hover {
  background: transparent; color: var(--ink); border-style: dashed;
}
.sheet-contact-suggest { display: flex; flex-direction: column; width: 100%; }
.sheet-contact-option {
  text-align: left; font-family: var(--mono); font-size: 1.3vmin;
  color: var(--ink); background: var(--paper);
  border: max(1px, .1vmin) solid var(--ink); border-top: 0;
  padding: 1vmin 1.2vmin; cursor: pointer;
}
.sheet-contact-option:first-child { border-top: max(1px, .1vmin) solid var(--ink); }
.sheet-contact-option:hover { background: var(--ink); color: var(--paper); }
@media (max-width: 760px) {
  .sheet-contact { flex-wrap: wrap; }
  .sheet-contact-option { font-size: 3vmin; padding: 2.6vmin 2vmin; }
  .sheet-contact-create { font-size: 3vmin; }
}

/* Status rows in the faction view: vessel name left, number right, matching
   the ship sheet's rows rather than a label crammed against a select. */
.faction-status-row { border: max(1px, .1vmin) solid var(--ink); margin: 0 0 .6vmin; }
.sheet-status-ship {
  font-family: var(--mono); font-size: 1.3vmin; font-weight: 700;
  letter-spacing: .06em; text-transform: uppercase;
}
.faction-player .loc-notes-title { margin-top: 1.6vmin; }
@media (max-width: 760px) {
  .sheet-status-ship { font-size: 3vmin; }
}

/* One corner control per view: × closes a panel from its root; a level deep
   the ‹ back button is the only corner control, since "back then close" is a
   tap away and backdrop, Esc and the system gesture all still dismiss. The
   close buttons stay in the DOM — the back-gesture ladder and Escape click
   them regardless of visibility. */
#crew-panel:has(#crew-sheet:not([hidden])) #crew-close,
#fleet-panel:has(#fleet-sheet:not([hidden])) #fleet-close,
#stakeholders-panel:has(#stakeholder-detail:not([hidden])) #stakeholders-close {
  display: none;
}

@media (max-width: 760px) {
  /* The faction pills fell back to the desktop menu scale after the sidebar
     went — 9px next to 14px NPC rows, reading as another interface entirely.
     Sized to sit beside the rows in the same list. */
  .factions-title { font-size: 3vmin; padding: 2vmin 2.4vmin; }
  .faction-pill { font-size: 3vmin; padding: 2.6vmin 3vmin; }
  #stakeholders-list .crew-open { font-size: 3.4vmin; }
}


/* Inline sourcebook details on the surface. */
.loc-details { margin-top: 2vmin; font-size: 1.6vmin; line-height: 1.65; }
.loc-details p { margin: 0 0 1.2vmin; }
.loc-details ul { margin: .4vmin 0 1.2vmin; padding-left: 2.2vmin; }

/* The people of a place: canon notables and placed NPCs, one live list. */
.loc-people-body { display: flex; flex-direction: column; gap: .6vmin; }
.loc-person {
  text-align: left; cursor: pointer;
  font-family: var(--mono);
  color: var(--ink); background: transparent;
  border: max(1px, .1vmin) solid var(--ink);
  padding: 1.2vmin 1.6vmin;
}
.loc-person:hover { background: var(--ink); color: var(--paper); }
.loc-person:hover .loc-person-desc { color: var(--paper); }
.loc-person-name { display: block; font-weight: 700; font-size: 1.4vmin;
                   letter-spacing: .08em; text-transform: uppercase; }
.loc-person-desc { display: block; font-size: 1.25vmin; color: var(--ink-soft);
                   margin-top: .3vmin; }
@media (max-width: 760px) {
  .loc-details { font-size: 3.2vmin; }
  .loc-person-name { font-size: 3.2vmin; }
  .loc-person-desc { font-size: 2.8vmin; }
  .loc-person { padding: 2.6vmin 3vmin; }
}

/* System sub-groups inside the Individer list at sector view. */
.stakeholder-subtitle {
  font-family: var(--mono); font-size: 1.1vmin; font-weight: 700;
  letter-spacing: .18em; text-transform: uppercase; color: var(--ink-soft);
  margin: 1vmin 0 .4vmin;
}
@media (max-width: 760px) { .stakeholder-subtitle { font-size: 2.8vmin; } }
