/* AuroraView.
   Laid out like a model demo page: a lifted panel holding "what this is and how
   to use it" on the left and the canvas you actually work on at the right.
   The rule that matters here is legibility — body copy is normal sentence case
   at a normal size in a colour you can actually read, panels are lifted off the
   page rather than drawn with hairlines, and there is exactly one bright thing
   on the screen: the Run button. */
/* The pool site's pair, self-hosted rather than pulled from Google — this page
   promises it hands nothing to a third party, and a webfont request is a
   third-party request. Both files are the latin subsets, both variable, so one
   file covers every weight the page uses. */
@font-face{
  font-family:'Cormorant Garamond';
  src:url('/fonts/cormorant-garamond-latin.woff2') format('woff2');
  font-weight:300 700;font-style:normal;font-display:swap;
}
@font-face{
  font-family:'DM Sans';
  src:url('/fonts/dm-sans-latin.woff2') format('woff2');
  font-weight:100 1000;font-style:normal;font-display:swap;
}

:root{
  --ink:#06090C;            /* page */
  --panel:#0C1116;          /* lifted panel */
  --panel-2:#111820;        /* card inside a panel */
  --panel-3:#161F28;        /* input wells */
  --line:rgba(233,237,241,.11);
  --line-2:rgba(233,237,241,.20);

  --cyan:#41E6D4;
  --cyan-dim:#1F7F76;
  --copper:#E09A5C;

  --text:#E9EDF1;                    /* headings, emphasis */
  --text-2:rgba(233,237,241,.76);    /* body copy */
  --text-3:rgba(233,237,241,.54);    /* hints, captions — the floor */

  --sans:'DM Sans',ui-sans-serif,system-ui,-apple-system,'Segoe UI',Roboto,Helvetica,Arial,sans-serif;
  --head:'Cormorant Garamond',ui-serif,Georgia,'Times New Roman',serif;
  --mono:ui-monospace,SFMono-Regular,Menlo,'JetBrains Mono','Cascadia Mono',Consolas,monospace;
  --pad:clamp(14px,2.4vw,28px);
  --topbar:58px;
  --r:14px;
}
*{margin:0;padding:0;box-sizing:border-box}
html{scroll-behavior:smooth}
body{font-family:var(--sans);background:var(--ink);color:var(--text-2);
  -webkit-font-smoothing:antialiased;font-size:15px;line-height:1.6;overflow-x:hidden}
a{color:inherit;text-decoration:none}
::selection{background:var(--cyan);color:#04070A}
:focus-visible{outline:2px solid var(--cyan);outline-offset:2px}
.mono{font-family:var(--mono)}
.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}

/* Section label. Small and tracked, but at readable contrast — this is the only
   place uppercase micro-type is used, and never for anything you have to read
   more than three words of. */
.eyebrow,.card__k,.field label,.cell__who{
  font-family:var(--mono);font-size:11px;letter-spacing:.16em;text-transform:uppercase;
  color:var(--text-3)}

/* ══ TOP BAR ═══════════════════════════════════════════════════════════════ */
.topbar{display:flex;align-items:center;justify-content:space-between;gap:16px;height:var(--topbar);
  padding:0 var(--pad);border-bottom:1px solid var(--line);background:var(--ink)}
/* The pool wordmark treatment: thin Cormorant, uppercase, widely tracked. */
.wordmark{font-family:var(--head);font-size:17px;font-weight:300;letter-spacing:.34em;
  text-transform:uppercase;color:var(--text);white-space:nowrap}
.wordmark span{color:var(--cyan);margin-left:.34em}

/* Sits against the wordmark rather than centred: the bar is read left to right
   and these are siblings of the name, not a separate region of the page. The
   auto margin is what pins the account button to the right once a third child
   is in a space-between row. */
.topnav{display:flex;gap:20px;margin-right:auto;padding-left:26px}
.topnav a{font-family:var(--mono);font-size:12px;letter-spacing:.1em;text-transform:uppercase;
  color:var(--text-3);white-space:nowrap;transition:color .18s}
.topnav a:hover,.topnav a[aria-current="page"]{color:var(--cyan)}
@media(max-width:560px){.topnav{gap:14px;padding-left:14px}}

.account{font-family:var(--mono);font-size:12px;color:var(--text-2);background:var(--panel-2);
  border:1px solid var(--line);border-radius:999px;padding:8px 15px;cursor:pointer;
  transition:border-color .18s,color .18s;white-space:nowrap}
.account:hover{border-color:var(--line-2);color:var(--text)}
.account.is-out{border-color:var(--copper);color:var(--copper)}

