/* Era by Eon - the sheet the console is printed on.

   Hard edges, offset shadows, graphite sheets over a fixed sunset. Everything
   here is hand-written CSS: the site is served under a CSP that allows no
   third-party script, so there is no utility-class framework to lean on.

   Every colour the sheets use is a token below, so the palette is one edit
   rather than a sweep: the graphite/green pass changed these nine lines and
   every page followed. */

:root{
  --sheet:#232326;
  --sheet-2:#2c2c30;
  --sheet-3:#2a2a2e;
  --sheet-4:#3a3a3f;
  --sheet-low:#1b1b1e;
  --ink:#F4E9DA;
  --ink-soft:#B3A48F;
  --rule:rgba(244,233,218,.18);
  --line:rgba(244,233,218,.3);
  --orange:#39FF14;
  --action:#39FF14;
  /* Text sits *on* the action colour in two places, and cream on neon green is
     1.4:1 - unreadable. Dark green is the same accent, legible. */
  --on-action:#0a2604;
  --teal:#4E97A8;
  --blueprint:#6FC3D9;
  --error:#ff6b5e;
  --shadow:rgba(16,16,18,1);
  --mono:'IBM Plex Mono',ui-monospace,SFMono-Regular,Menlo,monospace;
  --serif:'Hanken Grotesk',system-ui,-apple-system,Segoe UI,sans-serif;
  --sans:'Hanken Grotesk',system-ui,-apple-system,Segoe UI,sans-serif;
  --page:44px;
  --gutter:24px;
  --measure:720px;
  --sheet-w:1100px;
}

