/* ── Periastrum ─────────────────────────────────────────────────── */
@font-face { font-family: 'Fraunces'; font-style: normal; font-weight: 300 700; font-display: swap; src: url(assets/fraunces-roman-latin.woff2) format('woff2'); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; }
@font-face { font-family: 'Fraunces'; font-style: italic; font-weight: 300 700; font-display: swap; src: url(assets/fraunces-italic-latin.woff2) format('woff2'); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; }
@font-face { font-family: 'Fraunces'; font-style: normal; font-weight: 300 700; font-display: swap; src: url(assets/fraunces-roman-ext.woff2) format('woff2'); unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; }
@font-face { font-family: 'Fraunces'; font-style: italic; font-weight: 300 700; font-display: swap; src: url(assets/fraunces-italic-ext.woff2) format('woff2'); unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; }
/* the display faces (r43, the owner: "Victorian is ok, art deco ok… definitely not medieval"). Gloock (Duarte Pinto, OFL, 2022) is a
 * Didone with the contrast turned all the way up — an engraved plate on a dark field, nineteenth-century bones and no pastiche.
 * Abril Fatface (TypeTogether, OFL) is the Victorian fat face a paper of record set its name in; Limelight (Sorkin Type, OFL) is
 * 1930s cinema deco, for the paper that shouts. All three carry the whole Polish alphabet. Licences in assets/type/.
 * Nothing downloads until something on screen asks for the face, so the two mastheads cost nothing until a paper is opened. */
@font-face { font-family: 'Gloock'; font-style: normal; font-weight: 400; font-display: swap; src: url(assets/type/gloock-latin.woff2) format('woff2'); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; }
@font-face { font-family: 'Gloock'; font-style: normal; font-weight: 400; font-display: swap; src: url(assets/type/gloock-ext.woff2) format('woff2'); unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; }
@font-face { font-family: 'Abril Fatface'; font-style: normal; font-weight: 400; font-display: swap; src: url(assets/type/abrilfatface-latin.woff2) format('woff2'); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; }
@font-face { font-family: 'Abril Fatface'; font-style: normal; font-weight: 400; font-display: swap; src: url(assets/type/abrilfatface-ext.woff2) format('woff2'); unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; }
@font-face { font-family: 'Limelight'; font-style: normal; font-weight: 400; font-display: swap; src: url(assets/type/limelight-latin.woff2) format('woff2'); unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; }
@font-face { font-family: 'Limelight'; font-style: normal; font-weight: 400; font-display: swap; src: url(assets/type/limelight-ext.woff2) format('woff2'); unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; }

/* ══ the dials ═══════════════════════════════════════════════════════════════════════════════════════════════════════════
 * Everything worth tweaking lives in the one :root block below. Nothing under it holds a colour, a size or a duration of
 * its own except where a value is used exactly once and means nothing anywhere else.
 *
 * HOW TO RESKIN — five dials move the mood more than all the rest put together:
 *   1. --paper-rgb   the light. Every text tone, every hairline, every field and every ring is a tint of it.
 *   2. --night-rgb   the dark. The sky, the panes, the scrims and the shadow behind HUD text.
 *   3. --gold-rgb    the one warm accent: the chosen tab, credits, names, the pill you are meant to press.
 *   4. --serif       the voice. --display is the engraved face over it; set both to the same family for a plainer game.
 *   5. --r-pill      the shape. 999px is the whole game's roundness; drop it to 4px and it turns severe.
 * The three channel variables are written as bare numbers ("243 236 210") so a tint can be asked for as
 * rgb(var(--paper-rgb) / .38): change the base once and every tint of it follows.
 * ═══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════ */
