/* avd-ops portal components v2.5.0 (https://avd-ops.dev/, avd-ops/avd-ops site/assets/avd-ops-portal.css). MIT.
   Personal project, not for production, as is; not affiliated with the author's employer, Liquidware or Microsoft.
   The pieces a guided, step-by-step portal page shares: the progress rail, one stage panel in view, the
   "run in Cloud Shell, then paste the output" timeline, terminal blocks, the paste box, form fields, switches,
   buttons, the sticky Back and Next bar, result chips, check outcome pills, a file drop, and (2.5.0) the
   one-screen-at-a-time wizard: head, phase progress, full-screen step, "more" disclosure, reply and sheet
   (the segmented choice and the Run in row are in avd-ops.css).
   First drawn for the avd-landing-zone deployment portal, promoted here so every portal vendors one copy
   (docs/design-system.md). Load it after avd-ops.css and put class="portal" on <body>: everything here is scoped
   to it, so the avd-ops.dev pages are untouched. Colors come only from the avd-ops.css tokens. */

/* Page */
body.portal{font:16px/1.55 var(--body);-webkit-font-smoothing:antialiased}
.portal main{max-width:980px;margin:0 auto;padding-block:0;
  padding-left:max(var(--gutter),env(safe-area-inset-left,0px));padding-right:max(var(--gutter),env(safe-area-inset-right,0px))}
.portal h1{font-size:1.05rem;margin:0;letter-spacing:0}
.portal h2{font-size:1.45rem;margin:0 0 var(--space-2);letter-spacing:-.01em}
.portal h3{font-size:1.02rem;margin:0 0 var(--space-1);font-weight:600}
.portal p{margin:0 0 var(--space-3)}
.portal a{text-underline-offset:2px}
.portal code{background:var(--sunken);border:1px solid var(--line);border-radius:4px;padding:0 4px}
.portal .muted{color:var(--muted)}
.portal .hidden{display:none!important}
.portal .lede{color:var(--muted);margin:0;max-width:62ch;font-size:1rem}

/* Notice: the portal's research-only line before the first stage, and the footer. */
.portal footer.disclaimer{margin:28px 0 0;padding:var(--space-4) 0 calc(24px + env(safe-area-inset-bottom,0px));border-top:1px solid var(--line);font-size:.85rem;color:var(--muted)}

/* Panels: a stage, or a collapsible block such as Settings. */
.portal .panel{background:var(--surface);border:1px solid var(--line);border-radius:var(--radius);padding:20px;margin-bottom:var(--space-4);box-shadow:var(--shadow)}
.portal details.panel>summary{cursor:pointer;font:600 1rem var(--display)}
.portal details.panel[open]>summary{margin-bottom:var(--space-3)}
.portal .panel.accent{border-color:var(--accent)}

/* Forms */
.portal .row{display:flex;flex-wrap:wrap;gap:var(--space-3) var(--space-4);align-items:flex-end}
.portal .field{display:flex;flex-direction:column;align-items:stretch;gap:var(--space-1);flex:1 1 180px;min-width:0}
.portal .field>span{font-size:.82rem;font-weight:600;color:var(--muted)}
.portal .field>small{color:var(--muted);font-size:.8rem}
.portal :is(input[type=text],input[type=number],input[type=time],select,textarea){font:inherit;color:var(--fg);background:var(--surface);border:1px solid var(--line-strong);border-radius:var(--radius-sm);padding:7px 10px;width:100%}
.portal :is(input[type=text],input[type=number],input[type=time],select,textarea):focus{outline:none;border-color:var(--accent);box-shadow:0 0 0 3px var(--accent-soft)}
.portal :is(select,input):disabled{opacity:.55}
.portal textarea{font:12.5px/1.55 var(--mono);min-height:120px;resize:vertical}
.portal textarea.prose{font:inherit;min-height:96px}
.portal fieldset{border:1px solid var(--line);border-radius:var(--radius-sm);padding:var(--space-3) var(--space-4) var(--space-4);margin:0 0 var(--space-4);min-width:0}
.portal legend{font:600 .95rem var(--display);padding:0 var(--space-1)}