*{box-sizing:border-box}
[hidden]{display:none!important}
html{-webkit-text-size-adjust:100%}
body{
  margin:0;
  min-height:100vh;
  padding:var(--page) 16px;
  font-family:var(--sans);
  font-size:15px;
  line-height:1.65;
  color:var(--ink);
  background:linear-gradient(180deg,#3d4663 0%,#5c4a5e 38%,#8a5640 72%,#b06a3a 100%) fixed;
  position:relative;
}
@media(min-width:768px){body{padding-left:var(--page);padding-right:var(--page)}}
/* The grain that makes the gradient read as paper rather than as a gradient. */
body::after{
  content:"";
  position:fixed;
  inset:0;
  pointer-events:none;
  opacity:.5;
  z-index:100;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='240' height='240'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 0.95 0 0 0 0 0.9 0 0 0 0 0.82 0 0 0 0.04 0'/%3E%3C/filter%3E%3Crect width='240' height='240' filter='url(%23n)'/%3E%3C/svg%3E");
}

a{color:var(--orange);text-decoration:none}
a:hover{color:var(--action)}
h1,h2,h3{margin:0}
p{margin:0}
img{max-width:100%}

/* ---------- the sheets ---------- */
.sheet{
  position:relative;
  z-index:10;
  width:100%;
  max-width:var(--sheet-w);
  margin:0 auto;
  background-color:var(--sheet);
  border:1px solid rgba(244,233,218,.25);
  box-shadow:0 0 0 1px var(--sheet),0 0 0 2px rgba(244,233,218,.25),6px 8px 0 rgba(0,0,0,.4);
}
/* The menu hangs over the sheet below it, so the nav must paint above every sheet. */
.nav.sheet{z-index:20}
.nav{
  display:flex;
  align-items:center;
  justify-content:space-between;
  gap:16px;
  flex-wrap:wrap;
  padding:16px var(--gutter);
  margin-bottom:var(--gutter);
}
@media(min-width:768px){.nav{padding:16px var(--page)}}
/* On a narrow sheet the links wrap onto their own line rather than being hidden:
   a phone that cannot reach Environments, Consumption or Admin is a phone that
   can only read the landing page. */
.nav-links{display:flex;flex-wrap:wrap;align-items:center;gap:14px 18px;order:3;width:100%;border-top:1px solid var(--line);padding-top:12px}
@media(min-width:768px){.nav-links{order:0;width:auto;gap:24px;border-top:0;padding-top:0;flex-wrap:nowrap}}
.nav-side{display:flex;align-items:center;gap:14px}
.brand{
  display:inline-flex;
  align-items:baseline;
  gap:.3em;
  font-family:var(--serif);
  font-size:32px;
  font-weight:700;
  letter-spacing:-.01em;
  color:var(--ink);
}
.brand small{font-size:.5em;font-weight:400;opacity:.65}
.brand img{height:.62em;width:auto}
main.sheet{display:flex;flex-direction:column;margin-bottom:var(--page)}
footer.sheet{padding:48px var(--gutter);margin-top:var(--gutter);margin-bottom:32px;display:flex;flex-direction:column;gap:24px}
@media(min-width:768px){footer.sheet{padding:48px var(--page)}}
.foot-top{display:flex;flex-direction:column;gap:18px;justify-content:space-between;align-items:flex-start}
@media(min-width:768px){.foot-top{flex-direction:row;align-items:center}}
/* The sheets nobody navigates to until they need them: the inbox, and the two a
   reader goes looking for at the foot of a page because that is where they live. */
.foot-links{display:flex;flex-wrap:wrap;align-items:center;gap:12px 24px}
/* The slot is a flex item so the glyph centres on the row like a link's type
   does; left inline it would hang off the text's baseline, which has no glyph. */
#foot-community{display:flex;align-items:center}
.discord-link{display:flex;align-items:center}
.discord-link svg{width:17px;height:17px;flex:none;color:#5865F2}
.foot-note{border-top:1px solid var(--rule);padding-top:24px;font-size:14px;color:var(--ink);opacity:.75;max-width:900px}

/* ---------- type ---------- */
.eyebrow{
  font-family:var(--mono);
  font-size:11px;
  font-weight:600;
  letter-spacing:.2em;
  text-transform:uppercase;
  color:var(--orange);
}
.eyebrow.rule{border-bottom:1px solid var(--orange);padding-bottom:4px;align-self:center}
.label{font-family:var(--mono);font-size:11px;font-weight:600;letter-spacing:.12em;text-transform:uppercase;color:var(--ink-soft)}
.mono{font-family:var(--mono);font-size:12px}
.page-title{font-family:var(--mono);font-size:30px;font-weight:700;text-transform:uppercase;letter-spacing:-.01em;line-height:1.15}
@media(min-width:768px){.page-title{font-size:36px}}
.hero-title{font-family:var(--mono);font-size:32px;font-weight:700;text-transform:uppercase;letter-spacing:-.01em;line-height:1.15}
@media(min-width:768px){.hero-title{font-size:46px}}
.serif{font-family:var(--serif);font-weight:600}
.h2{font-family:var(--serif);font-size:32px;font-weight:600;line-height:1.2}
.h3{font-family:var(--serif);font-size:22px;font-weight:600}
.lead{font-size:18px;font-weight:500;color:var(--ink-soft);max-width:var(--measure)}
.sub{color:var(--ink-soft)}
.soft{color:var(--ink-soft)}
.hot{color:var(--orange);font-weight:600}
.bad{color:var(--error)}

/* ---------- sections ---------- */
section,header.head{padding:40px var(--gutter)}
@media(min-width:768px){section,header.head{padding:40px 64px}}
.rule-b{border-bottom:1px dashed var(--rule)}
.head{display:flex;flex-direction:column;gap:12px}
.head.split>.label{white-space:nowrap}
@media(min-width:768px){
  .head.split{flex-direction:row;align-items:flex-end;justify-content:space-between;gap:24px}
}
.stack{display:flex;flex-direction:column;gap:12px}
.stack-lg{display:flex;flex-direction:column;gap:32px}
.row{display:flex;align-items:center;gap:12px;flex-wrap:wrap}
.row.between{justify-content:space-between}
.grid2,.grid3{display:grid;gap:20px;grid-template-columns:1fr}
/* `1fr` floors at the content's min-content width, so one long unbreakable token
   (the install line's URL) widened its own column and squeezed its neighbours out
   of their share. The columns stay equal and the content wraps instead. */
@media(min-width:700px){.grid2{grid-template-columns:repeat(2,minmax(0,1fr))}}
@media(min-width:900px){.grid3{grid-template-columns:repeat(3,minmax(0,1fr))}}
.center{text-align:center;align-items:center}

/* ---------- controls ---------- */
.btn,.btn-cta{
  display:inline-flex;
  align-items:center;
  gap:8px;
  font-family:var(--mono);
  font-size:13px;
  font-weight:700;
  letter-spacing:.1em;
  text-transform:uppercase;
  padding:10px 16px;
  cursor:pointer;
  transition:transform .15s ease-out,box-shadow .15s ease-out,background .15s ease-out;
}
.btn{background:var(--sheet-low);color:var(--ink);border:1px solid var(--line);box-shadow:3px 3px 0 var(--shadow)}
.btn:hover{transform:translate(-1px,-1px);box-shadow:4px 4px 0 var(--shadow);color:var(--ink)}
.btn:active{transform:translate(2px,2px);box-shadow:0 0 0 var(--shadow)}
.btn.pale{background:var(--ink);color:var(--sheet)}
.btn-cta{background:var(--action);color:var(--on-action);border:1px solid var(--action);box-shadow:3px 3px 0 var(--shadow)}
.btn-cta:hover{transform:translate(-1px,-1px);box-shadow:5px 5px 0 var(--shadow),0 6px 24px -6px rgba(57,255,20,.7);color:var(--on-action)}
.btn-cta:active{transform:translate(2px,2px);box-shadow:0 0 0 var(--shadow)}
.btn-cta.lg{padding:15px 28px;font-size:15px}
.btn[disabled],.btn-cta[disabled]{opacity:.45;cursor:not-allowed;transform:none;box-shadow:none}
.link-btn{
  background:none;border:0;padding:0;cursor:pointer;
  font-family:var(--mono);font-size:12px;letter-spacing:.08em;text-transform:uppercase;color:var(--orange);
}
.link-btn:hover{color:var(--action)}
.link-btn.danger:hover{color:var(--error)}
.link-btn.armed{color:var(--error)}
.token-btn{
  font-family:var(--mono);font-size:11px;letter-spacing:.03em;color:var(--ink);
  border:1px solid var(--line);background:var(--sheet-3);padding:5px 10px;cursor:pointer;white-space:nowrap;
}
.token-btn:hover{background:var(--sheet-4);border-color:rgba(244,233,218,.55)}
/* One of these is a link out to a client rather than a button (Cursor's install
   deeplink), and it has to sit in the row looking like the rest of them. */
a.token-btn{display:inline-block;text-decoration:none;line-height:normal}
/* The one control in the row that goes somewhere rather than copying something
   for a client: coloured as the way in, since among monospace buttons that all
   copy set-up commands it read as one more of them. */
.token-btn.go{border-color:var(--action);color:var(--action)}
.token-btn.go:hover{background:var(--action);color:var(--on-action);border-color:var(--action)}
.token-btn.ok{border-color:var(--blueprint);color:var(--blueprint)}
.token-btn.warn{border-color:var(--error);color:var(--error)}
.navlink{font-family:var(--mono);font-size:13px;letter-spacing:.1em;text-transform:uppercase;color:var(--ink-soft)}
.navlink:hover{color:var(--orange)}
.navlink.on{color:var(--orange)}

/* option chips - the closed vocabulary the console publishes */
.opt{
  display:inline-flex;align-items:center;gap:8px;
  border:1px solid var(--line);background:var(--sheet-2);color:var(--ink);
  font-family:var(--mono);font-size:13px;letter-spacing:.02em;
  padding:9px 15px;cursor:pointer;white-space:nowrap;
  box-shadow:2px 2px 0 rgba(0,0,0,.5);
  transition:transform .12s ease-out,box-shadow .12s ease-out,background .12s ease-out;
}
.opt:hover{transform:translate(-1px,-1px);box-shadow:3px 3px 0 rgba(0,0,0,.5);border-color:rgba(244,233,218,.6)}
.opt[aria-pressed="true"],.opt.on{background:var(--action);color:var(--on-action);border-color:var(--action);box-shadow:2px 2px 0 rgba(0,0,0,.5)}
.opt.locked,.opt[disabled]{opacity:.75;cursor:default;border-style:dashed;transform:none;box-shadow:2px 2px 0 rgba(0,0,0,.5)}
.opt small{font-size:11px;opacity:.6}
.chip{
  font-family:var(--mono);font-size:11px;letter-spacing:.05em;text-transform:uppercase;
  border:1px solid var(--line);padding:3px 8px;white-space:nowrap;color:var(--ink-soft);
}
.chip.hot{color:var(--orange);font-weight:400}
.tag{font-family:var(--mono);font-size:13px;border:1px solid var(--ink);padding:4px 8px;color:var(--ink)}
/* The fleet is longer than the names worth printing, and a dashed chip reads as
   the list continuing rather than as one more system. */
.tag.more{border-style:dashed;border-color:var(--rule);color:var(--ink-soft)}

/* ---------- cards ---------- */
.card{border:1px solid var(--line);background:var(--sheet-2);box-shadow:3px 3px 0 rgba(0,0,0,.35);padding:20px}
.card.plain{box-shadow:none}
.step{border:2px solid var(--ink);padding:24px;display:flex;flex-direction:column;gap:12px}
.step .no,.lane .no{font-family:var(--mono);font-size:13px;font-weight:700;color:var(--orange)}

/* Build, test, demo: a row of the sheet each, not three boxes in a row. Side by
   side, one height had to hold a four-line command and a single link, which is
   what made the set dense at one end and empty at the other; down the sheet the
   same height is a pitch instead, and the three columns - where it lives, what it
   is, the way in - repeat under each other so the set reads as one thing. */
/* Named apart from the meter `.track` and the hero's `.ship-lane`: a bare
   `.track` already means a bar with a fill inside it. */
/* The last row closes on a rule like the two above it, so the caption under the
   set reads as a caption rather than as a fourth row. */
.lanes{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;border-bottom:1px dashed var(--rule)}
.lane{display:grid;gap:20px;padding:28px 0;border-top:1px dashed var(--rule)}
.lane:first-child{border-top:0;padding-top:0}
@media(min-width:900px){
  /* Three rows of one height, so the rules come down the sheet at an even pitch:
     the set is one thing read three ways, and a short last row would otherwise
     read as the section running out. Each row's panel hangs the same distance
     under the dashed line above it - the first row takes the section's own 40px,
     the rest clear their own rule, so the rule's pixel comes out of the padding
     rather than off the alignment. */
  .lanes{display:grid;grid-auto-rows:1fr}
  .lane{grid-template-columns:190px minmax(0,1fr) 360px;gap:44px;align-items:start;padding:39px 0 40px}
}
.lane-head{display:flex;flex-direction:column;gap:10px;align-items:flex-start}
/* One paragraph a row, in the sheet's own type: what the thing is and what running
   it leaves behind read as one sentence pair, rather than a second note under the
   command repeating half of it in smaller type. */
.lane>.sub{max-width:var(--measure)}
.lane>.sub code{font-family:var(--mono);font-size:12px}
.lane-do{display:flex;flex-direction:column;align-items:flex-start;min-width:0;width:100%}
.step .cmds,.lane .cmds,.cmds.panel{
  font-family:var(--mono);font-size:11px;color:var(--ink-soft);
  display:flex;flex-direction:column;gap:4px;
  /* A command wraps at its spaces; breaking anywhere split `zendesk` and
     `eonio/era-ci:1` mid-token, which is how a reader mistypes it. */
  overflow-wrap:break-word;
}
/* A card packs its block to its foot, under a rule that separates it from the
   prose above it. */
.step .cmds{margin-top:auto;padding-top:12px;border-top:1px dashed var(--rule)}
/* A row already has rules of its own, so one more would read as a stray line:
   the command sits in a recessed panel instead, the way code does everywhere
   else on these sheets. */
.lane .cmds{background:var(--sheet-low);border:1px solid var(--line);padding:14px 16px;line-height:1.7;gap:6px}
/* Chrome takes a break after a hyphen, so `--size` came out as `--` / `size` in
   a phone-width card. Each flag is held together instead. */
.cmds .nb{white-space:nowrap}
/* A placeholder in a command - `<tenant>` - reads as a placeholder rather than as
   something to type, the same way it does in the wiki's code blocks. */
.cmds .dim{color:var(--ink-soft);opacity:.7}
/* A wrapped command hangs under its own prompt, so the eye can still find where
   each line starts. */
.step .cmds>span,.lane .cmds>span{padding-left:14px;text-indent:-14px}
.step .cmds>span.tag-copy,.lane .cmds>span.tag-copy{padding-left:8px;text-indent:0}
/* The install line's URL is one long token, so it is the thing that gives rather
   than setting its column's floor and pushing the other two cards narrower. */
.cmds .cli-line{overflow-wrap:anywhere}
/* A command is only useful if it reaches the reader's shell, so the whole block
   is the copy target and the tag lives on its own line under the text rather
   than floating over it. A button does not inherit the sheet's type either, and
   `font:inherit` would take the prose the card is set in. */
.cmds.copy{
  cursor:pointer;background:none;border:0;text-align:left;width:100%;
  font-family:var(--mono);font-size:11px;color:var(--ink-soft);
}
.step .cmds.copy{border-top:1px dashed var(--rule)}
/* The button reset above drops the panel, so the row's block keeps it, and takes
   the accent border under the pointer to say the whole panel is the target. */
.lane .cmds.copy{background:var(--sheet-low);border:1px solid var(--line)}
.lane .cmds.copy:hover{border-color:var(--action)}
.cmds.copy:hover{color:var(--action)}
.cmds.copy .tag-copy{
  /* The tag is a second thing under the command, not its next line, so it stands
     off the text it belongs to. */
  align-self:flex-start;margin-top:20px;padding:2px 8px;border:1px solid var(--action);color:var(--action);
  font-size:9px;font-weight:700;letter-spacing:.15em;text-transform:uppercase;
  /* A command a reader does not know is copyable is a command they retype, so the
     tag stands at rest and only sharpens under the pointer. */
  opacity:.6;transition:opacity .15s ease-out;
}
.cmds.copy:hover .tag-copy,.cmds.copy:focus-visible .tag-copy,.cmds.copy.done .tag-copy{opacity:1}
.cmds.copy.done .tag-copy{background:var(--action);color:var(--on-action)}
.cmds.copy.warn .tag-copy{border-color:var(--error);color:var(--error);opacity:1}
@media(prefers-reduced-motion:reduce){.cmds.copy .tag-copy{transition:none}}
/* A block that stands on the sheet rather than inside a card or a row - the steps
   on the use-cases sheet, the skill button on the front one - carries the recessed
   panel itself. After the button reset above, which would otherwise drop it: same
   specificity, and the later rule wins. */
.cmds.panel,.cmds.copy.panel{background:var(--sheet-low);border:1px solid var(--line);padding:14px 16px;line-height:1.7;gap:6px}
.cmds.copy.panel:hover{border-color:var(--action)}
.cmds.panel>span{padding-left:14px;text-indent:-14px}
.cmds.panel>span.tag-copy{padding-left:8px;text-indent:0}
/* The skill is one control rather than a command to read: only as wide as the two
   lines it carries, left-aligned inside a centred sheet. */
.cmds.panel.skill-btn{width:auto;align-items:flex-start;font-size:12px;text-align:left}
.cmds.panel.skill-btn>span{padding-left:0;text-indent:0}
/* The commands lose the hanging indent above, but the tag is a label rather than a
   line of them: it keeps the padding that centres its word inside its own border. */
.cmds.panel.skill-btn>span.tag-copy{padding-left:8px}
/* A question is a prompt to paste, not a command to read: it wraps as prose, in
   the mono the agent will see it in, and the tag ends the row rather than
   standing under a single line. */
.cmds.panel.ask{flex-direction:row;align-items:baseline;justify-content:space-between;gap:12px;font-size:12px;line-height:1.6}
.cmds.panel.ask>span{padding-left:0;text-indent:0}
.cmds.panel.ask>.q{flex:1;overflow-wrap:anywhere}
.cmds.copy.ask .tag-copy{margin-top:0;flex:none}
/* Build runs three commands and Test one, but the two panels are read down one
   column, so they hold one height - Build's, at this column's width - and the tag
   stands on the panel's floor in both. One line of Docker then keeps room over its
   tag, which is the point: the tag is where the eye found it a row above. Rules
   after the tag's own margin, or that margin would win the cascade. */
@media(min-width:900px){
  .lane .cmds{min-height:184px}
  .lane .cmds.copy .tag-copy{margin-top:auto}
}
.code{background:var(--sheet-low);border:1px solid var(--line);box-shadow:4px 4px 0 rgba(0,0,0,.35);display:flex;flex-direction:column;min-width:0}
.code.hot-shadow{box-shadow:6px 6px 0 var(--action)}
.code-bar{display:flex;align-items:center;gap:8px;padding:10px 12px;border-bottom:1px solid var(--ink-soft);background:#33333a}
.code-bar .dot{width:10px;height:10px;border-radius:9999px;background:var(--sheet-4)}
.code-bar .dot.r{background:var(--error)}
.code-bar .dot.g{background:var(--teal)}
.code-bar span{margin-left:8px;font-family:var(--mono);font-size:11px;letter-spacing:.12em;text-transform:uppercase;color:var(--ink-soft)}
.code pre{margin:0;padding:16px;font-family:var(--mono);font-size:11.5px;line-height:1.55;overflow-x:auto;white-space:pre;color:#EFF1EC}
.caret{display:inline-block;width:8px;height:14px;background:var(--orange);margin-left:3px;vertical-align:middle;animation:blink 1s steps(1) infinite}
@keyframes blink{50%{opacity:0}}

/* a key/value ledger row, the way the sheets print specifications */
.spec{display:flex;flex-direction:column;max-width:var(--measure)}
.spec div{display:flex;align-items:baseline;gap:12px;padding:6px 0;border-bottom:1px dashed var(--rule)}
.spec dt,.spec .k{font-family:var(--mono);font-size:10px;letter-spacing:.12em;text-transform:uppercase;color:var(--ink-soft);width:82px;flex:none}
.spec dd,.spec .v{margin:0;font-family:var(--mono);font-size:12px;color:var(--ink);line-height:1.6}

/* ---------- environments ---------- */
.env{background:var(--sheet-2);border:1px solid var(--line);box-shadow:4px 4px 0 rgba(0,0,0,.35);padding:24px;display:flex;flex-direction:column;gap:24px}
@media(min-width:768px){.env{padding:32px}}
.env-head{display:flex;align-items:flex-start;gap:20px;flex-wrap:wrap;cursor:pointer;user-select:none;background:none;border:0;padding:0;text-align:left;color:inherit;width:100%}
/* The company's name, mail domain and tenant id are the strings a reader takes
   off this sheet by hand, and they sit inside the button that folds the card
   open: the head refuses selection everywhere else so a drag on a chip does
   not smear text, but these three select like ordinary prose. */
.env-head .sel{user-select:text;cursor:text}
.env-body{display:none;flex-direction:column;gap:24px}
.env.open .env-body{display:flex}
.chev{display:inline-block;transition:transform .15s ease-out}
.env.open .chev{transform:rotate(90deg)}
/* The company's own profile, folded away until asked for: four sections of prose
   sit between the card's opening line and its credential, so the reader who came
   for the token is not made to scroll past the company to reach it. Native
   disclosure, marker replaced by the same chevron the card's head turns. */
.profile{border:1px dashed var(--rule);padding:0 16px}
.profile>summary{display:flex;align-items:center;justify-content:space-between;gap:12px;cursor:pointer;padding:12px 0;list-style:none}
.profile>summary::-webkit-details-marker{display:none}
.profile[open]>summary .chev{transform:rotate(90deg)}
.profile>.stack{padding-bottom:14px}
.mark{
  width:56px;height:56px;flex:none;border:2px solid var(--ink);
  display:flex;align-items:center;justify-content:center;
  font-family:var(--serif);font-weight:700;font-size:24px;
  background:var(--ink);color:var(--sheet);
}
.mark.sm{width:40px;height:40px;font-size:18px}
.mark.teal{background:var(--teal);color:var(--sheet)}
.mark.dark{background:var(--sheet-3);color:var(--ink)}
.tok-row{border:1px solid rgba(57,255,20,.5);background:#0e1f09;padding:16px;display:flex;flex-direction:column;gap:12px}
@media(min-width:640px){.tok-row.idle{flex-direction:row;align-items:center;justify-content:space-between}}
.tok{
  flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
  background:var(--sheet-low);border:1px solid var(--rule);padding:8px 12px;
  font-family:var(--mono);font-size:12px;color:var(--ink);
}
.tok-warn{font-family:var(--mono);font-size:11px;color:var(--orange)}
/* the environment's day of data, and the controls that move it */
.day-row{border:1px dashed var(--rule);background:var(--sheet-low);padding:16px;display:flex;flex-direction:column;gap:12px}
.day-row.split{border-style:solid;border-color:var(--orange)}
.day-line{display:flex;flex-wrap:wrap;align-items:center;gap:12px;justify-content:space-between}
.day-jump{display:flex;flex-wrap:wrap;align-items:center;gap:8px}
.day-warn{font-family:var(--mono);font-size:11px;color:var(--orange)}
/* the quarter the environment's company lived through, as a page rather than as records */
.brief{border:1px dashed var(--rule);background:var(--sheet-low);padding:16px;display:flex;flex-direction:column;gap:12px}
.brief.ahead{border-color:var(--orange)}
.brief-lines{margin:0;padding-left:18px;display:flex;flex-direction:column;gap:6px}
.brief-lines li{font-size:14px;line-height:1.5}
.brief-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(116px,1fr));gap:12px}
.brief-cell{display:flex;flex-direction:column;gap:2px;min-width:0}
.brief-num{font-family:var(--mono);font-weight:600;font-size:17px;color:var(--ink)}
.int{border:1px solid var(--rule);background:var(--sheet-low);padding:12px 16px;display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:12px}
.int-name{display:flex;align-items:center;gap:12px;min-width:0}
.int-ico{
  width:34px;height:34px;flex:none;border:1px solid var(--line);
  display:flex;align-items:center;justify-content:center;
  font-family:var(--mono);font-weight:700;font-size:13px;
}
.int b{font-family:var(--sans);font-weight:600;font-size:15px}
.int-state{font-size:11px}
/* The two surfaces, one line each: the MCP clients above the REST base, their
   labels in one column so both lines start at the same x down the whole list
   rather than stepping in and out with the length of each system's name. */
.int-name{flex:1 1 180px}
/* Its own band under the name, the full width of the card: an endpoint squeezed
   into a column beside the buttons ellipsises to ``localhost:…``, which is the
   one part of a URL nobody needed to be told. */
.int-wires{flex:1 0 100%;min-width:0;display:flex;flex-direction:column;gap:6px;border-top:1px dashed var(--rule);padding-top:10px}
.int-line{display:flex;flex-wrap:wrap;align-items:center;gap:8px;min-width:0}
.int-line>.label{flex:none;width:32px}
/* What a line's surface is done with - the clients on one, the call and the
   vendor's docs on the other - at the far end of it, in one column down the row
   and away from the URL they are about; on a narrow card they wrap under it
   rather than squeezing the URL into an ellipsis. */
.int-acts{display:flex;flex-wrap:wrap;align-items:center;gap:8px;flex:none;margin-left:auto}
/* A URL on this line is pasted into a client, so it is printed whole and wraps
   where it has to: shortened, the one part a reader needed - the path, the port -
   is the part the ellipsis ate. The underline is reserved rather than added on
   hover, since a border appearing under one row's link would move that row's text
   and no other. */
.int-url{
  font-size:12px;color:var(--ink);border-bottom:1px dotted transparent;
  overflow-wrap:anywhere;min-width:0;
}
/* What a client pointed at that URL may do, said before the first refused POST. */
.int-note{font-size:11px;flex:none}
.int-url:hover{color:var(--orange);border-bottom-color:var(--orange)}

/* ---------- meters ---------- */
.meter{height:14px;background:var(--sheet-low);border:1px solid var(--line);position:relative;overflow:hidden}
.meter>span{position:absolute;inset:0 auto 0 0;background:linear-gradient(90deg,#8a5640,#c86a2e)}
.meter.over>span{background:linear-gradient(90deg,#a33,#ff6b5e)}
.bars{display:flex;flex-direction:column;gap:8px}
.bar-row{display:flex;align-items:center;gap:12px}
.bar-row .nm{font-family:var(--mono);font-size:12px;width:110px;flex:none;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.bar-row .val{font-family:var(--mono);font-size:12px;color:var(--ink-soft);width:64px;text-align:right;flex:none}
.track{height:10px;background:var(--sheet-low);border:1px solid rgba(244,233,218,.25);position:relative;overflow:hidden;flex:1}
.track>span{position:absolute;inset:0 auto 0 0;background:var(--ink-soft);opacity:.75}

/* ---------- notices ---------- */
.callout{border-left:4px solid var(--orange);background:var(--sheet-3);padding:14px 16px;font-size:14px;color:var(--ink)}
.callout.bad{border-left-color:var(--error)}
.empty{border:1px dashed var(--line);padding:32px;display:flex;flex-direction:column;gap:14px;align-items:flex-start}
.tbd{
  display:inline-flex;align-items:center;gap:6px;
  font-family:var(--mono);font-size:10px;font-weight:600;letter-spacing:.14em;text-transform:uppercase;
  border:1px dashed var(--line);color:var(--ink-soft);padding:3px 8px;
}
.pulse{width:8px;height:8px;border-radius:9999px;background:var(--orange);display:inline-block;animation:pulse 1.8s ease-in-out infinite}
@keyframes pulse{0%,100%{opacity:1}50%{opacity:.25}}
.spinner{
  width:12px;height:12px;flex:none;border:2px solid var(--line);border-top-color:var(--orange);
  border-radius:9999px;display:inline-block;animation:spin .8s linear infinite;
}
@keyframes spin{to{transform:rotate(360deg)}}
.skel{background:linear-gradient(90deg,var(--sheet-2),var(--sheet-4),var(--sheet-2));background-size:200% 100%;animation:sweep 1.4s ease-in-out infinite;height:96px;border:1px solid var(--rule)}
@keyframes sweep{0%{background-position:200% 0}100%{background-position:-200% 0}}
.fade-in{animation:fade .3s ease-out}
@keyframes fade{from{opacity:0;transform:translateY(6px)}to{opacity:1;transform:none}}

/* ---------- toasts (app.js) ---------- */
.toast-wrap{position:fixed;left:0;right:0;bottom:24px;z-index:200;display:flex;flex-direction:column;align-items:center;gap:10px;pointer-events:none}
.toast{
  pointer-events:auto;display:flex;align-items:center;gap:10px;
  background:var(--sheet-3);border:1px solid var(--line);box-shadow:4px 4px 0 rgba(0,0,0,.45);
  padding:10px 16px;font-family:var(--mono);font-size:12px;color:var(--ink);max-width:min(92vw,620px);
}
.toast .dot{width:8px;height:8px;border-radius:9999px;background:var(--orange);flex:none}
.toast.out{opacity:0;transition:opacity .3s ease-out}
.toast-undo{background:none;border:0;color:var(--orange);font-family:var(--mono);font-size:12px;text-transform:uppercase;cursor:pointer}

/* ---------- the local password dialog app.js opens ---------- */
.gsso-overlay{position:fixed;inset:0;z-index:300;background:rgba(16,11,6,.72);display:flex;align-items:center;justify-content:center;padding:24px}
.gsso-win{width:min(560px,100%);background:var(--sheet);border:1px solid var(--line);box-shadow:8px 10px 0 rgba(0,0,0,.5)}
.gsso-bar{display:flex;align-items:center;justify-content:space-between;padding:10px 14px;border-bottom:1px solid var(--rule);background:var(--sheet-3);font-family:var(--mono);font-size:11px;letter-spacing:.12em;text-transform:uppercase}
.gsso-bar button{background:none;border:0;color:var(--ink-soft);cursor:pointer;font-size:14px}
.gsso-body{padding:24px;display:flex;flex-direction:column;gap:12px}
.gsso-body h4{margin:0;font-family:var(--serif);font-size:24px;font-weight:600}
.gsso-sub{color:var(--ink-soft);font-size:14px}
.gsso-form{display:flex;flex-direction:column;gap:10px}
.gsso-form input{background:var(--sheet-low);border:1px solid var(--line);color:var(--ink);font-family:var(--mono);font-size:13px;padding:10px 12px}
.gsso-form input:focus{outline:none;border-color:var(--orange)}
.gsso-err{display:none;color:var(--error);font-family:var(--mono);font-size:12px}
.gsso-foot{font-size:13px;color:var(--ink-soft)}
/* What just landed on the clipboard, in full: a command a reader is about to run
   in their own shell is read first, so it wraps rather than scrolling sideways,
   and it is selectable for a browser that refused the write. */
.gsso-cmd{
  margin:0;padding:12px;background:var(--sheet-low);border:1px solid var(--rule);
  font-family:var(--mono);font-size:12px;color:var(--ink);
  white-space:pre-wrap;overflow-wrap:anywhere;max-height:40vh;overflow-y:auto;user-select:all;
}
/* The first prompt, printed on the sheet a build ends on: prose rather than a
   command, so it wraps and is read at the width of the card, and selectable for
   a reader who would rather take it by hand than by the button. */
.first-prompt{
  margin:0;padding:12px;background:var(--sheet-low);border:1px dashed var(--rule);
  font-family:var(--mono);font-size:12px;line-height:1.6;color:var(--ink-soft);
  white-space:pre-wrap;overflow-wrap:anywhere;user-select:all;
}
.gsso-spin{width:22px;height:22px;margin:8px auto;border:2px solid var(--line);border-top-color:var(--orange);border-radius:9999px;animation:spin .8s linear infinite}

/* ---------- the sky the sheets are pinned over ---------- */
.sky{position:fixed;inset:0;z-index:0;overflow:hidden;pointer-events:none}
.ship-lane{position:absolute;left:0}
.lane-1{top:clamp(70px,11vh,140px);animation:drift 80s linear infinite}
.lane-2{top:40vh;animation:drift-back 110s linear infinite;animation-delay:-38s}
.lane-3{top:66vh;animation:drift 140s linear infinite;animation-delay:-95s;opacity:.85}
.ship{width:clamp(90px,12vw,150px);height:auto;animation:bob 6s ease-in-out infinite;filter:drop-shadow(0 10px 14px rgba(0,0,0,.5))}
.lane-2 .ship{width:clamp(76px,9.5vw,118px);animation-duration:7s}
.lane-3 .ship{width:clamp(52px,6vw,78px);animation-duration:8.5s;animation-delay:-3s}
@keyframes drift{from{transform:translateX(-200px)}to{transform:translateX(calc(100vw + 200px))}}
@keyframes drift-back{from{transform:translateX(calc(100vw + 200px))}to{transform:translateX(-240px)}}
@keyframes bob{0%,100%{transform:translateY(0) rotate(-1.5deg)}50%{transform:translateY(-12px) rotate(1.5deg)}}

@media(prefers-reduced-motion:reduce){
  .ship-lane,.ship,.pulse,.spinner,.skel,.caret,.fade-in{animation:none}
  .lane-1{left:auto;right:8vw}
  .lane-2{left:5vw}
  .lane-3{left:auto;right:24vw}
  .btn,.btn-cta,.opt{transition:none}
  .btn:hover,.btn-cta:hover,.opt:hover{transform:none}
}

:focus-visible{outline:2px solid var(--orange);outline-offset:2px}

/* ---------- panels: a ruled block of figures, the way the console prints one ---------- */
.pnl{border:1px solid var(--line);background:var(--sheet-2);box-shadow:3px 3px 0 rgba(0,0,0,.35);padding:22px 24px;margin:0 0 26px}
.pnl-head{
  display:flex;justify-content:space-between;align-items:baseline;gap:12px;flex-wrap:wrap;
  border-bottom:1px dashed var(--rule);padding-bottom:11px;margin-bottom:16px;
  font-family:var(--mono);font-size:13px;font-weight:700;letter-spacing:.12em;text-transform:uppercase;
}
.pnl-sub{font-weight:400;font-size:11px;letter-spacing:.12em;text-transform:uppercase;color:var(--ink-soft)}
/* A panel written as a run of siblings - head, heading, prose, a way out. The
   reset on `p` leaves each of those touching the next, so the panel spaces its
   own prose rather than every page that prints one carrying inline margins. */
.pnl>h2+p,.pnl>p+p{margin-top:10px}
.pnl>p+.btn,.pnl>p+.btn-cta{margin-top:18px}
.note{font-size:13px;color:var(--ink-soft);line-height:1.75}
.empty h2{font-family:var(--serif);font-size:30px;font-weight:600}
.empty p{color:var(--ink-soft)}
.empty code{font-family:var(--mono);font-size:12px;color:var(--orange)}
.hidden{display:none}

/* ---------- stat tiles ---------- */
.tiles{display:grid;grid-template-columns:repeat(auto-fit,minmax(170px,1fr));border:1px solid var(--line);margin:0 0 26px}
.tile{padding:16px 18px;border-right:1px solid var(--rule);background:var(--sheet-2)}
.tile:last-child{border-right:none}
@media(max-width:700px){.tile{border-right:none;border-bottom:1px solid var(--rule)}.tile:last-child{border-bottom:none}}
.tile b{display:block;font-family:var(--mono);font-size:28px;font-weight:700;line-height:1.1;font-variant-numeric:tabular-nums}
.tile span{display:block;font-family:var(--mono);font-size:10px;letter-spacing:.12em;text-transform:uppercase;color:var(--ink-soft);margin-top:6px}

/* ---------- horizontal bars (a figure per row) ---------- */
.hbars .hrow{display:grid;grid-template-columns:130px 1fr 74px;gap:12px;align-items:center;padding:6px 0;font-size:12.5px}
@media(max-width:560px){.hbars .hrow{grid-template-columns:96px 1fr 62px;gap:8px}}
.hbars .nm{font-family:var(--mono);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.hbars .track{height:12px;border:1px solid var(--line);background:var(--sheet-low)}
.hbars .fill{height:100%;background:var(--orange);transform-origin:left}
.hbars .val{text-align:right;font-family:var(--mono);font-variant-numeric:tabular-nums;color:var(--ink-soft)}

/* ---------- forms: the boxes an operator types a limit into ---------- */
.adm-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(196px,1fr));gap:18px;margin:4px 0}
.adm-field{display:flex;flex-direction:column;gap:6px}
.adm-field span{font-family:var(--mono);font-size:11px;font-weight:700;letter-spacing:.12em;text-transform:uppercase;color:var(--ink-soft)}
.adm-field em{font-style:normal;font-size:12px;color:var(--ink-soft);line-height:1.6}
.adm-field input,.adm-field select,.adm-field textarea,.adm-row input{
  font-family:var(--mono);font-size:13px;font-variant-numeric:tabular-nums;
  background:var(--sheet-low);color:var(--ink);border:1px solid var(--line);padding:10px 12px;
}
.adm-field textarea{line-height:1.6;resize:vertical}
.adm-field input:focus,.adm-field select:focus,.adm-field textarea:focus,.adm-row input:focus{outline:none;border-color:var(--orange)}
.adm-field input::placeholder,.adm-field textarea::placeholder,.adm-row input::placeholder{color:var(--ink-soft);opacity:.7}
.adm-row{display:flex;gap:12px;align-items:center;flex-wrap:wrap;margin:0 0 6px}
.adm-row input{flex:1;min-width:220px}
.adm-actions{display:flex;align-items:center;gap:16px;flex-wrap:wrap;margin-top:18px;padding-top:14px;border-top:1px dashed var(--rule)}
.adm-note{font-family:var(--mono);font-size:12px;color:var(--ink-soft)}
.adm-note.bad{color:var(--error)}
.adm-editor{border:1px dashed var(--orange);background:var(--sheet-3);padding:16px 18px;margin:16px 0 4px}
.adm-editor h3{font-family:var(--mono);font-size:13px;font-weight:700;margin-bottom:4px;overflow-wrap:anywhere}
.adm-h3{font-family:var(--mono);font-size:10px;letter-spacing:.14em;text-transform:uppercase;color:var(--ink-soft);margin:24px 0 8px}

/* ---------- tables ---------- */
.adm-scroll{overflow-x:auto}
.adm-table{width:100%;border-collapse:collapse;font-size:12.5px}
.adm-table th{
  text-align:left;font-family:var(--mono);font-size:10px;letter-spacing:.12em;text-transform:uppercase;color:var(--ink-soft);
  font-weight:700;padding:0 12px 9px 0;border-bottom:1px solid var(--line);white-space:nowrap;
}
.adm-table td{padding:10px 12px 10px 0;border-bottom:1px solid var(--rule);font-variant-numeric:tabular-nums}
.adm-table td.mono{font-family:var(--mono);overflow-wrap:anywhere}
.adm-inherit{color:var(--ink-soft)}
.adm-buttons{display:flex;gap:10px;justify-content:flex-end;white-space:nowrap}
.adm-badge{font-family:var(--mono);font-size:10px;letter-spacing:.1em;text-transform:uppercase;border:1px solid var(--line);padding:2px 7px;color:var(--ink-soft)}
.adm-badge.on{border-color:var(--orange);color:var(--orange)}
.adm-badge.off{border-color:var(--ink);background:var(--ink);color:var(--sheet)}
.adm-badge.bad{border-color:var(--error);color:var(--error)}
.adm-shot{display:flex;align-items:center;gap:10px;border:1px solid var(--rule);background:var(--sheet-low);padding:7px 10px;margin-top:6px}
.adm-shot .adm-shot-name{font-family:var(--mono);font-size:13px;letter-spacing:.1em;text-transform:uppercase;color:var(--ink-soft)}
a.adm-shot-name{color:var(--orange)}
.adm-shot .adm-badge{margin-left:auto;cursor:help;position:relative}
.adm-badge[data-why]:hover::after{content:attr(data-why);position:absolute;right:0;bottom:calc(100% + 8px);width:280px;
  font-family:var(--sans);font-size:12px;letter-spacing:0;text-transform:none;line-height:1.45;
  color:var(--ink);background:var(--sheet-2);border:1px solid var(--line);padding:8px 10px;z-index:5}
.adm-shot .adm-badge.on{background:rgba(57,255,20,.1)}
.adm-shot .adm-badge.bad{background:rgba(255,107,94,.12)}
.adm-over{color:var(--error);font-weight:600}
.adm-off td.mono{opacity:.55}
.adm-open{cursor:pointer}
.adm-open:hover td{background:var(--sheet-3)}
/* Somebody else's prose, in the shape they typed it: the line breaks carry the
   list or the reproduction steps a fault report was written as. */
.adm-said{white-space:pre-wrap;overflow-wrap:anywhere;font-size:14px;line-height:1.7;max-height:40vh;overflow-y:auto}
.btn.sm{font-size:12px;padding:7px 14px}

/* ---------- consent screens (a client or an agent asking to connect) ---------- */
.consent{max-width:620px;margin:0 auto}
.consent .btn{width:100%;justify-content:center;margin-top:4px}
.consent .adm-field{margin-bottom:14px}
.who{
  border:1px dashed var(--orange);background:var(--sheet-3);padding:13px 15px;margin:0 0 16px;
  font-size:13px;line-height:1.7;overflow-wrap:anywhere;
}
.who b{color:var(--orange);font-weight:600}
.msg{font-size:13px;line-height:1.7;margin-top:14px;min-height:18px;color:var(--ink-soft)}
.msg.err{color:var(--error)}
.msg.ok{color:var(--orange);font-weight:600}

/* ---------- documentation ---------- */
.wiki{display:grid;grid-template-columns:240px 1fr;border:1px solid var(--line);background:var(--sheet-2)}
@media(max-width:760px){.wiki{grid-template-columns:1fr}}
.wiki-nav{border-right:1px solid var(--line);padding:20px 14px}
@media(max-width:760px){.wiki-nav{border-right:none;border-bottom:1px solid var(--line)}}
.wiki-nav h6{font-family:var(--mono);font-size:10px;font-weight:700;letter-spacing:.14em;text-transform:uppercase;color:var(--orange);margin:18px 0 7px}
.wiki-nav h6:first-child{margin-top:0}
.wiki-nav a{display:block;padding:6px 10px;font-size:13px;color:var(--ink-soft);cursor:pointer;border-left:2px solid transparent}
.wiki-nav a:hover{color:var(--ink)}
.wiki-nav a.on{color:var(--ink);font-weight:600;border-left-color:var(--orange);background:var(--sheet-3)}
.wiki-body{padding:28px 32px 32px;min-width:0}
@media(max-width:640px){.wiki-body{padding:22px 20px 26px}}
.wiki-eyebrow{font-family:var(--mono);font-size:10px;font-weight:600;letter-spacing:.2em;text-transform:uppercase;color:var(--orange);margin-bottom:8px}
.wiki-body h2{font-family:var(--serif);font-size:32px;font-weight:600;line-height:1.15;margin-bottom:12px}
.wiki-body h3{font-family:var(--mono);font-size:11px;font-weight:700;letter-spacing:.14em;text-transform:uppercase;margin:24px 0 8px}
.wiki-body p,.wiki-body li{color:var(--ink-soft);font-size:14px;line-height:1.8}
.wiki-body ol,.wiki-body ul{margin:8px 0 8px 20px}
.wiki-body b{color:var(--ink)}
.wiki-body code{font-family:var(--mono);font-size:12.5px;color:var(--orange);background:var(--sheet-low);padding:1px 5px;overflow-wrap:anywhere}
.wiki-body .code{
  display:block;background:var(--sheet-low);border:1px solid var(--line);box-shadow:4px 4px 0 rgba(0,0,0,.35);
  font-family:var(--mono);font-size:12px;line-height:1.7;color:var(--ink);
  padding:14px 16px;margin:14px 0;overflow-x:auto;white-space:pre-wrap;
}
.wiki-body .code code,.wiki-body .code span{background:none;padding:0}
/* Availability copy is swapped after the public console metadata arrives. */
.wiki-body .cli-release[hidden],.wiki-body .cli-noinstall[hidden]{display:none}
.wiki-body .code span{color:var(--blueprint)}
/* a comment inside a command block, so the command itself reads first */
.wiki-body .code .dim{color:var(--ink-soft)}
.wiki-body .callout{margin:16px 0 0}
.wiki-body table{border-collapse:collapse;width:100%;margin:12px 0;font-size:12.5px}
.wiki-body th,.wiki-body td{border:1px solid var(--rule);padding:8px 11px;text-align:left;color:var(--ink-soft);vertical-align:top}
.wiki-body th{color:var(--ink);font-weight:600}
/* The first column names a thing (a variable, a field) and the rest explain it, so only that column
   is held narrow - a width on every header squeezed the column of prose into the narrowest one. */
.wiki-body tr>:first-child{width:240px}
/* ---------- the worked examples (the docs' second half) ---------- */
/* The copy control belongs to the block above it, so it sits tight under it and
   only asserts itself on hover. */
.code-copy{display:flex;justify-content:flex-end;margin:-10px 0 16px}
.code-copy .token-btn{opacity:.45;font-size:10px;padding:3px 8px}
.code-copy .token-btn:hover,.code-copy .token-btn:focus-visible,.code-copy .token-btn.ok{opacity:1}
/* The systems table names each one's variables beside its vendor's docs, so its
   columns are code and narrow. A table that does not scroll on its own drags the
   whole sheet sideways on a phone - so it scrolls where the code blocks do. */
.wiki-body #conn-docs{overflow-x:auto}
.wiki-body .conn-table{min-width:520px}
.wiki-body .conn-table td{font-size:11.5px}
.wiki-body .conn-table tr>:first-child{width:150px}
.wiki-body .conn-table code{background:none;padding:0;color:var(--ink-soft)}
.wiki-pager{display:grid;grid-template-columns:1fr 1fr;gap:12px;margin-top:30px;padding-top:20px;border-top:1px dashed var(--rule)}
@media(max-width:640px){.wiki-pager{grid-template-columns:1fr}}
.pager{display:flex;flex-direction:column;gap:2px;border:1px solid var(--line);padding:12px 14px;cursor:pointer;color:var(--ink)}
.pager:hover{border-color:var(--orange);color:var(--ink)}
.pager.next{text-align:right}
.pager span{font-family:var(--mono);font-size:10px;letter-spacing:.14em;text-transform:uppercase;color:var(--orange)}
.pager b{font-size:13px;font-weight:600}

/* ---------- motion the shared client drives (app.js) ---------- */
.scroll-prog{position:fixed;top:0;left:0;right:0;height:3px;background:var(--action);transform:scaleX(0);transform-origin:left;z-index:300;pointer-events:none}
.ripple{position:absolute;border-radius:50%;background:rgba(244,233,218,.28);transform:scale(0);animation:ripple .6s ease-out;pointer-events:none}
@keyframes ripple{to{transform:scale(2.3);opacity:0}}
.hbars .fill.anim-hold{transform:scaleX(0)}
.hbars .fill.anim-run{animation:fillGrow .8s ease-out both;animation-delay:calc(var(--i,0)*70ms)}
@keyframes fillGrow{from{transform:scaleX(0)}to{transform:scaleX(1)}}
.pop-in{animation:popIn .4s ease-out both;animation-delay:calc(var(--i,0)*45ms)}
@keyframes popIn{from{opacity:0;translate:0 8px}to{opacity:1;translate:0 0}}
.step-in{animation:stepIn .24s ease-out both}
@keyframes stepIn{from{opacity:0;translate:0 8px}to{opacity:1;translate:0 0}}
/* The burst app.js appends to a sheet worth celebrating. Fixed to the viewport
   rather than laid out: seventy pieces inside a flex column are seventy rows of
   gap, which grew the finished sheet by a screenful for as long as they lived. */
.confetti{
  position:fixed;top:-14px;width:7px;height:12px;z-index:400;pointer-events:none;
  animation:confettiFall 1.9s linear forwards;
}
@keyframes confettiFall{from{translate:0 0;rotate:0deg;opacity:1}to{translate:0 102vh;rotate:540deg;opacity:0}}
@media(prefers-reduced-motion:reduce){
  .hbars .fill,.pop-in,.step-in,.ripple{animation:none!important}
  /* Callers check the preference before they print a burst; if one forgets, an
     unanimated piece must not hang at the top of the viewport instead. */
  .confetti{display:none!important}
  /* The konami code is answered with a toast instead; a floor of unanimated logos
     would just be forty logos sitting on the page. */
  .dance-floor{display:none!important}
  /* ``!important`` because the rules these turn off are printed further down the
     sheet, and a media query buys no specificity. */
  .wiz-bar>span,.opt-tip,.tip-note{transition:none!important}
}

/* ---------- the synthesis wizard: a rail of answers beside one sheet at a time ---------- */
.wiz{display:grid;grid-template-columns:minmax(0,1fr);gap:26px;align-items:start}
@media(min-width:900px){.wiz{grid-template-columns:264px minmax(0,1fr);gap:34px}}
.wiz-main{min-width:0}
/* On a phone the rail reads as the recap under the sheet; on a desktop it is the
   map beside it, and stays put while the reader works down a long list. */
.wiz-rail{display:flex;flex-direction:column;gap:14px;min-width:0;order:2}
@media(min-width:900px){.wiz-rail{order:0;position:sticky;top:96px}}
.wiz-prog{display:flex;flex-direction:column;gap:7px}
.wiz-bar{height:6px;border:1px solid var(--line);background:var(--sheet-low);display:block}
.wiz-bar>span{display:block;height:100%;width:var(--fill,0%);background:var(--action);transition:width .2s ease-out}
.wiz-nodes{list-style:none;display:flex;flex-direction:column;margin:0;padding:0;border:1px solid var(--rule);background:var(--sheet-low)}
.wiz-nodes>li{border-bottom:1px dashed var(--rule)}
.wiz-nodes>li:last-child{border-bottom:0}
.wiz-node{
  width:100%;display:flex;align-items:center;gap:11px;padding:9px 12px;
  background:none;border:0;text-align:left;color:var(--ink-soft);font:inherit;
}
button.wiz-node{cursor:pointer}
button.wiz-node:hover{background:var(--sheet-3);color:var(--ink)}
.wiz-node .no{font-family:var(--mono);font-size:11px;font-weight:700;width:20px;flex:none;text-align:center;border:1px solid var(--rule);padding:2px 0}
.wiz-node .nd{display:flex;flex-direction:column;gap:2px;min-width:0;flex:1}
.wiz-node .nm{font-family:var(--mono);font-size:10px;letter-spacing:.12em;text-transform:uppercase}
.wiz-node .ans{font-family:var(--mono);font-size:12px;color:var(--ink);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.wiz-node.done .no{border-color:var(--action);color:var(--action)}
.wiz-node.now{background:var(--sheet-3);color:var(--ink)}
.wiz-node.now .no{background:var(--action);border-color:var(--action);color:var(--on-action)}
.wiz-node.now .nm{color:var(--action)}
.wiz-node .edit{opacity:0;color:var(--action);flex:none}
button.wiz-node:hover .edit,button.wiz-node:focus-visible .edit{opacity:1}

.wiz-card{border:1px solid var(--line);background:var(--sheet-2);box-shadow:4px 4px 0 rgba(0,0,0,.35);padding:22px;display:flex;flex-direction:column;gap:20px;min-width:0}
@media(min-width:768px){.wiz-card{padding:30px 32px}}
/* The way back sits in the same corner of every sheet the wizard prints. */
.wiz-top{display:flex;align-items:center;justify-content:space-between;gap:12px;padding-bottom:14px;border-bottom:1px dashed var(--rule)}
.wiz-back{
  font-family:var(--mono);font-size:12px;letter-spacing:.06em;color:var(--ink);
  background:var(--sheet-3);border:1px solid var(--line);padding:7px 12px;cursor:pointer;white-space:nowrap;
}
.wiz-back:hover{border-color:var(--orange);color:var(--orange)}
.wiz-ask{display:flex;flex-direction:column;gap:6px}
.wiz-ask .h2{display:flex;align-items:center;gap:10px}
.wiz-foot{display:flex;align-items:center;gap:16px;flex-wrap:wrap;padding-top:16px;border-top:1px dashed var(--rule)}
.wiz-keys{font-size:11px}
.wiz-field{display:flex;flex-direction:column;gap:6px;max-width:var(--measure)}
.wiz-input{font-family:var(--mono);font-size:13px;background:var(--sheet-low);color:var(--ink);border:1px solid var(--line);padding:10px 12px;width:100%}
.wiz-input:focus{outline:none;border-color:var(--orange)}
.wiz-input::placeholder{color:var(--ink-soft);opacity:.7}

/* Options as a grid of cards: a flat row of sixty-six systems is a row that
   overflows a phone and cannot be read on a desktop either. */
.opt-set{display:flex;flex-direction:column;gap:12px}
/* A set the filter emptied prints nothing at all, its heading included: the
   generic .hidden cannot say so, .opt-set being the later display. */
.opt-set.hidden{display:none}
.opt-set-head{display:flex;align-items:baseline;gap:10px;flex-wrap:wrap}
.opt-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(158px,1fr));gap:10px}
@media(max-width:420px){.opt-grid{grid-template-columns:1fr}}
.opt-card{position:relative;justify-content:space-between;align-items:center;white-space:normal;padding:12px 14px;min-width:0}
.opt-txt{display:flex;flex-direction:column;gap:3px;min-width:0;text-align:left}
.opt-nm{display:flex;align-items:center;gap:7px;font-size:13px;overflow-wrap:anywhere}
.opt-card small{opacity:.7;line-height:1.4}
.opt-tick{width:14px;height:14px;flex:none;border:1px solid var(--line);position:relative}
.opt-card[aria-pressed="true"] .opt-tick{border-color:var(--on-action);background:var(--on-action)}
.opt-card[aria-pressed="true"] .opt-tick::after{content:'✓';position:absolute;inset:0;display:flex;align-items:center;justify-content:center;font-size:10px;color:var(--action)}
/* A system the fleet has but v1 does not provision: still printed, plainly not
   pickable, and carrying the way into the beta wherever the reader is - the
   set's own note, this tip on hover and focus, and a toast on a tap. */
/* Dimmed through its own text rather than the card: opacity on the card would
   group its children, and the tip over it has to be opaque. */
/* ``opacity:1`` undoes the ``.opt.locked`` fade these cards also match: stacked,
   the two put the name at .41 and made the opaque tip see-through. */
.opt-card.locked{border-style:dashed;color:var(--ink-soft);opacity:1}
.opt-card.locked .opt-txt,.opt-card.locked .opt-tick{opacity:.55}
.opt-card.locked:hover{border-color:var(--line);color:var(--ink-soft)}
/* Inside the card it belongs to rather than over the grid: a tip beside the card
   covered whichever neighbour it reached, and both texts became unreadable. */
.opt-tip{
  position:absolute;inset:0;z-index:5;
  display:flex;align-items:center;justify-content:center;text-align:center;
  border:1px solid var(--orange);background:var(--sheet-2);color:var(--ink);
  font-family:var(--mono);font-size:10.5px;line-height:1.45;padding:7px 9px;
  opacity:0;visibility:hidden;pointer-events:none;transition:opacity .12s ease-out;
}
.opt-card.locked:hover .opt-tip,.opt-card.locked:focus-visible .opt-tip,.opt-card.locked.tip-on .opt-tip{opacity:1;visibility:visible}
.soon-note{font-family:var(--mono);font-size:11px;color:var(--ink-soft)}
.soon-note a{color:var(--orange);text-decoration:underline}

/* A "?" beside a label, and the note it opens: for the words the console asks
   its questions in - a reader who does not know what a connector is should not
   have to leave the step to find out. Hover and focus open it, a tap pins it. */
.tip-host{position:relative;display:inline-flex;vertical-align:middle;margin-left:6px}
.tip-btn{
  width:16px;height:16px;flex:none;padding:0;cursor:help;
  display:flex;align-items:center;justify-content:center;
  border:1px solid var(--line);border-radius:50%;background:transparent;color:var(--ink-soft);
  font-family:var(--mono);font-size:10px;line-height:1;
}
.tip-btn:hover,.tip-host.tip-on .tip-btn{border-color:var(--orange);color:var(--orange)}
.tip-note{
  position:absolute;top:calc(100% + 7px);left:0;z-index:30;
  width:max-content;max-width:min(300px,calc(100vw - 48px));
  border:1px solid var(--orange);background:var(--sheet-2);color:var(--ink);
  font-family:var(--mono);font-size:11px;line-height:1.5;padding:9px 11px;text-align:left;
  opacity:0;visibility:hidden;pointer-events:none;transition:opacity .12s ease-out;
}
.tip-host:hover .tip-note,.tip-btn:focus-visible+.tip-note,.tip-host.tip-on .tip-note{opacity:1;visibility:visible}

/* Waiting on a real build: what is being written, and how long it has taken. */
.build-clock{display:flex;align-items:baseline;gap:10px;border:1px solid var(--rule);background:var(--sheet-low);padding:12px 14px}
.build-clock b{font-family:var(--mono);font-size:26px;font-variant-numeric:tabular-nums;color:var(--action)}
/* What the company is busy doing meanwhile: flavour, so it reads quieter than
   the elapsed clock and gives way to it when the row runs out of room. */
.build-clock .build-quip{margin-left:auto;min-width:0;font-size:12.5px;color:var(--ink-soft);text-align:right;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* A phone has no room for both on one line, and half a joke behind an ellipsis
   is worse than none: the line drops under the clock and reads in full. */
@media(max-width:560px){
  .build-clock{flex-wrap:wrap}
  .build-clock .build-quip{margin-left:0;flex-basis:100%;text-align:left;white-space:normal}
}
.build-list{list-style:none;margin:0;padding:0;display:grid;grid-template-columns:repeat(auto-fill,minmax(190px,1fr));gap:8px}
.build-list li{display:flex;align-items:center;gap:9px;border:1px solid var(--rule);background:var(--sheet-low);padding:9px 12px;min-width:0}
.build-list b{font-family:var(--sans);font-size:13px;font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.build-list .mono{margin-left:auto;font-size:10.5px}

.wiz-done-head{display:flex;align-items:center;gap:16px;flex-wrap:wrap}
.tok-head{display:flex;align-items:baseline;justify-content:space-between;gap:10px;flex-wrap:wrap}
.tok-head .tbd{border-color:var(--orange);color:var(--orange)}
.tok-line{display:flex;align-items:center;gap:10px;flex-wrap:wrap}
.tok-line .tok{flex:1 1 240px}
/* A door out of the token sheet, asked once before it is taken. */
[data-guard="armed"]{outline:2px dashed var(--error);outline-offset:3px}
.spec-edit div{justify-content:space-between}
.spec-edit .v{flex:1;overflow-wrap:anywhere}
.int-id{min-width:0}

.stack-sm{display:flex;flex-direction:column;gap:6px}
.stack-xs{display:flex;flex-direction:column;gap:2px}
.row-tight{display:flex;align-items:center;gap:8px;flex-wrap:wrap}
/* named for a screen reader, printed for nobody */
.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}

/* ---------- ↑↑↓↓←→←→BA ---------- */
/* Fixed and pointer-transparent: the logos dance over the sheet without moving a
   line of it, and era.js takes the whole floor away after a few seconds. */
.dance-floor{position:fixed;inset:0;z-index:500;overflow:hidden;pointer-events:none}
.dance{position:absolute;animation:dance 1.4s ease-in-out infinite;filter:drop-shadow(0 6px 10px rgba(0,0,0,.45))}
@keyframes dance{
  0%,100%{transform:translateY(0) rotate(-14deg) scale(1)}
  25%{transform:translateY(-24px) rotate(10deg) scale(1.12)}
  50%{transform:translateY(0) rotate(14deg) scale(1)}
  75%{transform:translateY(-14px) rotate(-10deg) scale(1.08)}
}

/* The note a driven browser is shown on the landing sheet. */
.agent-note{display:flex;flex-direction:column;gap:12px;padding:24px 0}

/* ---------- the runner on the 404 sheet ---------- */
.run-head{display:flex;align-items:baseline;justify-content:space-between;gap:12px;flex-wrap:wrap}
.run-scores{display:flex;gap:16px}
.run-scores b{font-family:var(--mono);color:var(--action);font-weight:600}
/* Fixed aspect rather than a height: the canvas is redrawn to its own box, and a
   game the width of a desktop sheet and 200px tall is unplayable on a phone. */
.runner{
  display:block;width:100%;aspect-ratio:9/2;min-height:150px;
  border:1px solid var(--rule);background:var(--sheet-low);touch-action:manipulation;cursor:pointer;
}
.runner:focus-visible{outline:2px solid var(--action);outline-offset:2px}

/* ---------- the API viewer (see viewer.html) ---------- */
/* The three choices a read is: which environment, which of its systems, which of
   that system's GETs. Side by side once there is room, stacked on a phone. */
.vw-pick{display:grid;grid-template-columns:1fr;gap:16px}
@media(min-width:768px){.vw-pick{grid-template-columns:repeat(3,minmax(0,1fr))}}
/* The parameters that route takes, which is anything from none to a dozen. */
.vw-args{display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:14px}
.vw-body{
  font-family:var(--mono);font-size:12.5px;line-height:1.7;
  border:1px solid var(--rule);background:var(--sheet-low);
  padding:14px 16px;margin:0;max-height:62vh;overflow:auto;
  white-space:pre-wrap;overflow-wrap:anywhere;
}
/* A record is deep, so the body is a tree the reader folds their way into: each
   level is indented by its own border, which is also the line to fold on. */
.js-node{border-left:1px solid var(--rule);margin-left:6px;padding-left:10px}
.js-node>summary{cursor:pointer;list-style:none}
.js-node>summary::before{content:'▸';display:inline-block;width:1em;color:var(--action)}
.js-node[open]>summary::before{content:'▾'}
.js-row{padding-left:1em}
.js-key{color:var(--blueprint)}
.js-str{color:var(--ink)}
.js-num{color:var(--action)}
.js-null{color:var(--ink-soft)}
/* A listed record opens where it sits (see explorer.html): the row is the handle,
   so it says so on hover and the record unfolds under it. */
.ex-row{cursor:pointer}
.ex-row:hover td{background:var(--sheet-low)}
.ex-file{max-width:100%;max-height:520px;border:1px solid var(--rule);border-radius:6px;background:var(--sheet-low)}
/* A PDF is paged by the browser's own reader, which needs room to be one. */
.ex-frame{width:100%;height:70vh;border:1px solid var(--rule);border-radius:6px;background:var(--sheet-low)}
/* A document read out of its package: pages, sheets or slides, each printed
   under the name the package gave it, in the sheet the rest of the page is. */
.ex-doc{border:1px solid var(--rule);border-radius:6px;background:var(--sheet);
  padding:14px 16px;max-height:70vh;overflow:auto}
.ex-part+.ex-part{margin-top:18px;border-top:1px solid var(--rule);padding-top:14px}
.ex-part>h4{margin:0 0 10px;font-size:12px;letter-spacing:.08em;text-transform:uppercase;color:var(--ink-soft)}
.ex-doc p{margin:0 0 8px;line-height:1.6}
.ex-doc p.ex-lead{font-weight:600;font-size:15px}
.ex-doc table{border-collapse:collapse;margin:0 0 10px;font-size:12.5px;width:100%}
.ex-doc td{border:1px solid var(--rule);padding:4px 8px;vertical-align:top;overflow-wrap:anywhere}
.ex-doc tr:first-child td{background:var(--sheet-low);font-weight:600}
.ex-cut{color:var(--ink-soft);font-size:12px}

/* ---------- the eggs (see eggs.js) ---------- */
/* Dinnerbone's name tag. `inline-block` because a rotated inline box turns
   nothing; the nav row is laid out the same either way, so nothing moves. */
.egg-flip{display:inline-block;rotate:180deg}
/* Half the screen, over the sheet rather than in it: fixed and
   pointer-transparent, so no line of the page moves and nothing under it stops
   being clickable. */
.egg-game{position:fixed;left:0;right:0;bottom:0;height:50vh;z-index:450;pointer-events:none}
.egg-game canvas{display:block;width:100%;height:100%}

/* ---------- the generation diagram (the why-Era sheet) ---------- */
/* Three bands - the graph, the projection, the systems it lands in - that stack
   on a phone and sit side by side once there is room for all three. The graph
   itself is an SVG with a small viewBox, so its labels stay readable at the
   width a phone gives it instead of shrinking with the drawing. */
.gen{display:grid;grid-template-columns:1fr;gap:18px;align-items:center}
@media(min-width:900px){.gen{grid-template-columns:minmax(0,1fr) 76px minmax(0,1fr);gap:20px}}
.gen-col{display:flex;flex-direction:column;gap:10px;min-width:0}
.gen-graph{display:block;width:100%;height:auto;border:1px solid var(--rule);background:var(--sheet-low)}
.gen-fan{
  display:flex;flex-direction:column;align-items:center;gap:6px;color:var(--action);
  font-family:var(--mono);font-size:10px;letter-spacing:.12em;text-transform:uppercase;text-align:center;
}
.gen-fan span{display:flex;flex-direction:column;align-items:center;gap:4px}
.gen-fan i{font-style:normal;font-size:22px;line-height:1}
.gen-fan .wide{display:none}
@media(min-width:900px){.gen-fan .wide{display:flex}.gen-fan .narrow{display:none}}
.gen-key{
  display:flex;flex-wrap:wrap;gap:6px 18px;
  font-family:var(--mono);font-size:10px;letter-spacing:.08em;text-transform:uppercase;color:var(--ink-soft);
}
.gen-key span{display:flex;align-items:center;gap:8px}
.gen-key i{width:26px;height:0;border-top:1px solid var(--rule)}
.gen-key i.dashed{border-top-style:dashed;border-top-color:var(--action);opacity:.7}
.gen-sys{display:flex;flex-direction:column;border:1px solid var(--rule);background:var(--sheet-low)}
.gen-sys div{
  display:flex;flex-wrap:wrap;align-items:baseline;gap:2px 10px;
  padding:8px 12px;border-bottom:1px dashed var(--rule);
}
.gen-sys div:last-child{border-bottom:none}
.gen-sys b{font-family:var(--mono);font-size:12px;font-weight:600;min-width:88px}
.gen-sys span{font-family:var(--mono);font-size:11px;color:var(--ink-soft);overflow-wrap:anywhere}
