/* Try Tesryn — the public demo. One dark instrument surface, phone first.

   It shows engineering work that actually ran: assets/demo-pack.json is generated by
   tools/demo-pack.py out of real `industrial run` output. Nothing on this page is written by hand,
   so the styling's job is to make real numbers, real quotes and real refusals easy to read on a
   phone held at arm's length in a loud room.

   Variables come from assets/styles.css (the site's own set). Dark throughout: .demo is a band. */

.demo-page{background:var(--void);color:var(--text)}
.demo-page .site-foot{border-top:1px solid var(--rule)}

/* ── the run: scenario, ask, go ─────────────────────────────────────────── */
.demo{padding:0 0 clamp(3rem,8vw,6rem)}
.demo .wrap{max-width:60rem}

.demo-pick{margin:0 0 clamp(1.5rem,4vw,2.5rem)}
.demo-pick>.k{display:block;font-family:var(--mono);font-size:.72rem;letter-spacing:.18em;
  text-transform:uppercase;color:var(--muted);margin:0 0 .6rem}
/* A grid item's default min-width is auto, so a long title refuses to be narrower than itself and
   pushes the page sideways at a doubled text size. Every item here is allowed to be narrow. */
.demo-scenarios{display:grid;gap:.6rem;grid-template-columns:minmax(0,1fr);margin:0;padding:0;list-style:none}
.demo-scenarios>li{min-width:0}
.demo-scenarios .t,.demo-scenarios .s{overflow-wrap:break-word}
@media (min-width:44rem){.demo-scenarios{grid-template-columns:minmax(0,1fr) minmax(0,1fr)}}
.demo-scenarios button{
  display:block;width:100%;min-width:0;max-width:100%;text-align:left;cursor:pointer;
  background:var(--panel);border:1px solid var(--rule);border-radius:12px;
  color:var(--text);font:inherit;padding:.8rem .9rem;min-height:var(--target-comfort,3rem);
  transition:border-color 160ms ease,background 160ms ease,transform 160ms ease;
}
.demo-scenarios button:hover{background:var(--panel-2);border-color:var(--rule-lit)}
.demo-scenarios button[aria-pressed="true"]{border-color:var(--flare);background:var(--panel-2)}
.demo-scenarios .t{display:block;font-weight:600;font-size:1rem;line-height:1.3}
.demo-scenarios .s{display:block;color:var(--muted);font-size:.85rem;line-height:1.45;margin-top:.2rem}
.demo-scenarios .o{display:inline-block;margin-top:.45rem;font-family:var(--mono);font-size:.68rem;
  letter-spacing:.1em;text-transform:uppercase;padding:.15rem .45rem;border-radius:999px;
  border:1px solid currentColor}
