﻿/* Ported from reference/web-original/head.html. The design tokens, the grid shell,
   and the responsive rules survive the port unchanged - that is the one part of this
   that came nearly free.

   Only what the star slice uses is here. The dossier, search results, faction list,
   readout card, and hover tip come back with the passes that need them. */

:root {
  --void: #06080d;
  --deep: #0a0e16;
  --panel: #0d121b;
  --panel-t: rgba(11, 15, 23, .9);
  --rule: #1b2431;
  --rule-soft: #131a25;
  --ink: #c9d4e2;
  --ink-2: #8494a6;
  --ink-3: #57657a;
  --amber: #e9a93c;
  --amber-2: #f2c476;
  --amber-dim: #6d4f1d;
  --ice: #7fb2d9;
  --danger: #d8563e;
  --f-disp: "Bahnschrift SemiCondensed", "Arial Narrow", system-ui, sans-serif;
  --f-body: "Segoe UI", system-ui, sans-serif;
  --f-mono: "Cascadia Mono", "SFMono-Regular", Consolas, ui-monospace, monospace;
  color-scheme: dark;
}

* { box-sizing: border-box }

body {
  margin: 0;
  background: var(--void);
  color: var(--ink);
  font-family: var(--f-body);
  font-size: 13px;
  line-height: 1.5;
  height: 100vh;
  overflow: hidden;
  -webkit-font-smoothing: antialiased;
}

button { font: inherit; color: inherit; background: none; border: none; cursor: pointer }
:focus-visible { outline: 1px solid var(--amber); outline-offset: 2px }

