/* Cohabyte: the facility.

   The palette is a dark navy family. The one rule of shape: rounded and rubber is
   hardware (the keys, the doors), chamfered is printed paper (the sheets). Consolas
   throughout.

   Two kinds of page. The Core (body.core) is one stage, the sphere drawn on a canvas and
   the consoles and doors placed over it. A room (body.room) is a quieter hall: a head
   strip with the room's name and the door back, then the content. Leaving one page for
   another goes through a WINDOW (doors.js and the block at the end of this file): a
   console is a window to its room; you are pulled toward it, a cut, and the window
   grows to fill the screen. The way back is the opposite: the room folds into the
   console's rectangle and the Mainframe is there behind it. */

:root {
  --bg:         #07070d;   /* window body, the rubber */
  --surface:    #1b1b20;   /* cards, rows, inputs: the rubber lifted toward white (the indigo pass, 2026-09-16, as the app's theme) */
  --surface-hi: #27272c;   /* hover state of surface */
  --border:     #204e64;   /* the one border colour: the rubber mixed 0.7 toward Byte's outline (was the indigo #2a2a5a) */
  --border-hi:  #7EC8E3;   /* hovered border: the accent itself */
  --accent:     #7EC8E3;   /* the brand accent */
  --text:       #c8c8e8;   /* primary text */
  --text-hi:    #ffffff;   /* emphasized text */
  --dim:        #888aaa;   /* secondary text */
  --faint:      #606064;   /* tertiary, disabled */
  --primary:    #1c3d52;   /* primary action fill */
  --primary-hi: #254e66;   /* primary action hover */
  --key:        #07070d;   /* a key's face is the rubber; the line carries the state */
  --gold:       #FFC72C;   /* the lamp of a console in a yellow state */
  --red:        #FF6B6B;   /* the lamp of a console in a rare red state */

  --font: Consolas, "Cascadia Mono", "DejaVu Sans Mono", Menlo, monospace;
  --page: 1040px;
  --gutter: 16px;
  --chamfer: 10px;
  --pull: 1.2s;            /* the dolly through a console: the Mainframe zooming, the frame growing, the room approaching, together (0.7 s until 2026-09-16: too quick and jarring, Cali) */
  --open: 1.2s;            /* the same on a standalone room page (a direct visit) */
  --dolly: cubic-bezier(0.45, 0.05, 0.15, 1);   /* a camera move: it gathers speed gently and settles long */
  --fold: 0.6s;            /* a room folding into its console; doors.js waits this long */
  --cool: 0.35s;           /* ...and the console cooling on the Mainframe */
  --paper: polygon(
    var(--chamfer) 0, calc(100% - var(--chamfer)) 0, 100% var(--chamfer),
    100% calc(100% - var(--chamfer)), calc(100% - var(--chamfer)) 100%,
    var(--chamfer) 100%, 0 calc(100% - var(--chamfer)), 0 var(--chamfer));
}

* { box-sizing: border-box; }

html { background: var(--bg); }

body {
  margin: 0;
  min-height: 100vh;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font);
  font-size: 15px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}

img { display: block; max-width: 100%; height: auto; }

a { color: var(--accent); text-decoration: none; }
a:hover { color: var(--text-hi); }
a:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }

h1, h2, h3 { color: var(--text-hi); margin: 0; line-height: 1.15; }
p { margin: 0; }

.fine { color: var(--dim); font-size: 13px; }

/* ── Keys and doors: the hardware idiom, rounded and rubber ─────────────── */

.key, .door {
  display: inline-block;
  padding: 9px 18px;
  border-radius: 8px;
  background: var(--key);
  color: var(--text-hi);
  border: 1px solid var(--border);
  border-bottom-width: 3px;              /* the wall, so the key stands off the case */
  line-height: 1.3;
  white-space: nowrap;
}
.key:hover, .door:hover { background: var(--surface-hi); border-color: var(--border-hi); color: var(--text-hi); }
.key:active, .door:active { border-bottom-width: 1px; transform: translateY(2px); }