/* ══ THE DECK ══════════════════════════════════════════════════════════════ */
/* The whole tool is meant to be visible at once — you should not have to scroll
   to find the Run button. So on a desktop the deck is sized to exactly the
   viewport left over under the top bar, and the drop zone is the part that
   gives: everything else keeps its natural height and the canvas absorbs the
   difference. Below 940px this all unwinds and the page scrolls normally. */
.deck{padding:var(--pad);max-width:1420px;margin-inline:auto}
.deck__grid{display:grid;grid-template-columns:minmax(300px,370px) 1fr;gap:0;
  background:var(--panel);border:1px solid var(--line);border-radius:var(--r);overflow:hidden}
@media(min-width:941px){
  .deck{height:calc(100svh - var(--topbar));display:flex}
  .deck__grid{flex:1;min-height:0}
  .intro,.canvas{min-height:0;overflow-y:auto}
}

/* ---- left: what it is ---- */
.intro{padding:clamp(20px,2.2vw,28px);border-right:1px solid var(--line);display:flex;flex-direction:column}
.eyebrow{margin-bottom:10px}
h1{font-family:var(--head);font-size:clamp(34px,3.6vw,46px);line-height:1.05;letter-spacing:.01em;
  font-weight:300;color:var(--text)}
h1 span{color:var(--cyan)}
.intro__lede{font-size:14px;line-height:1.6;color:var(--text-2);margin-top:12px}

/* Left-ruled aside, the way a docs page flags a caveat. */
.note{font-size:12.5px;line-height:1.6;color:var(--text-3);border-left:2px solid var(--cyan-dim);
  padding-left:12px;margin-top:14px}
.note--quiet{border-left:0;padding-left:0;margin-top:10px;text-align:center}
/* A note in one of the wide bottom sections would otherwise run the full 1180px
   at 12.5px, which is far too long a line to read. Same measure as the lede. */
.say .note{max-width:74ch}
/* In-copy links. The global reset strips anchors bare — right for the chrome,
   but it leaves a link inside a sentence indistinguishable from the sentence. */
.note a,.cell p a,.lede a{color:var(--cyan);text-decoration:underline;text-underline-offset:2px}
/* A button that reads as a link: the action is inline in a sentence, and a
   chip here would compete with Analyze for the eye. */
.linkbtn{background:none;border:0;padding:0;font:inherit;color:var(--cyan);
  cursor:pointer;text-decoration:underline;text-underline-offset:2px}
.linkbtn:hover{color:var(--text)}
.linkbtn:focus-visible{outline:2px solid var(--cyan);outline-offset:2px;border-radius:2px}

.card{background:var(--panel-2);border:1px solid var(--line);border-radius:10px;
  padding:14px 16px;margin-top:16px}
.card__k{margin-bottom:11px}
.steps{list-style:none;counter-reset:s;display:grid;gap:8px}
.steps li{counter-increment:s;position:relative;padding-left:24px;font-size:13px;
  line-height:1.55;color:var(--text-2)}
.steps li::before{content:counter(s) ".";position:absolute;left:0;top:0;
  font-family:var(--mono);font-size:12px;color:var(--cyan)}
.steps b{color:var(--text);font-weight:700}

/* ---- right: the canvas ---- */
.canvas{padding:clamp(20px,2.2vw,28px);display:flex;flex-direction:column;gap:14px;min-width:0}

/* The stage holds the drop target and the viewer in the same box, one of them
   hidden at a time. It is the flex:1 item, so it takes every pixel the column
   is not using for the filmstrip, the question and Run. */
.stage{flex:1;min-height:170px;display:flex;position:relative}

.drop{flex:1;position:relative;display:flex;flex-direction:column;align-items:center;
  justify-content:center;text-align:center;gap:0;padding:28px 24px;
  min-height:150px;width:100%;
  background:var(--panel-2);border:1.5px dashed var(--line-2);border-radius:12px;
  cursor:pointer;color:var(--text);transition:border-color .18s,background-color .18s}
.drop:hover{border-color:var(--cyan-dim);background:var(--panel-3)}
.drop[hidden]{display:none}
.drop__icon{display:grid;place-items:center;width:44px;height:44px;border-radius:50%;
  background:var(--panel-3);border:1px solid var(--line);margin-bottom:14px}
.drop__icon svg{width:19px;height:19px;color:var(--text-2)}
.drop b{display:block;font-size:15px;font-weight:700;color:var(--text);margin-bottom:6px}
.drop small{font-size:12.5px;color:var(--text-3)}
/* Dragging over anywhere on the stage, not just the empty drop card — once a
   photo is up, the card is gone and the photo is the target. */