/* Buttons. A plain <button> is the primary action; .secondary and .linkbtn are the quieter ones. */
.portal :is(button,a.btnlink){font:inherit;font-weight:600;border:1px solid var(--accent);border-radius:var(--radius-sm);padding:8px 16px;cursor:pointer;background:var(--accent);color:var(--on-accent);transition:background var(--fast) var(--ease),border-color var(--fast) var(--ease)}
.portal :is(button:hover:not(:disabled),a.btnlink:hover){background:var(--accent-hover);border-color:var(--accent-hover);color:var(--on-accent)}
.portal a.btnlink{display:inline-block;text-decoration:none}
.portal :is(button,a.btnlink).secondary{background:var(--surface);color:var(--accent);border-color:var(--line-strong)}
.portal :is(button,a.btnlink).secondary:hover:not(:disabled){background:var(--accent-soft);border-color:var(--accent);color:var(--accent)}
.portal button.linkbtn{background:none;border:0;padding:4px 0;color:var(--accent);text-decoration:underline;text-underline-offset:2px}
.portal button.linkbtn:hover:not(:disabled){background:none;color:var(--accent-hover)}
.portal button:disabled{opacity:.45;cursor:default}

/* Switch: a checkbox drawn as a toggle, with its label and hint beside it. */
.portal label.switch{display:flex;gap:var(--space-3);align-items:flex-start;margin-bottom:var(--space-3)}
.portal label.switch>input[type=checkbox]{appearance:none;-webkit-appearance:none;flex:0 0 auto;width:40px;height:24px;border-radius:12px;background:var(--line-strong);position:relative;cursor:pointer;margin-top:1px;transition:background var(--fast)}
.portal label.switch>input[type=checkbox]::after{content:"";position:absolute;top:3px;left:3px;width:18px;height:18px;border-radius:50%;background:var(--surface);box-shadow:var(--shadow);transition:left var(--fast)}
.portal label.switch>input[type=checkbox]:checked{background:var(--accent)}
.portal label.switch>input[type=checkbox]:checked::after{left:19px}
.portal label.switch>input[type=checkbox]:focus-visible{outline:2px solid var(--focus);outline-offset:2px}

/* Progress rail: one numbered stop per stage, optional phase labels (data-phase on the first li of a phase),
   one row that scrolls sideways when narrow. li.done, li.current and li.locked set the state. */
.portal ol.steps{list-style:none;display:flex;padding:26px 4px 6px;margin:14px 0;overflow-x:auto;scroll-snap-type:x proximity;scrollbar-width:none}
.portal ol.steps::-webkit-scrollbar{display:none}
.portal ol.steps li{flex:1 0 84px;scroll-snap-align:start;position:relative}
.portal ol.steps li[data-phase]::after{content:attr(data-phase);position:absolute;top:-24px;left:6px;font:600 .78rem/1 var(--body);color:var(--muted);white-space:nowrap}
.portal ol.steps li+li::before{content:"";position:absolute;top:15px;left:calc(-50% + 16px);right:calc(50% + 16px);height:2px;background:var(--line-strong)}
.portal ol.steps li.done+li::before{background:var(--good)}
.portal ol.steps button{width:100%;display:flex;flex-direction:column;align-items:center;gap:6px;text-align:center;background:none;color:var(--muted);border:0;font-size:.88rem;line-height:1.2;padding:0 2px 4px}
.portal ol.steps button:hover:not(:disabled){background:none;color:var(--fg)}
.portal ol.steps button:hover:not(:disabled) .n{border-color:var(--accent)}
.portal ol.steps .n{display:grid;place-items:center;width:32px;height:32px;border-radius:50%;border:2px solid var(--line-strong);background:var(--surface);font:600 .82rem var(--mono);color:var(--muted);position:relative;z-index:1}
.portal ol.steps li.done button{color:var(--fg)}
.portal ol.steps li.done .n{border-color:var(--good);background:var(--good);color:var(--surface)}
.portal ol.steps li.current button{color:var(--accent)}
.portal ol.steps li.current .n{border-color:var(--accent);background:var(--accent);color:var(--on-accent);box-shadow:0 0 0 5px var(--accent-soft)}
.portal ol.steps li.locked .n{border-style:dashed;background:transparent}
@media (max-width:560px){
  .portal ol.steps{padding-top:6px}
  .portal ol.steps li{flex:1 0 40px}
  .portal ol.steps li .lbl{display:none}
  .portal ol.steps li.current{flex:0 0 auto;padding-inline:4px}
  .portal ol.steps li.current .lbl{display:block;white-space:nowrap}
  .portal ol.steps li[data-phase]::after{display:none}
}