.key-primary { background: var(--primary); border-color: var(--primary-hi); }
.key-primary:hover { background: var(--primary-hi); border-color: #2f6180; }

.key-inert { color: var(--dim); cursor: default; }
.key-inert:hover { background: var(--key); border-color: var(--border); color: var(--dim); }
.key-inert:active { border-bottom-width: 3px; transform: none; }

.door {
  min-width: 9em;
  text-align: center;
  letter-spacing: 0.06em;
}
.door:hover { box-shadow: 0 0 18px rgba(126, 200, 227, 0.25); border-color: var(--accent); }

/* ── THE CORE ───────────────────────────────────────────────────────────── */

/* The Mainframe's background: the window body's dark navy across the whole room, and
   nothing else (Cali, 2026-09-16: the dark red that once gathered at the screen's edge
   is gone; the navy alone). On the body, not the canvas, so it reaches past the stage
   on a screen that is not 16:9. */
body.core {
  overflow: hidden;
  background: var(--bg);
}
body.core > .page {                       /* the Mainframe's own page, not a room's inside a window */
  min-height: 100vh;
  display: grid;
  place-items: center;
}

/* THE STAGE IS ONE FIXED PICTURE, 1600 by 900, scaled as a whole to fit the screen
   (core.js sets --s on resize to the smaller of the two ratios), so every monitor sees
   the same layout at a different size rather than a different layout. Everything in it
   is in stage pixels: the canvas draws at 1600 by 900, the consoles sit at fixed
   offsets, the type is set in the stage unit --u. A phone
   (the media query below) is the one exception: portrait needs its own layout. */
.stage {
  position: absolute;                    /* centred by hand: a grid centres an overflowing item at its start */
  left: 50%; top: 50%;
  width: 1600px;
  height: 900px;
  transform: translate(-50%, -50%) scale(var(--s, 1));
  transform-origin: center;
  --u: 13.5px;
}

#core {
  position: absolute;
  inset: 0;
  animation: reveal 1s ease-out both;
}

/* The four consoles are the doors. Each is centred on its coordinate, and the canvas
   reads that centre off the layout to start its conduit there. They are part of the
   drawing the conduits run into, as the routers and the cradle are: a schematic box,
   one line in the diagram's own colour, chamfered like the sheets, the face filled
   so the grid does not show through, no shadow. The line is the element's own
   background showing round an inset face (a border would be cut off at the
   chamfers). A lamp beside the name. Name and one word of state. */
.consoles { display: contents; }
.console {
  position: absolute;
  transform: translate(-50%, -50%);
  width: 13em;
  padding: 1em 1.3em 0.9em;
  background: rgba(42, 109, 138, 0.7);   /* the line: the routers' (core.js, DEEP at 0.7) */
  clip-path: var(--paper);
  color: var(--dim);
  font-size: max(12px, calc(var(--u) * 0.9));
  line-height: 1.4;
  letter-spacing: 0.1em;
}
.console::before {                       /* the face, inset by the line's width */
  content: "";
  position: absolute;
  inset: 1px;
  background: var(--bg);
  clip-path: var(--paper);
}
/* In one column per side, so the router between them (core.js) lines up. */
/* The two rows sit the same distance above and below the sphere's centre (55 %), so
   the router between them, and its feed, are level with the cradle's middle. */
.console:nth-of-type(1) { left: 210px; top: 34%; }
.console:nth-of-type(2) { left: calc(100% - 210px); top: 34%; }
.console:nth-of-type(3) { left: 210px; top: 76%; }
.console:nth-of-type(4) { left: calc(100% - 210px); top: 76%; }
.console { transition: background var(--cool) ease-out, color var(--cool) ease-out; }
.console h2::before { transition: background var(--cool) ease-out, box-shadow var(--cool) ease-out; }
/* hovered, the line goes blue whatever the state and stays: the preview sits inside
   it (Cali, 2026-09-16: the full blue line with the room inside, not the state's colour) */
.console:hover, .console:focus-visible { background: var(--accent); color: var(--text); }
.console:active { transform: translate(-50%, calc(-50% + 1px)); }
.console h2 {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 1.25em;
  letter-spacing: 0.2em;
  text-transform: uppercase;
}
.console h2::before {                    /* the lamp */
  content: "";
  width: 0.55em; height: 0.55em;
  border-radius: 50%;
  background: var(--accent);
  box-shadow: 0 0 8px var(--accent);
}
.console:hover h2::before, .console:focus-visible h2::before { background: var(--text-hi); box-shadow: 0 0 12px var(--text-hi); }
.console.check h2::before { background: var(--text-hi); box-shadow: 0 0 8px var(--text-hi); }   /* a check, in white */
.console.check .stat { color: var(--text-hi); }
.console.off h2::before { background: var(--gold); box-shadow: 0 0 8px var(--gold); }
.console.off .stat { color: var(--gold); }
.console.red h2::before { background: var(--red); box-shadow: 0 0 10px var(--red); }
.console.red { background: rgba(255, 107, 107, 0.7); }
.console.red .stat { color: var(--red); }
.console .stat { display: block; margin-top: 4px; padding-left: 18px; }