.stage.is-over .drop{border-color:var(--cyan);background:rgba(65,230,212,.06)}
.stage.is-over .shot__frame{outline:2px solid var(--cyan);outline-offset:3px}

/* ---- the stage viewer ---- */
.shot{flex:1;min-width:0;min-height:0;display:grid;grid-template-rows:minmax(0,1fr) auto;gap:9px}
.shot[hidden]{display:none}
/* Both layers are the same grid cell at the same size, and both letterbox the
   same way: object-fit:contain and the SVG's default xMidYMid meet are the
   identical operation, so viewBox coordinates land on the pixels they name.
   Do not give either one a different fit — the outlines drift immediately. */
.shot__frame{display:grid;min-width:0;min-height:0;border-radius:11px;overflow:hidden;
  background:var(--panel-2);border:1px solid var(--line)}
.shot__frame > img,.shot__frame > svg{grid-area:1/1;width:100%;height:100%;display:block}
.shot__frame > img{object-fit:contain}
.shot__frame > svg{pointer-events:none}
.shot__cap{display:flex;align-items:center;justify-content:space-between;gap:12px;
  font-family:var(--mono);font-size:11px;letter-spacing:.1em;text-transform:uppercase;
  color:var(--text-3)}
.chip--add{font-family:var(--sans);letter-spacing:0;text-transform:none;padding:6px 12px;
  font-size:12px;flex:none}

/* ---- outlines ----
   Drawn in the photo's own pixel coordinates, so every measurement below is a
   fraction of the image rather than a screen size: a rectangle looks the same
   weight on a 12MP photo and a phone screenshot. */
.box__rect{fill:none;stroke:var(--copper);stroke-linejoin:round;pointer-events:auto;cursor:pointer}
.box__hit{fill:transparent;pointer-events:auto;cursor:pointer}
.box__tagbg{fill:var(--copper)}
.box__tag{fill:#04070A;font-family:var(--mono);font-weight:700;dominant-baseline:central;
  text-anchor:middle;pointer-events:none}
/* The outline draws itself on rather than appearing — this is the moment the
   customer sees the thing actually being found. */
.box.is-new .box__rect{animation:draw .55s ease-out both}
@keyframes draw{from{stroke-dashoffset:var(--len)}to{stroke-dashoffset:0}}
.box.is-new .box__tagbg,.box.is-new .box__tag{animation:tagIn .3s .4s ease-out both}
@keyframes tagIn{from{opacity:0}to{opacity:1}}
/* One finding selected: it goes cyan and the rest step back, so "number 3" is
   a glance rather than a hunt. */
.shot.has-active .box{opacity:.4}
.shot.has-active .box.is-active{opacity:1}
.shot.has-active .box.is-active .box__rect{stroke:var(--cyan)}
.shot.has-active .box.is-active .box__tagbg{fill:var(--cyan)}

/* ---- filmstrip ---- */
.thumbs{display:flex;gap:8px;overflow-x:auto;overflow-y:hidden;flex:none;padding-bottom:3px;
  scrollbar-width:thin}
.thumbs:empty{display:none}
.thumb{position:relative;flex:0 0 62px;height:62px;border-radius:8px;overflow:hidden;
  border:1px solid var(--line);background:var(--panel-2);cursor:pointer;
  transition:border-color .18s,box-shadow .18s}
.thumb img{width:100%;height:100%;object-fit:cover;display:block;transition:opacity .2s}
.thumb.is-active{border-color:var(--cyan);box-shadow:0 0 0 2px rgba(65,230,212,.32)}
.thumb[data-state="reading"]{border-color:var(--cyan)}
.thumb[data-state="reading"] img{opacity:.4}
/* A band of light down the photo the machine has open right now. */
.thumb[data-state="reading"]::after{content:'';position:absolute;inset:0;pointer-events:none;
  background:linear-gradient(180deg,transparent 0 38%,rgba(65,230,212,.45) 50%,transparent 62% 100%);
  animation:scan 1.4s ease-in-out infinite}