/* Stage in view. A .stage is a .panel; only the current one shows. */
.portal .stage{padding:24px 26px}
.portal .stage>h2{display:flex;align-items:baseline;flex-wrap:wrap;gap:2px 10px}
.portal .stage>h2>.muted{font:400 .95rem var(--body)}
.portal .stage>.intro{max-width:76ch;margin-bottom:18px;color:var(--muted)}
@media (max-width:560px){.portal :is(.stage,.panel){padding:var(--space-4)}.portal h2{font-size:1.25rem}}

/* Command stage: "Run in Cloud Shell" then "Paste the output", numbered stops on one line. A stop takes
   .good, .ok or .poor once its result is known. */
.portal .slot{counter-reset:stop;margin-top:18px}
.portal .slot>.stop{position:relative;padding:0 0 24px 46px;counter-increment:stop}
.portal .slot>.stop:last-child{padding-bottom:0}
.portal .slot>.stop::before{content:counter(stop);position:absolute;left:0;top:-2px;width:30px;height:30px;border-radius:50%;display:grid;place-items:center;font:600 .82rem var(--mono);background:var(--accent-soft);color:var(--accent);border:2px solid var(--accent)}
.portal .slot>.stop:not(:last-child)::after{content:"";position:absolute;left:15px;top:32px;bottom:4px;width:2px;background:var(--line)}
.portal .slot>.stop>.label{font:600 .88rem/1.2 var(--body);color:var(--muted);margin:6px 0 12px}
.portal .slot>.stop.good::before{content:"\2713";background:var(--good);border-color:var(--good);color:var(--surface)}
.portal .slot>.stop.ok::before{background:var(--caution-soft);border-color:var(--caution);color:var(--caution)}
.portal .slot>.stop.poor::before{content:"!";background:var(--bad-soft);border-color:var(--bad);color:var(--bad)}
@media (max-width:560px){
  .portal .slot>.stop{padding-left:38px}
  .portal .slot>.stop::before{width:26px;height:26px;font-size:.75rem}
  .portal .slot>.stop:not(:last-child)::after{left:13px;top:28px}
}

/* Back and Next stay reachable at the bottom of the screen. */
.portal .stepnav{position:sticky;bottom:0;z-index:5;display:flex;gap:var(--space-3);align-items:center;justify-content:space-between;margin:0 0 var(--space-4);padding:14px 0 calc(12px + env(safe-area-inset-bottom,0px));background:var(--bg);border-top:1px solid var(--line)}
.portal .stepnav button{min-width:7.5rem;box-shadow:var(--shadow)}
.portal .stepnav .where{text-align:center;flex:1;min-width:0;font:.78rem var(--mono);letter-spacing:.02em;color:var(--muted)}
@media (max-width:560px){.portal .stepnav .where{display:none}.portal .stepnav button{min-width:0;flex:1 1 0}}

/* Wizard (2.5.0): one screen at a time (docs/design-system.md, "One screen at a time"). A slim head (the
   portal's name, one line on what it does, two quiet tools), a progress bar grouped by phase, one step that
   fills the screen, and Back and Next along the bottom on every screen size. */
