prreviewbuddy 0.95.2 → 0.96.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- import{d as e,ft as t,m as n,o as r,t as i,xt as a}from"./chunk-Cs33-tV3.js";function o(e){let t=[...document.querySelectorAll(`[data-shutdown]`)],n=document.querySelector(`[data-shutdown-dialog]`),r=document.querySelector(`[data-shutdown-confirm]`);for(let e of t)e.addEventListener(`click`,()=>n?.showModal());document.querySelector(`[data-shutdown-cancel]`)?.addEventListener(`click`,()=>n?.close()),r?.addEventListener(`click`,()=>{r.disabled=!0,r.textContent=`Stopping…`,fetch(e,{method:`POST`}).then(e=>{if(!e.ok)throw Error(`Shutdown refused: ${e.status}`);n?.close(),s(t)}).catch(()=>{r.disabled=!1,r.textContent=`Stop server`})})}function s(t){document.body.dataset.serverStopped=`true`,e(document,`unreachable`);let n=document.createElement(`div`);n.className=`prb-stopped-notice`,n.setAttribute(`role`,`status`);let r=document.body.dataset.wayBack;n.textContent=r?`Workspace server stopped. This page is no longer being served. Run ${r} to bring it back.`:`Workspace server stopped. This page is no longer being served.`,document.body.prepend(n);for(let e of t)e.disabled=!0,e.classList.contains(`prb-strip-action`)||(e.textContent=`Server stopped`)}var c=[{id:`system`,label:`System`,help:`Follow your device setting`},{id:`light`,label:`Light`,help:`Always use light mode`},{id:`dark`,label:`Dark`,help:`Always use dark mode`}];function l(e){return c.some(t=>t.id===e)}function u(e){let t=e.querySelector(`[data-settings-theme]:checked`)?.value;return l(t)?t:void 0}function d(e,t){e.documentElement.dataset.theme=t}function f(e){for(let t of e.querySelectorAll(`[data-settings-theme]`))t.addEventListener(`change`,()=>{let t=u(e);t&&d(e,t)})}var p=/^[A-Za-z0-9_\/.:=@%+,-]+$/;function m(e){return e!==``&&p.test(e)?e:`'${e.replace(/'/g,`'\\''`)}'`}function h(e){return e===`~`?`"$HOME"`:e.startsWith(`~/`)?`"$HOME"/${m(e.slice(2))}`:m(e)}var g=new Set([`connected`,`already-connected`,`replaced`,`disconnected`,`working`]);function _(e){return{agent:e.dataset.integration??``,name:e.dataset.name??``,config:e.dataset.config??``,add:e.dataset.addCommand??``,remove:e.dataset.removeCommand??``,registered:e.dataset.registered??``}}function v(e,t){return e===`connect`?{title:`Connect PR Review Buddy to ${t.name}?`,body:`This runs the command below, which adds PR Review Buddy to ${t.name}'s config at ${t.config}. Nothing else in it changes.`,command:t.add,note:`Start a new ${t.name} session afterwards to use it.`,confirm:`Connect`,danger:!1}:e===`replace`?{title:`Replace the PR Review Buddy ${t.name} uses?`,body:`${t.name} now starts ${t.registered}. This removes that registration and adds this copy of PR Review Buddy instead.`,command:`${t.remove}\n${t.add}`,note:`If the new one is not accepted, the previous registration is put back.`,confirm:`Replace`,danger:!1}:{title:`Disconnect ${t.name}?`,body:`This removes PR Review Buddy from ${t.name}'s config at ${t.config}. Your reviews are not affected.`,command:t.remove,note:`Sessions already open keep it until they end.`,confirm:`Disconnect`,danger:!0}}function y(e,t,n){let r=t.trim();return r?`${e}=${h(r)} ${n}`:``}var b={connect:`Connecting…`,replace:`Replacing…`,disconnect:`Disconnecting…`,verify:`Checking…`};function x(e,t=window){let n=e.querySelector(`[data-integrations]`),r=e.querySelector(`[data-integration-dialog]`);if(!n)return;function i(t,n,r,i){let a=t.querySelector(`[data-integration-result]`);if(a&&(a.textContent=n,a.dataset.kind=r?`ok`:`error`,i)){let t=e.createElement(`pre`),n=e.createElement(`code`);n.textContent=i,t.append(n),a.after(t)}}function a(e){if(!r)return Promise.resolve(t.confirm(`${e.title}\n\n${e.command}`));let n=(e,t)=>{let n=r.querySelector(e);n&&(n.textContent=t)};n(`[data-integration-dialog-title]`,e.title),n(`[data-integration-dialog-body]`,e.body),n(`[data-integration-dialog-command]`,e.command),n(`[data-integration-dialog-note]`,e.note);let i=r.querySelector(`[data-integration-confirm]`);return i&&(i.textContent=e.confirm,i.classList.toggle(`prb-dialog-danger`,e.danger),i.classList.toggle(`prb-dialog-primary`,!e.danger)),new Promise(e=>{let t=t=>{r.removeEventListener(`close`,o),i?.removeEventListener(`click`,n),s?.removeEventListener(`click`,a),r.open&&r.close(),e(t)},n=()=>t(!0),a=()=>t(!1),o=()=>t(!1),s=r.querySelector(`[data-integration-cancel]`);i?.addEventListener(`click`,n),s?.addEventListener(`click`,a),r.addEventListener(`close`,o),r.showModal(),s?.focus()})}async function o(e){try{let n=await t.fetch(`/settings`,{headers:{accept:`text/html`}});return n.ok?new DOMParser().parseFromString(await n.text(),`text/html`).querySelector(`[data-integration="${CSS.escape(e)}"]`):null}catch{return null}}async function s(e,n,r){let s=_(e);if(n!==`verify`&&!await a(v(n,s)))return;let c=[...e.querySelectorAll(`button`)],l=r.textContent;c.forEach(e=>e.disabled=!0),r.textContent=b[n],e.setAttribute(`aria-busy`,`true`);let u=null,d=null;try{let e=await t.fetch(`/integrations`,{method:`POST`,headers:{"content-type":`application/json`},body:JSON.stringify({agent:s.agent,action:n===`replace`?`connect`:n,replace:n===`replace`})}),r=await e.json().catch(()=>null);!e.ok||!r||typeof r.message!=`string`?d=r?.error??`Nothing was changed. The workspace server did not answer.`:u=r}catch{d=`Nothing was changed. The workspace server could not be reached.`}let f=u?await o(s.agent):null,p=f??e;f?e.replaceWith(f):(c.forEach(e=>e.disabled=!1),r.textContent=l,e.removeAttribute(`aria-busy`)),u?i(p,u.message,g.has(u.outcome),u.previousCommand):i(p,d??`Nothing was changed.`,!1),p.querySelector(`[data-integration-action], [data-integration-copy]`)?.focus()}async function c(e,n,r){try{await t.navigator.clipboard.writeText(n),i(e,`Copied. Run it in a terminal, then start a new agent session.`,!0)}catch{let n=e.querySelector(`.prb-integration-manual`);n&&(n.open=!0);let r=n?.querySelector(`code`);r&&t.getSelection()?.selectAllChildren(r),i(e,`The browser would not copy it. The command is selected below.`,!1)}r.focus()}n.addEventListener(`click`,e=>{let t=e.target,n=t.closest(`[data-integration]`);if(!n)return;let r=t.closest(`[data-integration-action]`);if(r)return void s(n,r.dataset.integrationAction,r);let i=t.closest(`[data-integration-copy]`);if(i)return void c(n,n.dataset.addCommand??``,i);let a=t.closest(`[data-profile-copy]`);if(a){let e=n.querySelector(`[data-profile-command]`)?.textContent??``;e&&c(n,e,a)}}),n.addEventListener(`input`,e=>{let t=e.target;if(!t.matches(`[data-profile-dir]`))return;let n=t.closest(`[data-integration]`),r=t.closest(`[data-integration-profile]`);if(!n||!r)return;let i=y(r.dataset.profileVariable??``,t.value,r.dataset.profileAddCommand??``),a=r.querySelector(`[data-profile-output]`),o=r.querySelector(`[data-profile-command]`),s=r.querySelector(`[data-profile-copy]`);o&&(o.textContent=i),a&&(a.hidden=!i),s&&(s.hidden=!i)})}o(`/shutdown`),t(),n(`global`,{}),i(`/restart`),f(document),x(document);var S=document.querySelector(`[data-settings-save]`),C=document.querySelector(`[data-settings-status]`),w=document.querySelector(`[data-settings-port]`),T=document.querySelector(`[data-settings-port-error]`),E=document.querySelector(`[data-settings-agent]`);function D(){let e=document.querySelector(`[data-settings-usage]:checked`);return e?e.value===`on`:void 0}function O(e,t){C&&(C.textContent=e,C.dataset.kind=t)}function k(e){T&&(T.textContent=e??``),w&&(e?(w.setAttribute(`aria-invalid`,`true`),w.focus(),w.select()):w.removeAttribute(`aria-invalid`))}async function A(){if(!S)return;let e=D(),t=u(document),n={...w?{port:w.value.trim()}:{},...E?{agent:E.value}:{},...e===void 0?{}:{usageCounts:e},...t===void 0?{}:{theme:t}};S.disabled=!0,S.textContent=`Saving`;try{let e=await(await fetch(`/settings`,{method:`POST`,headers:{"content-type":`application/json`},body:JSON.stringify(n)})).json().catch(()=>null);if(!e){O(`Nothing was saved. The workspace server did not answer.`,`error`);return}if(e.error){k(e.error),O(`Nothing was saved.`,`error`);return}k(null),w&&(w.value=String(e.port.configured)),d(document,e.theme),O(e.restartRequired?`Saved. This page is served on port ${e.port.current}; the workspace moves to ${e.port.configured} the next time it starts.`:`Saved.`,`saved`)}catch{O(`Nothing was saved. The workspace server could not be reached.`,`error`)}finally{S.disabled=!1,S.textContent=`Save changes`}}S?.addEventListener(`click`,()=>void A()),r(document,window,{paintUnread:!0}),a(window,()=>window.location.reload());
1
+ import{Ct as e,d as t,m as n,mt as r,o as i,t as a}from"./chunk-C0JUspm9.js";function o(e){let t=[...document.querySelectorAll(`[data-shutdown]`)],n=document.querySelector(`[data-shutdown-dialog]`),r=document.querySelector(`[data-shutdown-confirm]`);for(let e of t)e.addEventListener(`click`,()=>n?.showModal());document.querySelector(`[data-shutdown-cancel]`)?.addEventListener(`click`,()=>n?.close()),r?.addEventListener(`click`,()=>{r.disabled=!0,r.textContent=`Stopping…`,fetch(e,{method:`POST`}).then(e=>{if(!e.ok)throw Error(`Shutdown refused: ${e.status}`);n?.close(),s(t)}).catch(()=>{r.disabled=!1,r.textContent=`Stop server`})})}function s(e){document.body.dataset.serverStopped=`true`,t(document,`unreachable`);let n=document.createElement(`div`);n.className=`prb-stopped-notice`,n.setAttribute(`role`,`status`);let r=document.body.dataset.wayBack;n.textContent=r?`Workspace server stopped. This page is no longer being served. Run ${r} to bring it back.`:`Workspace server stopped. This page is no longer being served.`,document.body.prepend(n);for(let t of e)t.disabled=!0,t.classList.contains(`prb-strip-action`)||(t.textContent=`Server stopped`)}var c=[{id:`system`,label:`System`,help:`Follow your device setting`},{id:`light`,label:`Light`,help:`Always use light mode`},{id:`dark`,label:`Dark`,help:`Always use dark mode`}];function l(e){return c.some(t=>t.id===e)}function u(e){let t=e.querySelector(`[data-settings-theme]:checked`)?.value;return l(t)?t:void 0}function d(e,t){e.documentElement.dataset.theme=t}function f(e){for(let t of e.querySelectorAll(`[data-settings-theme]`))t.addEventListener(`change`,()=>{let t=u(e);t&&d(e,t)})}var p=/^[A-Za-z0-9_\/.:=@%+,-]+$/;function m(e){return e!==``&&p.test(e)?e:`'${e.replace(/'/g,`'\\''`)}'`}function h(e){return e===`~`?`"$HOME"`:e.startsWith(`~/`)?`"$HOME"/${m(e.slice(2))}`:m(e)}var g=new Set([`connected`,`already-connected`,`replaced`,`disconnected`,`working`]);function _(e){return{agent:e.dataset.integration??``,name:e.dataset.name??``,config:e.dataset.config??``,add:e.dataset.addCommand??``,remove:e.dataset.removeCommand??``,registered:e.dataset.registered??``}}function v(e,t){return e===`connect`?{title:`Connect PR Review Buddy to ${t.name}?`,body:`This runs the command below, which adds PR Review Buddy to ${t.name}'s config at ${t.config}. Nothing else in it changes.`,command:t.add,note:`Start a new ${t.name} session afterwards to use it.`,confirm:`Connect`,danger:!1}:e===`replace`?{title:`Replace the PR Review Buddy ${t.name} uses?`,body:`${t.name} now starts ${t.registered}. This removes that registration and adds this copy of PR Review Buddy instead.`,command:`${t.remove}\n${t.add}`,note:`If the new one is not accepted, the previous registration is put back.`,confirm:`Replace`,danger:!1}:{title:`Disconnect ${t.name}?`,body:`This removes PR Review Buddy from ${t.name}'s config at ${t.config}. Your reviews are not affected.`,command:t.remove,note:`Sessions already open keep it until they end.`,confirm:`Disconnect`,danger:!0}}function y(e,t,n){let r=t.trim();return r?`${e}=${h(r)} ${n}`:``}var b={connect:`Connecting…`,replace:`Replacing…`,disconnect:`Disconnecting…`,verify:`Checking…`};function x(e,t=window){let n=e.querySelector(`[data-integrations]`),r=e.querySelector(`[data-integration-dialog]`);if(!n)return;function i(t,n,r,i){let a=t.querySelector(`[data-integration-result]`);if(a&&(a.textContent=n,a.dataset.kind=r?`ok`:`error`,i)){let t=e.createElement(`pre`),n=e.createElement(`code`);n.textContent=i,t.append(n),a.after(t)}}function a(e){if(!r)return Promise.resolve(t.confirm(`${e.title}\n\n${e.command}`));let n=(e,t)=>{let n=r.querySelector(e);n&&(n.textContent=t)};n(`[data-integration-dialog-title]`,e.title),n(`[data-integration-dialog-body]`,e.body),n(`[data-integration-dialog-command]`,e.command),n(`[data-integration-dialog-note]`,e.note);let i=r.querySelector(`[data-integration-confirm]`);return i&&(i.textContent=e.confirm,i.classList.toggle(`prb-dialog-danger`,e.danger),i.classList.toggle(`prb-dialog-primary`,!e.danger)),new Promise(e=>{let t=t=>{r.removeEventListener(`close`,o),i?.removeEventListener(`click`,n),s?.removeEventListener(`click`,a),r.open&&r.close(),e(t)},n=()=>t(!0),a=()=>t(!1),o=()=>t(!1),s=r.querySelector(`[data-integration-cancel]`);i?.addEventListener(`click`,n),s?.addEventListener(`click`,a),r.addEventListener(`close`,o),r.showModal(),s?.focus()})}async function o(e){try{let n=await t.fetch(`/settings`,{headers:{accept:`text/html`}});return n.ok?new DOMParser().parseFromString(await n.text(),`text/html`).querySelector(`[data-integration="${CSS.escape(e)}"]`):null}catch{return null}}async function s(e,n,r){let s=_(e);if(n!==`verify`&&!await a(v(n,s)))return;let c=[...e.querySelectorAll(`button`)],l=r.textContent;c.forEach(e=>e.disabled=!0),r.textContent=b[n],e.setAttribute(`aria-busy`,`true`);let u=null,d=null;try{let e=await t.fetch(`/integrations`,{method:`POST`,headers:{"content-type":`application/json`},body:JSON.stringify({agent:s.agent,action:n===`replace`?`connect`:n,replace:n===`replace`})}),r=await e.json().catch(()=>null);!e.ok||!r||typeof r.message!=`string`?d=r?.error??`Nothing was changed. The workspace server did not answer.`:u=r}catch{d=`Nothing was changed. The workspace server could not be reached.`}let f=u?await o(s.agent):null,p=f??e;f?e.replaceWith(f):(c.forEach(e=>e.disabled=!1),r.textContent=l,e.removeAttribute(`aria-busy`)),u?i(p,u.message,g.has(u.outcome),u.previousCommand):i(p,d??`Nothing was changed.`,!1),p.querySelector(`[data-integration-action], [data-integration-copy]`)?.focus()}async function c(e,n,r){try{await t.navigator.clipboard.writeText(n),i(e,`Copied. Run it in a terminal, then start a new agent session.`,!0)}catch{let n=e.querySelector(`.prb-integration-manual`);n&&(n.open=!0);let r=n?.querySelector(`code`);r&&t.getSelection()?.selectAllChildren(r),i(e,`The browser would not copy it. The command is selected below.`,!1)}r.focus()}n.addEventListener(`click`,e=>{let t=e.target,n=t.closest(`[data-integration]`);if(!n)return;let r=t.closest(`[data-integration-action]`);if(r)return void s(n,r.dataset.integrationAction,r);let i=t.closest(`[data-integration-copy]`);if(i)return void c(n,n.dataset.addCommand??``,i);let a=t.closest(`[data-profile-copy]`);if(a){let e=n.querySelector(`[data-profile-command]`)?.textContent??``;e&&c(n,e,a)}}),n.addEventListener(`input`,e=>{let t=e.target;if(!t.matches(`[data-profile-dir]`))return;let n=t.closest(`[data-integration]`),r=t.closest(`[data-integration-profile]`);if(!n||!r)return;let i=y(r.dataset.profileVariable??``,t.value,r.dataset.profileAddCommand??``),a=r.querySelector(`[data-profile-output]`),o=r.querySelector(`[data-profile-command]`),s=r.querySelector(`[data-profile-copy]`);o&&(o.textContent=i),a&&(a.hidden=!i),s&&(s.hidden=!i)})}o(`/shutdown`),r(),n(`global`,{}),a(`/restart`),f(document),x(document);var S=document.querySelector(`[data-settings-save]`),C=document.querySelector(`[data-settings-status]`),w=document.querySelector(`[data-settings-port]`),T=document.querySelector(`[data-settings-port-error]`),E=document.querySelector(`[data-settings-agent]`);function D(){let e=document.querySelector(`[data-settings-usage]:checked`);return e?e.value===`on`:void 0}function O(e,t){C&&(C.textContent=e,C.dataset.kind=t)}function k(e){T&&(T.textContent=e??``),w&&(e?(w.setAttribute(`aria-invalid`,`true`),w.focus(),w.select()):w.removeAttribute(`aria-invalid`))}async function A(){if(!S)return;let e=D(),t=u(document),n={...w?{port:w.value.trim()}:{},...E?{agent:E.value}:{},...e===void 0?{}:{usageCounts:e},...t===void 0?{}:{theme:t}};S.disabled=!0,S.textContent=`Saving`;try{let e=await(await fetch(`/settings`,{method:`POST`,headers:{"content-type":`application/json`},body:JSON.stringify(n)})).json().catch(()=>null);if(!e){O(`Nothing was saved. The workspace server did not answer.`,`error`);return}if(e.error){k(e.error),O(`Nothing was saved.`,`error`);return}k(null),w&&(w.value=String(e.port.configured)),d(document,e.theme),O(e.restartRequired?`Saved. This page is served on port ${e.port.current}; the workspace moves to ${e.port.configured} the next time it starts.`:`Saved.`,`saved`)}catch{O(`Nothing was saved. The workspace server could not be reached.`,`error`)}finally{S.disabled=!1,S.textContent=`Save changes`}}S?.addEventListener(`click`,()=>void A()),i(document,window,{paintUnread:!0}),e(window,()=>window.location.reload());
package/static/shell.css CHANGED
@@ -5812,6 +5812,7 @@ span.prb-arch-location:hover { text-decoration: none; }
5812
5812
  * control in several sizes, and a caret that differed between them would be a bug nobody could name. */
