From d202e177e12ae20120eb983e3b9a78a456fd2919 Mon Sep 17 00:00:00 2001 From: TheGeneralist <180094941+thegeneralist01@users.noreply.github.com> Date: Mon, 20 Jul 2026 14:27:15 +0200 Subject: [PATCH] feat(frontend): add async capture UX with skeleton entries for in-progress captures (#31) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat(frontend): add SkeletonEntryRow with shimmer animation Adds a new SkeletonEntryRow component that renders animated shimmer placeholder cells matching the exact column layout of EntryRow (col-added, col-title with icon circle, col-type pill, col-size, col-url). CSS appended to styles.css using existing design tokens (--paper-2, --line-soft, --paper-3) for the warm-toned shimmer. * feat(frontend): async capture UX — reset dialog on submit, show skeleton rows When the user presses Archive, CaptureDialog now immediately resets its form to a fresh empty state and closes. Background captures continue polling via intervals that survive the dialog close. Skeleton rows appear at the top of EntriesView (filtered to the active archive) for each in-flight job, giving visual feedback that something is being processed. On completion the skeleton is removed and the entry list refreshes; on failure the skeleton is removed and an error toast fires — matching the existing toast behaviour. Architecture: - App owns pending-capture state (pendingCaptures) as the single source of truth, persisted to sessionStorage['pendingCaptures']. On page refresh, App seeds the list and passes it to CaptureDialog as activeJobs so polling reconnects without a second sessionStorage read. - CaptureDialog emits onJobStarted({id,jobUid,locator,archiveId}) only after submitCapture() returns a job_uid — never before, never on failure — ensuring no orphan skeletons can persist after a refresh. - onJobSettled(id) is called by startPolling on any terminal state (completed, failed, or network error), removing the skeleton. - EntriesView filters pendingCaptures by archiveId so a capture in archive A never shows a skeleton in archive B. Removed from CaptureDialog: submitItem, resetRow, hasActiveJobs, anyActive, CapStatusDot. CaptureRow is simplified to idle-only display with no disabled state, no retry button, no status dot. * fix(frontend): skeleton replacement ordering and col-check alignment - Await the entry list refresh before removing the skeleton so the real row arrives before the placeholder disappears. handleCaptured now returns its Promise.all; startPolling awaits it before calling onJobSettled on the success path. - Add col-check as the first child of SkeletonEntryRow to match EntryRow's DOM structure; without it, columns misalign on touch devices where col-check becomes display:flex. * fix(frontend): use Promise.allSettled in handleCaptured to prevent runs-fetch failure from poisoning successful captures Promise.all rejects on the first failure. If the /runs refresh threw, the rejection would propagate through startPolling's await and land in the outer catch block, firing an error toast for a capture that had already succeeded. Promise.allSettled settles unconditionally so a transient runs fetch error is silently absorbed while the entry list still refreshes. --- .../static/assets/index-D1LSSXsT.js | 47 +++++ .../static/assets/index-DKombv9L.css | 1 + frontend/src/App.jsx | 27 ++- frontend/src/components/CaptureDialog.jsx | 169 +++++++----------- frontend/src/components/EntriesView.jsx | 7 +- frontend/src/components/SkeletonEntryRow.jsx | 23 +++ frontend/src/styles.css | 32 ++++ 7 files changed, 197 insertions(+), 109 deletions(-) create mode 100644 crates/archivr-server/static/assets/index-D1LSSXsT.js create mode 100644 crates/archivr-server/static/assets/index-DKombv9L.css create mode 100644 frontend/src/components/SkeletonEntryRow.jsx diff --git a/crates/archivr-server/static/assets/index-D1LSSXsT.js b/crates/archivr-server/static/assets/index-D1LSSXsT.js new file mode 100644 index 0000000..8439d82 --- /dev/null +++ b/crates/archivr-server/static/assets/index-D1LSSXsT.js @@ -0,0 +1,47 @@ +(function(){const t=document.createElement("link").relList;if(t&&t.supports&&t.supports("modulepreload"))return;for(const l of document.querySelectorAll('link[rel="modulepreload"]'))r(l);new MutationObserver(l=>{for(const i of l)if(i.type==="childList")for(const a of i.addedNodes)a.tagName==="LINK"&&a.rel==="modulepreload"&&r(a)}).observe(document,{childList:!0,subtree:!0});function n(l){const i={};return l.integrity&&(i.integrity=l.integrity),l.referrerPolicy&&(i.referrerPolicy=l.referrerPolicy),l.crossOrigin==="use-credentials"?i.credentials="include":l.crossOrigin==="anonymous"?i.credentials="omit":i.credentials="same-origin",i}function r(l){if(l.ep)return;l.ep=!0;const i=n(l);fetch(l.href,i)}})();var hu={exports:{}},ts={},mu={exports:{}},G={};/** + * @license React + * react.production.min.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */var Ur=Symbol.for("react.element"),Hd=Symbol.for("react.portal"),Wd=Symbol.for("react.fragment"),Vd=Symbol.for("react.strict_mode"),Qd=Symbol.for("react.profiler"),Kd=Symbol.for("react.provider"),Xd=Symbol.for("react.context"),Jd=Symbol.for("react.forward_ref"),qd=Symbol.for("react.suspense"),Yd=Symbol.for("react.memo"),Gd=Symbol.for("react.lazy"),Ka=Symbol.iterator;function Zd(e){return e===null||typeof e!="object"?null:(e=Ka&&e[Ka]||e["@@iterator"],typeof e=="function"?e:null)}var gu={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},vu=Object.assign,yu={};function Jn(e,t,n){this.props=e,this.context=t,this.refs=yu,this.updater=n||gu}Jn.prototype.isReactComponent={};Jn.prototype.setState=function(e,t){if(typeof e!="object"&&typeof e!="function"&&e!=null)throw Error("setState(...): takes an object of state variables to update or a function which returns an object of state variables.");this.updater.enqueueSetState(this,e,t,"setState")};Jn.prototype.forceUpdate=function(e){this.updater.enqueueForceUpdate(this,e,"forceUpdate")};function xu(){}xu.prototype=Jn.prototype;function qi(e,t,n){this.props=e,this.context=t,this.refs=yu,this.updater=n||gu}var Yi=qi.prototype=new xu;Yi.constructor=qi;vu(Yi,Jn.prototype);Yi.isPureReactComponent=!0;var Xa=Array.isArray,wu=Object.prototype.hasOwnProperty,Gi={current:null},ku={key:!0,ref:!0,__self:!0,__source:!0};function ju(e,t,n){var r,l={},i=null,a=null;if(t!=null)for(r in t.ref!==void 0&&(a=t.ref),t.key!==void 0&&(i=""+t.key),t)wu.call(t,r)&&!ku.hasOwnProperty(r)&&(l[r]=t[r]);var u=arguments.length-2;if(u===1)l.children=n;else if(1>>1,A=R[q];if(0>>1;ql(Re,F))wel(je,Re)?(R[q]=je,R[we]=F,q=we):(R[q]=Re,R[de]=F,q=de);else if(wel(je,F))R[q]=je,R[we]=F,q=we;else break e}}return T}function l(R,T){var F=R.sortIndex-T.sortIndex;return F!==0?F:R.id-T.id}if(typeof performance=="object"&&typeof performance.now=="function"){var i=performance;e.unstable_now=function(){return i.now()}}else{var a=Date,u=a.now();e.unstable_now=function(){return a.now()-u}}var o=[],c=[],g=1,h=null,m=3,y=!1,w=!1,k=!1,j=typeof setTimeout=="function"?setTimeout:null,p=typeof clearTimeout=="function"?clearTimeout:null,d=typeof setImmediate<"u"?setImmediate:null;typeof navigator<"u"&&navigator.scheduling!==void 0&&navigator.scheduling.isInputPending!==void 0&&navigator.scheduling.isInputPending.bind(navigator.scheduling);function v(R){for(var T=n(c);T!==null;){if(T.callback===null)r(c);else if(T.startTime<=R)r(c),T.sortIndex=T.expirationTime,t(o,T);else break;T=n(c)}}function x(R){if(k=!1,v(R),!w)if(n(o)!==null)w=!0,ie(_);else{var T=n(c);T!==null&&ee(x,T.startTime-R)}}function _(R,T){w=!1,k&&(k=!1,p(S),S=-1),y=!0;var F=m;try{for(v(T),h=n(o);h!==null&&(!(h.expirationTime>T)||R&&!H());){var q=h.callback;if(typeof q=="function"){h.callback=null,m=h.priorityLevel;var A=q(h.expirationTime<=T);T=e.unstable_now(),typeof A=="function"?h.callback=A:h===n(o)&&r(o),v(T)}else r(o);h=n(o)}if(h!==null)var ge=!0;else{var de=n(c);de!==null&&ee(x,de.startTime-T),ge=!1}return ge}finally{h=null,m=F,y=!1}}var b=!1,C=null,S=-1,D=5,L=-1;function H(){return!(e.unstable_now()-LR||125q?(R.sortIndex=F,t(c,R),n(o)===null&&R===n(c)&&(k?(p(S),S=-1):k=!0,ee(x,F-q))):(R.sortIndex=A,t(o,R),w||y||(w=!0,ie(_))),R},e.unstable_shouldYield=H,e.unstable_wrapCallback=function(R){var T=m;return function(){var F=m;m=T;try{return R.apply(this,arguments)}finally{m=F}}}})(Eu);Cu.exports=Eu;var df=Cu.exports;/** + * @license React + * react-dom.production.min.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */var ff=f,et=df;function z(e){for(var t="https://reactjs.org/docs/error-decoder.html?invariant="+e,n=1;n"u"||typeof window.document>"u"||typeof window.document.createElement>"u"),ni=Object.prototype.hasOwnProperty,pf=/^[:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD][:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\-.0-9\u00B7\u0300-\u036F\u203F-\u2040]*$/,qa={},Ya={};function hf(e){return ni.call(Ya,e)?!0:ni.call(qa,e)?!1:pf.test(e)?Ya[e]=!0:(qa[e]=!0,!1)}function mf(e,t,n,r){if(n!==null&&n.type===0)return!1;switch(typeof t){case"function":case"symbol":return!0;case"boolean":return r?!1:n!==null?!n.acceptsBooleans:(e=e.toLowerCase().slice(0,5),e!=="data-"&&e!=="aria-");default:return!1}}function gf(e,t,n,r){if(t===null||typeof t>"u"||mf(e,t,n,r))return!0;if(r)return!1;if(n!==null)switch(n.type){case 3:return!t;case 4:return t===!1;case 5:return isNaN(t);case 6:return isNaN(t)||1>t}return!1}function We(e,t,n,r,l,i,a){this.acceptsBooleans=t===2||t===3||t===4,this.attributeName=r,this.attributeNamespace=l,this.mustUseProperty=n,this.propertyName=e,this.type=t,this.sanitizeURL=i,this.removeEmptyString=a}var ze={};"children dangerouslySetInnerHTML defaultValue defaultChecked innerHTML suppressContentEditableWarning suppressHydrationWarning style".split(" ").forEach(function(e){ze[e]=new We(e,0,!1,e,null,!1,!1)});[["acceptCharset","accept-charset"],["className","class"],["htmlFor","for"],["httpEquiv","http-equiv"]].forEach(function(e){var t=e[0];ze[t]=new We(t,1,!1,e[1],null,!1,!1)});["contentEditable","draggable","spellCheck","value"].forEach(function(e){ze[e]=new We(e,2,!1,e.toLowerCase(),null,!1,!1)});["autoReverse","externalResourcesRequired","focusable","preserveAlpha"].forEach(function(e){ze[e]=new We(e,2,!1,e,null,!1,!1)});"allowFullScreen async autoFocus autoPlay controls default defer disabled disablePictureInPicture disableRemotePlayback formNoValidate hidden loop noModule noValidate open playsInline readOnly required reversed scoped seamless itemScope".split(" ").forEach(function(e){ze[e]=new We(e,3,!1,e.toLowerCase(),null,!1,!1)});["checked","multiple","muted","selected"].forEach(function(e){ze[e]=new We(e,3,!0,e,null,!1,!1)});["capture","download"].forEach(function(e){ze[e]=new We(e,4,!1,e,null,!1,!1)});["cols","rows","size","span"].forEach(function(e){ze[e]=new We(e,6,!1,e,null,!1,!1)});["rowSpan","start"].forEach(function(e){ze[e]=new We(e,5,!1,e.toLowerCase(),null,!1,!1)});var ea=/[\-:]([a-z])/g;function ta(e){return e[1].toUpperCase()}"accent-height alignment-baseline arabic-form baseline-shift cap-height clip-path clip-rule color-interpolation color-interpolation-filters color-profile color-rendering dominant-baseline enable-background fill-opacity fill-rule flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-name glyph-orientation-horizontal glyph-orientation-vertical horiz-adv-x horiz-origin-x image-rendering letter-spacing lighting-color marker-end marker-mid marker-start overline-position overline-thickness paint-order panose-1 pointer-events rendering-intent shape-rendering stop-color stop-opacity strikethrough-position strikethrough-thickness stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width text-anchor text-decoration text-rendering underline-position underline-thickness unicode-bidi unicode-range units-per-em v-alphabetic v-hanging v-ideographic v-mathematical vector-effect vert-adv-y vert-origin-x vert-origin-y word-spacing writing-mode xmlns:xlink x-height".split(" ").forEach(function(e){var t=e.replace(ea,ta);ze[t]=new We(t,1,!1,e,null,!1,!1)});"xlink:actuate xlink:arcrole xlink:role xlink:show xlink:title xlink:type".split(" ").forEach(function(e){var t=e.replace(ea,ta);ze[t]=new We(t,1,!1,e,"http://www.w3.org/1999/xlink",!1,!1)});["xml:base","xml:lang","xml:space"].forEach(function(e){var t=e.replace(ea,ta);ze[t]=new We(t,1,!1,e,"http://www.w3.org/XML/1998/namespace",!1,!1)});["tabIndex","crossOrigin"].forEach(function(e){ze[e]=new We(e,1,!1,e.toLowerCase(),null,!1,!1)});ze.xlinkHref=new We("xlinkHref",1,!1,"xlink:href","http://www.w3.org/1999/xlink",!0,!1);["src","href","action","formAction"].forEach(function(e){ze[e]=new We(e,1,!1,e.toLowerCase(),null,!0,!0)});function na(e,t,n,r){var l=ze.hasOwnProperty(t)?ze[t]:null;(l!==null?l.type!==0:r||!(2u||l[a]!==i[u]){var o=` +`+l[a].replace(" at new "," at ");return e.displayName&&o.includes("")&&(o=o.replace("",e.displayName)),o}while(1<=a&&0<=u);break}}}finally{Ts=!1,Error.prepareStackTrace=n}return(e=e?e.displayName||e.name:"")?dr(e):""}function vf(e){switch(e.tag){case 5:return dr(e.type);case 16:return dr("Lazy");case 13:return dr("Suspense");case 19:return dr("SuspenseList");case 0:case 2:case 15:return e=Ps(e.type,!1),e;case 11:return e=Ps(e.type.render,!1),e;case 1:return e=Ps(e.type,!0),e;default:return""}}function ii(e){if(e==null)return null;if(typeof e=="function")return e.displayName||e.name||null;if(typeof e=="string")return e;switch(e){case Nn:return"Fragment";case Sn:return"Portal";case ri:return"Profiler";case ra:return"StrictMode";case li:return"Suspense";case si:return"SuspenseList"}if(typeof e=="object")switch(e.$$typeof){case bu:return(e.displayName||"Context")+".Consumer";case Pu:return(e._context.displayName||"Context")+".Provider";case la:var t=e.render;return e=e.displayName,e||(e=t.displayName||t.name||"",e=e!==""?"ForwardRef("+e+")":"ForwardRef"),e;case sa:return t=e.displayName||null,t!==null?t:ii(e.type)||"Memo";case $t:t=e._payload,e=e._init;try{return ii(e(t))}catch{}}return null}function yf(e){var t=e.type;switch(e.tag){case 24:return"Cache";case 9:return(t.displayName||"Context")+".Consumer";case 10:return(t._context.displayName||"Context")+".Provider";case 18:return"DehydratedFragment";case 11:return e=t.render,e=e.displayName||e.name||"",t.displayName||(e!==""?"ForwardRef("+e+")":"ForwardRef");case 7:return"Fragment";case 5:return t;case 4:return"Portal";case 3:return"Root";case 6:return"Text";case 16:return ii(t);case 8:return t===ra?"StrictMode":"Mode";case 22:return"Offscreen";case 12:return"Profiler";case 21:return"Scope";case 13:return"Suspense";case 19:return"SuspenseList";case 25:return"TracingMarker";case 1:case 0:case 17:case 2:case 14:case 15:if(typeof t=="function")return t.displayName||t.name||null;if(typeof t=="string")return t}return null}function Jt(e){switch(typeof e){case"boolean":case"number":case"string":case"undefined":return e;case"object":return e;default:return""}}function zu(e){var t=e.type;return(e=e.nodeName)&&e.toLowerCase()==="input"&&(t==="checkbox"||t==="radio")}function xf(e){var t=zu(e)?"checked":"value",n=Object.getOwnPropertyDescriptor(e.constructor.prototype,t),r=""+e[t];if(!e.hasOwnProperty(t)&&typeof n<"u"&&typeof n.get=="function"&&typeof n.set=="function"){var l=n.get,i=n.set;return Object.defineProperty(e,t,{configurable:!0,get:function(){return l.call(this)},set:function(a){r=""+a,i.call(this,a)}}),Object.defineProperty(e,t,{enumerable:n.enumerable}),{getValue:function(){return r},setValue:function(a){r=""+a},stopTracking:function(){e._valueTracker=null,delete e[t]}}}}function Zr(e){e._valueTracker||(e._valueTracker=xf(e))}function Ru(e){if(!e)return!1;var t=e._valueTracker;if(!t)return!0;var n=t.getValue(),r="";return e&&(r=zu(e)?e.checked?"true":"false":e.value),e=r,e!==n?(t.setValue(e),!0):!1}function Pl(e){if(e=e||(typeof document<"u"?document:void 0),typeof e>"u")return null;try{return e.activeElement||e.body}catch{return e.body}}function ai(e,t){var n=t.checked;return me({},t,{defaultChecked:void 0,defaultValue:void 0,value:void 0,checked:n??e._wrapperState.initialChecked})}function Za(e,t){var n=t.defaultValue==null?"":t.defaultValue,r=t.checked!=null?t.checked:t.defaultChecked;n=Jt(t.value!=null?t.value:n),e._wrapperState={initialChecked:r,initialValue:n,controlled:t.type==="checkbox"||t.type==="radio"?t.checked!=null:t.value!=null}}function Du(e,t){t=t.checked,t!=null&&na(e,"checked",t,!1)}function oi(e,t){Du(e,t);var n=Jt(t.value),r=t.type;if(n!=null)r==="number"?(n===0&&e.value===""||e.value!=n)&&(e.value=""+n):e.value!==""+n&&(e.value=""+n);else if(r==="submit"||r==="reset"){e.removeAttribute("value");return}t.hasOwnProperty("value")?ui(e,t.type,n):t.hasOwnProperty("defaultValue")&&ui(e,t.type,Jt(t.defaultValue)),t.checked==null&&t.defaultChecked!=null&&(e.defaultChecked=!!t.defaultChecked)}function eo(e,t,n){if(t.hasOwnProperty("value")||t.hasOwnProperty("defaultValue")){var r=t.type;if(!(r!=="submit"&&r!=="reset"||t.value!==void 0&&t.value!==null))return;t=""+e._wrapperState.initialValue,n||t===e.value||(e.value=t),e.defaultValue=t}n=e.name,n!==""&&(e.name=""),e.defaultChecked=!!e._wrapperState.initialChecked,n!==""&&(e.name=n)}function ui(e,t,n){(t!=="number"||Pl(e.ownerDocument)!==e)&&(n==null?e.defaultValue=""+e._wrapperState.initialValue:e.defaultValue!==""+n&&(e.defaultValue=""+n))}var fr=Array.isArray;function $n(e,t,n,r){if(e=e.options,t){t={};for(var l=0;l"+t.valueOf().toString()+"",t=el.firstChild;e.firstChild;)e.removeChild(e.firstChild);for(;t.firstChild;)e.appendChild(t.firstChild)}});function Cr(e,t){if(t){var n=e.firstChild;if(n&&n===e.lastChild&&n.nodeType===3){n.nodeValue=t;return}}e.textContent=t}var gr={animationIterationCount:!0,aspectRatio:!0,borderImageOutset:!0,borderImageSlice:!0,borderImageWidth:!0,boxFlex:!0,boxFlexGroup:!0,boxOrdinalGroup:!0,columnCount:!0,columns:!0,flex:!0,flexGrow:!0,flexPositive:!0,flexShrink:!0,flexNegative:!0,flexOrder:!0,gridArea:!0,gridRow:!0,gridRowEnd:!0,gridRowSpan:!0,gridRowStart:!0,gridColumn:!0,gridColumnEnd:!0,gridColumnSpan:!0,gridColumnStart:!0,fontWeight:!0,lineClamp:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,tabSize:!0,widows:!0,zIndex:!0,zoom:!0,fillOpacity:!0,floodOpacity:!0,stopOpacity:!0,strokeDasharray:!0,strokeDashoffset:!0,strokeMiterlimit:!0,strokeOpacity:!0,strokeWidth:!0},wf=["Webkit","ms","Moz","O"];Object.keys(gr).forEach(function(e){wf.forEach(function(t){t=t+e.charAt(0).toUpperCase()+e.substring(1),gr[t]=gr[e]})});function Fu(e,t,n){return t==null||typeof t=="boolean"||t===""?"":n||typeof t!="number"||t===0||gr.hasOwnProperty(e)&&gr[e]?(""+t).trim():t+"px"}function Mu(e,t){e=e.style;for(var n in t)if(t.hasOwnProperty(n)){var r=n.indexOf("--")===0,l=Fu(n,t[n],r);n==="float"&&(n="cssFloat"),r?e.setProperty(n,l):e[n]=l}}var kf=me({menuitem:!0},{area:!0,base:!0,br:!0,col:!0,embed:!0,hr:!0,img:!0,input:!0,keygen:!0,link:!0,meta:!0,param:!0,source:!0,track:!0,wbr:!0});function fi(e,t){if(t){if(kf[e]&&(t.children!=null||t.dangerouslySetInnerHTML!=null))throw Error(z(137,e));if(t.dangerouslySetInnerHTML!=null){if(t.children!=null)throw Error(z(60));if(typeof t.dangerouslySetInnerHTML!="object"||!("__html"in t.dangerouslySetInnerHTML))throw Error(z(61))}if(t.style!=null&&typeof t.style!="object")throw Error(z(62))}}function pi(e,t){if(e.indexOf("-")===-1)return typeof t.is=="string";switch(e){case"annotation-xml":case"color-profile":case"font-face":case"font-face-src":case"font-face-uri":case"font-face-format":case"font-face-name":case"missing-glyph":return!1;default:return!0}}var hi=null;function ia(e){return e=e.target||e.srcElement||window,e.correspondingUseElement&&(e=e.correspondingUseElement),e.nodeType===3?e.parentNode:e}var mi=null,In=null,On=null;function ro(e){if(e=Vr(e)){if(typeof mi!="function")throw Error(z(280));var t=e.stateNode;t&&(t=is(t),mi(e.stateNode,e.type,t))}}function Au(e){In?On?On.push(e):On=[e]:In=e}function Bu(){if(In){var e=In,t=On;if(On=In=null,ro(e),t)for(e=0;e>>=0,e===0?32:31-(zf(e)/Rf|0)|0}var tl=64,nl=4194304;function pr(e){switch(e&-e){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return e&4194240;case 4194304:case 8388608:case 16777216:case 33554432:case 67108864:return e&130023424;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 1073741824;default:return e}}function Rl(e,t){var n=e.pendingLanes;if(n===0)return 0;var r=0,l=e.suspendedLanes,i=e.pingedLanes,a=n&268435455;if(a!==0){var u=a&~l;u!==0?r=pr(u):(i&=a,i!==0&&(r=pr(i)))}else a=n&~l,a!==0?r=pr(a):i!==0&&(r=pr(i));if(r===0)return 0;if(t!==0&&t!==r&&!(t&l)&&(l=r&-r,i=t&-t,l>=i||l===16&&(i&4194240)!==0))return t;if(r&4&&(r|=n&16),t=e.entangledLanes,t!==0)for(e=e.entanglements,t&=r;0n;n++)t.push(e);return t}function Hr(e,t,n){e.pendingLanes|=t,t!==536870912&&(e.suspendedLanes=0,e.pingedLanes=0),e=e.eventTimes,t=31-gt(t),e[t]=n}function Of(e,t){var n=e.pendingLanes&~t;e.pendingLanes=t,e.suspendedLanes=0,e.pingedLanes=0,e.expiredLanes&=t,e.mutableReadLanes&=t,e.entangledLanes&=t,t=e.entanglements;var r=e.eventTimes;for(e=e.expirationTimes;0=yr),po=" ",ho=!1;function ac(e,t){switch(e){case"keyup":return dp.indexOf(t.keyCode)!==-1;case"keydown":return t.keyCode!==229;case"keypress":case"mousedown":case"focusout":return!0;default:return!1}}function oc(e){return e=e.detail,typeof e=="object"&&"data"in e?e.data:null}var _n=!1;function pp(e,t){switch(e){case"compositionend":return oc(t);case"keypress":return t.which!==32?null:(ho=!0,po);case"textInput":return e=t.data,e===po&&ho?null:e;default:return null}}function hp(e,t){if(_n)return e==="compositionend"||!ha&&ac(e,t)?(e=sc(),xl=da=Mt=null,_n=!1,e):null;switch(e){case"paste":return null;case"keypress":if(!(t.ctrlKey||t.altKey||t.metaKey)||t.ctrlKey&&t.altKey){if(t.char&&1=t)return{node:n,offset:t-e};e=r}e:{for(;n;){if(n.nextSibling){n=n.nextSibling;break e}n=n.parentNode}n=void 0}n=yo(n)}}function fc(e,t){return e&&t?e===t?!0:e&&e.nodeType===3?!1:t&&t.nodeType===3?fc(e,t.parentNode):"contains"in e?e.contains(t):e.compareDocumentPosition?!!(e.compareDocumentPosition(t)&16):!1:!1}function pc(){for(var e=window,t=Pl();t instanceof e.HTMLIFrameElement;){try{var n=typeof t.contentWindow.location.href=="string"}catch{n=!1}if(n)e=t.contentWindow;else break;t=Pl(e.document)}return t}function ma(e){var t=e&&e.nodeName&&e.nodeName.toLowerCase();return t&&(t==="input"&&(e.type==="text"||e.type==="search"||e.type==="tel"||e.type==="url"||e.type==="password")||t==="textarea"||e.contentEditable==="true")}function Sp(e){var t=pc(),n=e.focusedElem,r=e.selectionRange;if(t!==n&&n&&n.ownerDocument&&fc(n.ownerDocument.documentElement,n)){if(r!==null&&ma(n)){if(t=r.start,e=r.end,e===void 0&&(e=t),"selectionStart"in n)n.selectionStart=t,n.selectionEnd=Math.min(e,n.value.length);else if(e=(t=n.ownerDocument||document)&&t.defaultView||window,e.getSelection){e=e.getSelection();var l=n.textContent.length,i=Math.min(r.start,l);r=r.end===void 0?i:Math.min(r.end,l),!e.extend&&i>r&&(l=r,r=i,i=l),l=xo(n,i);var a=xo(n,r);l&&a&&(e.rangeCount!==1||e.anchorNode!==l.node||e.anchorOffset!==l.offset||e.focusNode!==a.node||e.focusOffset!==a.offset)&&(t=t.createRange(),t.setStart(l.node,l.offset),e.removeAllRanges(),i>r?(e.addRange(t),e.extend(a.node,a.offset)):(t.setEnd(a.node,a.offset),e.addRange(t)))}}for(t=[],e=n;e=e.parentNode;)e.nodeType===1&&t.push({element:e,left:e.scrollLeft,top:e.scrollTop});for(typeof n.focus=="function"&&n.focus(),n=0;n=document.documentMode,Cn=null,ki=null,wr=null,ji=!1;function wo(e,t,n){var r=n.window===n?n.document:n.nodeType===9?n:n.ownerDocument;ji||Cn==null||Cn!==Pl(r)||(r=Cn,"selectionStart"in r&&ma(r)?r={start:r.selectionStart,end:r.selectionEnd}:(r=(r.ownerDocument&&r.ownerDocument.defaultView||window).getSelection(),r={anchorNode:r.anchorNode,anchorOffset:r.anchorOffset,focusNode:r.focusNode,focusOffset:r.focusOffset}),wr&&zr(wr,r)||(wr=r,r=Il(ki,"onSelect"),0Pn||(e.current=Ti[Pn],Ti[Pn]=null,Pn--)}function ae(e,t){Pn++,Ti[Pn]=e.current,e.current=t}var qt={},Fe=Gt(qt),Ke=Gt(!1),dn=qt;function Hn(e,t){var n=e.type.contextTypes;if(!n)return qt;var r=e.stateNode;if(r&&r.__reactInternalMemoizedUnmaskedChildContext===t)return r.__reactInternalMemoizedMaskedChildContext;var l={},i;for(i in n)l[i]=t[i];return r&&(e=e.stateNode,e.__reactInternalMemoizedUnmaskedChildContext=t,e.__reactInternalMemoizedMaskedChildContext=l),l}function Xe(e){return e=e.childContextTypes,e!=null}function Fl(){ue(Ke),ue(Fe)}function Eo(e,t,n){if(Fe.current!==qt)throw Error(z(168));ae(Fe,t),ae(Ke,n)}function jc(e,t,n){var r=e.stateNode;if(t=t.childContextTypes,typeof r.getChildContext!="function")return n;r=r.getChildContext();for(var l in r)if(!(l in t))throw Error(z(108,yf(e)||"Unknown",l));return me({},n,r)}function Ml(e){return e=(e=e.stateNode)&&e.__reactInternalMemoizedMergedChildContext||qt,dn=Fe.current,ae(Fe,e),ae(Ke,Ke.current),!0}function To(e,t,n){var r=e.stateNode;if(!r)throw Error(z(169));n?(e=jc(e,t,dn),r.__reactInternalMemoizedMergedChildContext=e,ue(Ke),ue(Fe),ae(Fe,e)):ue(Ke),ae(Ke,n)}var _t=null,as=!1,Hs=!1;function Sc(e){_t===null?_t=[e]:_t.push(e)}function $p(e){as=!0,Sc(e)}function Zt(){if(!Hs&&_t!==null){Hs=!0;var e=0,t=se;try{var n=_t;for(se=1;e>=a,l-=a,Ct=1<<32-gt(t)+l|n<S?(D=C,C=null):D=C.sibling;var L=m(p,C,v[S],x);if(L===null){C===null&&(C=D);break}e&&C&&L.alternate===null&&t(p,C),d=i(L,d,S),b===null?_=L:b.sibling=L,b=L,C=D}if(S===v.length)return n(p,C),fe&&nn(p,S),_;if(C===null){for(;SS?(D=C,C=null):D=C.sibling;var H=m(p,C,L.value,x);if(H===null){C===null&&(C=D);break}e&&C&&H.alternate===null&&t(p,C),d=i(H,d,S),b===null?_=H:b.sibling=H,b=H,C=D}if(L.done)return n(p,C),fe&&nn(p,S),_;if(C===null){for(;!L.done;S++,L=v.next())L=h(p,L.value,x),L!==null&&(d=i(L,d,S),b===null?_=L:b.sibling=L,b=L);return fe&&nn(p,S),_}for(C=r(p,C);!L.done;S++,L=v.next())L=y(C,p,S,L.value,x),L!==null&&(e&&L.alternate!==null&&C.delete(L.key===null?S:L.key),d=i(L,d,S),b===null?_=L:b.sibling=L,b=L);return e&&C.forEach(function(M){return t(p,M)}),fe&&nn(p,S),_}function j(p,d,v,x){if(typeof v=="object"&&v!==null&&v.type===Nn&&v.key===null&&(v=v.props.children),typeof v=="object"&&v!==null){switch(v.$$typeof){case Gr:e:{for(var _=v.key,b=d;b!==null;){if(b.key===_){if(_=v.type,_===Nn){if(b.tag===7){n(p,b.sibling),d=l(b,v.props.children),d.return=p,p=d;break e}}else if(b.elementType===_||typeof _=="object"&&_!==null&&_.$$typeof===$t&&Lo(_)===b.type){n(p,b.sibling),d=l(b,v.props),d.ref=ir(p,b,v),d.return=p,p=d;break e}n(p,b);break}else t(p,b);b=b.sibling}v.type===Nn?(d=cn(v.props.children,p.mode,x,v.key),d.return=p,p=d):(x=El(v.type,v.key,v.props,null,p.mode,x),x.ref=ir(p,d,v),x.return=p,p=x)}return a(p);case Sn:e:{for(b=v.key;d!==null;){if(d.key===b)if(d.tag===4&&d.stateNode.containerInfo===v.containerInfo&&d.stateNode.implementation===v.implementation){n(p,d.sibling),d=l(d,v.children||[]),d.return=p,p=d;break e}else{n(p,d);break}else t(p,d);d=d.sibling}d=Ys(v,p.mode,x),d.return=p,p=d}return a(p);case $t:return b=v._init,j(p,d,b(v._payload),x)}if(fr(v))return w(p,d,v,x);if(tr(v))return k(p,d,v,x);ul(p,v)}return typeof v=="string"&&v!==""||typeof v=="number"?(v=""+v,d!==null&&d.tag===6?(n(p,d.sibling),d=l(d,v),d.return=p,p=d):(n(p,d),d=qs(v,p.mode,x),d.return=p,p=d),a(p)):n(p,d)}return j}var Vn=Ec(!0),Tc=Ec(!1),Ul=Gt(null),Hl=null,zn=null,xa=null;function wa(){xa=zn=Hl=null}function ka(e){var t=Ul.current;ue(Ul),e._currentValue=t}function Li(e,t,n){for(;e!==null;){var r=e.alternate;if((e.childLanes&t)!==t?(e.childLanes|=t,r!==null&&(r.childLanes|=t)):r!==null&&(r.childLanes&t)!==t&&(r.childLanes|=t),e===n)break;e=e.return}}function Mn(e,t){Hl=e,xa=zn=null,e=e.dependencies,e!==null&&e.firstContext!==null&&(e.lanes&t&&(Qe=!0),e.firstContext=null)}function ut(e){var t=e._currentValue;if(xa!==e)if(e={context:e,memoizedValue:t,next:null},zn===null){if(Hl===null)throw Error(z(308));zn=e,Hl.dependencies={lanes:0,firstContext:e}}else zn=zn.next=e;return t}var sn=null;function ja(e){sn===null?sn=[e]:sn.push(e)}function Pc(e,t,n,r){var l=t.interleaved;return l===null?(n.next=n,ja(t)):(n.next=l.next,l.next=n),t.interleaved=n,Lt(e,r)}function Lt(e,t){e.lanes|=t;var n=e.alternate;for(n!==null&&(n.lanes|=t),n=e,e=e.return;e!==null;)e.childLanes|=t,n=e.alternate,n!==null&&(n.childLanes|=t),n=e,e=e.return;return n.tag===3?n.stateNode:null}var It=!1;function Sa(e){e.updateQueue={baseState:e.memoizedState,firstBaseUpdate:null,lastBaseUpdate:null,shared:{pending:null,interleaved:null,lanes:0},effects:null}}function bc(e,t){e=e.updateQueue,t.updateQueue===e&&(t.updateQueue={baseState:e.baseState,firstBaseUpdate:e.firstBaseUpdate,lastBaseUpdate:e.lastBaseUpdate,shared:e.shared,effects:e.effects})}function Tt(e,t){return{eventTime:e,lane:t,tag:0,payload:null,callback:null,next:null}}function Vt(e,t,n){var r=e.updateQueue;if(r===null)return null;if(r=r.shared,Z&2){var l=r.pending;return l===null?t.next=t:(t.next=l.next,l.next=t),r.pending=t,Lt(e,n)}return l=r.interleaved,l===null?(t.next=t,ja(r)):(t.next=l.next,l.next=t),r.interleaved=t,Lt(e,n)}function kl(e,t,n){if(t=t.updateQueue,t!==null&&(t=t.shared,(n&4194240)!==0)){var r=t.lanes;r&=e.pendingLanes,n|=r,t.lanes=n,oa(e,n)}}function zo(e,t){var n=e.updateQueue,r=e.alternate;if(r!==null&&(r=r.updateQueue,n===r)){var l=null,i=null;if(n=n.firstBaseUpdate,n!==null){do{var a={eventTime:n.eventTime,lane:n.lane,tag:n.tag,payload:n.payload,callback:n.callback,next:null};i===null?l=i=a:i=i.next=a,n=n.next}while(n!==null);i===null?l=i=t:i=i.next=t}else l=i=t;n={baseState:r.baseState,firstBaseUpdate:l,lastBaseUpdate:i,shared:r.shared,effects:r.effects},e.updateQueue=n;return}e=n.lastBaseUpdate,e===null?n.firstBaseUpdate=t:e.next=t,n.lastBaseUpdate=t}function Wl(e,t,n,r){var l=e.updateQueue;It=!1;var i=l.firstBaseUpdate,a=l.lastBaseUpdate,u=l.shared.pending;if(u!==null){l.shared.pending=null;var o=u,c=o.next;o.next=null,a===null?i=c:a.next=c,a=o;var g=e.alternate;g!==null&&(g=g.updateQueue,u=g.lastBaseUpdate,u!==a&&(u===null?g.firstBaseUpdate=c:u.next=c,g.lastBaseUpdate=o))}if(i!==null){var h=l.baseState;a=0,g=c=o=null,u=i;do{var m=u.lane,y=u.eventTime;if((r&m)===m){g!==null&&(g=g.next={eventTime:y,lane:0,tag:u.tag,payload:u.payload,callback:u.callback,next:null});e:{var w=e,k=u;switch(m=t,y=n,k.tag){case 1:if(w=k.payload,typeof w=="function"){h=w.call(y,h,m);break e}h=w;break e;case 3:w.flags=w.flags&-65537|128;case 0:if(w=k.payload,m=typeof w=="function"?w.call(y,h,m):w,m==null)break e;h=me({},h,m);break e;case 2:It=!0}}u.callback!==null&&u.lane!==0&&(e.flags|=64,m=l.effects,m===null?l.effects=[u]:m.push(u))}else y={eventTime:y,lane:m,tag:u.tag,payload:u.payload,callback:u.callback,next:null},g===null?(c=g=y,o=h):g=g.next=y,a|=m;if(u=u.next,u===null){if(u=l.shared.pending,u===null)break;m=u,u=m.next,m.next=null,l.lastBaseUpdate=m,l.shared.pending=null}}while(!0);if(g===null&&(o=h),l.baseState=o,l.firstBaseUpdate=c,l.lastBaseUpdate=g,t=l.shared.interleaved,t!==null){l=t;do a|=l.lane,l=l.next;while(l!==t)}else i===null&&(l.shared.lanes=0);hn|=a,e.lanes=a,e.memoizedState=h}}function Ro(e,t,n){if(e=t.effects,t.effects=null,e!==null)for(t=0;tn?n:4,e(!0);var r=Vs.transition;Vs.transition={};try{e(!1),t()}finally{se=n,Vs.transition=r}}function Kc(){return ct().memoizedState}function Mp(e,t,n){var r=Kt(e);if(n={lane:r,action:n,hasEagerState:!1,eagerState:null,next:null},Xc(e))Jc(t,n);else if(n=Pc(e,t,n,r),n!==null){var l=Ue();vt(n,e,r,l),qc(n,t,r)}}function Ap(e,t,n){var r=Kt(e),l={lane:r,action:n,hasEagerState:!1,eagerState:null,next:null};if(Xc(e))Jc(t,l);else{var i=e.alternate;if(e.lanes===0&&(i===null||i.lanes===0)&&(i=t.lastRenderedReducer,i!==null))try{var a=t.lastRenderedState,u=i(a,n);if(l.hasEagerState=!0,l.eagerState=u,yt(u,a)){var o=t.interleaved;o===null?(l.next=l,ja(t)):(l.next=o.next,o.next=l),t.interleaved=l;return}}catch{}finally{}n=Pc(e,t,l,r),n!==null&&(l=Ue(),vt(n,e,r,l),qc(n,t,r))}}function Xc(e){var t=e.alternate;return e===he||t!==null&&t===he}function Jc(e,t){kr=Ql=!0;var n=e.pending;n===null?t.next=t:(t.next=n.next,n.next=t),e.pending=t}function qc(e,t,n){if(n&4194240){var r=t.lanes;r&=e.pendingLanes,n|=r,t.lanes=n,oa(e,n)}}var Kl={readContext:ut,useCallback:$e,useContext:$e,useEffect:$e,useImperativeHandle:$e,useInsertionEffect:$e,useLayoutEffect:$e,useMemo:$e,useReducer:$e,useRef:$e,useState:$e,useDebugValue:$e,useDeferredValue:$e,useTransition:$e,useMutableSource:$e,useSyncExternalStore:$e,useId:$e,unstable_isNewReconciler:!1},Bp={readContext:ut,useCallback:function(e,t){return wt().memoizedState=[e,t===void 0?null:t],e},useContext:ut,useEffect:$o,useImperativeHandle:function(e,t,n){return n=n!=null?n.concat([e]):null,Sl(4194308,4,Uc.bind(null,t,e),n)},useLayoutEffect:function(e,t){return Sl(4194308,4,e,t)},useInsertionEffect:function(e,t){return Sl(4,2,e,t)},useMemo:function(e,t){var n=wt();return t=t===void 0?null:t,e=e(),n.memoizedState=[e,t],e},useReducer:function(e,t,n){var r=wt();return t=n!==void 0?n(t):t,r.memoizedState=r.baseState=t,e={pending:null,interleaved:null,lanes:0,dispatch:null,lastRenderedReducer:e,lastRenderedState:t},r.queue=e,e=e.dispatch=Mp.bind(null,he,e),[r.memoizedState,e]},useRef:function(e){var t=wt();return e={current:e},t.memoizedState=e},useState:Do,useDebugValue:La,useDeferredValue:function(e){return wt().memoizedState=e},useTransition:function(){var e=Do(!1),t=e[0];return e=Fp.bind(null,e[1]),wt().memoizedState=e,[t,e]},useMutableSource:function(){},useSyncExternalStore:function(e,t,n){var r=he,l=wt();if(fe){if(n===void 0)throw Error(z(407));n=n()}else{if(n=t(),Pe===null)throw Error(z(349));pn&30||Dc(r,t,n)}l.memoizedState=n;var i={value:n,getSnapshot:t};return l.queue=i,$o(Ic.bind(null,r,i,e),[e]),r.flags|=2048,Ar(9,$c.bind(null,r,i,n,t),void 0,null),n},useId:function(){var e=wt(),t=Pe.identifierPrefix;if(fe){var n=Et,r=Ct;n=(r&~(1<<32-gt(r)-1)).toString(32)+n,t=":"+t+"R"+n,n=Fr++,0<\/script>",e=e.removeChild(e.firstChild)):typeof r.is=="string"?e=a.createElement(n,{is:r.is}):(e=a.createElement(n),n==="select"&&(a=e,r.multiple?a.multiple=!0:r.size&&(a.size=r.size))):e=a.createElementNS(e,n),e[kt]=t,e[$r]=r,id(e,t,!1,!1),t.stateNode=e;e:{switch(a=pi(n,r),n){case"dialog":oe("cancel",e),oe("close",e),l=r;break;case"iframe":case"object":case"embed":oe("load",e),l=r;break;case"video":case"audio":for(l=0;lXn&&(t.flags|=128,r=!0,ar(i,!1),t.lanes=4194304)}else{if(!r)if(e=Vl(a),e!==null){if(t.flags|=128,r=!0,n=e.updateQueue,n!==null&&(t.updateQueue=n,t.flags|=4),ar(i,!0),i.tail===null&&i.tailMode==="hidden"&&!a.alternate&&!fe)return Ie(t),null}else 2*xe()-i.renderingStartTime>Xn&&n!==1073741824&&(t.flags|=128,r=!0,ar(i,!1),t.lanes=4194304);i.isBackwards?(a.sibling=t.child,t.child=a):(n=i.last,n!==null?n.sibling=a:t.child=a,i.last=a)}return i.tail!==null?(t=i.tail,i.rendering=t,i.tail=t.sibling,i.renderingStartTime=xe(),t.sibling=null,n=pe.current,ae(pe,r?n&1|2:n&1),t):(Ie(t),null);case 22:case 23:return Oa(),r=t.memoizedState!==null,e!==null&&e.memoizedState!==null!==r&&(t.flags|=8192),r&&t.mode&1?Ye&1073741824&&(Ie(t),t.subtreeFlags&6&&(t.flags|=8192)):Ie(t),null;case 24:return null;case 25:return null}throw Error(z(156,t.tag))}function Jp(e,t){switch(va(t),t.tag){case 1:return Xe(t.type)&&Fl(),e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 3:return Qn(),ue(Ke),ue(Fe),Ca(),e=t.flags,e&65536&&!(e&128)?(t.flags=e&-65537|128,t):null;case 5:return _a(t),null;case 13:if(ue(pe),e=t.memoizedState,e!==null&&e.dehydrated!==null){if(t.alternate===null)throw Error(z(340));Wn()}return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 19:return ue(pe),null;case 4:return Qn(),null;case 10:return ka(t.type._context),null;case 22:case 23:return Oa(),null;case 24:return null;default:return null}}var dl=!1,Oe=!1,qp=typeof WeakSet=="function"?WeakSet:Set,O=null;function Rn(e,t){var n=e.ref;if(n!==null)if(typeof n=="function")try{n(null)}catch(r){ye(e,t,r)}else n.current=null}function Ai(e,t,n){try{n()}catch(r){ye(e,t,r)}}var Qo=!1;function Yp(e,t){if(Si=Dl,e=pc(),ma(e)){if("selectionStart"in e)var n={start:e.selectionStart,end:e.selectionEnd};else e:{n=(n=e.ownerDocument)&&n.defaultView||window;var r=n.getSelection&&n.getSelection();if(r&&r.rangeCount!==0){n=r.anchorNode;var l=r.anchorOffset,i=r.focusNode;r=r.focusOffset;try{n.nodeType,i.nodeType}catch{n=null;break e}var a=0,u=-1,o=-1,c=0,g=0,h=e,m=null;t:for(;;){for(var y;h!==n||l!==0&&h.nodeType!==3||(u=a+l),h!==i||r!==0&&h.nodeType!==3||(o=a+r),h.nodeType===3&&(a+=h.nodeValue.length),(y=h.firstChild)!==null;)m=h,h=y;for(;;){if(h===e)break t;if(m===n&&++c===l&&(u=a),m===i&&++g===r&&(o=a),(y=h.nextSibling)!==null)break;h=m,m=h.parentNode}h=y}n=u===-1||o===-1?null:{start:u,end:o}}else n=null}n=n||{start:0,end:0}}else n=null;for(Ni={focusedElem:e,selectionRange:n},Dl=!1,O=t;O!==null;)if(t=O,e=t.child,(t.subtreeFlags&1028)!==0&&e!==null)e.return=t,O=e;else for(;O!==null;){t=O;try{var w=t.alternate;if(t.flags&1024)switch(t.tag){case 0:case 11:case 15:break;case 1:if(w!==null){var k=w.memoizedProps,j=w.memoizedState,p=t.stateNode,d=p.getSnapshotBeforeUpdate(t.elementType===t.type?k:pt(t.type,k),j);p.__reactInternalSnapshotBeforeUpdate=d}break;case 3:var v=t.stateNode.containerInfo;v.nodeType===1?v.textContent="":v.nodeType===9&&v.documentElement&&v.removeChild(v.documentElement);break;case 5:case 6:case 4:case 17:break;default:throw Error(z(163))}}catch(x){ye(t,t.return,x)}if(e=t.sibling,e!==null){e.return=t.return,O=e;break}O=t.return}return w=Qo,Qo=!1,w}function jr(e,t,n){var r=t.updateQueue;if(r=r!==null?r.lastEffect:null,r!==null){var l=r=r.next;do{if((l.tag&e)===e){var i=l.destroy;l.destroy=void 0,i!==void 0&&Ai(t,n,i)}l=l.next}while(l!==r)}}function cs(e,t){if(t=t.updateQueue,t=t!==null?t.lastEffect:null,t!==null){var n=t=t.next;do{if((n.tag&e)===e){var r=n.create;n.destroy=r()}n=n.next}while(n!==t)}}function Bi(e){var t=e.ref;if(t!==null){var n=e.stateNode;switch(e.tag){case 5:e=n;break;default:e=n}typeof t=="function"?t(e):t.current=e}}function ud(e){var t=e.alternate;t!==null&&(e.alternate=null,ud(t)),e.child=null,e.deletions=null,e.sibling=null,e.tag===5&&(t=e.stateNode,t!==null&&(delete t[kt],delete t[$r],delete t[Ei],delete t[Rp],delete t[Dp])),e.stateNode=null,e.return=null,e.dependencies=null,e.memoizedProps=null,e.memoizedState=null,e.pendingProps=null,e.stateNode=null,e.updateQueue=null}function cd(e){return e.tag===5||e.tag===3||e.tag===4}function Ko(e){e:for(;;){for(;e.sibling===null;){if(e.return===null||cd(e.return))return null;e=e.return}for(e.sibling.return=e.return,e=e.sibling;e.tag!==5&&e.tag!==6&&e.tag!==18;){if(e.flags&2||e.child===null||e.tag===4)continue e;e.child.return=e,e=e.child}if(!(e.flags&2))return e.stateNode}}function Ui(e,t,n){var r=e.tag;if(r===5||r===6)e=e.stateNode,t?n.nodeType===8?n.parentNode.insertBefore(e,t):n.insertBefore(e,t):(n.nodeType===8?(t=n.parentNode,t.insertBefore(e,n)):(t=n,t.appendChild(e)),n=n._reactRootContainer,n!=null||t.onclick!==null||(t.onclick=Ol));else if(r!==4&&(e=e.child,e!==null))for(Ui(e,t,n),e=e.sibling;e!==null;)Ui(e,t,n),e=e.sibling}function Hi(e,t,n){var r=e.tag;if(r===5||r===6)e=e.stateNode,t?n.insertBefore(e,t):n.appendChild(e);else if(r!==4&&(e=e.child,e!==null))for(Hi(e,t,n),e=e.sibling;e!==null;)Hi(e,t,n),e=e.sibling}var be=null,ht=!1;function Dt(e,t,n){for(n=n.child;n!==null;)dd(e,t,n),n=n.sibling}function dd(e,t,n){if(jt&&typeof jt.onCommitFiberUnmount=="function")try{jt.onCommitFiberUnmount(ns,n)}catch{}switch(n.tag){case 5:Oe||Rn(n,t);case 6:var r=be,l=ht;be=null,Dt(e,t,n),be=r,ht=l,be!==null&&(ht?(e=be,n=n.stateNode,e.nodeType===8?e.parentNode.removeChild(n):e.removeChild(n)):be.removeChild(n.stateNode));break;case 18:be!==null&&(ht?(e=be,n=n.stateNode,e.nodeType===8?Us(e.parentNode,n):e.nodeType===1&&Us(e,n),br(e)):Us(be,n.stateNode));break;case 4:r=be,l=ht,be=n.stateNode.containerInfo,ht=!0,Dt(e,t,n),be=r,ht=l;break;case 0:case 11:case 14:case 15:if(!Oe&&(r=n.updateQueue,r!==null&&(r=r.lastEffect,r!==null))){l=r=r.next;do{var i=l,a=i.destroy;i=i.tag,a!==void 0&&(i&2||i&4)&&Ai(n,t,a),l=l.next}while(l!==r)}Dt(e,t,n);break;case 1:if(!Oe&&(Rn(n,t),r=n.stateNode,typeof r.componentWillUnmount=="function"))try{r.props=n.memoizedProps,r.state=n.memoizedState,r.componentWillUnmount()}catch(u){ye(n,t,u)}Dt(e,t,n);break;case 21:Dt(e,t,n);break;case 22:n.mode&1?(Oe=(r=Oe)||n.memoizedState!==null,Dt(e,t,n),Oe=r):Dt(e,t,n);break;default:Dt(e,t,n)}}function Xo(e){var t=e.updateQueue;if(t!==null){e.updateQueue=null;var n=e.stateNode;n===null&&(n=e.stateNode=new qp),t.forEach(function(r){var l=ih.bind(null,e,r);n.has(r)||(n.add(r),r.then(l,l))})}}function ft(e,t){var n=t.deletions;if(n!==null)for(var r=0;rl&&(l=a),r&=~i}if(r=l,r=xe()-r,r=(120>r?120:480>r?480:1080>r?1080:1920>r?1920:3e3>r?3e3:4320>r?4320:1960*Zp(r/1960))-r,10e?16:e,At===null)var r=!1;else{if(e=At,At=null,ql=0,Z&6)throw Error(z(331));var l=Z;for(Z|=4,O=e.current;O!==null;){var i=O,a=i.child;if(O.flags&16){var u=i.deletions;if(u!==null){for(var o=0;oxe()-$a?un(e,0):Da|=n),Je(e,t)}function xd(e,t){t===0&&(e.mode&1?(t=nl,nl<<=1,!(nl&130023424)&&(nl=4194304)):t=1);var n=Ue();e=Lt(e,t),e!==null&&(Hr(e,t,n),Je(e,n))}function sh(e){var t=e.memoizedState,n=0;t!==null&&(n=t.retryLane),xd(e,n)}function ih(e,t){var n=0;switch(e.tag){case 13:var r=e.stateNode,l=e.memoizedState;l!==null&&(n=l.retryLane);break;case 19:r=e.stateNode;break;default:throw Error(z(314))}r!==null&&r.delete(t),xd(e,n)}var wd;wd=function(e,t,n){if(e!==null)if(e.memoizedProps!==t.pendingProps||Ke.current)Qe=!0;else{if(!(e.lanes&n)&&!(t.flags&128))return Qe=!1,Kp(e,t,n);Qe=!!(e.flags&131072)}else Qe=!1,fe&&t.flags&1048576&&Nc(t,Bl,t.index);switch(t.lanes=0,t.tag){case 2:var r=t.type;Nl(e,t),e=t.pendingProps;var l=Hn(t,Fe.current);Mn(t,n),l=Ta(null,t,r,e,l,n);var i=Pa();return t.flags|=1,typeof l=="object"&&l!==null&&typeof l.render=="function"&&l.$$typeof===void 0?(t.tag=1,t.memoizedState=null,t.updateQueue=null,Xe(r)?(i=!0,Ml(t)):i=!1,t.memoizedState=l.state!==null&&l.state!==void 0?l.state:null,Sa(t),l.updater=us,t.stateNode=l,l._reactInternals=t,Ri(t,r,e,n),t=Ii(null,t,r,!0,i,n)):(t.tag=0,fe&&i&&ga(t),Be(null,t,l,n),t=t.child),t;case 16:r=t.elementType;e:{switch(Nl(e,t),e=t.pendingProps,l=r._init,r=l(r._payload),t.type=r,l=t.tag=oh(r),e=pt(r,e),l){case 0:t=$i(null,t,r,e,n);break e;case 1:t=Ho(null,t,r,e,n);break e;case 11:t=Bo(null,t,r,e,n);break e;case 14:t=Uo(null,t,r,pt(r.type,e),n);break e}throw Error(z(306,r,""))}return t;case 0:return r=t.type,l=t.pendingProps,l=t.elementType===r?l:pt(r,l),$i(e,t,r,l,n);case 1:return r=t.type,l=t.pendingProps,l=t.elementType===r?l:pt(r,l),Ho(e,t,r,l,n);case 3:e:{if(rd(t),e===null)throw Error(z(387));r=t.pendingProps,i=t.memoizedState,l=i.element,bc(e,t),Wl(t,r,null,n);var a=t.memoizedState;if(r=a.element,i.isDehydrated)if(i={element:r,isDehydrated:!1,cache:a.cache,pendingSuspenseBoundaries:a.pendingSuspenseBoundaries,transitions:a.transitions},t.updateQueue.baseState=i,t.memoizedState=i,t.flags&256){l=Kn(Error(z(423)),t),t=Wo(e,t,r,n,l);break e}else if(r!==l){l=Kn(Error(z(424)),t),t=Wo(e,t,r,n,l);break e}else for(Ge=Wt(t.stateNode.containerInfo.firstChild),Ze=t,fe=!0,mt=null,n=Tc(t,null,r,n),t.child=n;n;)n.flags=n.flags&-3|4096,n=n.sibling;else{if(Wn(),r===l){t=zt(e,t,n);break e}Be(e,t,r,n)}t=t.child}return t;case 5:return Lc(t),e===null&&bi(t),r=t.type,l=t.pendingProps,i=e!==null?e.memoizedProps:null,a=l.children,_i(r,l)?a=null:i!==null&&_i(r,i)&&(t.flags|=32),nd(e,t),Be(e,t,a,n),t.child;case 6:return e===null&&bi(t),null;case 13:return ld(e,t,n);case 4:return Na(t,t.stateNode.containerInfo),r=t.pendingProps,e===null?t.child=Vn(t,null,r,n):Be(e,t,r,n),t.child;case 11:return r=t.type,l=t.pendingProps,l=t.elementType===r?l:pt(r,l),Bo(e,t,r,l,n);case 7:return Be(e,t,t.pendingProps,n),t.child;case 8:return Be(e,t,t.pendingProps.children,n),t.child;case 12:return Be(e,t,t.pendingProps.children,n),t.child;case 10:e:{if(r=t.type._context,l=t.pendingProps,i=t.memoizedProps,a=l.value,ae(Ul,r._currentValue),r._currentValue=a,i!==null)if(yt(i.value,a)){if(i.children===l.children&&!Ke.current){t=zt(e,t,n);break e}}else for(i=t.child,i!==null&&(i.return=t);i!==null;){var u=i.dependencies;if(u!==null){a=i.child;for(var o=u.firstContext;o!==null;){if(o.context===r){if(i.tag===1){o=Tt(-1,n&-n),o.tag=2;var c=i.updateQueue;if(c!==null){c=c.shared;var g=c.pending;g===null?o.next=o:(o.next=g.next,g.next=o),c.pending=o}}i.lanes|=n,o=i.alternate,o!==null&&(o.lanes|=n),Li(i.return,n,t),u.lanes|=n;break}o=o.next}}else if(i.tag===10)a=i.type===t.type?null:i.child;else if(i.tag===18){if(a=i.return,a===null)throw Error(z(341));a.lanes|=n,u=a.alternate,u!==null&&(u.lanes|=n),Li(a,n,t),a=i.sibling}else a=i.child;if(a!==null)a.return=i;else for(a=i;a!==null;){if(a===t){a=null;break}if(i=a.sibling,i!==null){i.return=a.return,a=i;break}a=a.return}i=a}Be(e,t,l.children,n),t=t.child}return t;case 9:return l=t.type,r=t.pendingProps.children,Mn(t,n),l=ut(l),r=r(l),t.flags|=1,Be(e,t,r,n),t.child;case 14:return r=t.type,l=pt(r,t.pendingProps),l=pt(r.type,l),Uo(e,t,r,l,n);case 15:return ed(e,t,t.type,t.pendingProps,n);case 17:return r=t.type,l=t.pendingProps,l=t.elementType===r?l:pt(r,l),Nl(e,t),t.tag=1,Xe(r)?(e=!0,Ml(t)):e=!1,Mn(t,n),Yc(t,r,l),Ri(t,r,l,n),Ii(null,t,r,!0,e,n);case 19:return sd(e,t,n);case 22:return td(e,t,n)}throw Error(z(156,t.tag))};function kd(e,t){return Xu(e,t)}function ah(e,t,n,r){this.tag=e,this.key=n,this.sibling=this.child=this.return=this.stateNode=this.type=this.elementType=null,this.index=0,this.ref=null,this.pendingProps=t,this.dependencies=this.memoizedState=this.updateQueue=this.memoizedProps=null,this.mode=r,this.subtreeFlags=this.flags=0,this.deletions=null,this.childLanes=this.lanes=0,this.alternate=null}function at(e,t,n,r){return new ah(e,t,n,r)}function Ma(e){return e=e.prototype,!(!e||!e.isReactComponent)}function oh(e){if(typeof e=="function")return Ma(e)?1:0;if(e!=null){if(e=e.$$typeof,e===la)return 11;if(e===sa)return 14}return 2}function Xt(e,t){var n=e.alternate;return n===null?(n=at(e.tag,t,e.key,e.mode),n.elementType=e.elementType,n.type=e.type,n.stateNode=e.stateNode,n.alternate=e,e.alternate=n):(n.pendingProps=t,n.type=e.type,n.flags=0,n.subtreeFlags=0,n.deletions=null),n.flags=e.flags&14680064,n.childLanes=e.childLanes,n.lanes=e.lanes,n.child=e.child,n.memoizedProps=e.memoizedProps,n.memoizedState=e.memoizedState,n.updateQueue=e.updateQueue,t=e.dependencies,n.dependencies=t===null?null:{lanes:t.lanes,firstContext:t.firstContext},n.sibling=e.sibling,n.index=e.index,n.ref=e.ref,n}function El(e,t,n,r,l,i){var a=2;if(r=e,typeof e=="function")Ma(e)&&(a=1);else if(typeof e=="string")a=5;else e:switch(e){case Nn:return cn(n.children,l,i,t);case ra:a=8,l|=8;break;case ri:return e=at(12,n,t,l|2),e.elementType=ri,e.lanes=i,e;case li:return e=at(13,n,t,l),e.elementType=li,e.lanes=i,e;case si:return e=at(19,n,t,l),e.elementType=si,e.lanes=i,e;case Lu:return fs(n,l,i,t);default:if(typeof e=="object"&&e!==null)switch(e.$$typeof){case Pu:a=10;break e;case bu:a=9;break e;case la:a=11;break e;case sa:a=14;break e;case $t:a=16,r=null;break e}throw Error(z(130,e==null?e:typeof e,""))}return t=at(a,n,t,l),t.elementType=e,t.type=r,t.lanes=i,t}function cn(e,t,n,r){return e=at(7,e,r,t),e.lanes=n,e}function fs(e,t,n,r){return e=at(22,e,r,t),e.elementType=Lu,e.lanes=n,e.stateNode={isHidden:!1},e}function qs(e,t,n){return e=at(6,e,null,t),e.lanes=n,e}function Ys(e,t,n){return t=at(4,e.children!==null?e.children:[],e.key,t),t.lanes=n,t.stateNode={containerInfo:e.containerInfo,pendingChildren:null,implementation:e.implementation},t}function uh(e,t,n,r,l){this.tag=t,this.containerInfo=e,this.finishedWork=this.pingCache=this.current=this.pendingChildren=null,this.timeoutHandle=-1,this.callbackNode=this.pendingContext=this.context=null,this.callbackPriority=0,this.eventTimes=Ls(0),this.expirationTimes=Ls(-1),this.entangledLanes=this.finishedLanes=this.mutableReadLanes=this.expiredLanes=this.pingedLanes=this.suspendedLanes=this.pendingLanes=0,this.entanglements=Ls(0),this.identifierPrefix=r,this.onRecoverableError=l,this.mutableSourceEagerHydrationData=null}function Aa(e,t,n,r,l,i,a,u,o){return e=new uh(e,t,n,u,o),t===1?(t=1,i===!0&&(t|=8)):t=0,i=at(3,null,null,t),e.current=i,i.stateNode=e,i.memoizedState={element:r,isDehydrated:n,cache:null,transitions:null,pendingSuspenseBoundaries:null},Sa(i),e}function ch(e,t,n){var r=3"u"||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!="function"))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(_d)}catch(e){console.error(e)}}_d(),_u.exports=tt;var mh=_u.exports,Cd,nu=mh;Cd=nu.createRoot,nu.hydrateRoot;async function Ee(e){const t=await fetch(e);if(!t.ok)throw new Error(`${t.status} ${t.statusText}`);return t.json()}async function gh(){return Ee("/api/archives")}async function vh(e){return Ee(`/api/archives/${e}/entries`)}async function yh(e,t,n){const r=new URLSearchParams;return t&&r.set("q",t),n&&r.set("tag",n),Ee(`/api/archives/${e}/entries/search?${r}`)}async function Xi(e,t){return Ee(`/api/archives/${e}/entries/${t}`)}function xh(e,t,n){return Promise.all(n.map(r=>Ee(`/api/archives/${e}/entries/${t}/artifacts/${r}`)))}async function wh(e){if(!e||e.length===0)return{};const t=await fetch("/api/util/resolve-tco",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(e)});return t.ok?t.json():{}}async function kh(e,t,n){const r=await fetch(`/api/archives/${e}/entries/${t}`,{method:"PATCH",headers:{"Content-Type":"application/json"},body:JSON.stringify({title:n??null})});if(!r.ok)throw new Error(await r.text())}async function hl(e,t){return Ee(`/api/archives/${e}/entries/${t}/tags`)}async function ru(e,t,n){const r=await fetch(`/api/archives/${e}/entries/${t}/tags`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({tag_path:n})});if(!r.ok)throw new Error(`Failed to add tag (${r.status})`)}async function jh(e,t,n){const r=await fetch(`/api/archives/${e}/entries/${t}/tags/${n}`,{method:"DELETE"});if(!r.ok)throw new Error(`Remove failed (${r.status})`)}async function lu(e,t){const n=await fetch(`/api/archives/${e}/entries/${t}`,{method:"DELETE"});if(!n.ok)throw new Error(`Delete failed (${n.status})`)}async function Sh(e,t,n){const r=await fetch(`/api/archives/${e}/tags/${t}`,{method:"PATCH",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:n})});if(!r.ok)throw new Error(await r.text());return r.json()}async function Nh(e,t){const n=await fetch(`/api/archives/${e}/tags/${t}`,{method:"DELETE"});if(!n.ok)throw new Error(await n.text())}async function _h(e,t){const n=await fetch(`/api/archives/${e}/tags`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({path:t})});if(!n.ok)throw new Error(await n.text());return n.json()}async function Ch(e,t,n){const r=await fetch(`/api/archives/${e}/tags/${t}/move`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({parent_uid:n??null})});if(!r.ok)throw new Error(await r.text());return r.json()}async function Gs(e){return Ee(`/api/archives/${e}/runs`)}async function ml(e){return Ee(`/api/archives/${e}/tags`)}async function Eh(e,t,n=null,r=null){const l={locator:t};n&&n!=="best"&&(l.quality=n),r&&(typeof r.ublock_enabled=="boolean"&&(l.ublock_enabled=r.ublock_enabled),typeof r.reader_mode=="boolean"&&(l.reader_mode=r.reader_mode),typeof r.cookie_ext_enabled=="boolean"&&(l.cookie_ext_enabled=r.cookie_ext_enabled),typeof r.modal_closer_enabled=="boolean"&&(l.modal_closer_enabled=r.modal_closer_enabled),typeof r.via_freedium=="boolean"&&(l.via_freedium=r.via_freedium));const i=await fetch(`/api/archives/${e}/captures`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(l)});if(!i.ok){const a=await i.json().catch(()=>({}));throw new Error(a.error||`HTTP ${i.status}`)}return i.json()}async function Th(e,t){return Ee(`/api/archives/${e}/captures/probe?locator=${encodeURIComponent(t)}`)}async function Ed(e,t){return Ee(`/api/archives/${e}/capture_jobs/${t}`)}async function Ph(){return(await(await fetch("/api/auth/setup")).json()).setup_required===!0}async function bh(e,t){const n=await fetch("/api/auth/setup",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({username:e,password:t})});if(!n.ok)throw new Error((await n.json()).error||"Setup failed");return n.json()}async function Lh(e,t){const n=await fetch("/api/auth/login",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({username:e,password:t})});if(!n.ok)throw new Error((await n.json()).error||"Login failed");return n.json()}async function zh(){await fetch("/api/auth/logout",{method:"POST"})}async function Rh(){const e=await fetch("/api/auth/me");return e.status===401?null:e.json()}async function Dh(e){const t=await fetch("/api/auth/me",{method:"PATCH",headers:{"Content-Type":"application/json"},body:JSON.stringify({display_name:e})});if(!t.ok)throw new Error(await t.text())}async function $h(e){const t=await fetch("/api/auth/me",{method:"PATCH",headers:{"Content-Type":"application/json"},body:JSON.stringify(e)});if(!t.ok)throw new Error(await t.text())}async function Ih(e,t){const n=await fetch("/api/auth/me",{method:"PATCH",headers:{"Content-Type":"application/json"},body:JSON.stringify({current_password:e,new_password:t})});if(!n.ok){let r=await n.text();try{r=JSON.parse(r).error??r}catch{}throw new Error(r)}}async function Oh(){return Ee("/api/auth/tokens")}async function Fh(e){const t=await fetch("/api/auth/tokens",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:e})});if(!t.ok)throw new Error(await t.text());return t.json()}async function Mh(e){const t=await fetch(`/api/auth/tokens/${e}`,{method:"DELETE"});if(!t.ok)throw new Error(await t.text())}async function Wa(){return Ee("/api/admin/instance-settings")}async function Tl(e){const t=await fetch("/api/admin/instance-settings",{method:"PATCH",headers:{"Content-Type":"application/json"},body:JSON.stringify(e)});if(!t.ok)throw new Error(await t.text())}async function Ah(){return Ee("/api/admin/users")}async function Bh(e,t,n){const r=await fetch("/api/admin/users",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({username:e,password:t,email:n||void 0})});if(!r.ok){const l=await r.json().catch(()=>({}));throw new Error(l.error||`HTTP ${r.status}`)}return r.json()}async function Uh(e,t){const n=await fetch(`/api/admin/users/${e}/status`,{method:"PATCH",headers:{"Content-Type":"application/json"},body:JSON.stringify({status:t})});if(!n.ok){const r=await n.json().catch(()=>({}));throw new Error(r.error||`HTTP ${n.status}`)}return n.json()}async function Hh(){return Ee("/api/admin/roles")}async function Wh(e,t){const n=await fetch("/api/admin/roles",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({slug:e,name:t})});if(!n.ok){const r=await n.json().catch(()=>({}));throw new Error(r.error||`HTTP ${n.status}`)}return n.json()}async function Td(e){return Ee(`/api/archives/${e}/collections`)}async function Vh(e,t,n,r=2){const l=await fetch(`/api/archives/${e}/collections`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({name:t,slug:n,default_visibility_bits:r})});if(!l.ok){const i=await l.json().catch(()=>({error:l.statusText}));throw new Error(i.error||l.statusText)}return l.json()}async function Qh(e,t){return Ee(`/api/archives/${e}/collections/${t}`)}async function Pd(e,t,n,r=2){const l=await fetch(`/api/archives/${e}/collections/${t}/entries`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({entry_uid:n,visibility_bits:r})});if(!l.ok){const i=await l.json().catch(()=>({error:l.statusText}));throw new Error(i.error||l.statusText)}}async function Kh(e,t,n){const r=await fetch(`/api/archives/${e}/collections/${t}/entries/${n}`,{method:"DELETE"});if(!r.ok){const l=await r.json().catch(()=>({error:r.statusText}));throw new Error(l.error||r.statusText)}}async function Xh(e,t,n,r){const l=await fetch(`/api/archives/${e}/collections/${t}/entries/${n}`,{method:"PATCH",headers:{"content-type":"application/json"},body:JSON.stringify({visibility_bits:r})});if(!l.ok){const i=await l.json().catch(()=>({error:l.statusText}));throw new Error(i.error||l.statusText)}}async function Jh(e,t){return Ee(`/api/archives/${e}/entries/${t}/collections`)}async function su(e,t,n){const r=await fetch(`/api/archives/${e}/collections/${t}`,{method:"PATCH",headers:{"Content-Type":"application/json"},body:JSON.stringify(n)});if(!r.ok){const l=await r.json().catch(()=>({}));throw new Error(l.error??r.statusText)}}async function qh(e,t){const n=await fetch(`/api/archives/${e}/collections/${t}`,{method:"DELETE"});if(!n.ok){const r=await n.json().catch(()=>({}));throw new Error(r.error??n.statusText)}}async function Yh(e){return Ee(`/api/archives/${e}/blob-cleanup`)}async function Gh(e){const t=await fetch(`/api/archives/${e}/blob-cleanup`,{method:"DELETE"});if(!t.ok){const n=await t.json().catch(()=>({}));throw new Error(n.error??t.statusText)}return t.json()}async function Zh(e,t){const n=await fetch(`/api/archives/${e}/entries/${t}/rearchive`,{method:"POST"});if(!n.ok){const r=await n.json().catch(()=>({}));throw new Error(r.message||`rearchive failed: ${n.status}`)}return n.json()}async function em(){return Ee("/api/admin/cookie-rules")}async function tm(e,t,n){const r=await fetch("/api/admin/cookie-rules",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({url_pattern:e||null,pattern_kind:t,cookies_json:n})});if(!r.ok){const l=await r.json().catch(()=>({}));throw new Error(l.message||`HTTP ${r.status}`)}return r.json()}async function nm(e,t){const n=await fetch(`/api/admin/cookie-rules/${e}`,{method:"PATCH",headers:{"Content-Type":"application/json"},body:JSON.stringify(t)});if(!n.ok){const r=await n.json().catch(()=>({}));throw new Error(r.message||`HTTP ${n.status}`)}}async function rm(e){const t=await fetch(`/api/admin/cookie-rules/${e}`,{method:"DELETE"});if(!t.ok){const n=await t.json().catch(()=>({}));throw new Error(n.message||`HTTP ${t.status}`)}}const lm=window.fetch;window.fetch=async(...e)=>{var n;const t=await lm(...e);return t.status===401&&((typeof e[0]=="string"?e[0]:((n=e[0])==null?void 0:n.url)??"").includes("/api/auth/")||window.dispatchEvent(new CustomEvent("auth:expired"))),t};function sm({onLogin:e}){const[t,n]=f.useState(""),[r,l]=f.useState(""),[i,a]=f.useState(null),[u,o]=f.useState(!1);async function c(g){g.preventDefault(),a(null),o(!0);try{const h=await Lh(t,r);e(h)}catch(h){a(h.message)}finally{o(!1)}}return s.jsx("div",{className:"login-page",children:s.jsxs("div",{className:"login-card",children:[s.jsx("h1",{className:"login-brand",children:"Archivr"}),s.jsx("p",{className:"login-tagline",children:"Sign in to your archive"}),s.jsxs("form",{onSubmit:c,children:[s.jsxs("div",{className:"login-field",children:[s.jsx("label",{className:"login-label",htmlFor:"login-username",children:"Username"}),s.jsx("input",{className:"login-input",id:"login-username",type:"text",value:t,onChange:g=>n(g.target.value),autoFocus:!0,required:!0,autoComplete:"username"})]}),s.jsxs("div",{className:"login-field",children:[s.jsx("label",{className:"login-label",htmlFor:"login-password",children:"Password"}),s.jsx("input",{className:"login-input",id:"login-password",type:"password",value:r,onChange:g=>l(g.target.value),required:!0,autoComplete:"current-password"})]}),i&&s.jsx("p",{className:"login-error",children:i}),s.jsx("button",{className:"login-submit",type:"submit",disabled:u,children:u?"Signing in…":"Sign in"})]})]})})}function im({onComplete:e}){const[t,n]=f.useState(""),[r,l]=f.useState(""),[i,a]=f.useState(""),[u,o]=f.useState(null),[c,g]=f.useState(!1);async function h(m){if(m.preventDefault(),r!==i){o("Passwords do not match");return}if(r.length<8){o("Password must be at least 8 characters");return}o(null),g(!0);try{await bh(t,r),e()}catch(y){o(y.message)}finally{g(!1)}}return s.jsx("div",{className:"setup-page",children:s.jsxs("div",{className:"setup-card",children:[s.jsx("h1",{className:"setup-brand",children:"Archivr"}),s.jsx("p",{className:"setup-tagline",children:"Create your owner account to get started."}),s.jsxs("form",{onSubmit:h,children:[s.jsxs("div",{className:"setup-field",children:[s.jsx("label",{className:"setup-label",htmlFor:"setup-username",children:"Username"}),s.jsx("input",{className:"setup-input",id:"setup-username",type:"text",value:t,onChange:m=>n(m.target.value),autoFocus:!0,required:!0,autoComplete:"username"})]}),s.jsxs("div",{className:"setup-field",children:[s.jsx("label",{className:"setup-label",htmlFor:"setup-password",children:"Password"}),s.jsx("input",{className:"setup-input",id:"setup-password",type:"password",value:r,onChange:m=>l(m.target.value),required:!0,autoComplete:"new-password"})]}),s.jsxs("div",{className:"setup-field",children:[s.jsx("label",{className:"setup-label",htmlFor:"setup-confirm",children:"Confirm password"}),s.jsx("input",{className:"setup-input",id:"setup-confirm",type:"password",value:i,onChange:m=>a(m.target.value),required:!0,autoComplete:"new-password"})]}),u&&s.jsx("p",{className:"setup-error",children:u}),s.jsx("button",{className:"setup-submit",type:"submit",disabled:c,children:c?"Creating account…":"Create account"})]})]})})}function am({archives:e,archiveId:t,onArchiveChange:n,view:r,onViewChange:l,onCaptureClick:i}){const{currentUser:a,setCurrentUser:u}=f.useContext(vs)??{},[o,c]=f.useState(!1);async function g(){c(!0),await zh(),u(null),window.location.reload()}return s.jsxs("header",{className:"topbar",children:[s.jsx("div",{className:"brand",children:"Archivr"}),s.jsx("div",{className:"switcher",children:s.jsx("select",{"aria-label":"Select archive",value:t??"",onChange:h=>n(h.target.value),children:e.map(h=>s.jsx("option",{value:h.id,children:h.label},h.id))})}),s.jsx("nav",{className:"nav","aria-label":"Primary",children:["archive","tags","collections","runs","admin","settings"].map(h=>s.jsx("button",{className:`nav-link${r===h?" is-active":""}`,onClick:()=>l(h),children:h.charAt(0).toUpperCase()+h.slice(1)},h))}),s.jsx("button",{className:"capture-button",onClick:i,children:"Capture"}),a&&s.jsxs("div",{className:"user-menu",children:[s.jsx("span",{className:"user-name",children:a.display_name||a.username}),s.jsx("button",{className:"logout-btn",onClick:g,disabled:o,children:o?"Logging out…":"Log out"})]})]})}let Ji=1;function bd(e){const t=e.trim(),n=t.toLowerCase();for(const r of["yt:","youtube:"])if(n.startsWith(r)){const l=n.slice(r.length);return l.startsWith("video/")||l.startsWith("short/")||l.startsWith("shorts/")}if(n.startsWith("ytm:"))return!n.slice(4).startsWith("playlist/");for(const r of["x:","twitter:","tweet:"])if(n.startsWith(r))return n.slice(r.length).startsWith("media:");if(n.startsWith("spotify:"))return!1;if(n.startsWith("instagram:")||n.startsWith("facebook:")||n.startsWith("tiktok:")||n.startsWith("reddit:")||n.startsWith("snapchat:"))return!0;if(n.startsWith("http://")||n.startsWith("https://")){if(/^https?:\/\/music\.youtube\.com\/watch/.test(n)||/^https?:\/\/(?:www\.)?(?:youtu\.be\/[0-9A-Za-z_-]+|youtube\.com\/watch\?v=[0-9A-Za-z_-]+|youtube\.com\/shorts\/[0-9A-Za-z_-]+)/.test(t)||n.startsWith("https://x.com/")||n.startsWith("http://x.com/")||/^https?:\/\/(?:www\.)?instagram\.com\//.test(n)||/^https?:\/\/(?:www\.)?facebook\.com\//.test(n)||n.startsWith("https://fb.watch/")||n.startsWith("http://fb.watch/")||/^https?:\/\/(?:www\.)?tiktok\.com\//.test(n)||/^https?:\/\/(?:www\.)?reddit\.com\//.test(n)||n.startsWith("https://redd.it/")||n.startsWith("http://redd.it/")||/^https?:\/\/(?:www\.)?snapchat\.com\//.test(n))return!0;if(n.startsWith("https://open.spotify.com/")||n.startsWith("http://open.spotify.com/"))return!1}return!1}function ur(e=""){return{id:Ji++,locator:e,quality:"best",probeState:"idle",probeQualities:null,probeHasAudio:!1,status:"idle",error:null,jobUid:null,archiveId:null}}function om({open:e,archiveId:t,onClose:n,onCaptured:r,onToast:l,onJobStarted:i,onJobSettled:a,activeJobs:u=[]}){const o=f.useRef(null),c=f.useRef(!0),g=f.useRef(new Map),h=f.useRef(new Map),m=f.useRef(new Map),y=f.useRef(t);f.useEffect(()=>{y.current=t},[t]);const w=f.useRef(r),k=f.useRef(l);f.useEffect(()=>{w.current=r},[r]),f.useEffect(()=>{k.current=l},[l]);const j=f.useRef(i),p=f.useRef(a);f.useEffect(()=>{j.current=i},[i]),f.useEffect(()=>{p.current=a},[a]);const[d,v]=f.useState(()=>{try{const E=JSON.parse(sessionStorage.getItem("captureItems")||"null");if(Array.isArray(E)&&E.length>0){const U=E.filter(K=>!K.status||K.status==="idle");if(U.length>0)return U.forEach(K=>{K.id>=Ji&&(Ji=K.id+1)}),U}}catch{}return[ur()]});f.useEffect(()=>{sessionStorage.setItem("captureItems",JSON.stringify(d))},[d]);const[x,_]=f.useState(!1),[b,C]=f.useState(null),[S,D]=f.useState(null),[L,H]=f.useState(!0),[M,W]=f.useState(!0),[Y,ce]=f.useState(!0);f.useEffect(()=>{Wa().then(E=>{D(E),H(E.cookie_ext_enabled??!0),W(E.modal_closer_enabled??!0)}).catch(()=>D({}))},[]);const ie=b!==null?b:(S==null?void 0:S.ublock_enabled)??!0,[ee,R]=f.useState(!1);f.useEffect(()=>{["captureDialogLocator","captureDialogError","captureDialogBusy","captureDialogJobStatus","captureDialogJobUid"].forEach(E=>sessionStorage.removeItem(E)),u.forEach(E=>{E.jobUid&&!g.current.has(E.jobUid)&&T(E.id,E.jobUid,E.locator,E.archiveId,null)})},[]),f.useEffect(()=>{const E=o.current;if(!E)return;const U=()=>{h.current.forEach(K=>clearTimeout(K)),h.current.clear(),n()};return E.addEventListener("close",U),()=>E.removeEventListener("close",U)},[n]),f.useEffect(()=>{const E=o.current;E&&(e?(c.current||v([ur()]),c.current=!1,E.open||E.showModal()):(h.current.forEach(U=>clearTimeout(U)),h.current.clear(),E.open&&E.close()))},[e]),f.useEffect(()=>()=>{g.current.forEach(E=>clearInterval(E)),h.current.forEach(E=>clearTimeout(E))},[]);function T(E,U,K,V,X=null){if(g.current.has(U))return;const P=setInterval(async()=>{var B,re,le,rt;try{const Me=await Ed(V,U);if(Me.status==="completed"){clearInterval(g.current.get(U)),g.current.delete(U),await Promise.resolve((B=w.current)==null?void 0:B.call(w)),(re=p.current)==null||re.call(p,E);try{const ve=Me.notes_json?JSON.parse(Me.notes_json):null;if(ve!=null&&ve.ublock_skipped||ve!=null&&ve.cookie_ext_skipped){const qe=ve.ublock_skipped&&ve.cookie_ext_skipped?"Captured without ad-blocking or cookie-consent extension. Check ARCHIVR_UBLOCK_EXT and ARCHIVR_COOKIE_EXT in your server config.":ve.ublock_skipped?"Captured without ad-blocking. ARCHIVR_UBLOCK=true but ARCHIVR_UBLOCK_EXT is not set or the path is invalid.":"Captured without cookie-consent extension. ARCHIVR_COOKIE_EXT is not set or the path is invalid.";k.current(qe,K,"warning"),F(X,"warning",K)}else X||k.current(null,K,"success"),F(X,"archived")}catch{X||k.current(null,K,"success"),F(X,"archived")}}else if(Me.status==="failed"){clearInterval(g.current.get(U)),g.current.delete(U),(le=p.current)==null||le.call(p,E);const ve=Me.error_text||"Capture failed.";k.current(ve,K),F(X,"failed",K)}}catch(Me){clearInterval(g.current.get(U)),g.current.delete(U),(rt=p.current)==null||rt.call(p,E);const ve=Me.message||"Network error";k.current(ve,K),F(X,"failed",K)}},500);g.current.set(U,P)}function F(E,U,K=null){if(!E)return;const V=m.current.get(E);if(!V||(U==="archived"||U==="warning"?(V.archived++,U==="warning"&&(V.warnings++,K&&V.warningLocators.push(K))):(V.failed++,K&&V.failedLocators.push(K)),V.archived+V.failed0?`${X} archived (${P} with warnings)`:`${X} archived`;rt=B>0?`${qe}, ${B} failed`:qe}const Me=X===0?"error":B>0||P>0?"warning":"success",ve=[];re.length>0&&ve.push(`Failed: +${re.map(qe=>` ${qe}`).join(` +`)}`),le.length>0&&ve.push(`With warnings: +${le.map(qe=>` ${qe}`).join(` +`)}`);const en=ve.length>0?ve.join(` +`):null;k.current(en,null,Me,rt)}async function q(E,U,K){var B,re;const V=y.current,X=((B=crypto.randomUUID)==null?void 0:B.call(crypto))??`job-${Date.now()}-${Math.random()}`,P={ublock_enabled:ie,reader_mode:ee,cookie_ext_enabled:L,modal_closer_enabled:M,via_freedium:Y};try{const le=await Eh(V,E,U,P);(re=j.current)==null||re.call(j,{id:X,jobUid:le.job_uid,locator:E,archiveId:V}),T(X,le.job_uid,E,V,K)}catch(le){const rt=le.message||"Submission failed.";k.current(rt,E),F(K,"failed",E)}}function A(){var V,X;const E=d.filter(P=>P.locator.trim());if(E.length===0)return;const U=E.length>1?((V=crypto.randomUUID)==null?void 0:V.call(crypto))??`batch-${Date.now()}`:null;U&&m.current.set(U,{total:E.length,archived:0,warnings:0,failed:0,failedLocators:[],warningLocators:[]});const K=E.map(P=>P.quality||"best");v([ur()]),(X=o.current)==null||X.close(),E.forEach((P,B)=>q(P.locator.trim(),K[B],U))}function ge(){v(E=>[...E,ur()])}function de(E){clearTimeout(h.current.get(E)),h.current.delete(E),v(U=>{const K=U.filter(V=>V.id!==E);return K.length===0?[ur()]:K})}function Re(E,U){if(clearTimeout(h.current.get(E)),v(V=>V.map(X=>X.id===E?{...X,locator:U,probeState:"idle",probeQualities:null,probeHasAudio:!1,quality:"best"}:X)),!bd(U))return;const K=setTimeout(async()=>{h.current.delete(E),v(V=>V.map(X=>X.id===E?{...X,probeState:"probing"}:X));try{const V=await Th(y.current,U.trim());v(X=>X.map(P=>{if(P.id!==E||P.locator!==U)return P;const B=V.qualities??[],re=V.has_audio??!1,le=B.length===0&&re?"audio":"best";return{...P,probeState:"done",probeQualities:B,probeHasAudio:re,quality:le}}))}catch{v(V=>V.map(X=>X.id===E?{...X,probeState:"idle",probeQualities:null}:X))}},600);h.current.set(E,K)}function we(E,U){v(K=>K.map(V=>V.id===E?{...V,quality:U}:V))}const je=d.filter(E=>E.locator.trim()).length;return s.jsx("dialog",{ref:o,className:"capture-dialog",children:s.jsxs("div",{className:"capture-dialog-inner",children:[s.jsxs("div",{className:"capture-dialog-header",children:[s.jsx("h2",{className:"capture-dialog-title",children:"Capture"}),s.jsx("button",{type:"button",className:"capture-dialog-close",onClick:()=>{var E;return(E=o.current)==null?void 0:E.close()},"aria-label":"Close",children:s.jsxs("svg",{viewBox:"0 0 16 16",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",children:[s.jsx("line",{x1:"3",y1:"3",x2:"13",y2:"13"}),s.jsx("line",{x1:"13",y1:"3",x2:"3",y2:"13"})]})})]}),s.jsx("div",{className:"capture-rows",children:d.map((E,U)=>s.jsx(um,{item:E,autoFocus:U===d.length-1,onLocatorChange:K=>Re(E.id,K),onQualityChange:K=>we(E.id,K),onRemove:()=>de(E.id),onSubmit:A},E.id))}),s.jsxs("button",{type:"button",className:"capture-add-row",onClick:ge,children:[s.jsxs("svg",{viewBox:"0 0 16 16",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",children:[s.jsx("line",{x1:"8",y1:"2",x2:"8",y2:"14"}),s.jsx("line",{x1:"2",y1:"8",x2:"14",y2:"8"})]}),"Add another"]}),s.jsxs("div",{className:"capture-advanced",children:[s.jsxs("button",{type:"button",className:"capture-advanced-toggle",onClick:()=>_(E=>!E),"aria-expanded":x,children:[s.jsx("svg",{className:`capture-chevron${x?" capture-chevron--open":""}`,viewBox:"0 0 16 16",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:s.jsx("polyline",{points:"4 6 8 10 12 6"})}),"Advanced options"]}),x&&s.jsxs("div",{className:"capture-advanced-panel",children:[s.jsxs("label",{className:"capture-ext-row",children:[s.jsxs("span",{className:"capture-ext-label",children:[s.jsx("span",{className:"capture-ext-name",children:"uBlock Origin Lite"}),s.jsx("span",{className:"capture-ext-desc",children:"Block ads during this capture"})]}),s.jsx("button",{type:"button",role:"switch","aria-checked":ie,className:`ext-toggle ext-toggle--sm${ie?" ext-toggle--on":""}`,onClick:()=>C(E=>E===null?!ie:!E),"aria-label":"Toggle uBlock for this capture",children:s.jsx("span",{className:"ext-toggle-knob"})})]}),s.jsxs("label",{className:"capture-ext-row",style:{marginTop:8},children:[s.jsxs("span",{className:"capture-ext-label",children:[s.jsx("span",{className:"capture-ext-name",children:"Block cookie banners"}),s.jsx("span",{className:"capture-ext-desc",children:"Dismiss cookie consent banners during this capture"}),!(S!=null&&S.cookie_ext_available)&&s.jsxs("span",{className:"capture-ext-hint",children:["Not configured — set ",s.jsx("code",{children:"ARCHIVR_COOKIE_EXT"})]})]}),s.jsx("button",{type:"button",role:"switch","aria-checked":L,className:`ext-toggle ext-toggle--sm${L?" ext-toggle--on":""}`,onClick:()=>H(E=>!E),"aria-label":"Toggle cookie banner blocking for this capture",children:s.jsx("span",{className:"ext-toggle-knob"})})]}),s.jsxs("label",{className:"capture-ext-row",style:{marginTop:8},children:[s.jsxs("span",{className:"capture-ext-label",children:[s.jsx("span",{className:"capture-ext-name",children:"Reader mode"}),s.jsx("span",{className:"capture-ext-desc",children:"Distil to article text via Readability (off by default)"})]}),s.jsx("button",{type:"button",role:"switch","aria-checked":ee,className:`ext-toggle ext-toggle--sm${ee?" ext-toggle--on":""}`,onClick:()=>R(E=>!E),"aria-label":"Toggle reader mode for this capture",children:s.jsx("span",{className:"ext-toggle-knob"})})]}),s.jsxs("label",{className:"capture-ext-row",style:{marginTop:8},children:[s.jsxs("span",{className:"capture-ext-label",children:[s.jsx("span",{className:"capture-ext-name",children:"Close modals and dialogs"}),s.jsx("span",{className:"capture-ext-desc",children:"Auto-dismiss cookie banners and overlays during this capture"})]}),s.jsx("button",{type:"button",role:"switch","aria-checked":M,className:`ext-toggle ext-toggle--sm${M?" ext-toggle--on":""}`,onClick:()=>W(E=>!E),"aria-label":"Toggle modal closer for this capture",children:s.jsx("span",{className:"ext-toggle-knob"})})]}),s.jsxs("label",{className:"capture-ext-row",style:{marginTop:8},children:[s.jsxs("span",{className:"capture-ext-label",children:[s.jsx("span",{className:"capture-ext-name",children:"Freedium mirror"}),s.jsx("span",{className:"capture-ext-desc",children:"Route paywalled articles through a Freedium mirror (Medium, NYT, WaPo, etc.)"})]}),s.jsx("button",{type:"button",role:"switch","aria-checked":Y,className:`ext-toggle ext-toggle--sm${Y?" ext-toggle--on":""}`,onClick:()=>ce(E=>!E),"aria-label":"Toggle Freedium mirror for this capture",children:s.jsx("span",{className:"ext-toggle-knob"})})]})]})]}),s.jsxs("div",{className:"capture-actions",children:[s.jsx("button",{type:"button",className:"capture-submit",onClick:A,disabled:je===0,children:je>1?`Archive ${je}`:"Archive"}),s.jsx("button",{type:"button",className:"capture-cancel",onClick:()=>{var E;return(E=o.current)==null?void 0:E.close()},children:"Cancel"})]})]})})}function um({item:e,autoFocus:t,onLocatorChange:n,onQualityChange:r,onRemove:l,onSubmit:i}){const a=f.useRef(null);f.useEffect(()=>{var o;t&&((o=a.current)==null||o.focus())},[t]);const u=(()=>{if(!bd(e.locator))return null;if(e.probeState==="probing")return s.jsx("span",{className:"capture-quality-probing","aria-label":"Checking available qualities",children:"…"});if(e.probeState==="done"){const o=e.probeQualities??[],c=e.probeHasAudio??!1;return o.length===0&&!c?s.jsx("span",{className:"capture-quality-hint",children:"No media detected"}):o.length===0&&c?s.jsx("select",{className:"capture-quality",value:"audio",onChange:g=>r(g.target.value),"aria-label":"Video quality",children:s.jsx("option",{value:"audio",children:"Audio only"})}):s.jsxs("select",{className:"capture-quality",value:e.quality||"best",onChange:g=>r(g.target.value),"aria-label":"Video quality",children:[s.jsx("option",{value:"best",children:"Best quality"}),o.map(g=>s.jsx("option",{value:g,children:g},g)),c&&s.jsx("option",{value:"audio",children:"Audio only"})]})}return null})();return s.jsxs("div",{className:"capture-row",children:[s.jsxs("div",{className:"capture-row-main",children:[s.jsx("input",{ref:a,className:"capture-input",type:"text",placeholder:"https://… · yt:ID · ytm:ID · tweet:ID · x:ID",value:e.locator,onChange:o=>n(o.target.value),onKeyDown:o=>{o.key==="Enter"&&i()},autoComplete:"off",spellCheck:!1}),u,s.jsx("button",{type:"button",className:"capture-row-action capture-row-remove",onClick:l,"aria-label":"Remove",children:s.jsxs("svg",{viewBox:"0 0 16 16",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",children:[s.jsx("line",{x1:"3",y1:"3",x2:"13",y2:"13"}),s.jsx("line",{x1:"13",y1:"3",x2:"3",y2:"13"})]})})]}),e.error&&s.jsx("p",{className:"capture-row-error",children:e.error})]})}function cm(){return s.jsxs("div",{className:"skeleton-row",children:[s.jsx("div",{className:"col-check","aria-hidden":"true"}),s.jsx("div",{className:"col-added",children:s.jsx("span",{className:"skeleton-cell",style:{width:108,height:13}})}),s.jsxs("div",{className:"col-title",style:{gap:"0.42em",display:"flex",alignItems:"center"},children:[s.jsx("span",{className:"skeleton-cell",style:{width:14,height:14,borderRadius:"50%",flexShrink:0}}),s.jsx("span",{className:"skeleton-cell",style:{width:"58%",height:13}})]}),s.jsx("div",{className:"col-type",children:s.jsx("span",{className:"skeleton-cell",style:{width:58,height:20,borderRadius:99}})}),s.jsx("div",{className:"col-size",children:s.jsx("span",{className:"skeleton-cell",style:{width:44,height:12}})}),s.jsx("div",{className:"col-url",children:s.jsx("span",{className:"skeleton-cell",style:{width:"65%",height:12}})})]})}function Zl(e){if(!e)return"0 B";const t=["B","KB","MB","GB"];let n=e,r=0;for(;n>=1024&&r").replace(/"/g,'"').replace(/'/g,"'").replace(/'/g,"'")}function on(e){return dm(e)??""}function Ld(e){if(!e)return"";const t=new Date(e);if(isNaN(t))return e;const n=r=>String(r).padStart(2,"0");return`${t.getUTCFullYear()}-${n(t.getUTCMonth()+1)}-${n(t.getUTCDate())} ${n(t.getUTCHours())}:${n(t.getUTCMinutes())}`}const iu={youtube:'',youtube_music:'',spotify:'',x:'',instagram:'',facebook:'',tiktok:'',reddit:'',snapchat:'',local:'',web:'',other:'?'};function Va(e){return iu[e]??iu.other}function zd(e){return e.split("/").map(t=>t?t.split("-").map(n=>n.charAt(0).toUpperCase()+n.slice(1)).join(" "):"").join("/")}function fm({entry:e,archiveId:t,isSelected:n,isMultiSelected:r,onRowClick:l}){const[i,a]=f.useState(!1),o=e.source_kind==="web"&&e.entity_kind==="page"&&e.has_favicon&&t&&!i?s.jsx("img",{src:`/api/archives/${t}/entries/${e.entry_uid}/favicon`,width:"16",height:"16",alt:"",onError:()=>a(!0),style:{objectFit:"contain"}}):s.jsx("span",{dangerouslySetInnerHTML:{__html:Va(e.source_kind)}}),c=n||r;function g(h){h.stopPropagation(),l(e,{ctrlKey:!0,metaKey:!1,shiftKey:!1,preventDefault(){}})}return s.jsxs("div",{className:[n&&"is-selected",r&&"is-multi-selected"].filter(Boolean).join(" ")||void 0,tabIndex:0,"data-entry-uid":e.entry_uid,onMouseDown:h=>{h.shiftKey&&h.preventDefault()},onClick:h=>l(e,h),onKeyDown:h=>{h.key==="Enter"&&l(e,h)},children:[s.jsx("div",{className:"col-check",children:s.jsx("button",{type:"button",className:`row-checkbox${c?" is-checked":""}`,"aria-pressed":c,"aria-label":c?"Deselect entry":"Select entry",onClick:g,onKeyDown:h=>h.stopPropagation()})}),s.jsx("div",{className:"col-added",children:Ld(e.archived_at)}),s.jsxs("div",{className:"col-title",children:[s.jsx("span",{className:"source-icon",children:o}),s.jsx("span",{className:"entry-title",children:on(e.title)||on(e.entry_uid)})]}),s.jsx("div",{className:"col-type",children:s.jsx("span",{className:"type-pill",children:on(e.entity_kind)})}),s.jsxs("div",{className:"col-size",children:[s.jsx("span",{className:"size-total",children:Zl(e.total_artifact_bytes)}),e.cached_bytes>0&&e.total_artifact_bytes>0&&s.jsxs("span",{className:"size-cached-pct",title:`${Zl(e.cached_bytes)} already on disk from an earlier entry`,children:[Math.round(e.cached_bytes/e.total_artifact_bytes*100),"% cached"]})]}),s.jsx("div",{className:"url-cell col-url",children:on(e.original_url)})]})}function pm({entries:e,selectedUids:t,onRowClick:n,archiveId:r,pendingCaptures:l=[]}){return s.jsx("section",{id:"archive-view",className:"view is-active",children:s.jsxs("div",{className:"entry-table",children:[s.jsxs("div",{className:"entry-header-row",children:[s.jsx("div",{className:"col-check","aria-hidden":"true"}),s.jsx("div",{className:"col-added",children:"Added"}),s.jsx("div",{className:"col-title",children:"Title"}),s.jsx("div",{className:"col-type",children:"Type"}),s.jsx("div",{className:"col-size",children:"Size"}),s.jsx("div",{className:"col-url",children:"Original URL"})]}),s.jsxs("div",{id:"entries-body",children:[l.filter(i=>i.archiveId===r).reverse().map(i=>s.jsx(cm,{},i.id)),e.map(i=>s.jsx(fm,{entry:i,archiveId:r,isSelected:t.size===1&&t.has(i.entry_uid),isMultiSelected:t.size>=2&&t.has(i.entry_uid),onRowClick:n},i.entry_uid))]})]})})}function hm(e){if(!e)return"—";try{return new Date(e).toLocaleString(void 0,{year:"numeric",month:"short",day:"numeric",hour:"2-digit",minute:"2-digit"})}catch{return e}}function mm({status:e}){const t=e==="completed"?"run-status--completed":e==="failed"?"run-status--failed":e==="in_progress"?"run-status--in-progress":"",n=e?e.replace(/_/g," "):"—";return s.jsx("span",{className:`run-status ${t}`,children:n})}function gm({runs:e}){const[t,n]=f.useState(null);function r(l){n(i=>i===l?null:l)}return s.jsx("section",{id:"runs-view",className:"view is-active",children:s.jsxs("table",{className:"entry-table",children:[s.jsx("thead",{children:s.jsxs("tr",{children:[s.jsx("th",{children:"Started"}),s.jsx("th",{children:"Status"}),s.jsx("th",{children:"Requested"}),s.jsx("th",{children:"Completed"}),s.jsx("th",{children:"Failed"})]})}),s.jsx("tbody",{children:e.length===0?s.jsx("tr",{children:s.jsx("td",{colSpan:5,style:{color:"var(--muted)",padding:"24px 16px",textAlign:"center"},children:"No runs yet."})}):e.map(l=>{const i=l.status==="failed"&&l.error_summary,a=t===l.run_uid;return[s.jsxs("tr",{className:i?"run-row run-row--failed":"run-row",onClick:i?()=>r(l.run_uid):void 0,title:i?a?"Click to hide error":"Click to view error":void 0,children:[s.jsx("td",{children:hm(l.started_at)}),s.jsxs("td",{children:[s.jsx(mm,{status:l.status}),i&&s.jsx("span",{className:"run-expand-hint","aria-hidden":"true",children:a?"▴":"▾"})]}),s.jsx("td",{children:l.requested_count??"—"}),s.jsx("td",{children:l.completed_count??"—"}),s.jsx("td",{children:l.failed_count??"—"})]},l.run_uid),i&&a&&s.jsx("tr",{className:"run-error-row",children:s.jsx("td",{colSpan:5,children:s.jsx("pre",{className:"run-error-detail",children:l.error_summary})})},`${l.run_uid}-detail`)]})})]})})}const vm=4;function ym({archives:e}){const{currentUser:t}=f.useContext(vs)??{},n=t&&(t.role_bits&vm)!==0,[r,l]=f.useState("users"),[i,a]=f.useState([]),[u,o]=f.useState([]),[c,g]=f.useState(!1),[h,m]=f.useState(null),[y,w]=f.useState(""),[k,j]=f.useState(""),[p,d]=f.useState(""),[v,x]=f.useState(null),[_,b]=f.useState(!1),[C,S]=f.useState(""),[D,L]=f.useState(""),[H,M]=f.useState(null),[W,Y]=f.useState(!1),ce=f.useCallback(async()=>{if(n){g(!0),m(null);try{const[T,F]=await Promise.all([Ah(),Hh()]);a(T),o(F)}catch(T){m(T.message)}finally{g(!1)}}},[n]);f.useEffect(()=>{ce()},[ce]);async function ie(T){const F=T.status==="active"?"disabled":"active";try{await Uh(T.user_uid,F),a(q=>q.map(A=>A.user_uid===T.user_uid?{...A,status:F}:A))}catch(q){m(q.message)}}async function ee(T){if(T.preventDefault(),!y.trim()||!k){x("Username and password required");return}b(!0),x(null);try{await Bh(y.trim(),k,p.trim()||void 0),w(""),j(""),d(""),await ce()}catch(F){x(F.message)}finally{b(!1)}}async function R(T){if(T.preventDefault(),!C.trim()||!D.trim()){M("Slug and name required");return}Y(!0),M(null);try{await Wh(C.trim(),D.trim()),S(""),L(""),await ce()}catch(F){M(F.message)}finally{Y(!1)}}return n?s.jsxs("section",{id:"admin-view",className:"view admin-view is-active",children:[s.jsx("h1",{children:"Admin"}),s.jsxs("div",{className:"view-tabs",children:[s.jsx("button",{className:`view-tab${r==="users"?" is-active":""}`,onClick:()=>l("users"),children:"Users"}),s.jsx("button",{className:`view-tab${r==="roles"?" is-active":""}`,onClick:()=>l("roles"),children:"Roles"}),s.jsx("button",{className:`view-tab${r==="archives"?" is-active":""}`,onClick:()=>l("archives"),children:"Archives"})]}),h&&s.jsx("div",{className:"form-msg form-msg--err",children:h}),r==="users"&&s.jsxs("div",{className:"admin-section",children:[s.jsx("h2",{children:"Users"}),c?s.jsx("p",{className:"muted",children:"Loading…"}):s.jsxs("table",{className:"admin-table",children:[s.jsx("thead",{children:s.jsxs("tr",{children:[s.jsx("th",{children:"Username"}),s.jsx("th",{children:"Email"}),s.jsx("th",{children:"Roles"}),s.jsx("th",{children:"Status"}),s.jsx("th",{children:"Actions"})]})}),s.jsx("tbody",{children:i.map(T=>s.jsxs("tr",{className:T.status==="disabled"?"admin-row-disabled":"",children:[s.jsx("td",{children:T.username}),s.jsx("td",{className:"muted",children:T.email||"—"}),s.jsx("td",{children:T.role_slugs.join(", ")||"—"}),s.jsx("td",{children:s.jsx("span",{className:`status-badge status-${T.status}`,children:T.status})}),s.jsx("td",{children:s.jsx("button",{className:"admin-action-btn",onClick:()=>ie(T),children:T.status==="active"?"Ban":"Unban"})})]},T.user_uid))})]}),s.jsx("h3",{children:"Create User"}),s.jsxs("form",{className:"admin-form",onSubmit:ee,children:[s.jsx("input",{className:"admin-input",placeholder:"Username",value:y,onChange:T=>w(T.target.value),required:!0}),s.jsx("input",{className:"admin-input",type:"password",placeholder:"Password (min 8 chars)",value:k,onChange:T=>j(T.target.value),required:!0}),s.jsx("input",{className:"admin-input",type:"email",placeholder:"Email (optional)",value:p,onChange:T=>d(T.target.value)}),v&&s.jsx("div",{className:"form-msg form-msg--err",children:v}),s.jsx("button",{className:"btn-primary",type:"submit",disabled:_,children:_?"Creating…":"Create User"})]})]}),r==="roles"&&s.jsxs("div",{className:"admin-section",children:[s.jsx("h2",{children:"Roles"}),c?s.jsx("p",{className:"muted",children:"Loading…"}):s.jsxs("table",{className:"admin-table",children:[s.jsx("thead",{children:s.jsxs("tr",{children:[s.jsx("th",{children:"Slug"}),s.jsx("th",{children:"Name"}),s.jsx("th",{children:"Level"}),s.jsx("th",{children:"Bit"}),s.jsx("th",{children:"Built-in"})]})}),s.jsx("tbody",{children:u.map(T=>s.jsxs("tr",{children:[s.jsx("td",{children:s.jsx("code",{children:T.slug})}),s.jsx("td",{children:T.name}),s.jsx("td",{children:T.level}),s.jsx("td",{children:T.bit_position}),s.jsx("td",{children:T.is_builtin?"✓":""})]},T.role_uid))})]}),s.jsx("h3",{children:"Create Custom Role"}),s.jsxs("form",{className:"admin-form",onSubmit:R,children:[s.jsx("input",{className:"admin-input",placeholder:"Slug (e.g. moderator)",value:C,onChange:T=>S(T.target.value),required:!0}),s.jsx("input",{className:"admin-input",placeholder:"Display Name (e.g. Moderator)",value:D,onChange:T=>L(T.target.value),required:!0}),H&&s.jsx("div",{className:"form-msg form-msg--err",children:H}),s.jsx("button",{className:"btn-primary",type:"submit",disabled:W,children:W?"Creating…":"Create Role"})]})]}),r==="archives"&&s.jsxs("div",{className:"admin-section",children:[s.jsx("h2",{children:"Mounted Archives"}),s.jsx("div",{className:"admin-list",children:e.map(T=>s.jsxs("div",{className:"admin-archive",children:[s.jsx("strong",{children:T.label}),s.jsx("div",{className:"muted",children:T.archive_path})]},T.id))})]})]}):s.jsxs("section",{id:"admin-view",className:"view admin-view is-active",children:[s.jsx("h1",{children:"Admin"}),s.jsx("p",{className:"muted",children:"You need admin privileges to access this panel."}),s.jsx("h2",{children:"Mounted Archives"}),s.jsx("div",{className:"admin-list",children:e.map(T=>s.jsxs("div",{className:"admin-archive",children:[s.jsx("strong",{children:T.label}),s.jsx("div",{className:"muted",children:T.archive_path})]},T.id))})]})}function Rd({node:e,onPick:t}){var n;return s.jsxs("li",{children:[s.jsx("button",{className:"tag-picker-node-btn",title:e.tag.full_path,onClick:()=>t(e.tag),children:e.tag.slug}),((n=e.children)==null?void 0:n.length)>0&&s.jsx("div",{className:"tag-children",children:s.jsx("ul",{className:"tag-tree-list",children:e.children.map(r=>s.jsx(Rd,{node:r,onPick:t},r.tag.tag_uid))})})]})}function au({title:e,tagNodes:t,excludeUid:n,onPick:r,onCancel:l}){f.useEffect(()=>{function u(o){o.key==="Escape"&&(o.preventDefault(),o.stopPropagation(),l())}return document.addEventListener("keydown",u),()=>document.removeEventListener("keydown",u)},[l]);function i(u){return u.filter(o=>o.tag.tag_uid!==n).map(o=>({...o,children:i(o.children)}))}const a=n?i(t):t;return s.jsx("div",{className:"tag-picker-backdrop",onClick:u=>{u.target===u.currentTarget&&l()},children:s.jsxs("div",{className:"tag-picker-modal",role:"dialog","aria-modal":"true",children:[s.jsxs("div",{className:"tag-picker-header",children:[s.jsx("span",{className:"tag-picker-title",children:e}),s.jsx("button",{className:"tag-picker-close",onClick:l,title:"Cancel","aria-label":"Cancel",children:"×"})]}),s.jsxs("div",{className:"tag-picker-body",children:[s.jsx("button",{className:"tag-picker-root-btn",onClick:()=>r(null),title:"Place at root level (no parent)",children:"↑ Root tag (no parent)"}),a.length>0?s.jsx("ul",{className:"tag-tree-list tag-picker-tree",children:a.map(u=>s.jsx(Rd,{node:u,onPick:r},u.tag.tag_uid))}):s.jsx("p",{className:"tag-picker-empty",children:"No other tags available."})]})]})})}function Dd({parentPath:e,archiveId:t,onDone:n,onCancel:r}){const[l,i]=f.useState(""),a=f.useRef(!1);async function u(){const o=l.trim();if(!o){r();return}const c=e?`${e}/${o}`:`/${o}`;try{await _h(t,c),n()}catch(g){alert(g.message||"Create failed"),r()}}return s.jsx("input",{className:"tag-rename-input",autoFocus:!0,placeholder:"tag name",value:l,onChange:o=>i(o.target.value),onKeyDown:o=>{o.key==="Enter"&&o.currentTarget.blur(),o.key==="Escape"&&(a.current=!0,o.currentTarget.blur())},onBlur:()=>{a.current?(a.current=!1,r()):u()}})}function $d({node:e,archiveId:t,tagFilter:n,onTagFilterSet:r,onViewChange:l,onTagRenamed:i,onTagDeleted:a,onTagsRefresh:u,humanizeTags:o,moveSelectMode:c,onMoveSourceSelect:g,pendingCreateParentUid:h,onCreateDone:m,onCreateCancel:y}){var H;const w=n===e.tag.full_path,[k,j]=f.useState(!1),[p,d]=f.useState(""),v=f.useRef(!1);function x(){if(k)return;if(c){g(e);return}const M=w?null:e.tag.full_path;r(M),l("archive")}function _(M){M.stopPropagation(),!c&&(d(e.tag.slug),j(!0))}async function b(){const M=p.trim();if(!M||M===e.tag.slug){j(!1);return}try{const W=await Sh(t,e.tag.tag_uid,M);i(e.tag.full_path,W.full_path),u()}catch{}finally{j(!1)}}async function C(M){var Y;M.stopPropagation();const W=((Y=e.children)==null?void 0:Y.length)>0?`Delete tag "${e.tag.full_path}" and all its child tags? This cannot be undone.`:`Delete tag "${e.tag.full_path}"? This cannot be undone.`;if(window.confirm(W))try{await Nh(t,e.tag.tag_uid),a(e.tag.full_path),u()}catch{}}const S={archiveId:t,tagFilter:n,onTagFilterSet:r,onViewChange:l,onTagRenamed:i,onTagDeleted:a,onTagsRefresh:u,humanizeTags:o,moveSelectMode:c,onMoveSourceSelect:g,pendingCreateParentUid:h,onCreateDone:m,onCreateCancel:y},D=h===e.tag.tag_uid,L=((H=e.children)==null?void 0:H.length)>0;return s.jsxs("li",{children:[s.jsxs("div",{className:`tag-node-row${c?" tag-node-row--move-select":""}`,children:[k?s.jsx("input",{className:"tag-rename-input",autoFocus:!0,value:p,onChange:M=>d(M.target.value),onKeyDown:M=>{M.key==="Enter"&&M.currentTarget.blur(),M.key==="Escape"&&(v.current=!0,M.currentTarget.blur())},onBlur:()=>{v.current?(v.current=!1,j(!1)):b()}}):s.jsxs("button",{className:`tag-node-btn${w?" is-active":""}${c?" tag-node-btn--move-select":""}`,title:c?`Select "${e.tag.full_path}" to move`:e.tag.full_path,onClick:x,onDoubleClick:c?void 0:_,children:[s.jsx("span",{className:"tag-node-label",children:o?e.tag.name:e.tag.slug}),s.jsx("span",{className:"tag-node-count",children:e.children.length===0?`(${e.entry_count})`:`(${e.entry_count}) (${e.subtree_count} Total)`}),!c&&s.jsx("svg",{className:"edit-icon",viewBox:"0 0 16 16",fill:"none",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round",strokeLinejoin:"round","aria-hidden":"true",title:"Rename tag",onClick:M=>{M.stopPropagation(),_(M)},children:s.jsx("path",{d:"M11.5 2.5a1.5 1.5 0 0 1 2 2L5 13l-3 1 1-3 8.5-8.5z"})})]}),!k&&!c&&s.jsx("button",{className:"remove tag-node-delete",title:`Delete "${e.tag.full_path}"`,onClick:C,"aria-label":`Delete "${e.tag.full_path}"`,children:"×"})]}),(L||D)&&s.jsx("div",{className:"tag-children",children:s.jsxs("ul",{className:"tag-tree-list",children:[e.children.map(M=>s.jsx($d,{node:M,...S},M.tag.tag_uid)),D&&s.jsx("li",{children:s.jsx(Dd,{parentPath:e.tag.full_path,archiveId:t,onDone:m,onCancel:y})})]})})]})}function xm({archiveId:e,tagNodes:t,tagFilter:n,onTagFilterSet:r,onViewChange:l,onTagRenamed:i,onTagDeleted:a,onTagsRefresh:u,humanizeTags:o}){const[c,g]=f.useState(null),[h,m]=f.useState(null);function y(){g("select-source"),m(null)}function w(){g(null),m(null)}f.useEffect(()=>{if(c!=="select-source")return;function W(Y){Y.key==="Escape"&&(Y.preventDefault(),Y.stopPropagation(),w())}return document.addEventListener("keydown",W),()=>document.removeEventListener("keydown",W)},[c]);function k(W){m(W),g("select-dest")}async function j(W){const Y=h.tag.full_path,ce=h.tag.tag_uid,ie=(W==null?void 0:W.tag_uid)??null;w();try{const ee=await Ch(e,ce,ie);i(Y,ee.full_path),u()}catch(ee){alert(ee.message||"Move failed")}}const[p,d]=f.useState(null),[v,x]=f.useState(void 0);function _(){d("select-parent"),x(void 0)}function b(){d(null),x(void 0)}function C(W){x(W??null),d("input")}function S(){d(null),x(void 0),u()}const D=c==="select-source",L=p==="input"?v?v.tag_uid:"__root__":void 0,H={archiveId:e,tagFilter:n,onTagFilterSet:r,onViewChange:l,onTagRenamed:i,onTagDeleted:a,onTagsRefresh:u,humanizeTags:o,moveSelectMode:D,onMoveSourceSelect:k,pendingCreateParentUid:L,onCreateDone:S,onCreateCancel:b},M=L==="__root__";return s.jsxs("section",{id:"tags-view",className:"view is-active",children:[s.jsxs("div",{className:"tag-tree",children:[s.jsx("div",{className:"tag-tree-header",children:D?s.jsxs(s.Fragment,{children:[s.jsx("span",{className:"tag-tree-title tag-tree-title--move",children:"Select a tag to move"}),s.jsx("button",{className:"tag-tree-action-btn tag-tree-action-btn--cancel",onClick:w,children:"Cancel"})]}):s.jsxs(s.Fragment,{children:[s.jsx("span",{className:"tag-tree-title",children:"Tags"}),n&&s.jsxs("span",{className:"tag-tree-active",title:n,children:["Filtering: ",n]}),s.jsxs("div",{className:"tag-tree-actions",children:[s.jsx("button",{className:"tag-tree-action-btn",onClick:_,title:"Create a new tag",disabled:!!p||!!c,children:"+ New"}),s.jsx("button",{className:"tag-tree-action-btn",onClick:y,title:"Move a tag to a different parent",disabled:!!p||!!c||t.length===0,children:"Move"})]})]})}),t.length===0&&!M?s.jsx("p",{className:"muted",style:{padding:"8px 0"},children:"No tags yet."}):s.jsxs("ul",{className:"tag-tree-list",children:[t.map(W=>s.jsx($d,{node:W,...H},W.tag.tag_uid)),M&&s.jsx("li",{children:s.jsx(Dd,{parentPath:null,archiveId:e,onDone:S,onCancel:b})})]})]}),p==="select-parent"&&s.jsx(au,{title:"Create tag under…",tagNodes:t,excludeUid:null,onPick:C,onCancel:b}),c==="select-dest"&&h&&s.jsx(au,{title:`Move "${h.tag.slug}" under…`,tagNodes:t,excludeUid:h.tag.tag_uid,onPick:j,onCancel:w})]})}const mr=[{value:0,label:"Private"},{value:2,label:"Users only"},{value:3,label:"Public"}],wm=e=>{var t;return((t=mr.find(n=>n.value===e))==null?void 0:t.label)??String(e)};function km({archiveId:e}){const[t,n]=f.useState([]),[r,l]=f.useState(!1),[i,a]=f.useState(null),[u,o]=f.useState(null),[c,g]=f.useState(null),[h,m]=f.useState(!1),[y,w]=f.useState(null),[k,j]=f.useState(""),[p,d]=f.useState(""),[v,x]=f.useState(2),[_,b]=f.useState(!1),[C,S]=f.useState(null),[D,L]=f.useState(""),[H,M]=f.useState(2),[W,Y]=f.useState(!1),[ce,ie]=f.useState(null),[ee,R]=f.useState(!1),[T,F]=f.useState(""),q=f.useRef(null),A=t.find(P=>P.collection_uid===u)??null,ge=(A==null?void 0:A.slug)==="_default_",de=f.useCallback(async()=>{if(e){l(!0),a(null);try{const P=await Td(e);n(P)}catch(P){a(P.message)}finally{l(!1)}}},[e]),Re=f.useCallback(async P=>{if(!P){g(null);return}m(!0),w(null);try{const B=await Qh(e,P);g(B)}catch(B){w(B.message)}finally{m(!1)}},[e]);f.useEffect(()=>{de()},[de]),f.useEffect(()=>{Re(u)},[u,Re]),f.useEffect(()=>{ee&&q.current&&q.current.focus()},[ee]);async function we(P){P.preventDefault();const B=k.trim(),re=p.trim();if(!(!B||!re)){b(!0),S(null);try{const le=await Vh(e,B,re,v);j(""),d(""),x(2),await de(),o(le.collection_uid)}catch(le){S(le.message)}finally{b(!1)}}}async function je(){const P=T.trim();if(!P||!A){R(!1);return}try{await su(e,A.collection_uid,{name:P}),await de(),g(B=>B&&{...B,name:P})}catch(B){a(B.message)}finally{R(!1)}}async function E(P){if(A)try{await su(e,A.collection_uid,{default_visibility_bits:P}),await de(),g(B=>B&&{...B,default_visibility_bits:P})}catch(B){a(B.message)}}async function U(){if(A&&window.confirm(`Delete collection "${A.name}"? Entries will not be deleted.`))try{await qh(e,A.collection_uid),o(null),g(null),await de()}catch(P){a(P.message)}}async function K(P){P.preventDefault();const B=D.trim();if(!(!B||!A)){Y(!0),ie(null);try{await Pd(e,A.collection_uid,B,H),L(""),await Re(A.collection_uid)}catch(re){ie(re.message)}finally{Y(!1)}}}async function V(P){if(A)try{await Kh(e,A.collection_uid,P),await Re(A.collection_uid)}catch(B){w(B.message)}}async function X(P,B){if(A)try{await Xh(e,A.collection_uid,P,B),g(re=>re&&{...re,entries:re.entries.map(le=>le.entry_uid===P?{...le,collection_visibility_bits:B}:le)})}catch(re){w(re.message)}}return e?s.jsxs("div",{className:"collections-view",children:[s.jsx("h2",{className:"collections-heading",children:"Collections"}),r&&s.jsx("div",{className:"muted",children:"Loading…"}),i&&s.jsxs("div",{className:"collections-error",children:[i," ",s.jsx("button",{onClick:()=>a(null),className:"coll-dismiss",children:"×"})]}),s.jsxs("div",{className:"collections-layout",children:[s.jsxs("div",{className:"collections-sidebar",children:[t.map(P=>s.jsxs("button",{className:`coll-sidebar-row${u===P.collection_uid?" is-active":""}`,onClick:()=>o(P.collection_uid),children:[s.jsx("span",{className:"coll-row-name",children:P.name}),s.jsx("span",{className:"coll-row-meta",children:wm(P.default_visibility_bits)})]},P.collection_uid)),t.length===0&&!r&&s.jsx("div",{className:"muted",style:{padding:"8px 12px"},children:"No collections yet."})]}),A?s.jsxs("div",{className:"coll-detail",children:[s.jsxs("div",{className:"coll-detail-header",children:[ee?s.jsx("input",{ref:q,className:"coll-rename-input",value:T,onChange:P=>F(P.target.value),onBlur:je,onKeyDown:P=>{P.key==="Enter"&&je(),P.key==="Escape"&&R(!1)}}):s.jsxs("h3",{className:`coll-detail-name${ge?"":" coll-detail-name--editable"}`,title:ge?void 0:"Click to rename",onClick:()=>{ge||(F(A.name),R(!0))},children:[(c==null?void 0:c.name)??A.name,!ge&&s.jsx("span",{className:"coll-edit-hint",children:" ✎"})]}),!ge&&s.jsx("button",{className:"coll-delete-btn",onClick:U,title:"Delete collection",children:"Delete"})]}),s.jsxs("div",{className:"coll-detail-vis",children:[s.jsx("span",{className:"coll-vis-label",children:"Default visibility"}),s.jsx("select",{className:"coll-vis-select",value:(c==null?void 0:c.default_visibility_bits)??A.default_visibility_bits,onChange:P=>E(Number(P.target.value)),disabled:ge,children:mr.map(P=>s.jsx("option",{value:P.value,children:P.label},P.value))})]}),s.jsxs("div",{className:"coll-entries-section",children:[s.jsx("div",{className:"coll-section-heading",children:"Entries"}),h&&s.jsx("div",{className:"muted",children:"Loading…"}),y&&s.jsx("div",{className:"collections-error",children:y}),!h&&c&&(c.entries.length===0?s.jsx("div",{className:"muted",children:"No entries in this collection."}):s.jsx("ul",{className:"coll-entries-list",children:c.entries.map(P=>s.jsxs("li",{className:"coll-entry-row",children:[s.jsxs("div",{className:"coll-entry-info",children:[s.jsx("span",{className:"coll-entry-title",children:P.title||P.entry_uid}),s.jsx("span",{className:"coll-entry-kind muted",children:P.source_kind})]}),s.jsxs("div",{className:"coll-entry-actions",children:[s.jsx("select",{className:"coll-entry-vis-select",value:P.collection_visibility_bits,onChange:B=>X(P.entry_uid,Number(B.target.value)),children:mr.map(B=>s.jsx("option",{value:B.value,children:B.label},B.value))}),!ge&&s.jsx("button",{className:"coll-entry-remove",onClick:()=>V(P.entry_uid),title:"Remove from collection",children:"×"})]})]},P.entry_uid))}))]}),!ge&&s.jsxs("form",{className:"coll-add-entry-form",onSubmit:K,children:[s.jsx("div",{className:"coll-section-heading",children:"Add entry"}),s.jsxs("div",{className:"coll-add-entry-row",children:[s.jsx("input",{className:"coll-add-entry-input",type:"text",value:D,onChange:P=>L(P.target.value),placeholder:"entry_uid",required:!0}),s.jsx("select",{className:"coll-vis-select",value:H,onChange:P=>M(Number(P.target.value)),children:mr.map(P=>s.jsx("option",{value:P.value,children:P.label},P.value))}),s.jsx("button",{className:"coll-add-btn",type:"submit",disabled:W,children:W?"…":"Add"})]}),ce&&s.jsx("div",{className:"collections-error",style:{marginTop:4},children:ce})]})]}):s.jsx("div",{className:"coll-detail coll-detail--empty",children:s.jsx("div",{className:"muted",children:"Select a collection to view details."})})]}),s.jsxs("details",{className:"coll-create-details",children:[s.jsx("summary",{children:"+ Create collection"}),s.jsxs("form",{className:"coll-create-form",onSubmit:we,children:[s.jsxs("div",{className:"form-field",children:[s.jsx("label",{className:"form-label",htmlFor:"coll-name",children:"Name"}),s.jsx("input",{className:"capture-input",id:"coll-name",type:"text",value:k,onChange:P=>{j(P.target.value),p||d(P.target.value.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-|-$/g,""))},placeholder:"My Collection",required:!0})]}),s.jsxs("div",{className:"form-field",children:[s.jsx("label",{className:"form-label",htmlFor:"coll-slug",children:"Slug"}),s.jsx("input",{className:"capture-input",id:"coll-slug",type:"text",value:p,onChange:P=>d(P.target.value),placeholder:"my-collection",required:!0})]}),s.jsxs("div",{className:"form-field",children:[s.jsx("label",{className:"form-label",htmlFor:"coll-vis",children:"Default visibility"}),s.jsx("select",{className:"capture-input",id:"coll-vis",style:{height:42},value:v,onChange:P=>x(Number(P.target.value)),children:mr.map(P=>s.jsx("option",{value:P.value,children:P.label},P.value))})]}),C&&s.jsx("div",{className:"collections-error",children:C}),s.jsx("button",{className:"btn-primary",type:"submit",disabled:_,children:_?"Creating…":"Create collection"})]})]})]}):s.jsx("div",{className:"view-placeholder",children:"Select an archive."})}const jm=4;function Sm({tab:e,onTabChange:t,archiveId:n}){const{currentUser:r,setCurrentUser:l}=f.useContext(vs)??{},i=r&&(r.role_bits&jm)!==0,a=["profile","tokens",...i?["instance","cookies","extensions","storage"]:[]],u={profile:"Profile",tokens:"API Tokens",instance:"Instance",cookies:"Cookies",extensions:"Extensions",storage:"Storage"};return s.jsxs("section",{className:"admin-view",children:[s.jsx("h1",{children:"Settings"}),s.jsx("div",{className:"view-tabs",children:a.map(o=>s.jsx("button",{className:`view-tab${e===o?" is-active":""}`,onClick:()=>t(o),children:u[o]},o))}),e==="profile"&&s.jsx(Nm,{currentUser:r,setCurrentUser:l}),e==="tokens"&&s.jsx(_m,{}),e==="instance"&&i&&s.jsx(Cm,{}),e==="cookies"&&i&&s.jsx(Tm,{}),e==="extensions"&&i&&s.jsx(Pm,{}),e==="storage"&&i&&s.jsx(Em,{archiveId:n})]})}function Nm({currentUser:e,setCurrentUser:t}){const[n,r]=f.useState((e==null?void 0:e.display_name)??""),[l,i]=f.useState(!1),[a,u]=f.useState(null),[o,c]=f.useState(""),[g,h]=f.useState(""),[m,y]=f.useState(""),[w,k]=f.useState(!1),[j,p]=f.useState(null);async function d(x){x.preventDefault(),i(!0),u(null);try{await Dh(n),t(_=>({..._,display_name:n||null})),u({ok:!0,text:"Saved."})}catch(_){u({ok:!1,text:_.message})}finally{i(!1)}}async function v(x){if(x.preventDefault(),g!==m){p({ok:!1,text:"Passwords do not match."});return}k(!0),p(null);try{await Ih(o,g),c(""),h(""),y(""),p({ok:!0,text:"Password changed."})}catch(_){p({ok:!1,text:_.message})}finally{k(!1)}}return s.jsxs("div",{style:{maxWidth:440},children:[s.jsxs("div",{className:"form-section",children:[s.jsx("h2",{children:"Display Name"}),s.jsxs("form",{onSubmit:d,children:[s.jsxs("div",{className:"form-field",children:[s.jsx("label",{className:"form-label",htmlFor:"display-name",children:"Name shown in the UI"}),s.jsx("input",{className:"field-input",id:"display-name",placeholder:(e==null?void 0:e.username)??"",value:n,onChange:x=>r(x.target.value)})]}),a&&s.jsx("div",{className:`form-msg form-msg--${a.ok?"ok":"err"}`,children:a.text}),s.jsx("button",{className:"btn-primary",type:"submit",disabled:l,children:l?"Saving…":"Save"})]})]}),s.jsxs("div",{className:"form-section",children:[s.jsx("h2",{children:"Display Preferences"}),s.jsxs("label",{className:"checkbox-row",children:[s.jsx("input",{type:"checkbox",checked:(e==null?void 0:e.humanize_slugs)??!1,onChange:async x=>{const _=x.target.checked;try{await $h({humanize_slugs:_}),t(b=>({...b,humanize_slugs:_}))}catch{}}}),s.jsx("span",{className:"form-label",style:{margin:0},children:"Humanize tag display"})]}),s.jsx("p",{className:"muted",style:{fontSize:13,margin:"4px 0 0"},children:'When on, tag paths show as "X / Articles" instead of "x/articles".'})]}),s.jsxs("div",{className:"form-section",children:[s.jsx("h2",{children:"Change Password"}),s.jsxs("form",{onSubmit:v,children:[s.jsxs("div",{className:"form-field",children:[s.jsx("label",{className:"form-label",htmlFor:"cur-pw",children:"Current password"}),s.jsx("input",{className:"field-input",id:"cur-pw",type:"password",value:o,onChange:x=>c(x.target.value),required:!0})]}),s.jsxs("div",{className:"form-field",children:[s.jsx("label",{className:"form-label",htmlFor:"new-pw",children:"New password"}),s.jsx("input",{className:"field-input",id:"new-pw",type:"password",value:g,onChange:x=>h(x.target.value),required:!0})]}),s.jsxs("div",{className:"form-field",children:[s.jsx("label",{className:"form-label",htmlFor:"confirm-pw",children:"Confirm new password"}),s.jsx("input",{className:"field-input",id:"confirm-pw",type:"password",value:m,onChange:x=>y(x.target.value),required:!0})]}),j&&s.jsx("div",{className:`form-msg form-msg--${j.ok?"ok":"err"}`,children:j.text}),s.jsx("button",{className:"btn-primary",type:"submit",disabled:w,children:w?"Changing…":"Change Password"})]})]})]})}function _m(){const[e,t]=f.useState([]),[n,r]=f.useState(!0),[l,i]=f.useState(null),[a,u]=f.useState(""),[o,c]=f.useState(!1),[g,h]=f.useState(null),m=f.useCallback(async()=>{r(!0),i(null);try{t(await Oh())}catch(k){i(k.message)}finally{r(!1)}},[]);f.useEffect(()=>{m()},[m]);async function y(k){if(k.preventDefault(),!!a.trim()){c(!0);try{const j=await Fh(a.trim());h(j),u(""),m()}catch(j){i(j.message)}finally{c(!1)}}}async function w(k){try{await Mh(k),t(j=>j.filter(p=>p.token_uid!==k))}catch(j){i(j.message)}}return s.jsx("div",{style:{maxWidth:600},children:s.jsxs("div",{className:"form-section",children:[s.jsx("h2",{children:"API Tokens"}),g&&s.jsxs("div",{className:"token-banner",children:[s.jsx("strong",{children:"Token created."})," Copy it now — it won't be shown again.",s.jsx("code",{children:g.raw_token}),s.jsx("button",{className:"token-dismiss",onClick:()=>h(null),children:"Dismiss"})]}),s.jsxs("form",{className:"token-create-row",onSubmit:y,children:[s.jsx("input",{className:"field-input field-input--flex",placeholder:"Token name",value:a,onChange:k=>u(k.target.value),required:!0}),s.jsx("button",{className:"btn-primary",type:"submit",disabled:o,children:o?"Creating…":"Create token"})]}),l&&s.jsx("div",{className:"form-msg form-msg--err",children:l}),n?s.jsx("div",{className:"muted",children:"Loading…"}):s.jsxs("div",{children:[e.length===0&&s.jsx("div",{className:"muted",children:"No tokens yet."}),e.map(k=>s.jsxs("div",{className:"token-row",children:[s.jsxs("div",{className:"token-row-info",children:[s.jsx("strong",{children:k.name}),s.jsxs("div",{className:"muted",children:["Created ",k.created_at.slice(0,10),k.last_used_at&&` · Last used ${k.last_used_at.slice(0,10)}`]})]}),s.jsx("button",{className:"btn-danger",style:{fontSize:12,padding:"4px 10px"},onClick:()=>w(k.token_uid),children:"Revoke"})]},k.token_uid))]})]})})}function Cm(){const[e,t]=f.useState(null),[n,r]=f.useState(!0),[l,i]=f.useState(null),[a,u]=f.useState(!1),[o,c]=f.useState(null);f.useEffect(()=>{(async()=>{try{t(await Wa())}catch(h){i(h.message)}finally{r(!1)}})()},[]);async function g(h){h.preventDefault(),u(!0),c(null);try{await Tl(e),c({ok:!0,text:"Saved."})}catch(m){c({ok:!1,text:m.message})}finally{u(!1)}}return n?s.jsx("div",{className:"muted",children:"Loading…"}):l?s.jsx("div",{className:"form-msg form-msg--err",children:l}):e?s.jsx("div",{style:{maxWidth:440},children:s.jsxs("div",{className:"form-section",children:[s.jsx("h2",{children:"Instance Settings"}),s.jsxs("form",{onSubmit:g,children:[[["public_index_enabled","Public index (unauthenticated browsing)"],["public_entry_content_enabled","Public entry content"],["open_registration_enabled","Open registration"]].map(([h,m])=>s.jsxs("label",{className:"checkbox-row",children:[s.jsx("input",{type:"checkbox",checked:!!e[h],onChange:y=>t(w=>({...w,[h]:y.target.checked}))}),m]},h)),s.jsxs("div",{className:"form-field",style:{marginTop:4},children:[s.jsx("label",{className:"form-label",children:"Default entry visibility"}),s.jsxs("select",{className:"field-input",value:e.default_entry_visibility,onChange:h=>t(m=>({...m,default_entry_visibility:Number(h.target.value)})),children:[s.jsx("option",{value:0,children:"Private"}),s.jsx("option",{value:2,children:"Unlisted"}),s.jsx("option",{value:3,children:"Public"})]})]}),o&&s.jsx("div",{className:`form-msg form-msg--${o.ok?"ok":"err"}`,children:o.text}),s.jsx("button",{className:"btn-primary",type:"submit",disabled:a,children:a?"Saving…":"Save Settings"})]})]})}):null}function Zs(e){if(e===0)return"0 B";const t=["B","KB","MB","GB","TB"],n=Math.floor(Math.log(e)/Math.log(1024));return`${(e/Math.pow(1024,n)).toFixed(n===0?0:1)} ${t[n]}`}function Em({archiveId:e}){const[t,n]=f.useState("idle"),[r,l]=f.useState(null),[i,a]=f.useState(null),[u,o]=f.useState(null);function c(){n("idle"),l(null),a(null),o(null)}async function g(){n("scanning"),o(null),l(null);try{const y=await Yh(e);l(y),n("scanned")}catch(y){o(y.message),n("error")}}async function h(){n("deleting"),o(null);try{const y=await Gh(e);a(y),n("done")}catch(y){o(y.message),n("error")}}const m=r&&r.deletable_files===0&&r.orphaned_blob_rows===0;return s.jsx("div",{style:{maxWidth:440},children:s.jsxs("div",{className:"form-section",children:[s.jsx("h2",{children:"Orphan Cleanup"}),s.jsxs("p",{className:"muted",style:{marginBottom:16},children:["Scan for blob files and database records that are no longer referenced by any archive entry and safely delete them."," ",s.jsx("strong",{children:"Cleanup is blocked while captures are running."})]}),!e&&s.jsx("div",{className:"muted",children:"No archive selected."}),e&&t==="idle"&&s.jsx("button",{className:"btn-ghost",onClick:g,children:"Scan for orphaned blobs"}),t==="scanning"&&s.jsx("div",{className:"muted",children:"Scanning…"}),t==="scanned"&&r&&m&&s.jsxs(s.Fragment,{children:[s.jsx("div",{className:"form-msg form-msg--ok",children:"Archive is clean — nothing to remove."}),s.jsx("button",{className:"btn-ghost",style:{marginTop:10},onClick:c,children:"Done"})]}),t==="scanned"&&r&&!m&&s.jsxs("div",{children:[s.jsxs("div",{style:{marginBottom:14,lineHeight:1.6},children:["Found ",s.jsx("strong",{children:r.deletable_files})," unreferenced file",r.deletable_files!==1?"s":""," ","and ",s.jsx("strong",{children:r.orphaned_blob_rows})," orphaned DB record",r.orphaned_blob_rows!==1?"s":""," ","— ",s.jsx("strong",{children:Zs(r.total_bytes)})," recoverable."]}),s.jsxs("div",{style:{display:"flex",gap:8},children:[s.jsxs("button",{className:"btn-danger",onClick:h,children:["Delete (",Zs(r.total_bytes),")"]}),s.jsx("button",{className:"btn-ghost",onClick:c,children:"Cancel"})]})]}),t==="deleting"&&s.jsx("div",{className:"muted",children:"Deleting…"}),t==="done"&&i&&s.jsxs("div",{children:[s.jsxs("div",{className:"form-msg form-msg--ok",children:["Freed ",s.jsx("strong",{children:Zs(i.freed_bytes)})," ","— removed ",i.deleted_files," file",i.deleted_files!==1?"s":""," ","and ",i.deleted_blob_rows," DB record",i.deleted_blob_rows!==1?"s":"","."]}),i.errors&&i.errors.length>0&&s.jsxs("div",{className:"form-msg form-msg--err",style:{marginTop:6},children:[i.errors.length," file",i.errors.length!==1?"s":""," could not be deleted."]}),s.jsx("button",{className:"btn-ghost",style:{marginTop:10},onClick:c,children:"Scan again"})]}),t==="error"&&s.jsxs("div",{children:[s.jsx("div",{className:"form-msg form-msg--err",children:u}),s.jsx("button",{className:"btn-ghost",style:{marginTop:10},onClick:c,children:"Try again"})]})]})})}function Tm(){const[e,t]=f.useState(null),[n,r]=f.useState(!0),[l,i]=f.useState(null),[a,u]=f.useState("global"),[o,c]=f.useState(""),[g,h]=f.useState("{}"),[m,y]=f.useState(null),[w,k]=f.useState(!1),[j,p]=f.useState({});f.useEffect(()=>{d()},[]);async function d(){r(!0),i(null);try{t(await em())}catch(S){i(S.message)}finally{r(!1)}}async function v(S){S.preventDefault();try{JSON.parse(g)}catch{y({ok:!1,text:'cookies must be valid JSON, e.g. {"session": "abc"}'});return}k(!0),y(null);try{await tm(a==="global"?null:o.trim(),a,g),c(""),h("{}"),u("global"),y({ok:!0,text:"Rule added."}),await d()}catch(D){y({ok:!1,text:D.message})}finally{k(!1)}}async function x(S){try{await rm(S),await d()}catch(D){i(D.message)}}function _(S){p(D=>({...D,[S.rule_uid]:{cookiesInput:S.cookies_json,saving:!1,msg:null}}))}function b(S){p(D=>{const L={...D};return delete L[S],L})}async function C(S){const D=j[S.rule_uid];try{JSON.parse(D.cookiesInput)}catch{p(L=>({...L,[S.rule_uid]:{...L[S.rule_uid],msg:{ok:!1,text:"Invalid JSON"}}}));return}p(L=>({...L,[S.rule_uid]:{...L[S.rule_uid],saving:!0,msg:null}}));try{await nm(S.rule_uid,{cookies_json:D.cookiesInput}),b(S.rule_uid),await d()}catch(L){p(H=>({...H,[S.rule_uid]:{...H[S.rule_uid],saving:!1,msg:{ok:!1,text:L.message}}}))}}return n?s.jsx("div",{className:"muted",children:"Loading…"}):l?s.jsx("div",{className:"form-msg form-msg--err",children:l}):s.jsx("div",{style:{maxWidth:560},children:s.jsxs("div",{className:"form-section",children:[s.jsx("h2",{children:"Cookie Rules"}),s.jsx("p",{className:"muted",style:{marginBottom:12},children:"Cookies are injected into every capture network request (yt-dlp, HTTP downloads, web-page snapshots). Global rules apply to all URLs; wildcard and regex rules apply only to matching URLs."}),e&&e.length>0?s.jsxs("table",{className:"data-table",style:{width:"100%",marginBottom:16},children:[s.jsx("thead",{children:s.jsxs("tr",{children:[s.jsx("th",{children:"Pattern"}),s.jsx("th",{children:"Cookies"}),s.jsx("th",{style:{width:100},children:"Actions"})]})}),s.jsx("tbody",{children:e.map(S=>{const D=j[S.rule_uid],L=S.url_pattern?s.jsxs(s.Fragment,{children:[s.jsxs("span",{className:"muted",children:[S.pattern_kind,":"]})," ",s.jsx("code",{children:S.url_pattern})]}):s.jsx("span",{className:"muted",children:"global (all URLs)"});return s.jsxs("tr",{children:[s.jsx("td",{children:L}),s.jsx("td",{children:D?s.jsxs(s.Fragment,{children:[s.jsx("textarea",{className:"field-input",style:{fontFamily:"monospace",fontSize:12,width:"100%",minHeight:60},value:D.cookiesInput,onChange:H=>p(M=>({...M,[S.rule_uid]:{...M[S.rule_uid],cookiesInput:H.target.value}}))}),D.msg&&s.jsx("div",{className:`form-msg form-msg--${D.msg.ok?"ok":"err"}`,children:D.msg.text}),s.jsxs("div",{style:{display:"flex",gap:8,marginTop:4},children:[s.jsx("button",{className:"btn-primary",style:{fontSize:12,padding:"2px 8px"},disabled:D.saving,onClick:()=>C(S),children:D.saving?"Saving…":"Save"}),s.jsx("button",{className:"btn-secondary",style:{fontSize:12,padding:"2px 8px"},onClick:()=>b(S.rule_uid),children:"Cancel"})]})]}):s.jsx("code",{style:{fontSize:12,wordBreak:"break-all"},children:S.cookies_json})}),s.jsx("td",{children:!D&&s.jsxs("div",{style:{display:"flex",gap:6},children:[s.jsx("button",{className:"btn-secondary",style:{fontSize:12,padding:"2px 8px"},onClick:()=>_(S),children:"Edit"}),s.jsx("button",{className:"btn-danger",style:{fontSize:12,padding:"2px 8px"},onClick:()=>x(S.rule_uid),children:"Del"})]})})]},S.rule_uid)})})]}):s.jsx("p",{className:"muted",style:{marginBottom:16},children:"No cookie rules defined."}),s.jsx("h3",{style:{marginBottom:8},children:"Add Rule"}),s.jsxs("form",{onSubmit:v,children:[s.jsxs("div",{className:"form-field",children:[s.jsx("label",{className:"form-label",children:"Pattern type"}),s.jsxs("select",{className:"field-input",value:a,onChange:S=>u(S.target.value),children:[s.jsx("option",{value:"global",children:"Global (all URLs)"}),s.jsx("option",{value:"wildcard",children:"Wildcard (e.g. *.youtube.com)"}),s.jsx("option",{value:"regex",children:"Regex (matched against full URL)"})]})]}),a!=="global"&&s.jsxs("div",{className:"form-field",children:[s.jsx("label",{className:"form-label",children:a==="wildcard"?"URL/hostname pattern":"Regex pattern"}),s.jsx("input",{className:"field-input",type:"text",value:o,onChange:S=>c(S.target.value),placeholder:a==="wildcard"?"*.youtube.com or https://example.com/*":".*\\.youtube\\.com.*",required:!0})]}),s.jsxs("div",{className:"form-field",children:[s.jsx("label",{className:"form-label",children:"Cookies (JSON object)"}),s.jsx("textarea",{className:"field-input",style:{fontFamily:"monospace",fontSize:13,minHeight:70},value:g,onChange:S=>h(S.target.value),placeholder:'{"SESSION": "abc123", "token": "xyz"}',required:!0})]}),m&&s.jsx("div",{className:`form-msg form-msg--${m.ok?"ok":"err"}`,children:m.text}),s.jsx("button",{className:"btn-primary",type:"submit",disabled:w,children:w?"Adding…":"Add Rule"})]})]})})}function Pm(){const[e,t]=f.useState(null),[n,r]=f.useState(!0),[l,i]=f.useState(!1),[a,u]=f.useState(null);f.useEffect(()=>{(async()=>{try{t(await Wa())}catch(j){u({ok:!1,text:j.message})}finally{r(!1)}})()},[]);async function o(j){i(!0),u(null);try{await Tl({ublock_enabled:j}),t(p=>({...p,ublock_enabled:j})),u({ok:!0,text:"Saved."})}catch(p){u({ok:!1,text:p.message})}finally{i(!1)}}async function c(j){i(!0),u(null);try{await Tl({cookie_ext_enabled:j}),t(p=>({...p,cookie_ext_enabled:j})),u({ok:!0,text:"Saved."})}catch(p){u({ok:!1,text:p.message})}finally{i(!1)}}async function g(j){i(!0),u(null);try{await Tl({modal_closer_enabled:j}),t(p=>({...p,modal_closer_enabled:j})),u({ok:!0,text:"Saved."})}catch(p){u({ok:!1,text:p.message})}finally{i(!1)}}if(n)return s.jsx("div",{className:"muted",children:"Loading\\u2026"});const h=(e==null?void 0:e.ublock_ext_available)??!1,m=(e==null?void 0:e.ublock_enabled)??!0,y=(e==null?void 0:e.cookie_ext_available)??!1,w=(e==null?void 0:e.cookie_ext_enabled)??!0,k=(e==null?void 0:e.modal_closer_enabled)??!0;return s.jsx("div",{children:s.jsxs("div",{className:"form-section",children:[s.jsx("h2",{children:"Extensions"}),s.jsx("p",{className:"form-hint",style:{marginBottom:20},children:"Extensions run inside the browser during WebPage captures and can block ads, accept cookie banners, and more. Changes take effect on the next capture."}),s.jsxs("div",{className:"ext-grid",children:[s.jsx("div",{className:"ext-card",children:s.jsxs("div",{className:"ext-card-header",children:[s.jsxs("div",{className:"ext-card-info",children:[s.jsx("span",{className:"ext-card-name",children:"uBlock Origin Lite"}),s.jsx("span",{className:"ext-card-desc",children:"Blocks ads, trackers, and other page clutter during archiving via Chrome’s declarativeNetRequest API (Manifest V3)."}),!h&&s.jsxs("span",{className:"ext-card-hint",children:["Not configured — set ",s.jsx("code",{children:"ARCHIVR_UBLOCK_EXT"})," to the unpacked extension directory to enable."]})]}),s.jsx("button",{type:"button",role:"switch","aria-checked":m,className:`ext-toggle${m?" ext-toggle--on":""}`,onClick:()=>o(!m),disabled:l,"aria-label":"Toggle uBlock Origin Lite",children:s.jsx("span",{className:"ext-toggle-knob"})})]})}),s.jsx("div",{className:"ext-card",children:s.jsxs("div",{className:"ext-card-header",children:[s.jsxs("div",{className:"ext-card-info",children:[s.jsx("span",{className:"ext-card-name",children:"I Still Don’t Care About Cookies"}),s.jsx("span",{className:"ext-card-desc",children:"Dismiss cookie consent banners during archiving."}),!y&&s.jsxs("span",{className:"ext-card-hint",children:["Not configured — set ",s.jsx("code",{children:"ARCHIVR_COOKIE_EXT"})," to the unpacked extension directory to enable."]})]}),s.jsx("button",{type:"button",role:"switch","aria-checked":w,className:`ext-toggle${w?" ext-toggle--on":""}`,onClick:()=>c(!w),disabled:l,"aria-label":"Toggle I Still Don't Care About Cookies",children:s.jsx("span",{className:"ext-toggle-knob"})})]})}),s.jsx("div",{className:"ext-card",children:s.jsxs("div",{className:"ext-card-header",children:[s.jsxs("div",{className:"ext-card-info",children:[s.jsx("span",{className:"ext-card-name",children:"Modal & Dialog Closer"}),s.jsx("span",{className:"ext-card-desc",children:"Auto-dismiss cookie banners, consent overlays, and other modal dialogs before a WebPage capture is taken. Implemented as an injected browser script; no external extension required."})]}),s.jsx("button",{type:"button",role:"switch","aria-checked":k,className:`ext-toggle${k?" ext-toggle--on":""}`,onClick:()=>g(!k),disabled:l,"aria-label":"Toggle Modal and Dialog Closer",children:s.jsx("span",{className:"ext-toggle-knob"})})]})})]}),a&&s.jsx("div",{className:`form-msg form-msg--${a.ok?"ok":"err"}`,children:a.text})]})})}const ou={0:"Private",1:"Public",2:"Users only",3:"Public"},bm=()=>s.jsx("svg",{viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round",children:s.jsx("path",{d:"M7 17 17 7M9 7h8v8"})});function Lm({archiveId:e,selectedEntry:t,selectedUids:n,selectedEntries:r,detail:l,onTagFilterSet:i,tagNodes:a,onTagsRefresh:u,onEntryTitleChange:o,onEntryDeleted:c,onBulkDeleted:g,humanizeTags:h,onDetailRefresh:m,onOpenPreview:y,onPlay:w}){var Jr;const[k,j]=f.useState([]),[p,d]=f.useState(""),[v,x]=f.useState([]),[_,b]=f.useState(""),C=f.useRef(0),S=f.useRef(!1),[D,L]=f.useState(!1),[H,M]=f.useState(""),[W,Y]=f.useState("idle"),[ce,ie]=f.useState(""),ee=f.useRef(null),[R,T]=f.useState(!1);f.useEffect(()=>{T(!1)},[(Jr=l==null?void 0:l.summary)==null?void 0:Jr.entry_uid]);const F=(n==null?void 0:n.size)>=2,[q,A]=f.useState(""),[ge,de]=f.useState("idle"),[Re,we]=f.useState(""),[je,E]=f.useState([]),[U,K]=f.useState(""),[V,X]=f.useState("idle"),[P,B]=f.useState(""),[re,le]=f.useState("idle");f.useEffect(()=>{const $=++C.current;if(ee.current&&(clearInterval(ee.current),ee.current=null),Y("idle"),ie(""),!t||!e){j([]),x([]);return}L(!1),M(""),S.current=!1,j([]),Promise.all([hl(e,t.entry_uid),Jh(e,t.entry_uid)]).then(([te,Ae])=>{$===C.current&&(j(te),x(Ae))}).catch(()=>{})},[t,e]),f.useEffect(()=>()=>{clearInterval(ee.current)},[]),f.useEffect(()=>{if(!F||!e){E([]);return}Td(e).then(E).catch(()=>E([]))},[F,e]),f.useEffect(()=>{A(""),de("idle"),we(""),K(""),X("idle"),B(""),le("idle")},[n]);async function rt(){const $=n.size;if(!window.confirm(`Delete ${$} entr${$===1?"y":"ies"}? This cannot be undone.`))return;le("running");const te=new Set;for(const Ae of n)try{await lu(e,Ae),te.add(Ae)}catch{}le("idle"),g==null||g(te)}async function Me(){const $=q.trim();if($){de("running"),we("");try{for(const te of n)await ru(e,te,$);A(""),de("done"),u==null||u(),setTimeout(()=>de("idle"),1800)}catch(te){we(te.message),de("error")}}}async function ve(){if(!U)return;X("running"),B("");const $=[];for(const te of n)try{await Pd(e,U,te)}catch{$.push(te)}$.length>0?(B(`Failed for ${$.length} entr${$.length===1?"y":"ies"}.`),X("error")):(X("done"),setTimeout(()=>X("idle"),1800))}async function en(){const $=H.trim()||null;try{await kh(e,t.entry_uid,$),o==null||o(t.entry_uid,$)}catch{}finally{L(!1)}}async function qe(){const $=p.trim();if(!(!$||!t))try{await ru(e,t.entry_uid,$),d(""),b("");const te=await hl(e,t.entry_uid);j(te),u()}catch(te){b(te.message)}}async function ys($){try{await jh(e,t.entry_uid,$);const te=await hl(e,t.entry_uid);j(te),u()}catch{}}async function xs(){if(!(!t||!e)&&window.confirm("Delete this entry? This cannot be undone."))try{await lu(e,t.entry_uid),c==null||c(t.entry_uid)}catch{}}async function ws(){if(!t||!e||W==="running")return;const $=C.current,te=t.entry_uid;Y("running"),ie("");try{const{job_uid:Ae}=await Zh(e,te);if(C.current!==$)return;ee.current=setInterval(async()=>{try{const dt=await Ed(e,Ae);if(dt.status==="completed"){if(clearInterval(ee.current),ee.current=null,C.current!==$)return;Y("done");const wn=await hl(e,te);if(C.current!==$)return;j(wn),m==null||m()}else if(dt.status==="failed"){if(clearInterval(ee.current),ee.current=null,C.current!==$)return;Y("error"),ie(dt.error_text||"Re-archive failed.")}}catch{if(clearInterval(ee.current),ee.current=null,C.current!==$)return;Y("error"),ie("Network error while polling.")}},500)}catch(Ae){if(C.current!==$)return;Y("error"),ie(Ae.message||"Failed to start re-archive.")}}const ks=l?[["Added",Ld(l.summary.archived_at)],["Source",l.summary.source_kind],["Type",l.summary.entity_kind],["Visibility",ou[l.summary.visibility]??l.summary.visibility],["Root",l.structured_root_relpath]]:[],js=new Set(["mp3","ogg","m4a","opus","wav","flac","aac"]),Ss=new Set(["mp4","webm","mov","mkv","avi","m4v","ogv","pdf","html","htm","jpg","jpeg","png","gif","webp","avif","svg","bmp"]),yn=l?l.artifacts.findIndex($=>$.artifact_role==="primary_media"):-1,xn=yn>=0?l.artifacts[yn]:null,Kr=xn?xn.relpath.split(".").pop().toLowerCase():"",Xr=xn&&js.has(Kr),Ns=yn>=0&&t?`/api/archives/${e}/entries/${t.entry_uid}/artifacts/${yn}`:null,_s=l&&!Xr&&(l.summary.entity_kind==="tweet"||l.summary.entity_kind==="tweet_thread"||xn&&Ss.has(Kr));return s.jsxs("aside",{className:"context-rail",children:[s.jsx("div",{className:"rail-eyebrow",children:"Context"}),F?s.jsxs("div",{className:"bulk-panel",children:[s.jsxs("p",{className:"bulk-count",children:[s.jsx("span",{className:"bulk-count-num",children:n.size})," entries selected"]}),s.jsxs("div",{className:"rail-section",children:[s.jsx("div",{className:"rail-section-heading",children:"Assign tag"}),Re&&s.jsx("p",{className:"form-msg form-msg--err",style:{margin:"0 0 8px"},children:Re}),s.jsxs("div",{className:"tag-input-wrap",children:[s.jsx("span",{className:"hash",children:"/"}),s.jsx("input",{className:"tag-input",type:"text",placeholder:"science/cs",autoComplete:"off",value:q,onChange:$=>A($.target.value),onKeyDown:$=>{$.key==="Enter"&&Me()}}),s.jsx("button",{className:"tag-add-btn",onClick:Me,disabled:ge==="running"||!q.trim(),children:ge==="running"?"…":ge==="done"?"✓":"Add"})]})]}),je.length>0&&s.jsxs("div",{className:"rail-section",children:[s.jsx("div",{className:"rail-section-heading",children:"Add to collection"}),s.jsxs("div",{className:"bulk-coll-row",children:[s.jsxs("select",{className:"bulk-coll-select",value:U,onChange:$=>K($.target.value),children:[s.jsx("option",{value:"",children:"Pick a collection…"}),je.map($=>s.jsx("option",{value:$.collection_uid,children:$.name},$.collection_uid))]}),s.jsx("button",{className:"tag-add-btn",onClick:ve,disabled:!U||V==="running",children:V==="running"?"…":V==="done"?"✓":V==="error"?"!":"Add"})]}),P&&s.jsx("p",{className:"form-msg form-msg--err",style:{margin:"6px 0 0"},children:P})]}),s.jsx("div",{className:"rail-delete-zone",children:s.jsx("button",{className:"rail-delete-btn",onClick:rt,disabled:re==="running",children:re==="running"?"Deleting…":`Delete ${n.size} entr${n.size===1?"y":"ies"}`})})]}):t?l?s.jsxs(s.Fragment,{children:[D?s.jsx("input",{className:"rail-title-input",autoFocus:!0,value:H,onChange:$=>M($.target.value),onKeyDown:$=>{$.key==="Enter"&&$.currentTarget.blur(),$.key==="Escape"&&(S.current=!0,$.currentTarget.blur())},onBlur:()=>{S.current?L(!1):en(),S.current=!1}}):s.jsxs("h2",{className:"rail-title rail-title--editable",title:"Click to rename",onClick:()=>{M(l.summary.title??""),L(!0)},children:[on(l.summary.title)||on(l.summary.entry_uid),s.jsx("svg",{className:"edit-icon",viewBox:"0 0 16 16",fill:"none",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round",strokeLinejoin:"round","aria-hidden":"true",children:s.jsx("path",{d:"M11.5 2.5a1.5 1.5 0 0 1 2 2L5 13l-3 1 1-3 8.5-8.5z"})})]}),l.summary.original_url&&s.jsxs("a",{className:"url-tile",href:l.summary.original_url,target:"_blank",rel:"noopener noreferrer",children:[s.jsx("span",{className:"ico",dangerouslySetInnerHTML:{__html:Va(l.summary.source_kind)}}),s.jsx("span",{className:"u-text",children:l.summary.original_url}),s.jsx("span",{className:"ext",children:s.jsx(bm,{})})]}),Xr&&w&&s.jsx("button",{className:"rail-preview-btn",onClick:()=>w(Ns,t),children:"▶ Play"}),_s&&y&&s.jsx("button",{className:"rail-preview-btn",onClick:y,children:"Preview"}),s.jsx("div",{className:"meta-list",children:ks.filter(([,$])=>$!=null&&$!=="").map(([$,te])=>s.jsxs("div",{className:"meta-item",children:[s.jsx("span",{className:"meta-k",children:$}),s.jsx("span",{className:`meta-v${$==="Root"?" mono":""}`,children:on(te)})]},$))}),l.artifacts.length>0&&(()=>{const $=l.artifacts.map((Se,Gn)=>({...Se,_idx:Gn})),te=$.filter(Se=>Se.artifact_role==="font"),Ae=$.filter(Se=>Se.artifact_role!=="font"),dt=te.reduce((Se,Gn)=>Se+(Gn.byte_size||0),0),wn=l.summary.entry_uid,qr=Se=>s.jsx("li",{children:s.jsxs("a",{href:`/api/archives/${e}/entries/${wn}/artifacts/${Se._idx}`,target:"_blank",rel:"noopener noreferrer",className:"artifact-link",children:[s.jsx("span",{className:"artifact-name",children:Se.artifact_role==="font"?Se.relpath.split("/").pop():Se.artifact_role.replace(/_/g," ")}),s.jsx("span",{className:"artifact-size",children:Se.byte_size!=null?Zl(Se.byte_size):"—"})]})},Se._idx);return s.jsxs("div",{className:"rail-section",children:[s.jsxs("div",{className:"rail-section-heading",children:["Artifacts ",s.jsx("span",{className:"num",children:l.artifacts.length})]}),s.jsxs("ul",{className:"artifact-list",children:[Ae.map(qr),te.length>0&&s.jsxs("li",{className:"artifact-group",children:[s.jsxs("button",{type:"button",className:"artifact-group-header artifact-link","aria-expanded":R,onClick:()=>T(Se=>!Se),children:[s.jsxs("span",{className:"artifact-name",children:[s.jsx("span",{"aria-hidden":"true",className:`artifact-group-chevron${R?" open":""}`,children:"›"}),` fonts (${te.length})`]}),s.jsx("span",{className:"artifact-size",children:Zl(dt)})]}),R&&s.jsx("ul",{className:"artifact-list artifact-group-body",children:te.map(qr)})]})]})]})})()]}):s.jsx("p",{className:"tags-empty",children:"Loading\\u2026"}):s.jsx("p",{className:"tags-empty",children:"Select an entry."}),t&&!F&&s.jsxs(s.Fragment,{children:[s.jsxs("div",{className:"rail-section",children:[s.jsx("div",{className:"rail-section-heading",children:"Tags"}),k.length===0?s.jsx("p",{className:"tags-empty",children:"No tags yet."}):s.jsx("div",{className:"tags-wrap",children:k.map($=>s.jsxs("span",{className:"tag-pill",title:$.full_path,children:[h?zd($.full_path):$.full_path,s.jsx("button",{className:"remove",title:`Remove tag ${$.full_path}`,onClick:()=>ys($.tag_uid),children:"×"})]},$.tag_uid))}),_&&s.jsx("p",{className:"form-msg form-msg--err",style:{margin:"0 0 8px"},children:_}),s.jsxs("div",{className:"tag-input-wrap",children:[s.jsx("span",{className:"hash",children:"/"}),s.jsx("input",{className:"tag-input",type:"text",placeholder:"science/cs",autoComplete:"off",value:p,onChange:$=>d($.target.value),onKeyDown:$=>{$.key==="Enter"&&qe()}}),s.jsx("button",{className:"tag-add-btn",onClick:qe,children:"Add"})]})]}),v.length>0&&s.jsxs("div",{className:"rail-section",children:[s.jsx("div",{className:"rail-section-heading",children:"Collections"}),v.map($=>s.jsxs("div",{className:"coll-row",children:[s.jsx("span",{className:"coll-name",children:$.collection_uid}),s.jsx("span",{className:"vis-badge",children:ou[$.visibility_bits]??`bits:${$.visibility_bits}`})]},$.collection_uid))]}),l&&(l.summary.entity_kind==="tweet"||l.summary.entity_kind==="tweet_thread")&&s.jsxs("div",{className:"rail-section",children:[s.jsx("div",{className:"rail-section-heading",children:"Actions"}),s.jsx("button",{className:"rail-rearchive-btn",onClick:ws,disabled:W==="running",children:W==="running"?"Re-archiving…":"Re-archive"}),W==="done"&&s.jsx("p",{className:"form-msg form-msg--ok",style:{marginTop:"6px"},children:"Re-archived successfully."}),W==="error"&&s.jsx("p",{className:"form-msg form-msg--err",style:{marginTop:"6px"},children:ce})]}),s.jsx("div",{className:"rail-delete-zone",children:s.jsx("button",{className:"rail-delete-btn",onClick:xs,children:"Delete entry"})})]})]})}function zm({src:e}){const t=f.useRef(null);return f.useEffect(()=>{t.current&&t.current.load()},[e]),s.jsx("div",{className:"preview-video-wrap",style:{background:"#111",display:"flex",alignItems:"center",justifyContent:"center",width:"100%",height:"100%",minHeight:"240px"},children:e?s.jsxs("video",{ref:t,controls:!0,autoPlay:!1,style:{width:"100%",maxHeight:"100%",display:"block"},children:[s.jsx("source",{src:e}),"Your browser does not support the video element."]}):s.jsx("span",{style:{color:"var(--muted)",fontFamily:"var(--sans)",fontSize:"0.9rem"},children:"No video available"})})}function uu({src:e,type:t,title:n,originalUrl:r}){const l=r||e,i=n||null;return s.jsxs("div",{className:"preview-iframe-wrap",style:{flex:1,minHeight:0,display:"flex",flexDirection:"column"},children:[s.jsxs("div",{className:"preview-iframe-toolbar",style:{display:"flex",flexDirection:"column",gap:"2px",padding:"6px 12px",borderBottom:"1px solid var(--line-soft)",background:"var(--paper-2)",flexShrink:0},children:[i&&s.jsx("span",{style:{fontSize:"0.85rem",fontWeight:600,color:"var(--ink)",fontFamily:"var(--sans)",overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"},children:i}),s.jsxs("div",{style:{display:"flex",alignItems:"center",gap:"8px"},children:[s.jsx("span",{style:{flex:1,overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap",fontSize:"0.78rem",color:"var(--muted)",fontFamily:"var(--sans)"},children:l}),s.jsx("a",{href:e,target:"_blank",rel:"noreferrer noopener",style:{fontSize:"0.78rem",color:"var(--accent)",textDecoration:"none",whiteSpace:"nowrap",fontFamily:"var(--sans)",flexShrink:0},children:t==="pdf"?"Open PDF ↗":"Open in new tab ↗"})]})]}),s.jsx("iframe",{src:e,sandbox:"allow-same-origin allow-popups",allow:"autoplay 'none'",referrerPolicy:"no-referrer",style:{flex:1,border:"none",width:"100%",minHeight:0},title:i||(t==="pdf"?"PDF preview":"Page preview")})]})}function Rm({src:e,alt:t}){return s.jsx("div",{className:"preview-image-wrap",style:{display:"flex",alignItems:"center",justifyContent:"center",width:"100%",height:"100%",background:"var(--paper-2)",overflow:"hidden"},children:s.jsx("a",{href:e,target:"_blank",rel:"noreferrer noopener",style:{display:"contents"},children:s.jsx("img",{src:e,alt:t||"",style:{objectFit:"contain",maxHeight:"100%",maxWidth:"100%",display:"block",cursor:"pointer"}})})})}function Id(e){return e?new Intl.DateTimeFormat("en-US",{month:"short",day:"numeric",year:"numeric"}).format(new Date(e*1e3)):""}function cu(e){return!e||!e.includes("&")?e:e.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,'"').replace(/'/g,"'").replace(/'/g,"'")}const J={card:{background:"var(--paper)",border:"1px solid var(--line)",borderRadius:"12px",overflow:"hidden",maxWidth:"560px",margin:"0 auto",fontFamily:'var(--sans, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif)'},threadOuter:{border:"1px solid var(--line)",borderRadius:"12px",overflow:"hidden",maxWidth:"560px",margin:"0 auto",background:"var(--paper)",fontFamily:'var(--sans, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif)'},tweetRow:{display:"flex",gap:"10px",padding:"10px 12px"},tweetRowThread:{display:"flex",gap:"10px",padding:"10px 12px 0"},leftCol:{display:"flex",flexDirection:"column",alignItems:"center",flexShrink:0,width:"36px"},rightCol:{flex:1,minWidth:0,paddingBottom:"8px"},avatar:{width:"36px",height:"36px",borderRadius:"50%",objectFit:"cover",flexShrink:0,display:"block"},avatarPh:{width:"36px",height:"36px",borderRadius:"50%",background:"var(--line)",flexShrink:0},threadLine:{flex:1,width:"2px",background:"var(--line-soft, var(--line))",margin:"4px 0",minHeight:"12px",borderRadius:"1px"},authorRow:{display:"flex",alignItems:"baseline",gap:"4px",flexWrap:"wrap",marginBottom:"4px",lineHeight:"1.3"},authorName:{fontWeight:"700",fontSize:"14px",color:"var(--ink)"},authorHandle:{fontSize:"13px",color:"var(--muted)"},datePart:{fontSize:"13px",color:"var(--muted)"},tweetText:{fontSize:"14px",lineHeight:"1.5",color:"var(--ink)",whiteSpace:"pre-line",marginBottom:"8px",wordBreak:"break-word"},stats:{display:"flex",gap:"12px",fontSize:"13px",color:"var(--muted)"},link:{color:"var(--accent)",textDecoration:"none"},loading:{padding:"24px 16px",textAlign:"center",color:"var(--muted)",fontSize:"14px"},error:{padding:"24px 16px",textAlign:"center",color:"var(--alert)",fontSize:"14px"},mediaGrid:{marginBottom:"8px",borderRadius:"10px",overflow:"hidden",border:"1px solid var(--line)"},mediaImg:{display:"block",width:"100%",objectFit:"cover",maxHeight:"260px"},mediaVideo:{display:"block",width:"100%",maxHeight:"260px",background:"#000"},article:{maxWidth:"560px",margin:"0 auto",border:"1px solid var(--line)",borderRadius:"12px",overflow:"hidden",background:"var(--paper)",fontFamily:'var(--sans, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif)'},aCover:{width:"100%",display:"block",objectFit:"cover",maxHeight:"280px"},aMeta:{padding:"10px 14px 0"},aTweetTitle:{fontSize:"20px",fontWeight:"800",letterSpacing:"-0.3px",color:"var(--ink)",lineHeight:"1.3",marginBottom:"8px"},aAuthorRow:{display:"flex",alignItems:"center",gap:"8px",marginBottom:"8px"},aAvatar:{width:"36px",height:"36px",borderRadius:"50%",objectFit:"cover",flexShrink:0,display:"block"},aAvatarPh:{width:"36px",height:"36px",borderRadius:"50%",background:"var(--line)",flexShrink:0},aAuthorName:{fontSize:"14px",fontWeight:"700",color:"var(--ink)",lineHeight:"1.3"},aAuthorSub:{fontSize:"13px",color:"var(--muted)",lineHeight:"1.3"},aDivider:{border:"none",borderTop:"1px solid var(--line)",margin:"0"},aBody:{padding:"4px 14px 16px"},bH1:{fontSize:"22px",fontWeight:"800",letterSpacing:"-0.4px",color:"var(--ink)",lineHeight:"1.25",margin:"16px 0 6px"},bH2:{fontSize:"18px",fontWeight:"700",letterSpacing:"-0.2px",color:"var(--ink)",lineHeight:"1.3",margin:"14px 0 4px"},bP:{fontSize:"15px",color:"var(--ink)",lineHeight:"1.65",marginBottom:"12px",marginTop:"0"},bSpacer:{height:"4px",display:"block"},bQuote:{borderLeft:"3px solid var(--line)",padding:"2px 12px",margin:"12px 0",color:"var(--muted)",fontSize:"15px",lineHeight:"1.6"},bHr:{border:"none",borderTop:"1px solid var(--line)",margin:"14px 0"},bImg:{width:"100%",display:"block",borderRadius:"8px",margin:"12px 0"},bUl:{margin:"8px 0 12px",paddingLeft:"24px"},bOl:{margin:"8px 0 12px",paddingLeft:"24px"},bLi:{fontSize:"15px",color:"var(--ink)",lineHeight:"1.6",marginBottom:"4px"},bTweet:{display:"flex",alignItems:"center",gap:"10px",border:"1px solid var(--line)",borderRadius:"10px",padding:"10px 14px",margin:"12px 0",color:"var(--muted)",fontSize:"14px",textDecoration:"none"},bMdPre:{borderRadius:"8px",margin:"10px 0",overflow:"auto",background:"var(--paper-3, var(--field))",padding:"12px 14px"},bMdCode:{fontFamily:"ui-monospace, 'Cascadia Code', 'Fira Code', Menlo, Consolas, monospace",fontSize:"12px",lineHeight:"1.6",color:"var(--ink)",background:"transparent",display:"block"},iCode:{fontFamily:"ui-monospace, 'Cascadia Code', Menlo, Consolas, monospace",fontSize:"0.875em",background:"var(--paper-3, var(--field))",padding:"1px 5px",borderRadius:"4px",color:"var(--ink)"},qtBadge:{fontSize:"11px",color:"var(--muted)",display:"inline-flex",alignItems:"center",gap:"2px",marginLeft:"4px",letterSpacing:"0.03em",flexShrink:0},lightboxBackdrop:{position:"fixed",inset:0,zIndex:500,background:"rgba(0,0,0,0.92)",display:"flex",alignItems:"center",justifyContent:"center",padding:"20px"},lightboxContent:{display:"flex",flexDirection:"column",alignItems:"center",gap:"10px",maxWidth:"90vw",maxHeight:"90vh"},lightboxToolbar:{display:"flex",alignItems:"center",gap:"10px",alignSelf:"flex-end"},lightboxImg:{maxWidth:"88vw",maxHeight:"80vh",objectFit:"contain",borderRadius:"6px",display:"block"},lightboxNav:{display:"flex",gap:"12px",alignItems:"center"},lightboxNavBtn:{background:"rgba(255,255,255,0.18)",border:"none",color:"#fff",fontSize:"20px",cursor:"pointer",borderRadius:"50%",width:"36px",height:"36px",display:"flex",alignItems:"center",justifyContent:"center",lineHeight:1,flexShrink:0},lightboxBtn:{background:"rgba(255,255,255,0.18)",border:"none",color:"#fff",fontSize:"16px",cursor:"pointer",borderRadius:"50%",width:"30px",height:"30px",display:"flex",alignItems:"center",justifyContent:"center",lineHeight:1,flexShrink:0},lightboxLink:{color:"rgba(255,255,255,0.7)",textDecoration:"none",fontSize:"14px"},lightboxCounter:{color:"rgba(255,255,255,0.6)",fontSize:"13px"}},Ne={bg:"#000000",border:"#2f3336",text:"#e7e9ea",dim:"#71767b",accent:"#1d9bf0",codeBg:"#16181c"},ei={article:{background:Ne.bg,color:Ne.text,minHeight:"100%",fontFamily:'-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif'},articleInner:{maxWidth:"598px",margin:"0 auto",paddingBottom:"80px"},aCover:{width:"100%",display:"block",objectFit:"cover",maxHeight:"420px"},aMeta:{padding:"20px 16px 0"},aTweetTitle:{fontSize:"34px",fontWeight:"800",letterSpacing:"-0.5px",color:Ne.text,lineHeight:"44px",marginBottom:"16px"},aAuthorRow:{display:"flex",alignItems:"center",gap:"12px",marginBottom:"16px"},aAvatar:{width:"40px",height:"40px",borderRadius:"50%",objectFit:"cover",flexShrink:0,display:"block"},aAvatarPh:{width:"40px",height:"40px",borderRadius:"50%",background:Ne.border,flexShrink:0},aAuthorName:{fontSize:"15px",fontWeight:"700",color:Ne.text,lineHeight:"1.3"},aAuthorSub:{fontSize:"15px",color:Ne.dim,lineHeight:"1.3"},aDivider:{border:"none",borderTop:`1px solid ${Ne.border}`,margin:"0"},aBody:{padding:"4px 16px 0"},bH1:{fontSize:"26px",fontWeight:"800",letterSpacing:"-0.4px",color:Ne.text,lineHeight:"36px",margin:"24px 0 10px"},bH2:{fontSize:"26px",fontWeight:"800",letterSpacing:"-0.4px",color:Ne.text,lineHeight:"36px",margin:"24px 0 10px"},bP:{fontSize:"17px",color:Ne.text,lineHeight:"1.5",marginBottom:"16px",marginTop:"0"},bSpacer:{height:"6px",display:"block"},bQuote:{borderLeft:`3px solid ${Ne.border}`,padding:"2px 14px",margin:"14px 0",color:Ne.dim,fontSize:"17px",lineHeight:"1.5"},bHr:{border:"none",borderTop:`1px solid ${Ne.border}`,margin:"28px 0"},bImg:{width:"100%",display:"block",borderRadius:"12px",margin:"16px 0"},bUl:{margin:"10px 0 16px",paddingLeft:"28px"},bOl:{margin:"10px 0 16px",paddingLeft:"28px"},bLi:{fontSize:"17px",color:Ne.text,lineHeight:"1.5",marginBottom:"6px"},bTweet:{display:"flex",alignItems:"center",gap:"12px",border:`1px solid ${Ne.border}`,borderRadius:"12px",padding:"14px 16px",margin:"14px 0",color:Ne.dim,fontSize:"15px",textDecoration:"none"},bMdPre:{borderRadius:"12px",margin:"12px 0",overflow:"auto",background:"#1e2029"},bMdCode:{fontFamily:"ui-monospace, 'Cascadia Code', 'Fira Code', Menlo, Consolas, monospace",fontSize:"13px",lineHeight:"1.65",padding:"18px 20px",display:"block",color:Ne.text,background:"transparent"},iCode:{fontFamily:"ui-monospace, 'Cascadia Code', Menlo, Consolas, monospace",fontSize:"0.875em",background:Ne.codeBg,padding:"2px 6px",borderRadius:"4px",color:"#e6edf3"},link:{color:Ne.accent,textDecoration:"none"}};function Dm(e,t,n){const r={};return n&&n.forEach((l,i)=>{l.relpath&&(r[l.relpath]=`/api/archives/${e}/entries/${t}/artifacts/${i}`)}),r}function Bn(e,t,n){return e&&n[e]?n[e]:t||null}function Od(){return s.jsx("svg",{width:"20",height:"20",viewBox:"0 0 24 24",fill:"currentColor","aria-hidden":"true",style:{flexShrink:0,color:"var(--ink)"},children:s.jsx("path",{d:"M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-4.714-6.231-5.401 6.231H2.748l7.73-8.835L1.254 2.25H8.08l4.259 5.63L18.244 2.25zm-1.161 17.52h1.833L7.084 4.126H5.117L17.083 19.77z"})})}function Qa(e,t,...n){var r;if(e.fromIndex!=null&&e.toIndex!=null)return{s:e.fromIndex,e:e.toIndex};if(((r=e.indices)==null?void 0:r.length)===2)return{s:e.indices[0],e:e.indices[1]};if(t)for(const l of n){if(!l)continue;const i=t.indexOf(l);if(i!==-1)return{s:i,e:i+l.length}}return null}function Fd(e,t){const n=e.expanded_url||e.url||e.text||"",r=e.display_url||e.expanded_url||e.url||e.text||"",l=Qa(e,t,e.url,e.text,e.display_url,e.expanded_url);return!l||!n?null:{...l,kind:"url",href:n,display:r}}function Md(e,t){const n=e.screen_name||e.name||e.text||"",r=n?`@${n}`:null,l=Qa(e,t,r);return!l||!n?null:{...l,kind:"mention",screen_name:n}}const du=/https?:\/\/[^\s<>"'\])]+/g,$m=/[.,;:!?)()]+$/;function es(e,t){const n=[];let r=0,l;for(du.lastIndex=0;(l=du.exec(e))!==null;){l.index>r&&n.push(e.slice(r,l.index));let i=l[0].replace($m,"");n.push(s.jsx("a",{href:i,target:"_blank",rel:"noopener noreferrer",style:t,children:i},l.index));const a=l[0].slice(i.length);a&&n.push(a),r=l.index+l[0].length}return r===0?e:(rFd(u,e)).filter(Boolean),...(t.user_mentions||[]).map(u=>Md(u,e)).filter(Boolean)];if(r.length===0&&n.length===0)return es(cu(e),J.link);const l=new Set([0,e.length]);for(const u of r)u.s>=0&&u.s<=e.length&&l.add(u.s),u.e>=0&&u.e<=e.length&&l.add(u.e);for(const[u,o]of n)u>=0&&u<=e.length&&l.add(u),o>=0&&o<=e.length&&l.add(o);const i=(u,o)=>n.some(([c,g])=>c<=u&&g>=o),a=[...l].sort((u,o)=>u-o);return a.slice(0,-1).map((u,o)=>{const c=a[o+1];if(i(u,c))return null;const g=e.slice(u,c),h=r.filter(w=>w.s<=u&&w.e>=c),m=h.find(w=>w.kind==="url");if(m)return s.jsx("a",{href:m.href,target:"_blank",rel:"noopener noreferrer",style:J.link,children:m.display||g},o);const y=h.find(w=>w.kind==="mention");return y?s.jsx("a",{href:`https://x.com/${y.screen_name}`,target:"_blank",rel:"noopener noreferrer",style:J.link,children:g},o):s.jsx("span",{children:es(cu(g),J.link)},o)}).filter(u=>u!==null)}function Om(e,t,n,r,l=J){if(!e)return null;t=t||[],n=n||[],r=r||[];const i=[];for(const o of t)o.length>0&&i.push({s:o.offset,e:o.offset+o.length,kind:"style",style:o.style});for(const o of n){const c=Fd(o,e);c&&i.push(c)}for(const o of r){const c=Md(o,e);c&&i.push(c)}if(i.length===0)return es(e,l.link);const a=new Set([0,e.length]);for(const o of i)o.s>=0&&o.s<=e.length&&a.add(o.s),o.e>=0&&o.e<=e.length&&a.add(o.e);const u=[...a].sort((o,c)=>o-c);return u.slice(0,-1).map((o,c)=>{const g=u[c+1],h=i.filter(j=>j.s<=o&&j.e>=g),m=e.slice(o,g);let y;if(m.includes(` +`)){const j=m.split(` +`);y=j.flatMap((p,d)=>dj.kind==="style"&&j.style==="Code")&&(y=s.jsx("code",{style:l.iCode,children:y})),h.some(j=>j.kind==="style"&&j.style==="Bold")&&(y=s.jsx("strong",{children:y})),h.some(j=>j.kind==="style"&&j.style==="Italic")&&(y=s.jsx("em",{children:y})),h.some(j=>j.kind==="style"&&j.style==="Underline")&&(y=s.jsx("u",{children:y})),h.some(j=>j.kind==="style"&&j.style==="Strikethrough")&&(y=s.jsx("s",{children:y}));const w=h.find(j=>j.kind==="url");if(w){const j=/^https?:\/\/t\.co\//i.test(y);y=s.jsx("a",{href:w.href,target:"_blank",rel:"noopener noreferrer",style:l.link,children:j?w.display:y})}const k=h.find(j=>j.kind==="mention");return k&&(y=s.jsx("a",{href:`https://x.com/${k.screen_name}`,target:"_blank",rel:"noopener noreferrer",style:l.link,children:y})),s.jsx("span",{children:typeof y=="string"?es(y,l.link):y},c)})}function Fm(e,t,n){const r=(n==null?void 0:n.st)||J,l=e.resolved_entities||[];return l.length===0?null:l.map((i,a)=>{var u;switch(i.type){case"divider":return s.jsx("hr",{style:r.bHr},a);case"media":{const o=Bn(i.local_path,i.url,t);return o?s.jsx("a",{href:o,target:"_blank",rel:"noopener noreferrer",style:{display:"block",cursor:"zoom-in"},onClick:c=>{var g;!c.metaKey&&!c.ctrlKey&&(c.preventDefault(),(g=n==null?void 0:n.onImgClick)==null||g.call(n,o))},children:s.jsx("img",{src:o,style:r.bImg,loading:"lazy",alt:""})},a):null}case"tweet":return i.tweet_id?s.jsxs("a",{href:`https://x.com/i/status/${i.tweet_id}`,target:"_blank",rel:"noopener noreferrer",style:r.bTweet,children:[s.jsx(Od,{}),"View post on X"]},a):null;case"link":return i.url?s.jsx("p",{style:r.bP,children:s.jsx("a",{href:i.url,target:"_blank",rel:"noopener noreferrer",style:r.link,children:i.url})},a):null;case"markdown":{const o=i.markdown??((u=i.data)==null?void 0:u.markdown)??"";return s.jsx("pre",{style:r.bMdPre,children:s.jsx("code",{style:r.bMdCode,children:o})},a)}case"emoji":return i.url?s.jsx("img",{src:i.url,alt:"",style:{height:"1.2em",verticalAlign:"middle",margin:"0 1px"}},a):null;default:return null}})}function ti(e,t,n,r){const l=(r==null?void 0:r.st)||J,i=e.type||"",a=e.text||"",u=e.inline_style_ranges||[],o=e.data||{},c=Om(a,u,o.urls||[],o.mentions||[],l);switch(i){case"header-one":return s.jsx("h1",{style:l.bH1,children:c},t);case"header-two":{const g=a.match(/(?:x\.com|twitter\.com)\/i\/status\/(\d+)/);return g?s.jsxs("a",{href:`https://x.com/i/status/${g[1]}`,target:"_blank",rel:"noopener noreferrer",style:l.bTweet,children:[s.jsx(Od,{}),"View post on X"]},t):s.jsx("h2",{style:l.bH2,children:c},t)}case"unstyled":return a.trim()?s.jsx("p",{style:l.bP,children:c},t):s.jsx("span",{style:l.bSpacer},t);case"blockquote":return s.jsx("blockquote",{style:l.bQuote,children:c},t);case"unordered-list-item":case"ordered-list-item":return s.jsx("li",{style:l.bLi,children:c},t);case"atomic":return s.jsx("span",{children:Fm(e,n,r)},t);default:return a?s.jsx("p",{style:l.bP,children:c},t):null}}function Mm(e,t,n){const r=(n==null?void 0:n.st)||J,l=[];let i=0;for(;i{r&&(l==null||l(!0))},[r,l]);const u=r?ei:J,o=e.cover_media||{},c=e.author||t||{},g=e.first_published_at_secs?Id(e.first_published_at_secs):"",m=[c.screen_name?`@${c.screen_name}`:"",g].filter(Boolean).join(" · "),y=Bn(o.local_path,o.url,n),w=Bn(c.avatar_local_path,c.avatar_url,n),k=s.jsxs(s.Fragment,{children:[i&&s.jsx(Ad,{items:[{src:i,alt:""}],startIndex:0,onClose:()=>a(null)}),y&&s.jsx("a",{href:y,target:"_blank",rel:"noopener noreferrer",style:{display:"block",cursor:"zoom-in"},onClick:j=>{!j.metaKey&&!j.ctrlKey&&(j.preventDefault(),a(y))},children:s.jsx("img",{src:y,style:u.aCover,alt:"Article cover"})}),s.jsxs("div",{style:u.aMeta,children:[e.title&&s.jsx("div",{style:u.aTweetTitle,children:e.title}),s.jsxs("div",{style:u.aAuthorRow,children:[w?s.jsx("img",{src:w,style:u.aAvatar,alt:c.name||""}):s.jsx("div",{style:u.aAvatarPh}),s.jsxs("div",{children:[s.jsx("div",{style:u.aAuthorName,children:c.name||c.screen_name||"Unknown"}),m&&s.jsx("div",{style:u.aAuthorSub,children:m})]})]})]}),s.jsx("hr",{style:u.aDivider}),s.jsx("div",{style:u.aBody,children:Mm(e.blocks||[],n,{onImgClick:a,st:u})})]});return r?s.jsx("div",{style:ei.article,children:s.jsx("div",{style:ei.articleInner,children:k})}):s.jsx("div",{style:J.article,children:k})}function Bm({photos:e,onOpen:t}){const n=e.length;if(n===0)return null;if(n===1)return s.jsx("a",{href:e[0].src,target:"_blank",rel:"noopener noreferrer",style:{display:"block"},onClick:l=>{!l.metaKey&&!l.ctrlKey&&(l.preventDefault(),t(0))},children:s.jsx("img",{src:e[0].src,alt:e[0].alt||"",style:J.mediaImg,loading:"lazy"})});const r=n<=2?"180px":"140px";return s.jsx("div",{style:{display:"grid",gridTemplateColumns:"1fr 1fr",gridTemplateRows:n===2?r:`${r} ${r}`,gap:"2px"},children:e.map((l,i)=>s.jsx("a",{href:l.src,target:"_blank",rel:"noopener noreferrer",style:{display:"block",overflow:"hidden",gridRow:n===3&&i===0?"span 2":void 0},onClick:a=>{!a.metaKey&&!a.ctrlKey&&(a.preventDefault(),t(i))},children:s.jsx("img",{src:l.src,alt:l.alt||"",loading:"lazy",style:{width:"100%",height:"100%",objectFit:"cover",display:"block"}})},i))})}function Ad({items:e,startIndex:t,onClose:n}){const[r,l]=f.useState(t);f.useEffect(()=>{const a=u=>{(u.key==="Escape"||u.key==="ArrowLeft"||u.key==="ArrowRight")&&(u.stopPropagation(),u.preventDefault()),u.key==="Escape"&&n(),u.key==="ArrowRight"&&l(o=>Math.min(o+1,e.length-1)),u.key==="ArrowLeft"&&l(o=>Math.max(o-1,0))};return document.addEventListener("keydown",a),()=>document.removeEventListener("keydown",a)},[n,e.length]);const i=e[r];return s.jsx("div",{style:J.lightboxBackdrop,onClick:n,children:s.jsxs("div",{style:J.lightboxContent,onClick:a=>a.stopPropagation(),children:[s.jsxs("div",{style:J.lightboxToolbar,children:[e.length>1&&s.jsxs("span",{style:J.lightboxCounter,children:[r+1," / ",e.length]}),s.jsx("a",{href:i.src,target:"_blank",rel:"noopener noreferrer",style:J.lightboxLink,title:"Open in new tab",children:"↗"}),s.jsx("button",{style:J.lightboxBtn,onClick:n,"aria-label":"Close",children:"×"})]}),s.jsx("img",{src:i.src,alt:i.alt||"",style:J.lightboxImg}),e.length>1&&s.jsxs("div",{style:J.lightboxNav,children:[s.jsx("button",{style:J.lightboxNavBtn,onClick:()=>l(a=>Math.max(a-1,0)),disabled:r===0,children:"‹"}),s.jsx("button",{style:J.lightboxNavBtn,onClick:()=>l(a=>Math.min(a+1,e.length-1)),disabled:r===e.length-1,children:"›"})]})]})})}function fu({tweet:e,isInThread:t,isLast:n,artifactMap:r}){var d,v;const[l,i]=f.useState(null),a=e.author||{},u=e.created_at_secs?Id(e.created_at_secs):"",o=e.entities||{},c=Bn(a.avatar_local_path,a.avatar_url,r),g=t&&!n,h=e.is_quote_status===!0,m=t?J.tweetRowThread:J.tweetRow,y=e.full_text||"",w=((v=(d=e.extended_entities)==null?void 0:d.media)!=null&&v.length?e.extended_entities.media:o.media)||[],k=[],j=[];for(const x of w)if(x.type==="photo"){const _=Bn(x.local_path,x.media_url_https,r);_&&k.push({kind:"photo",src:_,alt:x.alt_text||""})}else if(x.type==="video"||x.type==="animated_gif"){const _=x.local_path&&r[x.local_path]||(()=>{var C,S;return(S=(((C=x.video_info)==null?void 0:C.variants)||[]).filter(D=>D.content_type==="video/mp4").sort((D,L)=>(L.bitrate||0)-(D.bitrate||0))[0])==null?void 0:S.url})();_&&j.push({kind:x.type==="animated_gif"?"gif":"video",src:_})}const p=[];for(const x of w){if(!x.url||!(x.type==="photo"?k.some(C=>C.src===Bn(x.local_path,x.media_url_https,r)):j.length>0))continue;const b=Qa(x,y,x.url);b&&p.push([b.s,b.e])}return s.jsxs(s.Fragment,{children:[l!==null&&s.jsx(Ad,{items:k,startIndex:l,onClose:()=>i(null)}),s.jsxs("div",{style:m,children:[s.jsxs("div",{style:J.leftCol,children:[c?s.jsx("img",{src:c,style:J.avatar,alt:a.name||""}):s.jsx("div",{style:J.avatarPh}),g&&s.jsx("div",{style:J.threadLine})]}),s.jsxs("div",{style:J.rightCol,children:[s.jsxs("div",{style:J.authorRow,children:[s.jsx("span",{style:J.authorName,children:a.name||a.screen_name||"Unknown"}),a.screen_name&&s.jsxs("span",{style:J.authorHandle,children:["@",a.screen_name]}),u&&s.jsxs("span",{style:J.datePart,children:["· ",u]}),h&&s.jsx("span",{style:J.qtBadge,title:"Quote tweet",children:"↻ QT"})]}),s.jsx("div",{style:J.tweetText,children:Im(y,o,p)}),k.length>0&&s.jsx("div",{style:J.mediaGrid,children:s.jsx(Bm,{photos:k,onOpen:x=>i(x)})}),j.map((x,_)=>s.jsx("div",{style:J.mediaGrid,children:s.jsx("video",{src:x.src,style:J.mediaVideo,controls:!0,loop:x.kind==="gif",muted:x.kind==="gif",autoPlay:x.kind==="gif"})},_)),(e.retweet_count>0||e.favorite_count>0)&&s.jsxs("div",{style:J.stats,children:[e.favorite_count>0&&s.jsxs("span",{children:["❤️ ",e.favorite_count.toLocaleString()]}),e.retweet_count>0&&s.jsxs("span",{children:["🔁 ",e.retweet_count.toLocaleString()]})]})]})]})]})}function Um({archiveId:e,entryUid:t,artifacts:n,entityKind:r,fullPage:l,onXArticle:i}){const[a,u]=f.useState(!0),[o,c]=f.useState(null),[g,h]=f.useState([]);if(f.useEffect(()=>{if(u(!0),c(null),h([]),!n||!e||!t){u(!1);return}const w=n.map((j,p)=>({...j,index:p})).filter(j=>j.artifact_role==="raw_tweet_json");if(w.length===0){c("No tweet data found."),u(!1);return}let k=!1;return xh(e,t,w.map(j=>j.index)).then(async j=>{if(k)return;const p=/https?:\/\/t\.co\/[A-Za-z0-9]+/g,d=C=>{var D;const S=C.full_text||"";return(((D=C.entities)==null?void 0:D.urls)||[]).map(L=>{var H;if(L.fromIndex!=null&&L.toIndex!=null)return[L.fromIndex,L.toIndex];if(((H=L.indices)==null?void 0:H.length)===2)return[L.indices[0],L.indices[1]];if(L.url){const M=S.indexOf(L.url);if(M!==-1)return[M,M+L.url.length]}return null}).filter(Boolean)},v=(C,S,D)=>C.some(([L,H])=>L<=S&&H>=D),x=new Set;for(const C of j){const S=C.full_text||"",D=d(C);let L;for(p.lastIndex=0;(L=p.exec(S))!==null;)v(D,L.index,L.index+L[0].length)||x.add(L[0])}const _=x.size>0?await wh([...x]).catch(()=>({})):{},b=j.map(C=>{var M;const S=C.full_text||"",D=d(C),L=[];let H;for(p.lastIndex=0;(H=p.exec(S))!==null;){const W=H[0],Y=_[W];Y&&Y!==W&&!v(D,H.index,H.index+W.length)&&L.push({url:W,expanded_url:Y,display_url:(()=>{try{const ce=new URL(Y);return ce.hostname+(ce.pathname.length>1?"/…":"")}catch{return Y}})(),fromIndex:H.index,toIndex:H.index+W.length})}return L.length===0?C:{...C,entities:{...C.entities||{},urls:[...((M=C.entities)==null?void 0:M.urls)||[],...L]}}});k||h(b)}).catch(j=>{k||c(j.message||"Failed to load tweet.")}).finally(()=>{k||u(!1)}),()=>{k=!0}},[e,t,n]),a)return s.jsx("div",{style:J.loading,children:"Loading…"});if(o)return s.jsxs("div",{style:J.error,children:["Error: ",o]});if(g.length===0)return null;const m=Dm(e,t,n);if(r==="tweet_thread")return s.jsx("div",{style:J.threadOuter,children:g.map((w,k)=>s.jsx(fu,{tweet:w,isInThread:!0,isLast:k===g.length-1,artifactMap:m},w.id||k))});const y=g[0];return y.is_article&&y.article?s.jsx(Am,{article:y.article,tweetAuthor:y.author,artifactMap:m,fullPage:l,onXArticle:i}):s.jsx("div",{style:J.card,children:s.jsx(fu,{tweet:y,isInThread:!1,isLast:!0,artifactMap:m})})}const Hm=new Set(["mp4","webm","mov","mkv","avi","m4v","ogv"]),Wm=new Set(["mp3","ogg","m4a","opus","wav","flac","aac"]),Vm=new Set(["jpg","jpeg","png","gif","webp","avif","svg","bmp"]);function Bd({archiveId:e,entry:t,detail:n,fullPage:r,onXArticle:l}){if(!t)return s.jsx("div",{className:"preview-panel preview-panel--empty",children:s.jsx("span",{style:{color:"var(--muted)",fontFamily:"var(--sans)",fontSize:"0.9rem"},children:"Select an entry to preview"})});if(!n)return s.jsx("div",{className:"preview-panel preview-panel--loading",children:s.jsx("span",{style:{color:"var(--muted)",fontFamily:"var(--sans)",fontSize:"0.9rem"},children:"Loading…"})});const{summary:i,artifacts:a}=n,u=i.entry_uid,o=i.entity_kind;if(o==="tweet"||o==="tweet_thread"){const y=s.jsx(Um,{archiveId:e,entryUid:u,artifacts:a,entityKind:o,fullPage:r,onXArticle:l});return r?y:s.jsx("div",{className:"preview-tweet-wrap",children:y})}const c=a.findIndex(y=>y.artifact_role==="primary_media");if(c===-1)return s.jsxs("div",{className:"preview-panel preview-panel--no-preview",children:[s.jsx("span",{style:{color:"var(--muted)",fontFamily:"var(--sans)",fontSize:"0.9rem"},children:"No preview available"}),a.length>0&&s.jsx("ul",{style:{marginTop:"12px",paddingLeft:"20px",fontSize:"0.8rem",color:"var(--muted-2)",fontFamily:"var(--sans)"},children:a.map((y,w)=>s.jsxs("li",{children:[y.artifact_role,": ",y.relpath]},w))})]});const g=a[c],h=`/api/archives/${e}/entries/${u}/artifacts/${c}`,m=g.relpath.split(".").pop().toLowerCase();return Hm.has(m)?s.jsx("div",{className:"preview-panel",children:s.jsx(zm,{src:h})}):Wm.has(m)?s.jsxs("div",{className:"preview-panel preview-panel--audio",style:{display:"flex",flexDirection:"column",alignItems:"center",justifyContent:"center",gap:"12px",padding:"24px",fontFamily:"var(--sans)"},children:[s.jsx("span",{style:{fontSize:"2rem"},children:"🎵"}),s.jsx("span",{style:{color:"var(--ink)",fontSize:"0.95rem",fontWeight:600},children:i.title||u}),s.jsx("audio",{src:h,controls:!0,style:{marginTop:"8px",width:"100%",maxWidth:"400px"}})]}):m==="pdf"?s.jsx("div",{className:"preview-panel",style:{flex:1,minHeight:0},children:s.jsx(uu,{src:h,type:"pdf",title:i.title,originalUrl:i.original_url})}):m==="html"||m==="htm"?s.jsx("div",{className:"preview-panel",style:{flex:1,minHeight:0},children:s.jsx(uu,{src:h,type:"page",title:i.title,originalUrl:i.original_url})}):Vm.has(m)?s.jsx("div",{className:"preview-panel",style:{height:"100%"},children:s.jsx(Rm,{src:h,alt:i.title||"Image"})}):s.jsxs("div",{className:"preview-panel preview-panel--no-preview",children:[s.jsx("span",{style:{color:"var(--muted)",fontFamily:"var(--sans)",fontSize:"0.9rem"},children:"No preview available"}),s.jsx("ul",{style:{marginTop:"12px",paddingLeft:"20px",fontSize:"0.8rem",color:"var(--muted-2)",fontFamily:"var(--sans)"},children:a.map((y,w)=>s.jsxs("li",{children:[y.artifact_role,": ",y.relpath]},w))})]})}function Qm({archiveId:e,entry:t,detail:n,onClose:r}){var l,i;return f.useEffect(()=>{const a=u=>{u.key==="Escape"&&r()};return window.addEventListener("keydown",a),()=>window.removeEventListener("keydown",a)},[r]),s.jsx("div",{className:"preview-modal-backdrop",onClick:r,children:s.jsxs("div",{className:`preview-modal${((l=n==null?void 0:n.summary)==null?void 0:l.entity_kind)==="tweet"||((i=n==null?void 0:n.summary)==null?void 0:i.entity_kind)==="tweet_thread"?"":" preview-modal--full"}`,onClick:a=>a.stopPropagation(),children:[s.jsxs("div",{className:"preview-modal-header",children:[s.jsx("span",{className:"preview-modal-title",children:(t==null?void 0:t.title)||(t==null?void 0:t.entry_uid)||"Preview"}),s.jsx("a",{className:"preview-modal-newtab",href:`/preview/${e}/${t==null?void 0:t.entry_uid}`,target:"_blank",rel:"noopener noreferrer",title:"Open in new tab",children:"↗"}),s.jsx("button",{className:"preview-modal-close",onClick:r,"aria-label":"Close preview",children:"×"})]}),s.jsx("div",{className:"preview-modal-body",children:s.jsx(Bd,{archiveId:e,entry:t,detail:n})})]})})}function pu(e){if(!isFinite(e)||isNaN(e))return"--:--";const t=Math.floor(e/60),n=Math.floor(e%60);return`${t}:${String(n).padStart(2,"0")}`}function Km({entry:e,src:t,archiveId:n,onClose:r}){const l=f.useRef(null),[i,a]=f.useState(!1),[u,o]=f.useState(0),[c,g]=f.useState(NaN),[h,m]=f.useState(1);f.useEffect(()=>{!l.current||!t||(l.current.load(),o(0),g(NaN),a(!1))},[t]),f.useEffect(()=>{l.current&&(l.current.volume=h)},[h]);function y(){const d=l.current;d&&(i?d.pause():d.play().catch(()=>{}))}function w(d){const v=l.current;if(!v||!isFinite(c))return;const x=Number(d.target.value);v.currentTime=x,o(x)}function k(d){m(Number(d.target.value))}const j=(e==null?void 0:e.title)||(e==null?void 0:e.entry_uid)||"Unknown",p=(e==null?void 0:e.source_kind)||"other";return s.jsxs(s.Fragment,{children:[s.jsx("audio",{ref:l,src:t||void 0,preload:"auto",onPlay:()=>a(!0),onPause:()=>a(!1),onEnded:()=>a(!1),onTimeUpdate:()=>{var d;return o(((d=l.current)==null?void 0:d.currentTime)??0)},onLoadedMetadata:()=>{var d;return g(((d=l.current)==null?void 0:d.duration)??NaN)},onDurationChange:()=>{var d;return g(((d=l.current)==null?void 0:d.duration)??NaN)},style:{display:"none"}}),s.jsxs("div",{className:"audio-bar",style:{position:"fixed",bottom:0,left:0,right:0,zIndex:100,background:"var(--paper-3)",borderTop:"1px solid var(--line)",display:"flex",alignItems:"center",gap:"16px",padding:"0 16px",height:"56px",fontFamily:"var(--sans)"},children:[s.jsxs("div",{className:"audio-bar-info",style:{display:"flex",alignItems:"center",gap:"8px",minWidth:0,flex:"0 1 220px",overflow:"hidden"},children:[s.jsx("span",{className:"source-icon",style:{flexShrink:0,width:"18px",height:"18px",display:"flex",alignItems:"center"},dangerouslySetInnerHTML:{__html:Va(p)}}),s.jsx("span",{style:{overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap",fontSize:"0.85rem",color:"var(--ink)"},title:j,children:j})]}),s.jsxs("div",{className:"audio-bar-controls",style:{display:"flex",alignItems:"center",gap:"10px",flex:"1 1 0",minWidth:0},children:[s.jsx("button",{onClick:y,"aria-label":i?"Pause":"Play",style:{background:"none",border:"none",cursor:"pointer",padding:"4px",color:"var(--ink)",flexShrink:0,fontSize:"1.2rem",lineHeight:1},children:i?"⏸":"▶"}),s.jsx("span",{style:{fontSize:"0.75rem",color:"var(--muted)",whiteSpace:"nowrap",flexShrink:0},children:pu(u)}),s.jsx("input",{type:"range",min:0,max:isFinite(c)?c:0,step:.1,value:isFinite(u)?u:0,onChange:w,"aria-label":"Seek",style:{flex:1,minWidth:0,accentColor:"var(--accent)"}}),s.jsx("span",{style:{fontSize:"0.75rem",color:"var(--muted)",whiteSpace:"nowrap",flexShrink:0},children:pu(c)})]}),s.jsxs("div",{className:"audio-bar-right",style:{display:"flex",alignItems:"center",gap:"8px",flex:"0 1 160px"},children:[s.jsx("span",{style:{fontSize:"0.85rem",color:"var(--muted)",flexShrink:0},children:"🔊"}),s.jsx("input",{type:"range",min:0,max:1,step:.01,value:h,onChange:k,"aria-label":"Volume",style:{width:"80px",accentColor:"var(--accent)"}}),s.jsx("button",{onClick:r,"aria-label":"Close audio player",style:{background:"none",border:"none",cursor:"pointer",padding:"4px",color:"var(--muted)",fontSize:"1rem",lineHeight:1,marginLeft:"4px"},children:"✕"})]})]})]})}function Xm({archiveId:e,entryUid:t}){var m,y;const[n,r]=f.useState(null),[l,i]=f.useState(!0),[a,u]=f.useState(null),[o,c]=f.useState(!1);f.useEffect(()=>{if(!o)return;const w=document.documentElement,k=document.body,j=w.style.colorScheme,p=k.style.background;return w.style.colorScheme="dark",k.style.background="#000",()=>{w.style.colorScheme=j,k.style.background=p}},[o]),f.useEffect(()=>{c(!1),Xi(e,t).then(w=>{r(w),i(!1)}).catch(w=>{u((w==null?void 0:w.message)||"Failed to load entry"),i(!1)})},[e,t]);const g=((m=n==null?void 0:n.summary)==null?void 0:m.title)||t,h=(y=n==null?void 0:n.summary)==null?void 0:y.original_url;return s.jsxs("div",{style:{minHeight:"100vh",display:"flex",flexDirection:"column",background:o?"#000":"var(--paper)",fontFamily:"var(--sans)"},children:[s.jsxs("div",{style:{display:"flex",alignItems:"center",gap:"10px",padding:o?"8px 12px":"10px 16px",borderBottom:o?"none":"1px solid var(--line)",flexShrink:0,position:o?"sticky":"relative",top:0,zIndex:20,background:o?"rgba(0,0,0,0.82)":"var(--paper-2)",backdropFilter:o?"blur(12px)":"none",WebkitBackdropFilter:o?"blur(12px)":"none"},children:[s.jsx("a",{href:"/",style:{color:o?"#1d9bf0":"var(--accent)",textDecoration:"none",fontSize:"13px",flexShrink:0},children:"← Archive"}),s.jsx("span",{style:{flex:1,fontSize:"14px",fontWeight:600,color:o?"#e7e9ea":"var(--ink)",overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"},children:g}),h&&s.jsx("a",{href:h,target:"_blank",rel:"noopener noreferrer",style:{color:o?"#71767b":"var(--muted)",textDecoration:"none",fontSize:"13px",flexShrink:0},children:"Original ↗"})]}),s.jsxs("div",{style:o?{flex:1}:{flex:1,minHeight:0,overflow:"auto",display:"flex",flexDirection:"column"},children:[l&&s.jsx("div",{style:{padding:"48px",textAlign:"center",color:"var(--muted)",fontSize:"14px"},children:"Loading…"}),a&&s.jsx("div",{style:{padding:"48px",textAlign:"center",color:"var(--alert)",fontSize:"14px"},children:a}),n&&s.jsx(Bd,{archiveId:e,entry:n.summary,detail:n,fullPage:!0,onXArticle:c})]})]})}const Jm=7e3;function qm({toasts:e,onDismiss:t,onIgnoreUblock:n}){return e.length?s.jsx("div",{className:"toast-stack",role:"log","aria-live":"polite","aria-label":"Notifications",children:e.map(r=>s.jsx(Gm,{toast:r,onDismiss:t,onIgnoreUblock:n},r.id))}):null}function Ym(e){if(!e)return null;if(e.length<=52)return e;try{const{hostname:t,pathname:n,search:r}=new URL(e),l=n.split("/").filter(Boolean),i=(l[l.length-1]??"")+r,a=i?`${t}/…/${i}`:t;return a.length<=56?a:a.slice(0,53)+"…"}catch{return"…"+e.slice(-51)}}function Gm({toast:e,onDismiss:t,onIgnoreUblock:n}){const[r,l]=f.useState(!1),i=e.type==="warning",a=e.type==="success";f.useEffect(()=>{if(r)return;const o=setTimeout(()=>t(e.id),Jm);return()=>clearTimeout(o)},[r,e.id,t]);const u=Ym(e.locator);return a?s.jsx("div",{className:"toast toast--success",role:"alert","aria-atomic":"true",children:s.jsxs("div",{className:"toast-top",children:[s.jsx("span",{className:"toast-icon","aria-hidden":"true",children:"✓"}),s.jsxs("div",{className:"toast-body",children:[s.jsx("span",{className:"toast-headline",children:e.headline||"Archived"}),u&&s.jsx("span",{className:"toast-locator",title:e.locator,children:u})]}),s.jsx("div",{className:"toast-btns",children:s.jsx("button",{type:"button",className:"toast-dismiss",onClick:()=>t(e.id),"aria-label":"Dismiss",children:"×"})})]})}):i?s.jsxs("div",{className:"toast toast--warning",role:"alert","aria-atomic":"true",children:[s.jsxs("div",{className:"toast-top",children:[s.jsx("span",{className:"toast-icon","aria-hidden":"true",children:"⚠"}),s.jsxs("div",{className:"toast-body",children:[s.jsx("span",{className:"toast-headline",children:e.headline||"Archived with warnings"}),u&&s.jsx("span",{className:"toast-locator",title:e.locator,children:u})]}),s.jsxs("div",{className:"toast-btns",children:[e.text&&s.jsx("button",{type:"button",className:"toast-view-btn",onClick:()=>l(o=>!o),"aria-expanded":r,children:r?"Hide":"Details"}),e.locator&&s.jsx("button",{type:"button",className:"toast-view-btn toast-ignore-btn",onClick:()=>{n==null||n(),t(e.id)},children:"Ignore"}),s.jsx("button",{type:"button",className:"toast-dismiss",onClick:()=>t(e.id),"aria-label":"Dismiss",children:"×"})]})]}),r&&s.jsx("p",{className:"toast-warning-detail",children:e.text||"The page was captured but one or more browser extensions were unavailable (ad-blocking or cookie-consent). Check ARCHIVR_UBLOCK_EXT and ARCHIVR_COOKIE_EXT in your server config."})]}):s.jsxs("div",{className:"toast toast--error",role:"alert","aria-atomic":"true",children:[s.jsxs("div",{className:"toast-top",children:[s.jsx("span",{className:"toast-icon","aria-hidden":"true",children:"✕"}),s.jsxs("div",{className:"toast-body",children:[s.jsx("span",{className:"toast-headline",children:e.headline||"Capture failed"}),u&&s.jsx("span",{className:"toast-locator",title:e.locator,children:u})]}),s.jsxs("div",{className:"toast-btns",children:[e.text&&s.jsx("button",{type:"button",className:"toast-view-btn",onClick:()=>l(o=>!o),children:r?"Hide":"View error"}),s.jsx("button",{type:"button",className:"toast-dismiss",onClick:()=>t(e.id),"aria-label":"Dismiss",children:"×"})]})]}),r&&e.text&&s.jsx("pre",{className:"toast-error-detail",children:e.text})]})}const vs=f.createContext(null),cr=(()=>{const e=window.location.pathname.match(/^\/preview\/([^/]+)\/([^/]+)/);return e?{archiveId:e[1],entryUid:e[2]}:null})(),Zm=["archive","tags","collections","runs","admin","settings"],eg=["profile","tokens","instance","cookies","extensions","storage"];function tn(){const e=window.location.pathname.split("/").filter(Boolean),t=Zm.includes(e[0])?e[0]:"archive",n=t==="settings"&&eg.includes(e[1])?e[1]:"profile",r=new URLSearchParams(window.location.search),l=r.get("q")??"",i=t==="archive"?r.get("tag")??null:null,a=t==="archive"?r.get("entry")??null:null;return{view:t,settingsTab:n,q:l,tag:i,entry:a}}function tg(e,t){return e==="archive"?"/":e==="settings"?`/settings/${t}`:`/${e}`}function ng(){const[e,t]=f.useState("loading"),[n,r]=f.useState(null);f.useEffect(()=>{(async()=>{if(await Ph()){t("setup");return}const I=await Rh();if(!I){t("login");return}r(I),t("authenticated")})()},[]),f.useEffect(()=>{const N=()=>{r(null),t("login")};return window.addEventListener("auth:expired",N),()=>window.removeEventListener("auth:expired",N)},[]),f.useEffect(()=>{const N=()=>{const{view:I,settingsTab:Q,q:ne,tag:De,entry:lt}=tn();v(I),_(Q),C(ne),p(De),h(lt),y(null),k(lt?new Set([lt]):new Set)};return window.addEventListener("popstate",N),()=>window.removeEventListener("popstate",N)},[]);const[l,i]=f.useState([]),[a,u]=f.useState(null),[o,c]=f.useState([]),[g,h]=f.useState(()=>tn().entry),[m,y]=f.useState(null),[w,k]=f.useState(()=>{const N=tn().entry;return N?new Set([N]):new Set}),[j,p]=f.useState(()=>tn().tag),[d,v]=f.useState(()=>tn().view),[x,_]=f.useState(()=>tn().settingsTab),[b,C]=f.useState(()=>tn().q),[S,D]=f.useState(""),[L,H]=f.useState(!1),[M,W]=f.useState([]),[Y,ce]=f.useState([]),[ie,ee]=f.useState(()=>sessionStorage.getItem("captureDialogOpen")==="true"),[R,T]=f.useState([]),F=f.useRef(0),[q,A]=f.useState(()=>{try{const N=JSON.parse(sessionStorage.getItem("pendingCaptures")||"[]");if(Array.isArray(N))return N}catch{}return[]});f.useEffect(()=>{sessionStorage.setItem("pendingCaptures",JSON.stringify(q))},[q]);const[ge,de]=f.useState(()=>sessionStorage.getItem("ublockWarningIgnored")==="true"),[Re,we]=f.useState(null),je=f.useRef(0),E=f.useRef(null),U=f.useRef(!1),K=f.useRef(!0),V=f.useRef(null),X=(n==null?void 0:n.humanize_slugs)??!1;f.useEffect(()=>{const N=++je.current;we(null),!(!m||!a)&&Xi(a,m.entry_uid).then(I=>{N===je.current&&we(I)}).catch(()=>{})},[m,a]),f.useEffect(()=>{sessionStorage.setItem("captureDialogOpen",ie)},[ie]);const P=f.useCallback(async(N,I,Q)=>{if(N){H(!0);try{let ne;I||Q?ne=await yh(N,I,Q):ne=await vh(N),c(ne),k(De=>{if(De.size<2)return De;const lt=new Set(ne.map(kn=>kn.entry_uid)),Zn=new Set([...De].filter(kn=>lt.has(kn)));return Zn.size===De.size?De:Zn}),D(ne.length===0?"No results":`${ne.length} result${ne.length===1?"":"s"}`)}catch{c([]),D("Search failed. Try again.")}finally{H(!1)}}},[]);f.useEffect(()=>{e==="authenticated"&&gh().then(N=>{if(i(N),N.length>0){const I=N[0].id;u(I)}})},[e]),f.useEffect(()=>{if(a){if(K.current){K.current=!1,Promise.all([Gs(a).then(W),ml(a).then(ce)]);return}p(null),y(null),h(null),k(new Set),Promise.all([P(a,"",null),Gs(a).then(W),ml(a).then(ce)])}},[a]),f.useEffect(()=>{if(a===null)return;const N=setTimeout(()=>{P(a,b,j)},300);return()=>clearTimeout(N)},[b,a]),f.useEffect(()=>{a!==null&&(j!==null&&v("archive"),P(a,b,j))},[j,a]);const B=f.useCallback(N=>{u(N)},[]),re=f.useCallback(N=>{v(N),N==="tags"&&a&&ml(a).then(ce)},[a]);f.useEffect(()=>{if(cr)return;const N=tg(d,x);window.location.pathname!==N&&history.pushState(null,"",N+window.location.search)},[d,x]);const le=f.useCallback(N=>{h(N?N.entry_uid:null),y(N)},[]),rt=f.useCallback((N,I)=>{if(I.shiftKey&&V.current!==null){I.preventDefault();const Q=o.findIndex(er=>er.entry_uid===V.current),ne=o.findIndex(er=>er.entry_uid===N.entry_uid);if(Q===-1||ne===-1){V.current=N.entry_uid,k(new Set([N.entry_uid])),le(N);return}const De=Math.min(Q,ne),lt=Math.max(Q,ne),Zn=o.slice(De,lt+1),kn=new Set(Zn.map(er=>er.entry_uid));k(kn),kn.size===1&&le(Zn[0])}else I.ctrlKey||I.metaKey?(V.current=N.entry_uid,k(Q=>{const ne=new Set(Q);return ne.has(N.entry_uid)?ne.delete(N.entry_uid):ne.add(N.entry_uid),ne})):(V.current=N.entry_uid,k(new Set([N.entry_uid])),le(N))},[o,le]),Me=f.useCallback(N=>{p(N)},[]),ve=f.useCallback(()=>{p(null)},[]),en=f.useCallback(()=>{a&&ml(a).then(ce)},[a]),qe=f.useCallback((N,I)=>{j===N?p(I):j!=null&&j.startsWith(N+"/")&&p(I+j.slice(N.length))},[j]),ys=f.useCallback(N=>{(j===N||j!=null&&j.startsWith(N+"/"))&&p(null)},[j]),xs=f.useCallback((N,I)=>{c(Q=>Q.map(ne=>ne.entry_uid===N?{...ne,title:I}:ne)),y(Q=>Q&&Q.entry_uid===N?{...Q,title:I}:Q),we(Q=>Q&&Q.summary.entry_uid===N?{...Q,summary:{...Q.summary,title:I}}:Q)},[]),ws=f.useCallback(()=>{if(!a||!m)return;const N=++je.current;Xi(a,m.entry_uid).then(I=>{N===je.current&&we(I)}).catch(()=>{})},[a,m]),ks=f.useCallback(N=>{c(I=>I.filter(Q=>Q.entry_uid!==N)),y(I=>(I==null?void 0:I.entry_uid)===N?null:I),h(I=>I===N?null:I),k(I=>{const Q=new Set(I);return Q.delete(N),Q})},[]),js=f.useCallback(N=>{c(I=>I.filter(Q=>!N.has(Q.entry_uid))),k(new Set),y(null),h(null)},[]);f.useEffect(()=>{if(w.size>=2)h(null),y(null);else if(w.size===1){const[N]=w;h(N)}else h(null),y(null)},[w]);const Ss=f.useMemo(()=>o.filter(N=>w.has(N.entry_uid)),[o,w]);f.useEffect(()=>{if(!g||m)return;const N=o.find(I=>I.entry_uid===g);N&&y(N)},[o,g,m]),f.useEffect(()=>{if(cr)return;const N=new URLSearchParams;b&&N.set("q",b),d==="archive"&&j&&N.set("tag",j),d==="archive"&&g&&N.set("entry",g);const I=N.toString(),Q=window.location.pathname+(I?"?"+I:"");window.location.pathname+window.location.search!==Q&&history.replaceState(null,"",Q)},[b,j,g,d]),f.useEffect(()=>{const N=I=>{var Q,ne;(I.metaKey||I.ctrlKey)&&I.key==="k"&&(I.preventDefault(),d==="archive"?((Q=E.current)==null||Q.focus(),(ne=E.current)==null||ne.select()):(U.current=!0,v("archive")))};return document.addEventListener("keydown",N),()=>document.removeEventListener("keydown",N)},[d]),f.useEffect(()=>{d==="archive"&&U.current&&(U.current=!1,requestAnimationFrame(()=>{var N,I;(N=E.current)==null||N.focus(),(I=E.current)==null||I.select()}))},[d]);const yn=f.useCallback(()=>{ee(!0)},[]),xn=f.useCallback(()=>{ee(!1)},[]),Kr=f.useCallback(()=>{if(a)return Promise.all([P(a,b,j),Gs(a).then(W)])},[a,b,j,P]),Xr=f.useCallback((N,I,Q="error",ne=null)=>{if(Q==="warning"&&ge&&I)return;const De=++F.current;T(lt=>[...lt,{id:De,text:N,locator:I,type:Q,headline:ne}])},[ge]),Ns=f.useCallback(N=>{T(I=>I.filter(Q=>Q.id!==N))},[]),_s=f.useCallback(()=>{sessionStorage.setItem("ublockWarningIgnored","true"),de(!0),T(N=>N.filter(I=>!(I.type==="warning"&&I.locator)))},[]),Jr=f.useCallback(N=>{A(I=>[...I,N])},[]),$=f.useCallback(N=>{A(I=>I.filter(Q=>Q.id!==N))},[]),[te,Ae]=f.useState(null),[dt,wn]=f.useState(null),qr=f.useCallback(()=>{m&&Ae(m.entry_uid)},[m]),Se=f.useCallback(()=>Ae(null),[]),Gn=f.useCallback((N,I)=>{wn({src:N,entry:I})},[]),Ud=f.useCallback(()=>wn(null),[]);return f.useEffect(()=>{Ae(null)},[m]),f.useEffect(()=>{const N=I=>{var ne,De,lt;if(I.key!=="Escape"||ie||te)return;const Q=(ne=document.activeElement)==null?void 0:ne.tagName;Q==="INPUT"||Q==="TEXTAREA"||Q==="SELECT"||w.size>0&&(I.preventDefault(),k(new Set),(lt=(De=document.activeElement)==null?void 0:De.blur)==null||lt.call(De))};return window.addEventListener("keydown",N),()=>window.removeEventListener("keydown",N)},[ie,te,w]),f.useEffect(()=>(document.body.classList.toggle("has-audio-bar",!!dt),()=>document.body.classList.remove("has-audio-bar")),[dt]),e==="loading"?s.jsx("div",{className:"auth-loading",children:"Loading\\u2026"}):e==="setup"?s.jsx(im,{onComplete:()=>t("login")}):e==="login"?s.jsx(sm,{onLogin:N=>{r(N),t("authenticated")}}):cr?s.jsx(Xm,{archiveId:cr.archiveId,entryUid:cr.entryUid}):s.jsx(vs.Provider,{value:{currentUser:n,setCurrentUser:r},children:s.jsxs(s.Fragment,{children:[s.jsx(am,{archives:l,archiveId:a,onArchiveChange:B,view:d,onViewChange:re,onCaptureClick:yn}),s.jsxs("main",{className:"app-shell",children:[s.jsxs("div",{className:"workspace",children:[d==="archive"&&s.jsxs("div",{className:"toolbar",children:[s.jsxs("div",{className:"search-field",children:[s.jsx("span",{className:"ico","aria-hidden":"true",children:s.jsxs("svg",{viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",children:[s.jsx("circle",{cx:"11",cy:"11",r:"7"}),s.jsx("line",{x1:"16.5",y1:"16.5",x2:"21",y2:"21"})]})}),s.jsx("input",{ref:E,className:"search-input",type:"search","aria-label":"Search archive","aria-busy":L,placeholder:"Search titles, URLs, types, tags…",value:b,onChange:N=>C(N.target.value)}),s.jsx("span",{className:"kbd",children:"⌘K"})]}),s.jsxs("span",{className:"result-count",children:[S&&s.jsxs(s.Fragment,{children:[s.jsx("b",{children:S.split(" ")[0]})," ",S.split(" ").slice(1).join(" ")]}),j&&s.jsxs("button",{className:"tag-filter-badge",onClick:ve,children:["× ",X?zd(j):j]})]})]}),d==="archive"&&s.jsx(pm,{entries:o,selectedUids:w,onRowClick:rt,archiveId:a,pendingCaptures:q}),d==="runs"&&s.jsx(gm,{runs:M}),d==="admin"&&s.jsx(ym,{archives:l}),d==="tags"&&s.jsx(xm,{archiveId:a,tagNodes:Y,tagFilter:j,onTagFilterSet:Me,onViewChange:re,onTagRenamed:qe,onTagDeleted:ys,onTagsRefresh:en,humanizeTags:X}),d==="collections"&&s.jsx(km,{archiveId:a}),d==="settings"&&s.jsx(Sm,{tab:x,onTabChange:_,archiveId:a})]}),s.jsx(Lm,{archiveId:a,selectedEntry:m,selectedUids:w,selectedEntries:Ss,detail:Re,onTagFilterSet:Me,tagNodes:Y,onTagsRefresh:en,onEntryTitleChange:xs,onEntryDeleted:ks,onBulkDeleted:js,humanizeTags:X,onDetailRefresh:ws,onOpenPreview:qr,onPlay:Gn})]}),te&&m&&m.entry_uid===te&&s.jsx(Qm,{archiveId:a,entry:m,detail:Re,onClose:Se}),dt&&s.jsx(Km,{entry:dt.entry,src:dt.src,archiveId:a,onClose:Ud}),s.jsx(om,{open:ie,archiveId:a,onClose:xn,onCaptured:Kr,onToast:Xr,activeJobs:q,onJobStarted:Jr,onJobSettled:$}),s.jsx(qm,{toasts:R,onDismiss:Ns,onIgnoreUblock:_s})]})})}Cd(document.getElementById("root")).render(s.jsx(f.StrictMode,{children:s.jsx(ng,{})})); diff --git a/crates/archivr-server/static/assets/index-DKombv9L.css b/crates/archivr-server/static/assets/index-DKombv9L.css new file mode 100644 index 0000000..efc8824 --- /dev/null +++ b/crates/archivr-server/static/assets/index-DKombv9L.css @@ -0,0 +1 @@ +@import"https://fonts.googleapis.com/css2?family=Cormorant+Garamond:wght@500;600&family=Spectral:wght@500;600&display=swap";:root{color-scheme:light;--ink: #20251f;--muted: #6b6f66;--muted-2: #8a8d83;--paper: #f5f0e7;--paper-2: #e9e1d2;--paper-3: #fffaf0;--line: #d2c6b5;--line-soft: #e5dccd;--accent: #8d3f30;--accent-2: #b78342;--link: #245f72;--top: #141d18;--field: #fffdf7;--r: 3px;--r2: 6px;--r3: 10px;--sans: "Helvetica Neue", Helvetica, Arial, sans-serif;--serif: "Spectral", Georgia, "Times New Roman", serif;--display: "Cormorant Garamond", Georgia, serif}*{box-sizing:border-box}body{margin:0;min-height:100vh;background:var(--paper);color:var(--ink);font-family:var(--sans);font-size:14px;-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility}button,input,select{font:inherit}.workspace,.context-rail{scrollbar-width:thin;scrollbar-color:var(--line) transparent}.workspace::-webkit-scrollbar,.context-rail::-webkit-scrollbar{width:11px;height:11px}.workspace::-webkit-scrollbar-track,.context-rail::-webkit-scrollbar-track{background:transparent}.workspace::-webkit-scrollbar-thumb,.context-rail::-webkit-scrollbar-thumb{background:var(--line);border-radius:999px;border:3px solid transparent;background-clip:padding-box}.workspace::-webkit-scrollbar-thumb:hover,.context-rail::-webkit-scrollbar-thumb:hover{background:var(--muted-2);background-clip:padding-box;border:3px solid transparent}.topbar{height:58px;display:grid;grid-template-columns:auto auto 1fr auto auto;align-items:center;gap:26px;padding:0 22px;background:var(--top);color:#efe6d6;border-bottom:3px solid var(--accent)}.brand{font-family:var(--display);font-weight:600;font-size:30px;line-height:1;letter-spacing:.01em;color:#f4ead8}.switcher{position:relative;display:inline-flex;align-items:center}.switcher select{-moz-appearance:none;appearance:none;-webkit-appearance:none;border:1px solid rgba(247,238,223,.2);background:#f7eedf0f;color:#f1e8d8;font-family:var(--sans);font-weight:550;font-size:13.5px;letter-spacing:.04em;padding:8px 32px 8px 15px;cursor:pointer;border-radius:6px;transition:background .15s ease,border-color .15s ease}.switcher select:hover{background:#f7eedf1c;border-color:#f7eedf57}.switcher:after{content:"";position:absolute;right:15px;top:50%;width:6px;height:6px;margin-top:-5px;border-right:1.2px solid #b6ab98;border-bottom:1.2px solid #b6ab98;transform:rotate(45deg);pointer-events:none}.nav{display:flex;gap:22px;justify-content:flex-end;min-width:0}.nav-link{border:0;background:transparent;color:#cdc1ad;cursor:pointer;padding:6px 0;font-size:12.5px;font-weight:600;letter-spacing:.1em;text-transform:uppercase;position:relative}.nav-link:hover,.nav-link.is-active{color:#f4ead8}.nav-link.is-active:after{content:"";position:absolute;left:0;right:0;bottom:-2px;height:1px;background:var(--accent-2)}.capture-button{display:inline-flex;align-items:center;gap:8px;position:relative;overflow:hidden;border:0;background:linear-gradient(180deg,color-mix(in srgb,var(--accent) 88%,#fff) 0%,var(--accent) 55%);color:#f7eddd;padding:10px 18px;cursor:pointer;font-size:12px;font-weight:600;letter-spacing:.15em;text-transform:uppercase;border-radius:var(--r);box-shadow:inset 0 1px #fff5e629,0 1px 2px #141d184d;transition:filter .18s ease,box-shadow .18s ease}.capture-button:hover{filter:brightness(.93);box-shadow:inset 0 1px #fff5e61f,0 2px 6px #141d1857}.capture-button:before{content:"";position:absolute;top:0;bottom:0;left:0;width:45%;background:linear-gradient(100deg,transparent 0%,rgba(255,246,232,.45) 50%,transparent 100%);transform:translate(-180%) skew(-18deg);pointer-events:none}@media (prefers-reduced-motion: no-preference){.capture-button:hover:before{animation:cap-sheen .7s ease}}@keyframes cap-sheen{0%{transform:translate(-180%) skew(-18deg)}to{transform:translate(340%) skew(-18deg)}}.app-shell{height:calc(100vh - 58px);display:grid;grid-template-columns:minmax(0,1fr) 340px}.workspace{min-width:0;overflow:auto;display:flex;flex-direction:column}.view{display:none}.view.is-active{display:block}.toolbar{position:sticky;top:0;z-index:3;display:flex;align-items:center;gap:16px;padding:12px 22px;background:color-mix(in srgb,var(--paper) 88%,white);border-bottom:1px solid var(--line-soft)}.search-field{position:relative;flex:1 1 auto;min-width:0;display:flex;align-items:center;height:42px;background:var(--field);border:1px solid var(--line);border-radius:20px;transition:border-color .15s ease,box-shadow .15s ease}.search-field:focus-within{border-color:var(--accent);box-shadow:0 0 0 3px color-mix(in srgb,var(--accent) 14%,transparent)}.search-field .ico{display:grid;place-items:center;width:46px;height:100%;color:var(--muted-2);flex-shrink:0}.search-field .ico svg{width:16px;height:16px}.search-input{flex:1;min-width:0;height:100%;border:0;background:transparent;color:var(--ink);padding:0 6px 0 0;font-size:14px;letter-spacing:.01em;outline:none}.search-input::placeholder{color:var(--muted-2)}.search-field .kbd{margin-right:12px;display:inline-flex;align-items:center;padding:3px 7px;font-size:11px;color:var(--muted);background:var(--paper-2);border:1px solid var(--line-soft);border-radius:var(--r);flex-shrink:0}.result-count{flex-shrink:0;font-size:13px;color:var(--muted);letter-spacing:.02em;white-space:nowrap}.result-count b{color:var(--ink);font-weight:600;font-variant-numeric:tabular-nums}.tag-filter-badge{display:inline-flex;align-items:center;gap:4px;background:var(--accent);color:#fff;border:0;border-radius:var(--r);font-size:12px;padding:2px 8px;cursor:pointer;margin-left:8px}.tag-filter-badge:hover{opacity:.85}.entry-table{width:100%;font-size:12.5px}.entry-header-row{display:flex;align-items:stretch;position:sticky;top:67px;z-index:2;background:color-mix(in srgb,var(--paper) 92%,white);border-bottom:1px solid var(--line-soft);color:var(--muted);font-size:10.5px;text-transform:uppercase;letter-spacing:.08em}.entry-header-row>div{padding:9px 10px;flex-shrink:0;font-weight:600;display:flex;align-items:center}#entries-body>div{display:flex;align-items:center;cursor:default;border-bottom:1px solid var(--line-soft)}#entries-body>div>div{padding:7px 10px;flex-shrink:0;overflow:hidden}#entries-body>div:nth-child(2n){background:#f2ede5}#entries-body>div:nth-child(odd){background:var(--paper-3)}#entries-body>div.is-selected{background:#eee2d2;outline:2px solid var(--accent);outline-offset:-2px}#entries-body>div.is-multi-selected{background:#eee2d2;outline:2px solid var(--accent);outline-offset:-2px}.col-added{width:162px;color:var(--muted)}.col-title{flex:1 1 0;min-width:0;overflow:hidden;display:flex;align-items:center;gap:.42em}.col-type{width:116px}.col-size{width:100px;display:flex;flex-direction:column;justify-content:center;gap:1px}.size-total{font-variant-numeric:tabular-nums}.size-cached-pct{font-size:10px;color:var(--muted);opacity:.8;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.col-url{flex:0 0 30%;min-width:0;overflow:hidden}.entry-header-row .col-added,#entries-body>div .col-added{padding-left:22px}.entry-header-row>div:last-child,#entries-body>div>div:last-child{padding-right:22px}.entry-title{color:var(--link);font-weight:700;min-width:0}.entry-header-row>div{padding:9px 10px;flex-shrink:0;font-weight:600}.source-icon{display:flex;align-items:center;justify-content:center;width:1.05em;height:1.05em;flex-shrink:0}.source-icon>*{width:100%;height:100%;display:flex;align-items:center;justify-content:center}.source-icon svg{width:100%;height:100%}.url-cell{color:#555b55;white-space:nowrap;text-overflow:ellipsis;word-break:break-all}#entries-body .url-cell:hover,#entries-body .is-selected .url-cell{overflow:visible;white-space:normal}.type-pill{display:inline-block;padding:2px 6px;background:#d8e3df;color:#275a5f;border:1px solid #bfd0ca;border-radius:var(--r)}.col-check{display:none;width:40px;flex-shrink:0;align-items:center;justify-content:center;padding:0!important;cursor:pointer}.row-checkbox{-webkit-appearance:none;-moz-appearance:none;appearance:none;padding:0;border:1.5px solid var(--line);cursor:pointer;display:block;width:17px;height:17px;border-radius:4px;background:var(--paper-3);transition:border-color .15s ease,background .15s ease;position:relative;flex-shrink:0}.row-checkbox.is-checked{background:var(--accent);border-color:var(--accent)}.row-checkbox.is-checked:after{content:"";position:absolute;left:4px;top:2px;width:5px;height:8px;border:2px solid #fff;border-top:none;border-left:none;transform:rotate(45deg)}@media (pointer: coarse){.col-check{display:flex}.entry-header-row .col-added,#entries-body>div .col-added{padding-left:10px}}#runs-view .entry-table{border-collapse:collapse;table-layout:auto}#runs-view .entry-table th{position:sticky;top:0;z-index:1;text-align:left;padding:10px;background:color-mix(in srgb,var(--paper) 92%,white);color:var(--muted);border-bottom:1px solid var(--line-soft);font-size:10.5px;text-transform:uppercase;letter-spacing:.08em}#runs-view .entry-table td{padding:10px;border-bottom:1px solid var(--line-soft);vertical-align:top}#runs-view .entry-table tr:nth-child(2n) td{background:#f2ede5}#runs-view .entry-table tr:nth-child(odd) td{background:var(--paper-3)}.context-rail{border-left:1px solid var(--line);background:var(--paper);padding:20px 20px 32px;overflow:auto}.rail-eyebrow{font-size:10.5px;font-weight:600;letter-spacing:.16em;text-transform:uppercase;color:var(--muted-2);margin-bottom:16px}.rail-title{display:block;font-family:var(--sans);font-weight:700;font-size:15.5px;line-height:1.4;color:var(--ink);margin:0 0 16px;word-break:break-word}.url-tile{display:flex;align-items:center;gap:9px;padding:10px 12px;background:var(--paper-3);border:1px solid var(--line);border-radius:var(--r3);margin-bottom:20px;text-decoration:none}.url-tile:hover{background:var(--field);border-color:var(--accent)}.url-tile .ico{color:var(--ink);flex-shrink:0;display:grid;place-items:center}.url-tile .ico svg{width:15px;height:15px}.url-tile .u-text{min-width:0;flex:1;font-size:12.5px;color:var(--link);font-family:ui-monospace,SF Mono,Menlo,monospace;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.url-tile .ext{color:var(--muted-2);flex-shrink:0}.url-tile .ext svg{width:13px;height:13px;display:block}.meta-list{margin-bottom:24px;border-top:1px solid var(--line-soft)}.meta-item{display:grid;grid-template-columns:92px 1fr;gap:14px;align-items:baseline;padding:9px 0;border-bottom:1px solid var(--line-soft)}.meta-k{font-size:10.5px;font-weight:600;text-transform:uppercase;letter-spacing:.06em;color:var(--muted-2)}.meta-v{font-size:13.5px;color:var(--ink);word-break:break-word;line-height:1.4}.meta-v.mono{font-family:ui-monospace,SF Mono,Menlo,monospace;font-size:12px;color:var(--muted)}.rail-section{margin-bottom:24px}.rail-section-heading{display:flex;align-items:baseline;gap:8px;font-size:10.5px;font-weight:600;text-transform:uppercase;letter-spacing:.12em;color:var(--muted-2);margin-bottom:9px;padding-bottom:8px;border-bottom:1px solid var(--line)}.rail-section-heading .num{color:var(--muted-2);font-weight:600}.artifact-list{list-style:none;margin:0;padding:0}.artifact-link{display:flex;align-items:baseline;justify-content:space-between;gap:12px;padding:7px 2px;border-bottom:1px solid var(--line-soft);text-decoration:none}.artifact-link:last-child{border-bottom:0}.artifact-name{font-size:13px;color:var(--link);min-width:0;word-break:break-word}.artifact-link:hover .artifact-name{text-decoration:underline}.artifact-size{font-size:11.5px;color:var(--muted-2);flex-shrink:0;font-variant-numeric:tabular-nums}.artifact-group{list-style:none}.artifact-group-header{width:100%;background:none;border:none;border-bottom:1px solid var(--line-soft);cursor:pointer;text-align:left;color:inherit;font:inherit}.artifact-group-header:hover .artifact-name{text-decoration:underline}.artifact-group-chevron{display:inline-block;font-style:normal;transition:transform .15s ease;transform:rotate(0);transform-origin:45% 50%;margin-right:3px}.artifact-group-chevron.open{transform:rotate(90deg)}.artifact-group-body{padding-left:14px}.tags-wrap{display:flex;flex-wrap:wrap;gap:7px;margin:0 0 12px}.tag-pill{display:inline-flex;align-items:center;gap:7px;background:var(--paper-2);border:1px solid var(--line);border-radius:var(--r);font-size:12px;padding:4px 7px 4px 10px;color:var(--ink)}.tag-pill .remove{border:0;background:transparent;cursor:pointer;color:var(--muted-2);width:15px;height:15px;display:grid;place-items:center;font-size:13px;line-height:1}.tag-pill .remove:hover{color:var(--accent)}.tags-empty{font-size:13px;color:var(--muted);margin:0 0 11px}.tag-input-wrap{display:flex;align-items:center;gap:8px;background:var(--field);border:1px solid var(--line);border-radius:var(--r2);padding:2px 2px 2px 11px;transition:border-color .15s ease,box-shadow .15s ease}.tag-input-wrap:focus-within{border-color:var(--accent);box-shadow:0 0 0 3px color-mix(in srgb,var(--accent) 12%,transparent)}.tag-input-wrap .hash{color:var(--muted-2);font-size:13px}.tag-input{flex:1;min-width:0;border:0;background:transparent;color:var(--ink);font-size:13px;padding:6px 0;outline:none;font-family:ui-monospace,SF Mono,Menlo,monospace}.tag-add-btn{border:0;background:var(--ink);color:var(--paper-3);padding:6px 13px;font-size:11.5px;letter-spacing:.06em;text-transform:uppercase;border-radius:var(--r);cursor:pointer;white-space:nowrap}.tag-add-btn:hover{background:#2c332b}.coll-row{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:9px 13px;background:var(--field);border:1px solid var(--line);border-radius:var(--r2);margin-bottom:6px;transition:border-color .15s ease}.coll-row:hover{border-color:var(--accent)}.coll-name{font-size:13px;color:var(--ink);font-weight:500}.vis-badge{display:inline-flex;align-items:center;gap:6px;font-size:11px;color:var(--muted);background:var(--paper-2);border:1px solid var(--line-soft);border-radius:999px;padding:3px 10px}.vis-badge:before{content:"";width:6px;height:6px;border-radius:50%;background:var(--accent-2)}.bulk-panel{padding-top:2px}.bulk-count{font-size:13px;color:var(--muted);margin-bottom:22px}.bulk-count-num{font-size:22px;font-weight:700;color:var(--ink);line-height:1;margin-right:4px}.bulk-coll-row{display:flex;align-items:center;gap:8px}.bulk-coll-select{flex:1;min-width:0;height:32px;padding:0 8px;border:1px solid var(--line);border-radius:var(--r);background:var(--field);color:var(--ink);font-size:13px;cursor:pointer;outline:none;transition:border-color .15s ease}.bulk-coll-select:focus{border-color:var(--accent)}.tag-add-btn:disabled{opacity:.45;cursor:default}.rail-delete-zone{margin-top:24px;padding-top:20px;border-top:1px solid var(--line-soft)}.rail-delete-btn{width:100%;padding:8px 14px;background:none;border:1px solid color-mix(in srgb,var(--accent) 45%,transparent);color:var(--accent);border-radius:var(--r);cursor:pointer;font-size:12.5px;font-weight:600;letter-spacing:.04em;text-transform:uppercase;transition:background .15s ease,border-color .15s ease}.rail-delete-btn:hover{background:color-mix(in srgb,var(--accent) 8%,transparent);border-color:var(--accent)}.rail-rearchive-btn{width:100%;padding:6px 12px;background:var(--surface-2, #2a2a2a);color:var(--text, #e0e0e0);border:1px solid var(--border, #444);border-radius:4px;cursor:pointer;font-size:13px}.rail-rearchive-btn:hover:not(:disabled){background:var(--surface-3, #333)}.rail-rearchive-btn:disabled{opacity:.6;cursor:not-allowed}.capture-dialog{border:1px solid var(--line);background:var(--paper);padding:0;width:min(540px,calc(100vw - 32px));border-radius:var(--r3);box-shadow:0 20px 60px #141d1847}.capture-dialog::backdrop{background:#141d1873}.capture-dialog-inner{padding:28px}.capture-dialog-title{margin:0;font-size:22px;font-family:var(--display);font-weight:600}.capture-label{display:block;font-size:11px;font-weight:600;margin-bottom:6px;color:var(--muted-2);text-transform:uppercase;letter-spacing:.06em}.capture-input{width:100%;height:44px;border:1px solid var(--line);background:var(--field);color:var(--ink);padding:0 14px;font-size:15px;margin-bottom:10px;border-radius:var(--r2);outline:none;transition:border-color .15s ease,box-shadow .15s ease}.capture-input:focus{border-color:var(--accent);box-shadow:0 0 0 3px color-mix(in srgb,var(--accent) 14%,transparent)}.form-field .capture-input{margin-bottom:0}.capture-error{color:var(--accent);font-size:13px;margin-bottom:10px;min-height:18px}.capture-actions{display:flex;flex-direction:column;gap:8px;margin-top:18px}.capture-submit{border:0;background:var(--ink);color:var(--paper);padding:13px 20px;border-radius:var(--r2);cursor:pointer;font-weight:600;font-size:15px;width:100%;min-width:220px;letter-spacing:.01em}.capture-submit:hover{opacity:.85}.capture-submit:disabled{opacity:.45;cursor:default}.capture-cancel{border:0;background:none;color:var(--muted);padding:7px 18px;border-radius:var(--r);cursor:pointer;font-size:13px;text-align:center;width:100%}.capture-cancel:hover{color:var(--ink);background:var(--paper-2)}.capture-advanced{margin-top:12px}.capture-advanced-toggle{display:flex;align-items:center;gap:5px;background:none;border:0;cursor:pointer;color:var(--muted);font-size:12.5px;padding:4px 0;border-radius:var(--r)}.capture-advanced-toggle:hover{color:var(--ink)}.capture-chevron{width:14px;height:14px;flex-shrink:0;transition:transform .18s ease}.capture-chevron--open{transform:rotate(180deg)}.capture-advanced-panel{margin-top:8px;padding:10px 12px;border:1px solid var(--line);border-radius:var(--r2);background:var(--paper-2)}.capture-ext-row{display:flex;align-items:center;justify-content:space-between;gap:12px;cursor:default}.capture-ext-label{flex:1;min-width:0}.capture-ext-name{display:block;font-size:13px;font-weight:600;color:var(--ink)}.capture-ext-desc{display:block;font-size:11.5px;color:var(--muted);margin-top:1px}.capture-dialog-header{display:flex;align-items:center;justify-content:space-between;margin-bottom:20px}.capture-dialog-close{flex-shrink:0;background:none;border:0;cursor:pointer;color:var(--muted);width:28px;height:28px;display:grid;place-items:center;border-radius:var(--r);padding:0}.capture-dialog-close svg{width:14px;height:14px}.capture-dialog-close:hover{background:var(--paper-2);color:var(--ink)}.capture-rows{display:flex;flex-direction:column;gap:8px;margin-bottom:8px}.capture-row{display:flex;flex-direction:column;gap:3px}.capture-row-main{display:flex;align-items:center;gap:8px}.capture-row-main .capture-input{margin-bottom:0}.capture-quality{flex-shrink:0;height:32px;padding:0 6px;border:1px solid var(--line);border-radius:var(--r);background:var(--paper);color:var(--ink);font-size:12px;cursor:pointer;outline:none;transition:border-color .15s}.capture-quality:hover{border-color:var(--accent-2)}.capture-quality:focus{border-color:var(--accent)}.capture-quality:disabled{opacity:.5;cursor:default}.capture-quality-probing{flex-shrink:0;font-size:12px;color:var(--muted);padding:0 4px;letter-spacing:.05em}.capture-quality-hint{flex-shrink:0;font-size:12px;color:var(--muted);font-style:italic}.cap-dot{flex-shrink:0;width:20px;height:20px;border-radius:50%;display:grid;place-items:center;font-size:10px;font-weight:700;line-height:1}.cap-dot--idle{background:var(--paper-2)}.cap-dot--running{background:#fdefd8;color:#8a4f10}.cap-dot--ok{background:#d8eddf;color:#235c35}.cap-dot--err{background:#f5ddd8;color:#8d3f30}.cap-spinner{display:block;width:10px;height:10px;border:2px solid currentColor;border-top-color:transparent;border-radius:50%;animation:cap-spin .7s linear infinite}@keyframes cap-spin{to{transform:rotate(360deg)}}.capture-row-action{flex-shrink:0;background:none;border:0;cursor:pointer;color:var(--muted);width:28px;height:28px;display:grid;place-items:center;border-radius:var(--r);padding:0}.capture-row-action svg{width:12px;height:12px}.capture-row-action:hover{color:var(--accent);background:var(--paper-2)}.capture-row-remove:hover{color:var(--accent)}.capture-row-error{margin:0;padding-left:28px;font-size:12px;color:var(--accent);line-height:1.45}.capture-add-row{display:flex;align-items:center;gap:7px;width:100%;background:none;border:1px dashed var(--line);border-radius:var(--r);color:var(--muted);font-size:13px;cursor:pointer;padding:7px 12px;margin-top:4px;margin-bottom:18px;transition:border-color .15s,color .15s,background .15s}.capture-add-row svg{width:13px;height:13px;flex-shrink:0}.capture-add-row:hover{border-color:var(--accent-2);color:var(--ink);background:var(--paper-2)}.toast-stack{position:fixed;bottom:24px;right:24px;z-index:9000;display:flex;flex-direction:column;gap:10px;width:340px;max-width:calc(100vw - 32px);pointer-events:none}.toast{pointer-events:auto;background:var(--paper);border:1px solid var(--line);border-radius:var(--r2);box-shadow:0 6px 24px #141d182e,0 1px 4px #141d181a;overflow:hidden;animation:toast-slide-in .22s cubic-bezier(.22,.68,0,1.2)}@keyframes toast-slide-in{0%{opacity:0;transform:translateY(10px) scale(.97)}to{opacity:1;transform:translateY(0) scale(1)}}.toast--error{border-left:3px solid var(--accent)}.toast--warning{border-left:3px solid #e8a000}.toast--success{border-left:3px solid #22a855}.toast-top{display:flex;align-items:flex-start;gap:10px;padding:12px 12px 12px 14px}.toast-icon{flex-shrink:0;font-size:13px;font-weight:700;color:var(--accent);margin-top:2px}.toast--success .toast-icon{color:#22a855}.toast--warning .toast-icon{color:#e8a000}.toast-body{flex:1;min-width:0}.toast-headline{display:block;font-size:13.5px;font-weight:600;color:var(--ink);line-height:1.3}.toast-locator{display:block;font-size:12px;color:var(--muted);margin-top:2px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.toast-btns{display:flex;align-items:center;gap:6px;flex-shrink:0}.toast-view-btn{background:none;border:1px solid var(--line);color:var(--link);font-size:12px;cursor:pointer;padding:3px 9px;border-radius:var(--r);white-space:nowrap}.toast-view-btn:hover{background:var(--paper-2);border-color:var(--link)}.toast-dismiss{background:none;border:0;cursor:pointer;color:var(--muted);font-size:20px;line-height:1;width:24px;height:24px;display:grid;place-items:center;border-radius:var(--r);padding:0}.toast-dismiss:hover{color:var(--ink);background:var(--paper-2)}.toast-error-detail{margin:0;padding:10px 14px 12px;font-family:ui-monospace,SF Mono,Menlo,monospace;font-size:11.5px;line-height:1.55;color:var(--muted);background:var(--paper-2);border-top:1px solid var(--line);white-space:pre-wrap;word-break:break-word;max-height:200px;overflow-y:auto}.toast-warning-detail{margin:0;padding:10px 14px 12px;font-size:12px;line-height:1.55;color:var(--muted);background:var(--paper-2);border-top:1px solid var(--line);white-space:pre-wrap;word-break:break-word}.toast-ignore-btn{color:var(--muted)}.ext-toggle{flex-shrink:0;position:relative;width:44px;height:24px;border-radius:12px;background:var(--line);border:0;cursor:pointer;transition:background .18s ease;padding:0}.ext-toggle--sm{width:36px;height:20px;border-radius:10px}.ext-toggle--on{background:var(--ink)}.ext-toggle:disabled{opacity:.4;cursor:default}.ext-toggle-knob{position:absolute;top:3px;left:3px;width:18px;height:18px;border-radius:50%;background:var(--paper);transition:transform .18s ease;display:block;box-shadow:0 1px 3px #0003}.ext-toggle--sm .ext-toggle-knob{width:14px;height:14px;top:3px;left:3px}.ext-toggle--on .ext-toggle-knob{transform:translate(20px)}.ext-toggle--sm.ext-toggle--on .ext-toggle-knob{transform:translate(16px)}.ext-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(260px,1fr));gap:12px}.ext-card{border:1px solid var(--line);border-radius:var(--r2);padding:16px 18px;background:var(--paper)}.ext-card-header{display:flex;align-items:flex-start;justify-content:space-between;gap:16px}.ext-card-info{flex:1;min-width:0}.ext-card-name{display:block;font-weight:600;font-size:14px;margin-bottom:4px}.ext-card-desc{display:block;font-size:13px;color:var(--muted);line-height:1.5}.ext-card-hint{display:block;font-size:12px;color:#e8a000;margin-top:6px}.ext-card-hint code{font-size:11.5px}.form-hint{font-size:13px;color:var(--muted);line-height:1.55;margin:0}.muted{color:var(--muted)}.admin-view{padding:22px}.admin-list{display:grid;gap:10px;max-width:780px}.admin-archive{border:1px solid var(--line);background:var(--paper-3);padding:12px;border-radius:var(--r2)}.tag-tree{padding:20px 22px;max-width:320px}.tag-tree-header{display:flex;align-items:baseline;gap:10px;margin-bottom:14px;border-bottom:1px solid var(--line-soft);padding-bottom:10px}.tag-tree-title{font-size:11px;font-weight:700;color:var(--muted);text-transform:uppercase;letter-spacing:.07em}.tag-tree-active{font-size:12px;color:var(--muted-2);font-style:italic}.tag-tree-list{list-style:none;margin:0;padding:0}.tag-children{padding-left:16px}.tag-node-btn{border:0;background:transparent;color:var(--link);cursor:pointer;padding:3px 0;text-align:left;font-size:13px;display:block;width:100%}.tag-node-btn:hover{text-decoration:underline}.tag-node-btn.is-active{font-weight:600;color:var(--ink)}.tag-node-row{display:flex;align-items:center;gap:4px}.tag-node-row .tag-node-btn{flex:1 1 0;min-width:0;display:flex;align-items:center;gap:4px;width:auto}.tag-node-btn .edit-icon{width:.75em;height:.75em;flex-shrink:0;vertical-align:-.1em;opacity:.35}.tag-node-btn:hover .edit-icon{opacity:.65}.tag-node-delete{flex-shrink:0;border:0;background:transparent;color:var(--muted-2);cursor:pointer;padding:0 3px;font-size:14px;line-height:1;opacity:0}.tag-node-row:hover .tag-node-delete{opacity:1}.tag-node-delete:hover{color:var(--accent)}.tag-rename-input{font-size:13px;flex:1 1 0;min-width:0;padding:2px 5px;border:1px solid var(--accent);border-radius:var(--r);background:var(--field);color:var(--ink);outline:none}.tag-node-label{flex-shrink:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.tag-node-count{font-size:11px;color:var(--muted-2);font-weight:400;flex-shrink:0;margin-left:3px}.tag-tree-header{align-items:center}.tag-tree-actions{margin-left:auto;display:flex;gap:4px}.tag-tree-action-btn{font-size:11px;padding:2px 7px;border:1px solid var(--line);border-radius:var(--r);background:transparent;color:var(--muted);cursor:pointer;line-height:1.5;white-space:nowrap;transition:background .1s,color .1s}.tag-tree-action-btn:hover:not(:disabled){background:var(--paper-2);color:var(--ink)}.tag-tree-action-btn:disabled{opacity:.4;cursor:default}.tag-tree-action-btn--cancel{border-color:var(--accent);color:var(--accent)}.tag-tree-action-btn--cancel:hover{background:color-mix(in srgb,var(--accent) 8%,transparent)}.tag-tree-title--move{font-style:italic;color:var(--accent-2)}.tag-node-row--move-select .tag-node-btn{cursor:crosshair;color:var(--ink)}.tag-node-row--move-select .tag-node-btn:hover{background:color-mix(in srgb,var(--link) 10%,transparent);text-decoration:none;border-radius:var(--r)}.tag-picker-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:200;background:#00000073;display:flex;align-items:center;justify-content:center;padding:20px}.tag-picker-modal{background:var(--paper);border-radius:var(--r3);box-shadow:0 16px 56px #0000003d;width:300px;max-width:100%;display:flex;flex-direction:column;max-height:60vh}.tag-picker-header{display:flex;align-items:center;padding:12px 14px;border-bottom:1px solid var(--line);flex-shrink:0;gap:8px}.tag-picker-title{flex:1;font-size:13px;font-weight:600;color:var(--ink);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.tag-picker-close{width:26px;height:26px;border-radius:50%;border:none;background:transparent;color:var(--muted-2);font-size:18px;line-height:1;cursor:pointer;display:flex;align-items:center;justify-content:center;flex-shrink:0}.tag-picker-close:hover{background:var(--paper-2);color:var(--ink)}.tag-picker-body{flex:1;min-height:0;overflow-y:auto;padding:8px 12px 12px}.tag-picker-root-btn{display:block;width:100%;text-align:left;padding:5px 8px;margin-bottom:6px;border:1px dashed var(--line);border-radius:var(--r);background:transparent;color:var(--muted);font-size:12px;cursor:pointer}.tag-picker-root-btn:hover{background:var(--paper-2);color:var(--ink);border-color:var(--muted-2)}.tag-picker-tree{border-top:1px solid var(--line-soft);padding-top:6px;margin-top:2px}.tag-picker-node-btn{border:0;background:transparent;color:var(--link);cursor:pointer;padding:3px 6px;text-align:left;font-size:13px;display:block;width:100%;border-radius:var(--r)}.tag-picker-node-btn:hover{background:var(--paper-2);text-decoration:none}.tag-picker-empty{font-size:13px;color:var(--muted-2);margin:6px 0 0}.collections-view{padding:24px}.collections-heading{margin:0 0 16px;font-size:22px;font-family:var(--display);font-weight:600}.collections-error{color:var(--accent);font-size:13px;margin-bottom:8px}.coll-dismiss{background:none;border:none;cursor:pointer;color:var(--accent);font-size:16px;line-height:1;padding:0 4px}.collections-layout{display:grid;grid-template-columns:220px 1fr;gap:0;border:1px solid var(--line);border-radius:var(--r2);min-height:340px}.collections-sidebar{border-right:1px solid var(--line);overflow-y:auto}.coll-sidebar-row{display:flex;flex-direction:column;width:100%;padding:10px 14px;border:none;border-bottom:1px solid var(--line-soft);background:none;cursor:pointer;text-align:left;gap:2px}.coll-sidebar-row:hover{background:var(--paper-2)}.coll-sidebar-row.is-active{background:var(--paper-2);border-left:3px solid var(--accent)}.coll-row-name{font-size:14px;font-weight:600;color:var(--ink)}.coll-row-meta{font-size:11px;color:var(--muted);text-transform:uppercase;letter-spacing:.04em}.coll-detail{padding:20px 24px;display:flex;flex-direction:column;gap:16px}.coll-detail--empty{justify-content:center;align-items:center}.coll-detail-header{display:flex;align-items:center;gap:12px}.coll-detail-name{margin:0;font-size:18px;font-family:var(--display);font-weight:600;flex:1}.coll-detail-name--editable{cursor:pointer}.coll-detail-name--editable:hover{color:var(--link)}.coll-edit-hint{font-size:14px;opacity:.5;margin-left:4px}.coll-rename-input{flex:1;font-size:16px;font-family:var(--display);border:1px solid var(--line);padding:4px 8px;background:var(--field);color:var(--ink);border-radius:var(--r)}.coll-delete-btn{border:1px solid var(--accent);background:none;color:var(--accent);padding:5px 12px;font-size:13px;cursor:pointer;border-radius:var(--r)}.coll-delete-btn:hover{background:var(--accent);color:var(--paper)}.coll-detail-vis{display:flex;align-items:center;gap:10px}.coll-vis-label{font-size:13px;font-weight:600;color:var(--muted);text-transform:uppercase;letter-spacing:.04em;white-space:nowrap}.coll-vis-select{border:1px solid var(--line);background:var(--paper-3);color:var(--ink);padding:4px 8px;font-size:13px;border-radius:var(--r)}.coll-section-heading{font-size:11px;font-weight:700;color:var(--muted);text-transform:uppercase;letter-spacing:.06em;margin-bottom:8px}.coll-entries-section{flex:1}.coll-entries-list{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:2px}.coll-entry-row{display:flex;align-items:center;gap:10px;padding:7px 0;border-bottom:1px solid var(--line-soft)}.coll-entry-info{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px}.coll-entry-title{font-size:14px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.coll-entry-kind{font-size:11px;text-transform:uppercase;letter-spacing:.04em}.coll-entry-actions{display:flex;align-items:center;gap:6px;flex-shrink:0}.coll-entry-vis-select{border:1px solid var(--line);background:var(--paper-3);color:var(--ink);padding:3px 6px;font-size:12px;border-radius:var(--r)}.coll-entry-remove{border:none;background:none;cursor:pointer;color:var(--muted);font-size:18px;line-height:1;padding:0 4px}.coll-entry-remove:hover{color:var(--accent)}.coll-add-entry-form{border-top:1px solid var(--line-soft);padding-top:12px}.coll-add-entry-row{display:flex;gap:8px;align-items:center}.coll-add-entry-input{flex:1;border:1px solid var(--line);background:var(--paper-3);color:var(--ink);padding:6px 10px;font-size:13px;min-width:0;border-radius:var(--r)}.coll-add-btn{border:none;background:var(--ink);color:var(--paper);padding:6px 14px;font-size:13px;font-weight:600;cursor:pointer;white-space:nowrap;border-radius:var(--r)}.coll-add-btn:hover{opacity:.85}.coll-add-btn:disabled{opacity:.45;cursor:default}.auth-loading{min-height:100vh;display:flex;align-items:center;justify-content:center;color:var(--muted);font-size:15px;background:var(--paper)}.user-menu{display:flex;align-items:center;gap:14px;padding-left:6px;flex-shrink:0}.user-name{font-size:12.5px;color:var(--muted-2);letter-spacing:.01em;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:140px}.logout-btn{border:1px solid rgba(255,255,255,.18);background:transparent;color:#c8bfb0;font-size:12px;padding:4px 11px;border-radius:var(--r);cursor:pointer;white-space:nowrap;transition:background .15s,color .15s}.logout-btn:hover{background:#ffffff1a;color:var(--paper)}.logout-btn:disabled{opacity:.5;cursor:default}.login-page,.setup-page{min-height:100vh;display:flex;flex-direction:column;align-items:center;justify-content:center;background:var(--paper)}.login-card,.setup-card{width:100%;max-width:360px;padding:40px 36px 44px;background:var(--paper-3);border:1px solid var(--line);border-radius:var(--r3);box-shadow:0 2px 20px #141d1812}.login-brand,.setup-brand{font-family:var(--display);font-size:32px;font-weight:600;color:var(--ink);letter-spacing:-.01em;margin:0 0 6px}.login-tagline,.setup-tagline{font-size:13px;color:var(--muted);margin:0 0 28px}.login-field,.setup-field{display:flex;flex-direction:column;gap:5px;margin-bottom:14px}.login-label,.setup-label{font-size:11.5px;font-weight:600;color:var(--muted);text-transform:uppercase;letter-spacing:.06em}.login-input,.setup-input{width:100%;border:1px solid var(--line);background:var(--field);color:var(--ink);padding:9px 11px;font-size:14px;border-radius:var(--r2);outline:none;transition:border-color .15s}.login-input:focus,.setup-input:focus{border-color:var(--accent)}.login-error,.setup-error{font-size:13px;color:var(--accent);margin:4px 0 8px}.login-submit,.setup-submit{width:100%;margin-top:8px;border:none;background:var(--top);color:var(--paper);font-size:14px;font-weight:600;padding:11px 16px;border-radius:var(--r2);cursor:pointer;letter-spacing:.02em;transition:opacity .15s}.login-submit:hover,.setup-submit:hover{opacity:.85}.login-submit:disabled,.setup-submit:disabled{opacity:.45;cursor:default}.view-tabs{display:flex;gap:2px;margin-bottom:22px;border-bottom:1px solid var(--line-soft);padding-bottom:0}.view-tab{border:none;background:none;color:var(--muted);font-size:13px;font-weight:600;padding:7px 14px;cursor:pointer;border-bottom:2px solid transparent;margin-bottom:-1px;letter-spacing:.02em;transition:color .12s;text-transform:uppercase;letter-spacing:.06em;font-size:11.5px}.view-tab:hover{color:var(--ink)}.view-tab.is-active{color:var(--ink);border-bottom-color:var(--accent)}.form-section{margin-bottom:32px}.form-section h2{font-size:14px;font-weight:700;color:var(--muted);text-transform:uppercase;letter-spacing:.06em;margin:0 0 14px}.form-row{display:flex;gap:8px;margin-bottom:10px}.form-field{display:flex;flex-direction:column;gap:5px;margin-bottom:12px}.form-label{font-size:11.5px;font-weight:600;color:var(--muted);text-transform:uppercase;letter-spacing:.05em}.field-input{border:1px solid var(--line);background:var(--field);color:var(--ink);padding:8px 10px;font-size:13.5px;border-radius:var(--r);outline:none;transition:border-color .15s;min-width:0}.field-input:focus{border-color:var(--accent)}.field-input--flex{flex:1}.form-msg{font-size:13px;margin:6px 0}.form-msg--ok{color:var(--link)}.form-msg--err{color:var(--accent)}.btn-primary{border:none;background:var(--top);color:var(--paper);font-size:13px;font-weight:600;padding:8px 16px;border-radius:var(--r);cursor:pointer;white-space:nowrap}.btn-primary:hover{opacity:.85}.btn-primary:disabled{opacity:.45;cursor:default}.btn-ghost{border:1px solid var(--line);background:none;color:var(--ink);font-size:13px;padding:7px 14px;border-radius:var(--r);cursor:pointer}.btn-ghost:hover{background:var(--paper-2)}.btn-danger{border:1px solid var(--accent);background:none;color:var(--accent);font-size:13px;padding:7px 14px;border-radius:var(--r);cursor:pointer}.btn-danger:hover{background:var(--accent);color:var(--paper)}.admin-view h1{font-family:var(--display);font-weight:600;font-size:26px;margin:0 0 20px}.admin-table{width:100%;border-collapse:collapse;font-size:13px;margin-bottom:28px}.admin-table th{text-align:left;font-size:11px;font-weight:700;text-transform:uppercase;letter-spacing:.07em;color:var(--muted);padding:8px 10px;border-bottom:1px solid var(--line);background:var(--paper-2)}.admin-table th:first-child{padding-left:16px}.admin-table td{padding:9px 10px;border-bottom:1px solid var(--line-soft);color:var(--ink);vertical-align:middle}.admin-table td:first-child{padding-left:16px}.admin-table tr:hover td{background:var(--paper-2)}.admin-row-disabled td{opacity:.45}.admin-section{margin-bottom:36px;max-width:860px}.admin-section h2{font-size:14px;font-weight:700;color:var(--muted);text-transform:uppercase;letter-spacing:.06em;margin:0 0 14px}.admin-section h3{font-size:13px;font-weight:700;color:var(--muted);text-transform:uppercase;letter-spacing:.05em;margin:22px 0 10px}.admin-form{display:flex;flex-direction:column;gap:8px;max-width:480px}.admin-input{border:1px solid var(--line);background:var(--field);color:var(--ink);padding:8px 10px;font-size:13.5px;border-radius:var(--r);outline:none;transition:border-color .15s}.admin-input:focus{border-color:var(--accent)}.admin-action-btn{border:1px solid var(--line);background:none;color:var(--ink);font-size:12px;padding:4px 10px;border-radius:var(--r);cursor:pointer;white-space:nowrap}.admin-action-btn:hover{border-color:var(--accent);color:var(--accent)}.status-badge{display:inline-block;padding:2px 8px;border-radius:var(--r);font-size:11.5px;font-weight:600;text-transform:uppercase;letter-spacing:.04em}.status-active{background:#d8eddf;color:#235c35;border:1px solid #b4d9be}.status-disabled{background:#ede8e0;color:var(--muted);border:1px solid var(--line)}.run-status{display:inline-block;padding:2px 8px;border-radius:var(--r);font-size:11.5px;font-weight:600;text-transform:uppercase;letter-spacing:.04em}.run-status--completed{background:#d8eddf;color:#235c35;border:1px solid #b4d9be}.run-status--failed{background:#f5ddd8;color:#8d3f30;border:1px solid #e0b8b0}.run-status--in-progress{background:#fdefd8;color:#8a4f10;border:1px solid #f0cfa0}.run-row--failed{cursor:pointer}.run-row--failed:hover td{background:#fdf0ed!important}.run-expand-hint{margin-left:6px;font-size:10px;color:var(--accent);vertical-align:middle}.run-error-row td{padding:0!important;background:var(--paper-2)!important}.run-error-detail{margin:0;padding:10px 16px 12px;font-family:ui-monospace,SF Mono,Menlo,monospace;font-size:11.5px;line-height:1.55;color:var(--muted);white-space:pre-wrap;word-break:break-word;max-height:220px;overflow-y:auto}.token-banner{background:#d8eddf;border:1px solid #b4d9be;padding:12px 14px;margin-bottom:16px;font-size:13px;border-radius:var(--r2)}.token-banner code{word-break:break-all;display:block;margin-top:6px;padding:6px 8px;background:var(--field);border:1px solid var(--line);border-radius:var(--r);font-size:12px;font-family:ui-monospace,SF Mono,Menlo,monospace}.token-dismiss{margin-top:8px;font-size:12px;border:1px solid var(--line);background:none;cursor:pointer;padding:3px 8px;border-radius:var(--r);color:var(--muted)}.token-dismiss:hover{background:var(--paper-2)}.token-row{display:flex;align-items:center;justify-content:space-between;border:1px solid var(--line);background:var(--paper-3);padding:10px 12px;border-radius:var(--r);margin-bottom:6px}.token-row-info strong{font-size:14px;display:block}.token-row-info .muted{font-size:12px;margin-top:2px}.token-create-row{display:flex;gap:8px;margin-bottom:16px}.checkbox-row{display:flex;align-items:center;gap:10px;margin-bottom:12px;cursor:pointer;font-size:14px}.checkbox-row input[type=checkbox]{width:15px;height:15px;accent-color:var(--accent)}.coll-create-details{margin-top:16px}.coll-create-details summary{font-weight:600;cursor:pointer;font-size:13px;color:var(--link);list-style:none;display:flex;align-items:center;gap:6px;padding:8px 12px;border:1px solid var(--line-soft);border-radius:var(--r2);background:var(--paper-3);width:fit-content}.coll-create-details summary:hover{background:var(--paper-2)}.coll-create-details[open] summary{border-bottom-left-radius:0;border-bottom-right-radius:0}.coll-create-form{border:1px solid var(--line-soft);border-top:none;padding:14px;border-radius:0 0 var(--r2) var(--r2);background:var(--paper-3);display:flex;flex-direction:column;gap:10px;max-width:440px}@media (max-width: 900px){.topbar{grid-template-columns:1fr auto;height:auto;min-height:58px;padding:12px}.switcher,.nav{grid-column:1 / -1}.nav{justify-content:flex-start;overflow-x:auto}.app-shell{height:auto;grid-template-columns:1fr}.context-rail{border-left:0;border-top:1px solid var(--line)}.entry-table{min-width:860px}}.rail-title--editable{cursor:pointer}.rail-title--editable:hover{opacity:.75}.rail-title--editable .edit-icon{display:inline-block;width:.75em;height:.75em;margin-left:.35em;vertical-align:middle;opacity:0;transition:opacity .1s;flex-shrink:0}.rail-title--editable:hover .edit-icon{opacity:.5}.rail-title-input{width:100%;font:inherit;font-size:inherit;font-weight:600;background:transparent;border:none;border-bottom:1px solid currentColor;color:inherit;padding:0;margin:0 0 8px;outline:none}.preview-panel{flex:1;display:flex;flex-direction:column;min-height:0}.preview-panel-loading,.preview-panel-empty{flex:1;display:flex;align-items:center;justify-content:center;flex-direction:column;gap:8px;color:var(--muted-2);font-size:14px;text-align:center;padding:24px}.preview-video-wrap{flex:1;display:flex;align-items:center;justify-content:center;background:#0d0d0b;min-height:200px}.preview-video-wrap video{max-width:100%;max-height:100%;width:100%;display:block}.preview-iframe-wrap{flex:1;display:flex;flex-direction:column;min-height:0}.preview-iframe-toolbar{display:flex;flex-direction:column;gap:2px;padding:6px 12px;background:var(--paper-2);border-bottom:1px solid var(--line);flex-shrink:0;text-transform:none;letter-spacing:normal}.preview-iframe-toolbar span{font-size:11px;color:var(--muted-2)}.preview-iframe-toolbar a{margin-left:auto;color:var(--link);font-size:12px;text-decoration:none;padding:3px 8px;border:1px solid var(--line);border-radius:var(--r2);background:var(--field);transition:border-color .12s}.preview-iframe-toolbar a:hover{border-color:var(--accent);text-decoration:none}.preview-iframe-wrap iframe{flex:1;width:100%;border:none;background:#fff;min-height:0}.preview-image-wrap{flex:1;display:flex;align-items:center;justify-content:center;padding:20px;background:var(--paper-2)}.preview-image-wrap img{max-width:100%;max-height:100%;object-fit:contain;border-radius:var(--r3);cursor:zoom-in;display:block;box-shadow:0 4px 24px #0000001a}.preview-tweet-wrap{flex:1;min-height:0;overflow-y:auto;padding:12px 16px;background:var(--paper-2);scrollbar-width:thin;scrollbar-color:var(--line) transparent}.preview-tweet-wrap::-webkit-scrollbar{width:8px}.preview-tweet-wrap::-webkit-scrollbar-track{background:transparent}.preview-tweet-wrap::-webkit-scrollbar-thumb{background:var(--line);border-radius:999px;border:2px solid transparent;background-clip:padding-box}.preview-tweet-wrap::-webkit-scrollbar-thumb:hover{background:var(--muted-2);background-clip:padding-box;border:2px solid transparent}.tw-card{border:1px solid var(--line);border-radius:12px;padding:16px;background:var(--paper);max-width:560px;margin:0 auto 12px}.tw-thread{max-width:560px;margin:0 auto}.tw-thread-item{display:flex;gap:0;margin-bottom:0}.tw-thread-connector{display:flex;flex-direction:column;align-items:center;flex-shrink:0;width:52px;padding-top:2px}.tw-thread-avatar-col{display:flex;flex-direction:column;align-items:center;flex-shrink:0}.tw-thread-line{width:2px;background:var(--line);flex:1;min-height:16px;margin:4px 0}.tw-thread-body{flex:1;min-width:0;padding:0 0 16px 12px}.tw-thread-body:last-child{padding-bottom:0}.tw-avatar{width:40px;height:40px;border-radius:50%;object-fit:cover;flex-shrink:0;display:block}.tw-avatar-ph{width:40px;height:40px;border-radius:50%;background:var(--paper-2);border:1px solid var(--line);flex-shrink:0}.tw-header{display:flex;align-items:baseline;gap:6px;flex-wrap:wrap;margin-bottom:6px}.tw-author-name{font-size:14.5px;font-weight:700;color:var(--ink)}.tw-author-handle{font-size:13px;color:var(--muted-2)}.tw-dot{color:var(--muted-2);font-size:13px}.tw-date{font-size:13px;color:var(--muted-2)}.tw-text{font-size:15px;line-height:1.65;color:var(--ink);white-space:pre-line;word-break:break-word;margin-bottom:10px}.tw-text a{color:var(--link);text-decoration:none}.tw-text a:hover{text-decoration:underline}.tw-stats{display:flex;gap:20px;color:var(--muted-2);font-size:13px;margin-top:10px;padding-top:10px;border-top:1px solid var(--line-soft)}.tw-stats span{display:flex;align-items:center;gap:4px}.tw-article{max-width:598px;margin:0 auto}.tw-article-cover{width:100%;display:block;object-fit:cover;max-height:380px}.tw-article-meta{padding:20px 16px 0}.tw-article-title{font-size:22px;font-weight:800;letter-spacing:-.3px;color:var(--ink);line-height:1.3;margin-bottom:14px}.tw-article-author-row{display:flex;align-items:center;gap:12px;margin-bottom:14px}.tw-article-author-name{font-size:14px;font-weight:700;color:var(--ink)}.tw-article-author-sub{font-size:13px;color:var(--muted-2)}.tw-article-divider{border:none;border-top:1px solid var(--line);margin:0}.tw-article-body{padding:8px 16px 60px}.tw-b-h1{font-size:24px;font-weight:800;letter-spacing:-.3px;color:var(--ink);line-height:1.25;margin:22px 0 10px}.tw-b-h2{font-size:19px;font-weight:700;letter-spacing:-.15px;color:var(--ink);line-height:1.3;margin:20px 0 8px}.tw-b-p{font-size:16px;color:var(--ink);line-height:1.72;margin-bottom:14px}.tw-b-p:empty{display:none}.tw-b-spacer{height:6px;display:block}.tw-b-blockquote{border-left:3px solid var(--line);padding:2px 14px;margin:14px 0;color:var(--muted);font-size:16px;line-height:1.65}.tw-b-hr{border:none;border-top:1px solid var(--line);margin:24px 0}.tw-b-img{width:100%;display:block;border-radius:10px;margin:14px 0}.tw-b-ul,.tw-b-ol{margin:10px 0 14px;padding-left:26px}.tw-b-li{font-size:16px;color:var(--ink);line-height:1.65;margin-bottom:6px}.tw-b-code{font-family:ui-monospace,SF Mono,Menlo,monospace;font-size:.875em;background:var(--paper-2);padding:2px 5px;border-radius:4px;color:var(--ink)}.tw-b-pre{background:var(--paper-2);border:1px solid var(--line);border-radius:8px;padding:14px 16px;overflow-x:auto;margin:12px 0}.tw-b-pre code{font-family:ui-monospace,SF Mono,Menlo,monospace;font-size:13px;line-height:1.6}.tw-b-tweet-link{display:flex;align-items:center;gap:10px;border:1px solid var(--line);border-radius:10px;padding:12px 14px;margin:12px 0;color:var(--muted);font-size:14px;text-decoration:none;background:var(--paper-3);transition:background .12s}.tw-b-tweet-link:hover{background:var(--field)}.tw-b-tweet-link svg{flex-shrink:0;color:var(--ink)}.audio-bar{position:fixed;bottom:0;left:0;right:0;height:72px;background:var(--paper);border-top:1px solid var(--line);display:flex;align-items:center;gap:20px;padding:0 24px;z-index:100;box-shadow:0 -2px 16px #00000014}.audio-bar-info{display:flex;align-items:center;gap:10px;min-width:0;flex:0 0 200px}.audio-bar-icon{flex-shrink:0;width:20px;height:20px;display:flex;align-items:center;justify-content:center}.audio-bar-icon svg{width:20px;height:20px}.audio-bar-title{font-size:13px;color:var(--ink);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;min-width:0;font-weight:500}.audio-bar-controls{flex:1;display:flex;align-items:center;gap:12px;min-width:0}.audio-bar-play-btn{width:38px;height:38px;border-radius:50%;background:var(--accent);color:var(--paper);border:none;cursor:pointer;display:flex;align-items:center;justify-content:center;flex-shrink:0;transition:background .12s,transform .1s}.audio-bar-play-btn:hover{background:var(--accent-2)}.audio-bar-play-btn:active{transform:scale(.93)}.audio-bar-play-btn svg{width:15px;height:15px}.audio-bar-seek{flex:1;min-width:0;display:flex;align-items:center;gap:8px}.audio-bar-seek input[type=range]{flex:1;accent-color:var(--accent);height:4px;cursor:pointer;min-width:0}.audio-bar-time{font-size:11.5px;color:var(--muted-2);white-space:nowrap;min-width:80px;text-align:right;font-variant-numeric:tabular-nums}.audio-bar-right{flex:0 0 auto;display:flex;align-items:center;gap:10px}.audio-bar-volume{display:flex;align-items:center;gap:6px}.audio-bar-volume svg{width:14px;height:14px;color:var(--muted-2);flex-shrink:0}.audio-bar-volume input[type=range]{width:72px;accent-color:var(--accent);cursor:pointer}.audio-bar-close{width:28px;height:28px;border-radius:50%;border:none;background:transparent;color:var(--muted-2);cursor:pointer;display:flex;align-items:center;justify-content:center;font-size:18px;padding:0;line-height:1;transition:background .12s,color .12s}.audio-bar-close:hover{background:var(--field);color:var(--ink)}.preview-modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:200;background:#0000008c;display:flex;align-items:center;justify-content:center;padding:20px}.preview-modal{background:var(--paper);border-radius:12px;box-shadow:0 24px 80px #00000047;width:90vw;max-width:1100px;max-height:88vh;display:flex;flex-direction:column;overflow:hidden}.preview-modal--full{height:88vh}.preview-modal--full .preview-modal-body{max-height:none}.preview-modal-header{display:flex;align-items:center;padding:14px 18px;border-bottom:1px solid var(--line);flex-shrink:0;gap:12px}.preview-modal-title{flex:1;min-width:0;font-size:14px;font-weight:600;color:var(--ink);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.preview-modal-close{width:30px;height:30px;border-radius:50%;border:none;background:transparent;color:var(--muted-2);font-size:20px;line-height:1;cursor:pointer;display:flex;align-items:center;justify-content:center;flex-shrink:0;transition:background .12s,color .12s}.preview-modal-close:hover{background:var(--field);color:var(--ink)}.preview-modal-body{flex:1;min-height:0;overflow:hidden;display:flex;flex-direction:column;max-height:calc(88vh - 52px)}.rail-preview-btn{display:block;width:100%;padding:8px 12px;margin-bottom:16px;background:var(--accent);color:var(--paper);border:none;border-radius:var(--r3);font-size:13px;font-weight:600;cursor:pointer;text-align:center;transition:background .12s}.rail-preview-btn:hover{background:var(--accent-2)}.preview-modal-newtab{display:flex;align-items:center;justify-content:center;width:28px;height:28px;border-radius:var(--r2);color:var(--muted-2);text-decoration:none;font-size:16px;flex-shrink:0;transition:background .12s,color .12s}.preview-modal-newtab:hover{background:var(--field);color:var(--ink)}body.has-audio-bar{padding-bottom:56px}@keyframes skeleton-shimmer{0%{background-position:200% center}to{background-position:-200% center}}.skeleton-cell{display:inline-block;border-radius:3px;background:linear-gradient(90deg,var(--paper-2) 25%,var(--line-soft) 50%,var(--paper-2) 75%);background-size:200% 100%;animation:skeleton-shimmer 1.8s ease-in-out infinite}.skeleton-row{display:flex;align-items:center;background:var(--paper-3)}.skeleton-row>div{padding:7px 10px;flex-shrink:0;overflow:hidden}.skeleton-row .col-added{padding-left:22px}.skeleton-row>div:last-child{padding-right:22px}@media (pointer: coarse){.skeleton-row .col-added{padding-left:10px}} diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx index eaf90a0..3f4c258 100644 --- a/frontend/src/App.jsx +++ b/frontend/src/App.jsx @@ -107,6 +107,18 @@ export default function App() { const [toasts, setToasts] = useState([]) const toastIdRef = useRef(0) + const [pendingCaptures, setPendingCaptures] = useState(() => { + try { + const saved = JSON.parse(sessionStorage.getItem('pendingCaptures') || '[]') + if (Array.isArray(saved)) return saved + } catch {} + return [] + }) + + useEffect(() => { + sessionStorage.setItem('pendingCaptures', JSON.stringify(pendingCaptures)) + }, [pendingCaptures]) + const [ublockWarningIgnored, setUblockWarningIgnored] = useState( () => sessionStorage.getItem('ublockWarningIgnored') === 'true' ) @@ -424,7 +436,7 @@ export default function App() { const handleCaptured = useCallback(() => { if (!archiveId) return - Promise.all([ + return Promise.allSettled([ loadEntries(archiveId, searchQuery, tagFilter), fetchRuns(archiveId).then(setRuns), ]) @@ -447,6 +459,15 @@ export default function App() { setUblockWarningIgnored(true) setToasts(prev => prev.filter(t => !(t.type === 'warning' && t.locator))) }, []) + + const handleJobStarted = useCallback((record) => { + setPendingCaptures(prev => [...prev, record]) + }, []) + + const handleJobSettled = useCallback((id) => { + setPendingCaptures(prev => prev.filter(c => c.id !== id)) + }, []) + const [previewEntryUid, setPreviewEntryUid] = useState(null) const [currentAudio, setCurrentAudio] = useState(null) @@ -541,6 +562,7 @@ export default function App() { selectedUids={selectedUids} onRowClick={handleRowClick} archiveId={archiveId} + pendingCaptures={pendingCaptures} /> )} {view === 'runs' && } @@ -605,6 +627,9 @@ export default function App() { onClose={handleCaptureClose} onCaptured={handleCaptured} onToast={handleToast} + activeJobs={pendingCaptures} + onJobStarted={handleJobStarted} + onJobSettled={handleJobSettled} /> diff --git a/frontend/src/components/CaptureDialog.jsx b/frontend/src/components/CaptureDialog.jsx index 1099c3f..3878303 100644 --- a/frontend/src/components/CaptureDialog.jsx +++ b/frontend/src/components/CaptureDialog.jsx @@ -74,11 +74,7 @@ function makeItem(locator = '') { } } -function hasActiveJobs(items) { - return items.some(it => it.status === 'submitting' || it.status === 'running') -} - -export default function CaptureDialog({ open, archiveId, onClose, onCaptured, onToast }) { +export default function CaptureDialog({ open, archiveId, onClose, onCaptured, onToast, onJobStarted, onJobSettled, activeJobs = [] }) { const dialogRef = useRef(null) const isFirstRenderRef = useRef(true) // jobUid → intervalId; survives dialog close since component stays mounted @@ -97,13 +93,20 @@ export default function CaptureDialog({ open, archiveId, onClose, onCaptured, on useEffect(() => { onCapturedRef.current = onCaptured }, [onCaptured]) useEffect(() => { onToastRef.current = onToast }, [onToast]) + const onJobStartedRef = useRef(onJobStarted) + const onJobSettledRef = useRef(onJobSettled) + useEffect(() => { onJobStartedRef.current = onJobStarted }, [onJobStarted]) + useEffect(() => { onJobSettledRef.current = onJobSettled }, [onJobSettled]) + const [items, setItems] = useState(() => { try { const saved = JSON.parse(sessionStorage.getItem('captureItems') || 'null') if (Array.isArray(saved) && saved.length > 0) { - // Ensure nextItemId stays ahead of restored ids - saved.forEach(it => { if (it.id >= nextItemId) nextItemId = it.id + 1 }) - return saved + const idle = saved.filter(it => !it.status || it.status === 'idle') + if (idle.length > 0) { + idle.forEach(it => { if (it.id >= nextItemId) nextItemId = it.id + 1 }) + return idle + } } } catch {} return [makeItem()] @@ -142,24 +145,20 @@ export default function CaptureDialog({ open, archiveId, onClose, onCaptured, on // Reader mode: off by default, per-session only const [readerMode, setReaderMode] = useState(false) - // On mount: clean up old single-locator sessionStorage keys; reconnect running jobs + // On mount: clean up old single-locator sessionStorage keys; reconnect running bg jobs useEffect(() => { ;['captureDialogLocator','captureDialogError','captureDialogBusy', 'captureDialogJobStatus','captureDialogJobUid'].forEach(k => sessionStorage.removeItem(k)) - setItems(prev => prev.map(it => - // 'submitting' means page was refreshed mid-fetch — reset to idle so user can retry - it.status === 'submitting' ? { ...it, status: 'idle', error: null } : it - )) - - // Reconnect polling for any jobs still running from a previous session - items.forEach(it => { - if (it.status === 'running' && it.jobUid && it.archiveId && !pollIntervals.current.has(it.jobUid)) { - startPolling(it.id, it.jobUid, it.locator, it.archiveId) + // Reconnect polling for any bg jobs still running from a previous session. + // activeJobs is read from the initial prop value (App's sessionStorage-seeded state). + activeJobs.forEach(job => { + if (job.jobUid && !pollIntervals.current.has(job.jobUid)) { + startPolling(job.id, job.jobUid, job.locator, job.archiveId, null) } }) // eslint-disable-next-line react-hooks/exhaustive-deps - }, []) // intentionally runs once on mount with initial values + }, []) // Handle native dialog 'close' event (Escape key or programmatic .close()) useEffect(() => { @@ -174,12 +173,12 @@ export default function CaptureDialog({ open, archiveId, onClose, onCaptured, on return () => dialog.removeEventListener('close', handler) }, [onClose]) - // Open/close driven by parent; don't reset if active jobs are in flight + // Open/close driven by parent; always reset form on reopen useEffect(() => { const dialog = dialogRef.current if (!dialog) return if (open) { - if (!isFirstRenderRef.current && !hasActiveJobs(items)) { + if (!isFirstRenderRef.current) { setItems([makeItem()]) } isFirstRenderRef.current = false @@ -199,22 +198,16 @@ export default function CaptureDialog({ open, archiveId, onClose, onCaptured, on } }, []) - function startPolling(itemId, jobUid, locator, aid, batchId = null) { - if (pollIntervals.current.has(jobUid)) return // already polling + function startPolling(bgJobId, jobUid, locator, aid, batchId = null) { + if (pollIntervals.current.has(jobUid)) return const intervalId = setInterval(async () => { try { const updated = await pollCaptureJob(aid, jobUid) if (updated.status === 'completed') { clearInterval(pollIntervals.current.get(jobUid)) pollIntervals.current.delete(jobUid) - setItems(prev => prev.map(it => it.id === itemId ? { ...it, status: 'completed' } : it)) - setTimeout(() => { - setItems(prev => { - const next = prev.filter(it => it.id !== itemId) - return next.length === 0 ? [makeItem()] : next - }) - }, 1400) - onCapturedRef.current() + await Promise.resolve(onCapturedRef.current?.()) + onJobSettledRef.current?.(bgJobId) try { const notes = updated.notes_json ? JSON.parse(updated.notes_json) : null if (notes?.ublock_skipped || notes?.cookie_ext_skipped) { @@ -237,10 +230,8 @@ export default function CaptureDialog({ open, archiveId, onClose, onCaptured, on } else if (updated.status === 'failed') { clearInterval(pollIntervals.current.get(jobUid)) pollIntervals.current.delete(jobUid) + onJobSettledRef.current?.(bgJobId) const errText = updated.error_text || 'Capture failed.' - setItems(prev => prev.map(it => - it.id === itemId ? { ...it, status: 'failed', error: errText } : it - )) onToastRef.current(errText, locator) settleBatch(batchId, 'failed', locator) } @@ -248,10 +239,8 @@ export default function CaptureDialog({ open, archiveId, onClose, onCaptured, on } catch (e) { clearInterval(pollIntervals.current.get(jobUid)) pollIntervals.current.delete(jobUid) + onJobSettledRef.current?.(bgJobId) const msg = e.message || 'Network error' - setItems(prev => prev.map(it => - it.id === itemId ? { ...it, status: 'failed', error: msg } : it - )) onToastRef.current(msg, locator) settleBatch(batchId, 'failed', locator) } @@ -294,31 +283,31 @@ export default function CaptureDialog({ open, archiveId, onClose, onCaptured, on onToastRef.current(text, null, type, headline) } - - async function submitItem(item, batchId = null) { - if (!item.locator.trim()) return - const aid = archiveId - const loc = item.locator.trim() - const qual = item.quality || 'best' - setItems(prev => prev.map(it => it.id === item.id ? { ...it, status: 'submitting', error: null } : it)) + async function submitBgJob(locator, quality, batchId) { + const aid = archiveIdRef.current + const id = crypto.randomUUID?.() ?? `job-${Date.now()}-${Math.random()}` + // Capture session options at call time (synchronous — before first await) + const extensions = { + ublock_enabled: ublockEnabled, + reader_mode: readerMode, + cookie_ext_enabled: cookieExtEnabled, + modal_closer_enabled: modalCloserEnabled, + via_freedium: freediumEnabled, + } try { - const extensions = { ublock_enabled: ublockEnabled, reader_mode: readerMode, cookie_ext_enabled: cookieExtEnabled, modal_closer_enabled: modalCloserEnabled, via_freedium: freediumEnabled } - const job = await submitCapture(aid, loc, qual, extensions) - setItems(prev => prev.map(it => - it.id === item.id ? { ...it, status: 'running', jobUid: job.job_uid, archiveId: aid } : it - )) - startPolling(item.id, job.job_uid, loc, aid, batchId) + const job = await submitCapture(aid, locator, quality, extensions) + // Notify App to add skeleton + persist + onJobStartedRef.current?.({ id, jobUid: job.job_uid, locator, archiveId: aid }) + startPolling(id, job.job_uid, locator, aid, batchId) } catch (e) { const msg = e.message || 'Submission failed.' - setItems(prev => prev.map(it => it.id === item.id ? { ...it, status: 'failed', error: msg } : it)) - onToastRef.current(msg, loc) - settleBatch(batchId, 'failed', loc) + onToastRef.current(msg, locator) + settleBatch(batchId, 'failed', locator) } } - function handleArchive() { - const toSubmit = items.filter(it => it.status === 'idle' && it.locator.trim()) + const toSubmit = items.filter(it => it.locator.trim()) if (toSubmit.length === 0) return const batchId = toSubmit.length > 1 ? (crypto.randomUUID?.() ?? `batch-${Date.now()}`) @@ -326,8 +315,13 @@ export default function CaptureDialog({ open, archiveId, onClose, onCaptured, on if (batchId) { batchRef.current.set(batchId, { total: toSubmit.length, archived: 0, warnings: 0, failed: 0, failedLocators: [], warningLocators: [] }) } - toSubmit.forEach(it => submitItem(it, batchId)) + // Capture options at call time before any state changes + const capturedQuality = toSubmit.map(it => it.quality || 'best') + // Reset form and close dialog immediately + setItems([makeItem()]) dialogRef.current?.close() + // Submit each in background + toSubmit.forEach((it, i) => submitBgJob(it.locator.trim(), capturedQuality[i], batchId)) } function addRow() { @@ -343,12 +337,6 @@ export default function CaptureDialog({ open, archiveId, onClose, onCaptured, on }) } - function resetRow(id) { - setItems(prev => prev.map(it => - it.id === id ? { ...it, status: 'idle', error: null } : it - )) - } - function updateLocator(id, val) { // Cancel any in-flight debounce and immediately clear stale probe results. // This prevents old qualities from being visible (and submittable) while @@ -390,8 +378,7 @@ export default function CaptureDialog({ open, archiveId, onClose, onCaptured, on setItems(prev => prev.map(it => it.id === id ? { ...it, quality: val } : it)) } - const pendingCount = items.filter(it => it.status === 'idle' && it.locator.trim()).length - const anyActive = hasActiveJobs(items) + const pendingCount = items.filter(it => it.locator.trim()).length return ( @@ -415,11 +402,10 @@ export default function CaptureDialog({ open, archiveId, onClose, onCaptured, on updateLocator(item.id, val)} onQualityChange={val => updateQuality(item.id, val)} onRemove={() => removeRow(item.id)} - onReset={() => resetRow(item.id)} onSubmit={handleArchive} /> ))} @@ -549,7 +535,7 @@ export default function CaptureDialog({ open, archiveId, onClose, onCaptured, on {pendingCount > 1 ? `Archive ${pendingCount}` : 'Archive'} @@ -557,19 +543,17 @@ export default function CaptureDialog({ open, archiveId, onClose, onCaptured, on ) } -function CaptureRow({ item, autoFocus, onLocatorChange, onQualityChange, onRemove, onReset, onSubmit }) { +function CaptureRow({ item, autoFocus, onLocatorChange, onQualityChange, onRemove, onSubmit }) { const inputRef = useRef(null) - const isActive = item.status === 'submitting' || item.status === 'running' useEffect(() => { - if (autoFocus && item.status === 'idle') { + if (autoFocus) { inputRef.current?.focus() } }, [autoFocus]) // eslint-disable-line react-hooks/exhaustive-deps - // Quality control shown right of the input (hidden when active or completed) + // Quality control shown right of the input const qualityEl = (() => { - if (item.status === 'completed' || isActive) return null if (!isVideoSource(item.locator)) return null if (item.probeState === 'probing') { return @@ -611,9 +595,8 @@ function CaptureRow({ item, autoFocus, onLocatorChange, onQualityChange, onRemov })() return ( -
+
- onLocatorChange(e.target.value)} onKeyDown={e => { if (e.key === 'Enter') onSubmit() }} - disabled={isActive || item.status === 'completed'} autoComplete="off" spellCheck={false} /> {qualityEl} - {item.status === 'failed' && ( - - )} - {!isActive && item.status !== 'completed' && item.status !== 'failed' && ( - - )} +
{item.error && (

{item.error}

@@ -649,20 +621,3 @@ function CaptureRow({ item, autoFocus, onLocatorChange, onQualityChange, onRemov
) } - -function CapStatusDot({ status }) { - if (status === 'submitting' || status === 'running') { - return ( - - - - ) - } - if (status === 'completed') { - return - } - if (status === 'failed') { - return - } - return