.name {
  position: absolute;
  left: 50%; top: 8%;
  transform: translateX(-50%);
  font-size: max(28px, calc(var(--u) * 2.9));   /* the name leads; the motto sits under it, smaller */
  -webkit-text-stroke: 0.035em currentColor;    /* thicker than Consolas's one bold (Cali, 2026-09-16) */
  paint-order: stroke fill;
  letter-spacing: 0.32em;
  padding-left: 0.32em;                  /* the tracking's trailing space, balanced */
  white-space: nowrap;
  display: flex;
  align-items: center;
  gap: 0.45em;
}
.name .mark {                            /* the mark, beside the C */
  width: 1.3em; height: 1.3em;           /* a vector (assets/mark.svg), so it is crisp at any size */
}

/* The corner, top right of the stage: the download key (inert until there is a zip)
   and the operator login, the words alone, no key (Cali, 2026-09-16: the download
   moved here from Storage's head strip). */
.corner {
  position: absolute;
  right: 40px; top: 40px;
  display: flex;
  align-items: center;
  gap: 26px;
}
.login {
  padding: 4px 6px;
  color: var(--dim);
  font-size: max(11px, calc(var(--u) * 0.8));
  letter-spacing: 0.1em;
  text-transform: uppercase;
  opacity: 0.6;
  transition: opacity var(--cool) ease-out, color var(--cool) ease-out;
}
.login:hover, .login:focus-visible, .login.hot { opacity: 1; color: var(--text-hi); }

.motto {
  position: absolute;
  left: 50%; top: 17.5%;                 /* the cradle's top vertex sits between the name and this */
  transform: translateX(-50%);
  width: max-content;
  max-width: 90%;
  text-align: center;
  color: var(--text);
  font-size: max(15px, calc(var(--u) * 1.3));
}

/* The opening: the whole picture, sphere, consoles, name and motto, fades in together
   over the first second. */
.reveal, .console { animation: reveal 1s ease-out both; }

@keyframes reveal { from { opacity: 0; } to { opacity: 1; } }

/* Back from a room: everything is already there. */
.returning .reveal, .returning .console, .returning #core { animation: none; }

/* A phone holds the stage upright: the sphere in the middle, two consoles above it and
   two below, the name and motto at the top. */
@media (max-width: 760px) {
  .stage { position: relative; left: 0; top: 0; width: 100vw; height: 100vh; transform: none; --u: min(1vw, 1.5vh); }
  .name  { top: 5%; font-size: 24px; }
  .motto { top: 10.5%; font-size: 14px; }
  .corner { right: 12px; top: 12px; flex-direction: column; align-items: flex-end; gap: 6px; }   /* stacked: side by side they overrun the name */
  .login { font-size: 10px; }
  .download-key { font-size: 11px; padding: 6px 10px; }
  .console { font-size: 11px; padding: 0.8em 1.1em 0.7em; }
  .console:nth-of-type(1) { left: 22%; top: 25%; }
  .console:nth-of-type(2) { left: 78%; top: 25%; }
  .console:nth-of-type(3) { left: 22%; top: 79%; }
  .console:nth-of-type(4) { left: 78%; top: 79%; }
}

/* ── A ROOM ─────────────────────────────────────────────────────────────── */

body.room .page, .roomview .page, .preview .page {
  min-height: 100vh;
  position: relative;
}
body.room { overflow: hidden; }          /* the stage's untransformed box would scroll the page */

/* THE ROOM'S STAGE (2026-09-16, the rooms on the fixed stage): a room is one fixed
   picture, 1600 by 900, inside its page, scaled to fit whatever shows it (the window,
   a console's window, a preview; rooms.js fitStage sets --s), so every screen sees the
   same room at a different size, as the Mainframe. On a phone the picture is a
   portrait one, 480 by 1040, the device the width of it. The page itself stays the
   viewport box that the fold and the arrival move. */
