/* ============================================================
   Academy Model Station — working signalling panel
   Page chrome, desk furniture and the board's SVG classes.
   Fonts are loaded by the page itself.
   ============================================================ */

:root{
  --void:#05090d; --case:#0d151d; --case-edge:#1d2c39; --plate:#132029;
  --rail:#d7e9f7; --rail-dim:#6d8598;
  --ink:#e6f0f8; --ink-2:#93a9ba; --ink-3:#5f7385;
  --red:#ff4438; --green:#22c55e; --amber:#ffb020; --brass:#c9a227; --cyan:#7fd7ff;
}
*{box-sizing:border-box;}
html,body{margin:0;padding:0;}
body{
  background:radial-gradient(120% 80% at 50% -10%, #10202b 0%, var(--void) 62%), var(--void);
  color:var(--ink);
  font-family:"IBM Plex Sans", system-ui, -apple-system, Segoe UI, sans-serif;
  font-size:15px; line-height:1.55;
}
/* the top bar spans the glass the way it does on the trainee and
   instructor pages, so the page's own margin belongs to the wrap
   under it rather than to the body */
.wrap{width:100%;max-width:none;margin:0;padding:24px 24px 80px;box-sizing:border-box;}

/* ---------------------------------------------------------------
   Top bar

   The same bar the trainee and instructor pages carry, and for the
   same reason: whichever screen a reader is on, the way back is at
   the same corner, the name of the place is beside it, who is at the
   desk reads next, and the page's own controls end the row. The
   boards used to state their name in a masthead three times this
   height; a board is not a more important page than a console, so it
   no longer opens like one.

   chrome.js writes the contents from the session. The page supplies
   only what it is called, in data-name and data-zone.
   --------------------------------------------------------------- */
.topbar{position:sticky;top:0;z-index:30;display:flex;flex-wrap:wrap;align-items:center;
  gap:10px 20px;padding:10px 22px;background:rgba(9,15,21,.95);
  border-bottom:1px solid var(--case-edge);backdrop-filter:blur(6px);}

/* the way back reads first, so it sits ahead of the mark rather than
   at the far end of the bar with the page's own controls */
.back{display:inline-flex;align-items:center;gap:8px;order:-1;
  font-family:"Barlow Condensed",sans-serif;font-size:13px;font-weight:600;
  letter-spacing:.14em;text-transform:uppercase;color:var(--ink-2);text-decoration:none;
  border:1px solid var(--case-edge);border-radius:2px;padding:7px 13px;}
.back:hover{color:var(--ink);background:#1a2b38;}
.back:focus-visible{outline:2px solid var(--cyan);outline-offset:2px;}
/* free practice: nobody is signed in, so there is nowhere to go back to,
   and the bar says so rather than offering a way back to nowhere */
.back.none{border-style:dashed;color:var(--ink-3);cursor:default;}
.back-arrow{font-family:"IBM Plex Mono",monospace;font-size:14px;color:var(--brass);}

.topbar-mark{display:flex;flex-direction:column;text-decoration:none;line-height:1.1;min-width:0;}
.topbar-zone{font-family:"IBM Plex Mono",monospace;font-size:9.5px;letter-spacing:.26em;
  text-transform:uppercase;color:var(--brass);}
.topbar-name{font-family:"Barlow Condensed",sans-serif;font-size:19px;font-weight:600;
  letter-spacing:.14em;text-transform:uppercase;color:var(--ink);}
a.topbar-mark:hover .topbar-name{color:#fff;}

.topbar-who{display:flex;flex-wrap:wrap;align-items:center;gap:6px 14px;}
.who-name{font-family:"Barlow Condensed",sans-serif;font-size:15px;font-weight:600;
  letter-spacing:.1em;text-transform:uppercase;color:var(--ink);}
.who-fact{font-family:"IBM Plex Mono",monospace;font-size:11px;color:var(--ink-2);}
.who-fact b{color:var(--rail);font-weight:500;}

.topbar-acts{margin-left:auto;display:flex;flex-wrap:wrap;align-items:center;gap:10px;}
/* free practice offers a way in where a session would offer a way out, and
   that belongs at the controls end of the bar, not ahead of the mark */
.topbar-acts .back{order:0;}
.ghost{background:transparent;}
.ghost:hover{background:#1a2b38;}

/* what the masthead's strapline said, in the register of the bar: worth
   reading once, not at the size the masthead read it at. It is the one
   part of the bar that gives way — it shortens, and then goes, rather
   than pushing the controls onto a second row */
.topbar-strap{flex:1 1 0;min-width:0;overflow:hidden;text-overflow:ellipsis;
  white-space:nowrap;font-family:"IBM Plex Mono",monospace;font-size:11px;
  letter-spacing:.04em;color:var(--ink-3);}

/* and who is at the desk outranks what the page is for: with a session in
   the bar there is not room for both, and a strapline cut to two words is
   worth less than the name of the reader it was crowding */
.topbar:has(.topbar-who) .topbar-strap{display:none;}
@media (max-width:1000px){.topbar-strap{display:none;}}
@media (max-width:640px){
  .topbar{padding:9px 14px;gap:8px 14px;}
  .topbar-who{width:100%;order:3;}
}

/* The sign-in page is the one screen that still opens with a hero, and
   these three are its. Every other page names itself in the bar above. */
.zone{font-family:"Barlow Condensed",sans-serif;font-size:14px;letter-spacing:.34em;
  text-transform:uppercase;color:var(--brass);margin:0 0 2px;}
h1{font-family:"Barlow Condensed",sans-serif;font-weight:600;font-size:clamp(32px,5vw,54px);
  letter-spacing:.06em;text-transform:uppercase;margin:0;line-height:1;}
h1 span{color:var(--rail-dim);}
.strap{font-family:"IBM Plex Mono",monospace;font-size:12px;color:var(--ink-2);
  letter-spacing:.06em;margin:6px 0 0;}


/* ---- the panel's own controls. They belong to the board, not to the
   page, so they sit with the board and go full screen with it ---- */
.board-bar{display:flex;flex-wrap:wrap;align-items:center;justify-content:flex-end;
  gap:8px 10px;margin-bottom:10px;}
.trainbox{display:flex;flex-wrap:wrap;align-items:center;gap:6px 14px;
  border:1px solid var(--case-edge);border-radius:2px;padding:7px 12px;background:var(--plate);}
.trainsw{display:flex;align-items:center;gap:7px;cursor:pointer;
  font-family:"Barlow Condensed",sans-serif;font-size:14px;font-weight:600;
  letter-spacing:.12em;text-transform:uppercase;color:var(--ink-2);white-space:nowrap;}
.trainsw:hover{color:var(--ink);}
.trainsw input{width:14px;height:14px;margin:0;accent-color:var(--cyan);cursor:pointer;}
.trainsw input:checked + span{color:var(--ink);}
.trainsw input:focus-visible{outline:2px solid var(--cyan);outline-offset:2px;}

/* the two books sit at the other end of the bar from the controls: they
   are read, not worked, and a reader should not have to hunt among the
   things that move trains to find them */
.docbox{display:flex;flex-wrap:wrap;gap:8px;margin-right:auto;}

/* ---- the books, behind one control ----
   The menu hangs off the burger rather than off the bar, so it stays
   under it however the bar wraps, and it rides above the board — which
   is why the wrapper, not the bar, is what it is positioned against. */
.docmenu{position:relative;}
.burger{display:inline-flex;align-items:center;gap:9px;}
.burger svg{width:17px;height:17px;flex:none;fill:none;stroke:currentColor;
  stroke-width:2;stroke-linecap:round;}
.burger[aria-expanded="true"]{background:#22384a;border-color:#3a5a70;}

.docmenu-list{position:absolute;top:calc(100% + 6px);left:0;z-index:40;
  display:flex;flex-direction:column;min-width:230px;padding:5px;
  background:var(--case);border:1px solid var(--case-edge);border-radius:3px;
  box-shadow:0 18px 44px -18px #000;}
/* the items read as a list rather than as five more buttons in the bar:
   the box around each one is what the menu already draws */
.docmenu-list button{text-align:left;background:none;border:0;border-radius:2px;
  padding:9px 12px;color:var(--ink-2);letter-spacing:.1em;}
.docmenu-list button:hover{background:#1a2b38;color:var(--ink);}

/* a station with no written rules hides its SWR item, and an author
   display rule would otherwise outrank the browser's [hidden] */
.board-bar [hidden]{display:none;}

/* ---- the stage: the board, and the log rail beside it ----
   The log reads while the board is worked, so it stands to the right of
   the board rather than under it. Folded, the rail gives its column back
   to the board and keeps only its own name and the way to open it. */
/* the rail stands as tall as the board it reports on, and the list
   inside it takes whatever height that leaves */
.stage{display:grid;grid-template-columns:minmax(0,1fr) minmax(300px,360px);
  gap:16px;align-items:stretch;}
.stage.log-shut{grid-template-columns:minmax(0,1fr) auto;}

/* .deskbox is written further down, so the rail has to out-rank it on
   its own padding */
.logpane.deskbox{display:flex;flex-direction:column;min-width:0;padding:10px 12px 12px;}
/* the heading is the control: one thing to read, one thing to press */
.logtoggle{display:flex;align-items:center;gap:10px;width:100%;
  background:none;border:0;border-radius:2px;padding:4px 2px;margin:0 0 10px;
  font-family:"Barlow Condensed",sans-serif;font-size:15px;font-weight:600;
  letter-spacing:.18em;text-transform:uppercase;color:var(--ink-2);cursor:pointer;}
.logtoggle:hover{background:none;color:var(--ink);}
/* logical, because the shut rail reads top-to-bottom: end is the right
   in one and the bottom in the other, and the chevron wants both */
.logtoggle-name{margin-inline-end:auto;}
.logchev{width:16px;height:16px;flex:none;fill:none;stroke:currentColor;stroke-width:2;
  stroke-linecap:round;stroke-linejoin:round;transition:transform .15s ease;}
.logbody{flex:1;min-height:0;position:relative;}

/* shut: the rail turns on its side, so the board has the width and the
   log still says what it is. The flow turns with it — a row in
   vertical-rl stacks top to bottom — so the direction stays as it is. */
.stage.log-shut .logpane.deskbox{padding:12px 8px;}
/* shut, the name and the way back to the log are one short mark at the
   top of the rail — nothing is being pushed apart to fill a column */
.stage.log-shut .logtoggle{width:auto;margin:0;writing-mode:vertical-rl;}
.stage.log-shut .logtoggle-name{margin-inline-end:0;}
.stage.log-shut .logchev{transform:rotate(180deg);}
.stage.log-shut .logbody{display:none;}

/* A grid row is sized to its items' content, so a log left in the flow
   makes the rail taller as it fills and takes the board up with it: the
   rail stops being a scroller and the page just grows instead. Beside
   the board the list is therefore taken out of the flow — it then sizes
   nothing, the row is the board's height alone, and the list scrolls
   inside whatever that leaves. Stacked under the board, and in the
   editor's preview, there is no board height to fill, so it stays in the
   flow under the cap it carries below. */
@media (min-width:1101px){
  body:not(.bare) .logpane #log{position:absolute;inset:0;max-height:none;}
}

.panel{background:linear-gradient(180deg,rgba(255,255,255,.05),rgba(255,255,255,0) 22%),var(--case);
  border:1px solid var(--case-edge);border-radius:4px;padding:10px 10px 6px;
  box-shadow:0 22px 60px -30px #000 inset,0 0 0 6px #080e13;overflow-x:auto;}
.panel svg{display:block;width:100%;min-width:980px;height:auto;}

/* ---- the board, and the control that fills the glass with it ---- */
.panelwrap{position:relative;min-width:0;}
.fs-btn{display:inline-flex;align-items:center;justify-content:center;
  width:38px;height:38px;padding:0;border-radius:2px;flex:none;
  background:var(--plate);border:1px solid var(--case-edge);}
.fs-btn:hover{background:#1a2b38;border-color:#2c4557;}
.fs-btn svg{width:18px;height:18px;fill:none;stroke:var(--ink-2);stroke-width:2;
  stroke-linecap:round;stroke-linejoin:round;}
.fs-btn:hover svg{stroke:var(--ink);}
/* one icon, two states: brackets pointing out to open, in to close */
.fs-btn .fs-out{display:none;}
.fs-btn.is-open .fs-in{display:none;}
.fs-btn.is-open .fs-out{display:block;}

/* full screen, and the fallback that stands in for it where the
   Fullscreen API will not give us an element */
.panelwrap:fullscreen,
.panelwrap.maximised{background:var(--void);display:flex;flex-direction:column;
  justify-content:center;padding:20px 26px 26px;}
.panelwrap.maximised{position:fixed;inset:0;z-index:90;}
body.has-maximised{overflow:hidden;}
.panelwrap:fullscreen .panel,
.panelwrap.maximised .panel{width:100%;max-height:100%;border-radius:0;
  box-shadow:0 0 0 1px #080e13;overflow:auto;}
.panelwrap:fullscreen .panel svg,
.panelwrap.maximised .panel svg{min-width:0;max-height:calc(100vh - 132px);}

/* ---- multi-aspect heads, and the marker plate that makes a signal automatic ---- */
.head{fill:#0b131a;stroke:#2c4557;stroke-width:1;}
.marker{fill:#101c25;stroke:#c9a227;stroke-width:1;}
.markertext{font-family:"IBM Plex Mono",monospace;font-size:9px;font-weight:600;
  fill:#c9a227;letter-spacing:.04em;}

/* ---- bare: the panel as the editor's preview ----
   Everything that is page rather than board goes, so the frame beside
   the editor carries the board and the log it prints, and nothing else. */
body.bare .wrap{padding:10px 12px 12px;}
body.bare .topbar,body.bare #reference,body.bare #notes,
body.bare .desk{display:none;}
body.bare .stage{grid-template-columns:minmax(0,1fr);}
body.bare #log{max-height:150px;}

/* ---- the sheet the control table and the SWR open in ----
   One dialog for both books. Modal, so it is in the top layer and rides
   above the board even when the board has the whole screen; the board
   goes on running behind it, and Escape shuts it. */
.sheet{position:fixed;margin:auto;width:min(1080px,94vw);max-height:88vh;padding:0;
  background:var(--case);color:var(--ink);border:1px solid var(--case-edge);border-radius:4px;
  box-shadow:0 40px 120px -40px #000;overflow:hidden;}
.sheet::backdrop{background:rgba(3,7,10,.78);}
.sheet-head{display:flex;align-items:flex-start;gap:18px;padding:16px 22px 14px;
  background:var(--plate);border-bottom:1px solid var(--case-edge);}
.sheet-kicker{font-family:"Barlow Condensed",sans-serif;font-size:12px;letter-spacing:.28em;
  text-transform:uppercase;color:var(--brass);margin:0 0 3px;}
.sheet-head h2{font-size:22px;margin:0;}
.sheet-head h2::before{display:none;}      /* the brass rule belongs to the page, not the sheet */
.sheet-close{margin-left:auto;flex:none;}
.sheet-body{padding:2px 22px 26px;overflow:auto;max-height:calc(88vh - 74px);}
.sheet-body section{margin-top:32px;}
.sheet-sub{color:var(--ink-2);font-size:14px;margin:18px 0 0;max-width:78ch;}
.sheet-body table{min-width:600px;}
@media (max-width:720px){
  .sheet{width:100vw;max-width:100vw;max-height:100vh;border-radius:0;}
  .sheet-body{max-height:calc(100vh - 88px);padding:2px 14px 24px;}
}
/* the stand-in, for a browser with no showModal: no top layer and no
   ::backdrop, so the sheet is placed itself and the shadow spread across
   the viewport does the darkening the backdrop would have done */
.sheet.standin{position:fixed;top:4vh;left:50%;transform:translateX(-50%);z-index:120;
  box-shadow:0 0 0 100vmax rgba(3,7,10,.78);}
body.has-sheet{overflow:hidden;}
/* a control that cannot work says so, and stops looking pressable */
.docbox button[disabled]{opacity:.45;cursor:not-allowed;}

/* ---- the forms ----
   A form is meant to read like the paper it is printed on: the blanks
   sit in the sentences, not in a column of labelled boxes beside them,
   because picking the right blank out of a paragraph under pressure is
   the part of the job this is teaching. */
/* the way back is only there two levels deep, and an author display rule
   would otherwise outrank the browser's [hidden] — leaving an empty pill
   over the title of every book that has no second level */
.sheet-back[hidden]{display:none;}
.sheet-back{display:inline-block;margin:0 0 8px;padding:5px 11px;font-size:12px;
  letter-spacing:.14em;background:transparent;border:1px solid var(--case-edge);color:var(--ink-2);}
.sheet-back:hover{color:var(--ink);background:#1a2b38;}

/* ---- searching the forms ----
   The way into a list of thirty-five. It sits above the groups because
   that is where a reader arrives, and it is the sheet's focus when the
   list opens: this is a picker, and typing is the fastest way through
   one. */
.formfindbox{display:flex;flex-wrap:wrap;align-items:baseline;gap:6px 14px;
  margin:22px 0 6px 38px;}
.formfind{flex:1;min-width:240px;max-width:520px;font:inherit;font-size:14px;
  background:#0f1a23;color:var(--ink);border:1px solid #2c4557;border-radius:2px;
  padding:9px 12px;}
.formfind::placeholder{color:var(--ink-3);}
.formfind:focus-visible{outline:2px solid var(--cyan);outline-offset:2px;}
.formcount{margin:0;font-family:"Barlow Condensed",sans-serif;font-size:13px;
  letter-spacing:.14em;text-transform:uppercase;color:var(--ink-3);}
.formnone{margin-left:38px;}
/* an author display rule outranks the browser's [hidden], and the search
   hides by the attribute — without these two the filter does nothing */
.formlist[hidden],.formcard[hidden]{display:none;}

/* the groups the reference puts the authorities in, so a reader looking
   for the right form for a case scans eight headings rather than
   thirty-five cards */
.formgroup{font-family:"Barlow Condensed",sans-serif;font-size:15px;font-weight:600;
  letter-spacing:.18em;text-transform:uppercase;color:var(--brass);
  margin:30px 0 6px 38px;}
.formgroup + .sub{margin-bottom:12px;}
.formlist{display:grid;gap:10px;grid-template-columns:repeat(auto-fill,minmax(300px,1fr));margin-left:38px;}
.formcard{display:grid;gap:3px;text-align:left;padding:13px 15px;background:var(--plate);
  border:1px solid var(--case-edge);border-left:3px solid var(--brass);border-radius:3px;
  text-transform:none;letter-spacing:0;font-family:"IBM Plex Sans",sans-serif;}
.formcard:hover{background:#1a2b38;border-color:#2c4557;border-left-color:var(--brass);}
.formcode{font-family:"IBM Plex Mono",monospace;font-size:14px;font-weight:600;color:var(--rail);
  letter-spacing:.04em;}
.formtitle{font-family:"Barlow Condensed",sans-serif;font-size:16px;font-weight:600;
  letter-spacing:.06em;text-transform:uppercase;color:var(--ink);}
.formabout{font-size:12.5px;color:var(--ink-2);line-height:1.4;}
.formgo{font-family:"Barlow Condensed",sans-serif;font-size:12px;letter-spacing:.16em;
  text-transform:uppercase;color:var(--cyan);margin-top:4px;}
/* a form named in the requirement but not yet drawn does not pretend */
.formcard.waiting{border-left-color:var(--ink-3);}
.formcard.waiting .formcode,.formcard.waiting .formtitle{color:var(--ink-2);}
.formcard.waiting .formgo{color:var(--ink-3);}

.paper{margin-left:38px;padding:20px 22px;background:#0b1219;border:1px solid var(--case-edge);
  border-radius:3px;}
.formfor{margin:0 0 14px 38px;font-family:"IBM Plex Mono",monospace;font-size:11px;
  letter-spacing:.16em;text-transform:uppercase;color:var(--ink-3);}
.formhead{font-family:"Barlow Condensed",sans-serif;font-size:14px;font-weight:600;
  letter-spacing:.18em;text-transform:uppercase;color:var(--brass);
  margin:22px 0 10px;padding-bottom:5px;border-bottom:1px solid var(--case-edge);}
.formhead:first-child{margin-top:0;}
.formpara{font-size:14.5px;line-height:2.1;margin:0 0 12px;color:var(--ink);}
.formpara b{color:#fff;}
.formnote{font-size:12.5px;color:var(--ink-2);margin:14px 0 0;padding-left:12px;
  border-left:2px solid var(--case-edge);}
.formwarn{margin:0 0 14px 38px;padding:10px 14px;font-size:13px;color:#ffd8a8;
  background:#241a10;border:1px solid #5a4620;border-radius:3px;max-width:76ch;}
.formerr{margin:0 0 14px 38px;padding:10px 14px;font-size:13px;color:#ffb4ad;
  background:#1a1113;border:1px solid #5a2620;border-radius:3px;max-width:76ch;}
.formerr[hidden]{display:none;}
.formok{margin:0 0 16px 38px;padding:10px 14px;font-size:13px;color:#9fe6b4;
  background:#101f17;border:1px solid #23472f;border-radius:3px;max-width:76ch;}

.formgrid{display:flex;flex-wrap:wrap;gap:12px 18px;margin-bottom:16px;}
.fieldbox{display:flex;flex-direction:column;gap:5px;}
.fieldlab{font-family:"Barlow Condensed",sans-serif;font-size:12px;letter-spacing:.12em;
  text-transform:uppercase;color:var(--ink-2);}
/* the blank itself: a ruled line, not a box, because that is what it is */
.ff{font:inherit;font-size:14px;color:var(--cyan);background:#101c25;
  border:1px solid #2c4557;border-bottom:2px solid #3d5b70;border-radius:2px;
  padding:5px 9px;min-width:0;}
.ff:focus-visible{outline:2px solid var(--cyan);outline-offset:1px;}
.ff:hover{border-color:#3d5b70;}
.ff.bad{border-color:var(--red);border-bottom-color:var(--red);background:#1a1113;}
.ff-s{width:110px;} .ff-m{width:210px;} .ff-l{width:340px;}
/* a date or time carries the browser picker inside the box, so it needs
   more room than the blank it stands in would suggest */
input[type=date].ff{width:158px;} input[type=time].ff{width:124px;}
.formpara .ff{margin:0 3px;vertical-align:baseline;}
select.ff{color:var(--cyan);}
.ff-check{width:15px;height:15px;min-width:15px;padding:0;accent-color:var(--cyan);
  vertical-align:middle;border-bottom-width:1px;}
.inlinecheck{display:inline-flex;align-items:center;gap:8px;padding:2px 10px;margin:0 2px;
  background:#101c25;border:1px solid #2c4557;border-radius:2px;}
.inlinecheck span{font-size:13.5px;color:var(--ink-2);}

/* the sheet relaxes table widths, so the caution order has to insist:
   nine columns of blanks are unusable squeezed and scroll instead */
.sheet-body table.formtable{min-width:920px;font-size:13px;}
.formtable th{font-size:11px;padding-right:8px;}
.formtable td{padding:4px 8px 4px 0;border-bottom:none;}
.formtable .ff{width:100%;padding:4px 7px;font-size:13px;}

.formsign{display:flex;flex-wrap:wrap;gap:16px 34px;margin-top:26px;}
.signblock{display:flex;flex-direction:column;gap:6px;min-width:220px;}
.signrule{display:block;height:1px;background:var(--rail-dim);margin-top:26px;}
.signname{font-size:12px;color:var(--ink-2);}

.formacts{display:flex;flex-wrap:wrap;gap:10px;margin:18px 0 0 38px;}
.formacts .primary{background:#1d3a2a;border-color:#2f6244;color:#c8f2d8;}
.formacts .primary:hover{background:#24493a;}

.issued{list-style:none;margin:0 0 0 38px;padding:0;font-size:13px;}
.issued li{display:flex;flex-wrap:wrap;gap:4px 10px;align-items:baseline;padding:8px 0;
  border-bottom:1px solid rgba(29,44,57,.85);color:var(--ink-2);}
.issued b{font-family:"IBM Plex Mono",monospace;color:var(--rail);}
.issued-at{margin-left:auto;font-family:"IBM Plex Mono",monospace;font-size:11px;color:var(--ink-3);}

@media (max-width:720px){
  .formlist,.paper,.formacts,.issued,.formerr,.formok,.formwarn,.formfor,.formgroup,
  .formfindbox,.formnone{margin-left:0;}
  .paper{padding:16px 14px;}
  .formpara{line-height:2.3;}
  .ff-l{width:100%;max-width:280px;}
}

/* the panel cannot run without its configuration file */
.bootfail{margin:0;padding:22px 24px;border:1px solid #5a2620;border-left:3px solid var(--red);
  background:#1a1113;border-radius:3px;color:#ffb4ad;font-size:13.5px;}
.bootfail b{display:block;color:var(--ink);font-family:"Barlow Condensed",sans-serif;
  font-size:16px;letter-spacing:.14em;text-transform:uppercase;margin-bottom:6px;}
.bootfail code{font-family:"IBM Plex Mono",monospace;color:var(--cyan);}

/* ---- desk ---- */
/* the log used to hold the right-hand column; with it gone the desk's
   own boxes spread across the width the page now has */
.desk{display:grid;grid-template-columns:repeat(auto-fit,minmax(380px,1fr));gap:16px;margin-top:16px;}
.desk-left{display:contents;}
.deskbox{background:var(--plate);border:1px solid var(--case-edge);border-radius:3px;padding:14px 16px;}
.deskbox h3{font-family:"Barlow Condensed",sans-serif;font-size:15px;letter-spacing:.18em;
  text-transform:uppercase;color:var(--ink-2);margin:0 0 10px;font-weight:600;}
.fault-form{display:grid;grid-template-columns:1fr 1fr;gap:10px 12px;margin-bottom:12px;}
.fault-form .full{grid-column:1/-1;}
.fault-form label{display:block;font-family:"Barlow Condensed",sans-serif;font-size:12px;letter-spacing:.12em;
  text-transform:uppercase;color:var(--ink-2);margin:0 0 6px;}
.fault-form select,.fault-form input{width:100%;font:inherit;background:#0f1a23;color:var(--ink);
  border:1px solid #2c4557;border-radius:2px;padding:8px 10px;}
.fault-form select:focus-visible,.fault-form input:focus-visible{outline:2px solid var(--cyan);outline-offset:2px;}
.fault-actions{display:flex;flex-wrap:wrap;gap:8px;margin-bottom:12px;}
.fault-status{margin:0 0 10px;font-size:13px;color:var(--ink-2);}
.fault-status b{color:var(--ink);}
.fault-list{list-style:none;margin:0;padding:0;font-family:"IBM Plex Mono",monospace;font-size:12px;max-height:180px;overflow-y:auto;}
.fault-list li{padding:6px 0;border-bottom:1px solid rgba(29,44,57,.8);color:var(--ink-2);}
.fault-list li strong{color:var(--ink);}
.fault-list li.active{color:#ffb4ad;}
button{font-family:"Barlow Condensed",sans-serif;font-size:14px;font-weight:600;letter-spacing:.12em;
  text-transform:uppercase;color:var(--ink);background:#1a2b38;border:1px solid #2c4557;
  border-radius:2px;padding:8px 14px;cursor:pointer;}
button:hover{background:#22384a;}
button:focus-visible,[tabindex]:focus-visible{outline:2px solid var(--cyan);outline-offset:2px;}
.hint{font-size:13px;color:var(--ink-2);margin:0;}
.hint b{color:var(--ink);}
#log{list-style:none;margin:0;padding:0;font-family:"IBM Plex Mono",monospace;font-size:11.5px;
  max-height:min(68vh,720px);overflow-y:auto;}
/* the plate is dark enough that the platform's own scrollbar disappears
   into it, and a scroller nobody can see is a scroller nobody uses */
#log,.fault-list{scrollbar-width:thin;scrollbar-color:#33536b transparent;}
/* One record, read in columns: what number it is, when, and what
   happened — with who did it opening the third column, because on a
   failure the board refusing a route and the trainee asking for it a
   third time are not the same event and must not read as one. */
#log li{display:grid;grid-template-columns:24px 56px minmax(0,1fr);gap:7px;
  align-items:start;padding:7px 0;border-bottom:1px solid rgba(29,44,57,.8);
  color:var(--ink-2);}
#log .seq{color:#3f5364;}
#log time.t{color:var(--cyan);}
#log .txt{min-width:0;overflow-wrap:anywhere;}
/* the identifier a reader is meant to pick out without reading the line */
#log .txt b{color:var(--ink);font-weight:500;}
#log li.ok .txt{color:#9fe6b4;}
#log li.no .txt{color:#ff9a91;}
#log li.mv .txt{color:var(--cyan);}
/* what the board answered is not what the trainee did, so its clock is
   quieter; a fault is the one line allowed to colour its whole row */
#log li.by-bd time.t{color:var(--ink-3);}
#log li.fault{background:rgba(255,68,56,.07);margin:0 -6px;padding-left:6px;padding-right:6px;}

/* who did it, and — when an exercise is marking — what it satisfied */
#log .actor{display:inline-block;font-size:9px;letter-spacing:.12em;
  text-transform:uppercase;border:1px solid var(--case-edge);border-radius:2px;
  padding:0 5px;margin-right:6px;color:var(--ink-3);}
#log .actor.tr{color:var(--cyan);border-color:#28576e;}
#log .actor.in{color:var(--amber);border-color:#5c451a;}
#log .det{display:inline-block;font-size:9px;letter-spacing:.1em;
  text-transform:uppercase;color:#9fe6b4;border:1px solid #2c5a3c;border-radius:2px;
  padding:0 5px;margin-left:6px;background:#11291c;}
#log .det.miss{color:#ff9a91;border-color:#5c2a25;background:#2a1613;}

/* ---- the station on the ground ----
   The window the 3D view button opens — station-view.html, which wears
   this same stylesheet so that the two windows are one instrument: the
   diagram on one screen and the place it stands for on the other. The
   window is nothing but glass, so the glass takes everything the head
   leaves it. */
body.viewwin{height:100vh;padding:0;display:flex;flex-direction:column;overflow:hidden;}
.viewwin-head{flex:none;display:flex;flex-wrap:wrap;align-items:baseline;gap:4px 22px;
  padding:11px 18px 10px;background:var(--plate);border-bottom:1px solid var(--case-edge);}
.viewwin-kicker{font-family:"Barlow Condensed",sans-serif;font-size:11px;letter-spacing:.28em;
  text-transform:uppercase;color:var(--brass);margin:0 0 2px;}
.viewwin-head h1{font-family:"Barlow Condensed",sans-serif;font-weight:600;font-size:23px;
  letter-spacing:.08em;text-transform:uppercase;margin:0;line-height:1.05;}
.viewwin-strap{flex:1;min-width:220px;font-size:12.5px;color:var(--ink-2);margin:0;max-width:92ch;
  /* two lines of it and no more: the head is not what this window is for */
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;}
.viewwin-back{flex:none;margin-left:auto;align-self:center;font-size:12px;padding:6px 11px;}
.viewwin-body{flex:1;min-height:0;display:flex;padding:12px 16px 14px;}
.viewwin .s3d{flex:1;min-height:0;display:flex;flex-direction:column;}
.viewwin .s3d-stage{flex:1;min-height:0;height:auto;}
.viewwin .s3d-note{flex:none;}
/* the window opened with no panel behind it, and the window whose panel
   has since gone: one sentence, in the middle of the glass */
.viewwin-say{margin:auto;max-width:62ch;text-align:center;padding:0 24px;}
.viewwin-say b{display:block;font-family:"Barlow Condensed",sans-serif;font-size:19px;
  font-weight:600;letter-spacing:.1em;text-transform:uppercase;color:var(--ink);margin-bottom:8px;}
.viewwin-say p{margin:0;font-size:13.5px;color:var(--ink-2);line-height:1.6;}

.s3d-bar{display:flex;flex-wrap:wrap;align-items:center;gap:8px 14px;margin-bottom:10px;}
.s3d-views{display:flex;flex-wrap:wrap;gap:8px;}
.s3d-views button{font-size:13px;padding:7px 12px;}
.s3d-views button.on{background:#1d3243;border-color:var(--cyan);color:#eaf6ff;}
.s3d-legend{font-family:"IBM Plex Mono",monospace;font-size:11px;letter-spacing:.06em;
  color:var(--ink-3);margin-left:auto;max-width:46ch;}
.s3d-stage{position:relative;background:var(--case);border:1px solid var(--case-edge);
  border-radius:4px;box-shadow:0 22px 60px -30px #000 inset,0 0 0 6px #080e13;
  overflow:hidden;height:min(60vh,680px);}
.s3d-canvas{display:block;width:100%;height:100%;touch-action:none;outline:none;}
.s3d-note{font-family:"IBM Plex Mono",monospace;font-size:11.5px;color:var(--ink-2);
  margin:9px 0 0;}
.s3d-note.warn{color:#ff9a91;}
@media (max-width:720px){
  .viewwin-head{padding:9px 13px 9px;}
  .viewwin-strap{display:none;}    /* on a small window the glass is worth more */
  .viewwin-body{padding:10px 11px 12px;}
  .s3d-legend{display:none;}
  .s3d-stage{height:52vh;}
}

/* ---- reference sections ---- */
section{margin-top:44px;}
h2{font-family:"Barlow Condensed",sans-serif;font-size:24px;font-weight:600;letter-spacing:.16em;
  text-transform:uppercase;margin:0 0 4px;}
h2::before{content:"";display:inline-block;width:26px;height:2px;background:var(--brass);
  vertical-align:middle;margin-right:12px;}
.sub{color:var(--ink-2);font-size:14px;margin:0 0 18px 38px; }
.sub.foot{margin-top:16px;}
.legend{display:grid;gap:10px;grid-template-columns:repeat(auto-fill,minmax(230px,1fr));margin-left:38px;}
.key{display:flex;align-items:center;gap:12px;background:var(--plate);border:1px solid var(--case-edge);
  border-radius:3px;padding:9px 12px;}
.key b{display:block;font-family:"Barlow Condensed",sans-serif;font-weight:600;letter-spacing:.08em;
  text-transform:uppercase;font-size:14px;}
.key span{display:block;font-size:12px;color:var(--ink-2);line-height:1.35;}
.scroll{overflow-x:auto;margin-left:38px;}
table{border-collapse:collapse;width:100%;min-width:680px;font-size:13.5px;}
caption{text-align:left;font-family:"IBM Plex Mono",monospace;font-size:11px;letter-spacing:.16em;
  text-transform:uppercase;color:var(--ink-3);padding-bottom:8px;}
th,td{text-align:left;vertical-align:top;padding:9px 14px 9px 0;border-bottom:1px solid rgba(29,44,57,.85);}
th{font-family:"Barlow Condensed",sans-serif;font-weight:600;letter-spacing:.12em;text-transform:uppercase;
  font-size:13px;color:var(--ink-2);border-bottom-color:var(--case-edge);}
td.id{font-family:"IBM Plex Mono",monospace;font-weight:600;color:var(--rail);white-space:nowrap;}
td em{font-style:normal;color:var(--ink-2);}
.note{margin:52px 0 0;padding:18px 22px;border:1px solid var(--case-edge);border-left:3px solid var(--brass);
  background:var(--plate);border-radius:3px;font-size:13.5px;color:var(--ink-2);}
.note b{color:var(--ink);}
@media (max-width:1100px){
  /* too narrow to stand beside a 980-unit board: the rail goes back
     under it, and folding it still works there — lying down again, and
     folding upward rather than sideways */
  .stage,.stage.log-shut{grid-template-columns:minmax(0,1fr);}
  .stage.log-shut .logtoggle{width:100%;min-height:0;writing-mode:horizontal-tb;}
  .stage.log-shut .logpane.deskbox{padding:10px 12px;}
  .logchev{transform:rotate(90deg);}
  .stage.log-shut .logchev{transform:rotate(-90deg);}
}
@media (max-width:900px){.desk{grid-template-columns:1fr;}}
/* the page draws in from the edges on a phone; the bar spans them, so the
   inset is the wrap's and not the body's */
@media (max-width:720px){.sub,.legend,.scroll{margin-left:0;}.wrap{padding:20px 14px 60px;}}

/* ============================================================
   The board itself — these classes are worn by elements inside
   the inline <svg id="board">, both the drawn ones and the ones
   the script generates.
   ============================================================ */

.rail{fill:none;stroke:#f0a63c;stroke-width:5;stroke-linecap:round;}
.lead{fill:none;stroke:#4a5f70;stroke-width:4.5;stroke-linecap:round;transition:stroke .18s;}
.lead.rev{stroke:#f0a63c;}
.diag{fill:none;stroke:#4a5f70;stroke-width:4.5;stroke-linecap:round;transition:stroke .18s;}
.diag.rev{stroke:#f0a63c;}
.bdy{stroke:#6d8598;stroke-width:2.5;}
/* scenery: the fixed furniture each station's yaml draws under the working layers */
.limit{stroke:#2f4a5c;stroke-width:1.5;stroke-dasharray:3 7;}
.arrow{stroke:#93a9ba;stroke-width:2;fill:none;}
.platform{fill:url(#pfhatch);stroke:#2c4557;}
.pfname{font-family:"IBM Plex Mono",monospace;font-size:13px;fill:#c3d6e5;letter-spacing:.04em;}
.stopblock{stroke:#9fb8c9;stroke-width:5;}
.stub{stroke:#9fb8c9;stroke-width:3;fill:none;}
.lbl{font-family:"IBM Plex Mono",monospace;font-size:13px;fill:#e6f0f8;letter-spacing:.04em;}
.lbl-s{font-family:"IBM Plex Mono",monospace;font-size:11px;fill:#93a9ba;letter-spacing:.06em;}
.tc{font-family:"IBM Plex Mono",monospace;font-size:12px;fill:#5fd0c8;letter-spacing:.08em;}
.ttl{font-family:"Barlow Condensed",sans-serif;font-size:15px;font-weight:600;fill:#93a9ba;letter-spacing:.2em;}
.stalk{stroke:#cfe0ee;stroke-width:2;fill:none;}
.hit{cursor:pointer;}
.signame{font-family:"IBM Plex Mono",monospace;font-size:11.5px;fill:#b9cddc;letter-spacing:.04em;}
.xbox rect{fill:#141f28;stroke:#39566b;transition:fill .18s,stroke .18s;}
.xbox.avail rect{fill:#1d3243;stroke:#eaf6ff;}
.xbox text{font-family:"IBM Plex Mono",monospace;font-size:11.5px;fill:#9fb8c9;letter-spacing:.06em;}
.xbox.avail text{fill:#eaf6ff;}
.pbox rect{fill:#16252f;stroke:#39566b;transition:fill .18s,stroke .18s;}
.pbox.rev rect{fill:#3a3116;stroke:#ffd166;}
.pbox.locked rect{stroke:#ff4438;}
.pbox text{font-family:"IBM Plex Mono",monospace;font-size:12.5px;fill:#dbe7f1;letter-spacing:.06em;}
/* panel furniture the model does not work: counted controls, the SM's key */
.furn rect{fill:none;stroke:#2c4557;}
.furn .furn-lamp{fill:#16252f;stroke:#3d5b70;stroke-width:1.5;}
.furn .furn-t{font-family:"IBM Plex Mono",monospace;font-size:10px;fill:#5f7385;letter-spacing:.06em;}
.route{fill:none;stroke:#f4fbff;stroke-width:8;stroke-linecap:round;stroke-linejoin:round;opacity:.95;}
.occ{fill:none;stroke:#ff4438;stroke-width:5;opacity:0;transition:opacity .1s;}
.occ.on{opacity:1;}