@keyframes scan{from{transform:translateY(-100%)}to{transform:translateY(100%)}}
.thumb[data-state="done"] img{opacity:.78}
.thumb[data-state="failed"],.thumb[data-state="skipped"]{border-color:var(--copper)}
.thumb__state{position:absolute;left:4px;bottom:4px;font-family:var(--mono);font-size:10px;
  line-height:1;padding:3px 5px;border-radius:4px;background:var(--cyan);color:#04070A}
.thumb__state:empty{display:none}
.thumb[data-state="failed"] .thumb__state,.thumb[data-state="skipped"] .thumb__state{background:var(--copper)}
/* How many outlines this photo has, so the strip says where the interesting
   pictures are before you click through them. */
.thumb__n{position:absolute;top:4px;left:4px;font-family:var(--mono);font-size:10px;line-height:1;
  padding:3px 5px;border-radius:4px;background:var(--copper);color:#04070A;font-weight:700}
.thumb__n:empty{display:none}
.thumb__x{position:absolute;top:4px;right:4px;width:19px;height:19px;border-radius:50%;border:0;
  cursor:pointer;background:rgba(6,9,12,.84);color:var(--text);font-size:13px;line-height:1;
  display:grid;place-items:center}
.thumb__x:hover{background:var(--copper);color:#04070A}

/* ---- the question ---- */
.ask__field{display:flex;align-items:flex-start;gap:11px;background:var(--panel-3);
  border:1px solid var(--line-2);border-radius:11px;padding:13px 16px;cursor:text;
  transition:border-color .18s}
.ask__field:focus-within{border-color:var(--cyan)}
.ask__icon{flex:none;display:grid;place-items:center;margin-top:2px}
.ask__icon svg{width:17px;height:17px;color:var(--text-3)}
#prompt{flex:1;background:none;border:0;color:var(--text);font-family:var(--sans);
  font-size:14.5px;line-height:1.6;resize:vertical;min-height:24px;max-height:180px;
  field-sizing:content}
#prompt:focus{outline:none}
#prompt::placeholder{color:var(--text-3)}
.ask__hint{font-size:12.5px;line-height:1.6;color:var(--text-3);margin-top:9px;padding-left:2px}

/* ---- buttons ---- */
.btn{display:inline-flex;align-items:center;justify-content:center;gap:9px;
  background:var(--cyan);color:#04070A;border:1px solid var(--cyan);border-radius:10px;
  font-family:var(--sans);font-size:15px;font-weight:600;padding:13px 26px;cursor:pointer;
  transition:filter .18s,opacity .18s}
.btn:hover{filter:brightness(1.08)}
.btn:disabled{opacity:.32;cursor:not-allowed;filter:none}
/* Run sits under the question, in the same column as the photo it runs on. The
   stage above is the flex:1 item, so it is the one that absorbs spare height
   and Run stays at the foot of the canvas without an auto margin. */
.btn--big{width:100%;padding:14px 26px;font-size:15px}
.btn--ghost{background:none;color:var(--text-2);border-color:var(--line-2)}
.btn--ghost:hover{border-color:var(--cyan);color:var(--cyan);filter:none}

/* ══ OUTPUT ════════════════════════════════════════════════════════════════
   The left column, once a job is under way. It owns its own scrollbar so the
   tabs and the progress strip stay put while the write-up runs on underneath
   them, and so nothing about a job can push the stage off screen. */
.pitch[hidden],.rail[hidden]{display:none}
body.is-live .intro{padding:0;overflow:hidden}
.rail{flex:1;min-height:0;display:flex;flex-direction:column}
.rail__bar{flex:none;display:flex;align-items:center;justify-content:space-between;gap:10px;
  padding:11px 14px;border-bottom:1px solid var(--line)}
.rail__body{flex:1;min-height:0;overflow-y:auto;overscroll-behavior:contain}
.rail__foot{flex:none;display:flex;align-items:center;justify-content:space-between;gap:10px;
  flex-wrap:wrap;padding:10px 14px;border-top:1px solid var(--line)}
.tabs{display:flex;gap:6px}
.tab{font-size:13.5px;color:var(--text-3);background:none;border:1px solid transparent;
  border-radius:8px;padding:8px 14px;cursor:pointer;transition:all .18s}
.tab:hover{color:var(--text)}
.tab.is-on{background:var(--panel-3);border-color:var(--line);color:var(--cyan)}
.output__acts{display:flex;gap:7px;flex-wrap:wrap}
.chip{font-size:12.5px;color:var(--text-2);background:none;border:1px solid var(--line);
  border-radius:8px;padding:8px 13px;cursor:pointer;transition:border-color .18s,color .18s}
.chip:hover{border-color:var(--cyan);color:var(--cyan)}

.progress[hidden]{display:none}
.progress{position:relative;height:28px;border-bottom:1px solid var(--line);
  background:var(--panel-2);overflow:hidden}
.progress::before{content:'';position:absolute;inset:0 auto 0 0;width:var(--pct,0%);
  background:rgba(65,230,212,.15);border-right:1px solid var(--cyan);transition:width .35s ease}
.progress::after{content:attr(data-label);position:absolute;inset:0;display:flex;align-items:center;
  padding:0 16px;font-family:var(--mono);font-size:12px;color:var(--text-2)}

/* ---- findings ----
   The ranked list above the write-up. Prominence is carried by a coloured rail
   on the left edge rather than a badge: it orders the list at a glance without
   putting a word like "MEDIUM" next to every single entry. */
.finds:empty{display:none}
.finds{padding:22px clamp(18px,3vw,34px) 4px}
.finds__k{font-family:var(--mono);font-size:11px;letter-spacing:.16em;text-transform:uppercase;
  color:var(--text-3);margin-bottom:14px}
.finds__k span{display:inline-block;margin-left:8px;padding:2px 8px;border-radius:999px;
  background:var(--panel-3);color:var(--text-2);letter-spacing:.06em}
.finds__none{font-size:14.5px;color:var(--text-3);padding-bottom:14px}

/* The list and the outlines on the stage are two views of one thing: an entry
   here carries the number of the rectangle over there, hovering one lights the
   other, and clicking an entry brings its photo up on the stage. There is no
   second copy of the photo down here any more — the picture you dropped is the
   picture that gets marked. */
.finds__list{list-style:none;display:grid;gap:10px}
.find{background:var(--panel-2);border:1px solid var(--line);border-left:3px solid var(--text-3);
  border-radius:9px;padding:14px 16px;display:grid;grid-template-columns:auto 1fr;gap:12px;align-items:start;
  cursor:pointer;transition:border-color .18s,background-color .18s,transform .18s}
.find:hover{background:var(--panel-3);transform:translateX(2px)}
.find.is-active{border-color:var(--cyan);background:rgba(65,230,212,.07)}
.find.is-active .find__n{background:var(--cyan)}
/* Only entries that were not there a moment ago animate; the list is rebuilt on
   every photo and re-running all of them would strobe the column. */
.find.is-new{animation:findIn .32s cubic-bezier(.22,.61,.36,1) both}
@keyframes findIn{from{opacity:0;transform:translateY(7px)}to{opacity:1;transform:none}}
/* A finding the detector could not put a rectangle on. Saying so is better than
   letting the reader hunt the stage for an outline that was never drawn. */
.find--unplaced .find__n{background:var(--panel-3);color:var(--text-3)}
.find__n{display:grid;place-items:center;min-width:22px;height:22px;padding:0 6px;border-radius:4px;
  background:var(--copper);color:#04070A;font-family:var(--mono);font-size:11px;font-weight:700;line-height:1}
.find[data-prom="high"]{border-left-color:var(--copper)}
.find[data-prom="medium"]{border-left-color:var(--cyan-dim)}
.find[data-prom="low"]{border-left-color:var(--line-2)}
.find__what{font-size:14.5px;font-weight:700;color:var(--text);line-height:1.45}
.find__why{font-size:13.5px;line-height:1.65;color:var(--text-2);margin-top:5px}
.find__meta{font-family:var(--mono);font-size:11px;color:var(--text-3);margin-top:8px}

.report{padding:28px clamp(18px,3vw,34px);font-size:15px;line-height:1.8;color:var(--text-2);max-width:76ch}
.finds + .report{padding-top:22px}
/* The write-up's opening sentence is the verdict across the whole batch, so it
   is set larger than the body that follows it. */
.report > p:first-child{font-size:17px;line-height:1.6;color:var(--text);margin-bottom:20px}
.report p,.turn--av p{margin:0 0 15px}
.report h3,.turn--av h3{font-family:var(--sans);font-size:16px;font-weight:700;color:var(--text);margin:28px 0 12px}
.report h4,.turn--av h4{font-family:var(--sans);font-size:14.5px;font-weight:600;color:var(--copper);margin:22px 0 9px}
.report ul,.turn--av ul{margin:0 0 15px;padding-left:20px}
.report li,.turn--av li{margin-bottom:7px}
.report strong,.turn--av strong{color:var(--text);font-weight:600}
.report .muted,.turn--av .muted{color:var(--text-3)}
.report .is-error,.turn--av .is-error{color:var(--copper)}
.caret{display:inline-block;width:8px;height:16px;background:var(--cyan);vertical-align:-3px;
  animation:blink 1s steps(2) infinite}
@keyframes blink{50%{opacity:0}}
.spinner{display:inline-block;width:12px;height:12px;border:2px solid var(--line);
  border-top-color:var(--cyan);border-radius:50%;animation:spin .8s linear infinite}
@keyframes spin{to{transform:rotate(360deg)}}

.tablewrap{overflow-x:auto}
.pane table{width:100%;border-collapse:collapse;font-size:13.5px}
.pane th{text-align:left;padding:12px 16px;border-bottom:1px solid var(--line);color:var(--text-3);
  font-weight:500;font-size:12px;letter-spacing:.1em;text-transform:uppercase;white-space:nowrap}
.pane td{padding:12px 16px;border-bottom:1px solid var(--line);color:var(--text-2);
  vertical-align:top;line-height:1.65}
.pane tr:last-child td{border-bottom:0}
.t-name{color:var(--text-3);max-width:170px;overflow-wrap:anywhere}
.output__foot{padding:12px 16px;border-top:1px solid var(--line);font-size:12.5px;color:var(--text-3)}

/* ══ PCB RENDER ════════════════════════════════════════════════════════════ */

/* ══ EVERYTHING ELSE, AT THE BOTTOM ════════════════════════════════════════ */
.below{border-top:1px solid var(--line);margin-top:20px}
.say{padding:clamp(46px,6vw,84px) var(--pad);max-width:1180px;margin-inline:auto;
  border-bottom:1px solid var(--line)}
.say:last-of-type{border-bottom:0}
h2{font-family:var(--head);font-size:clamp(28px,3.4vw,42px);line-height:1.12;letter-spacing:.01em;
  font-weight:300;color:var(--text)}
.lede{font-size:15.5px;line-height:1.75;color:var(--text-2);max-width:74ch;margin-top:16px}

.grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(250px,1fr));gap:16px;margin-top:38px}
.grid--3{grid-template-columns:repeat(auto-fit,minmax(240px,1fr))}
.cell{background:var(--panel);border:1px solid var(--line);border-radius:11px;padding:22px 22px 20px;
  display:flex;flex-direction:column}
.cell h3{font-size:17px;font-weight:600;letter-spacing:-.015em;color:var(--text)}
.cell p{font-size:14px;line-height:1.7;color:var(--text-2);margin-top:11px}
/* Pinned to the bottom of the card. The cards stretch to a common height, so a
   label that just follows its paragraph lands at a different point in each one. */
.cell__who{margin-top:auto!important;padding-top:16px;color:var(--text-3)!important;font-size:11px!important}

.plans{width:100%;border-collapse:collapse;margin-top:36px}
.plans th,.plans td{border-bottom:1px solid var(--line);padding:20px 0;text-align:left;
  vertical-align:baseline}
.plans tr:last-child th,.plans tr:last-child td{border-bottom:0}
.plans th{width:120px;font-size:15px;font-weight:600;color:var(--text)}
.plans__price{width:140px;font-size:22px;font-weight:600;color:var(--cyan);letter-spacing:-.02em}
.plans__price small{font-size:13px;font-weight:400;color:var(--text-3);letter-spacing:0}
.plans td:last-child{font-size:14.5px;line-height:1.7;color:var(--text-2);padding-left:22px}
@media(max-width:700px){
  .plans,.plans tbody,.plans tr,.plans th,.plans td{display:block;width:auto}
  .plans tr{border-bottom:1px solid var(--line);padding:18px 0}
  .plans th,.plans td{border-bottom:0;padding:0 0 6px}
  .plans td:last-child{padding-left:0}
}

.field{display:grid;gap:8px}
.field input,.field textarea{background:var(--panel-2);border:1px solid var(--line);border-radius:9px;
  padding:12px 14px;font-family:var(--sans);font-size:14.5px;color:var(--text);resize:vertical}
.field textarea{min-height:104px;line-height:1.65}
.field input:focus,.field textarea:focus{outline:none;border-color:var(--cyan)}
.field input::placeholder,.field textarea::placeholder{color:var(--text-3)}
form.contact__form{display:grid;gap:20px;width:min(560px,100%);margin-top:34px;justify-items:stretch}
form.contact__form .btn{justify-self:start}

footer{padding:30px var(--pad);border-top:1px solid var(--line);display:flex;
  justify-content:space-between;gap:16px;flex-wrap:wrap;font-size:13px;color:var(--text-3);
  max-width:1180px;margin-inline:auto}
footer a{color:var(--text-2)}
footer a:hover{color:var(--cyan)}

/* ══ TIP JAR ═══════════════════════════════════════════════════════════════
   Hidden until /api/tip says a link is configured, so an unset TIP_URL shows
   nothing rather than a beer button that goes nowhere. Floats bottom-right
   once enabled. */
.tip[hidden]{display:none}
.tip{position:fixed;right:22px;bottom:22px;z-index:40;display:flex;align-items:center;
  gap:14px;border:1px solid var(--line-2);border-radius:999px;background:var(--panel);
  padding:10px 10px 10px 12px;box-shadow:0 14px 34px rgba(0,0,0,.38)}
.tip__qr{flex:none;width:52px;height:52px;display:grid;place-items:center;
  border:1px solid var(--line);border-radius:50%;background:var(--panel-2);padding:6px}
.tip__qr svg{width:100%;height:100%;display:block;border-radius:2px}
.tip__link{display:inline-flex;align-items:center;gap:8px;font-size:14px;
  color:var(--copper);border:1px solid var(--line);border-radius:999px;padding:11px 18px;
  white-space:nowrap;transition:border-color .18s,background-color .18s}
.tip__link:hover{border-color:var(--copper);background:rgba(224,154,92,.09)}

/* ══ KEY SHEET ═════════════════════════════════════════════════════════════ */
.sheet{border:1px solid var(--line-2);border-radius:var(--r);background:var(--panel);
  color:var(--text-2);padding:0;width:min(430px,92vw)}
.sheet::backdrop{background:rgba(4,7,10,.76)}
.sheet .card__k{padding:16px 20px;border-bottom:1px solid var(--line);margin:0}
.sheet__body{padding:20px;display:grid;gap:16px}
.sheet__acts{display:flex;gap:10px;flex-wrap:wrap;margin-top:4px}

/* ══ DOCS + 404 ════════════════════════════════════════════════════════════ */
header{display:flex;align-items:center;justify-content:space-between;gap:20px;
  padding:18px var(--pad);border-bottom:1px solid var(--line)}
.brand{font-family:var(--head);font-size:17px;font-weight:300;letter-spacing:.34em;
  text-transform:uppercase;color:var(--text);white-space:nowrap}
.brand span{color:var(--cyan);margin-left:.34em}
.nav{display:flex;gap:24px}
.nav a{font-size:14px;color:var(--text-3);transition:color .18s}
.nav a:hover{color:var(--text)}
.nav__cta{font-size:14px;font-weight:500;color:var(--cyan);border:1px solid var(--line-2);
  border-radius:9px;padding:9px 16px;transition:border-color .18s}
.nav__cta:hover{border-color:var(--cyan)}
@media(max-width:860px){.nav{display:none}}

section{padding:clamp(46px,6vw,84px) var(--pad);max-width:1180px;margin-inline:auto}
.hero{display:grid;justify-items:start}
.hero__cta{display:flex;gap:12px;flex-wrap:wrap;margin-top:32px}
.doc{max-width:80ch}
pre{background:var(--panel-2);border:1px solid var(--line);border-radius:10px;padding:20px;
  overflow-x:auto;font-family:var(--mono);font-size:13px;line-height:1.8;color:var(--text-2);margin:18px 0}
pre .c{color:var(--text-3)}
pre .s{color:var(--cyan)}
pre .k{color:var(--copper)}
code,.in{font-family:var(--mono);font-size:13px;color:var(--cyan)}

/* ══ RESPONSIVE ════════════════════════════════════════════════════════════ */
/* On a short laptop screen the left column overflows first — the canvas has
   slack to give but the intro does not, and Run ends up under the fold inside
   its own column. Tighten the copy rather than let that happen. Must sit after
   the base .intro/h1 rules: a media query adds no specificity, so placed above
   them it loses the cascade to the very rules it exists to override. */
@media(min-width:941px) and (max-height:820px){
  .intro{padding:15px 18px}
  .eyebrow{margin-bottom:7px}
  h1{font-size:clamp(26px,2.4vw,30px)}
  .intro__lede{font-size:12.5px;line-height:1.5;margin-top:9px}
  .note{font-size:11.5px;line-height:1.5;margin-top:10px;padding-left:10px}
  .card{padding:10px 12px;margin-top:10px}
  .card__k{margin-bottom:8px}
  .steps{gap:5px}
  .steps li{font-size:12px;line-height:1.45;padding-left:21px}
  .btn--big{padding:11px 26px;font-size:14px}
  .note--quiet{margin-top:7px}
}

/* Stacked, the columns are resequenced or the page reads backwards: the pitch
   would come before the tool it is pitching. Canvas first — stage, filmstrip,
   question, Run — and the words underneath. There is no viewport-height frame
   to work inside here, so portal.js brings the rail up when a run starts. */
@media(max-width:940px){
  .deck__grid{grid-template-columns:1fr}
  .canvas{order:-1}
  .intro{border-right:0;border-top:1px solid var(--line)}
  .stage{min-height:min(58vh,420px)}
  body.is-live .intro{overflow:visible}
  .rail__body{overflow:visible}
}

/* ══ PRINT ═════════════════════════════════════════════════════════════════
   Save as PDF goes through the browser's own print dialog: no PDF library, and
   what the customer files is exactly what they proofread on screen. */
/* The output lives inside the deck now, so the deck can no longer be hidden
   wholesale — it is unwound into a plain block with only the rail left in it. */
/* ══ THE CONVERSATION ══════════════════════════════════════════════════════
   Deliberately not a chat app. The answer is the document the reader came for,
   so it is set as prose at full width exactly like the write-up; the question
   is the quieter thing, tucked to the right so the column still reads top to
   bottom as a series of answers rather than as a dialogue to wade through. */
.thread{padding:24px clamp(18px,3vw,34px);display:flex;flex-direction:column;gap:26px}
.thread:empty::after{
  content:'Ask anything about what you dropped — a roster, a timesheet, a statement, a roof. Tell it the rules you work to and it applies them exactly, and it asks rather than guessing at a code it does not know.';
  display:block;max-width:52ch;color:var(--text-3);font-size:14px;line-height:1.75}
/* After a batch the conversation is with the findings, and the thing worth
   saying first is that the write-up itself can be re-cut — nobody guesses that
   a chat box will re-typeset a document unless it says so. */
.thread[data-state=analysis]:empty::after{
  content:'The findings are open. Ask about any of them — or say how you want the write-up laid out: grouped by room, cut to a punch list, addressed to the client, in your own trade’s format. It will write the whole thing out again.'}
.turn--you{align-self:flex-end;max-width:min(88%,54ch);background:var(--panel-3);
  border:1px solid var(--line);border-radius:var(--r) var(--r) 5px var(--r);
  padding:12px 16px;color:var(--text);font-size:14.5px;line-height:1.6;white-space:pre-wrap}
.turn--av{max-width:76ch;font-size:15px;line-height:1.8;color:var(--text-2)}
.turn--av > *:last-child{margin-bottom:0}

/* A table in an answer is the answer — a swap list read as a paragraph is not
   something anyone can act on. Scrolls inside itself so a wide one never pushes
   the rail sideways. */
.turn--av .tablewrap{margin:4px 0 15px;border:1px solid var(--line);border-radius:10px}
.turn--av table.md{width:100%;border-collapse:collapse;font-size:13.5px}
.turn--av table.md th{text-align:left;padding:10px 14px;border-bottom:1px solid var(--line);
  color:var(--text-3);font-weight:600;white-space:nowrap}
.turn--av table.md td{padding:10px 14px;border-bottom:1px solid var(--line);
  color:var(--text-2);vertical-align:top}
.turn--av table.md tr:last-child td{border-bottom:0}
.turn--av code{font-family:var(--mono);font-size:.92em;color:var(--text);
  background:var(--panel-3);border-radius:5px;padding:1px 5px}

/* Ask leads; the write-up is the thing you can also do. */
.acts{display:flex;gap:10px;align-items:stretch}
.acts .btn--big{flex:1;width:auto}
.acts .btn--ghost{flex:none;white-space:nowrap;padding:14px 18px;font-size:14px}
.acts .btn--ghost[hidden]{display:none}
.chip--new[hidden]{display:none}

@media print{
  @page{margin:16mm}
  body{background:#fff;color:#111}
  .no-print,header,footer,.topbar,.below,.progress,.canvas,.pitch{display:none!important}
  .deck{display:block!important;height:auto!important;padding:0;max-width:none}
  .deck__grid{display:block!important;border:0;background:none;overflow:visible}
  .intro{display:block!important;border:0;padding:0;overflow:visible!important}
  .rail{display:block!important}
  .rail__body{overflow:visible!important}
  .pane[hidden]{display:block!important}
  .report{color:#111;max-width:none;padding:0;font-size:11pt}
  .report h3,.report strong{color:#000}
  .report h4{color:#333}
  .pane table{margin-top:22px;font-size:9pt}
  .pane th{color:#555;border-bottom:1px solid #999}
  .pane td{color:#222;border-bottom:1px solid #ddd}
  .caret{display:none}
  .tip{display:none!important}
}

@media(prefers-reduced-motion:reduce){
  *,*::before,*::after{animation-duration:.001ms!important;animation-iteration-count:1!important;
    transition-duration:.001ms!important}
  html{scroll-behavior:auto}
}

/* Board renders — three live path-traced boards, one plate per cell. The
   images share an aspect and crop to it, so a wide assembly and a square one
   sit at the same height without any per-image tuning. */
.grid--renders{gap:20px}
.cell--render{padding:0;overflow:hidden}
.cell--render img{display:block;width:100%;aspect-ratio:16/10;object-fit:cover}
.cell--render figcaption{padding:18px 22px 20px}
.cell--render figcaption p{margin-top:6px;font-size:13px;color:var(--text-2)}