.portal .wz-head{display:flex;align-items:center;gap:var(--space-3) var(--space-5);padding-block:22px 0;border-bottom:0}
.portal .wz-head .title{margin-right:auto;min-width:0}
.portal .wz-head h1{font:700 1.05rem/1.2 var(--display);margin:0}
.portal .wz-head .purpose{margin:2px 0 0;font-size:.86rem;color:var(--muted);max-width:none}
.portal .wz-tools{display:flex;gap:2px;flex-wrap:wrap}
.portal .wz-tool{display:inline-flex;align-items:center;gap:6px;min-height:36px;padding:0 10px;border:0;border-radius:var(--radius-sm);background:none;color:var(--muted);font:600 .86rem var(--body);text-decoration:none;cursor:pointer}
.portal .wz-tool:hover,.portal .wz-tool[aria-expanded="true"]{background:var(--sunken);color:var(--fg)}
.portal .wz-tool svg{width:16px;height:16px;flex:none}
@media (pointer:coarse){.portal .wz-tool{min-height:var(--tap)}}
/* Phones: the tools as icons (each keeps its name for screen readers in .t), and no purpose line. */
@media (max-width:560px){.portal .wz-head{padding-top:14px}.portal .wz-head .purpose{display:none}.portal .wz-tool{width:var(--tap);min-height:var(--tap);justify-content:center;padding:0}
  .portal .wz-tool>.t{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap}}

/* Progress: ol.wz-progress > li.phase[data-steps] > .phase-name + .segs > button.seg. A phase is as wide as its
   steps, so its name sits over its own steps. .seg.done, .seg.current; a disabled .seg is not reached yet. */