.roomstage {
  position: absolute;
  left: 50%; top: 50%;
  width: 1600px; height: 900px;
  transform: translate(-50%, -50%) scale(var(--s, 1));
  transform-origin: center;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
@media (max-width: 760px) { .roomstage { width: 480px; height: 1040px; } }


/* THE PREVIEW (doors.js): a hovered console shows its room inside its own face, the
   whole room page at 1600 by 900 scaled to the console's width, its scene running,
   with the console's name and state kept readable over it. */
.console .preview, .door-back .preview {
  position: absolute;
  inset: 1px;                            /* inside the line, which stays */
  z-index: 0;
  overflow: hidden;
  border-radius: 0;
  background: var(--bg);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.25s ease-out;
}
.console .preview.on, .door-back .preview.on { opacity: 1; }
.console .preview { clip-path: var(--paper); }   /* the face's chamfer, so the line is one width all round */
.console .preview .page { position: absolute; left: 0; top: 0; width: 1600px; height: 900px; min-height: 0; transform-origin: 0 0; }
.console .preview::after, .door-back .preview::after {
  content: "";
  position: absolute; inset: 0;
  background: linear-gradient(180deg, rgba(7, 7, 13, 0.2), rgba(7, 7, 13, 0.8));
}
.console h2, .console .stat { position: relative; z-index: 1; }

/* ...and the Mainframe key in a room's window previews the Mainframe the same way: a
   live copy of its canvas, scaled to cover the key, under the key's text. */
.door-back { position: relative; overflow: hidden; }
.door-back .preview { border-radius: 6px; }
.door-back .preview canvas { position: absolute; left: 0; top: 0; }
.door-back .preview::after { background: linear-gradient(180deg, rgba(7, 7, 13, 0.25), rgba(7, 7, 13, 0.6)); }
.door-back > span { position: relative; z-index: 1; }

/* The room's scenery (rooms.js) is a canvas across the whole page, under the head
   strip and the readouts. It lives inside .page so a window's scale carries it. */
.scene { position: absolute; inset: 0; z-index: 0; }
.roomhead, .roombody { position: relative; z-index: 2; }   /* the words and their boxes over everything on the canvas; the crew passes behind them */

.roomhead {
  max-width: var(--page);
  width: 100%;
  margin: 0 auto;
  padding: 18px var(--gutter);
  display: flex;
  align-items: center;
  gap: 22px;
  border-bottom: 1px solid var(--border);
}
.roomhead h1 {
  font-size: 18px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}
.roomhead .crumb { color: var(--faint); }
.roomhead .crumb::after { content: "  /  "; white-space: pre; }
.door-back { min-width: 0; }
/* The status bar: the console's own word and lamp, so the inside says what the
   outside says, on the same clock (rooms.js reads the board each second). */
.status {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: 10px;
  color: var(--dim);
  font-size: 13px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  white-space: nowrap;
  transition: color var(--cool) ease-out;
}
.status::before {
  content: "";
  width: 8px; height: 8px;
  border-radius: 50%;
  background: var(--accent);
  box-shadow: 0 0 8px var(--accent);
  transition: background var(--cool) ease-out, box-shadow var(--cool) ease-out;
}
.status.check { color: var(--text-hi); }
.status.check::before { background: var(--text-hi); box-shadow: 0 0 8px var(--text-hi); }
.status.off { color: var(--gold); }
.status.off::before { background: var(--gold); box-shadow: 0 0 8px var(--gold); }
.status.red { color: var(--red); }
.status.red::before { background: var(--red); box-shadow: 0 0 10px var(--red); }
.door-back > span::before { content: "\2190\00a0"; }

.roombody {
  max-width: var(--page);
  width: 100%;
  margin: 0 auto;
  padding: 40px var(--gutter) 56px;
}

/* The head strip stays at the top; the readouts sit in the middle of what is left, by auto margins, so a page taller than the screen still flows. */
body.room .roombody, .roomview .roombody, .preview .roombody { flex: 0 0 auto; margin-top: auto; margin-bottom: auto; }

.roomsub { font-size: 16px; margin: 36px 0 16px; }
.lede { max-width: 62ch; margin-bottom: 24px; }

.about {
  display: flex;
  align-items: flex-start;
  gap: 24px;
}
.about img { width: 96px; flex: none; }
.about h2 { font-size: 22px; }
.about p:last-child { max-width: 62ch; margin-top: 12px; }

/* ── Sheets: printed paper, chamfered ───────────────────────────────────── */

.sheet {
  margin: 0;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 1px;                              /* the rule between cells is the case showing through */
  background: var(--border);
  clip-path: var(--paper);
}
.sheet > div { background: var(--surface); padding: 18px 20px; }
.sheet dt { color: var(--accent); font-weight: bold; margin-bottom: 4px; }
.sheet dd.check, .sheet dd .check { color: var(--text-hi); } /* a readout under the room's check, yellow or red state (status.js); or one figure of a shared line */
.sheet dd.off, .sheet dd .off { color: var(--gold); }
.sheet dd.red, .sheet dd .red { color: var(--red); }
.sheet dd { margin: 0; }

.sheet.compact { grid-template-columns: 1fr; }
.sheet.compact > div { display: grid; grid-template-columns: 18ch 1fr; gap: 12px; padding: 12px 18px; }
.sheet.compact dt { margin: 0; }

/* THE SCREEN (Cali, 2026-09-16): a room's readouts are on the screen of that room's
   own device, drawn round the box on the canvas (rooms.js reads the box's rectangle).
   The sheet is the screen's glass, one pane (Cali, 2026-09-16: the words on a screen,
   not boxes in the middle of a case): the room's black lit a little at the centre, a
   scanline every 3 px, one diagonal glare, the words glowing on the phosphor with a
   faint rule between the rows. Rounded, not chamfered: a screen, not paper. Narrower
   than the page so the device has room round it. */
.sheet.screen {
  position: relative;
  width: 520px;
  max-width: 100%;
  gap: 0;
  clip-path: none;
  border-radius: 4px;
  overflow: hidden;
  background: radial-gradient(ellipse 70% 80% at 50% 45%, #0e1a22 0, #080d13 65%, #05080c 100%);   /* opaque, so the glass still hides what stands behind it */
  box-shadow: inset 0 0 18px rgba(0, 0, 0, 0.8), inset 0 0 2px rgba(126, 200, 227, 0.25);
}
.sheet.screen > div { background: transparent; }
.sheet.screen > div + div { border-top: 1px solid rgba(126, 200, 227, 0.09); }   /* the rule between the rows, light on the pane */
.sheet.screen dt { text-shadow: 0 0 6px rgba(126, 200, 227, 0.45); }
.sheet.screen dd { text-shadow: 0 0 6px rgba(232, 232, 240, 0.35); }
.sheet.screen dd.off { text-shadow: 0 0 7px rgba(255, 199, 44, 0.5); }
.sheet.screen dd.red { text-shadow: 0 0 7px rgba(255, 107, 107, 0.5); }
.sheet.screen::after {                        /* the scanlines, and the glare across the pane */
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background:
    linear-gradient(115deg, transparent 38%, rgba(126, 200, 227, 0.045) 46%, rgba(126, 200, 227, 0.07) 50%, rgba(126, 200, 227, 0.045) 54%, transparent 62%),
    repeating-linear-gradient(180deg, rgba(0, 0, 0, 0.4) 0 1px, transparent 1px 3px);
}
.sheet.screen { margin: 0 auto; }                              /* in the middle, where the box was (Cali, 2026-09-16) */
.roombody[data-room="units"] .sheet.screen   { width: 420px; margin-bottom: 44px; }   /* the handset's keys under it */
.roombody[data-room="storage"] .sheet.screen { width: 440px; margin-bottom: 54px; }   /* the enclosure's bays under it */
.roombody[data-room="sound"] .sheet.screen   { width: 440px; }                        /* the receiver's meters and knob beside it */

/* ── The pose row (Records) ─────────────────────────────────────────────── */

.poses {
  list-style: none;
  margin: 40px 0 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 16px;
}
.poses li {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-end;
  gap: 8px;
  padding: 16px 12px 14px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 12px;                    /* a screen: hardware */
}
.poses img { width: 150px; }
.poses span { color: var(--dim); }

/* ── The bays (Assembly) ────────────────────────────────────────────────── */

.bays {
  list-style: none;
  margin: 0; padding: 0;
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  grid-auto-rows: minmax(150px, auto);
  gap: 16px;
}
.bay {
  position: relative;
  padding: 36px 18px 18px;
  background: var(--surface);
  clip-path: var(--paper);
}
.bayno {
  position: absolute;
  left: 14px; top: 10px;
  font-size: 11px;
  letter-spacing: 0.14em;
  color: var(--faint);
}

.bay.lit {
  grid-column: 1 / span 2;
  display: grid;
  grid-template-columns: 150px 1fr;
  gap: 20px;
  align-items: start;
  background: linear-gradient(180deg, var(--surface-hi), var(--surface));
}
.bay.lit .bayno { color: var(--accent); }
.bay.lit img { width: 150px; align-self: center; }
.bay.lit h2 { font-size: 20px; }

.bay.dark {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  gap: 4px;
  color: var(--dim);
}
.bay.dark h2 { font-size: 12px; color: var(--faint); letter-spacing: 0.1em; margin-top: 8px; }
.bay.dark:only-of-type, .bays .bay.dark { min-height: 180px; }
.bay.dark .bio { margin-top: 6px; font-size: 12px; color: var(--faint); }

.spec {
  width: 100%;
  margin-top: 10px;
  border-collapse: collapse;
  font-size: 14px;
}
.spec th, .spec td { text-align: left; vertical-align: top; padding: 5px 0; border-top: 1px solid var(--border); }
.spec th { color: var(--dim); font-weight: normal; width: 15ch; padding-right: 12px; }
.spec tr:last-child th, .spec tr:last-child td { border-bottom: 1px solid var(--border); }

.bio { margin-top: 14px; font-style: italic; }

.lock {
  position: relative;
  width: 44px; height: 44px;
  flex: none;
  border: 1px solid var(--border);
}
.lock::before {                          /* the shackle */
  content: "";
  position: absolute;
  left: 14px; top: 8px;
  width: 12px; height: 13px;
  border: 3px solid var(--faint);
  border-bottom: 0;
  border-radius: 9px 9px 0 0;
}
.lock::after {                           /* the body */
  content: "";
  position: absolute;
  left: 11px; top: 21px;
  width: 22px; height: 15px;
  background: var(--faint);
  border-radius: 3px;
}

/* ── Dispatch ───────────────────────────────────────────────────────────── */

.download-key { white-space: nowrap; padding: 6px 13px; }   /* a smaller key than the rest, the font as it is (Cali, 2026-09-16) */
/* Hovered, the inert key says why it does nothing: its words change to NOT YET AVAILABLE
   (Cali, 2026-09-16: in the box, not a tooltip). Both texts share one cell, so the key
   keeps the wider one's width and nothing shifts. */
.download-key { display: inline-grid; text-align: center; }
.download-key > span { grid-area: 1 / 1; transition: opacity var(--cool) ease-out; }
.download-key > .else { opacity: 0; }
.download-key:hover > span { opacity: 0; }
.download-key:hover > .else { opacity: 1; }

/* The Mainframe key and the download key are schematic boxes like the consoles: one
   line in the drawing's colour, chamfered, the face filled, no wall, no shadow. */
.door-back, .download-key {
  position: relative;
  isolation: isolate;
  background: rgba(42, 109, 138, 0.7);
  border: 0;
  border-radius: 0;
  box-shadow: none;
  clip-path: var(--paper);
  transition: background var(--cool) ease-out, color var(--cool) ease-out;
}
.door-back::before, .download-key::before {
  content: "";
  position: absolute;
  inset: 1px;
  z-index: -1;
  background: var(--bg);
  clip-path: var(--paper);
}
.door-back:hover, .door-back:focus-visible { background: var(--accent); box-shadow: none; border: 0; }
.door-back:active { transform: translateY(1px); border: 0; }
.door-back.hot { background: var(--text-hi); box-shadow: none; border: 0; }
.download-key, .download-key:hover, .download-key:active { background: rgba(42, 109, 138, 0.45); color: var(--dim); border: 0; transform: none; }
.door-back .preview { border-radius: 0; z-index: 0; }

/* ── The operator login ─────────────────────────────────────────────────── */

.access { display: grid; gap: 14px; justify-items: start; margin-top: 28px; max-width: 420px; }
.access label { display: grid; gap: 6px; width: 100%; }
.access label > span { color: var(--accent); font-weight: bold; font-size: 13px; letter-spacing: 0.06em; }
.access input {
  width: 100%;
  padding: 9px 12px;
  border-radius: 6px;
  background: var(--surface);
  color: var(--text-hi);
  border: 1px solid var(--border);
  font: inherit;
}
.access input:focus { outline: none; border-color: var(--accent); }
.access-aside { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }
.access-word { min-height: 1.4em; letter-spacing: 0.08em; font-size: 13px; }
.access-word.check { color: var(--text-hi); }
.access-word.red { color: var(--red); }
.access button { cursor: pointer; font: inherit; }

/* ── Narrow screens ─────────────────────────────────────────────────────── */

@media (max-width: 820px) {
  .poses { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .bays { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 560px) {
  .roomhead { gap: 14px; padding: 14px var(--gutter); flex-wrap: wrap; }   /* the download key drops to its own line, still at the right */
  .roomhead .crumb { display: none; }    /* the key and the room's name are the whole strip */
  .sheet { grid-template-columns: 1fr; }
  .sheet.compact > div { grid-template-columns: 1fr; gap: 2px; }
  .poses img { width: 110px; }
  .bays { grid-template-columns: 1fr; }
  .bay.lit { grid-column: 1; grid-row: auto; grid-template-columns: 1fr; justify-items: center; }
  .spec th { width: 12ch; }
}

@media (prefers-reduced-motion: reduce) {
  .reveal, .console, #core { animation: none; }
  .key:active, .door:active { transform: none; }
  body, .page, .pull, .window, .roomview, .console, .console h2::before { animation: none !important; transition: none !important; }
  .window { display: none !important; }
}

/* ── The windows ────────────────────────────────────────────────────────── */

/* Leaving: THE DOLLY. The Mainframe zooms about the
   clicked console by whatever takes the console's rectangle to the screen (doors.js
   sets the origin, --zoom and the slide of the console's centre to the screen's
   inline) and goes to black behind it; the console stays lit above the dim. A
   transition both ways: out with the frame growing, back with it shrinking. */
.page { position: relative; }
body.core > .page { transition: transform var(--pull) var(--dolly); }
.pull {
  position: absolute;
  inset: 0;
  z-index: 50;
  background: var(--bg);
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--pull) var(--dolly);
}
.pull.on { opacity: 1; }
.console.hot, .door.hot {
  z-index: 60;
  border-color: var(--accent);
  box-shadow: 0 0 26px rgba(126, 200, 227, 0.45);
}
.console.hot { background: var(--text-hi); box-shadow: none; }
.door.hot { position: relative; }
.login.hot { z-index: 60; }                 /* already absolute; a relative here would pull it out of its corner */
.console.hot h2::before { background: var(--text-hi); box-shadow: 0 0 12px var(--text-hi); }
.leaving body > .page { transform: translate(var(--tx, 0px), var(--ty, 0px)) scale(var(--zoom, 1.25)); }
/* through the move, the page and the room are each one composited layer, so the
   browser scales a picture rather than re-rasterising the page every frame */
.leaving body > .page, .roomview .page, .arriving .page, .entering .page, .folding .page { will-change: transform; backface-visibility: hidden; }

/* THE WINDOW ON THE MAINFRAME (doors.js): a room, fetched, shown inside a frame that sits
   on the console's rectangle, the whole room scaled to fit it (the room seen from afar,
   as the hover preview shows it); then the frame opens to the screen and the room
   grows to full size in the same curve as the Mainframe zooms in behind, one dolly
   through the console. Closing runs the same in reverse, the Mainframe already there
   and returning from its zoom around the shrinking frame. Transitions on the frame's
   edges and the room's scale. --s0 is the room's scale at the console (doors.js).
   The frame is the console's own box, chamfered with its one pixel line, the whole
   way (Cali, 2026-09-16: a square frame was still a square): its chamfer grows with
   the zoom, as the console's would, and the frame opens PAST the screen by that
   much, so the cut corners and the line end up just off the edges and never square
   off. --c is the chamfer, --zoom the dolly's (doors.js), the same the Mainframe
   takes. The polygons are the paper and ring shapes, written here in --c because a
   custom property inside another is fixed where the outer one is declared. */
.roomview {
  --c: var(--chamfer);
  --l: 1px;                              /* the line's width: the console's one pixel, times the zoom as the frame grows */
  position: fixed;
  z-index: 90;
  overflow: hidden;
  top: var(--wy); left: var(--wx);
  right: calc(100vw - var(--wx) - var(--ww));
  bottom: calc(100vh - var(--wy) - var(--wh));
  background: var(--bg);
  clip-path: polygon(
    var(--c) 0, calc(100% - var(--c)) 0, 100% var(--c),
    100% calc(100% - var(--c)), calc(100% - var(--c)) 100%,
    var(--c) 100%, 0 calc(100% - var(--c)), 0 var(--c));
}
.roomview::after {                       /* ...and its line, over the room */
  content: "";
  position: absolute;
  inset: 0;
  z-index: 2;
  pointer-events: none;
  background: var(--accent);
  /* the outline around its own inset, even-odd: the outer loop closed back to its first
     point, then the inner loop closed the same way, so the seam between them is a
     doubled segment and not a diagonal that cuts a corner off */
  clip-path: polygon(evenodd,
    var(--c) 0, calc(100% - var(--c)) 0, 100% var(--c),
    100% calc(100% - var(--c)), calc(100% - var(--c)) 100%,
    var(--c) 100%, 0 calc(100% - var(--c)), 0 var(--c), var(--c) 0,
    calc(var(--c) + var(--l)) var(--l), calc(100% - var(--c) - var(--l)) var(--l),
    calc(100% - var(--l)) calc(var(--c) + var(--l)), calc(100% - var(--l)) calc(100% - var(--c) - var(--l)),
    calc(100% - var(--c) - var(--l)) calc(100% - var(--l)), calc(var(--c) + var(--l)) calc(100% - var(--l)),
    var(--l) calc(100% - var(--c) - var(--l)), var(--l) calc(var(--c) + var(--l)), calc(var(--c) + var(--l)) var(--l));
}
.roomview.off::after { background: var(--gold); }   /* a yellow or red console's window is framed in its colour (Cali, 2026-09-16) */
.roomview.red::after { background: var(--red); }
.roomview .page {
  position: absolute;
  width: 100vw; height: 100vh;
  left: 0; top: 0;
  transform-origin: 0 0;
  transform: scale(var(--s0, 0.25));
}
.roomview.open {
  --c: calc(var(--chamfer) * var(--zoom, 4));
  --l: calc(1px * var(--zoom, 4));
  inset: calc(-1 * var(--c));            /* past the screen by the chamfer: the corners and the line go just off the edges, the room at 0 */
  transition: inset var(--pull) var(--dolly), clip-path var(--pull) var(--dolly);
}
.roomview.open::after { transition: clip-path var(--pull) var(--dolly); }   /* the line widens with the frame */
.roomview.closing::after { transition: clip-path var(--pull) var(--dolly); }
.roomview.open .page { left: var(--c); top: var(--c); transform: none; transition: transform var(--pull) var(--dolly), left var(--pull) var(--dolly), top var(--pull) var(--dolly); }
.roomview.closing { transition: inset var(--pull) var(--dolly), clip-path var(--pull) var(--dolly); }
.roomview.closing .page { transition: transform var(--pull) var(--dolly), left var(--pull) var(--dolly), top var(--pull) var(--dolly); }

/* Arriving: the body is clipped to the saved rectangle (the custom properties are set
   before first paint by the inline head script) and the page is scaled into it from
   its top corner, the room seen from afar; the frame sits on the rectangle. doors.js
   swaps arriving for entering on the same frame, and clip, scale and frame all move
   under a transition, the same dolly. Everything outside the clip is the html
   background, which is the black. */
.arriving body, .entering body {
  clip-path: inset(var(--wy) calc(100vw - var(--wx) - var(--ww)) calc(100vh - var(--wy) - var(--wh)) var(--wx));
}
.arriving .page { transform-origin: 0 0; transform: translate(var(--wx), var(--wy)) scale(var(--s0, 0.25)); }
.entering body  { clip-path: inset(0 0 0 0); transition: clip-path var(--open) var(--dolly); }
.entering .page { transform-origin: 0 0; transform: none; transition: transform var(--open) var(--dolly); }

.window {
  display: none;
  position: fixed;
  z-index: 100;
  pointer-events: none;
  top: var(--wy); left: var(--wx);
  right: calc(100vw - var(--wx) - var(--ww));
  bottom: calc(100vh - var(--wy) - var(--wh));
  border: 2px solid var(--accent);
  border-radius: 10px;
  box-shadow: 0 0 28px rgba(126, 200, 227, 0.5), inset 0 0 18px rgba(126, 200, 227, 0.25);
}
.arriving .window, .entering .window { display: block; }
.entering .window {
  inset: -10px;                          /* off the edges, then the glow goes too */
  opacity: 0;
  transition: inset var(--open) ease-out, opacity 0.15s ease-out calc(var(--open) - 0.1s);
}

/* Folding back: doors.js first parks the frame at the edges with the clip open
   (framed), settles that, then sets the console's rectangle and folds; clip, frame
   and scale all move under a transition, ease-in, the room drawing back. */
.framed body  { clip-path: inset(0 0 0 0); }
.framed .window { display: block; inset: -10px; opacity: 1; }
.folding body {
  clip-path: inset(var(--wy) calc(100vw - var(--wx) - var(--ww)) calc(100vh - var(--wy) - var(--wh)) var(--wx));
  transition: clip-path var(--fold) ease-in;
}
.folding .page { transform-origin: 0 0; transform: translate(var(--wx), var(--wy)) scale(var(--s0, 0.25)); transition: transform var(--fold) ease-in; }
.folding .window {
  top: var(--wy); left: var(--wx);
  right: calc(100vw - var(--wx) - var(--ww));
  bottom: calc(100vh - var(--wy) - var(--wh));
  transition: inset var(--fold) ease-in;
}

/* Arriving back: the Mainframe is full on the first frame with the frame on the
   console (doors.js has lit it); the frame cools away and the console with it. */
.arriving-back .window, .entered-back .window { display: block; }
.entered-back .window { opacity: 0; transition: opacity var(--cool) ease-out; }