::-webkit-scrollbar { width: 9px; height: 9px }
::-webkit-scrollbar-track { background: var(--deep) }
::-webkit-scrollbar-thumb { background: #1e2836; border: 2px solid var(--deep); border-radius: 5px }
::-webkit-scrollbar-thumb:hover { background: #2b3849 }

.lbl {
  font-family: var(--f-disp); font-weight: 600; font-size: 10px; letter-spacing: .13em;
  text-transform: uppercase; color: var(--ink-3);
}
.num { font-family: var(--f-mono); font-variant-numeric: tabular-nums }

/* ---------- boot ---------- */
.boot {
  position: fixed; inset: 0; display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: 10px; background: var(--void);
}
.boot-mark {
  font-family: var(--f-disp); font-weight: 700; font-size: 15px; letter-spacing: .16em;
  text-transform: uppercase; color: var(--ink-3);
}
.boot-note { font-family: var(--f-mono); font-size: 11px; color: var(--ink-3) }

/* ---------- shell ---------- */
.app {
  display: grid; height: 100vh;
  grid-template-columns: 288px minmax(0, 1fr) 340px;
  grid-template-rows: auto minmax(0, 1fr) auto;
  grid-template-areas: "top top top" "rail stage doss" "chrono chrono chrono";
}

.topbar {
  grid-area: top; display: flex; align-items: center; gap: 20px; padding: 0 16px; height: 52px;
  border-bottom: 1px solid var(--rule); background: var(--panel); position: relative; z-index: 6;
}
.brand { display: flex; align-items: center; gap: 10px; flex: none }
/* The wordmark and the tally sit on one baseline, and the mark centres against the block
   they form. Aligning all three on the baseline drops the mark low, because a replaced
   element's baseline is its bottom edge.

   Then the words come back down by 3px, and that offset is the whole point of this rule.
   `align-items: center` above centres the two *boxes*, and it does so exactly - measured,
   the mark's box centre and the text's ink centre land within a quarter of a pixel. It
   still reads as misaligned, because the emblem is a chevron that widens downward and its
   ink is nowhere near its box centre: the artwork's alpha centroid sits 6.85px below
   centre on the 60px file, which is 3.4px at the 30px it is drawn. The eye aligns on
   visual mass, so a box-centred chevron reads low and the words read high against it.

   The words move rather than the mark, so the emblem keeps symmetrical space in a 52px
   bar; raising the mark instead would leave 6.9px above it against 15.2px below, which
   trades this problem for a worse one. Rounded from 3.4 to a whole pixel because it is
   text that is moving and the wordmark is better off on the pixel grid - the missing
   0.4px is well under what the eye can find.

   `position: relative` offsets the box without moving anything else, so the mark and the
   gap between them are untouched. Re-measure this if the emblem artwork is ever
   replaced: it is a fact about that file's shape, not about the layout. */
.brand .words { display: flex; align-items: baseline; gap: 10px; min-width: 0; position: relative; top: 3px }
/* Width and height are on the element as well, so it reserves its box before the file
   arrives and the title does not jump left on a cold load. */
.brand .mark { width: 30px; height: 30px; flex: none; margin-right: 2px }
.brand h1 {
  font-family: var(--f-disp); font-weight: 700; font-size: 15px; letter-spacing: .06em;
  text-transform: uppercase; margin: 0; color: var(--ink);
}
.brand .tag { font-family: var(--f-mono); font-size: 10px; color: var(--ink-3); letter-spacing: .04em }
/* Carried down by the same 3px as the wordmark, and for the same reason once removed: the
   emblem's visual mass is what set that offset, and the era caption reads as sitting on
   one line with the title beside it. Shifting only the wordmark left this block riding
   2.5 to 4.5px high of it.

   The same number rather than one of its own, so the relationship the two blocks already
   had is preserved and not re-invented - the year's baseline sat 1px below the title's
   before either moved, and still does. See .brand .words for where 3px comes from; if
   that changes, this changes with it. */
.eranow { display: flex; align-items: baseline; gap: 10px; min-width: 0; flex: 1; position: relative; top: 3px }
.eranow .yr {
  font-family: var(--f-disp); font-weight: 700; font-size: 19px; color: var(--amber);
  letter-spacing: .02em; flex: none;
}
.eranow .nm { font-size: 12px; color: var(--ink-2); white-space: nowrap; overflow: hidden; text-overflow: ellipsis }

.tools { display: flex; gap: 2px; flex: none; border: 1px solid var(--rule); border-radius: 3px; padding: 2px }
.tools button {
  padding: 5px 11px; border-radius: 2px; font-family: var(--f-disp); font-weight: 600;
  font-size: 10.5px; letter-spacing: .1em; text-transform: uppercase; color: var(--ink-3);
}
.tools button:hover { color: var(--ink); background: var(--rule-soft) }
.tools button[aria-pressed="true"] { background: var(--amber); color: #12161d }
.railtoggle { display: none }

/* ---------- rails ---------- */
.rail { grid-area: rail; border-right: 1px solid var(--rule) }
.doss { grid-area: doss; border-left: 1px solid var(--rule) }

.rail, .doss {
  background: var(--panel); display: flex; flex-direction: column; min-height: 0;
  overflow-y: auto; overflow-x: hidden; position: relative; z-index: 5;
}
.sect { border-bottom: 1px solid var(--rule-soft); padding: 13px 14px }
.sect > .lbl { display: block; margin-bottom: 9px }

/* The gesture help, pinned to the foot of the rail.

   `margin-top: auto` puts it at the bottom when the rail's content is short;
   `position: sticky` holds it there once the content is long enough to scroll,
   which with 37 realms listed it always is. The rail is the scroll container, so
   the sticky offset is measured against it. It needs an opaque background of its
   own or the sections scroll through it. */
.rail .sect.controls {
  margin-top: auto; position: sticky; bottom: 0; z-index: 1;
  background: var(--panel); border-bottom: none; border-top: 1px solid var(--rule);
}

.opt { display: flex; align-items: center; gap: 8px; padding: 3px 0; cursor: pointer; font-size: 12px }
.opt input { accent-color: var(--amber); margin: 0 }

/* A checkbox with its detail beside it. The label keeps the checkbox behaviour of the
   options above it; the row spreads so the buttons sit flush right. */
.opt.pick { cursor: default; justify-content: space-between; gap: 10px }
.opt.pick label { display: flex; align-items: center; gap: 8px; cursor: pointer; min-width: 0 }
.seg { display: flex; gap: 1px; border: 1px solid var(--rule); border-radius: 3px; padding: 1px; flex: none }
.seg button {
  padding: 2px 7px; border-radius: 2px; font-family: var(--f-disp); font-weight: 600;
  font-size: 9.5px; letter-spacing: .08em; text-transform: uppercase; color: var(--ink-3);
}
.seg button:hover:not(:disabled) { color: var(--ink); background: var(--rule-soft) }
.seg button[aria-pressed="true"] { background: var(--amber); color: #12161d }

/* Disabled reads as unavailable rather than as merely unselected, so the whole group
   fades with its border. Without that the buttons look pressable and do nothing. */
.seg:has(button:disabled) { border-color: var(--rule-soft) }
.seg button:disabled { color: var(--ink-3); opacity: .38; cursor: default }

/* Used by the stage's key box. Kept as a list, because that is what it is. */
.key {
  list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 3px;
  font-size: 11.5px; color: var(--ink-2);
}
.key li { display: flex; align-items: center; gap: 6px }
.hintbox { margin: 10px 0 0; font-size: 11px; color: var(--ink-3); line-height: 1.5 }
kbd {
  font-family: var(--f-mono); font-size: 10px; border: 1px solid var(--rule); border-radius: 2px;
  padding: 0 3px; margin: 0 1px; color: var(--ink-2);
}

.stat { display: grid; grid-template-columns: auto 1fr; gap: 3px 12px; font-size: 11.5px }
.stat dt { color: var(--ink-3) }
.stat dd { margin: 0; font-family: var(--f-mono); font-size: 11px; text-align: right }

/* ---------- dossier ---------- */
.doss .empty { padding: 30px 18px; color: var(--ink-3); font-size: 12px; text-align: center }

/* The era tally is pinned to the foot of the panel: these are facts about the era, not
   about the world, so they should not scroll away with a record they do not belong to.

   Both halves are needed. `margin-top: auto` floats it down when the record above is
   short - an empty dossier is mostly space - and `position: sticky` holds it there if the
   panel ever does have to scroll, which is the same pattern the rail's gesture help uses.
   It needs an opaque background of its own, or the sections scroll through it. */
.doss .sect.era {
  margin-top: auto; position: sticky; bottom: 0; z-index: 1;
  background: var(--panel); border-bottom: none; border-top: 1px solid var(--rule);
}
.doss .empty svg { opacity: .5; margin-bottom: 12px }

.dh { padding: 15px 16px 13px; border-bottom: 1px solid var(--rule-soft) }
.dh h2 {
  font-family: var(--f-disp); font-weight: 700; font-size: 21px; margin: 0; letter-spacing: .01em;
  text-wrap: balance; line-height: 1.15;
}
.dh .alt { font-size: 11.5px; color: var(--ink-3); margin-top: 3px; font-style: italic }

/* The world's name, owner and divisions on the left, the realm's badge on the right,
   centred against the whole column rather than hung from its top. The badge answers to
   the block, not to the owner row, so aligning it to one line of that block left it
   sitting high against three.

   `min-width: 0` on the left column is what lets a long faction name wrap instead of
   pushing the badge out of the panel - a flex item's default minimum is its content
   width. */
.hold { display: flex; align-items: center; gap: 12px }
.held { flex: 1; min-width: 0 }

/* A fixed box whatever the artwork's own shape. The emblems come at a dozen aspect
   ratios, and letting each one size the row would make the dossier jump as the reader
   moves from world to world. */
.crest {
  flex: none; width: 80px; height: 80px; object-fit: contain; object-position: top center;
}
/* No emblem: the placeholder, in the section labels' own ink rather than a grey of its
   own. It stands in the same box as a badge, so the block beside it does not reflow. */
.crest.none { color: var(--ink-3) }

/* The badge and the realm's dates under it. Fixed to the crest's own width so the
   caption wraps inside the box rather than widening the column and squeezing the
   owner's name beside it. */
.crestbox { flex: none; width: 80px }
.crestcap {
  margin-top: 4px; text-align: center; font-family: var(--f-mono);
  font-size: 9.5px; color: var(--ink-3); white-space: nowrap;
}

/* Where a drive reaches in one jump. Rows run to the panel edge like the realm list, so
   a long neighbourhood scrolls against the edge rather than inside a box of its own.

   This section takes the panel's slack and is the only part of the record that scrolls.
   The rest of the dossier is bounded - a name, six facts, 44 era bands, three buttons -
   while the neighbour list is not, so scrolling the whole panel to reach the end of one
   list carries the header and the era tally away with it for no reason.

   The floor goes on the *section*, and the list is left free to shrink. Putting it on the
   list instead is wrong in a way that looks almost right: flex shrinks the section to the
   space left over, the list refuses to go below its floor, and the surplus spills out of
   the bottom of the section and under the era tally. The section therefore carries both
   the floor and `overflow: hidden`, so the list can never paint outside it.

   The floor is about three rows plus the label. Where even that does not fit - a short
   window, with the record above it fixed at roughly 550px - .doss scrolls, which is why
   it keeps its own overflow rather than being pinned shut, and why the era tally is
   sticky as well as pushed down. On any normal window there is slack, the list takes it,
   and the panel itself does not move. */
.doss .hint { margin: 0; font-size: 11.5px; color: var(--ink-3); line-height: 1.45 }
.doss .sect.hopsect {
  flex: 1 1 auto; min-height: 125px; display: flex; flex-direction: column;
  overflow: hidden;
}
.hops {
  list-style: none; margin: 0; padding: 0;
  flex: 1 1 auto; min-height: 0; overflow-y: auto;
}
.hops button {
  display: flex; align-items: center; gap: 8px; width: 100%; padding: 3px 4px;
  border-radius: 2px; text-align: left;
}
.hops button:hover { background: var(--rule-soft) }
/* 11px, matching the realm list rather than the 9px this started at: these carry an
   emblem now, and a badge at 9px is a smudge. `img.sw.em` above strips the inset rule
   and the corner, which exist to give a flat colour an edge. */
.hops .sw {
  width: 11px; height: 11px; border-radius: 2px; flex: none;
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .16);
}
.hops .hn {
  flex: 1; min-width: 0; font-size: 12px; color: var(--ink);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
/* The distances line up on the right, so the column reads as a ladder from here
   outwards - which is the order the list is in. */
.hops .hd {
  flex: none; font-family: var(--f-mono); font-size: 10.5px; color: var(--ink-3);
  font-variant-numeric: tabular-nums;
}
.hops .hd::after { content: " LY"; color: #2f3947 }

.owner { display: flex; align-items: center; gap: 9px; margin-top: 11px }
.owner .sw {
  width: 14px; height: 14px; border-radius: 2px; flex: none;
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .18);
}

/* An emblem stands in the swatch's box at the swatch's size. It carries no inset rule:
   that outline exists to give a flat colour an edge, and artwork has its own. */
img.sw.em {
  object-fit: contain; border-radius: 0; box-shadow: none; background: none;
}
/* The owner is a row of parts now rather than one string, because a disputed world
   names two factions and each of them is worth following. `gap` spaces them, so the
   markup does not have to carry significant whitespace between inline elements. */
.owner .on {
  font-weight: 600; font-size: 13px; min-width: 0;
  display: flex; align-items: baseline; flex-wrap: wrap; gap: 0 5px;
}
.owner .qual { font-weight: 400; color: var(--ink-2) }
.owner .oc { font-family: var(--f-mono); font-size: 10.5px; color: var(--ink-3) }

/* A faction link. Underlined only on hover: at rest the owner should read as a name,
   not as a row of blue. The dotted rule is what marks it as followable meanwhile. */
.owner .fl {
  color: var(--ink); text-decoration: none;
  border-bottom: 1px dotted var(--ink-3);
}
.owner .fl:hover, .owner .fl:focus-visible { color: var(--amber); border-bottom-color: var(--amber) }
/* One administrative division to a line. The left padding lines the list up under
   the owner's name rather than under its colour swatch. */
.prov {
  list-style: none; margin: 5px 0 0; font-size: 11.5px; color: var(--ink-2);
  padding-left: 23px; display: flex; flex-direction: column; gap: 2px;
}
.prov li { line-height: 1.4 }

dl.facts { display: grid; grid-template-columns: auto 1fr; gap: 5px 14px; margin: 0; font-size: 12px }
dl.facts dt { color: var(--ink-3) }
dl.facts dd { margin: 0; font-family: var(--f-mono); font-size: 11.5px }

.hist { display: flex; gap: 1px; height: 34px; margin-top: 2px }
.hist button { flex: 1; min-width: 0; border-radius: 1px; position: relative; padding: 0 }
.hist button:hover { transform: scaleY(1.14) }
.hist button.now { box-shadow: inset 0 0 0 1.5px var(--amber); z-index: 2 }
.histax {
  display: flex; justify-content: space-between; margin-top: 4px;
  font-family: var(--f-mono); font-size: 9.5px; color: var(--ink-3);
}

.dact { display: flex; gap: 6px; flex-wrap: wrap; margin-top: 4px }
.btn {
  padding: 6px 10px; border: 1px solid var(--rule); border-radius: 2px; font-family: var(--f-disp);
  font-weight: 600; font-size: 10px; letter-spacing: .1em; text-transform: uppercase;
  color: var(--ink-2); text-decoration: none; display: inline-block;
}
.btn:hover { border-color: var(--amber-dim); color: var(--amber) }
.btn.pri { background: var(--amber); color: #12161d; border-color: var(--amber) }
.btn.pri:hover { background: var(--amber-2); color: #12161d }

/* ---------- stage ---------- */
.stage { grid-area: stage; position: relative; background: var(--void); overflow: hidden; min-width: 0; touch-action: none }
.stage canvas { position: absolute; inset: 0; width: 100%; height: 100%; display: block }
.stage.grab { cursor: grab }
.stage.grabbing { cursor: grabbing }

.vig {
  position: absolute; inset: 0; pointer-events: none;
  background: radial-gradient(ellipse at 50% 45%, transparent 52%, rgba(3, 5, 9, .5) 100%);
}

/* Hover tip. Positioned at the world's screen position and offset clear of the marker,
   so it never sits under the pointer itself. */
.tip {
  position: absolute; pointer-events: none; z-index: 9; padding: 4px 8px; background: #0f151f;
  border: 1px solid var(--rule); border-radius: 2px; font-size: 11.5px; white-space: nowrap;
  transform: translate(10px, -50%); box-shadow: 0 4px 14px rgba(0, 0, 0, .6); display: none;
}
.tip b { font-weight: 600 }
.tip span { font-family: var(--f-mono); font-size: 10px; color: var(--ink-3); margin-left: 6px }

/* Wrapper for the page's stage overlays. No box of its own, so it changes no
   layout; it exists only to be a place for pointerdown to stop. */
.stagechrome { display: contents }

/* Readout card, floating over the stage while a course is being plotted. */
.readout {
  position: absolute; left: 12px; top: 12px; z-index: 8; max-width: 290px;
  background: var(--panel-t); border: 1px solid var(--rule); border-radius: 3px;
  padding: 10px 12px; backdrop-filter: blur(6px);
}
.readout .rh { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-bottom: 7px }
.readout .x { pointer-events: auto; color: var(--ink-3); font-size: 14px; line-height: 1; padding: 2px 4px }
.readout .x:hover { color: var(--danger) }
.readout .big { font-family: var(--f-disp); font-weight: 700; font-size: 14px; line-height: 1.35; color: var(--amber) }
.readout .rows { display: grid; grid-template-columns: auto 1fr; gap: 3px 12px; font-size: 11.5px; margin: 8px 0 0 }
.readout .rows dt { color: var(--ink-3) }
.readout .rows dd { margin: 0; font-family: var(--f-mono); font-size: 11px }
.readout p { margin: 7px 0 0; font-size: 11.5px; color: var(--ink-2) }
.readout .hint { color: var(--ink-3); font-size: 11px }
.readout .warn { color: var(--danger) }

/* Range slider in the rail. */
input[type=range] { width: 100%; accent-color: var(--amber) }

.hud { position: absolute; pointer-events: none; z-index: 8 }
.hud.bl { left: 12px; bottom: 12px; display: flex; flex-direction: column; gap: 7px; align-items: flex-start }
.hud.tr { right: 12px; top: 12px; display: flex; flex-direction: column; gap: 6px; align-items: flex-end }
.hud.br { right: 12px; bottom: 12px; display: flex; flex-direction: column; gap: 6px; align-items: flex-end }

/* The key, over the chart it explains. Same card treatment as the readout, so the
   two overlays read as one family.

   `pointer-events: auto` is not optional, and the failure is not the obvious one.
   `.hud` is `pointer-events: none` so the map stays draggable around it, and a child
   that does not opt back in is transparent to the pointer: the press falls through to
   the stage, which reads it as a click on empty chart and clears the dossier. The card
   looks solid and quietly wipes the selection. `.zoom` opts in for the same reason, and
   the stopPropagation on `.hud.br` only helps once the element receives the event. */
.keybox {
  pointer-events: auto; background: var(--panel-t); border: 1px solid var(--rule);
  border-radius: 3px; padding: 8px 11px 9px; backdrop-filter: blur(6px);
}
.keybox .lbl { display: block; margin-bottom: 5px }
.scalebar { display: flex; flex-direction: column; gap: 3px }
.scalebar .bar { height: 5px; border: 1px solid var(--ink-3); border-top: none }
.scalebar .t { font-family: var(--f-mono); font-size: 10px; color: var(--ink-3) }
.coord { font-family: var(--f-mono); font-size: 10.5px; color: var(--ink-3) }

.zoom {
  pointer-events: auto; display: flex; flex-direction: column; border: 1px solid var(--rule);
  border-radius: 3px; overflow: hidden; background: var(--panel-t);
}
.zoom button { width: 28px; height: 26px; font-size: 15px; line-height: 1; color: var(--ink-2) }
.zoom button:hover:not(:disabled) { background: var(--rule-soft); color: var(--ink) }
.zoom button:disabled { opacity: .28; cursor: default }
.zoom button + button { border-top: 1px solid var(--rule) }
.zoom .home { font-size: 10px; font-family: var(--f-disp); font-weight: 600; letter-spacing: .06em }

/* ---------- chronoscale ---------- */
.chrono {
  grid-area: chrono; background: var(--panel); border-top: 1px solid var(--rule);
  padding: 8px 16px 10px; display: flex; align-items: center; gap: 16px; position: relative; z-index: 6;
}
.transport { display: flex; gap: 2px; flex: none }
.transport button {
  width: 28px; height: 28px; border: 1px solid var(--rule); border-radius: 2px;
  color: var(--ink-2); display: grid; place-items: center;
}
.transport button:hover { border-color: var(--amber-dim); color: var(--amber) }
.scaleZone { flex: 1; min-width: 0 }
.fan { display: block; width: 100%; height: 16px }
.fan line { stroke: var(--rule); stroke-width: .6 }
.fan line.on { stroke: var(--amber); stroke-width: 1.4 }
.ticks { position: relative; height: 30px; cursor: pointer }
.ticks button {
  position: absolute; top: 0; bottom: 0; width: 16px; transform: translateX(-50%);
  display: flex; flex-direction: column; align-items: center; justify-content: flex-start; padding-top: 1px;
}
.ticks .m { width: 1px; height: 9px; background: var(--ink-3) }
.ticks button.maj .m { height: 13px; background: var(--ink-2) }
.ticks button:hover .m { background: var(--amber-2); width: 2px }
.ticks button.on .m { background: var(--amber); width: 2px; height: 16px }
.ticks .yl { font-family: var(--f-mono); font-size: 9px; color: var(--ink-3); margin-top: 2px }
.ticks button.on .yl { color: var(--amber); font-weight: 500 }
.ticks button:not(.on):not(.maj) .yl { display: none }
.eradesc { flex: none; width: 210px; font-size: 10.5px; color: var(--ink-3); text-align: right; line-height: 1.35 }

/* ---------- error ---------- */
#blazor-error-ui {
  background: var(--danger); bottom: 0; box-shadow: 0 -1px 2px rgba(0, 0, 0, .2); color: #12161d;
  display: none; left: 0; padding: 8px 14px; position: fixed; width: 100%; z-index: 1000; font-size: 12px;
}
#blazor-error-ui .dismiss { cursor: pointer; position: absolute; right: 12px; top: 8px }

@media (max-width: 1180px) { .app { grid-template-columns: 250px minmax(0, 1fr) 300px } }

@media (max-width: 980px) {
  .app { grid-template-columns: minmax(0, 1fr); grid-template-areas: "top" "stage" "chrono" }
  .rail, .doss {
    position: absolute; top: 52px; bottom: 0; width: 290px; z-index: 30;
    transition: transform .18s ease; box-shadow: 0 0 40px rgba(0, 0, 0, .7);
  }
  .rail { left: 0; transform: translateX(-100%) }
  .doss { right: 0; transform: translateX(100%) }
  .rail.open, .doss.open { transform: none }
  .railtoggle { display: flex }
  .eradesc { display: none }
  .brand .tag { display: none }
}

@media (max-width: 760px) {
  .topbar {
    flex-wrap: wrap; height: auto; padding: 7px 12px 8px; gap: 8px 12px;
    align-items: center; justify-content: space-between;
  }
  .brand h1 { font-size: 13px }
  .eranow { flex: 0 1 auto; order: 1 }
  .eranow .yr { font-size: 16px }
  .eranow .nm { display: none }
  .railtoggle { order: 3 }
  .rail, .doss { top: auto; height: calc(100% - 96px); bottom: 0; width: min(300px, 86vw) }
  .ticks button .yl { display: none }
  .chrono { padding: 8px 12px 10px; gap: 10px }

  /* The stage is the whole width here and every pixel of it is the map. */
  .hud.br { display: none }
}

@media (prefers-reduced-motion: reduce) { * { transition: none !important; animation: none !important } }

/* ---------------------------------------------------------------- search
   Ported from the original. The list is absolutely positioned over the rail
   rather than pushing it, so the rail below does not jump as the user types. */
.searchwrap { position: relative }

input[type=search] {
  width: 100%; padding: 7px 9px; background: var(--deep); border: 1px solid var(--rule);
  border-radius: 2px; color: var(--ink); font-family: var(--f-body); font-size: 12.5px
}
input[type=search]::placeholder { color: var(--ink-3) }
input[type=search]:focus { outline: none; border-color: var(--amber-dim) }

.results {
  position: absolute; top: 100%; left: 0; right: 0; margin-top: 3px; background: #0f151f;
  border: 1px solid var(--rule); border-radius: 2px; max-height: 270px; overflow-y: auto;
  z-index: 20; box-shadow: 0 12px 28px rgba(0, 0, 0, .6)
}
.results:empty { display: none }
.results button {
  display: flex; width: 100%; align-items: center; gap: 8px; padding: 6px 9px; text-align: left
}
.results button:hover, .results button.on { background: var(--rule-soft) }
.results .dot { width: 7px; height: 7px; border-radius: 50%; flex: none }
.results .rn { flex: 1; font-size: 12.5px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis }
.results .rf { font-family: var(--f-mono); font-size: 10px; color: var(--ink-3) }

/* A section label that is also its collapse control, shared by the realm list and the
   chart options. The whole strip is the hit target rather than just the chevron: the
   rail is taller than most windows, and a reader folding a section away to reach what
   is under it should not have to aim at a 10px arrow.

   The tally is optional and means "showing out of all" in both places - realms drawn,
   options switched on. It is what makes a folded section still say something. */
.secthead {
  display: flex; align-items: center; gap: 8px; width: 100%; padding: 0;
  margin-bottom: 9px; text-align: left;
}
.secthead .lbl { flex: 1; cursor: pointer }
.secthead:hover .lbl, .secthead:hover .chev { color: var(--ink-2) }
.secthead .tally { font-family: var(--f-mono); font-size: 10.5px; color: var(--ink-3) }
.secthead .tally .of { color: #2f3947 }
.secthead .chev { color: var(--ink-3); transition: transform .16s ease; flex: none }
.secthead[aria-expanded="false"] .chev { transform: rotate(-90deg) }

/* ------------------------------------------------------- faction list
   Ported from the original, plus a collapse it did not have.

   The one rule that is not the original's is the height. It uses
   `.sect.grow{flex:1;min-height:0}` so the list takes the rail's spare space,
   which collapses the list to nothing the moment the rail's own content
   overflows - and with 37 realms it always does. A bounded max-height gives
   the list its own scroll at every rail height instead. */

/* Negative margin then equal padding: the rows run to the panel edge so the
   scrollbar sits against it, while the text stays on the rail's own margin. */
.facscroll { overflow-y: auto; max-height: 42vh; margin: 0 -14px; padding: 0 14px }
/* The row is a div wrapping two buttons - the visibility toggle and the go-to
   arrow - because a button cannot be nested inside another button. The row
   keeps the padding and the hover so the two read as one strip. */
.facrow {
  display: flex; align-items: center; padding: 3px 4px;
  border-radius: 2px;
}
.facrow:hover { background: var(--rule-soft) }
.facrow .factog {
  display: flex; align-items: center; gap: 8px; flex: 1; min-width: 0;
  text-align: left;
}
.facrow .sw {
  width: 11px; height: 11px; border-radius: 2px; flex: none;
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .16);
}
.facrow .fn {
  flex: 1; font-size: 12px; white-space: nowrap; overflow: hidden;
  text-overflow: ellipsis; color: var(--ink);
}
.facrow .fc { font-family: var(--f-mono); font-size: 10.5px; color: var(--ink-3) }
.facrow.off .fn, .facrow.off .fc { color: var(--ink-3); text-decoration: line-through }
.facrow.off .sw { opacity: .25 }

/* Reserved at full size whether or not it is showing, so the names and counts stay
   in their columns and the rows do not shift under the pointer as it moves down the
   list. Revealed on hover or focus: 37 rows of arrows would compete with the
   swatches, which are what the list is actually for. It stays at full strength on a
   hidden realm - where a realm is does not depend on whether it is drawn. */
.facrow .facgo {
  display: flex; align-items: center; justify-content: center;
  width: 20px; height: 20px; flex: none; margin-left: 6px;
  border-radius: 2px; color: var(--ink-3); opacity: 0;
  transition: opacity .12s ease, color .12s ease;
}
.facrow:hover .facgo, .facrow .facgo:focus { opacity: 1 }
.facrow .facgo:hover { color: var(--ink); background: var(--rule-soft) }

/* Coarse pointers get no hover, so the control would never appear. */
@media (hover: none) {
  .facrow .facgo { opacity: 1 }
}

.facfoot {
  display: flex; gap: 12px; margin-top: 9px; padding-top: 9px;
  border-top: 1px solid var(--rule-soft);
}
.link {
  font-family: var(--f-disp); font-weight: 600; font-size: 10px; letter-spacing: .1em;
  text-transform: uppercase; color: var(--ink-3);
}
.link:hover { color: var(--amber) }

/* ------------------------------------------------------------ notice
   The circled ? in the topbar, and the dialog it opens. */
.help {
  flex: none; width: 24px; height: 24px; border-radius: 50%; border: 1px solid var(--rule);
  color: var(--ink-3); font-family: var(--f-disp); font-weight: 700; font-size: 12px;
  line-height: 1; display: flex; align-items: center; justify-content: center;
}
.help:hover { color: var(--amber); border-color: var(--amber-dim) }

.modalback {
  position: fixed; inset: 0; z-index: 200; display: flex; align-items: center;
  justify-content: center; padding: 24px; background: rgba(3, 5, 9, .72);
  backdrop-filter: blur(3px);
}
.modal {
  width: min(620px, 100%); max-height: 100%; display: flex; flex-direction: column;
  background: var(--panel); border: 1px solid var(--rule); border-radius: 4px;
  box-shadow: 0 24px 60px rgba(0, 0, 0, .7);
}
.modal .mh {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  padding: 11px 14px; border-bottom: 1px solid var(--rule);
}
.modal .x { color: var(--ink-3); font-size: 17px; line-height: 1; padding: 2px 4px }
.modal .x:hover { color: var(--danger) }
.mbody { overflow-y: auto; padding: 4px 16px 16px; font-size: 12.5px; color: var(--ink-2) }
.mbody h3 {
  font-family: var(--f-disp); font-weight: 600; font-size: 11px; letter-spacing: .1em;
  text-transform: uppercase; color: var(--amber); margin: 16px 0 6px;
}
.mbody p { margin: 0 0 9px; line-height: 1.6 }
/* The only anchors in the app. There is no site-wide link rule to inherit from, so a
   notice link would otherwise arrive in the browser's own blue on a dark panel. It
   breaks anywhere because the SUCKit URL is 56 characters and the dialog is narrower
   than that on a phone. */
.mbody a {
  color: var(--ice); text-decoration: underline; text-decoration-color: var(--amber-dim);
  text-underline-offset: 2px; overflow-wrap: anywhere;
}
.mbody a:hover, .mbody a:focus-visible { color: var(--amber); text-decoration-color: var(--amber) }
.mbody .hint { color: var(--ink-3) }
.mbody .warn { color: var(--danger) }