.portal ol.wz-progress{display:flex;gap:10px;margin:18px 0 0;padding:0;list-style:none}
.portal .wz-progress .phase{display:grid;gap:4px;min-width:0;flex:1}
.portal .wz-progress .phase[data-steps="2"]{flex:2} .portal .wz-progress .phase[data-steps="3"]{flex:3}
.portal .wz-progress .phase[data-steps="4"]{flex:4} .portal .wz-progress .phase[data-steps="5"]{flex:5}
.portal .wz-progress .phase-name{font-size:.78rem;font-weight:600;color:var(--muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.portal .wz-progress .phase.now .phase-name{color:var(--fg)}
.portal .wz-progress .segs{display:flex;gap:4px}
.portal .wz-progress button.seg{flex:1;min-width:0;height:22px;padding:0;border:0;border-radius:0;background:none;display:flex;align-items:center;cursor:pointer}
.portal .wz-progress button.seg::before{content:"";display:block;width:100%;height:4px;border-radius:2px;background:var(--line-strong)}
.portal .wz-progress button.seg:hover:not(:disabled){background:none}
.portal .wz-progress button.seg:hover:not(:disabled)::before{background:var(--accent-hover)}
.portal .wz-progress button.seg.done::before{background:var(--good)}
.portal .wz-progress button.seg.current::before{background:var(--accent);height:6px;border-radius:3px}
.portal .wz-progress button.seg:disabled{opacity:1;cursor:default}
.portal .wz-progress button.seg:disabled::before{background:var(--line)}
.portal .wz-progress button.seg:focus-visible{outline:2px solid var(--focus);outline-offset:2px}
@media (pointer:coarse){.portal .wz-progress button.seg{height:var(--tap)}}

/* Wizard layout (2.5.0): the steps as a list down the left, as the docs side list, and the step beside it.
   main.wz-layout > .wz-rail (the portal's name, ol.wz-list, .wz-tools) + the step column. Below 64rem the rail
   becomes a head over the step: the name and the tools on one row, then ol.wz-progress in place of the list. */
.portal .wz-layout{display:grid;grid-template-columns:14rem minmax(0,1fr);gap:var(--space-6);max-width:var(--page);margin:0 auto;
  padding-left:max(var(--gutter),env(safe-area-inset-left,0px));padding-right:max(var(--gutter),env(safe-area-inset-right,0px))}
.portal .wz-rail{position:sticky;top:calc(var(--bar) + 1px + env(safe-area-inset-top,0px));align-self:start;max-height:calc(100dvh - var(--bar) - 1px - env(safe-area-inset-top,0px));overflow-y:auto;scrollbar-width:thin;
  display:grid;gap:var(--space-4);align-content:start;padding-block:28px 24px;border:0}
.portal .wz-rail h1{font:700 1rem/1.25 var(--display);margin:0 0 0 10px}
.portal .wz-rail .purpose{margin:4px 0 0 10px;font-size:.8rem;color:var(--muted)}
.portal ol.wz-list{list-style:none;margin:0;padding:0;display:grid;gap:2px}
.portal .wz-list .group{font-size:.8rem;font-weight:600;color:var(--muted);margin:var(--space-4) 0 var(--space-1);padding-left:10px}
.portal .wz-list .group:first-child{margin-top:0}
.portal .wz-list button.step{display:flex;align-items:center;gap:10px;width:100%;min-height:36px;padding:0 10px;border:0;border-radius:var(--radius-sm);background:none;color:var(--fg);font:400 .9rem/1.2 var(--body);text-align:left}
.portal .wz-list button.step:hover:not(:disabled){background:var(--sunken);color:var(--fg)}
.portal .wz-list .n{flex:none;width:20px;height:20px;border-radius:50%;display:grid;place-items:center;font:600 .68rem var(--mono);border:1.5px solid var(--line-strong);color:var(--muted)}
.portal .wz-list button.step.done .n{background:var(--good);border-color:var(--good);color:var(--surface)}
.portal .wz-list button.step[aria-current="step"]{background:var(--accent-soft);color:var(--accent);font-weight:600}
.portal .wz-list button.step[aria-current="step"] .n{background:var(--accent);border-color:var(--accent);color:var(--on-accent)}
.portal .wz-list button.step:disabled{opacity:1;color:var(--muted)}
.portal .wz-list button.step:disabled .n{border-style:dashed}
.portal .wz-rail .wz-tools{display:grid;gap:2px;border-top:1px solid var(--line);padding-top:var(--space-3)}
.portal .wz-rail ol.wz-progress{display:none}
@media (pointer:coarse){.portal .wz-list button.step{min-height:var(--tap)}}
.portal .wz-nav.wide>.in{max-width:var(--page)}
@media (min-width:64.01rem){.portal .wz-nav.wide>.in{padding-left:calc(max(var(--gutter),env(safe-area-inset-left,0px)) + 14rem + var(--space-6))}}
@media (max-width:64rem){
  .portal .wz-layout{grid-template-columns:minmax(0,1fr);gap:0}
  .portal .wz-rail{position:static;max-height:none;overflow:visible;grid-template-columns:minmax(0,1fr) auto;gap:0 var(--space-3);align-items:center;padding-block:18px 0}
  .portal .wz-rail h1,.portal .wz-rail .purpose{margin-left:0}
  .portal .wz-rail ol.wz-list{display:none}
  .portal .wz-rail ol.wz-progress{display:flex;grid-column:1/-1}
  .portal .wz-rail .wz-tools{display:flex;border:0;padding:0;grid-row:1;grid-column:2}
}
@media (max-width:560px){.portal .wz-rail .purpose{display:none}}

/* The step: a large title, one line that says what to do, the one action, then detail behind details.more. */
.portal .wz-stage{padding-block:clamp(24px,5vh,56px) 40px}
.portal .wz-stage h2{font:700 clamp(1.8rem,1.3rem + 2vw,2.6rem)/1.08 var(--display);letter-spacing:-.02em;margin:0 0 10px}
.portal .wz-stage .purpose{font-size:1rem;color:var(--muted);margin:0 0 24px;max-width:56ch}
.portal .wz-stage .act{display:flex;flex-wrap:wrap;align-items:center;gap:var(--space-3) 18px;margin:0 0 var(--space-4)}
.portal .wz-stage .quiet{color:var(--muted);font-size:.86rem}
.portal details.more{border-top:1px solid var(--line);padding-top:var(--space-3);margin-top:var(--space-5);max-width:46rem}
.portal details.more>summary{cursor:pointer;list-style:none;display:inline-flex;align-items:center;gap:var(--space-2);min-height:32px;color:var(--muted);font-size:.88rem;font-weight:600}
.portal details.more>summary::-webkit-details-marker{display:none}
.portal details.more>summary::before{content:"+";font:600 1rem/1 var(--mono);color:var(--accent);width:1ch}
.portal details.more[open]>summary::before{content:"\2212"}
.portal details.more>summary:hover{color:var(--fg)}
.portal details.more>:not(summary){font-size:.92rem;color:var(--muted)}
.portal details.more>:nth-child(2){margin-top:var(--space-2)}

/* Run in, as one quiet line over a command block: "For Cloud Shell, PowerShell. Change". */
.portal .runline{display:flex;flex-wrap:wrap;align-items:center;gap:4px 10px;font-size:.84rem;color:var(--muted);margin:0 0 10px}
.portal .runline strong{color:var(--fg);font-weight:600}
.portal .runline button.linkbtn{font-size:.84rem;padding:0}

/* The answer to a paste, bottom line first, as a reply in a chat: .reply > .bl (the verdict, with .good, .ok or
   .poor and its word) then one or two plain sentences, then the next action. */
.portal .reply{background:var(--surface);border:1px solid var(--line);border-radius:4px var(--radius-lg) var(--radius-lg) var(--radius-lg);padding:14px 18px;box-shadow:var(--shadow)}
.portal .reply .bl{display:flex;align-items:center;gap:10px;font:600 1.15rem/1.3 var(--display);margin:0 0 6px;color:var(--fg)}
.portal .reply .bl::before{content:"\2022";flex:none;width:22px;height:22px;border-radius:50%;display:grid;place-items:center;font-size:.8rem;background:var(--accent-soft);color:var(--accent)}
.portal .reply .bl.good::before{content:"\2713";background:var(--good);color:var(--surface)}
.portal .reply .bl.ok::before{content:"\2026";background:var(--caution-soft);color:var(--caution)}
.portal .reply .bl.poor::before{content:"!";background:var(--bad-soft);color:var(--bad)}

/* Back and Next: one bar along the bottom of the screen, on every screen size. .where names the step. */
.portal .wz-nav{position:sticky;bottom:0;z-index:5;background:var(--bg);border-top:1px solid var(--line);box-shadow:0 -10px 18px -16px var(--shell)}
.portal .wz-nav>.in{display:flex;align-items:center;gap:var(--space-3);min-height:68px;max-width:980px;margin:0 auto;
  padding:10px max(var(--gutter),env(safe-area-inset-right,0px)) calc(10px + env(safe-area-inset-bottom,0px)) max(var(--gutter),env(safe-area-inset-left,0px))}
.portal .wz-nav .where{flex:1;min-width:0;text-align:center;font-size:.84rem;color:var(--muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.portal .wz-nav button{min-width:7.5rem}
@media (max-width:560px){.portal .wz-nav .where{display:none}.portal .wz-nav button{flex:1 1 0;min-width:0}.portal .wz-nav button:first-child{flex:0 0 auto}}

/* Sheet: a panel that slides over the step (Settings, Where did I leave off), with .sheet-backdrop behind it.
   Full width on a phone. The page toggles .hidden on both. */
.portal .sheet{position:fixed;z-index:40;top:calc(var(--bar) + 1px + env(safe-area-inset-top,0px));right:0;bottom:0;width:min(34rem,100vw);margin:0;overflow-y:auto;overscroll-behavior:contain;
  background:var(--surface);border:0;border-left:1px solid var(--line);border-radius:0;box-shadow:var(--shadow-2);padding:22px max(22px,env(safe-area-inset-right,0px)) calc(28px + env(safe-area-inset-bottom,0px)) 22px}
.portal button.sheet-backdrop{position:fixed;inset:0;z-index:35;background:var(--shell);opacity:.45;border:0;border-radius:0;padding:0;cursor:default}
.portal button.sheet-backdrop:hover{background:var(--shell);border:0}
.portal .sheet h2{font-size:1.3rem}
.portal .sheet .row{align-items:stretch}
@media (max-width:560px){.portal .sheet{border-left:0;padding-left:max(var(--gutter),env(safe-area-inset-left,0px));padding-right:max(var(--gutter),env(safe-area-inset-right,0px))}}

/* Terminal block: one Cloud Shell command with its own Copy button. */
.portal .term{border:1px solid var(--term-border);border-radius:var(--radius-sm);background:var(--term-bg);overflow:hidden}
.portal .term-head{display:flex;align-items:center;justify-content:space-between;gap:var(--space-2);padding:6px 8px 6px 12px;background:var(--term-head);border-bottom:1px solid var(--term-border)}
.portal .term-label{font:600 .78rem/1 var(--mono);color:var(--term-muted)}
.portal .term-label::before{content:"PS>";color:var(--prompt);margin-right:8px}
.portal .term[data-shell="bash"] .term-label::before{content:"$"}
.portal .term-head button{padding:4px 12px;font-size:.85rem;background:transparent;color:var(--term-text);border-color:var(--term-border)}
.portal .term-head button:hover:not(:disabled){background:var(--term-border);border-color:var(--term-muted);color:var(--term-text)}
.portal .term pre{background:transparent;border:0;border-radius:0;color:var(--term-text);margin:0;padding:14px;overflow-x:auto;font:12.5px/1.65 var(--mono);white-space:pre;tab-size:4}

/* Paste box: where the operator pastes a run's output. */
.portal textarea.paste{border-style:dashed;border-width:2px;background:var(--sunken);min-height:140px}
.portal textarea.paste:focus{border-style:solid}

/* Result chip: a run's overall result, always with its word. */
.portal .result{display:inline-block;font:600 .7rem/1.6 var(--mono);letter-spacing:.06em;text-transform:uppercase;border-radius:4px;padding:1px 8px;background:var(--accent-soft);color:var(--accent)}
.portal .result.good{color:var(--good);background:var(--good-soft)}
.portal .result.ok{color:var(--caution);background:var(--caution-soft)}
.portal .result.poor{color:var(--bad);background:var(--bad-soft)}

/* Check outcome pill: pass, warn, gap or unknown, always with its word, never color alone. */
.portal .outcome{display:inline-block;font:600 .7rem/1.6 var(--mono);letter-spacing:.06em;text-transform:uppercase;border-radius:var(--pill);padding:1px 9px;border:1px solid transparent;white-space:nowrap}
.portal .outcome.o-pass{color:var(--good);background:var(--good-soft)}
.portal .outcome.o-warn{color:var(--caution);background:var(--caution-soft)}
.portal .outcome.o-gap{color:var(--bad);background:var(--bad-soft)}
.portal .outcome.o-unknown{color:var(--muted);background:var(--sunken);border-color:var(--line)}


/* File drop: a labeled file input with a drop zone. The page fills .file with the name and size, and .error on
   a schema mismatch. The file is read in the browser and never uploaded; the hint says so. */
.portal .filedrop{display:block;position:relative;border:2px dashed var(--line-strong);border-radius:var(--radius);background:var(--sunken);padding:var(--space-5) var(--space-4);text-align:center;cursor:pointer;transition:border-color var(--fast) var(--ease),background var(--fast) var(--ease)}
.portal .filedrop:hover,.portal .filedrop.over{border-color:var(--accent);background:var(--accent-soft)}
.portal .filedrop:focus-within{border-style:solid;border-color:var(--accent)}
.portal .filedrop input[type=file]{position:absolute;inset:0;opacity:0;cursor:pointer;width:100%}
.portal .filedrop .what{font-weight:600;display:block}
.portal .filedrop .hint{display:block;color:var(--muted);font-size:.85rem}
.portal .filedrop .file{display:block;margin-top:var(--space-2);font:.85rem var(--mono);color:var(--fg)}
.portal .filedrop .error{display:block;margin-top:var(--space-2);color:var(--bad);font-weight:600}

/* Key and value table, and a table that scrolls inside its own border. */
.portal .table-wrap{overflow-x:auto;border:1px solid var(--line);border-radius:var(--radius-sm);background:var(--surface)}
.portal .table-wrap th{font:600 .82rem var(--body);color:var(--muted);background:var(--sunken)}
.portal .table-wrap tbody tr:last-child td{border-bottom:0}
.portal table.kv td:first-child{color:var(--muted);width:40%}
.portal td.num{text-align:right;font:.88rem var(--mono);font-variant-numeric:tabular-nums}

@media (prefers-reduced-motion:reduce){.portal *,.portal *::before,.portal *::after{transition:none!important;animation:none!important}}