.o-ok{color:#5FD39A}.o-info{color:var(--glow)}.o-none{color:#FF8A8A}

/* the request, as the customer wrote it */
.demo-ask{background:var(--panel);border:1px solid var(--rule);border-left:3px solid var(--flare);
  border-radius:0 12px 12px 0;padding:1rem 1.1rem;margin:0 0 1.2rem}
.demo-ask .k{display:block;font-family:var(--mono);font-size:.7rem;letter-spacing:.16em;
  text-transform:uppercase;color:var(--muted);margin:0 0 .5rem}
.demo-ask p{margin:0;font-size:1.02rem;line-height:1.6}

.demo-go{display:flex;flex-wrap:wrap;gap:.6rem;align-items:center;margin:0 0 1.4rem}
.demo-go .btn{min-height:var(--target-comfort,3rem)}
.demo-elapsed{font-family:var(--mono);font-size:.78rem;color:var(--muted);
  font-variant-numeric:tabular-nums}
.demo-elapsed b{color:var(--glow);font-weight:500}

/* ── stages ─────────────────────────────────────────────────────────────── */
.demo-stages{list-style:none;margin:0;padding:0;display:grid;gap:.85rem}
.stage{
  position:relative;background:var(--panel);border:1px solid var(--rule);border-radius:14px;
  padding:1rem 1.05rem;overflow:hidden;
}
/* A stage that hasn't run yet is drawn quietly, not dimmed. Fading the whole card with opacity took
   its title to 2.25:1 (measured by tools/ui-check.mjs) — and it hid the one thing worth reading
   before you press Run: the list of what is about to happen. So the card goes hollow and its spine
   goes dashed, and every word in it stays at full contrast. */
.stage[data-state="waiting"]{background:transparent;border-style:dashed}
.stage[data-state="waiting"] .stage-t{color:var(--muted)}
.stage[data-state="running"]{border-color:var(--flare)}
.stage[data-state="done"]{border-color:var(--rule-lit)}
.stage::before{content:"";position:absolute;left:0;top:0;bottom:0;width:2px;background:var(--rule)}
.stage[data-state="waiting"]::before{background:transparent}
.stage[data-state="running"]::before{background:var(--flare)}
.stage[data-state="done"]::before{background:linear-gradient(var(--deep),var(--flare))}

/* At a doubled text size the status word ("waiting", "running") is as wide as the title, so the
   row wraps instead of pushing the card past the viewport. */
.stage-head{display:flex;flex-wrap:wrap;gap:.35rem .7rem;align-items:baseline;margin:0}
.stage-n{font-family:var(--mono);font-size:.72rem;color:var(--muted);flex:none;padding-top:.15rem}
.stage-t{font-size:1.02rem;font-weight:600;margin:0;line-height:1.3;flex:1 1 8rem;min-width:0;overflow-wrap:break-word}
.stage-pip{flex:0 1 auto;font-family:var(--mono);font-size:.68rem;letter-spacing:.08em;
  text-transform:uppercase;color:var(--muted)}
.stage[data-state="done"] .stage-pip{color:#5FD39A}
.stage[data-state="running"] .stage-pip{color:var(--flare)}
.stage-body{margin:.7rem 0 0}
.stage[data-state="waiting"] .stage-body{display:none}
/* A stage used to open with a paragraph. Measured on a phone, the demo ran to 2083 words, and a
   paragraph is the thing nobody reads standing up in a loud room. What is left: a one-line label
   between sections, and one small note at the foot of a stage where the point is something the
   figures cannot say. */
.stage-sub{margin:1rem 0 .5rem;font-family:var(--mono);font-size:.68rem;letter-spacing:.14em;
  text-transform:uppercase;color:var(--muted)}
.stage-sub:first-child{margin-top:0}
.stage-note{margin:.9rem 0 0;font-size:.78rem;line-height:1.5;color:var(--muted);
  padding-left:.7rem;border-left:2px solid var(--rule-lit)}
.stage-where{margin:0 0 .7rem;font-size:.9rem;line-height:1.5;color:var(--muted)}
.stage-where strong{color:var(--glow);font-weight:600}

/* Long evidence is clamped to three lines and opens on a tap. The first clause is almost always
   the finding; the rest is the detail behind it, and it can wait until somebody wants it. */
.ruled .r-w,.checks .ck-w,.says li{
  display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:3;overflow:hidden}
.clamp-open .r-w,.clamp-open .ck-w,.clamp-open li{-webkit-line-clamp:unset;overflow:visible}
.more-line{display:block;margin:.5rem 0 0;font-family:var(--mono);font-size:.68rem;
  letter-spacing:.1em;text-transform:uppercase;color:var(--flare);background:none;border:0;
  padding:.4rem 0;cursor:pointer;min-height:var(--target-min,2.75rem);text-align:left}

/* a headline number or two inside a stage */
.stage-nums{display:flex;flex-wrap:wrap;gap:.5rem .9rem;margin:0 0 .8rem;padding:0;list-style:none}
.stage-nums li{display:flex;flex-direction:column;min-width:4.5rem}
.stage-nums .n{font-family:var(--mono);font-size:1.35rem;line-height:1.1;color:var(--glow);
  font-variant-numeric:tabular-nums}
.stage-nums .l{font-size:.72rem;color:var(--muted);letter-spacing:.04em;margin-top:.15rem}
.stage-nums .n-bad{color:#FF8A8A}
.stage-nums .n-ok{color:#5FD39A}

/* field rows: what was read, and the words it came from */
.fields{list-style:none;margin:0;padding:0;display:grid;gap:.5rem}
.fields li{border-top:1px solid var(--rule);padding:.5rem 0 0}
.fields li:first-child{border-top:0;padding-top:0}
.fields .f-top{display:flex;gap:.6rem;align-items:baseline;flex-wrap:wrap}
.fields .f-l{font-size:.92rem;flex:1 1 9rem;min-width:0}
.fields .f-v{font-family:var(--mono);font-size:.92rem;color:var(--glow);
  font-variant-numeric:tabular-nums;white-space:nowrap}
.fields .f-from{display:block;margin:.3rem 0 0;font-size:.82rem;color:var(--muted);
  line-height:1.5;border-left:2px solid var(--rule-lit);padding-left:.6rem}
.fields .f-from::before{content:"\201C"}
.fields .f-from::after{content:"\201D"}
.fields.fields-unknown .f-v{color:var(--muted)}

/* the search space, as 60 cells that resolve */
.space{display:grid;gap:3px;grid-template-columns:repeat(12,1fr);margin:0 0 .9rem}
.space i{display:block;aspect-ratio:1;border-radius:2px;background:var(--rule);
  transition:background 240ms ease}
.space i[data-v="feasible"]{background:var(--flare)}
.space i[data-v="chosen"]{background:var(--glow);box-shadow:0 0 0 2px rgba(255,180,84,.35)}
.space-key{display:flex;flex-wrap:wrap;gap:.35rem .9rem;margin:0 0 .9rem;padding:0;list-style:none;
  font-size:.76rem;color:var(--muted)}
.space-key li{display:flex;align-items:center;gap:.35rem}
.space-key i{width:9px;height:9px;border-radius:2px;background:var(--rule);flex:none}
.space-key .kf i{background:var(--flare)}
.space-key .kc i{background:var(--glow)}

/* ruled out, with the engineering reason */
.ruled{list-style:none;margin:0;padding:0;display:grid;gap:.6rem}
.ruled li{border-left:2px solid #6B3030;padding:.1rem 0 .1rem .7rem}
.ruled .r-p{font-family:var(--mono);font-size:.8rem;color:var(--text);word-break:break-word}
.ruled .r-w{display:block;font-size:.85rem;color:var(--muted);line-height:1.55;margin-top:.2rem}
.ruled .r-k{font-family:var(--mono);font-size:.68rem;letter-spacing:.08em;text-transform:uppercase;
  color:#FF8A8A;margin-left:.4rem}

/* the configuration that was chosen */
.chosen{list-style:none;margin:0 0 .9rem;padding:0;display:grid;gap:.45rem}
.chosen li{display:flex;gap:.7rem;align-items:baseline;border-top:1px solid var(--rule);
  padding-top:.45rem;flex-wrap:wrap}
.chosen li:first-child{border-top:0;padding-top:0}
.chosen .c-r{font-family:var(--mono);font-size:.7rem;letter-spacing:.08em;text-transform:uppercase;
  color:var(--muted);flex:0 0 6.5rem}
.chosen .c-n{font-size:.94rem;flex:1 1 10rem;min-width:0;word-break:break-word}
.chosen .c-n b{font-weight:600}
.chosen .c-q{font-family:var(--mono);font-size:.8rem;color:var(--muted)}

/* the cell plan, drawn from the run's own coordinates */
.plan{margin:0 0 .9rem;background:#0B0C10;border:1px solid var(--rule);border-radius:10px;
  padding:.5rem}
.plan svg{display:block;width:100%;height:auto}
.plan-key{display:flex;flex-wrap:wrap;gap:.35rem .9rem;margin:.5rem 0 0;padding:0;list-style:none;
  font-size:.74rem;color:var(--muted)}
.plan-key li{display:flex;align-items:center;gap:.35rem}
.plan-key i{width:14px;height:0;border-top:2px solid var(--flare);flex:none}
.plan-key .kr i{border-top-style:dashed;border-top-color:var(--glow)}
.plan-key .kg i{border-top-color:#5FD39A}

/* a check, with its grounds */
.checks{list-style:none;margin:0;padding:0;display:grid;gap:.6rem}
.checks li{background:var(--panel-2);border:1px solid var(--rule);border-radius:10px;padding:.65rem .75rem}
.checks .ck-top{display:flex;gap:.6rem;align-items:baseline;flex-wrap:wrap}
.checks .ck-n{font-size:.92rem;font-weight:600;flex:1 1 8rem}
.checks .ck-w{display:block;font-size:.85rem;color:var(--muted);line-height:1.55;margin-top:.35rem}
.badge{font-family:var(--mono);font-size:.68rem;letter-spacing:.09em;text-transform:uppercase;
  padding:.16rem .45rem;border-radius:999px;border:1px solid currentColor;flex:none;white-space:nowrap}
.b-pass{color:#5FD39A}.b-fail{color:#FF8A8A}.b-unknown{color:var(--glow)}
.b-info{color:var(--muted)}.b-stated{color:var(--glow)}

/* buy list: each line with the page it was read off */
.bom{list-style:none;margin:0;padding:0;display:grid;gap:.75rem}
.bom>li{border-top:1px solid var(--rule);padding:.7rem 0 0}
.bom>li:first-child{border-top:0;padding-top:0}
.bom .b-top{display:flex;gap:.6rem;align-items:baseline;flex-wrap:wrap}
.bom .b-role{font-family:var(--mono);font-size:.68rem;letter-spacing:.08em;text-transform:uppercase;
  color:var(--muted);flex:0 0 100%}
.bom .b-name{font-size:.98rem;font-weight:600;flex:1 1 10rem;min-width:0;word-break:break-word}
.bom .b-qty{font-family:var(--mono);font-size:.82rem;color:var(--muted)}
.bom .b-code{font-family:var(--mono);font-size:.78rem;color:var(--glow);word-break:break-all}
.cite{margin:.5rem 0 0;background:#0B0C10;border:1px solid var(--rule);border-radius:8px;
  padding:.55rem .65rem}
.cite .q{margin:0;font-family:var(--mono);font-size:.8rem;line-height:1.55;color:var(--text);
  word-break:break-word}
.cite .m{margin:.4rem 0 0;font-size:.76rem;color:var(--muted);line-height:1.5}
.cite .m a{color:var(--flare)}

/* refusals and open questions: the honest half */
.says{list-style:none;margin:0;padding:0;display:grid;gap:.55rem}
.says li{font-size:.9rem;line-height:1.6;color:var(--muted);border-left:2px solid var(--glow);
  padding-left:.7rem}
.says.says-q li{border-left-color:var(--flare);color:var(--text)}

/* the verdict */
.verdict{background:var(--panel-2);border:1px solid var(--rule-lit);border-radius:14px;
  padding:1.05rem 1.1rem;margin:1rem 0 0}
.verdict .v-k{font-family:var(--mono);font-size:.7rem;letter-spacing:.16em;text-transform:uppercase;
  color:var(--muted);margin:0 0 .5rem}
.verdict .v-s{font-family:var(--mono);font-size:1.05rem;color:var(--glow);margin:0 0 .5rem;
  word-break:break-word}
.verdict p{margin:0 0 .6rem;font-size:.94rem;line-height:1.6;color:var(--muted)}
.verdict .actions{margin:.9rem 0 0}

/* provenance: the hashes, so a claim can be traced */
.prov{margin:1.2rem 0 0;font-size:.78rem;color:var(--muted);line-height:1.6}
.prov summary{cursor:pointer;color:var(--muted);min-height:var(--target-min,2.75rem);
  display:flex;align-items:center}
.prov ul{list-style:none;margin:.5rem 0 0;padding:0;display:grid;gap:.3rem}
.prov code{font-family:var(--mono);font-size:.74rem;color:var(--muted);word-break:break-all}

/* a failure that is the page's, not the engineering's */
.demo-fail{background:var(--panel);border:1px solid #6B3030;border-radius:12px;padding:1rem;
  margin:1rem 0 0}
.demo-fail p{margin:0 0 .6rem;font-size:.94rem;line-height:1.6}
.demo-fail p:last-child{margin-bottom:0}

/* ── sticky action bar, phone only ──────────────────────────────────────── */
.demo-bar{position:sticky;bottom:0;z-index:12;display:flex;gap:.5rem;
  padding:.6rem var(--gutter,1rem) calc(.6rem + env(safe-area-inset-bottom,0px));
  margin:1.5rem calc(-1 * var(--gutter,1rem)) 0;
  background:linear-gradient(rgba(8,9,11,0),rgba(8,9,11,.96) 38%);
  border-top:1px solid var(--rule)}
.demo-bar .btn{flex:1 1 0;min-height:var(--target-comfort,3rem);text-align:center;
  display:flex;align-items:center;justify-content:center;font-size:.94rem}
@media (min-width:52rem){.demo-bar{position:static;background:none;border-top:0;margin-top:1.8rem;
  padding-left:0;padding-right:0}.demo-bar .btn{flex:0 0 auto}}

/* ── narrow phones ──────────────────────────────────────────────────────── */
@media (max-width:26rem){
  .space{grid-template-columns:repeat(10,1fr)}
  .stage{padding:.85rem .85rem}
  .chosen .c-r{flex:0 0 100%}
  .stage-nums{gap:.5rem .7rem}
  .stage-nums .n{font-size:1.2rem}
}

/* motion: only ever an entrance, and only if it was asked for */
@media (prefers-reduced-motion:no-preference){
  .stage[data-state="done"] .stage-body,.stage[data-state="running"] .stage-body{
    animation:stage-in 320ms cubic-bezier(.22,1,.36,1) both}
  .space i{transition:background 240ms ease}
}
html[data-motion="reduce"] .stage-body{animation:none!important}
@keyframes stage-in{from{opacity:0;transform:translateY(6px)}to{opacity:1;transform:none}}

[hidden]{display:none!important}

/* ── unknowns, as chips: a long list of "we don't know this" has to stay glanceable ── */
.chips-list{display:flex;flex-wrap:wrap;gap:.35rem;margin:0 0 .3rem;padding:0;list-style:none}
.chips-list li{font-size:.78rem;line-height:1.4;color:var(--muted);background:var(--panel-2);
  border:1px solid var(--rule);border-radius:999px;padding:.28rem .6rem}

/* the disclosures inside a stage read as controls, not as footnotes */
.stage .prov{margin:.7rem 0 0}
.stage .prov>summary{color:var(--flare);font-size:.86rem;padding:.25rem 0;
  min-height:var(--target-min,2.75rem)}
.stage .prov>summary::marker{color:var(--muted)}
.stage .prov>ul{margin-top:.6rem}

/* the demo's own hero is shorter than the marketing ones: the job list has to be near the top on
   a phone, because that is the first thing a person at a conference needs to touch. */
/* The stage is the page, so it has to be on the first screen of a phone. The hero is one line and
   the smallest padding the fade can resolve in; everything else is the film. */
.demo-page .hero-sm{padding-top:clamp(1rem,4vw,2rem);padding-bottom:clamp(2.2rem,8vw,3.2rem)}
.demo-page .hero-sm h1{font-size:clamp(1.6rem,6.4vw,2.6rem);margin-bottom:0}
.demo-page .hero-sm .lede{font-size:clamp(.96rem,3.6vw,1.1rem);margin-bottom:.8rem}
.demo-page .demo{padding-top:clamp(.8rem,3vw,1.6rem)}

/* The bar sat over the bottom of the stage. The film ends with its own way on, so this one waits
   at the end of the section instead of floating over the thing it is interrupting. */
.demo-page .demo-bar{position:static;background:none;border-top:0;flex-wrap:wrap;
  margin:1.6rem 0 0;padding-left:0;padding-right:0}
.demo-page .demo-bar .btn{flex:1 1 10rem}
@media (min-width:52rem){.demo-page .demo-bar .btn{flex:0 0 auto}}
@media (max-width:40rem){
  .demo-page .hero-sm .statusline{font-size:.74rem}
  .demo{padding-top:1rem}
}

/* ── the whole page is dark, so the sections below the demo are too ─────────
   styles.css paints a normal <section> for the light reading surface: --ink-muted body copy and an
   --ember section tag, both of which land at about 3:1 on the void. The demo page sets its own dark
   background, so it has to state the colours that go with it rather than inherit the paper ones.
   Measured with tools/ui-check.mjs: 2.96:1 and 3.28:1 before, 7.2:1 and 6.9:1 after. */
.demo-page section{color:var(--text)}
.demo-page section p,.demo-page section li{color:var(--muted)}
.demo-page section h2,.demo-page section h3,.demo-page section strong{color:var(--text)}
.demo-page .section-tag{color:var(--flare)}
.demo-page section + section{border-top-color:var(--rule)}
.demo-page .btn-ghost{background:rgba(255,255,255,.03);border-color:var(--rule);color:var(--text)}
.demo-page .btn-primary{background:var(--flare);color:#0A0B0D}

/* the stage's own heading and its number are text, and have to read as text */
.stage-t{color:var(--text)}
.stage-n{color:var(--muted)}

[hidden]{display:none!important}

/* On a phone the stage is as tall as the conference page's (summit.css): the film has a tall-screen camera, and a
   208 px strip made the cell a thumbnail. The last card, where somebody types, is as tall as it needs. */
@media (max-width:61.99rem){
  .demo-page .film-scene{height:clamp(18.5rem,54vh,26rem)}
  .demo-page .film-scene:has(.film-your-turn){height:auto;min-height:clamp(18.5rem,54vh,26rem)}
}
/* On a laptop or a desk the film's stage is as tall as the first screen allows under the page's own
   header and hero, and its drawings are drawn to that height; the column stays 60rem, which is the
   reading width the long version under it wants. The last card lays itself out wide (film.css). */
@media (min-width:62rem){
  /* the title is one line here (the hero's picture keeps to the right half), so the stage starts higher */
  .demo-page .hero-sm h1{max-width:none}
  .demo-page .film{--film-h:clamp(23rem,calc(100vh - 30rem),36rem)}
  .demo-page .film-scene{height:var(--film-h)}
  .demo-page .film-scene:has(.film-your-turn){height:auto;min-height:var(--film-h)}
  .demo-page .film-elev{max-height:calc(var(--film-h) - 4.5rem)}
  .demo-page .film-mag{width:min(100%,calc(var(--film-h) - 5rem))}
}