5813
5813
  .prb-index-status select,
5814
5814
  .prb-settings-field select,
5815
+ .prb-qr-picker select,
5815
5816
  select.prb-addreview-control {
5816
5817
  appearance: none;
5817
5818
  -webkit-appearance: none;
@@ -7293,3 +7294,294 @@ select.prb-addreview-control { padding-right: 32px; }
7293
7294
  }
7294
7295
  .prb-tour-actions .prb-tour-next:hover { border-color: var(--brand-hover); background: var(--brand-hover); }
7295
7296
  .prb-tour-actions button[hidden] { display: none; }
7297
+
7298
+ /* ── Quick Review ──
7299
+ One review's brief over the Reviews list (client/quick_review.ts). Sized in script to the content
7300
+ area right of the sidebar, inset at most 16px and at most 2.5% each way, so the UA's own dialog
7301
+ limits are lifted here and the box is exactly what the script measured. */
7302
+ .prb-quick-review {
7303
+ position: fixed;
7304
+ inset: auto;
7305
+ left: var(--qr-left, 2.5vw);
7306
+ top: var(--qr-top, 2.5vh);
7307
+ width: var(--qr-width, 95vw);
7308
+ height: var(--qr-height, 95vh);
7309
+ max-width: none;
7310
+ max-height: none;
7311
+ margin: 0;
7312
+ padding: 0;
7313
+ box-sizing: border-box;
7314
+ border: 1px solid var(--border);
7315
+ border-radius: 12px;
7316
+ background: var(--surface-raised);
7317
+ color: var(--text-primary);
7318
+ font: inherit;
7319
+ box-shadow: 0 18px 48px var(--shadow-float);
7320
+ }
7321
+ .prb-quick-review[open] { display: flex; flex-direction: column; }
7322
+ .prb-quick-review::backdrop { background: var(--backdrop); }
7323
+ .prb-qr-head {
7324
+ display: flex;
7325
+ flex-wrap: wrap;
7326
+ align-items: center;
7327
+ gap: 8px 16px;
7328
+ padding: 14px 20px 10px;
7329
+ border-bottom: 1px solid var(--border);
7330
+ }
7331
+ .prb-qr-identity { flex: 1 1 320px; min-width: 0; }
7332
+ .prb-qr-title { margin: 0; font-size: var(--t-title); line-height: var(--lh-tight); overflow-wrap: anywhere; }
7333
+ .prb-qr-sub { margin: 2px 0 0; font-size: var(--t-meta); color: var(--text-secondary); }
7334
+ .prb-qr-controls { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
7335
+ .prb-qr-position { margin: 0 4px 0 0; font-size: var(--t-meta); color: var(--text-secondary); font-variant-numeric: tabular-nums; }
7336
+ .prb-qr-button {
7337
+ padding: 4px 12px;
7338
+ border: 1px solid var(--border);
7339
+ border-radius: 8px;
7340
+ background: transparent;
7341
+ color: var(--text-secondary);
7342
+ font: inherit;
7343
+ font-size: var(--t-meta);
7344
+ cursor: pointer;
7345
+ }
7346
+ .prb-qr-button:hover:not(:disabled) { color: var(--text-primary); border-color: var(--border-strong); }
7347
+ .prb-qr-button:disabled { opacity: 0.5; cursor: default; }
7348
+ .prb-qr-menu-host { position: relative; display: inline-flex; align-items: center; gap: 2px; }
7349
+ /* A card places its menu in its corner; in the header it is one more control in the row. */
7350
+ .prb-qr-menu-host > .prb-menu { position: relative; top: auto; right: auto; }
7351
+ .prb-qr-menu-host:empty { display: none; }
7352
+ .prb-qr-outcomes {
7353
+ display: flex;
7354
+ flex-wrap: wrap;
7355
+ align-items: center;
7356
+ gap: 6px 12px;
7357
+ padding: 8px 20px;
7358
+ border-bottom: 1px solid var(--border);
7359
+ background: var(--surface);
7360
+ }
7361
+ .prb-qr-standing { margin: 0; font-size: var(--t-meta); color: var(--text-secondary); }
7362
+ .prb-qr-standing[data-current] { color: var(--text-primary); font-weight: 600; }
7363
+ .prb-qr-outcome-buttons { display: flex; flex-wrap: wrap; gap: 6px; }
7364
+ .prb-qr-outcome-note { margin: 0; font-size: var(--t-meta); color: var(--text-secondary); }
7365
+ .prb-qr-outcome-note:empty { display: none; }
7366
+ .prb-qr-scope { flex-basis: 100%; margin: 0; font-size: var(--t-micro); color: var(--text-muted); }
7367
+ .prb-qr-notice {
7368
+ margin: 0;
7369
+ padding: 6px 20px;
7370
+ font-size: var(--t-meta);
7371
+ background: var(--warning-subtle);
7372
+ color: var(--warning-ink);
7373
+ }
7374
+ .prb-qr-body {
7375
+ flex: 1 1 auto;
7376
+ min-height: 0;
7377
+ overflow-y: auto;
7378
+ padding: 8px 20px 32px;
7379
+ outline: none;
7380
+ scroll-behavior: auto;
7381
+ }
7382
+ .prb-qr-section { padding: 14px 0; border-bottom: 1px solid var(--border); }
7383
+ .prb-qr-section:last-child { border-bottom: none; }
7384
+ .prb-qr-heading { margin: 0 0 8px; font-size: var(--t-section); }
7385
+ .prb-qr-subheading { margin: 12px 0 6px; font-size: var(--t-meta); text-transform: uppercase; letter-spacing: 0.04em; color: var(--text-secondary); }
7386
+ .prb-qr-body p { margin: 0 0 8px; font-size: var(--t-body); line-height: var(--lh-body); }
7387
+ .prb-qr-body code { font-size: var(--t-code); }
7388
+ .prb-qr-muted, .prb-qr-body .prb-qr-muted { color: var(--text-secondary); }
7389
+ .prb-qr-list { margin: 0 0 8px; padding-left: 18px; font-size: var(--t-body); line-height: var(--lh-body); }
7390
+ .prb-qr-list li { margin: 2px 0; }
7391
+ .prb-qr-since-headline { font-weight: 600; }
7392
+ .prb-qr-stale { padding: 8px 12px; border-radius: 8px; background: var(--warning-subtle); color: var(--warning-ink); }
7393
+ .prb-qr-themes { color: var(--text-secondary); }
7394
+ .prb-qr-details { margin: 6px 0; }
7395
+ .prb-qr-details > summary { cursor: pointer; font-size: var(--t-meta); color: var(--link); }
7396
+ .prb-qr-details[open] > summary { margin-bottom: 6px; }
7397
+ .prb-qr-full > summary { cursor: pointer; padding: 12px 0; font-size: var(--t-section); font-weight: 600; }
7398
+ .prb-qr-change { display: grid; grid-template-columns: 1fr auto 1fr; gap: 12px; align-items: start; }
7399
+ .prb-qr-change-side { padding: 10px 12px; border: 1px solid var(--border); border-radius: 8px; background: var(--surface); }
7400
+ .prb-qr-change-side .prb-qr-subheading { margin-top: 0; }
7401
+ .prb-qr-change-arrow { align-self: center; color: var(--text-muted); font-size: var(--t-section); }
7402
+ .prb-qr-why-status { display: inline-block; padding: 1px 8px; border-radius: 999px; font-size: var(--t-micro); background: var(--neutral-subtle); color: var(--text-secondary); }
7403
+ .prb-qr-why-stated { background: var(--success-subtle); color: var(--success-ink); }
7404
+ .prb-qr-why-unclear { background: var(--warning-subtle); color: var(--warning-ink); }
7405
+ .prb-qr-chip {
7406
+ display: inline-block;
7407
+ margin-right: 6px;
7408
+ padding: 1px 8px;
7409
+ border-radius: 999px;
7410
+ font-size: var(--t-micro);
7411
+ background: var(--neutral-subtle);
7412
+ color: var(--text-secondary);
7413
+ white-space: nowrap;
7414
+ }
7415
+ .prb-qr-chip-state[data-pr-state="merged"] { background: var(--merged-subtle); color: var(--merged-ink); }
7416
+ .prb-qr-chip-state[data-pr-state="open"] { background: var(--success-subtle); color: var(--success-ink); }
7417
+ .prb-qr-deps, .prb-qr-findings { list-style: none; margin: 0 0 8px; padding: 0; }
7418
+ .prb-qr-dep {
7419
+ display: flex;
7420
+ flex-wrap: wrap;
7421
+ align-items: center;
7422
+ gap: 4px 6px;
7423
+ padding: 6px 0;
7424
+ border-bottom: 1px solid var(--border);
7425
+ font-size: var(--t-body);
7426
+ }
7427
+ .prb-qr-dep-title { flex: 1 1 200px; min-width: 0; }
7428
+ .prb-qr-dep-actions { display: inline-flex; flex-wrap: wrap; gap: 10px; }
7429
+ .prb-qr-evidence { flex-basis: 100%; font-size: var(--t-meta); }
7430
+ .prb-qr-suppressed .prb-qr-dep-title { color: var(--text-secondary); }
7431
+ .prb-qr-link, .prb-qr-link-button, .prb-qr-ref {
7432
+ padding: 0;
7433
+ border: none;
7434
+ background: none;
7435
+ color: var(--link);
7436
+ font: inherit;
7437
+ font-size: var(--t-meta);
7438
+ text-decoration: none;
7439
+ cursor: pointer;
7440
+ }
7441
+ .prb-qr-link:hover, .prb-qr-link-button:hover, .prb-qr-ref:hover { opacity: 0.8; text-decoration: none; }
7442
+ .prb-qr-ref { font-family: var(--font-mono, ui-monospace, monospace); }
7443
+ .prb-qr-links { display: flex; flex-wrap: wrap; gap: 16px; }
7444
+ /* Link a dependency: the Settings field's box (.prb-settings-field), so a form here reads as the
7445
+ product's own and not the browser's. The review field takes the rest of the row; the direction
7446
+ holds two short values and keeps its own width. */
7447
+ .prb-qr-picker { display: flex; flex-wrap: wrap; align-items: end; gap: 10px 12px; padding: 4px 0 2px; }
7448
+ .prb-qr-picker-field { display: flex; flex-direction: column; gap: 5px; min-width: 0; }
7449
+ .prb-qr-picker-review { flex: 1 1 280px; }
7450
+ .prb-qr-picker-label {
7451
+ font-size: var(--t-micro);
7452
+ letter-spacing: 0.04em;
7453
+ text-transform: uppercase;
7454
+ color: var(--text-tertiary, var(--text-secondary));
7455
+ }
7456
+ .prb-qr-picker select,
7457
+ .prb-qr-combo input {
7458
+ box-sizing: border-box;
7459
+ height: 36px;
7460
+ padding: 0 10px;
7461
+ border: 1px solid var(--border);
7462
+ border-radius: 8px;
7463
+ background-color: var(--surface-2);
7464
+ color: var(--text-primary);
7465
+ font: inherit;
7466
+ font-size: var(--t-body);
7467
+ }
7468
+ .prb-qr-picker select { padding-right: 32px; cursor: pointer; }
7469
+ .prb-qr-combo input::placeholder { color: var(--text-muted); }
7470
+ .prb-qr-picker select:focus,
7471
+ .prb-qr-combo input:focus { outline: none; border-color: var(--brand); }
7472
+ .prb-qr-picker-submit { height: 36px; padding: 0 16px; font-size: var(--t-body); }
7473
+ .prb-qr-combo { position: relative; }
7474
+ .prb-qr-combo input { width: 100%; }
7475
+ /* The open list: the filter menu's panel (.prb-index-status select::picker), hung under the box. */
7476
+ .prb-qr-combo-list {
7477
+ position: absolute;
7478
+ z-index: 3;
7479
+ top: calc(100% + 6px);
7480
+ left: 0;
7481
+ right: 0;
7482
+ max-height: 248px;
7483
+ overflow: auto;
7484
+ margin: 0;
7485
+ padding: 5px;
7486
+ list-style: none;
7487
+ border: 1px solid var(--border);
7488
+ border-radius: 9px;
7489
+ background: var(--surface-raised);
7490
+ box-shadow: 0 10px 28px var(--shadow-float);
7491
+ }
7492
+ .prb-qr-combo-list [role="option"] {
7493
+ padding: 7px 9px;
7494
+ border-radius: 6px;
7495
+ color: var(--text-secondary);
7496
+ font-size: var(--t-meta);
7497
+ white-space: nowrap;
7498
+ overflow: hidden;
7499
+ text-overflow: ellipsis;
7500
+ cursor: pointer;
7501
+ }
7502
+ .prb-qr-combo-list [role="option"]:hover,
7503
+ .prb-qr-combo-list [role="option"][data-active] { background: var(--surface-2); color: var(--text-primary); }
7504
+ .prb-qr-combo-list [role="option"][aria-selected="true"] { background: var(--brand-muted); color: var(--brand-ink); }
7505
+ .prb-qr-combo-empty { padding: 7px 9px; color: var(--text-muted); font-size: var(--t-meta); }
7506
+ .prb-qr-combo-list [hidden] { display: none; }
7507
+ .prb-qr-finding {
7508
+ margin: 0 0 10px;
7509
+ padding: 10px 12px;
7510
+ border: 1px solid var(--border);
7511
+ border-radius: 8px;
7512
+ background: var(--surface);
7513
+ }
7514
+ .prb-qr-question { border-style: dashed; }
7515
+ .prb-qr-finding-meta { display: flex; align-items: center; gap: 6px; margin-bottom: 4px; }
7516
+ .prb-qr-ref-label { font-family: var(--font-mono, ui-monospace, monospace); font-size: var(--t-meta); color: var(--text-secondary); }
7517
+ .prb-qr-finding-title { font-weight: 600; }
7518
+ .prb-qr-step { font-size: var(--t-body); }
7519
+ .prb-qr-code { margin-top: 6px; }
7520
+ /* The code rows are the light pane's, coloured for a light page, and Quick Review sits outside .prb-doc,
7521
+ so the frame brings that surface with it in both themes. */
7522
+ .prb-qr-code .prb-code-scroll {
7523
+ --pane-line: rgba(15, 23, 42, 0.12);
7524
+ max-height: 320px; overflow: auto; border: 1px solid var(--pane-line); border-radius: 6px;
7525
+ background: #ffffff; color: #1f2328; color-scheme: light;
7526
+ }
7527
+ .prb-qr-facts { display: grid; grid-template-columns: max-content 1fr; gap: 4px 12px; margin: 0 0 8px; font-size: var(--t-body); }
7528
+ .prb-qr-facts dt { color: var(--text-secondary); }
7529
+ .prb-qr-facts dd { margin: 0; }
7530
+ .prb-qr-clean { padding: 8px 12px; border-radius: 8px; background: var(--neutral-subtle); }
7531
+ .prb-qr-state, .prb-qr-loading { padding: 24px 0; color: var(--text-secondary); }
7532
+ .prb-card-outcome {
7533
+ display: inline-flex;
7534
+ align-items: center;
7535
+ padding: 1px 8px;
7536
+ border-radius: 999px;
7537
+ font-size: var(--t-micro);
7538
+ background: var(--neutral-subtle);
7539
+ color: var(--text-secondary);
7540
+ white-space: nowrap;
7541
+ }
7542
+ .prb-card-outcome[data-standing="current"][data-outcome="no-concerns"] { background: var(--success-subtle); color: var(--success-ink); }
7543
+ .prb-card-outcome[data-standing="current"][data-outcome="needs-changes"] { background: var(--danger-subtle); color: var(--danger-ink); }
7544
+ .prb-card-outcome[data-standing="current"][data-outcome="needs-decision"] { background: var(--warning-subtle); color: var(--warning-ink); }
7545
+ /* What you will do next: beside the verdict, never in its colours, so a Later cannot read as one. */
7546
+ .prb-card-deferral, .prb-qr-deferral {
7547
+ display: inline-flex;
7548
+ align-items: center;
7549
+ padding: 0 7px;
7550
+ border: 1px dashed var(--border-strong);
7551
+ border-radius: 999px;
7552
+ font-size: var(--t-micro);
7553
+ color: var(--text-secondary);
7554
+ white-space: nowrap;
7555
+ }
7556
+ .prb-qr-deferral[hidden] { display: none; }
7557
+ /* The key a control answers to, where it stands. Quieter than .prb-kbd: it rides inside a button. */
7558
+ .prb-qr-key {
7559
+ display: inline-block;
7560
+ min-width: 1.4em;
7561
+ margin-left: 4px;
7562
+ padding: 0 4px;
7563
+ border: 1px solid var(--border);
7564
+ border-radius: 4px;
7565
+ color: var(--text-secondary);
7566
+ font: 500 var(--t-micro) / 1.4 ui-monospace, SFMono-Regular, 'SF Mono', Menlo, monospace;
7567
+ text-align: center;
7568
+ white-space: nowrap;
7569
+ }
7570
+ .prb-qr-key:empty { display: none; }
7571
+ .prb-qr-hint {
7572
+ display: flex;
7573
+ align-items: center;
7574
+ gap: 12px;
7575
+ padding: 6px 20px;
7576
+ font-size: var(--t-meta);
7577
+ background: var(--neutral-subtle);
7578
+ color: var(--text-primary);
7579
+ }
7580
+ .prb-qr-hint[hidden] { display: none; }
7581
+ .prb-qr-hint-text { margin: 0; flex: 1 1 auto; }
7582
+ @media (max-width: 860px) {
7583
+ .prb-qr-head, .prb-qr-outcomes, .prb-qr-notice, .prb-qr-hint { padding-left: 12px; padding-right: 12px; }
7584
+ .prb-qr-body { padding: 8px 12px 24px; }
7585
+ .prb-qr-change { grid-template-columns: 1fr; }
7586
+ .prb-qr-change-arrow { transform: rotate(90deg); justify-self: center; }
7587
+ }