:root {
  /* 2026-10-08, the owner: "can we make metal color (pings, marks, etc/ in palette) a bit more vivid? are these tunable in css constants?"
   * The sensor palette: what a ping's echo is made of, as "r, g, b" (js/ping.js TINT reads these; its own values are the fallback). The
   * crown's rays, the chart's ping bearings and the sim card's swatches all take them from here. Metal was 225, 205, 255 until 10-08. */
  --ping-metal: 200, 150, 255;
  --ping-rock: 170, 200, 160;
  --ping-ice: 160, 215, 255;
  --ping-gas: 255, 170, 110;
  --ping-star: 255, 214, 120;
  --ping-plain: 190, 255, 235;
  --map-mark-l: 30;   /* the chart's ping marks: the echo's hue and saturation at this lightness (a percentage), dark ink on the paper (js/map.js markInk) */
  /* ── typefaces ─────────────────────────────────────────────── */
  --serif: 'Fraunces', 'Iowan Old Style', 'Palatino Linotype', Palatino, Georgia, serif;   /* the text face */
  --display: 'Gloock', 'Fraunces', Georgia, serif;                                          /* every heading */
  --text-face: var(--serif);      /* aliases, so a rule reads by role */
  --display-face: var(--display);
  --masthead-press: 'Abril Fatface', var(--display);   /* the paper of record's name */
  --masthead-wild: 'Limelight', var(--display);        /* the paper that shouts */
  --mono: ui-monospace, Menlo, Consolas, monospace;    /* telemetry and the save text */
  --w-text: 300;        /* the body weight: Fraunces is a variable face, 300 is its reading weight */
  --w-normal: 400;      /* headings, and every b/strong in the game, which is a colour and not a weight */
  --w-semi: 600;        /* the paper's dateline */
  --w-bold: 700;        /* the paper's headlines and drop cap */
  --i-tabs: italic;     /* the tab bar is set in italic */
  --i-label: italic;    /* so are buttons, fields, numbers and anything spoken */
  --i-off: normal;

  /* ── the type scale (the sizes actually in use, named for what they carry) ── */
  --fs-base: 16px;
  --fs-title: clamp(30px, 6vw, 44px);     /* a pane's h1 */
  --fs-title-card: clamp(30px, 7vw, 42px);/* a card's h2, which is its title */
  --fs-h2: 18px;
  --fs-lede: 18px;
  --fs-xl: 22px;        /* the signature, and "paused" across the sky */
  --fs-lg: 19px;        /* the captain's name */
  --fs-md: 17px;        /* a quest's summary line, a crewmate's name */
  --fs-body: 16px;      /* pane paragraphs, summaries, card text, every input a phone must not zoom */
  --fs-say: 15.5px;     /* a spoken line */
  --fs-row: 15px;       /* the rows and the key/value lines */
  --fs-note: 14.5px;    /* the key table, the chart's notes */
  --fs-tab: 14px;
  --fs-sm: 13.5px;      /* toasts, small notes, a crewmate's story */
  --fs-label: 13px;     /* small buttons, tags, the pills in a row */
  --fs-cap: 12.5px;     /* captions, the sandbox's dims, the readout under the HUD */
  --fs-xs: 12px;        /* tags, the phone's tab bar, the small round buttons */
  --fs-xxs: 11px;       /* the HUD bar labels, the save box */
  --fs-nano: 10.5px;    /* telemetry, the gauge numbers */
  --fs-whisper: clamp(15px, 2.6vw, 18px);
  /* the paper has a scale of its own: it is printed, not lit */
  --fs-n-masthead: clamp(27px, 6.2vw, 50px);
  --fs-n-masthead-wild: clamp(22px, 5.2vw, 42px);
  --fs-n-lead: clamp(23px, 4.6vw, 33px);
  --fs-n-head: clamp(19px, 3.4vw, 26px);
  --fs-n-lede: 16px;
  --fs-n-body: 13.6px;
  --fs-n-drop: 42px;
  --fs-n-small: 11.5px;   /* byline, classifieds, the dateline */
  --fs-n-cap: 11px;       /* a plate's caption */
  --fs-n-rule: 10.5px;    /* the small-caps rules: meta, the plate's mark, the classifieds' head */
  --fs-n-plate: 10px;

  /* ── line heights ──────────────────────────────────────────── */
  --lh-1: 1;            /* a masthead */
  --lh-head: 1.05;      /* a title of two lines */
  --lh-n-head: 1.14;
  --lh-cap: 1.35;
  --lh-n-class: 1.4;
  --lh-say: 1.45;       /* the whisper and the paper's lede */
  --lh-lede: 1.5;
  --lh-mono: 1.5;       /* telemetry */
  --lh-n-body: 1.5;
  --lh-snug: 1.55;      /* the HUD's right column, a spoken line, a card */
  --lh-body: 1.6;       /* a pane paragraph */
  --lh-drop: .78;

  /* ── letter-spacings ───────────────────────────────────────── */
  --ls-tight: -.005em;  /* the fat faces, which are tight by nature */
  --ls-display: .005em;
  --ls-h2: .01em;
  --ls-masthead: .015em;
  --ls-credit: .02em;
  --ls-whisper: .03em;
  --ls-tab: .04em;
  --ls-hud: .05em;
  --ls-label: .06em;    /* the commonest: small labels and buttons */
  --ls-btn: .08em;
  --ls-place: .09em;
  --ls-wide: .1em;      /* the HUD bar labels */
  --ls-rule: .12em;     /* the paper's small caps */
  --ls-badge: .18em;    /* "sandbox" */
  --ls-lvl: .2em;       /* a level's dots, the classifieds' head */
  --ls-abd: 2px;        /* an ability's score */
  --ls-none: 0;

  /* ── colours: the three bases, as channels, so every tint follows one change ── */
  --paper-rgb: 243 236 210;   /* the light — text, hairlines, fields, rings */
  --night-rgb: 5 7 14;        /* the sky */
  --pane-rgb: 4 5 11;         /* a hair darker than the sky: the tab bar and the panes laid over it */
  --gold-rgb: 255 224 160;    /* the one warm accent */
  --teal-rgb: 190 255 235;    /* the sensors, and the pilot's own line */
  --blue-rgb: 150 180 255;    /* the loop, and the pilot's voice in the log */
  --ink-rgb: 20 18 14;        /* printer's ink, on the paper only */

  /* grounds */
  --night: rgb(var(--night-rgb));                 /* the page */
  --sheet: rgb(var(--pane-rgb) / .92);            /* a tab pane over the sky */
  --tabbar: rgb(var(--pane-rgb) / .86);           /* the tab bar: smoked glass, no blur (2026-09-28: a blur over the moving sky was made again every frame; docs/perigee/0928_performance.md §2 idea 3) */
  --scrim-btn: rgb(var(--night-rgb) / .72);       /* under a touch button, over the moving sky: no blur, for the same reason */
  --card-bg: rgb(var(--night-rgb) / .82);         /* a card */
  --toast-bg: rgb(var(--night-rgb) / .75);
  --scrim: rgb(var(--night-rgb) / .55);           /* under a touch button, and inside a field */
  --scrim-soft: rgb(var(--night-rgb) / .5);
  --option-bg: #0c0f18;                           /* a native select's list, which cannot be transparent */
  --news-ground: #bcbab1;                         /* grey newsprint */
  --news-fibre-rgb: 255 255 255;                  /* the fibre across the grain */
  --news-light-rgb: 250 249 244;                  /* the lit corner of the sheet */
  --news-shade-rgb: 58 54 44;                     /* the shaded one */

  /* text tones */
  --paper: rgb(var(--paper-rgb));                 /* what is being said now */
  --paper-dim: rgb(var(--paper-rgb) / .66);       /* what is being said about it */
  --paper-faint: rgb(var(--paper-rgb) / .38);     /* what is only labelled */
  --ink: rgb(var(--ink-rgb));                     /* the paper's three tones */
  --ink-dim: rgb(var(--ink-rgb) / .74);
  --ink-faint: rgb(var(--ink-rgb) / .5);

  /* accents */
  --gold: rgb(var(--gold-rgb));                   /* the chosen tab, credits, a name, the pill to press */
  --gold-lit: #fff6d8;                            /* the same pill under the pointer */
  --teal: rgb(var(--teal-rgb) / .85);             /* the sensors */
  --teal-lit: rgb(var(--teal-rgb));
  --blue: rgb(var(--blue-rgb) / .85);             /* the loop */
  --you: #9fd3c7;                                 /* the pilot's own line in a talk: verdigris */
  --you-log: rgb(var(--blue-rgb) / .9);           /* the pilot's own voice in the log */
  --danger: #ff9a80;                              /* fuel running out */
  --bad: #ffb0a0;                                 /* a tag that warns */
  --bad-rgb: 255 150 130;                         /* …and the rule round it */
  --hot-rgb: 255 196 96;                          /* a tag that is live */
  --hot: rgb(var(--hot-rgb) / .9);
  --navy: rgb(96 124 190);                        /* the loop's swatch */

  /* the HUD gauges, one colour each */
  --bar-hull: #e0b090;
  --bar-shields: #7fb8ff;
  --bar-tractor: #8fd6c8;                         /* 2026-09-29: the tractor's switch (js/game/tractor.js) */
  --bar-fuel: var(--gold);
  --bar-drive: #b9a3e6;
  --bar-ping: rgb(150 215 200 / .75);
  --bar-ping-ready: var(--teal-lit);
  --bar-laser: #ffb37a;
  --bar-laser-hot: #ff5a3c;
  --heat: #ff8a6a;                                /* the laser's number when it is too hot */

  /* borders, hairlines and rings */
  --hairline: rgb(var(--paper-rgb) / .08);        /* the rule under every row */
  --line: rgb(var(--paper-rgb) / .22);            /* a drawn border */
  --line-soft: rgb(var(--paper-rgb) / .18);
  --line-faint: rgb(var(--paper-rgb) / .14);
  --line-dim: rgb(var(--paper-rgb) / .12);
  --line-track: rgb(var(--paper-rgb) / .1);       /* the empty part of a bar, and the telemetry box */
  --ring: rgb(var(--paper-rgb) / .25);            /* round a face, a flag, a field */
  --ring-soft: rgb(var(--paper-rgb) / .3);
  --field-bg: rgb(var(--paper-rgb) / .06);        /* an input that sits on a pane */
  --field-gold: var(--gold);                      /* 2026-09-27, the owner: a field you type into is a pill turned over, dark ink on gold */
  --field-gold-lit: var(--gold-lit);              /* …under the pointer, and while it is being typed in */
  --field-ink: var(--ink);                        /* what is typed, and the caret (about 13:1 on the gold) */
  --field-ph: rgb(var(--ink-rgb) / .62);          /* the placeholder: faded ink that still reads at 4.5:1 on the gold */
  --field-edge: var(--gold-edge);
  --field-focus: var(--paper);                    /* the focus ring, drawn outside the field, on the dark pane */
  --field-sel: rgb(var(--ink-rgb) / .88);         /* a selection inside a field: gold letters on ink, the pill the right way up */
  --ghost-bg: rgb(var(--paper-rgb) / .05);        /* a quiet button */
  --ghost-bg-hi: rgb(var(--paper-rgb) / .12);     /* the same under the pointer */
  --gold-line: rgb(var(--gold-rgb) / .55);
  --gold-line-soft: rgb(var(--gold-rgb) / .45);
  --gold-edge: rgb(var(--gold-rgb) / .7);
  --gold-edge-lit: rgb(var(--gold-rgb) / .75);
  --gold-wash: rgb(var(--gold-rgb) / .06);        /* the pill's ground */
  --gold-wash-hi: rgb(var(--gold-rgb) / .16);     /* the same, lit */
  --gold-wash-on: rgb(var(--gold-rgb) / .2);      /* a chosen pill */
  --teal-line: rgb(var(--teal-rgb) / .4);
  --blue-line: rgb(var(--blue-rgb) / .4);
  --ink-line: rgb(var(--ink-rgb) / .45);
  --ink-rule: rgb(var(--ink-rgb) / .5);           /* the double rules */
  --bad-line: rgb(var(--bad-rgb) / .4);
  --hot-line: rgb(var(--hot-rgb) / .35);

  /* shadows and overlays */
  --glow-hud: 0 1px 6px rgb(var(--night-rgb) / .95);           /* HUD text against the sky */
  --glow-soft: 0 2px 14px rgb(var(--night-rgb) / .9);
  --glow-wide: 0 2px 18px rgb(var(--night-rgb) / .9);
  --shadow-map: 0 8px 34px rgb(0 0 0 / .55), 0 0 0 1px rgb(60 40 20 / .6);
  --shadow-news: 0 30px 70px rgb(0 0 0 / .66), 0 0 0 1px rgb(var(--ink-rgb) / .35);
  --blur-pane: blur(8px);
  --blur-card: blur(10px);
  --blur-btn: blur(6px);

  /* ── shape ─────────────────────────────────────────────────── */
  --r-pill: 999px;      /* every button, tag, field and segment */
  --r-round: 50%;       /* the touch buttons, the faces, the dots */
  --r-card: 18px;
  --r-field: 12px;      /* the save box, which is a textarea and cannot be a pill */
  --r-box: 10px;        /* the telemetry frame */
  --r-map: 4px;
  --r-bar: 2px;
  --bw: 1px;            /* a hairline */
  --bw-thick: 2px;      /* a chosen tab's underline, a chosen face's ring */
  --bw-rule: 3px;       /* the paper's double rules */

  /* ── spacing ───────────────────────────────────────────────── */
  --tabs-h: 44px;
  --sat: env(safe-area-inset-top);
  --sab: env(safe-area-inset-bottom);
  --sal: env(safe-area-inset-left);
  --sar: env(safe-area-inset-right);
  --tab-gutter: 6px;    /* the tab bar's own left and right */
  --tab-gutter-sm: 2px;
  --tab-pad: 9px;       /* inside one tab */
  --tab-pad-sm: 7px;
  --pane-max: 40rem;    /* the measure of a pane's column */
  --pane-pad-x: 16px;
  --pane-pad-y: 18px;
  --pane-pad-b: 40px;
  --hud-inset: 14px;    /* the HUD's margin from the edge */
  --gap-xs: 6px;        /* the gap scale: everything that sits beside something else */
  --gap-sm: 8px;
  --gap: 12px;          /* the standard gap between two things on a line */
  --gap-lg: 14px;
  --gap-xl: 16px;
  --row-pad: 8px;       /* above and below a row */
  --kv-pad: 7px;
  --bars-w: min(236px, 58vw);   /* how long a HUD bar runs */
  --bar-h: 4px;                 /* and how thick */
  --bar-gap: 5px;
  --bar-label-w: 52px;
  --bar-knob-w: 44px;           /* the column the dials sit in, wide enough for the longest word on one (r59: "sport") */
  --tap: 44px;          /* the smallest thing a thumb is asked to hit */
  --tap-sm: 32px;       /* …on a pane, where the pointer is a finger tip and not a thumb */
  --btn-touch: 76px;    /* fire */
  --btn-touch-lg: 88px; /* thrust */
  --btn-touch-sm: 58px; /* strafe, ping, listen */
  --stick: 124px;       /* a joystick's ring, on a phone held sideways */
  --face: 26px;         /* a face in a line of text */
  --face-big: 54px;     /* a face in a hail */
  --face-crew: 56px;    /* a face on the crew tab */
  --face-whisper: 44px; /* a face beside the whisper */
  --pill-pad: 6px 12px;
  --pill-pad-lg: 10px 22px;
  --pill-pad-sm: 7px 14px;
  --card-pad: 24px 22px 20px;
  --news-pad: 24px 22px 18px;
  --news-pad-sm: 18px 16px 14px;
  --chk: 18px;          /* a checkbox */

  /* ── motion ────────────────────────────────────────────────── */
  --t-fast: .12s;       /* the laser bar, which must feel like a trigger */
  --t: .2s;             /* a button lighting up */
  --t-slow: .25s;       /* a tab changing, a bar filling */
  --t-fade: .3s;        /* a pane and a toast arriving */
  --t-card: .8s;        /* a card arriving: slow, so it is read as a thing and not a flash */
  --t-whisper: .8s;     /* the whisper going out */
  --t-urge: 1s;         /* the low-fuel line breathing */
  --t-hot: .7s;         /* the laser bar pulsing when it is too hot */
  --t-typing: 1.25s;    /* three dots */
  --ease: ease;
  --ease-io: ease-in-out;

  /* ── layers ────────────────────────────────────────────────── */
  --z-hud: 10;
  --z-touch: 12;
  --z-pane: 15;
  --z-tabs: 20;
  --z-toast: 30;
  --z-card: 40;
}
* { box-sizing: border-box; -webkit-tap-highlight-color: transparent; }
html, body { height: 100%; margin: 0; }
body { background: var(--night); color: var(--paper); font-family: var(--text-face); font-weight: var(--w-text); overflow: hidden; position: fixed; inset: 0; -webkit-font-smoothing: antialiased; touch-action: none; user-select: none; -webkit-user-select: none; overscroll-behavior: none; }
#c { position: fixed; inset: 0; width: 100%; height: 100%; display: block; touch-action: none; cursor: crosshair; }
.hidden { display: none !important; }
.sr-only { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
button { font-family: inherit; }
body.pl .lang-en, body:not(.pl) .lang-pl { display: none; }

/* tabs across the top */
#tabs { position: fixed; top: 0; left: 0; right: 0; height: calc(var(--tabs-h) + var(--sat)); padding: var(--sat) calc(var(--tab-gutter) + var(--sar)) 0 calc(var(--tab-gutter) + var(--sal)); display: flex; align-items: stretch; gap: 0; background: var(--tabbar); border-bottom: var(--bw) solid var(--hairline); overflow-x: auto; overflow-y: hidden; scrollbar-width: none; z-index: var(--z-tabs); }
#tabs::-webkit-scrollbar { display: none; }
#tabs button { flex: 1 0 auto; background: none; border: 0; border-bottom: var(--bw-thick) solid transparent; color: var(--paper-faint); font-style: var(--i-tabs); font-size: var(--fs-tab); letter-spacing: var(--ls-tab); padding: 0 var(--tab-pad); cursor: pointer; transition: color var(--t-slow), border-color var(--t-slow); white-space: nowrap; min-width: var(--tap); }
#tabs button:hover, #tabs button:focus-visible { color: var(--paper-dim); outline: none; }
#tabs button.on { color: var(--gold); border-bottom-color: var(--gold-edge); }
#tabs button.off { opacity: .4; }
#tabs .spacer { flex: 1 1 auto; }
#btnLang { flex: 0 0 auto; padding: 0 4px; }
#btnLang svg { width: 22px; height: 22px; border-radius: var(--r-round); box-shadow: 0 0 0 var(--bw) var(--ring); vertical-align: middle; }
@media (max-width: 480px) { #tabs { padding-left: calc(var(--tab-gutter-sm) + var(--sal)); padding-right: calc(var(--tab-gutter-sm) + var(--sar)); scroll-behavior: smooth; } #tabs button { font-size: var(--fs-xs); padding: 0 var(--tab-pad-sm); min-width: 0; letter-spacing: var(--ls-none); flex: 0 0 auto; } #btnLang { padding: 0 3px; position: sticky; right: 0; background: linear-gradient(90deg, rgb(var(--pane-rgb) / 0), rgb(var(--pane-rgb) / .82) 28%); } #btnLang svg { width: 20px; height: 20px; } }

/* hud on the fly tab */
#hud { position: fixed; inset: 0; pointer-events: none; z-index: var(--z-hud); }
.hud-top { position: absolute; top: calc(var(--tabs-h) + var(--sat) + 10px); left: calc(var(--hud-inset) + var(--sal)); right: calc(var(--hud-inset) + var(--sar)); display: flex; justify-content: space-between; align-items: flex-start; gap: var(--gap); }
/* the bars, and under them the three gauges: drive and sensors fill as they recharge, the laser fills as it heats */
.bars { display: flex; flex-direction: column; gap: var(--bar-gap); width: var(--bars-w); }
.bar { display: grid; grid-template-columns: var(--bar-label-w) 1fr 40px var(--bar-knob-w); align-items: center; gap: var(--gap-sm); font-size: var(--fs-xxs); letter-spacing: var(--ls-wide); color: var(--paper-dim); text-shadow: var(--glow-hud), 0 0 2px rgb(var(--night-rgb) / 1); }
.bar i { display: block; height: var(--bar-h); border-radius: var(--r-bar); background: var(--line-track); overflow: hidden; }
.bar b { display: block; height: 100%; width: 100%; border-radius: var(--r-bar); transition: width var(--t-slow); }
#barHull { background: var(--bar-hull); } #barShields { background: var(--bar-shields); } #barTractor { background: var(--bar-tractor); } #barFuel { background: var(--bar-fuel); }
/* 2026-09-28, the battery (js/game/battery.js): a pale green, brighter while it charges, red when low; it stays lit on a dark ship, and a dry tank blinks the fuel bar as a dark ship did */
#barBatt { background: rgba(150, 205, 160, 0.8); } #barBatt.charging { background: rgb(170, 235, 180); } #barBatt.low { background: var(--bad); } .bar em.low { color: var(--bad); }
body.dark #hud .bar.batt { opacity: 1; } body.dry #hud .bar.fuel, body.dry #hud .bar:nth-child(3) { animation: darkblink 1.6s ease-in-out infinite; }
/* the near-body line is the only HUD text whose length is the world's choice, so it is the one that must give way. The two HUD
   columns are flex items: without min-width 0 the right one cannot shrink below its longest line and pushes into the bars on a
   phone, which is what pw38 had been catching at random for rounds (r39). It now clips instead. */
.hud-right { text-align: right; font-size: var(--fs-cap); letter-spacing: var(--ls-hud); color: var(--paper-faint); text-shadow: var(--glow-hud); font-variant-numeric: tabular-nums; line-height: var(--lh-snug); min-width: 0; max-width: calc(100% - var(--bars-w) - var(--hud-inset)); }
.hud-right #hudCredits { color: var(--gold); font-size: var(--fs-row); font-style: var(--i-label); letter-spacing: var(--ls-credit); }
.hud-right #hudNear { color: var(--paper-dim); font-style: var(--i-label); }
#hudNear { display: block; max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* 2026-09-28, the "brake call" bench, the owner: "autopilot: {name}. any hand on the controls takes her back. — I know it by heart.
 * Can we have some 'autopilot on' light next to the autopilot setting? Or the autopilot setting button gently pulsating?" A light,
 * gold on dark, beside the word (js/ui.js hud(): #hudAuto.hidden toggled by G.auto); it pulses, or — prefers-reduced-motion — holds
 * steady, which is the pulsing button's own point without the motion. */
.autoBadge { display: flex; align-items: center; justify-content: flex-end; gap: 6px; margin-top: 2px; color: var(--gold); font-style: var(--i-label); letter-spacing: var(--ls-tab); font-size: var(--fs-cap); }
.autolight { width: 7px; height: 7px; border-radius: var(--r-round); background: var(--gold); box-shadow: 0 0 6px 2px rgb(var(--gold-rgb) / .7); flex: 0 0 auto; animation: autoPulse 2.2s ease-in-out infinite; }
@keyframes autoPulse { 0%, 100% { opacity: .5; } 50% { opacity: 1; } }
/* the tutorial's highlight (js/game/tutorial.js): the control to learn breathes in the gold of the autopilot light; the sandbox badge is not shown while the lesson runs (the pilot is being taught, not testing) */
.tutGlow { animation: tutPulse 1.6s ease-in-out infinite; box-shadow: 0 0 0 2px rgb(var(--gold-rgb) / .9), 0 0 12px 3px rgb(var(--gold-rgb) / .55); }
@keyframes tutPulse { 0%, 100% { box-shadow: 0 0 0 2px rgb(var(--gold-rgb) / .9), 0 0 6px 1px rgb(var(--gold-rgb) / .35); } 50% { box-shadow: 0 0 0 4px rgb(var(--gold-rgb) / .9), 0 0 18px 6px rgb(var(--gold-rgb) / .7); } }
@media (prefers-reduced-motion: reduce) { .tutGlow { animation: none; } }
body.tutoring #hudSandbox { display: none; }
@media (prefers-reduced-motion: reduce) { .autolight { animation: none; opacity: 1; } }
/* 2026-09-29: "fly on with company", offered beside the autopilot light just after it let go for company (js/ui.js hud; the owner could not find the setting) */
.autoCo { pointer-events: auto; display: inline-block; margin-top: 4px; font-family: inherit; font-style: var(--i-label); font-size: var(--fs-cap); letter-spacing: var(--ls-tab); color: var(--gold); background: var(--scrim-soft); border: var(--bw) solid var(--gold-line); border-radius: var(--r-pill); padding: 2px 10px; cursor: pointer; }
.autoCo:hover, .autoCo:focus-visible { background: rgb(var(--gold-rgb) / .14); }
#hudLow { position: absolute; top: calc(var(--tabs-h) + var(--sat) + 86px); left: 0; right: 0; text-align: center; font-style: var(--i-label); font-size: var(--fs-tab); letter-spacing: var(--ls-wide); color: var(--danger); animation: urge var(--t-urge) var(--ease-io) infinite alternate; }
@keyframes urge { from { opacity: .55; } to { opacity: 1; } }
#whisper { position: absolute; left: 0; right: 0; bottom: calc(92px + var(--sab)); text-align: center; padding: 0 28px; max-width: 46rem; margin: 0 auto; line-height: var(--lh-say); font-style: var(--i-label); font-size: var(--fs-whisper); letter-spacing: var(--ls-whisper); color: var(--paper-dim); opacity: 0; transition: opacity var(--t-whisper); text-shadow: var(--glow-wide); }
#whisper.on { opacity: 1; }
/* the whispers are a stack (r50): the one being read at the bottom, new ones above it, each with a ring that empties and a cross to dismiss it */
#whisper { display: flex; flex-direction: column; justify-content: flex-end; align-items: center; gap: 6px; pointer-events: none; }
.wcard { display: flex; align-items: center; gap: 10px; max-width: 100%; opacity: 0; transform: translateY(-6px); transition: opacity .3s ease, transform .3s ease; }
.wcard.in { opacity: 1; transform: none; }
.wcard.out { opacity: 0; transform: translateY(6px); }
.wcard.wait.in { opacity: .5; }
.wcard.urgent { color: var(--gold); }
.wcard.ghost { font-family: var(--mono); font-style: normal; letter-spacing: .06em; }
.wcard .wtext { text-align: center; }
.wcard .wface { width: var(--face-whisper); height: var(--face-whisper); border-radius: var(--r-round); object-fit: cover; flex: none; box-shadow: 0 0 0 var(--bw) var(--ring-soft), 0 2px 12px rgb(var(--night-rgb) / .8); }
.wcard .wface.hidden { display: none; }
.wcard .wx { pointer-events: auto; flex: none; width: 22px; height: 22px; padding: 0; border: 0; background: none; cursor: pointer; opacity: .45; transition: opacity .2s; color: inherit; }
.wcard .wx:hover, .wcard .wx:focus-visible { opacity: 1; }
.wcard .wx svg { width: 22px; height: 22px; display: block; fill: none; stroke: currentColor; stroke-linecap: round; }
.wcard .wx .wtrack { stroke-width: 1.2; opacity: .25; }
.wcard .wx .wring { stroke-width: 1.8; stroke-dasharray: 62.83; stroke-dashoffset: 0; transition: stroke-dashoffset .12s linear; }
.wcard .wx path { stroke-width: 1.4; opacity: .8; }
body.touch .wcard .wx { width: 30px; height: 30px; } body.touch .wcard .wx svg { width: 30px; height: 30px; }
/* 2026-09-28: a radio card (the patrol's exchanges, js/game/patrolradio.js): one transmission a line */
.wcard.radio .wtext { white-space: pre-line; }
/* 2026-09-28: static on far voices (js/fxstatic.js). A card with a far voice gets a dark field, and on it a strip of sixteen frames of TV
   static (assets/fx/static/static.webp, grey) stepped by a transform animation, screened so its black adds nothing; --static is 0..0.5 by
   the speaker's distance. The layer sits under the words (z-index -1 in the card's own stacking context). Reduced motion: one still frame */
.wcard.radio.far { position: relative; isolation: isolate; padding: 5px 12px; border-radius: 10px; background: rgb(var(--night-rgb) / .55); overflow: hidden; }
.card.hail.far { isolation: isolate; }
.fxstatic { position: absolute; inset: 0; overflow: hidden; pointer-events: none; z-index: -1; opacity: var(--static, 0); mix-blend-mode: screen; border-radius: inherit; }
.fxstatic::before { content: ''; position: absolute; top: 0; left: 0; width: 1600%; height: 100%; background: url(assets/fx/static/static.webp?v=1) 0 0 / 100% 100% no-repeat; animation: fxstatic 1.07s steps(16) infinite; will-change: transform; }
@keyframes fxstatic { to { transform: translateX(-100%); } }
.hidden .fxstatic::before { animation-play-state: paused; }
@media (prefers-reduced-motion: reduce) { .fxstatic::before { animation: none; } }
#whisper.urgent { color: var(--gold); }
/* a dry tank: the instruments go dark, all but the fuel bar, which is the one thing worth looking at (r49) */
body.dark #hud .bar { opacity: 0.28; transition: opacity 0.6s; }
body.dark #hud .bar.fuel, body.dark #hud .bar:nth-child(3) { opacity: 1; animation: darkblink 1.6s ease-in-out infinite; }
@keyframes darkblink { 50% { opacity: 0.45; } }
/* a speaker's face in the log, half the size of a portrait (r47) */
.row.said { display: grid; grid-template-columns: auto 26px 1fr; gap: 8px; align-items: start; }
.row.said .lface { width: 26px; height: 26px; border-radius: 50%; object-fit: cover; display: block; background: rgba(243,236,210,0.06); }
.row.said .lface.none { background: none; }
/* the gallery's own bar, in the fly view, so the world is not behind a panel (r47) */
#galBar { position: fixed; left: 50%; transform: translateX(-50%); top: 56px; z-index: 30; width: min(620px, max(300px, calc(100vw - 580px))); background: rgba(5,7,14,0.82); border: 1px solid rgba(243,236,210,0.18); border-radius: 12px; padding: 8px 12px; backdrop-filter: blur(3px); }
#galBar .say { margin: 6px 0; font-size: 14px; }
#galBar input { flex: 1; min-width: 120px; padding: 6px 12px; font-size: inherit; }   /* its colours are every field's (the end of this file) */
#galBar .simrow { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; }
/* the sim tab's test bench (r46) */
.bench { border: 1px solid var(--line, rgba(243,236,210,0.16)); border-radius: 10px; padding: 10px 12px; margin: 8px 0 14px; }
.bench textarea { width: 100%; box-sizing: border-box; border-radius: 8px; padding: 8px; font-size: inherit; resize: vertical; }
.benchG { display: inline-block; min-width: 108px; }
#whisper.ghost { font-family: var(--mono); font-style: normal; letter-spacing: .06em; }   /* typed on the crew board by nobody aboard (the haunting) */
/* the action line under the ship: kept for the day it is wanted again, but the touch button says it instead */
#hudAction { position: absolute; left: 0; right: 0; bottom: calc(36px + var(--sab)); text-align: center; font-style: var(--i-label); font-size: var(--fs-row); letter-spacing: var(--ls-btn); color: var(--gold); text-shadow: var(--glow-soft); display: none; }
body.touch #whisper { bottom: calc(132px + var(--sab)); padding-left: 16px; padding-right: calc(var(--sar) + 33px + var(--btn-touch-sm) + 12px); }   /* clear of the ping and listen buttons, which stand in a column at the right: the game's voice used to be printed underneath them (review 09-19: 55 px of every line covered at 360, 390 and 412 px) */
#hudSandbox { position: absolute; top: calc(var(--tabs-h) + var(--sat) + 6px); left: 0; right: 0; text-align: center; font-style: var(--i-label); font-size: var(--fs-xs); letter-spacing: var(--ls-badge); color: var(--gold); opacity: .8; text-shadow: var(--glow-hud); }
#hudPaused { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; font-style: var(--i-label); font-size: var(--fs-xl); color: var(--paper-faint); letter-spacing: var(--ls-wide); }
#hudPaused.onShip { inset: auto; display: block; transform: translateX(-50%); white-space: nowrap; text-align: center; line-height: 1; }   /* 2026-10-13: centred under the ship, two lines below her (js/ui.js pausedAt) */

/* touch controls */
#touchui { position: fixed; inset: 0; pointer-events: none; z-index: var(--z-touch); }
#touchui button { pointer-events: auto; position: absolute; font-family: inherit; font-style: var(--i-label); letter-spacing: var(--ls-btn); color: var(--paper-dim); background: var(--scrim-btn); border: var(--bw) solid var(--ring-soft); border-radius: var(--r-round); width: var(--btn-touch); height: var(--btn-touch); font-size: var(--fs-label); cursor: pointer; touch-action: none; -webkit-user-select: none; user-select: none; }
#touchui button:active { background: rgb(var(--gold-rgb) / .22); color: var(--gold); border-color: var(--gold-edge); }
#btnThrust { right: calc(18px + var(--sar)); bottom: calc(26px + var(--sab)); width: var(--btn-touch-lg); height: var(--btn-touch-lg); font-size: var(--fs-tab); }
#btnFire { left: calc(18px + var(--sal)); bottom: calc(26px + var(--sab)); }
#touchui .strafe { display: none; width: var(--btn-touch-sm); height: var(--btn-touch-sm); font-size: 18px; font-style: var(--i-off); bottom: calc(118px + var(--sab)); }
body.touch.strafe #touchui .strafe { display: block; }   /* 2026-09-27, the owner: "No need for strafe onscreen buttons on desktop." A and D strafe there */
/* the sticks (a phone held sideways): the left one burns and strafes, the right one is the heading and, at the rim, the trigger */
.stick { display: none; pointer-events: auto; position: absolute; bottom: calc(14px + var(--sab)); width: var(--stick); height: var(--stick); border-radius: var(--r-round); border: var(--bw) solid var(--ring-soft); background: var(--scrim); touch-action: none; -webkit-user-select: none; user-select: none; }
.stick i { position: absolute; left: 50%; top: 50%; width: 44%; height: 44%; margin: -22% 0 0 -22%; border-radius: var(--r-round); background: rgb(var(--gold-rgb) / .16); border: var(--bw) solid var(--gold-line); pointer-events: none; }
#stickL { left: calc(18px + var(--sal)); } #stickR { right: calc(18px + var(--sar)); }
#stickR.armed { border-color: rgb(255 154 128 / .55); box-shadow: 0 0 0 2px rgb(255 154 128 / .14); } #stickR.hot { border-color: var(--danger); } #stickR.hot i { background: rgb(255 154 128 / .3); border-color: var(--danger); }
body.sticks .stick { display: block; }
body.sticks #btnThrust, body.sticks #touchui .strafe, body.sticks.strafe #touchui .strafe { display: none; }
body.sticks #btnFire { left: auto; right: calc(30px + var(--stick) + var(--sar)); bottom: calc(14px + var(--sab)); }
body.sticks #touchui #btnPing { right: calc(24px + var(--sar)); bottom: calc(24px + var(--stick) + var(--sab)); }
body.sticks #touchui #btnListen { right: calc(84px + var(--sar)); bottom: calc(24px + var(--stick) + var(--sab)); }
body.sticks #actStack { max-width: calc(100vw - 2 * var(--stick) - 190px); }
#btnStrafeL { left: calc(12px + var(--sal)); } #btnStrafeR { left: calc(78px + var(--sal)); }
#hudFtl { color: var(--paper-faint); letter-spacing: var(--ls-label); }
#hudFtl.ready { color: var(--gold); }
#cloudCode { width: 100%; margin-top: 10px; font-family: var(--mono); font-style: var(--i-off); font-size: var(--fs-xs); border-radius: var(--r-field); padding: 8px 10px; box-sizing: border-box; }
#shipCloud b.code { font-family: var(--mono); letter-spacing: .04em; font-weight: 400; }   /* r64: the copy on lorefold.com */
#saveText { width: 100%; margin-top: 10px; font-family: var(--mono); font-style: var(--i-off); font-size: var(--fs-xxs); border-radius: var(--r-field); padding: 10px; box-sizing: border-box; }
/* 2026-09-29, stacked actions (js/ui.js actButtons): #btnAction, the one E runs, on top, and the rest under it, each the same gold pill; the column stands where the one button stood and grows upward */
#actStack { position: absolute; left: 50%; transform: translateX(-50%); bottom: calc(30px + var(--sab)); display: flex; flex-direction: column; align-items: center; gap: 6px; max-width: calc(100vw - 230px); pointer-events: none; }
#touchui #actStack button { position: static; border-radius: var(--r-pill); width: auto; height: auto; min-height: var(--tap); padding: var(--pill-pad-lg); color: var(--gold); border-color: var(--gold-line); background: rgb(var(--gold-rgb) / .1); font-size: var(--fs-row); max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
@media (max-width: 480px) { #touchui #actStack button { white-space: normal; line-height: 1.25; text-align: center; } }   /* P60: on a phone held upright the column is 160 px wide, and "tell him you've flown one" (the lesson's skip) read "tell him you'…"; two lines rather than a cut */
#touchui #actStack button.hidden { display: none; }
#touchui #actStack button.held { opacity: .45; }   /* the top just out of reach, waiting out its grace (K.ACT_GRACE) */
body:not(.touch) #btnThrust, body:not(.touch) #btnFire { display: none; }

/* tab panes */
.tabpane { position: fixed; inset: 0; top: calc(var(--tabs-h) + var(--sat)); overflow-y: auto; -webkit-overflow-scrolling: touch; background: var(--sheet); z-index: var(--z-pane); animation: fadein var(--t-fade) var(--ease) both; user-select: text; -webkit-user-select: text; }
@keyframes fadein { from { opacity: 0; } to { opacity: 1; } }
.inner { max-width: var(--pane-max); margin: 0 auto; padding: var(--pane-pad-y) var(--pane-pad-x) calc(var(--pane-pad-b) + var(--sab)); }
.tabpane h1 { font-family: var(--display-face); font-style: var(--i-off); font-weight: var(--w-normal); letter-spacing: var(--ls-display); font-size: var(--fs-title); margin: 0 0 var(--gap-lg); line-height: var(--lh-head); }
.tabpane h2 { font-family: var(--display-face); font-style: var(--i-off); font-weight: var(--w-normal); font-size: var(--fs-h2); letter-spacing: var(--ls-h2); margin: 24px 0 var(--gap-sm); color: var(--gold); }
.tabpane p { margin: 0 0 var(--gap); font-size: var(--fs-body); line-height: var(--lh-body); color: var(--paper-dim); }
.tabpane p.lede { font-size: var(--fs-lede); font-style: var(--i-label); color: var(--paper); line-height: var(--lh-lede); }
.dim { color: var(--paper-faint); }
.kv { display: flex; justify-content: space-between; gap: var(--gap); padding: var(--kv-pad) 0; border-bottom: var(--bw) solid var(--hairline); font-size: var(--fs-row); }
.kv span { color: var(--paper-faint); letter-spacing: var(--ls-label); font-size: var(--fs-label); }
.kv b { font-weight: var(--w-normal); font-style: var(--i-label); font-variant-numeric: tabular-nums; }
.row { display: flex; align-items: center; gap: 10px var(--gap-lg); flex-wrap: wrap; padding: var(--row-pad) 0; border-bottom: var(--bw) solid var(--hairline); font-size: var(--fs-row); }
.row b { font-weight: var(--w-normal); font-style: var(--i-label); font-variant-numeric: tabular-nums; color: var(--gold); }
.row .dim { font-size: var(--fs-label); }
/* 2026-09-28, the owner's screenshot: the shelf's words pushed the buttons onto a line of their own and every column wandered with the
 * width of the one before it. One grid: name · price · against the base · aboard · the shelf · the buttons, on one line; a phone takes
 * the buttons onto a second line, on purpose, under the same columns */
.row.mk { display: grid; grid-template-columns: minmax(6.5em, 1.3fr) 4.6em 4.8em minmax(5.5em, .8fr) minmax(7.5em, 1.1fr) auto; column-gap: var(--gap-lg); align-items: center; }
.row.mk > * { min-width: 0; white-space: nowrap; }
.row.mk > b { text-align: right; }
.row.mk .mk-have.on { color: var(--paper); }
.row.mk .stock { overflow: hidden; text-overflow: ellipsis; }
.row.mk .acts { display: flex; gap: var(--gap-xs); justify-content: flex-end; }
#tab-market .inner { max-width: max(var(--pane-max), min(940px, 100%)); }
/* 2026-09-28 (docs/perigee/manifests.md step 1): the market's families, one list folded shut; a good's name keeps its marks beside it
 * however narrow the column (the name gives way first, and says itself in full on hover) */
details.mkfam { padding: 0; margin: 0; border: 0; }
details.mkfam > summary { display: flex; align-items: baseline; gap: var(--gap); padding: var(--row-pad) 0; border-bottom: var(--bw) solid var(--hairline); list-style: none; font-size: var(--fs-body); color: var(--paper-dim); }
details.mkfam > summary::-webkit-details-marker { display: none; }
details.mkfam > summary::before { content: '▸'; flex: none; width: 1em; color: var(--paper-faint); }
details.mkfam[open] > summary::before { content: '▾'; }
details.mkfam > summary:hover, details.mkfam[open] > summary { color: var(--paper); }
details.mkfam > summary .mk-have { margin-left: auto; }
details.mkfam > summary .mk-have.on { color: var(--paper); }
details.mkfam > .row.mk { padding-left: 1em; }
.mk-name { display: flex; align-items: center; gap: 5px; }   /* 2026-09-29: also the plain cargo row (js/ui.js renderCargo), so a good's miniature reads the same both places */
.mk-nm { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.mk-icon { flex: none; width: 28px; height: 28px; border-radius: 50%; object-fit: cover; display: block; background: rgb(var(--paper-rgb) / .06); }   /* the goods' painted miniatures (assets/goods/), js/goods/01-minis.js goodIconHtml */
.row.mk .mk-marks { flex: none; display: inline-flex; gap: 3px; }
.lic { font-size: var(--fs-label); color: var(--paper-faint); white-space: nowrap; } .row.mk .lic { flex: none; } .lic.no { color: var(--bad); }   /* P70: the mining licence beside ore (js/ui.js licTag) */
.row.mk .mark { display: block; color: var(--gold); opacity: .85; cursor: help; }
.row.mk .mark svg { width: 15px; height: 15px; display: block; fill: none; stroke: currentColor; stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round; }   /* the market is a table: it gets the room for one line a row */
@media (max-width: 1000px) and (min-width: 761px) {
  .row.mk { grid-template-columns: minmax(6.5em, 1.3fr) 4.6em 4.8em minmax(5.5em, .8fr) minmax(7.5em, 1.1fr); grid-template-areas: "n p c h s" "a a a a a"; row-gap: 6px; }
  .row.mk > :nth-child(1) { grid-area: n; } .row.mk > :nth-child(2) { grid-area: p; } .row.mk > :nth-child(3) { grid-area: c; }
  .row.mk > :nth-child(4) { grid-area: h; } .row.mk > :nth-child(5) { grid-area: s; } .row.mk .acts { grid-area: a; }
  .mk-icon { width: 20px; height: 20px; }   /* the name band is its own grid row here (unlike desktop, where the acts row's own height already covers a 28px icon): 20px keeps the row exactly as tall as before */
}
@media (max-width: 760px) {
  .row.mk { grid-template-columns: minmax(5.5em, 1fr) 4.2em 4.6em; grid-template-areas: "n p c" "h s s" "a a a"; row-gap: 6px; column-gap: var(--gap-md, 10px); }
  .row.mk > :nth-child(1) { grid-area: n; } .row.mk > :nth-child(2) { grid-area: p; } .row.mk > :nth-child(3) { grid-area: c; }
  .row.mk > :nth-child(4) { grid-area: h; } .row.mk > :nth-child(5) { grid-area: s; text-align: right; } .row.mk .acts { grid-area: a; justify-content: stretch; }
  .row.mk .acts button { flex: 1 1 0; }
  .mk-icon { width: 20px; height: 20px; }   /* the name band is its own grid row here too; 20px keeps the row exactly as tall as before (measured, scratchpad/mkshot.js) */
}
.row.mk .acts button, .pill { font-family: inherit; font-style: var(--i-label); font-size: var(--fs-label); letter-spacing: var(--ls-label); color: var(--paper-dim); background: var(--ghost-bg); border: var(--bw) solid var(--line-soft); border-radius: var(--r-pill); padding: var(--pill-pad); cursor: pointer; transition: background var(--t), color var(--t); white-space: nowrap; min-height: var(--tap-sm); }
.row.mk .acts button:hover, .pill:hover, .row.mk .acts button:focus-visible, .pill:focus-visible { background: var(--ghost-bg-hi); color: var(--paper); outline: none; }
.row.mk .acts button:disabled, .pill:disabled { opacity: .35; cursor: default; background: none; }
/* 2026-09-28: a store the governor keeps (js/game/market.js refused): greyed like a disabled button, but it still answers a hover (the
 * tooltip) and a tap (the same words as a toast), which a disabled button would not */
.row.mk .acts button.refused, .row.mk .acts button.refused:hover { opacity: .35; cursor: not-allowed; background: none; color: var(--paper-dim); }
.row.mk .stock.held { text-decoration: underline dotted; text-underline-offset: 3px; }
.pill { color: var(--gold); border-color: var(--gold-line-soft); background: var(--gold-wash); font-size: var(--fs-row); padding: var(--pill-pad-lg); }
.pill:hover, .pill:focus-visible { background: var(--gold-wash-hi); color: var(--gold-lit); }
.pill.ghost { color: var(--paper-dim); border-color: var(--line); background: transparent; }
.pill.small { font-size: var(--fs-label); padding: var(--pill-pad-sm); }
.tag { display: inline-block; font-size: var(--fs-xs); letter-spacing: var(--ls-label); color: var(--paper-dim); border: var(--bw) solid var(--line-faint); border-radius: var(--r-pill); padding: 3px 10px; margin: 0 var(--gap-xs) var(--gap-xs) 0; }
.services { display: flex; gap: var(--gap-sm); flex-wrap: wrap; margin: 10px 0; }
.marketHead { display: flex; justify-content: space-between; align-items: baseline; gap: var(--gap); flex-wrap: wrap; margin-bottom: var(--gap-xs); }
.marketHead .credits { font-style: var(--i-label); color: var(--gold); font-variant-numeric: tabular-nums; }
/* quests */
details.q { padding: 10px 0; }
details.q summary { font-size: var(--fs-md); }
details.q.lingers { padding: 10px 12px; border: var(--bw) solid var(--ring); border-radius: var(--r-card); background: var(--scrim); }
.pill.commit { border-color: rgb(var(--paper-rgb) / .55); }
svg.seal { width: 15px; height: 15px; margin: 0 5px -3px 0; fill: none; stroke: currentColor; stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round; opacity: .9; }
.say { margin: var(--gap-sm) 0 var(--gap-xs); font-size: var(--fs-say); line-height: var(--lh-snug); color: var(--paper-dim); font-style: var(--i-label); white-space: pre-line; }   /* r57: a line break written into a quest is a line break on the glass — three names cut into a stone are three lines */
.say .who { font-style: var(--i-off); color: var(--gold); letter-spacing: var(--ls-tab); }
.say .who::after { content: ' ·'; }
.prog { display: flex; justify-content: space-between; gap: var(--gap); font-size: var(--fs-tab); color: var(--paper-dim); padding: var(--gap-xs) 0; }
.prog b { white-space: nowrap; color: var(--gold); font-weight: var(--w-normal); font-style: var(--i-label); }
.qacts { display: flex; flex-direction: column; align-items: flex-start; gap: var(--gap-xs); margin-top: var(--gap-sm); }
.qacts .pill { text-align: left; white-space: normal; }
.qacts.row { flex-direction: row; flex-wrap: wrap; }
.line { display: flex; gap: var(--gap); align-items: flex-start; }
.face { width: var(--face); height: var(--face); border-radius: var(--r-round); object-fit: cover; vertical-align: middle; margin-right: var(--gap-sm); box-shadow: 0 0 0 var(--bw) var(--ring); }
.face.big { width: var(--face-big); height: var(--face-big); flex: 0 0 var(--face-big); margin: var(--gap-sm) 0 0; }
.seen { margin-top: 22px; font-size: var(--fs-tab); }
#tab-quests .inner { padding-bottom: 70vh; }   /* room to scroll, so the open dialogue can always be kept in place after a click */
.seen i { color: var(--gold); }
details.person summary { font-size: var(--fs-say); }
details.person.away { filter: grayscale(1); opacity: 0.55; }   /* 2026-10-02: away on a trip of their life (js/away.js): greyed, as a shop shut for now */
/* 2026-09-27: the governor's tally board, chalked by the secretary every morning (js/game/governor.js); and the debug card's six dials */
.tally { font-family: var(--mono); font-size: var(--fs-note); line-height: var(--lh-mono); color: var(--paper-dim); border-left: var(--bw) solid var(--line-track); padding: 2px 0 2px var(--gap); margin: var(--gap-sm) 0; }
.dials { font-family: var(--mono); font-size: var(--fs-nano); }
/* telemetry */
#hudDebug { font-family: var(--mono); font-size: var(--fs-nano); line-height: var(--lh-mono); color: var(--paper-faint); white-space: pre; text-shadow: var(--glow-hud); }
.hud-left { display: flex; flex-direction: column; gap: 9px; min-width: 0; }   /* the bars, and under them the telemetry when it is on */
.telewrap { overflow-x: auto; -webkit-overflow-scrolling: touch; border: var(--bw) solid var(--line-track); border-radius: var(--r-box); margin-bottom: var(--gap-lg); }
#telePre { margin: 0; padding: 10px var(--gap); font-family: var(--mono); font-size: var(--fs-xxs); line-height: var(--lh-say); color: var(--paper-dim); }
/* upgrades on the ship tab */
.up { padding: 10px 0; border-bottom: var(--bw) solid var(--hairline); }
.upHead { display: flex; justify-content: space-between; align-items: baseline; gap: var(--gap); font-size: var(--fs-body); }
.upName { font-style: var(--i-label); }
.lvl { color: var(--gold); letter-spacing: var(--ls-lvl); font-size: var(--fs-xs); }
details.up summary { font-size: var(--fs-body); display: flex; align-items: baseline; gap: var(--gap-sm); flex-wrap: wrap; }
details.up summary .lvl { margin-left: 2px; }
/* 10-11, the yard's used hulls as an accordion (the owner: "I want t dropdown accordion for each hull to expand the details/offer"): a ▸ that turns ▾ open */
details.up.used > summary { list-style: none; }
details.up.used > summary::-webkit-details-marker { display: none; }
details.up.used > summary::before { content: '▸'; flex: none; width: 1em; color: var(--paper-faint); }
details.up.used[open] > summary::before { content: '▾'; }
details.up.used { border-bottom: var(--bw) solid var(--hairline); }
/* each figure a bullet: green ▲ better than the ship flown now, red ▼ worse, then the figure now */
ul.trcmp { margin: 6px 0; padding-left: 1.1em; display: grid; grid-template-columns: 1fr 1fr; column-gap: 28px; row-gap: 2px; font-size: var(--fs-note); list-style: disc; }
ul.trcmp li { display: list-item; color: var(--paper-dim); border: 0; padding: 0; margin: 0; min-height: 0; background: none; }
ul.trcmp li b { color: var(--paper); font-weight: normal; }
ul.trcmp .tra { font-style: normal; font-size: 0.85em; }
ul.trcmp li.up .tra { color: #6fcf7a; }
ul.trcmp li.dn .tra { color: #e0564a; }
@media (max-width: 520px) { ul.trcmp { grid-template-columns: 1fr; } }
.tag.bad { color: var(--bad); border-color: var(--bad-line); }
.up.row .upHead { color: var(--paper-dim); }
/* P49: each fitting's condition, a small bar beside its level on the ship tab (never on the flying glass; js/ui.js renderUpgrades) */
.lvlCond { display: inline-flex; align-items: center; gap: 8px; }
.cond { display: inline-block; width: 44px; height: 5px; border: var(--bw) solid var(--hairline); border-radius: 3px; overflow: hidden; vertical-align: middle; align-self: center; }
.cond i { display: block; height: 100%; background: var(--gold); opacity: 0.8; }
.cond.c-worn i { background: var(--gold); opacity: 0.6; }
.cond.c-tired i, .cond.c-failing i { background: var(--bad); opacity: 0.85; }
.sysRow b { display: inline-flex; align-items: center; gap: 8px; }
.sysRow .sysWord { font-size: var(--fs-label); }
/* P53: the grey of a part's age eats the bar in from the right (its condition: the most a yard can mend it to); the part card a tap opens */
.cond { position: relative; }
.cond s { position: absolute; top: 0; right: 0; bottom: 0; background: repeating-linear-gradient(135deg, rgb(var(--paper-rgb) / .34) 0 2px, rgb(var(--paper-rgb) / .2) 2px 4px); text-decoration: none; }
.sysRow.tap { cursor: pointer; }
.sysRow.tap:hover > span:first-child, .sysRow.open > span:first-child { color: var(--gold); }
.partCard { margin: 2px 0 8px 12px; padding: 6px 10px; border-left: var(--bw) solid var(--gold-line); font-size: var(--fs-label); }
.partCard .kv { padding: 2px 0; border: 0; }
.partCard .kv b { font-weight: normal; text-align: right; }
/* P81: the ship's slots and the yard's fitting screen (js/fitpanel.js): groups of slots, each its module (name, maker, grade as dots, its bar)
 * or empty; at the yard an accordion, one slot open: what is fitted, what in the hold fits, what the yard has, each with the dealers' ▲▼ */
.fyNote { margin: 0 0 var(--gap-xs); font-size: var(--fs-label); }
.fyGh { font-size: var(--fs-xs); font-weight: var(--w-normal); letter-spacing: .08em; color: var(--gold); margin: 12px 0 2px; }
.kv .lvl, .fyRow .lvl { color: var(--gold); letter-spacing: var(--ls-lvl); font-size: var(--fs-xs); }
.fyRow .fyName { min-width: 0; }
.fyRow.empty b { font-style: var(--i-label); }
details.up.fy summary .cond { margin-left: 4px; }
.fyPick { margin: 6px 0 4px 2px; padding: 2px 0 6px 10px; border-left: var(--bw) solid var(--gold-line); }
.fyH4 { margin: 10px 0 2px; font-size: var(--fs-label); font-weight: var(--w-normal); letter-spacing: .06em; color: var(--paper-faint); }
.fyOffer { padding: 8px 0; border-top: var(--bw) solid var(--hairline); }
.fyH4 + .fyOffer { border-top: 0; }
.fyTag { display: inline-flex; align-items: center; gap: 6px; font-size: var(--fs-label); white-space: nowrap; }
.fyBtns { display: inline-flex; flex-wrap: wrap; gap: 6px; justify-content: flex-end; }
.fyStory, .fyTrade { font-size: var(--fs-label); }
.fyAboardFit { margin: 4px 0; }
/* P84: what hers is worth against new, in the dealers' red and green; why she is held at the berth; the order of a module for an empty slot */
.fyTrade { color: var(--paper-dim); } .fyTrade .tra { font-style: normal; font-size: 0.85em; } .fyTrade.up .tra { color: #6fcf7a; } .fyTrade.dn .tra { color: #e0564a; }
.fyWarn { font-size: var(--fs-label); }
.fyHeld { margin: 0 0 8px; padding: 4px 0 4px 10px; border-left: var(--bw) solid var(--gold-line); font-size: var(--fs-note); color: var(--paper-dim); } .fyHeld p { margin: 2px 0; }
.fyHeld.held { border-left-color: #e0564a; color: var(--paper); }
.fyOrder { padding: 4px 0; } .fyLien { margin-top: 4px; }
@media (max-width: 520px) { .fyBtns { width: 100%; justify-content: flex-start; } .fyPick { padding-left: 6px; } .fyOffer .upHead { flex-wrap: wrap; } }
/* P53: the coil's odometer — a drum counter as a car's or a camera's shutter counter has: white-on-black drums in a brass bezel behind
 * glass, the last drum caught a little past true, the others with a hair of gear lash; dark at the top and the bottom where the drums
 * turn away (the roundness), a fleck of dust and a glint on the glass. Digits roll on (.roll) when the count has moved */
.odo { --odo-h: 15px; --odo-w: 10px; display: inline-flex; vertical-align: middle; margin-left: 8px; padding: 2px; border-radius: 3px;
  background: linear-gradient(180deg, #b39a62 0%, #6e5a32 45%, #4a3c22 55%, #9c8452 100%); box-shadow: 0 1px 2px rgb(0 0 0 / .6), inset 0 0 0 1px rgb(0 0 0 / .45); }
.odoWin { position: relative; display: inline-flex; gap: 1px; padding: 0 1px; background: #050505; border-radius: 2px; overflow: hidden; box-shadow: inset 0 1px 2px rgb(0 0 0 / .9); }
.odoDrum { position: relative; width: var(--odo-w); height: var(--odo-h); overflow: hidden; background: #141210; }
.odoDrum.last { background: #ece4cc; }
.odoStrip { display: block; transform: translateY(calc((var(--d) + var(--lash, 0)) * var(--odo-h) * -1)); will-change: transform; }
.odoStrip.roll { transition: transform 1.1s cubic-bezier(.45, .05, .3, 1); }
.odoStrip i { display: block; height: var(--odo-h); line-height: var(--odo-h); text-align: center; font: 600 12px/var(--odo-h) var(--mono); font-style: normal; color: #efe8d6; }
.odoDrum.last .odoStrip i { color: #1a1612; }
/* the roundness: each drum dark where it turns away, top and bottom; then the dust and the glint on the glass over all of them */
.odoDrum::after { content: ''; position: absolute; inset: 0; pointer-events: none; background: linear-gradient(180deg, rgb(0 0 0 / .85) 0%, rgb(0 0 0 / .25) 28%, rgb(0 0 0 / 0) 45%, rgb(0 0 0 / 0) 58%, rgb(0 0 0 / .3) 76%, rgb(0 0 0 / .88) 100%); }
.odoWin::after { content: ''; position: absolute; inset: 0; pointer-events: none; opacity: .5; mix-blend-mode: screen;
  background-image: radial-gradient(circle at 18% 30%, rgb(255 250 235 / .5) 0 .6px, transparent 1px), radial-gradient(circle at 63% 72%, rgb(255 250 235 / .4) 0 .5px, transparent 1px), radial-gradient(circle at 84% 18%, rgb(255 250 235 / .35) 0 .7px, transparent 1.2px), radial-gradient(circle at 40% 88%, rgb(255 250 235 / .3) 0 .5px, transparent 1px),
    url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='64' height='16'><filter id='d'><feTurbulence type='fractalNoise' baseFrequency='1.3' numOctaves='2' seed='53'/><feColorMatrix values='0 0 0 0 1  0 0 0 0 .97  0 0 0 0 .9  0 0 0 2.2 -1.45'/></filter><rect width='64' height='16' filter='url(%23d)'/></svg>"),
    linear-gradient(115deg, rgb(255 255 255 / 0) 30%, rgb(255 255 255 / .14) 42%, rgb(255 255 255 / 0) 52%); }
@media (prefers-reduced-motion: reduce) { .odoStrip.roll { transition-duration: .01s; } }
.namer { display: flex; align-items: center; gap: var(--gap-sm); flex-wrap: wrap; margin-top: 10px; }
.namer p { flex: 1 0 100%; margin: 0 0 4px; }
.namer input { font-size: var(--fs-row); padding: var(--pill-pad-sm); min-width: 0; flex: 1 1 160px; }
.upNext { display: flex; justify-content: space-between; align-items: center; gap: var(--gap); flex-wrap: wrap; margin-top: var(--gap-xs); font-size: var(--fs-sm); }
details { border-bottom: var(--bw) solid var(--hairline); padding: var(--row-pad) 0; }
summary { cursor: pointer; font-style: var(--i-label); font-size: var(--fs-body); }
details p { margin-top: var(--gap-sm); }
/* the settings (the owner's screenshot, r64l): their own class, because .chk is the skill-check chip and its pill border was
 * wrapping every row; a short label on the row, the explaining line dim under it, and a box drawn in the game's own ink */
.sets { display: flex; flex-direction: column; gap: 2px; margin-bottom: var(--gap-sm); }
label.set { display: flex; align-items: center; gap: 12px; font-size: var(--fs-row); color: var(--paper-dim); padding: 6px 0; cursor: pointer; width: fit-content; }
label.set:hover { color: var(--paper); }
label.set input { appearance: none; -webkit-appearance: none; flex: 0 0 auto; width: var(--chk); height: var(--chk); margin: 0; border: var(--bw) solid var(--gold-line-soft); border-radius: 5px; background: transparent; cursor: pointer; display: grid; place-items: center; transition: background .15s, border-color .15s; }
label.set input:hover { border-color: var(--gold-line); }
label.set input:checked { background: var(--gold); border-color: var(--gold); }
label.set input:checked::after { content: ''; width: 5px; height: 9px; margin-top: -2px; border: solid rgb(var(--ink-rgb)); border-width: 0 2px 2px 0; transform: rotate(45deg); }
label.set input:focus-visible { outline: 2px solid var(--gold-line); outline-offset: 2px; }
.sets p.setNote { margin: -4px 0 6px calc(var(--chk) + 12px); font-size: var(--fs-sm); color: var(--paper-faint); max-width: 34rem; }
/* 2026-09-28: a choice of three (frame rate, render scale; js/game/pace.js), the label and its pills on one row, the note under it */
.sets .setSeg { display: flex; align-items: center; flex-wrap: wrap; gap: 12px; font-size: var(--fs-row); color: var(--paper-dim); padding: 6px 0; }
.sets .setSeg + p.setNote { margin-left: 0; margin-top: 0; }
.maprow { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-bottom: 10px; }
.maprow .spacer { flex: 1 1 auto; }
.maprow .zoom { min-width: 40px; padding: var(--gap-xs) 10px; font-size: var(--fs-body); font-style: var(--i-off); }
.maprow input { font-size: var(--fs-row); padding: var(--pill-pad-sm); min-width: 0; flex: 0 1 190px; }
.seg { display: flex; border: var(--bw) solid var(--line); border-radius: var(--r-pill); overflow: hidden; }
.seg button { background: none; border: 0; color: var(--paper-dim); font-style: var(--i-label); font-size: var(--fs-label); letter-spacing: var(--ls-tab); padding: var(--pill-pad-sm); min-height: var(--tap-sm); cursor: pointer; }
.seg button.on { background: rgb(var(--gold-rgb) / .14); color: var(--gold); }
.jet { display: inline-flex; align-items: center; gap: var(--gap-xs); margin-left: auto; font-size: var(--fs-label); color: var(--paper-faint); }
.jet input { width: 4.5em; font-size: var(--fs-tab); padding: 5px 10px; text-align: center; }
.sim { width: 100%; margin-top: var(--gap-sm); } .sim .pill { margin-right: 4px; } .sim p { margin: var(--gap-sm) 0 0; font-size: var(--fs-sm); }
.card.hail { text-align: left; width: min(520px, calc(100vw - 32px)); }
.card.hail .who { color: var(--gold); font-size: var(--fs-label); letter-spacing: var(--ls-tab); margin-top: var(--gap-sm); }
.card.hail .say { margin: var(--gap-xs) 0 0; }
.card.hail .hailBody { flex: 1 1 auto; }
.card.hail .qacts { margin-top: var(--gap-lg); }
/* r62 — a scene picture beside the dialogue (the owner: "the picture should not be scrollable and on the side. the response options could
   be under the picture then, while the text can be to the right, scrollable"). The card stops scrolling as a whole; only the text does.
   Without a picture nothing here applies and the card is what it always was. Narrow screens stack it: picture, text, replies. */
.card.hail .hailSide { display: none; }
.card.hail.scene { --scene-h: min(660px, calc(100vh - 40px)); width: min(880px, calc(100vw - 32px)); max-height: var(--scene-h); display: grid; grid-template-columns: minmax(200px, 300px) minmax(0, 1fr); grid-template-rows: auto minmax(0, 1fr); grid-template-areas: "side main" "acts main"; column-gap: var(--gap-xl); overflow: hidden; }
.card.hail.scene .hailSide { display: block; grid-area: side; }
.card.hail.scene .hailMain { grid-area: main; min-height: 0; max-height: calc(var(--scene-h) - 44px); overflow-y: auto; padding-right: var(--gap-xs); }
.card.hail.scene .qacts { grid-area: acts; align-self: start; align-items: stretch; margin-top: var(--gap); }
.card.hail.scene #hailFace { display: none; }
.scenePic { display: block; width: 100%; aspect-ratio: 3 / 4; max-height: 48vh; object-fit: cover; border-radius: var(--r-box); border: var(--bw) solid var(--line-faint); background: #05070a; user-select: none; -webkit-user-drag: none; pointer-events: none; }
.qscene { display: grid; grid-template-columns: minmax(180px, 250px) minmax(0, 1fr); column-gap: var(--gap-xl); align-items: start; margin-top: var(--gap-sm); }
.qscene .qside .qacts { align-items: stretch; }
.qtail { margin-top: var(--gap-sm); } .qscene .qside .qtail { padding: 0 var(--gap-xs); }   /* r66: what is left to do sits under the replies, not in the text */
.qscene .qmain { max-height: 62vh; padding-right: var(--gap-xs); }
.qscene .qmain .line .face { display: none; }
@media (max-width: 700px) {
  .card.hail.scene { display: block; overflow-y: auto; }
  .card.hail.scene .hailMain { max-height: none; overflow: visible; padding-right: 0; }
  .card.hail.scene .scenePic, .qscene .scenePic { aspect-ratio: auto; max-height: 30vh; }
  .qscene { display: flex; flex-direction: column; }
  .qscene .qside { display: contents; }
  .qscene .qside .scenePic { order: 0; }
  .qscene .qmain { order: 1; max-height: none; overflow: visible; }
  .qscene .qside .qacts { order: 2; }
  .qscene .qside .qtail { order: 3; }
}
/* r62 — a skill check on a reply: the ability and the step it asks for, in gold when the pilot has it and in grey (with what they do have)
   when not. A failed check leaves the reply on the board, shut, so the pilot can come back to it. */
.chk { display: inline-block; font-size: var(--fs-xs); font-style: normal; letter-spacing: var(--ls-label); text-transform: lowercase; line-height: 1.5; padding: 0 7px; margin: 0 7px 0 0; border: var(--bw) solid var(--gold-line-soft); border-radius: var(--r-pill); color: var(--gold); vertical-align: 1px; white-space: nowrap; }
.chk.no { color: var(--paper-faint); border-color: var(--line-soft); }
.chk i { font-style: normal; opacity: .72; }
/* 2026-09-28, the owner: "it's Tallow that passes the engineering test, place his avatar to the left of 'engineering 4'" (js/game/crew.js checkView) */
.chk.by { padding-left: 2px; }
.chk .chkface { width: 36px; height: 36px; border-radius: 50%; object-fit: cover; vertical-align: middle; margin: -10px 8px -9px -4px; border: var(--bw) solid var(--gold-line-soft); }
.pill:has(> .chk.by) { display: inline-flex; align-items: center; text-align: left; }   /* 2026-10-13: a reply with a face on its chip keeps its words beside the chip, never wrapped under the face */
.pill:disabled .chk.no { color: var(--paper-dim); }
/* in the narrow column beside a picture a reply may wrap: the check goes on its own line above it, the why on its own line under it,
   and the pill gives up its round ends for a card's */
.card.hail.scene .qacts .pill, .qscene .qacts .pill { border-radius: var(--r-field); }
.card.hail.scene .qacts .pill .chk, .qscene .qacts .pill .chk { display: table; margin: 1px 0 4px; }
.card.hail.scene .qacts .pill .dim, .qscene .qacts .pill .dim { display: block; margin-top: 2px; }
.sel { display: flex; flex-wrap: wrap; align-items: center; gap: var(--gap-sm) var(--gap-lg); padding: 10px 0; font-size: var(--fs-row); border-bottom: var(--bw) solid var(--hairline); }
.sel b { font-weight: var(--w-normal); font-style: var(--i-label); color: var(--gold); font-size: var(--fs-md); }
/* the arrow in the select is a data URI and cannot hold a var(): its stroke is --paper written out by hand */
select { font-family: inherit; font-style: var(--i-label); font-size: var(--fs-tab); color: var(--paper); color-scheme: dark; appearance: none; -webkit-appearance: none; background: var(--field-bg) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1l5 5 5-5' fill='none' stroke='%23f3ecd2' stroke-opacity='.6' stroke-width='1.5'/%3E%3C/svg%3E") no-repeat right var(--gap) center; border: var(--bw) solid var(--line); border-radius: var(--r-pill); padding: var(--gap-xs) 30px var(--gap-xs) var(--gap); outline: none; cursor: pointer; }
select:focus-visible { border-color: var(--gold-line); }
select option, select optgroup { background: var(--option-bg); color: var(--paper); font-style: var(--i-off); }
.mapbox { width: 100%; }
#mapCanvas { display: block; max-width: 100%; border-radius: var(--r-map); margin: 0 auto; touch-action: none; cursor: grab; box-shadow: var(--shadow-map); user-select: none; -webkit-user-select: none; }
.sig { margin-top: 30px; font-style: var(--i-label); font-size: var(--fs-xl); color: var(--paper); }
.sigsub { font-size: var(--fs-cap); color: var(--paper-faint); margin-top: -6px; }
.keys { display: grid; grid-template-columns: auto 1fr; gap: 4px var(--gap-lg); font-size: var(--fs-note); color: var(--paper-dim); margin-bottom: var(--gap); }
.keys span:nth-child(odd) { color: var(--gold); font-style: var(--i-label); text-align: right; }
/* ── the manual (r63): the about tab is a book now. The contents sit beside the chapter and stay put while it scrolls;
 * the world (the lore, the words) is its own group under the manual's. On a narrow screen the contents become rows above. ── */
.inner.manual { max-width: calc(var(--pane-max) + 13rem); display: grid; grid-template-columns: 10.5rem minmax(0, 1fr); gap: 0 2.5rem; align-items: start; }
.mannav { position: sticky; top: 0; padding-top: 8px; }
.mgroup { display: flex; flex-direction: column; align-items: flex-start; margin: 0 0 22px; }
.mhead { font-size: var(--fs-xs); letter-spacing: var(--ls-badge); color: var(--paper-faint); margin: 0 0 6px; }
.mannav button { font-family: inherit; font-style: var(--i-label); font-size: var(--fs-row); color: var(--paper-dim); background: none; border: 0; border-left: var(--bw) solid var(--line-faint); padding: 5px 0 5px 12px; cursor: pointer; text-align: left; transition: color var(--t); }
.mannav button:hover, .mannav button:focus-visible { color: var(--paper); outline: none; }
.mannav button.on { color: var(--gold); border-left-color: var(--gold-edge); }
.manmain { min-width: 0; }
.chap a[data-ch] { color: var(--gold); cursor: pointer; text-decoration: underline dotted rgb(var(--gold-rgb) / .5); text-underline-offset: 3px; }
dl.words { margin: 0 0 var(--gap); }
dl.words dt { color: var(--paper); font-style: var(--i-label); font-size: var(--fs-row); margin: 14px 0 2px; }
dl.words dd { margin: 0; font-size: var(--fs-body); line-height: var(--lh-body); color: var(--paper-dim); }
@media (max-width: 760px) {
  .inner.manual { display: block; }
  .mannav { position: static; padding: 0; margin: 0 0 18px; }
  .mgroup { flex-direction: row; flex-wrap: wrap; align-items: baseline; gap: 0 12px; margin: 0 0 8px; }
  .mhead { width: 100%; margin: 0; }
  .mannav button { border-left: 0; border-bottom: var(--bw) solid transparent; padding: 6px 0; }
  .mannav button.on { border-bottom-color: var(--gold-edge); }
}

/* toast and the first-visit sheet */
#toast { position: fixed; left: 50%; top: calc(var(--tabs-h) + var(--sat) + 14px); transform: translateX(-50%); display: flex; flex-direction: column; align-items: center; gap: var(--gap-xs); max-width: calc(100vw - 32px); z-index: var(--z-toast); pointer-events: none; }
.tcard { font-size: var(--fs-sm); font-style: var(--i-label); color: var(--paper-dim); background: var(--toast-bg); border: var(--bw) solid var(--line-dim); border-radius: var(--r-pill); padding: var(--gap-sm) var(--gap-xl); animation: fadein var(--t-fade) var(--ease) both; text-align: center; }
.askWrap { position: fixed; inset: 0; background: rgb(var(--night-rgb) / .55); z-index: calc(var(--z-card) + 1); }
.card.ask { z-index: calc(var(--z-card) + 2); width: min(400px, calc(100vw - 32px)); }
.card.ask .actions { margin-top: var(--gap-lg); }
#crewTrouble .choices { display: flex; flex-direction: column; gap: var(--gap-sm, 6px); margin-top: var(--gap-lg); }
.choice { display: flex; align-items: center; gap: 8px; text-align: left; justify-content: flex-start; }
.choice .face { width: 28px; height: 28px; border-radius: 50%; }
.choice .chip { display: block; font-style: normal; font-size: .8em; opacity: .7; }
#crewTrouble .trouble { margin-bottom: var(--gap-lg); }
.pill.warn { color: var(--bad); border-color: var(--bad-line); background: rgb(var(--bad-rgb) / .08); }
.pill.warn:hover, .pill.warn:focus-visible { background: rgb(var(--bad-rgb) / .16); color: var(--bad); }
.card { position: fixed; left: 50%; top: 50%; transform: translate(-50%, -50%); width: min(440px, calc(100vw - 32px)); max-height: calc(100vh - 40px); overflow-y: auto; background: var(--card-bg); backdrop-filter: var(--blur-card); -webkit-backdrop-filter: var(--blur-card); border: var(--bw) solid var(--line-faint); border-radius: var(--r-card); padding: var(--card-pad); text-align: center; animation: cardin var(--t-card) var(--ease) both; z-index: var(--z-card); }
@keyframes cardin { from { opacity: 0; transform: translate(-50%, -48%); } to { opacity: 1; transform: translate(-50%, -50%); } }
.card h2 { margin: 0 0 var(--gap-xs); font-family: var(--display-face); font-style: var(--i-off); font-weight: var(--w-normal); letter-spacing: var(--ls-display); font-size: var(--fs-title-card); line-height: var(--lh-head); }
.card p { margin: 10px 0 0; font-size: var(--fs-body); color: var(--paper-dim); line-height: var(--lh-snug); }
.card p em { color: var(--gold); font-style: var(--i-label); }
.card .actions { margin-top: 20px; display: flex; gap: 10px; flex-wrap: wrap; justify-content: center; }
.card .dots { margin-top: var(--gap-lg); }
.dots span { display: inline-block; width: 7px; height: 7px; border-radius: var(--r-round); background: var(--ring); margin: 0 3px; }
.dots span.on { background: var(--gold); }
@media (prefers-reduced-motion: reduce) { .card, .tabpane, #toast, .tcard, #hudLow { animation: none; } }

/* the pilot's own words in a talk: 16 px so a phone does not zoom into the field */
.sayit { display: flex; gap: var(--gap-sm); margin-top: var(--gap-sm); align-items: center; }
.sayit input { font-size: var(--fs-body); padding: var(--gap-sm) var(--gap-lg); min-width: 0; flex: 1 1 140px; }

/* the captain's face and name */
.pilot { display: flex; gap: var(--gap-lg); align-items: center; margin: var(--gap-xs) 0 10px; }
.pilotF { display: grid; grid-template-columns: auto 1fr; gap: var(--gap-xs) 10px; align-items: center; flex: 1 1 auto; min-width: 0; }
.pilotF input { font-size: var(--fs-body); padding: var(--pill-pad-sm); min-width: 0; width: 100%; box-sizing: border-box; }
.pics { display: flex; flex-wrap: wrap; gap: var(--gap-sm); margin: var(--gap-xs) 0 var(--gap-sm); }
.pics .pic { padding: 0; border: var(--bw-thick) solid transparent; border-radius: var(--r-round); background: none; width: 52px; height: 52px; overflow: hidden; cursor: pointer; opacity: .55; }
.pics .pic img { width: 100%; height: 100%; object-fit: cover; display: block; }
.pics .pic.on { border-color: var(--gold); opacity: 1; }
.capLocked { opacity: .32; filter: grayscale(1); pointer-events: none; user-select: none; transition: opacity var(--t-slow), filter var(--t-slow); }   /* 2026-10-14: a creation step not yet reached by its continue (js/capsteps.js gate) */
.pics.rows { display: grid; grid-template-columns: repeat(10, 52px); justify-content: start; }   /* 10-14, the owner: twenty faces in two rows of ten, men above, women below (js/game/pilot.js PILOT_ORDER) */
@media (max-width: 700px) { .pics.rows { grid-template-columns: repeat(5, 52px); } }

.near { margin: var(--gap-sm) 0 2px; display: flex; flex-wrap: wrap; gap: var(--gap-xs); align-items: center; }
.placelist { margin: var(--gap-sm) 0 2px; font-size: var(--fs-row); }   /* 2026-10-02: the places known at a body (js/places.js chart) */
.placelist ul { list-style: none; margin: 2px 0 0; padding: 0; }
.placelist li { padding: 1px 0; overflow-wrap: anywhere; }
.placelist li.away { filter: grayscale(1); opacity: .6; }

/* the pilot's papers */
.sheet { display: grid; gap: var(--gap-xs); margin: var(--gap-sm) 0; }
.sheet .ab { display: grid; grid-template-columns: 92px auto auto auto 1fr; gap: 4px var(--gap-sm); align-items: center; justify-content: start; }
.sheet .ab .abd { letter-spacing: var(--ls-abd); color: var(--gold); font-weight: var(--w-normal); }
.sheet .ab .abw { grid-column: 1 / -1; font-size: var(--fs-cap); margin-top: -2px; contain: inline-size; }   /* P60: the line under a row no longer widens its own buttons (each row is a grid of its own, and a long line stretched its auto columns) */
.sheet .ab button { min-width: 34px; padding: 2px var(--gap-sm); }
.perk { margin: 4px 0; }
.perk.unearned > b { opacity: 0.55; font-weight: normal; } .perk .perklv { font-size: 0.85em; letter-spacing: 0.04em; opacity: 0.85; } .perk .perkh { font-style: italic; }   /* 2026-10-04: perks earned by practice */
#sheetBg { margin: 4px 0; }

/* the sensor ping: a small round button above the thrust on a phone, a line under the drive's timer everywhere */
#touchui #btnPing { right: calc(33px + var(--sar)); bottom: calc(128px + var(--sab)); width: var(--btn-touch-sm); height: var(--btn-touch-sm); font-size: var(--fs-xs); color: var(--teal); border-color: var(--teal-line); }
#touchui #btnPing.wait { color: var(--paper-faint); border-color: var(--line-soft); font-style: var(--i-off); font-size: var(--fs-xxs); }
body:not(.touch) #btnPing { display: none; }
#hudPing { color: var(--paper-faint); letter-spacing: var(--ls-label); }
#hudPing.ready { color: var(--teal); }
#hudPing, #hudFtl { font-size: var(--fs-nano); }

/* a dialogue reads like a book: oldest first, the pilot's own lines in verdigris with a dash, older exchanges paler in three steps (all still readable) */
.book { flex: 1 1 auto; min-width: 0; }
.book .say { margin: var(--gap-xs) 0; }
.say.you { color: var(--you); font-style: var(--i-off); }
.say.f1 { opacity: .5; } .say.f2 { opacity: .34; } .say.f3 { opacity: .24; }   /* r66, the owner: "dim previous messages more" (was .78 / .62 / .5) */
/* P92: the die under the pilot's words (js/dicepanel.js): a d20, flat and brass, no glow; it tumbles for under a second and lands, and
 * holds still under reduced motion. The one not kept (advantage) is paler. A critical is said in the words of the line, not by colour */
.dieline { display: flex; align-items: center; gap: var(--gap-sm); margin: var(--gap-xs) 0; font-size: var(--fs-xs); font-style: var(--i-label); color: var(--gold); }
.dieline.f1 { opacity: .5; } .dieline.f2 { opacity: .34; } .dieline.f3 { opacity: .24; }
.dieline .dice { display: inline-flex; gap: 4px; flex: none; }
.dieline .die { width: 34px; height: 34px; overflow: visible; }
.dieline .die .d-out { fill: rgb(var(--gold-rgb) / .12); stroke: var(--gold); stroke-width: 1.4; stroke-linejoin: round; }
.dieline .die .d-in { fill: rgb(var(--gold-rgb) / .2); stroke: var(--gold); stroke-width: 1; stroke-linejoin: round; }
.dieline .die .d-edge { fill: none; stroke: var(--gold); stroke-width: .8; opacity: .7; }
.dieline .die text { fill: var(--gold); font-family: var(--serif); font-size: 11px; font-style: normal; text-anchor: middle; }
.dieline .die.dropped { opacity: .42; }
.dieline.miss .dietext { color: var(--paper-faint); }
.dieline.tumble .die { animation: dietumble .7s cubic-bezier(.2, .7, .3, 1) var(--dd, 0ms) 1 both; transform-origin: 50% 50%; }
.dieline.tumble .die text, .dieline.tumble .dietext { animation: dieland .7s steps(1, end) var(--dd, 0ms) 1 both; }
@keyframes dietumble { 0% { transform: translateY(-14px) rotate(-420deg) scale(.7); } 70% { transform: translateY(2px) rotate(-20deg) scale(1.04); } 100% { transform: none; } }
@keyframes dieland { 0%, 80% { opacity: 0; } 100% { opacity: 1; } }
@media (prefers-reduced-motion: reduce) { .dieline.tumble .die, .dieline.tumble .die text, .dieline.tumble .dietext { animation: none; } }
.chk.roll { border-style: dashed; }
.card.hail .book .say { margin: 5px 0 0; }
.para { display: block; height: .55em; }   /* r66: a new speaker, a new paragraph (js/paras.js): a half line between, as in a book */

/* the three gauges under hull, shields and fuel */
.bar em { font-style: var(--i-off); font-size: var(--fs-nano); letter-spacing: var(--ls-tab); color: var(--paper-faint); text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
.bar em.ready { color: var(--gold); } .bar em.hot { color: var(--heat); }
#barFtl { background: var(--bar-drive); } #barFtl.ready { background: var(--gold); }
#barPing { background: var(--bar-ping); } #barPing.ready { background: var(--bar-ping-ready); }
/* P85: a small bar for each fitted weapon, side by side where the laser's bar was (js/gunbars.js): the beam's and the pulse's, each filling and locking on its own */
#barLaser.guns { display: flex; gap: 3px; background: none; overflow: visible; } #barLaser .gun { flex: 1 1 0; min-width: 0; height: 100%; border-radius: var(--r-bar); background: var(--line-track); overflow: hidden; }
#barLaser .gun b { background: var(--bar-laser); transition: width var(--t-fast); } #barLaser .gun.beam b { background: #ffd9b0; } #barLaser .gun.hot b { background: var(--bar-laser-hot); animation: hotpulse var(--t-hot) var(--ease-io) infinite alternate; }
@keyframes hotpulse { from { opacity: 1; } to { opacity: .45; } }

/* ── the sandbox (sim tab): rows of choices, and the sensor readout ── */
.simrow { display: flex; flex-wrap: wrap; gap: var(--gap-xs); align-items: center; margin: var(--gap-sm) 0; }
.simrow .dim { font-size: var(--fs-cap); margin-right: 2px; }
.pill.on { color: var(--gold); border-color: var(--gold-edge-lit); background: var(--gold-wash-on); }
.ups { display: flex; flex-direction: column; gap: var(--bar-gap); margin: 10px 0; }
.uprow { display: grid; grid-template-columns: 1fr auto; align-items: center; gap: var(--gap-sm); }
.uprow .lvls { display: flex; gap: 4px; }
.uprow .lvls .pill { padding: 5px 0; min-width: 36px; text-align: center; }
.echo { display: grid; grid-template-columns: 12px 1fr auto; gap: 1px var(--gap-sm); align-items: baseline; font-size: var(--fs-sm); padding: var(--gap-xs) 0; border-bottom: var(--bw) solid rgb(var(--paper-rgb) / .06); }
.echo .swatch { width: 10px; height: 10px; border-radius: var(--r-round); background: var(--line-track); box-shadow: 0 0 7px rgb(var(--teal-rgb) / .2); }
.echo .eName { color: var(--paper-dim); }
.echo .eD { color: var(--paper); font-variant-numeric: tabular-nums; font-style: var(--i-label); }
.echo .eMore { grid-column: 2 / 4; font-size: var(--fs-xs); }
.echo.mute { opacity: .55; }
#tab-sim h3 { margin: var(--gap-lg) 0 4px; font-family: var(--display-face); font-style: var(--i-off); font-weight: var(--w-normal); }
.person.row img.face { width: 32px; height: 32px; }
.capName { font-style: var(--i-label); font-size: var(--fs-lg); color: var(--paper); }
.pilotF .capName { grid-column: 1 / 3; }

/* ── the crew (r36): a portrait to the left of the whisper, and the people on the crew tab ── */
#whisperFace { width: var(--face-whisper); height: var(--face-whisper); border-radius: var(--r-round); object-fit: cover; float: left; margin: 0 10px 2px 0; box-shadow: 0 0 0 var(--bw) var(--ring-soft), 0 2px 12px rgb(var(--night-rgb) / .8); }
.crewCard { display: grid; grid-template-columns: var(--face-crew) 1fr; gap: 4px var(--gap); align-items: start; padding: 10px 0; border-bottom: var(--bw) solid var(--hairline); }
.crewCard img.face { width: var(--face-crew); height: var(--face-crew); grid-row: span 3; margin: 0; }
/* 10-11, the owner: "the section Nobody Yet is problematic and misaligned": a card with no portrait (the empty seat) keeps the same circle and the same columns, its words beside it, never under it */
.crewCard > i.face { width: var(--face-crew); height: var(--face-crew); grid-row: span 3; margin: 0; }
.crewCard > .who, .crewCard > .who + div { grid-column: 2; }
.crewCard .who { font-style: var(--i-label); font-size: var(--fs-md); color: var(--paper); }
.crewCard .who .dim { font-style: var(--i-off); font-size: var(--fs-label); }
.crewCard .story { font-size: var(--fs-sm); color: var(--paper-dim); margin: 2px 0 0; }
.crewCard .abs { display: flex; flex-wrap: wrap; gap: 2px 10px; font-size: var(--fs-xs); color: var(--paper-faint); margin-top: 3px; }
.crewCard .abs b { font-weight: var(--w-normal); color: var(--gold); letter-spacing: var(--ls-btn); }
.crewCard .acts { grid-column: 2; margin-top: var(--gap-xs); }
.crewCard.on { background: rgb(var(--gold-rgb) / .05); }
/* 2026-09-28: a crewmate's department, this week against last (js/game/fights.js kpiView). A label that wraps, two narrow numbers: fits 320 px */
.kpi { margin-top: 6px; font-size: var(--fs-xs); color: var(--paper-dim); max-width: 26rem; }
.kpi .kh, .kpi .kr, .kpi .kf { display: grid; grid-template-columns: minmax(0, 1fr) 4.6em 4.6em; gap: 0 8px; align-items: baseline; padding: 1px 0; }
.kpi .kh { color: var(--paper-faint); border-bottom: var(--bw) solid var(--hairline); padding-bottom: 2px; margin-bottom: 2px; }
.kpi .kh b { font-weight: var(--w-normal); color: var(--paper); overflow-wrap: anywhere; }
.kpi .kh span, .kpi .kr b, .kpi .kr i { text-align: right; white-space: nowrap; }
.kpi .kr span, .kpi .kf span { overflow-wrap: anywhere; }
.kpi .kr b { font-weight: var(--w-normal); color: var(--gold); letter-spacing: var(--ls-btn); }
.kpi .kr i { font-style: normal; color: var(--paper-faint); }
.kpi .kf { grid-template-columns: minmax(0, 1fr) auto; border-top: var(--bw) solid var(--hairline); margin-top: 2px; padding-top: 2px; }
.kpi .kf b { font-weight: var(--w-normal); color: var(--gold); text-align: right; }

/* ── the papers (r37): a front page on grey newsprint, over the night. The card is only the frame; the sheet is the paper ── */
.card.news { width: min(720px, calc(100vw - 20px)); max-height: calc(100vh - 24px); padding: 0; background: none; border: 0; border-radius: 0; text-align: left; backdrop-filter: none; -webkit-backdrop-filter: none; }
/* a new issue spins in from the centre like the old pictures' newspaper: 8 turns (4 a second) over 2 s while it grows from a speck, slowing to rest upright
 * at full size. Transform only (the Pi paints slowly); 8 x 360 deg is the same pose as none, so the card ends on its resting transform */
.card.news.spin { animation: paperspin 2s cubic-bezier(.12,.5,.22,1) 1 both; will-change: transform; }
@keyframes paperspin { from { transform: translate(-50%, -50%) rotate(-2880deg) scale(.05); } to { transform: translate(-50%, -50%) rotate(0deg) scale(1); } }
@keyframes paperfade { from { opacity: 0; } to { opacity: 1; } }
@media (prefers-reduced-motion: reduce) { .card.news.spin { animation: paperfade .25s ease-out 1 both; will-change: auto; } }
.nsheet { color: var(--ink); background-color: var(--news-ground);
  background-image: repeating-linear-gradient(0deg, rgb(var(--ink-rgb) / .045) 0 1px, rgb(var(--news-fibre-rgb) / 0) 1px 3px), repeating-linear-gradient(90deg, rgb(var(--news-fibre-rgb) / .035) 0 1px, rgb(var(--news-fibre-rgb) / 0) 1px 4px), radial-gradient(120% 80% at 28% 0%, rgb(var(--news-light-rgb) / .22), rgb(var(--news-light-rgb) / 0) 58%), radial-gradient(90% 70% at 100% 100%, rgb(var(--news-shade-rgb) / .2), rgb(var(--news-shade-rgb) / 0) 72%);
  padding: var(--news-pad); box-shadow: var(--shadow-news); }
.nsheet p { color: var(--ink-dim); }
/* ── the papers on the log tab (r63): three stacks by title, the newest on top, the older ones fanned under it ── */
#logShelf { margin: 0 0 var(--gap-lg); }
.shelf { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 22px 16px; align-items: start; }   /* three titles, three columns: opening one stack lengthens its own column and moves nothing else */
@media (max-width: 560px) { .shelf { grid-template-columns: 1fr; } }
.stack { position: relative; }
.stack .pile { position: relative; padding: 0 12px 11px 0; }   /* the sheets under the top one belong to the pile, not to the list that opens below it */
.stack .under { position: absolute; inset: 0 12px 11px 0; background: var(--news-ground); border-radius: 2px; box-shadow: 0 2px 8px rgb(0 0 0 / .55), inset 0 0 0 1px rgb(var(--ink-rgb) / .12); }
.stack .under.u1 { transform: translate(6px, 5px) rotate(1.8deg); filter: brightness(.9); }
.stack .under.u2 { transform: translate(11px, 10px) rotate(-1.6deg); filter: brightness(.8); }
.stack .sheet { position: relative; display: flex; flex-direction: column; gap: 5px; width: 100%; min-height: 8.5rem; text-align: left; cursor: pointer; color: var(--ink); background: var(--news-ground); border: 0; border-radius: 2px; padding: 12px 14px 14px; font: inherit; box-shadow: 0 3px 14px rgb(0 0 0 / .55); transition: transform var(--t); }
.stack .sheet:hover, .stack .sheet:focus-visible { transform: translateY(-2px); outline: none; box-shadow: 0 6px 18px rgb(0 0 0 / .6), 0 0 0 var(--bw) var(--gold-edge); }
.stack .mast { font-family: var(--display-face); font-weight: var(--w-normal); font-size: 1.15rem; line-height: 1.05; text-transform: uppercase; letter-spacing: var(--ls-masthead); border-bottom: var(--bw-rule) double var(--ink-rule); padding-bottom: 6px; }
.stack.face-press .mast { font-family: var(--masthead-press); letter-spacing: var(--ls-tight); }
.stack.face-wild .mast { font-family: var(--masthead-wild); }
.stack .nno { font-size: var(--fs-xs); letter-spacing: var(--ls-rule); text-transform: uppercase; color: var(--ink-dim); }
.stack .nno b { font-weight: var(--w-normal); color: var(--ink); }
.stack .nhl { font-size: var(--fs-note); line-height: 1.3; color: var(--ink); font-style: var(--i-label); }
.stack .sheet.read .nhl { color: var(--ink-dim); }
.stack .more { margin-top: 10px; color: var(--paper-dim); }
.stack .past { margin-top: 6px; display: grid; gap: 0; background: var(--sheet); border-top: var(--bw) solid var(--line); }
.stack .past .row { width: 100%; text-align: left; background: none; border: 0; border-bottom: var(--bw) solid var(--line-faint); padding: 8px 2px; font: inherit; font-size: var(--fs-note); cursor: pointer; color: var(--paper); display: grid; gap: 2px; }
.stack .past .row .dim { color: var(--paper-dim); font-style: var(--i-label); }
.stack .past .row:hover, .stack .past .row:focus-visible { color: var(--gold); outline: none; }
.card.news .actions { position: sticky; bottom: 0; margin: 0; padding: var(--gap) 0 10px; background: linear-gradient(to top, rgb(var(--night-rgb) / .94) 55%, rgb(var(--night-rgb) / 0)); }
/* the masthead */
.nhead { text-align: center; border-bottom: var(--bw-rule) double var(--ink-rule); padding-bottom: 9px; margin-bottom: var(--gap-lg); }
.card.news .nhead h2 { margin: 0; font-family: var(--display-face); font-style: var(--i-off); font-weight: var(--w-normal); font-size: var(--fs-n-masthead); line-height: var(--lh-1); letter-spacing: var(--ls-masthead); text-transform: uppercase; color: var(--ink); }
/* a paper sets its own masthead: face: 'press' | 'wild' in NEWS_PAPERS, nothing for the house face */
.card.news .nhead.face-press h2 { font-family: var(--masthead-press); font-weight: var(--w-normal); letter-spacing: var(--ls-tight); }
.card.news .nhead.face-wild h2 { font-family: var(--masthead-wild); font-weight: var(--w-normal); letter-spacing: var(--ls-masthead); font-size: var(--fs-n-masthead-wild); }
.nsheet .nmotto { margin: 5px 0 0; font-style: var(--i-label); font-size: var(--fs-xs); letter-spacing: var(--ls-hud); color: var(--ink-faint); }
.nsheet .nmeta { display: flex; justify-content: space-between; gap: 10px; margin: var(--gap-sm) 0 0; padding-top: var(--gap-xs); border-top: var(--bw) solid rgb(var(--ink-rgb) / .3); font-size: var(--fs-n-rule); letter-spacing: var(--ls-rule); text-transform: uppercase; color: var(--ink-dim); }
/* a story: the first one is the page's lead, the rest follow under rules */
.nstory { border-top: var(--bw) solid rgb(var(--ink-rgb) / .28); margin-top: 13px; padding-top: var(--gap); }
.nstory.first { border-top: 0; margin-top: 0; padding-top: 0; }
.nstory h3 { margin: 0 0 5px; font-weight: var(--w-bold); font-size: var(--fs-n-head); line-height: var(--lh-n-head); letter-spacing: var(--ls-tight); color: var(--ink); }
.nstory.first h3 { font-size: var(--fs-n-lead); text-align: center; }
.nsheet .nby { margin: 0 0 var(--kv-pad); font-size: var(--fs-n-small); font-style: var(--i-label); color: var(--ink-faint); }
.nstory.first .nby { text-align: center; }
.nsheet .nlede { margin: 0 0 9px; font-size: var(--fs-n-lede); font-style: var(--i-label); line-height: var(--lh-say); color: var(--ink); }
.nbody { columns: 2; column-gap: 20px; column-rule: var(--bw) solid rgb(var(--ink-rgb) / .16); }
.nsheet .nbody p { margin: 0 0 9px; font-size: var(--fs-n-body); line-height: var(--lh-n-body); text-align: justify; hyphens: auto; -webkit-hyphens: auto; }
.nstory.first .nbody > p:first-of-type:not(:has(.nplace))::first-letter { float: left; margin: 3px var(--gap-xs) 0 0; font-size: var(--fs-n-drop); line-height: var(--lh-drop); font-weight: var(--w-bold); color: var(--ink); }   /* a story that opens on a dateline sets that in small caps instead: two openings at once read as a mistake */
.nplace { font-weight: var(--w-semi); font-size: var(--fs-n-small); letter-spacing: var(--ls-place); text-transform: uppercase; color: var(--ink); }
/* the plate: the owner's picture goes at its src, and until the file is there the shape is drawn and marked */
.npic { margin: 0 0 10px; break-inside: avoid; }
.npic.wide { margin: 2px 0 var(--gap); }
.npic.wide img { max-height: 300px; object-fit: cover; }
.npic img { display: block; width: 100%; height: auto; border: var(--bw) solid var(--ink-line); filter: grayscale(1) contrast(1.05) brightness(.99); }
.npic.noimg img { display: none; }
.npic .nplate { display: none; }
.npic.noimg .nplate { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 3px; aspect-ratio: 3 / 2; border: var(--bw) dashed var(--ink-line); background-image: repeating-linear-gradient(45deg, rgb(var(--ink-rgb) / .055) 0 6px, rgb(var(--ink-rgb) / 0) 6px 12px); font-size: var(--fs-n-rule); letter-spacing: var(--ls-wide); text-transform: uppercase; color: var(--ink-faint); text-align: center; padding: var(--gap-xs); box-sizing: border-box; }
.npic.wide.noimg .nplate { aspect-ratio: 16 / 6; }   /* a plate across the page is a band, not a hole: it comes after the plain one so it wins */
.npic .nplate i { font-style: var(--i-label); text-transform: none; letter-spacing: var(--ls-none); font-size: var(--fs-n-plate); }
.npic figcaption { margin-top: 4px; font-size: var(--fs-n-cap); font-style: var(--i-label); line-height: var(--lh-cap); color: var(--ink-faint); }
/* the strip at the foot of the page */
.nclass { columns: 3; column-gap: var(--gap-xl); border-top: var(--bw-rule) double var(--ink-line); margin-top: var(--gap-lg); padding-top: var(--gap-sm); }
.nclass h4 { column-span: all; margin: 0 0 var(--gap-xs); font-weight: var(--w-normal); font-size: var(--fs-n-rule); letter-spacing: var(--ls-lvl); text-transform: uppercase; text-align: center; color: var(--ink-dim); }
.nsheet .nclass p { margin: 0 0 var(--gap-xs); font-size: var(--fs-n-small); line-height: var(--lh-n-class); break-inside: avoid; }
@media (max-width: 560px) { .nbody, .nclass { columns: 1; } .nsheet { padding: var(--news-pad-sm); } .nstory.first h3 { text-align: left; } .nstory.first .nby { text-align: left; } }
/* the log's row that is a paper, and the sim tab's rack */
/* the rack's issue rows were laid out as the market's (.row.mk, six fixed columns) and the read-it button sat on the ids; its own grid: name, what it is (wraps), the button */
.row.nrk { display: grid; grid-template-columns: minmax(11em, auto) minmax(0, 1fr) auto; column-gap: var(--gap-lg); align-items: center; }
.row.nrk > .dim { min-width: 0; overflow-wrap: anywhere; }
.row.nrk .acts { display: flex; justify-content: flex-end; }
@media (max-width: 560px) { .row.nrk { grid-template-columns: minmax(0, 1fr) auto; grid-template-areas: "n a" "d d"; row-gap: 4px; } .row.nrk > :nth-child(1) { grid-area: n; } .row.nrk > .dim { grid-area: d; } .row.nrk .acts { grid-area: a; } }
.row.paperrow { cursor: pointer; }
.row.paperrow:hover, .row.paperrow:focus-visible { color: var(--gold); outline: none; }
.pmark { display: inline-block; width: 9px; height: 11px; margin-right: var(--kv-pad); vertical-align: -1px; background: var(--paper-dim); box-shadow: inset 0 0 0 var(--bw) rgb(var(--night-rgb) / .6); }
.row.paperrow.read .pmark { background: rgb(var(--paper-rgb) / .26); }
/* 2026-10-03: one of Wren's drawings in the papers' card (js/ui.js drawingCard) */
.nsheet.wdraw { text-align: center; }
.wdraw .wpic { margin: 0 0 var(--kv-pad); }
.wdraw .wpic img { display: block; width: 100%; height: auto; max-height: 70vh; object-fit: contain; }
.wdraw .wmiss { display: block; padding: 48px 12px; font-style: var(--i-label); color: var(--ink-faint); }
.wdraw .wline { margin: 0 0 var(--kv-pad); font-style: italic; text-align: left; }
.wdraw .nby { text-align: right; }
.nprob { margin: 4px 0 0; padding-left: 18px; font-size: var(--fs-cap); color: var(--paper-faint); }
.nprob li { margin: 2px 0; }

/* ── the loop (r39): the listen button lives above the ping, and the chart's bearing panel reads like a navigator's slate ── */
#touchui #btnListen { right: calc(33px + var(--sar)); bottom: calc(196px + var(--sab)); width: var(--btn-touch-sm); height: var(--btn-touch-sm); font-size: var(--fs-xs); color: var(--blue); border-color: var(--blue-line); }
#touchui #btnListen.wait { color: var(--paper-faint); border-color: var(--line-soft); font-style: var(--i-off); font-size: var(--fs-xxs); }
#touchui #btnListen.dim { opacity: .35; }
body:not(.touch) #btnListen { display: none; }
#dfBox { margin-top: var(--gap-xs); }
#dfBox h2 { margin: var(--gap) 0 4px; font-family: var(--display-face); font-style: var(--i-off); font-weight: var(--w-normal); }
#dfBox h3 { margin: var(--gap) 0 4px; font-family: var(--display-face); font-style: var(--i-off); font-weight: var(--w-normal); }
#dfBox p { margin: 4px 0 0; font-size: var(--fs-note); }
.swatch.navy { background: var(--navy); }
.tag.hot { color: var(--hot); border-color: var(--hot-line); }

/* the log (r40): what was said is written down beside what happened, in the voice that said it */
.row.said span:last-child { font-style: var(--i-label); color: var(--paper-dim); }
.row.said .who { font-style: var(--i-off); color: var(--gold); font-size: var(--fs-label); letter-spacing: var(--ls-tab); margin-right: 4px; }
.row.said .who.you { color: var(--you-log); }
#logFilter { margin-bottom: 4px; }

/* the sensor dial (r41): a rotary switch beside the sensor bar — click to step up, shift-click or right-click to step down,
   the wheel to spin it. The array is a capacitor: less reach asked for is less charge to wait for. */
.knob { pointer-events: auto; font-family: inherit; font-style: var(--i-label); font-size: var(--fs-xxs); letter-spacing: var(--ls-label); color: var(--teal); background: var(--scrim-soft); border: var(--bw) solid rgb(var(--teal-rgb) / .35); border-radius: var(--r-pill); padding: 1px var(--kv-pad); cursor: pointer; min-width: 34px; text-align: center; font-variant-numeric: tabular-nums; }
.knob:hover, .knob:focus-visible { background: rgb(var(--teal-rgb) / .14); color: var(--paper); outline: none; }
.knob.one { opacity: .45; cursor: default; }
/* ── a pane that scrolls without a bar in the way (r59, the owner: "modal needs to be scrollable inside (click and drag),
 * scrollbar invisible unless being scrolled or mouseover. should be universal class for everything"). The gutter is always
 * reserved and only the thumb comes and goes, so nothing moves when the pointer arrives. Put `scrolly` on anything new;
 * the panes, cards and tables that already scroll are named here so they behave the same without touching their markup. ── */
.scrolly, .card, .tabpane, .telewrap, #mapSel { scrollbar-width: thin; scrollbar-color: transparent transparent; transition: scrollbar-color var(--t-fade) linear; }
.scrolly:hover, .card:hover, .tabpane:hover, .telewrap:hover, #mapSel:hover, .scrolly.scrolling, .card.scrolling, .tabpane.scrolling, .telewrap.scrolling, #mapSel.scrolling { scrollbar-color: rgb(var(--teal-rgb) / .38) transparent; }
.scrolly { overflow-y: auto; overscroll-behavior: contain; -webkit-overflow-scrolling: touch; }
.grabbing { cursor: grabbing; user-select: none; -webkit-user-select: none; }
#burnMode { min-width: var(--bar-knob-w); padding: 1px 2px; letter-spacing: var(--ls-none); }
#burnMode.sport { color: var(--heat); border-color: rgb(255 138 106 / .45); }
#burnMode.eco { color: var(--bar-fuel); border-color: rgb(var(--teal-rgb) / .28); }
/* the shields' switch (2026-09-28, js/game/shields.js): on, the knob is the teal of every dial; off, it goes faint and the bar keeps what they hold at a third */
#shieldSw { min-width: var(--bar-knob-w); padding: 1px 2px; letter-spacing: var(--ls-none); }
#shieldSw.off { color: var(--paper-faint); border-color: var(--line-soft); }
/* 2026-09-29: the battery's charging switch (js/game/battery.js), the same knob */
#battSw { min-width: var(--bar-knob-w); padding: 1px 2px; letter-spacing: var(--ls-none); } #battSw.off { color: var(--paper-faint); border-color: var(--line-soft); }
#barShields.off { opacity: .32; }
/* the tractor's switch (2026-09-29, js/game/tractor.js; the owner: "press X key to switch off the active tractor beams to prevent
 * stealing someone else's loot"): the same idiom as the shields — full and lit when on, faint when off, so it reads at a glance */
#tracSw { min-width: var(--bar-knob-w); padding: 1px 2px; letter-spacing: var(--ls-none); }
#tracSw.off { color: var(--paper-faint); border-color: var(--line-soft); }
#barTractor.off { opacity: .32; }
#barLant { background: #9a6cf0; } #barLant.off { opacity: .32; } #lantSw { min-width: var(--bar-knob-w); padding: 1px 2px; letter-spacing: var(--ls-none); } #lantSw.off { color: var(--paper-faint); border-color: var(--line-soft); }   /* 2026-10-06: the astral lantern's gauge */
/* 2026-09-28, todo item 2: the ship's heat (js/game/heat.js): a thin bar under the laser's, cold steel, warm amber, hot red */
.bar.heat i { height: max(2px, calc(var(--bar-h) * 0.6)); }
#barHeat { background: rgba(140, 170, 205, 0.55); transition: width var(--t-fast), background var(--t-fast); } #barHeat.warm { background: var(--bar-laser); } #barHeat.hot { background: var(--bar-laser-hot); }
.bar em.cold { color: rgba(160, 190, 225, 0.85); } .bar em.warm { color: var(--bar-laser); }

/* somebody is composing a reply (r42): three dots that move, rather than three that sit there */
.typing { display: inline-flex; gap: 5px; align-items: center; height: 1em; vertical-align: -1px; }
.typing i { width: 5px; height: 5px; border-radius: var(--r-round); background: var(--paper-dim); animation: typing var(--t-typing) infinite var(--ease-io) both; }
.typing i:nth-child(2) { animation-delay: .16s; } .typing i:nth-child(3) { animation-delay: .32s; }
@keyframes typing { 0%, 70%, 100% { transform: translateY(0); opacity: .35; } 35% { transform: translateY(-4px); opacity: 1; } }
@media (prefers-reduced-motion: reduce) { .typing i { animation: none; opacity: .6; } }

/* ── the tap menu (UI.popup): a ring of round icon buttons at the point touched. One control for the crown, the chart, the marks and whatever wants it next ── */
.popup { position: fixed; inset: 0; z-index: var(--z-card); pointer-events: none; }
.popup .pop { position: absolute; width: var(--tap); height: var(--tap); margin: calc(var(--tap) / -2) 0 0 calc(var(--tap) / -2); padding: 0; display: grid; place-items: center; border-radius: var(--r-round); border: var(--bw) solid var(--gold-line-soft); background: var(--card-bg); color: var(--gold); -webkit-backdrop-filter: var(--blur-btn); backdrop-filter: var(--blur-btn); pointer-events: auto; cursor: pointer; animation: popin var(--t) var(--ease) both; }
.popup .pop:hover, .popup .pop:focus-visible { background: var(--gold-wash-hi); outline: none; }
.popup .pop.dim { color: var(--paper-dim); border-color: var(--line); }
.popup .pop svg { width: 20px; height: 20px; fill: none; stroke: currentColor; stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round; }
.popup .popDot { position: absolute; width: 8px; height: 8px; margin: -4px 0 0 -4px; border-radius: var(--r-round); border: var(--bw) solid var(--gold-line); }
.popup .popT { position: absolute; transform: translateX(-50%); max-width: 80vw; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; font-size: var(--fs-xs); font-style: var(--i-label); letter-spacing: var(--ls-whisper); color: var(--paper-dim); text-shadow: var(--glow-wide); padding: 3px 10px; border-radius: var(--r-round); background: var(--card-bg); border: var(--bw) solid var(--line); }   /* 2026-10-08, the owner: "subtitle underneath is white. can't see it" (over the paper chart): on a pill of the buttons' own card colour, so it reads over paper or space */
@keyframes popin { from { opacity: 0; transform: scale(.6); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) { .popup .pop { animation: none; } }

/* ── the chart on the whole screen (a phone needs it: pinch and drag instead of a stylus) ── */
#mapFull svg, .mapfloat svg { width: 16px; height: 16px; fill: none; stroke: currentColor; stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round; display: block; }
.mapbox { position: relative; }
#mapTip { position: absolute; z-index: 3; pointer-events: none; display: flex; flex-direction: column; gap: 2px; max-width: 70%; padding: 5px 9px; border-radius: 6px; background: rgba(243,232,200,0.96); color: rgb(58,40,22); box-shadow: 0 2px 8px rgba(0,0,0,0.4); font-size: var(--fs-row); }
#mapTip.hidden { display: none; }
#mapTip .mq.focus { color: rgb(150,62,28); }
#mapTip .mq.offered { color: rgb(60,105,70); }
.mapqkey { font-size: var(--fs-row); }
.qacts.mapq { margin-top: var(--gap-sm); }
.mapfloat { display: none; }
.mapbox.full { position: fixed; left: 0; right: 0; bottom: 0; top: calc(var(--tabs-h) + var(--sat)); z-index: calc(var(--z-pane) + 2); background: var(--night); display: grid; place-items: center; }
.mapbox.full #mapCanvas { border-radius: 0; box-shadow: none; max-width: none; margin: 0; }
.mapbox.full .mapfloat { display: flex; gap: var(--gap-sm); position: absolute; top: 10px; right: calc(10px + var(--sar)); }
.mapfloat button { width: var(--tap); height: var(--tap); display: grid; place-items: center; border-radius: var(--r-round); border: var(--bw) solid var(--line); background: var(--card-bg); color: var(--paper); font: inherit; font-size: var(--fs-lg); -webkit-backdrop-filter: var(--blur-btn); backdrop-filter: var(--blur-btn); cursor: pointer; }
body.mapfull #mapSel:not(:empty) { position: fixed; left: 0; right: 0; bottom: 0; z-index: calc(var(--z-pane) + 3); max-height: 42vh; overflow: auto; padding: var(--gap) calc(var(--gap-xl) + var(--sar)) calc(var(--gap) + var(--sab)) calc(var(--gap-xl) + var(--sal)); background: var(--sheet); border-top: var(--bw) solid var(--hairline); -webkit-backdrop-filter: var(--blur-card); backdrop-filter: var(--blur-card); }

/* ── a phone held sideways (a first pass, 2026-09-19): the glass is wide and only ~360 px tall, so everything that was stacked for an upright phone has to get out of the middle. The whisper goes to the top, between the bars and the numbers; the bars get shorter and closer; ping and listen stand side by side over the thrust button instead of in a column that reached the numbers; the help sheet and the cards scroll inside the height there is. ── */
@media (orientation: landscape) and (max-height: 500px) {
  :root { --bars-w: min(190px, 30vw); --bar-gap: 3px; --btn-touch: 64px; --btn-touch-lg: 74px; --btn-touch-sm: 50px; }
  body.touch #whisper, #whisper { bottom: auto; top: calc(var(--tabs-h) + var(--sat) + 6px); left: calc(var(--bars-w) + 150px + var(--sal)); right: calc(210px + var(--sar)); padding: 0 8px; max-width: none; font-size: 14px; line-height: 1.35; }
  #touchui #btnPing { right: calc(24px + var(--sar)); bottom: calc(108px + var(--sab)); }
  #touchui #btnListen { right: calc(84px + var(--sar)); bottom: calc(108px + var(--sab)); }
  #touchui .strafe { bottom: calc(98px + var(--sab)); }
  #actStack { bottom: calc(14px + var(--sab)); }
  #btnFire { bottom: calc(16px + var(--sab)); } #btnThrust { bottom: calc(16px + var(--sab)); }
  .hud-right { line-height: 1.35; }
  .card { max-height: calc(100vh - 16px); }
}
/* 09-25: what is broken aboard, under the low-hull line: steady, not urgent, so a stuck drive reads as the ship's trouble, not the game's (js/game/crisis.js) */
#hudFault { position: absolute; top: calc(var(--tabs-h) + var(--sat) + 108px); left: 0; right: 0; text-align: center; font-style: var(--i-label); font-size: var(--fs-xs); letter-spacing: var(--ls-wide); color: var(--hot); pointer-events: none; }
.mends { margin-top: var(--gap-xs); display: flex; flex-wrap: wrap; gap: var(--gap-xs); }
.mends.kit { align-items: center; }
.mends .kit-what { flex: 1 1 18em; font-size: .9em; line-height: 1.35; }   /* 2026-09-29, the owner: "there needs to be an explanation what a 'yard kit' is, next to the buy button (or over, if long)" */
.tag.hurt { color: var(--bad); border-color: var(--bad-line); margin: 0 0 0 var(--gap-xs); }
/* a bus bar shaken loose: the glass flickers, now and then, for a moment (never while the haunting runs) */
body.flicker #c { animation: flick .11s steps(2) infinite; }
@keyframes flick { 50% { opacity: .55; filter: brightness(1.5); } }
@media (prefers-reduced-motion: reduce) { body.flicker #c { animation: none; opacity: .8; } }
/* 09-25: the people aboard, under the bars (js/game/aboard.js, ui.js renderAboard) */
#crewPanel { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 10px; width: var(--bars-w); }
#crewPanel:empty { display: none; }
.mate { position: relative; width: 44px; height: 44px; border-radius: 50%; border: 2px solid var(--line-faint); overflow: visible; }
.mate img { width: 100%; height: 100%; border-radius: 50%; object-fit: cover; display: block; transition: opacity .6s, filter .6s; }
.mate.mood-asleep img { opacity: .55; }
.mate.mood-tired img { filter: saturate(.55); }
.mate.mood-concerned { border-color: var(--hot-line); }
/* 2026-09-26 (js/game/aboard.js): the Envoy facing the bulkhead after a jump, and a mark for what a story left (book, knot, drop) */
.mate.mood-turned { border-style: dashed; }
.mate.mood-turned img { opacity: .5; filter: grayscale(.8); }
.mate .mark { position: absolute; left: -5px; top: -5px; width: 14px; height: 14px; border-radius: 50%; background: var(--card-bg); display: grid; place-items: center; pointer-events: none; }
.mate .mark::after { content: ''; display: block; box-sizing: border-box; }
.mate .mark-knot::after { width: 8px; height: 8px; border: 2px solid var(--paper); border-radius: 50%; }
.mate .mark-book::after { width: 9px; height: 7px; border: 2px solid var(--paper); border-radius: 1px; }
.mate .mark-drop::after { width: 6px; height: 6px; background: var(--paper); border-radius: 0 50% 50% 50%; transform: rotate(45deg); }
.mate.hurt { border-color: var(--bad); animation: hurtPulse 1.4s ease-in-out infinite; }
@keyframes hurtPulse { 0%, 100% { box-shadow: 0 0 0 0 rgba(220, 60, 50, .75); } 50% { box-shadow: 0 0 0 6px rgba(220, 60, 50, 0); } }
.mate.smoke::after { content: ''; position: absolute; inset: -3px; border-radius: 50%; pointer-events: none;
  background: radial-gradient(circle at 30% 70%, rgba(150,145,140,.85), transparent 55%), radial-gradient(circle at 70% 35%, rgba(120,115,110,.8), transparent 50%), radial-gradient(circle at 50% 50%, rgba(90,88,86,.55), transparent 70%);
  animation: smokeDrift 4s ease-in-out infinite alternate; }
@keyframes smokeDrift { from { transform: translate(-2px, 1px) scale(1); opacity: .8; } to { transform: translate(2px, -2px) scale(1.08); opacity: .95; } }
.mate .wrench { position: absolute; right: -6px; bottom: -6px; width: 20px; height: 20px; border-radius: 50%; background: var(--card-bg); display: grid; place-items: center; }
.mate .wrench svg { width: 14px; height: 14px; fill: var(--paper); animation: wrench .6s steps(1) infinite; transform-origin: 50% 50%; }
@keyframes wrench { 0% { transform: rotate(-30deg); } 33.3% { transform: rotate(0deg); } 66.6% { transform: rotate(30deg); } }
@media (max-width: 700px), (pointer: coarse) { .mate .mark { width: 11px; height: 11px; left: -4px; top: -4px; } }
@media (max-width: 700px), (pointer: coarse) { .mate { width: 30px; height: 30px; } #crewPanel { gap: 6px; margin-top: 6px; } .mate .wrench { width: 16px; height: 16px; } .mate .wrench svg { width: 11px; height: 11px; } }
@media (prefers-reduced-motion: reduce) { .mate.hurt, .mate.smoke::after, .mate .wrench svg { animation: none; } .mate.hurt { box-shadow: 0 0 0 3px rgba(220, 60, 50, .6); } }
/* P59 (10-10): the captain first among the faces, in a brass ring and a hairline apart; every face a button that opens that person in the
 * target box (js/personpanel.js, ui.js renderAboard); the one shown is ringed */
button.mate, .capt { box-sizing: content-box; padding: 0; margin: 0; background: none; font: inherit; color: inherit; cursor: pointer; pointer-events: auto; -webkit-tap-highlight-color: transparent; }
.capt { position: relative; width: 44px; height: 44px; border-radius: 50%; border: 2px solid var(--gold-line); margin-right: 6px; flex: 0 0 auto; }
.capt::after { content: ''; position: absolute; right: -10px; top: 18%; bottom: 18%; width: 1px; background: var(--line-faint); pointer-events: none; }
.capt:last-child::after { display: none; }
.capt img { width: 100%; height: 100%; border-radius: 50%; object-fit: cover; display: block; }
.capt .ph { position: absolute; inset: 0; border-radius: 50%; background: radial-gradient(circle at 50% 38%, rgb(var(--gold-rgb) / .38) 0 17%, transparent 18%), radial-gradient(ellipse 40% 30% at 50% 92%, rgb(var(--gold-rgb) / .3) 0 98%, transparent 100%); }
.mate.on, .capt.on { box-shadow: 0 0 0 2px rgb(var(--gold-rgb) / .6); }
.mate:focus-visible, .capt:focus-visible { outline: 2px solid var(--gold); outline-offset: 3px; }
@media (max-width: 700px), (pointer: coarse) { .capt { width: 30px; height: 30px; margin-right: 4px; } .capt::after { right: -7px; } }

/* ── aboard, not for sale (js/game/items.js, js/items/): the pilot's unique things, each with a miniature the size of a face under the bars;
 * a tap opens what it is. With debug on, every quality below them, with where and when it was set ── */
#keptBox { margin-top: 8px; }
.kept { display: flex; flex-direction: column; gap: 6px; }
.kitem summary { display: flex; align-items: center; gap: 10px; cursor: pointer; list-style: none; }
.kitem summary::-webkit-details-marker { display: none; }
.kicon { flex: none; width: 36px; height: 36px; border-radius: 50%; border: 2px solid var(--line-faint); display: grid; place-items: center; overflow: hidden; color: var(--paper); }
.kicon svg { width: 26px; height: 26px; fill: none; stroke: currentColor; stroke-width: 1.3; stroke-linecap: round; stroke-linejoin: round; }
.kicon img { width: 100%; height: 100%; object-fit: cover; border-radius: 50%; display: block; }
.kitem[open] .kicon, .kitem summary:hover .kicon { border-color: var(--gold-line-soft); color: var(--gold); }
.kitem p { margin: 4px 0 8px 46px; }
.kitem p .pill { margin-left: 6px; }
.qgroup h3 { font-size: var(--fs-xs); font-weight: var(--w-normal); letter-spacing: .08em; color: var(--gold); margin: 12px 0 2px; }
.qrow { display: flex; flex-wrap: wrap; align-items: baseline; gap: 0 12px; font-size: var(--fs-xs); padding: 3px 0; border-bottom: 1px solid var(--line-faint); }
.qrow code { font-family: var(--mono); }
.qrow.norec .dim { font-style: italic; opacity: .7; }
/* 09-26: the pins at the foot of the glass (js/game/pins.js; js/game/crisis.js crisisPins). One a fault until it is mended, the most urgent at the foot; the whispers stack above them (#hud --pins-h lifts #whisper), and they never enter the whispers' queue or time out */
#pins { position: absolute; left: 0; right: 0; bottom: calc(92px + var(--sab)); margin: 0 auto; max-width: 46rem; padding: 0 28px; display: flex; flex-direction: column; justify-content: flex-end; align-items: center; gap: 6px; pointer-events: none; font-style: var(--i-label); font-size: var(--fs-whisper); letter-spacing: var(--ls-whisper); line-height: var(--lh-say); color: var(--paper); text-shadow: var(--glow-wide); }
#pins:empty { display: none; }
#whisper { margin-bottom: calc(var(--pins-h, 0px) + var(--act-h, 0px)); }   /* 09-29: and over the stacked action buttons (--act-h, js/ui.js actButtons) */
#hud.pinned #whisper { max-height: calc(100% - 92px - var(--sab) - var(--pins-h, 0px) - var(--tabs-h) - var(--sat) - 190px); overflow: hidden; }   /* with pins up the whispers keep clear of the bars: the newest, at the top, wait out of sight (their clocks do not run until they are read) */
body.touch #hud.pinned #whisper { max-height: calc(100% - 132px - var(--sab) - var(--pins-h, 0px) - var(--tabs-h) - var(--sat) - 190px); }
.pin { display: flex; flex-wrap: wrap; justify-content: center; align-items: center; column-gap: 10px; row-gap: 2px; max-width: 100%; padding: 6px 12px; border: var(--bw) solid var(--line-faint); border-radius: var(--r-card); background: rgb(var(--night-rgb) / .55); pointer-events: auto; animation: fadein .3s ease both; }
.pin .ptext { text-align: center; }
.pin .psec, .pin .pmore { font-style: normal; font-size: var(--fs-xs); font-variant-numeric: tabular-nums; opacity: .8; flex: none; }
.pin .pface { width: 32px; height: 32px; border-radius: var(--r-round); object-fit: cover; flex: none; box-shadow: 0 0 0 var(--bw) var(--ring-soft); }
.pin.ask { flex-direction: column; align-items: stretch; gap: 6px; }
.pin.ask .phead { display: flex; align-items: baseline; justify-content: center; gap: 8px; }
.pin .pchoices { display: flex; flex-wrap: wrap; justify-content: center; gap: 6px; }
.pin .pchoices .choice { font-style: normal; text-shadow: none; white-space: normal; max-width: 100%; }
.pin .px, .pin .pring { flex: none; width: 26px; height: 26px; padding: 0; border: 0; background: none; color: inherit; display: block; }
.pin .px { cursor: pointer; }
.pin .px svg, .pin .pring svg { width: 100%; height: 100%; display: block; fill: none; stroke: currentColor; stroke-linecap: round; }
.pin .wtrack { stroke-width: 1.2; opacity: .25; }
.pin .wring { stroke-width: 1.8; stroke-dasharray: 62.83; stroke-dashoffset: 0; transition: stroke-dashoffset .12s linear; }
.pin .px path { stroke-width: 1.6; }
.pin .pclock { white-space: nowrap; font-style: normal; font-size: var(--fs-xs); font-variant-numeric: tabular-nums; color: var(--hot); flex: none; text-align: center; }
.pin.aft { color: var(--gold); border-color: var(--hot-line); }
.pin.red { color: var(--bad); border-color: var(--bad-line); animation: pinRed 1s ease-in-out infinite; }
.pin.crew, .pin.wait, .pin.idle, .pin.end, .pin.coil { font-size: var(--fs-xs); color: var(--paper-dim); background: rgb(var(--night-rgb) / .35); padding: 4px 10px; }
.pin.end.ok { color: var(--paper); }
/* 09-27: the coil's day (do not attend; js/game/drive.js drivePin), quiet like the others; on the ship tab it sits above the figures */
#shipPins { display: flex; justify-content: center; margin: 4px 0 12px; font-style: var(--i-label); line-height: var(--lh-say); color: var(--paper); }
#shipPins:empty { display: none; }
@keyframes pinRed { 50% { box-shadow: 0 0 0 4px rgb(var(--bad-rgb) / .25); } }
body.touch #pins { bottom: calc(132px + var(--sab)); padding-left: 16px; padding-right: calc(var(--sar) + 33px + var(--btn-touch-sm) + 12px); }
body.touch .pin .pchoices .choice { min-height: var(--tap); }
body.touch .pin .px { width: var(--tap); height: var(--tap); padding: 7px; margin: -7px -7px -7px 0; }
@media (orientation: landscape) and (max-height: 500px) {
  body.touch #pins, #pins { bottom: auto; top: calc(var(--tabs-h) + var(--sat) + 6px); left: calc(var(--bars-w) + 150px + var(--sal)); right: calc(210px + var(--sar)); padding: 0 8px; max-width: none; font-size: 14px; line-height: 1.35; }
  #whisper, #hud.pinned #whisper, body.touch #hud.pinned #whisper { margin-bottom: 0; margin-top: var(--pins-h, 0px); max-height: none; overflow: visible; }   /* sideways the whispers hang from the top, so the pins go first and the whispers under them */
}
@media (prefers-reduced-motion: reduce) { .pin, .pin.red { animation: none; } }
/* the world in numbers under "learn more" (js/planetdata.js; ui.js worldTable): the key/value rows of .kv as a compact table, two columns of
 * pairs where there is room. A field the ship cannot read yet is a faint dash */
.pdata { margin: var(--gap-sm) 0 var(--gap-xs); }
.pdata h3 { margin: 0 0 var(--gap-xs); font-family: var(--display-face); font-style: var(--i-off); font-weight: var(--w-normal); font-size: var(--fs-row); }
.pdata h3 .dim { font-family: var(--text-face); font-style: var(--i-label); font-size: var(--fs-label); }
.pdata table { width: 100%; border-collapse: collapse; font-size: var(--fs-label); }
.pdata tbody { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); column-gap: var(--gap-lg); }
.pdata tr { display: flex; justify-content: space-between; align-items: baseline; gap: var(--gap); padding: 3px 0; border-bottom: var(--bw) solid var(--hairline); }
.pdata th { font-weight: var(--w-normal); text-align: left; color: var(--paper-faint); letter-spacing: var(--ls-label); white-space: nowrap; }
.pdata td { text-align: right; color: var(--paper); font-style: var(--i-label); font-variant-numeric: tabular-nums; }
.pdata tr.unk td { color: var(--paper-faint); cursor: help; }
.pdata p.dim { margin: var(--gap-xs) 0 0; font-size: var(--fs-label); }

/* ── every field you type into (2026-09-27, the owner: "edit field styling is default browser, should be styled like the game (maybe like
 * the buttons, but black on gold (inverted)?"). One look for all of them: a pill turned over, dark ink on gold, in the game's italic, with
 * a faded-ink placeholder, an ink caret, a selection in gold on ink, and a focus ring outside the field where the dark pane shows it. Each
 * field keeps its own size, padding and place (the rules above); only what they share lives here. A textarea keeps its squarer corner. ── */
input:is([type="text"], [type="number"], [type="search"], :not([type])), textarea { font-family: inherit; font-style: var(--i-label); font-weight: var(--w-normal); color: var(--field-ink); background: var(--field-gold); border: var(--bw) solid var(--field-edge); border-radius: var(--r-pill); caret-color: var(--field-ink); outline: none; user-select: text; -webkit-user-select: text; transition: background var(--t), box-shadow var(--t); }
textarea { border-radius: var(--r-field); }
#cloudCode, #saveText { font-family: var(--mono); font-style: var(--i-off); border-radius: var(--r-field); }
input:is([type="text"], [type="number"], [type="search"], :not([type])):hover, textarea:hover { background: var(--field-gold-lit); }
input:is([type="text"], [type="number"], [type="search"], :not([type])):focus, textarea:focus { background: var(--field-gold-lit); outline: none; }
input:is([type="text"], [type="number"], [type="search"], :not([type])):focus-visible, textarea:focus-visible { outline: 2px solid var(--field-focus); outline-offset: 2px; }
input:is([type="text"], [type="number"], [type="search"], :not([type]))::placeholder, textarea::placeholder { color: var(--field-ph); opacity: 1; font-style: var(--i-label); }
input:is([type="text"], [type="number"], [type="search"], :not([type]))::selection, textarea::selection { background: var(--field-sel); color: var(--gold); }
input:is([type="text"], [type="number"], [type="search"], :not([type])):disabled, textarea:disabled { opacity: .45; cursor: not-allowed; }
input:is([type="text"], [type="number"], [type="search"], :not([type])):-webkit-autofill { -webkit-text-fill-color: var(--field-ink); box-shadow: 0 0 0 40px var(--field-gold) inset; }
input[type="number"] { -moz-appearance: textfield; appearance: textfield; }   /* the jettison count: the browser's spinners were grey on gold and too small to hit */
input[type="number"]::-webkit-inner-spin-button, input[type="number"]::-webkit-outer-spin-button { -webkit-appearance: none; margin: 0; }
/* the ship's name: at the yard for a new hull (the ship tab) and at a governor's desk (the talk card) */
.rename { display: flex; align-items: center; gap: var(--gap-sm); flex-wrap: wrap; margin-top: 10px; }
.rename input { font-size: var(--fs-body); padding: var(--pill-pad-sm); min-width: 0; flex: 1 1 160px; }
.rename-note { margin: 10px 0 0; font-size: var(--fs-sm); }
/* ── the start screen (2026-09-27, the owner: "generate start screen graphics on higgsfield and make start screen"; js/game/start.js) ──
 * The painting fills the screen and never loses the ship: object-position and the drift's origin sit on her in each picture (wide: half
 * across, 68 % down; tall: 52 %, 62 %). The words and the doors stand in the empty sky above her. Over the tabs, under a toast and a card */
.start { position: fixed; inset: 0; z-index: calc(var(--z-tabs) + 5); background: var(--night); overflow: hidden; transition: opacity .9s var(--ease); --ship-at: 50% 68%; }
.start.out { opacity: 0; pointer-events: none; }
.startArt, .startArt img { position: absolute; inset: 0; width: 100%; height: 100%; display: block; }
/* 2026-09-28: the drift (56 s there and back, 3%) and the twinkles are set four times a second by js/game/start.js (stillTick), not animated
 * here: a CSS animation had the compositor make the whole screen sixty times a second (docs/perigee/0928_performance.md §2 idea 6) */
.startArt img { object-fit: cover; object-position: var(--ship-at); transform-origin: var(--ship-at); transform: scale(1.005); }
.startSky { position: absolute; inset: 0; pointer-events: none; }
.startSky i { position: absolute; border-radius: 50%; background: rgb(var(--paper-rgb) / .9); box-shadow: 0 0 3px rgb(var(--paper-rgb) / .5); opacity: .1; }
.startSky i.warm { background: var(--gold); box-shadow: 0 0 4px rgb(var(--gold-rgb) / .6); }
.startMenu { position: absolute; left: 0; right: 0; top: calc(var(--sat) + 10vh); padding: 0 calc(16px + var(--sar)) 0 calc(16px + var(--sal)); display: flex; flex-direction: column; align-items: center; text-align: center; opacity: 0; transform: translateY(8px); transition: opacity 1.4s var(--ease), transform 1.4s var(--ease); }
.start.ready .startMenu { opacity: 1; transform: none; }
.startMenu h1 { font-family: var(--serif); font-weight: 300; font-style: normal; font-variation-settings: 'opsz' 72;   /* at 150 px Fraunces' own optical size thins the e's bar to nothing: it is held at a phone's */ font-size: clamp(56px, min(13vw, 17vh), 150px); line-height: 1; letter-spacing: .035em; color: var(--gold); margin: 0; text-shadow: 0 0 44px rgb(var(--gold-rgb) / .2), 0 2px 18px rgb(var(--night-rgb) / .9); }
.startMenu h1::after { content: ''; display: block; width: min(180px, 40vw); height: 1px; margin: 14px auto 0; background: linear-gradient(90deg, transparent, var(--gold-line), transparent); }
.startSub { margin: 14px 0 0; font-size: clamp(12.5px, 1.3vw, 15px); font-variant-caps: all-small-caps; letter-spacing: .24em; color: var(--paper-dim); max-width: min(92vw, 60em); line-height: 1.6; text-shadow: var(--glow-soft); }
.startActs { margin-top: clamp(26px, 6vh, 56px); display: flex; flex-direction: column; align-items: center; gap: 12px; }
.start .pill { min-height: 44px; min-width: 44px; }
.start .pill.startMain { font-size: var(--fs-lg); padding: 11px 40px; min-width: 220px; letter-spacing: var(--ls-btn); background: rgb(var(--night-rgb) / .45); }
.start .pill.startMain:hover, .start .pill.startMain:focus-visible { background: var(--gold-wash-hi); }
.startMeta { font-size: var(--fs-cap); font-style: italic; color: rgb(var(--paper-rgb) / .52); letter-spacing: var(--ls-label); margin-top: -4px; text-shadow: var(--glow-soft); }
.startRow { display: flex; gap: 10px; align-items: center; justify-content: center; flex-wrap: wrap; margin-top: 6px; }
.startRow .pill { font-size: var(--fs-row); padding: 10px 22px; background: rgb(var(--night-rgb) / .45); }
.startLang { width: 44px; height: 44px; border-radius: 50%; border: var(--bw) solid var(--line); background: rgb(var(--night-rgb) / .45); padding: 0; cursor: pointer; display: grid; place-items: center; }
.startLang svg { width: 24px; height: 24px; display: block; }
.startLang:hover, .startLang:focus-visible { border-color: var(--gold-line); background: var(--ghost-bg-hi); }
.start button:focus-visible { outline: 1px solid var(--gold-edge); outline-offset: 3px; }
@media (orientation: portrait) { .start { --ship-at: 52% 62%; } .startMenu { top: calc(var(--sat) + 12vh); } .startMenu h1 { font-size: clamp(56px, 19vw, 120px); } }
@media (orientation: landscape) and (max-height: 520px) { .startMenu { top: calc(var(--sat) + 4vh); } .startMenu h1 { font-size: clamp(40px, 14vh, 72px); } .startMenu h1::after { margin-top: 8px; } .startSub { margin-top: 8px; font-size: 12px; }
  .startActs { margin-top: 16px; flex-direction: row; flex-wrap: wrap; justify-content: center; gap: 10px; } .startRow { display: contents; } .startMeta { order: 9; width: 100%; margin-top: 0; } .start .pill.startMain { min-width: 0; padding: 10px 30px; font-size: var(--fs-row); } }
@media (prefers-reduced-motion: reduce) { .startArt img { animation: none; transform: none; } .startSky { display: none; } .start, .startMenu { transition: none; } }
/* 2026-09-29: the rental's counter under the gauges (js/noshippanel.js; the owner: "a counter on how many days left in the 'fly' screen. a status bar?"): the days left as a bar, amber in the last week, red and empty once the company has her drive; with no ship the row says so and the other gauges go faint */
.bar.rent i { height: max(2px, calc(var(--bar-h) * 0.6)); }
#barRent { background: rgba(214, 200, 170, 0.7); } #barRent.warn { background: var(--bar-laser); } #barRent.cut, #barRent.noship { width: 0 !important; }
.bar.rent em.low { color: var(--bad); } .bar.rent em.none { color: var(--paper-dim); }
body.noship #hud .bar:not(.rent) { opacity: 0.22; }
.noship h3 { margin: 0 0 6px; }

/* 2026-10-06, the golden layout (the owner: "move the center of the gameplay to golden ratio to the right, so the space to the left is for:
 * bars, info panel, ephemeral messages and quest modals"). js/render.js goldSet puts the ship at 0.618 of a wide glass and sets body.gold and
 * --gold-w (the left column, 0.382 of the width). The bars and the readout stack in it, the whispers and the toasts speak from its foot and top,
 * his and everyone's cards open in it; what belongs to the ship (the action buttons, the badges, "paused") is centred on her line instead */
body.gold .hud-top { right: auto; width: calc(var(--gold-w) - var(--hud-inset) * 2 - var(--sal)); flex-direction: column; justify-content: flex-start; }
body.gold .hud-right { text-align: left; max-width: 100%; width: 100%; }
body.gold #whisper { right: auto; width: var(--gold-w); max-width: none; margin-left: 0; margin-right: 0; padding: 0 20px 0 calc(var(--hud-inset) + var(--sal)); box-sizing: border-box; align-items: flex-start; text-align: left; }
body.gold #toast { left: calc(var(--gold-w) / 2); max-width: calc(var(--gold-w) - 32px); }
body.gold .card.hail { left: calc(var(--hud-inset) + var(--sal)); transform: translateY(-50%); width: var(--hail-w); }   /* flush with the bars and the whispers (10-06, the owner: "aligned to the left like the bars section and ephemeral msgs") */
body.gold .card.hail.scene { display: block; overflow-y: auto; }
body.gold .card.hail.scene .hailMain { max-height: none; overflow: visible; padding-right: 0; }
body.gold .card.hail.scene .scenePic { aspect-ratio: auto; max-height: 30vh; }
body.gold #hudSandbox, body.gold #hudLow, body.gold #hudFault, body.gold #hudPaused { left: calc(100vw - 2 * var(--gold-w)); }   /* centred on the ship's line: the span from here to the right edge has her in its middle */
body.gold #actStack { left: calc(100vw - var(--gold-w)); max-width: calc(2 * var(--gold-w) - 40px); }
body.gold #whisper > *, body.gold #whisper span { text-align: left; }
body.gold .autoBadge { justify-content: flex-start; }   /* the readout is left-aligned in the column now: the autopilot's light sits under the speed, not at the column's far edge (10-06) */

/* 2026-10-06, the log's button and the lower left (the owner: "treat 'loot gained' messages as the same class as other ephemeral messages ...
 * Keep them all in the lower left ... 'log' becomes a button, (perhaps a round icon?) placed in bottom left and all the messages once they are
 * read shrink to the log button and the log button gently blinks"). On the golden layout only: a phone keeps its sticks in that corner and the
 * tab bar's "log" (where the lines go there instead, js/logbtn.js) */
#logBtn { display: none; }
body.gold #logBtn { display: flex; position: fixed; left: calc(var(--hud-inset) + var(--sal)); bottom: calc(22px + var(--sab)); width: 40px; height: 40px; padding: 0; border-radius: 50%; align-items: center; justify-content: center; background: var(--scrim-soft); border: var(--bw) solid var(--gold-line); color: var(--gold); z-index: var(--z-toast); cursor: pointer; transition: background var(--t-fade) linear, box-shadow .4s ease-out; }
body.gold #logBtn svg { width: 20px; height: 20px; fill: none; stroke: currentColor; stroke-width: 1.7; stroke-linecap: round; }
body.gold #logBtn:hover, body.gold #logBtn:focus-visible, body.gold #logBtn.on { background: rgb(var(--gold-rgb) / .16); }
#logBtn.ack, #tabs button.ack { animation: logAck 1s ease-out 1; }
@keyframes logAck { 0% { box-shadow: 0 0 0 0 rgb(var(--gold-rgb) / .0); } 25% { box-shadow: 0 0 0 4px rgb(var(--gold-rgb) / .45), 0 0 14px 4px rgb(var(--gold-rgb) / .35); } 100% { box-shadow: 0 0 0 10px rgb(var(--gold-rgb) / 0); } }
@media (prefers-reduced-motion: reduce) { #logBtn.ack, #tabs button.ack { animation: none; background: rgb(var(--gold-rgb) / .16); } }
body.gold #tabs button[data-tab="log"] { display: none; }
body.gold .tabpane { padding-bottom: 76px; }   /* the round button stands over every page's foot */
body.gold #toast { top: auto; bottom: calc(26px + var(--sab)); left: calc(var(--hud-inset) + var(--sal) + 52px); transform: none; align-items: flex-start; max-width: calc(var(--gold-w) - 84px); }
body.gold #whisper { bottom: calc(80px + var(--sab) + var(--toast-h, 0px)); margin-bottom: var(--pins-h, 0px); }   /* the whispers stand on the toasts, all of it in the lower left */
body.gold #hud.pinned #whisper { bottom: calc(max(92px, 80px + var(--toast-h, 0px)) + var(--sab)); }   /* 2026-10-08 (P37, pw123): with a pin up the whispers stand on it, as everywhere (09-26). The pins stay at 92 px while the whispers came down to 80, so their foot sank 6 px into the pin's top, the close mark of the last one on the pin's edge */
.logfly { will-change: transform, opacity; }
body.gold .card.hail { animation-name: cardinL; }   /* the card's entry keeps its own transform (cardin ends on translate(-50%, -50%), which would centre it again) */
@keyframes cardinL { from { opacity: 0; transform: translateY(-48%); } to { opacity: 1; transform: translateY(-50%); } }
body.gold .card.hail { top: auto; bottom: calc(76px + var(--sab)); transform: none; max-height: calc(100vh - var(--tabs-h) - var(--sat) - 96px - var(--sab)); animation-name: cardinB; }   /* at the foot of the column, over the messages: the bars above stay in sight, so what he lights up there can be seen while he speaks (10-06) */
body.gold { --hail-w: min(520px, calc(var(--gold-w) - var(--hud-inset) * 2 - var(--sal))); --hail-r: calc(var(--hud-inset) + var(--sal) + var(--hail-w) + 20px); }   /* 2026-10-13, the owner: the quest card stays in the left column on every tab, so the log can be read beside it */
body.gold:has(#hail:not(.hidden)):not(.flytab) .tabpane .inner { margin-left: max(var(--hail-r), calc((100% - var(--pane-max)) / 2)); margin-right: auto; }   /* a tab opened under an open quest card steps to the right of it instead of under it */
body.gold:has(#hail:not(.hidden)) #whisper, body.gold:has(#hail:not(.hidden)) #pins { left: var(--hail-r); width: auto; right: auto; max-width: min(30rem, calc(100vw - var(--hail-r) - 24px - var(--sar))); padding-left: 0; bottom: calc(76px + var(--sab)); margin-bottom: 0; }   /* 2026-10-13, the owner: "stack horizontally to the right on top of quest pop-up": the whispers stand beside the card, from its foot up, never under it */
@keyframes cardinB { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }

/* 2026-10-06, the owner: "'about' ... probably should be a round question mark button next to the language flag": the about tab, round, by the flag */
#tabs button.roundQ { flex: 0 0 auto; width: 44px; min-width: 44px; padding: 0; margin: 0 2px 0 0; display: flex; align-items: center; justify-content: center; border-bottom-color: transparent; }   /* a thumb's 44 px to hit (pw40), the circle drawn inside it */
#tabs button.roundQ span { width: 26px; height: 26px; border-radius: 50%; border: var(--bw) solid var(--gold-line); display: flex; align-items: center; justify-content: center; font-family: var(--display-face); font-style: normal; font-size: 15px; line-height: 1; color: var(--gold); }
#tabs button.roundQ.on span { background: rgb(var(--gold-rgb) / .16); }
#tabs button.roundQ.on { border-bottom-color: transparent; }
/* 2026-10-08, the owner: "some sort of green check mark or another indicator of yes, your game is safe 100%" — the save badge beside the "?"
 * (js/game/cloud.js cloudBadge, in the ship tab's "this game"): green, the server holds this game; amber, a newer save on its way; red, refused or another device's newer
 * copy; grey, kept on this device only. The colours are here to tune. */
:root { --save-ok: 110 210 130; --save-wait: 235 185 90; --save-bad: 235 95 85; --save-local: 160 160 150; }
/* the badge in the ship tab's "this game" (moved there from the tab bar, the owner 10-08), its words beside it */
.saveState { display: flex; align-items: center; gap: 10px; margin: 4px 0 10px; }
.saveState #saveBadgeText { font-size: var(--fs-xs); font-style: var(--i-label); color: var(--paper-dim); line-height: 1.35; }
button.saveB { flex: 0 0 auto; width: 44px; height: 44px; padding: 0; margin: 0; display: flex; align-items: center; justify-content: center; background: none; border: 0; cursor: pointer; }
button.saveB span { width: 28px; height: 28px; border-radius: 50%; border: var(--bw) solid var(--gold-line); display: flex; align-items: center; justify-content: center; font-family: var(--serif); font-size: 15px; line-height: 1; }
button.saveB.ok span { color: rgb(var(--save-ok)); border-color: rgb(var(--save-ok) / .7); background: rgb(var(--save-ok) / .12); }
button.saveB.wait span { color: rgb(var(--save-wait)); border-color: rgb(var(--save-wait) / .7); }
button.saveB.bad span, button.saveB.clash span { color: rgb(var(--save-bad)); border-color: rgb(var(--save-bad) / .8); background: rgb(var(--save-bad) / .14); animation: saveBad 1.8s ease-in-out infinite; }
button.saveB.local span { color: rgb(var(--save-local)); border-color: rgb(var(--save-local) / .5); }
@keyframes saveBad { 50% { box-shadow: 0 0 0 4px rgb(var(--save-bad) / .18); } }
@media (prefers-reduced-motion: reduce) { button.saveB.bad span, button.saveB.clash span { animation: none; } }
#tabs button.roundQ.tutGlow { box-shadow: none; animation: none; } #tabs button.roundQ.tutGlow span { animation: tutPulse 1.6s ease-in-out infinite; }   /* the glow on the circle, not the hit area */

/* 2026-10-07, the owner: "Language and question mark buttons - align to right": flush with the right edge, as the bars are with the left */
#tabs { padding-right: calc(var(--hud-inset) + var(--sar)); }
#tabs #btnLang { padding-right: 0; }
/* the owner: "any button like interact, jump, whatever, needs to be on the left": on the golden layout the action stack stands in the left
 * column over the log button and the toasts, and the whispers stand on it (--acts-h, js/ui.js actButtons) */
body.gold #actStack { left: calc(var(--hud-inset) + var(--sal)); transform: none; align-items: flex-start; bottom: calc(76px + var(--sab) + var(--toast-h, 0px)); max-width: calc(var(--gold-w) - var(--hud-inset) * 2); }
body.gold #whisper { bottom: calc(80px + var(--sab) + var(--toast-h, 0px) + var(--acts-h, 0px)); }
/* 2026-10-09 (P50): the fault pins in the left column too, flush with the messages, standing over the toasts and the action buttons, with the whispers on top of them (the old centred place stays for gold off and for phones, which have no body.gold) */
body.gold #pins { right: auto; width: var(--gold-w); max-width: none; margin: 0; padding: 0 20px 0 calc(var(--hud-inset) + var(--sal)); box-sizing: border-box; align-items: flex-start; bottom: calc(max(92px, 80px + var(--toast-h, 0px) + var(--acts-h, 0px)) + var(--sab)); }
body.gold #hud.pinned #whisper { bottom: calc(max(92px, 80px + var(--toast-h, 0px) + var(--acts-h, 0px)) + var(--sab)); }
/* 2026-10-07: witchspace as layers the compositor turns (js/witchfx.js): over the glass, under the HUD, centred on the ship's line */
#witchfx { position: fixed; inset: 0; pointer-events: none; z-index: 5; display: none; overflow: hidden; }
#witchfx.on { display: block; }
#witchfx .wfx-dark { position: absolute; inset: 0; background: #040208; opacity: 0; will-change: opacity; }
#witchfx .wfx-layer { position: absolute; left: var(--wfx-cx, 50%); top: 50%; width: var(--wfx-side, 100vmax); height: var(--wfx-side, 100vmax); transform: translate(-50%, -50%); opacity: 0; will-change: transform, opacity; }
#witchfx .wfx-star, #witchfx .wfx-vortex, #witchfx .wfx-life { mix-blend-mode: screen; }   /* painted on black: black adds nothing, so these need no alpha (2026-10-14: the starflower, its vortex, the flower of life) */
#witchfx .wfx-vig { position: absolute; inset: 0; background: radial-gradient(circle at var(--wfx-cx, 50%) 50%, rgba(0,0,0,0) 22%, rgba(0,0,0,.92) 72%); opacity: 0; will-change: opacity; }
/* 2026-10-07 — the coil's song (js/coilsongfx.js; docs/perigee/tasks/done/P01-coil-song.md). The owner: "amber, but faintly glowing, not much
 * brighter than the dark background". Over witchspace (#witchfx, z 5) and the new sky, under the HUD; only over the cockpit. Narrow and tall
 * screens: high in the middle, clear of the bars above and the controls below. The golden layout: the left column, between the bars and the
 * whispers. A beat (CoilSong.BEATS) stands up in capitals, a little brighter. */
#coilsong { position: fixed; left: calc(18px + var(--sal)); right: calc(18px + var(--sar)); top: calc(var(--tabs-h) + var(--sat) + 19vh); max-height: 30vh; overflow: hidden; pointer-events: none; user-select: none; z-index: 6; display: none;
  font-family: 'Fraunces', Georgia, serif; font-style: italic; font-weight: 300; font-size: 15px; line-height: 1.62; letter-spacing: .015em; text-wrap: pretty;
  color: rgb(212 150 74 / .40); text-shadow: 0 0 8px rgb(255 166 64 / .30), 0 0 1px rgb(255 196 120 / .22); opacity: 1; transition: opacity var(--cs-fade, 3500ms) ease; }
#coilsong.on { display: block; }
#coilsong.fade { opacity: 0; }
#coilsong.long { font-size: 14px; }
#coilsong.over { -webkit-mask-image: linear-gradient(to bottom, transparent 0, #000 2.6em); mask-image: linear-gradient(to bottom, transparent 0, #000 2.6em); }
#coilsong .beat { font-style: normal; font-weight: 500; letter-spacing: .09em; color: rgb(238 178 96 / .68); text-shadow: 0 0 10px rgb(255 170 70 / .42); }
body:not(.flytab) #coilsong { display: none; }
body.gold #coilsong { left: calc(var(--hud-inset) + var(--sal)); right: auto; width: min(440px, calc(var(--gold-w) - var(--hud-inset) * 2 - var(--sal))); top: 36vh; max-height: 36vh; font-size: 16px; }
body.gold #coilsong.long { font-size: 15px; }
@media (min-width: 1500px) { body.gold #coilsong { font-size: 17px; width: min(480px, calc(var(--gold-w) - var(--hud-inset) * 2 - var(--sal))); } body.gold #coilsong.long { font-size: 16px; } }
#logList .songrow .song { font-family: 'Fraunces', Georgia, serif; font-style: italic; font-weight: 300; color: rgb(212 150 74 / .62); }   /* the coil's song, kept whole */
/* P23 (2026-10-08): the cargo tab's ? button, a proper size to tap on a phone (44 px square target, drawn small) */
.qmark { flex: none; margin-left: var(--gap-xs, 6px); min-width: 44px; min-height: 44px; border: 0; background: transparent; color: var(--gold, #d9b45a); font: inherit; font-weight: 600; cursor: pointer; position: relative; }
.qmark::before { content: ""; position: absolute; left: 50%; top: 50%; width: 22px; height: 22px; margin: -11px 0 0 -11px; border: 1px solid currentColor; border-radius: 50%; opacity: .7; }
.qmark:hover::before, .qmark:focus-visible::before { opacity: 1; }
/* 2026-10-09 (P56 lane B) — the target panel (js/tpanel.js, js/game/tpanel.js). The owner: "There should be area, under the bars and crew avatars,
 * that's reserved for target data ... Should be square"; nothing steered for, no panel; "the panel opens for witchspace telemetry. this is where
 * it lands" (the coil's song, #tgtSong, typed as before by js/coilsongfx.js). As wide as the bars, square; smaller on a phone, where the song
 * still gets the bars' width. Words only: nothing in it can be tapped. */
#tgtPanel { width: var(--bars-w); aspect-ratio: 1 / 1; box-sizing: border-box; margin-top: 8px; padding: 8px 10px; overflow: hidden; display: flex; flex-direction: column; gap: 4px; background: var(--scrim-soft); border: var(--bw) solid rgb(var(--paper-rgb) / .12); border-radius: 6px; font-size: var(--fs-xs); line-height: 1.35; color: var(--paper-dim); text-shadow: var(--glow-hud); font-variant-numeric: tabular-nums; pointer-events: none; }
#tgtPanel .tpTop { display: flex; gap: 8px; align-items: center; min-height: 0; }
#tpPic { width: 56px; height: 56px; flex: 0 0 auto; }
#tgtPanel .tpHead { min-width: 0; display: flex; flex-direction: column; }
#tpName { font-weight: var(--w-normal); color: var(--gold); font-size: var(--fs-label); font-style: var(--i-label); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
#tpSub { color: var(--paper-faint); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
#tgtPanel .tpRow { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
#tgtPanel .tpRow.dim, #tgtPanel .tpRow > span { color: var(--paper-faint); }
#tgtPanel .tpTp { white-space: normal; display: -webkit-box; -webkit-line-clamp: 2; line-clamp: 2; -webkit-box-orient: vertical; }
#tgtPanel .tpHeat { display: flex; align-items: center; gap: 6px; }
#tgtPanel .tpHeat i { flex: 1 1 auto; height: 3px; background: rgb(var(--paper-rgb) / .12); border-radius: 2px; overflow: hidden; }
#tgtPanel .tpHeat b { display: block; height: 100%; background: var(--heat); opacity: .8; }
#tgtPanel .tpHeat.faint b { opacity: .45; }
#tgtPanel .tpHeat em { font-style: normal; }
#tgtPanel .tpHeat.hot em { color: var(--heat); }
#tpSpec { width: 100%; height: 32px; display: block; flex: 0 0 auto; }
#tgtPanel .tpMatch { color: var(--paper); }
#tgtPanel .tpBounty { color: var(--gold); }
#tgtSong { display: none; }
#tgtPanel.song > :not(#tgtSong) { display: none; }
#tgtPanel.song #tgtSong { display: block; flex: 1 1 auto; min-height: 0; overflow: hidden; }
#tgtPanel #coilsong { position: static; left: auto; right: auto; top: auto; width: auto; height: 100%; max-height: 100%; font-size: 13.5px; line-height: 1.5; z-index: auto; text-shadow: 0 0 8px rgb(255 166 64 / .30), 0 0 1px rgb(255 196 120 / .22); }
#tgtPanel #coilsong.long { font-size: 12.5px; }
#tgtPanel { background: rgb(var(--night-rgb) / .84); }   /* P60 (2026-10-10): the names the glass writes beside worlds and hulls showed through the square at half shade and ran into its rows (a phone, the lesson's marker); a deeper shade keeps the rows legible (no blur: it would recomposite every frame on the Pi) */
@media (min-width: 701px) and (max-height: 860px) { body.gold #tgtPanel { width: clamp(150px, calc(100vh - 635px), var(--bars-w)); padding: 6px 8px; gap: 2px; font-size: 11px; } body.gold #tpSpec { height: 22px; } }   /* P60 (2026-10-10): on a laptop's 800 px the square, the purse lines under it and the whispers above the buttons ran into each other; a shorter screen gets a smaller square (still square) */
@media (max-width: 700px) { #tgtPanel { width: min(150px, 40vw); padding: 5px 6px; gap: 2px; font-size: 10.5px; margin-top: 6px; } #tgtPanel.song { width: var(--bars-w); } #tpPic { width: 34px; height: 34px; } #tpName { font-size: 11.5px; } #tpSpec { height: 20px; } #tgtPanel #coilsong { font-size: 12px; line-height: 1.45; } #tgtPanel #coilsong.long { font-size: 11.5px; } }
@media (orientation: landscape) and (max-height: 500px) { #tgtPanel { width: min(130px, 22vw); padding: 4px 6px; gap: 1px; font-size: 10px; } #tgtPanel.song { width: var(--bars-w); } #tpPic { width: 28px; height: 28px; } #tpSpec { height: 16px; } }
/* P59 (10-10): a person in the square (js/personpanel.js): their face, name and role, and a few lines in words; the target waits underneath */
#tpPerson { display: none; }
#tgtPanel.person > :not(#tpPerson) { display: none !important; }
#tgtPanel.person #tpPerson { display: flex; flex-direction: column; gap: 4px; min-height: 0; }
#tpPerson .ppFace { flex: 0 0 auto; width: 56px; height: 56px; border-radius: 50%; overflow: hidden; border: 2px solid var(--line-faint); box-sizing: border-box; background: rgb(var(--paper-rgb) / .06); }
#tpPerson.cap .ppFace { border-color: var(--gold-line); }
#ppFace { width: 100%; height: 100%; object-fit: cover; display: block; }
#tpPerson .ppRow { white-space: normal; display: -webkit-box; -webkit-line-clamp: 2; line-clamp: 2; -webkit-box-orient: vertical; }
#tpPerson .ppRow.hot { color: var(--bad); }
@media (max-width: 700px) { #tpPerson .ppFace { width: 34px; height: 34px; } #tpPerson { gap: 2px; } }
@media (orientation: landscape) and (max-height: 500px) { #tpPerson .ppFace { width: 28px; height: 28px; } }
/* P61 (2026-10-10): a person's status as three short bars with a word (health, food, mood; the air while it is bad), never a number */
#tpPerson .ppBar { display: grid; grid-template-columns: 4.6em 1fr auto; align-items: center; gap: 6px; font-size: .92em; line-height: 1.25; min-width: 0; }
#tpPerson .ppBar .ppK { color: var(--paper-faint); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
#tpPerson .ppBar .ppTrack { height: 5px; border-radius: 3px; background: rgb(var(--paper-rgb) / .12); overflow: hidden; min-width: 28px; }
#tpPerson .ppBar .ppTrack i { display: block; height: 100%; border-radius: 3px; background: rgb(var(--paper-rgb) / .62); transition: width .6s ease; }
#tpPerson .ppBar .ppW { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 9.5em; text-align: right; }
#tpPerson .ppBar.hot .ppTrack i { background: var(--bad); }
#tpPerson .ppBar.hot .ppW { color: var(--bad); }
/* 2026-10-14 (the owner): the face clicked under the bars, bigger, to be seen; "talk" for a crewmate and "hail" for a ship at the foot of the
   square (js/personpanel.js, js/tpanel.js). The rows give way first, so the buttons always stay in the square */
#tpPerson .ppFace { width: 36%; height: auto; aspect-ratio: 1 / 1; }
@media (max-width: 700px) { #tpPerson .ppFace { width: 34%; height: auto; } }
@media (orientation: landscape) and (max-height: 500px) { #tpPerson .ppFace { width: 30%; height: auto; } }
#tgtPanel.person #tpPerson { flex: 1 1 auto; }
#tpPerson #ppRows, #tgtPanel #tpRows, #tgtPanel #tpMore { min-height: 0; overflow: hidden; flex: 0 1 auto; }
#tgtPanel .tpActs { margin-top: auto; flex: 0 0 auto; display: flex; justify-content: center; gap: 6px; padding-top: 2px; }
#tgtPanel .tpActs .pill { min-width: 56%; pointer-events: auto; cursor: pointer; }   /* 2026-10-14: the square lets clicks through to the glass (pointer-events: none); its buttons (talk, hail) take them */
#tgtPanel.tgt:not(.person) > .tpActs { order: 9; }
@media (max-width: 700px) { #tpPerson .ppBar { grid-template-columns: 3.8em 1fr auto; gap: 4px; font-size: .86em; } #tpPerson .ppBar .ppW { max-width: 7.5em; } }
#hailFace.none { display: none; }   /* a call with no face shows no empty ring (10-09) */
/* 10-11: the music is wired off for now (js/audio.js MUSIC_WIRED), so its box is not offered */
label.set:has(#music) { display: none; }
.tabpane h2[tabindex="-1"]:focus { outline: none; }   /* P95: the crew tab's step headings take focus from a "continue" */
/* P102: the end coming at the old address, under the title (js/game/dusk.js). A cold light that falters now and then */
.startDusk { margin: 18px auto 0; max-width: min(92vw, 36em); font-size: clamp(12.5px, 1.25vw, 14.5px); line-height: 1.55; font-style: italic; color: #cbbcff; text-shadow: 0 0 14px rgba(150, 120, 255, .35); animation: duskFalter 9s ease-in-out infinite; }
.startDusk a { color: inherit; text-decoration: underline dotted; text-underline-offset: 3px; pointer-events: auto; }
@keyframes duskFalter { 0%, 44%, 100% { opacity: .92; } 47% { opacity: .3; } 49% { opacity: .8; } 51% { opacity: .45; } 54% { opacity: .92; } }
@media (prefers-reduced-motion: reduce) { .startDusk { animation: none; } }
/* P105 (2026-10-15): the first visit's loading line on the cover (inline script in index.html after #start): a thin line that fills as the scripts arrive, and one
 * quiet word under it. Hidden until the script says the wait is long (js: .on); the script removes it when window.PG exists. */
.loadLine { position: absolute; left: 50%; bottom: calc(var(--sab, 0px) + 9vh); width: min(220px, 56vw); transform: translateX(-50%); opacity: 0; transition: opacity .8s var(--ease); pointer-events: none; text-align: center; }
.loadLine.on { opacity: 1; }
.loadLine i { display: block; height: 1px; background: var(--gold-line); transform: scaleX(0); transform-origin: left; transition: transform .35s linear; }
.loadLine span { display: block; margin-top: 12px; font-size: clamp(12px, 1.2vw, 14px); font-variant-caps: all-small-caps; letter-spacing: .24em; color: var(--paper-dim); }
@media (prefers-reduced-motion: reduce) { .loadLine, .loadLine i { transition: none; } }
