Download index.html from rafmacalaba/datause-extraction-webgpu: direct link, hf CLI and curl.
- Browser
- Download file 67.2 kB
-
https://huggingface.co/spaces/rafmacalaba/datause-extraction-webgpu/resolve/main/index.html
- Command line
-
hf download hf://spaces/rafmacalaba/datause-extraction-webgpu/index.html
-
curl -L -o index.html https://huggingface.co/spaces/rafmacalaba/datause-extraction-webgpu/resolve/main/index.html
67.2 kB
| <html lang="en"> | |
| <head> | |
| <meta charset="utf-8" /> | |
| <meta name="viewport" content="width=device-width, initial-scale=1" /> | |
| <title>Data-use extraction — WebGPU demo</title> | |
| <script> | |
| (function () { | |
| try { | |
| if (localStorage.getItem("datause-theme") === "dark") { | |
| document.documentElement.setAttribute("data-theme", "dark"); | |
| } | |
| } catch (e) {} | |
| })(); | |
| </script> | |
| <link rel="preconnect" href="https://fonts.googleapis.com" /> | |
| <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin /> | |
| <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&family=JetBrains+Mono:wght@400;500;600&display=swap" rel="stylesheet" /> | |
| <style> | |
| :root { | |
| --bg: #eaf3fb; | |
| --bg-dot: #d6dee8; | |
| --grad-1: #e9f4fc; | |
| --grad-2: #b9dcef; | |
| --grad-3: #7cc1e8; | |
| --grad-4: #009cde; | |
| --grad-glow: rgba(0, 156, 222, 0.28); | |
| --grad-haze: rgba(255, 255, 255, 0.65); | |
| --surface: #ffffff; | |
| --surface-2: #f1f5f9; | |
| --surface-3: #e7eef6; | |
| --text: #0f172a; | |
| --text-muted: #475569; | |
| --text-subtle: #64748b; | |
| --border: #e2e8f0; | |
| --border-strong: #cbd5e1; | |
| --accent: #002244; | |
| --accent-2: #009cde; | |
| --accent-hover: #00172e; | |
| --accent-soft: rgba(0, 156, 222, 0.10); | |
| --accent-glow: rgba(0, 156, 222, 0.35); | |
| --wb: #009cde; | |
| --ok: #16a34a; | |
| --warn: #d97706; | |
| --err: #dc2626; | |
| --err-soft: rgba(220, 38, 38, 0.08); | |
| --btn-fg: #ffffff; | |
| --log-bg: #0b1220; | |
| --log-fg: #cbd5e1; | |
| --cat-fur: #ede7dc; | |
| --cat-fur-shadow: #d8cfbe; | |
| --cat-inner: #ffc7d6; | |
| --cat-eye: #1a1a1a; | |
| --cat-pupil: #ede7dc; | |
| --cat-nose: #ff7a8a; | |
| --cat-z: #94a3b8; | |
| --cat-sparkle: #009cde; | |
| --na: #1d4ed8; --na-bg: #dbeafe; | |
| --de: #002244; --de-bg: #e7edf5; | |
| --va: #475569; --va-bg: #f1f5f9; | |
| --radius: 16px; | |
| --radius-sm: 10px; | |
| --radius-lg: 20px; | |
| --shadow-sm: 0 1px 2px rgba(15, 23, 42, 0.04); | |
| --shadow: 0 1px 3px rgba(15, 23, 42, 0.06), 0 12px 32px -16px rgba(15, 23, 42, 0.18); | |
| --shadow-lg: 0 4px 6px rgba(15, 23, 42, 0.05), 0 24px 48px -20px rgba(15, 23, 42, 0.25); | |
| --font: "Inter", system-ui, -apple-system, sans-serif; | |
| --mono: "JetBrains Mono", ui-monospace, monospace; | |
| --ease: cubic-bezier(0.22, 1, 0.36, 1); | |
| } | |
| [data-theme="dark"] { | |
| --bg: #05080d; | |
| --bg-dot: #1c2333; | |
| --grad-1: #07142a; | |
| --grad-2: #0e2a4f; | |
| --grad-3: #155184; | |
| --grad-4: #009cde; | |
| --grad-glow: rgba(0, 156, 222, 0.22); | |
| --grad-haze: rgba(125, 211, 252, 0.10); | |
| --surface: #0c1119; | |
| --surface-2: #131a23; | |
| --surface-3: #1a2230; | |
| --text: #f1f5f9; | |
| --text-muted: #94a3b8; | |
| --text-subtle: #64748b; | |
| --border: #1e293b; | |
| --border-strong: #334155; | |
| --accent: #38bdf8; | |
| --accent-2: #38bdf8; | |
| --accent-hover: #7dd3fc; | |
| --accent-soft: rgba(56, 189, 248, 0.12); | |
| --accent-glow: rgba(56, 189, 248, 0.35); | |
| --wb: #38bdf8; | |
| --ok: #4ade80; | |
| --warn: #fbbf24; | |
| --err: #f87171; | |
| --err-soft: rgba(248, 113, 113, 0.12); | |
| --btn-fg: #05080d; | |
| --log-bg: #020617; | |
| --log-fg: #94a3b8; | |
| --cat-fur: #f5ebd7; | |
| --cat-fur-shadow: #d8c8a8; | |
| --cat-inner: #ff9eb5; | |
| --cat-eye: #0a0e0f; | |
| --cat-pupil: #f5ebd7; | |
| --cat-nose: #ff7a8a; | |
| --cat-z: #64748b; | |
| --cat-sparkle: #38bdf8; | |
| --na: #93c5fd; --na-bg: rgba(59, 130, 246, 0.18); | |
| --de: #cbd5e1; --de-bg: rgba(203, 213, 225, 0.10); | |
| --va: #94a3b8; --va-bg: rgba(148, 163, 184, 0.15); | |
| --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.3); | |
| --shadow: 0 1px 3px rgba(0, 0, 0, 0.4), 0 12px 32px -16px rgba(0, 0, 0, 0.5); | |
| --shadow-lg: 0 4px 6px rgba(0, 0, 0, 0.4), 0 24px 48px -20px rgba(0, 0, 0, 0.6); | |
| } | |
| *, *::before, *::after { box-sizing: border-box; } | |
| html { scroll-behavior: smooth; } | |
| body { | |
| margin: 0; | |
| font-family: var(--font); | |
| background-color: var(--bg); | |
| background-image: | |
| radial-gradient(ellipse 70% 55% at 18% 12%, var(--grad-haze), transparent 62%), | |
| radial-gradient(ellipse 60% 50% at 92% 88%, var(--grad-glow), transparent 70%), | |
| linear-gradient(165deg, var(--grad-1) 0%, var(--grad-2) 45%, var(--grad-3) 88%, var(--grad-4) 130%); | |
| background-attachment: fixed; | |
| color: var(--text); | |
| line-height: 1.55; | |
| -webkit-font-smoothing: antialiased; | |
| -moz-osx-font-smoothing: grayscale; | |
| transition: background-color 0.3s var(--ease), color 0.3s var(--ease); | |
| } | |
| .num { font-variant-numeric: tabular-nums; } | |
| .wrap { max-width: 1200px; margin: 0 auto; padding: 1.75rem 1.5rem 4rem; } | |
| /* Loader ---------------------------------------------------------- */ | |
| .loader { | |
| position: fixed; inset: 0; z-index: 100; | |
| background-color: var(--bg); | |
| background-image: | |
| radial-gradient(ellipse 70% 55% at 18% 12%, var(--grad-haze), transparent 62%), | |
| radial-gradient(ellipse 60% 50% at 92% 88%, var(--grad-glow), transparent 70%), | |
| linear-gradient(165deg, var(--grad-1) 0%, var(--grad-2) 45%, var(--grad-3) 88%, var(--grad-4) 130%); | |
| background-attachment: fixed; | |
| display: flex; align-items: center; justify-content: center; | |
| transition: opacity .55s var(--ease), visibility .55s; | |
| } | |
| .loader.hidden { opacity: 0; visibility: hidden; pointer-events: none; } | |
| .loader-theme-toggle { | |
| position: absolute; top: 24px; right: 28px; z-index: 101; | |
| display: inline-flex; align-items: center; gap: 0.5rem; | |
| font-family: var(--mono); font-size: 11px; letter-spacing: 0.1em; | |
| text-transform: uppercase; | |
| color: var(--text-muted); background: var(--surface); | |
| border: 1px solid var(--border); border-radius: 999px; | |
| padding: 0.5rem 0.85rem; cursor: pointer; | |
| box-shadow: var(--shadow-sm); | |
| transition: color .2s var(--ease), border-color .2s var(--ease); | |
| } | |
| .loader-theme-toggle:hover { color: var(--text); border-color: var(--accent-2); } | |
| .loader-theme-toggle svg { width: 14px; height: 14px; } | |
| .loader-inner { width: min(1120px, 94vw); text-align: left; } | |
| .loader-layout { | |
| display: grid; | |
| grid-template-columns: minmax(0, 1.1fr) minmax(200px, 0.85fr) minmax(0, 1fr); | |
| align-items: center; | |
| gap: clamp(1.5rem, 4vw, 3.25rem); | |
| } | |
| .loader-copy { min-width: 0; } | |
| .loader-visual { | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| position: relative; | |
| } | |
| .loader-about { | |
| min-width: 0; | |
| padding-left: clamp(1rem, 2vw, 1.5rem); | |
| border-left: 1px solid var(--border); | |
| } | |
| .loader-about h2 { | |
| margin: 0 0 0.85rem; | |
| font-family: var(--mono); font-size: 12px; letter-spacing: 0.18em; | |
| text-transform: uppercase; color: var(--text-muted); font-weight: 600; | |
| } | |
| .loader-about p { | |
| margin: 0 0 0.85rem; color: var(--text-muted); | |
| font-size: 0.82rem; line-height: 1.6; | |
| } | |
| .loader-about p b { color: var(--text); font-weight: 600; } | |
| .loader-about ul { | |
| margin: 0; padding: 0; list-style: none; | |
| display: grid; gap: 0.5rem; | |
| } | |
| .loader-about li { | |
| display: flex; gap: 0.6rem; align-items: flex-start; | |
| font-family: var(--mono); font-size: 0.72rem; letter-spacing: 0.02em; | |
| color: var(--text-muted); line-height: 1.5; | |
| } | |
| .loader-about li::before { | |
| content: "—"; color: var(--accent-2); flex: none; | |
| } | |
| .loader-about .privacy { | |
| display: flex; gap: 0.55rem; align-items: flex-start; | |
| margin-top: 1rem; padding-top: 0.85rem; | |
| border-top: 1px solid var(--border); | |
| color: var(--text-subtle); font-size: 0.72rem; line-height: 1.5; | |
| } | |
| .loader-about .privacy svg { | |
| width: 14px; height: 14px; flex: none; margin-top: 0.1rem; | |
| color: var(--accent-2); | |
| } | |
| .loader-about .privacy b { color: var(--text); font-weight: 600; } | |
| .cat-sculpture { | |
| width: 100%; | |
| max-width: 280px; | |
| height: auto; | |
| max-height: min(52vh, 360px); | |
| filter: drop-shadow(0 16px 36px rgba(0, 0, 0, 0.42)); | |
| transition: transform 0.3s var(--ease); | |
| } | |
| .cat-sculpture:hover { | |
| transform: scale(1.02) translateY(-2px); | |
| } | |
| .loader-brand { | |
| display: inline-flex; align-items: center; gap: .7rem; | |
| font-family: var(--mono); font-size: 12px; letter-spacing: .24em; | |
| text-transform: uppercase; margin-bottom: 2.2rem; color: var(--text-muted); | |
| } | |
| .loader-brand::before { | |
| content: ""; display: inline-block; | |
| width: 8px; height: 8px; border-radius: 50%; | |
| background: var(--accent-2); box-shadow: 0 0 14px var(--accent-glow); | |
| animation: pulse 1.4s ease-in-out infinite; | |
| } | |
| .loader-pct { | |
| font-family: var(--mono); font-size: 72px; font-weight: 500; line-height: 1; | |
| color: var(--text); letter-spacing: -.03em; font-variant-numeric: tabular-nums; | |
| } | |
| .loader-pct i { margin-left: .12em; color: var(--text-subtle); font-size: .36em; font-style: normal; font-weight: 400; } | |
| .loader-rule { | |
| position: relative; width: 100%; height: 3px; margin: 20px 0 14px; | |
| background: var(--surface-2); border-radius: 999px; overflow: hidden; | |
| } | |
| .loader-rule i { | |
| position: absolute; inset: 0 auto 0 0; display: block; width: 0%; | |
| background: linear-gradient(90deg, var(--accent), var(--accent-2)); | |
| box-shadow: 0 0 14px var(--accent-glow); | |
| transition: width .3s var(--ease); border-radius: 999px; | |
| } | |
| .loader-status { | |
| font-family: var(--mono); font-size: 12.5px; letter-spacing: .18em; | |
| text-transform: uppercase; color: var(--text); font-variant-numeric: tabular-nums; | |
| font-weight: 600; | |
| } | |
| .loader-truth { margin: 8px 0 0; color: var(--text-muted); font-family: var(--mono); font-size: 12px; letter-spacing: .02em; } | |
| .loader-cta { | |
| display: inline-flex; align-items: center; justify-content: center; gap: .55rem; | |
| min-width: 220px; margin-top: 2.2rem; | |
| font: inherit; font-family: var(--mono); font-size: 13px; letter-spacing: .14em; | |
| text-transform: uppercase; font-weight: 600; | |
| color: #071512; background: var(--accent-2); | |
| border: none; border-radius: var(--radius-sm); | |
| padding: 0.9rem 1.5rem; cursor: pointer; | |
| box-shadow: 0 0 18px var(--accent-glow); | |
| transition: background .18s var(--ease), transform .06s ease, box-shadow .18s var(--ease), opacity .3s var(--ease), color .3s var(--ease); | |
| } | |
| .loader-cta:hover:not(:disabled) { background: var(--accent); box-shadow: 0 0 26px var(--accent-glow); } | |
| .loader-cta:active:not(:disabled) { transform: translateY(1px); } | |
| .loader-cta:disabled { | |
| opacity: 0.35; cursor: not-allowed; box-shadow: none; | |
| background: var(--surface-3); color: var(--text-subtle); | |
| } | |
| @keyframes pulse { 50% { opacity: 0.35; transform: scale(0.85); } } | |
| @media (max-width: 720px) { | |
| .loader-layout { grid-template-columns: 1fr; gap: 1.2rem; } | |
| .loader-visual { order: -1; } | |
| .cat-sculpture { max-width: 170px; max-height: 22vh; } | |
| .loader-brand { margin-bottom: 1.2rem; } | |
| .loader-pct { font-size: 54px; } | |
| .loader-cta { margin-top: 1.4rem; width: 100%; } | |
| .loader-theme-toggle { top: 16px; right: 16px; } | |
| .loader-about { border-left: none; padding-left: 0; } | |
| .loader-about p, .loader-about li { font-size: 0.7rem; } | |
| } | |
| /* Header ---------------------------------------------------------- */ | |
| header { | |
| display: flex; align-items: center; justify-content: space-between; gap: 1.5rem; | |
| margin-bottom: 1.75rem; | |
| padding-bottom: 1.5rem; | |
| border-bottom: 1px solid var(--border); | |
| } | |
| .brand { display: flex; align-items: center; gap: .9rem; min-width: 0; } | |
| .brand-mark { | |
| width: 42px; height: 42px; border-radius: 12px; | |
| background: linear-gradient(135deg, var(--accent), var(--accent-2)); | |
| display: flex; align-items: center; justify-content: center; | |
| color: #ffffff; | |
| box-shadow: 0 6px 20px -6px var(--accent-glow), inset 0 1px 0 rgba(255,255,255,0.22); | |
| flex: none; | |
| } | |
| .brand-mark svg { width: 22px; height: 22px; } | |
| .brand-text { min-width: 0; } | |
| .brand-text h1 { | |
| margin: 0; font-size: 0.98rem; font-weight: 700; | |
| font-family: var(--mono); | |
| letter-spacing: 0.16em; | |
| text-transform: uppercase; | |
| color: var(--text); | |
| } | |
| .brand-text .sub { | |
| margin: 3px 0 0; color: var(--text-muted); font-size: 0.72rem; | |
| font-family: var(--mono); letter-spacing: 0.08em; | |
| text-transform: uppercase; | |
| white-space: nowrap; overflow: hidden; text-overflow: ellipsis; | |
| } | |
| .header-actions { display: flex; align-items: center; gap: 0.6rem; flex: none; } | |
| .icon-btn, .status-pill { | |
| display: inline-flex; align-items: center; gap: 0.5rem; | |
| font-size: 0.8rem; font-weight: 500; color: var(--text-muted); | |
| background: var(--surface); border: 1px solid var(--border); | |
| border-radius: 999px; padding: 0.45rem 0.9rem; white-space: nowrap; | |
| box-shadow: var(--shadow-sm); | |
| transition: color .2s var(--ease), border-color .2s var(--ease); | |
| } | |
| .icon-btn { cursor: pointer; font-family: var(--font); } | |
| .icon-btn:hover { color: var(--text); border-color: var(--border-strong); } | |
| .icon-btn svg { display: block; } | |
| .status-dot { | |
| width: 8px; height: 8px; border-radius: 50%; background: var(--border-strong); flex: none; | |
| transition: background .2s var(--ease); | |
| } | |
| .status-pill.ready { color: var(--text); } | |
| .status-pill.ready .status-dot { background: var(--ok); box-shadow: 0 0 10px rgba(22, 163, 74, 0.4); } | |
| .status-pill.err { color: var(--text); } | |
| .status-pill.err .status-dot { background: var(--err); box-shadow: 0 0 10px rgba(220, 38, 38, 0.4); } | |
| .status-pill.busy { color: var(--text); } | |
| .status-pill.busy .status-dot { background: var(--warn); animation: pulse 1.2s ease-in-out infinite; } | |
| /* Pipeline step indicator ----------------------------------------- */ | |
| .pipeline { | |
| display: flex; align-items: center; gap: 0; | |
| margin-bottom: 1.5rem; | |
| background: var(--surface); border: 1px solid var(--border); | |
| border-radius: var(--radius); box-shadow: var(--shadow-sm); | |
| padding: 0.95rem 1.25rem; | |
| overflow-x: auto; | |
| } | |
| .step { display: flex; align-items: center; gap: 0.65rem; flex: 1; min-width: 0; } | |
| .step-num { | |
| width: 26px; height: 26px; border-radius: 50%; | |
| background: var(--surface-2); color: var(--text-muted); | |
| display: flex; align-items: center; justify-content: center; | |
| font-family: var(--mono); font-size: 11px; font-weight: 600; | |
| border: 1.5px solid var(--border); | |
| flex: none; transition: all .2s var(--ease); | |
| } | |
| .step-text { font-size: 0.78rem; color: var(--text-muted); font-weight: 500; white-space: nowrap; } | |
| .step-text b { color: var(--text); font-weight: 600; } | |
| .step-arrow { flex: none; color: var(--text-subtle); margin: 0 0.75rem; display: flex; align-items: center; } | |
| .step-arrow svg { display: block; } | |
| .step.active .step-num { background: var(--accent); color: var(--btn-fg); border-color: var(--accent); box-shadow: 0 0 14px var(--accent-glow); } | |
| .step.active .step-text { color: var(--text); } | |
| .step.done .step-num { background: var(--ok); color: white; border-color: var(--ok); } | |
| /* Models strip — bento tiles --------------------------------------- */ | |
| .models-strip { | |
| display: grid; | |
| grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); | |
| gap: 1rem; | |
| margin-bottom: 1.5rem; | |
| } | |
| .model-card { | |
| position: relative; | |
| display: flex; flex-direction: column; gap: 0.7rem; | |
| background: var(--surface); border: 1px solid var(--border); | |
| border-radius: var(--radius); padding: 1.15rem 1.25rem; | |
| text-decoration: none; color: var(--text); | |
| box-shadow: var(--shadow-sm); | |
| transition: border-color .2s var(--ease), box-shadow .2s var(--ease); | |
| overflow: hidden; | |
| } | |
| .model-card::before { | |
| content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 3px; | |
| background: linear-gradient(180deg, var(--accent), var(--accent-2)); | |
| opacity: 0; transition: opacity .2s var(--ease); | |
| } | |
| .model-card:hover { border-color: var(--border-strong); box-shadow: var(--shadow); } | |
| .model-card:hover::before { opacity: 1; } | |
| .model-card-top { display: flex; align-items: center; justify-content: space-between; gap: 0.5rem; } | |
| .model-card-name { display: flex; align-items: center; gap: 0.6rem; font-weight: 600; font-size: 0.95rem; min-width: 0; } | |
| .model-card-name-icon { | |
| width: 28px; height: 28px; border-radius: 8px; | |
| background: var(--surface-2); color: var(--accent-2); | |
| display: flex; align-items: center; justify-content: center; flex: none; | |
| } | |
| .model-role { | |
| font-size: 0.62rem; font-weight: 600; text-transform: uppercase; letter-spacing: 0.06em; | |
| color: var(--accent-2); background: var(--accent-soft); | |
| border-radius: 999px; padding: 0.22rem 0.6rem; | |
| font-family: var(--mono); flex: none; | |
| } | |
| .model-card-repo { | |
| font-family: var(--mono); font-size: 0.74rem; color: var(--text); | |
| overflow-wrap: anywhere; | |
| } | |
| .model-card-repo .repo-ns { color: var(--text-muted); } | |
| .model-card-file { | |
| font-family: var(--mono); font-size: 0.7rem; color: var(--text-muted); | |
| overflow-wrap: anywhere; padding-left: 0.9rem; | |
| } | |
| /* Status bar ------------------------------------------------------- */ | |
| .status-bar { | |
| display: flex; align-items: center; gap: 1rem; flex-wrap: wrap; | |
| background: var(--surface); border: 1px solid var(--border); | |
| border-radius: var(--radius); box-shadow: var(--shadow-sm); | |
| padding: 0.85rem 1.1rem; margin-bottom: 1.5rem; | |
| } | |
| .status-bar-label { | |
| font-size: 0.82rem; color: var(--text-muted); min-width: 0; flex: 1 1 240px; | |
| display: flex; align-items: center; gap: .55rem; | |
| } | |
| .status-bar-label .label-icon { color: var(--text-subtle); flex: none; } | |
| .status-bar-label b { color: var(--text); font-family: var(--mono); font-weight: 500; } | |
| .status-readout { | |
| flex: 1 1 280px; min-width: 0; | |
| display: flex; flex-direction: column; gap: 0.5rem; | |
| } | |
| .status-readout-head { | |
| display: flex; align-items: center; gap: 0.55rem; | |
| font-family: var(--mono); font-size: 0.7rem; | |
| text-transform: uppercase; letter-spacing: 0.18em; | |
| color: var(--text-sub); | |
| } | |
| .status-readout-head .label-icon { color: var(--text-subtle); flex: none; } | |
| .status-readout-head b { color: var(--text); font-weight: 500; } | |
| .status-readout-pct { | |
| margin-left: auto; | |
| color: var(--text); font-weight: 600; font-size: 0.88rem; | |
| letter-spacing: 0.04em; | |
| } | |
| .status-readout-rule { | |
| position: relative; height: 1px; background: var(--border-strong); | |
| overflow: hidden; | |
| } | |
| .status-readout-rule i { | |
| position: absolute; inset: 0 auto 0 0; display: block; width: 0%; | |
| background: linear-gradient(90deg, var(--accent), var(--accent-2)); | |
| box-shadow: 0 0 8px var(--accent-glow); | |
| transition: width .3s var(--ease); | |
| } | |
| .status-readout-status { | |
| font-family: var(--mono); font-size: 0.78rem; | |
| color: var(--text); font-variant-numeric: tabular-nums; | |
| white-space: nowrap; overflow: hidden; text-overflow: ellipsis; | |
| } | |
| /* Chips ----------------------------------------------------------- */ | |
| .chip { | |
| display: inline-flex; align-items: center; gap: 0.4rem; | |
| font: inherit; font-size: 0.78rem; font-weight: 500; | |
| color: var(--text); background: var(--surface); | |
| border: 1px solid var(--border); border-radius: 999px; | |
| padding: 0.4rem 0.85rem; cursor: pointer; | |
| transition: color .15s var(--ease), border-color .15s var(--ease), background .15s var(--ease); | |
| font-family: var(--font); | |
| } | |
| .chip:hover { border-color: var(--accent-2); color: var(--accent); background: var(--accent-soft); } | |
| .chip svg { display: block; } | |
| /* Sample selector & Segmented Controls ----------------------------- */ | |
| .sample-controls { | |
| display: flex; | |
| align-items: center; | |
| justify-content: space-between; | |
| gap: 0.75rem; | |
| flex-wrap: wrap; | |
| } | |
| .sample-seg { | |
| display: inline-flex; | |
| padding: 3px; | |
| background: var(--surface-2); | |
| border: 1px solid var(--border); | |
| border-radius: 9px; | |
| } | |
| .sample-seg-btn { | |
| font: inherit; | |
| font-family: var(--mono); | |
| font-size: 0.68rem; | |
| font-weight: 600; | |
| padding: 0.35rem 0.75rem; | |
| border: none; | |
| background: transparent; | |
| color: var(--text-muted); | |
| border-radius: 6px; | |
| cursor: pointer; | |
| transition: color .15s var(--ease), background .15s var(--ease), box-shadow .15s var(--ease); | |
| letter-spacing: 0.08em; | |
| text-transform: uppercase; | |
| } | |
| .sample-seg-btn:hover:not(.active) { color: var(--text); } | |
| .sample-seg-btn.active { | |
| background: var(--surface); | |
| color: var(--text); | |
| box-shadow: var(--shadow-sm); | |
| } | |
| .sample-shuffle-btn { | |
| display: inline-flex; | |
| align-items: center; | |
| gap: 0.4rem; | |
| font: inherit; | |
| font-family: var(--mono); | |
| font-size: 0.68rem; | |
| font-weight: 600; | |
| letter-spacing: 0.08em; | |
| text-transform: uppercase; | |
| padding: 0.35rem 0.7rem; | |
| color: var(--accent-2); | |
| background: var(--surface-2); | |
| border: 1px solid var(--border); | |
| border-radius: 7px; | |
| cursor: pointer; | |
| transition: all .15s var(--ease); | |
| } | |
| .sample-shuffle-btn:hover { | |
| background: var(--accent-soft); | |
| border-color: var(--accent-2); | |
| color: var(--accent); | |
| box-shadow: 0 0 12px var(--accent-glow); | |
| } | |
| .sample-shuffle-btn svg { width: 13px; height: 13px; } | |
| .samples-group { | |
| display: flex; | |
| flex-wrap: wrap; | |
| gap: 0.45rem; | |
| margin-top: 0.15rem; | |
| } | |
| .samples-group[hidden] { display: none; } | |
| .samples-group-label { | |
| flex-basis: 100%; | |
| font-family: var(--mono); | |
| font-size: 0.6rem; | |
| font-weight: 600; | |
| letter-spacing: 0.14em; | |
| text-transform: uppercase; | |
| color: var(--text-subtle); | |
| } | |
| .sample-chip { | |
| display: inline-flex; | |
| align-items: center; | |
| gap: 0.4rem; | |
| font: inherit; | |
| font-family: var(--mono); | |
| font-size: 0.72rem; | |
| font-weight: 500; | |
| letter-spacing: 0.02em; | |
| color: var(--text-muted); | |
| background: var(--surface-2); | |
| border: 1px solid var(--border); | |
| border-radius: 8px; | |
| padding: 0.38rem 0.75rem; | |
| cursor: pointer; | |
| transition: all .15s var(--ease); | |
| } | |
| .sample-chip:hover { | |
| color: var(--text); | |
| border-color: var(--accent-2); | |
| background: var(--accent-soft); | |
| } | |
| .sample-chip.active { | |
| color: var(--text); | |
| background: var(--surface); | |
| border-color: var(--accent-2); | |
| box-shadow: 0 0 12px var(--accent-glow); | |
| font-weight: 600; | |
| } | |
| /* Bento main grid -------------------------------------------------- */ | |
| .bento { | |
| display: grid; | |
| grid-template-columns: 1fr 1fr; | |
| gap: 1.25rem; | |
| margin-bottom: 1.25rem; | |
| } | |
| @media (max-width: 900px) { .bento { grid-template-columns: 1fr; } } | |
| .card { | |
| background: var(--surface); border: 1px solid var(--border); | |
| border-radius: var(--radius); box-shadow: var(--shadow-sm); | |
| padding: 1.5rem; | |
| display: flex; flex-direction: column; gap: 1rem; | |
| min-width: 0; | |
| } | |
| .card-head { display: flex; align-items: center; justify-content: space-between; gap: 1rem; } | |
| .card-head h2 { | |
| margin: 0; font-size: 0.7rem; font-weight: 600; | |
| text-transform: uppercase; letter-spacing: 0.1em; | |
| color: var(--text-muted); | |
| } | |
| .badge-pill { | |
| font-family: var(--mono); font-size: 0.62rem; font-weight: 500; | |
| color: var(--text-subtle); background: var(--surface-2); | |
| padding: 0.22rem 0.55rem; border-radius: 6px; | |
| letter-spacing: 0.04em; text-transform: uppercase; | |
| } | |
| .card-hint { margin: 0; color: var(--text-muted); font-size: 0.82rem; line-height: 1.55; } | |
| /* Segmented toggle ------------------------------------------------ */ | |
| .seg-toggle { | |
| display: inline-flex; padding: 3px; | |
| background: var(--surface-2); border: 1px solid var(--border); | |
| border-radius: 9px; | |
| } | |
| .seg-opt { | |
| font: inherit; font-family: var(--font); | |
| font-size: 0.68rem; font-weight: 600; | |
| padding: 0.32rem 0.72rem; border: none; background: transparent; | |
| color: var(--text-muted); border-radius: 6px; cursor: pointer; | |
| transition: color .15s var(--ease), background .15s var(--ease), box-shadow .15s var(--ease); | |
| letter-spacing: 0.02em; | |
| } | |
| .seg-opt:hover:not(:disabled) { color: var(--text); } | |
| .seg-opt.active { | |
| background: var(--surface); color: var(--text); | |
| box-shadow: var(--shadow-sm); | |
| } | |
| .seg-opt:focus-visible { outline: none; box-shadow: 0 0 0 2px var(--accent-2); } | |
| .seg-opt:disabled { opacity: 0.45; cursor: not-allowed; } | |
| /* Results panes -------------------------------------------------- */ | |
| .results-host { display: contents; } | |
| .result-pane { display: block; } | |
| .result-pane[hidden] { display: none; } | |
| .result-json .json-meta, .result-trace .json-meta { | |
| display: flex; flex-wrap: wrap; gap: 0.5rem 1rem; | |
| font-family: var(--mono); font-size: 0.72rem; | |
| color: var(--text-muted); margin-bottom: 0.7rem; | |
| padding-bottom: 0.6rem; | |
| border-bottom: 1px dashed var(--border); | |
| } | |
| .result-json .json-meta b, .result-trace .json-meta b { color: var(--text); font-weight: 600; } | |
| .result-json pre, .result-trace pre { | |
| margin: 0; padding: 1rem 1.1rem; | |
| background: #0b1220; color: #cbd5e1; | |
| border: 1px solid var(--border); border-radius: var(--radius-sm); | |
| font-family: var(--mono); font-size: 0.78rem; line-height: 1.65; | |
| white-space: pre-wrap; word-break: break-word; | |
| max-height: 36rem; overflow: auto; | |
| font-variant-numeric: tabular-nums; | |
| tab-size: 2; | |
| } | |
| [data-theme="dark"] .result-json pre, [data-theme="dark"] .result-trace pre { background: #020617; } | |
| .result-json .jk, .result-trace .jk { color: #7dd3fc; } | |
| .result-json .js, .result-trace .js { color: #fcd34d; } | |
| .result-json .jn, .result-trace .jn { color: #c4b5fd; } | |
| .result-json .jb, .result-trace .jb { color: #f472b6; } | |
| /* Pretty tree ------------------------------------------------------ */ | |
| .tree { | |
| background: var(--surface); border: 1px solid var(--border); | |
| border-left: 3px solid var(--accent-2); border-radius: var(--radius-sm); | |
| padding: 0.9rem 1.1rem; | |
| } | |
| .tree + .tree { margin-top: 0.6rem; } | |
| .tree-root { display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; } | |
| .tree-name { font-weight: 600; font-size: 0.92rem; color: var(--text); } | |
| .tree-ms { color: var(--text-subtle); font-size: 0.7rem; font-family: var(--mono); margin-left: auto; } | |
| .tree-conf { | |
| font-family: var(--mono); font-size: 0.68rem; font-weight: 600; | |
| padding: 0.12rem 0.5rem; border-radius: 999px; letter-spacing: 0.02em; | |
| white-space: nowrap; | |
| } | |
| .tree-conf.c-high { color: var(--ok); background: color-mix(in srgb, var(--ok) 14%, transparent); } | |
| .tree-conf.c-mid { color: var(--warn); background: color-mix(in srgb, var(--warn) 14%, transparent); } | |
| .tree-conf.c-low { color: var(--err); background: color-mix(in srgb, var(--err) 14%, transparent); } | |
| .tree-body { | |
| position: relative; margin: 0.4rem 0 0 0.4rem; | |
| padding-left: 1.15rem; border-left: 1px solid var(--border-strong); | |
| } | |
| .tree-leaf { | |
| position: relative; display: flex; align-items: baseline; gap: 0.45rem; | |
| padding: 0.13rem 0; font-size: 0.82rem; line-height: 1.5; | |
| } | |
| .tree-leaf::before { | |
| content: ""; position: absolute; left: -1.15rem; top: 0.75em; | |
| width: 0.9rem; height: 1px; background: var(--border-strong); | |
| } | |
| .tree-leaf .k { color: var(--accent-2); font-weight: 600; font-family: var(--mono); font-size: 0.74rem; white-space: nowrap; } | |
| .tree-leaf .arrow { color: var(--text-subtle); } | |
| .tree-leaf .v { color: var(--text); } | |
| .tree-group { | |
| position: relative; margin: 0.15rem 0 0; padding-left: 1.15rem; | |
| border-left: 1px solid var(--border-strong); | |
| } | |
| .tree-group::before { | |
| content: ""; position: absolute; left: -1.15rem; top: 0.75em; | |
| width: 0.9rem; height: 1px; background: var(--border-strong); | |
| } | |
| .tree-label { | |
| font-weight: 600; color: var(--text-muted); font-size: 0.74rem; | |
| font-family: var(--mono); letter-spacing: 0.03em; padding: 0.1rem 0; | |
| } | |
| .tree-slot { display: block; } | |
| .tree-stream { | |
| font-family: var(--mono); font-size: 0.78rem; color: var(--text-subtle); | |
| padding: 0.15rem 0; font-style: italic; line-height: 1.5; | |
| } | |
| .tree-stream.streaming::after { | |
| content: "▌"; margin-left: 2px; color: var(--accent-2); | |
| animation: blink 1s steps(2) infinite; | |
| } | |
| .tree-none { font-size: 0.78rem; color: var(--text-subtle); font-style: italic; margin: 0.35rem 0 0 0.4rem; padding-left: 1.15rem; } | |
| /* Samples --------------------------------------------------------- */ | |
| .samples-block { display: flex; flex-direction: column; gap: 0.55rem; } | |
| .samples-label { | |
| font-size: 0.68rem; font-weight: 600; color: var(--text-subtle); | |
| text-transform: uppercase; letter-spacing: 0.08em; | |
| display: flex; align-items: center; gap: 0.45rem; | |
| } | |
| .samples-label .count { | |
| font-family: var(--mono); font-weight: 500; | |
| color: var(--text-subtle); background: var(--surface-2); | |
| padding: 0.05rem 0.45rem; border-radius: 999px; | |
| font-size: 0.6rem; letter-spacing: 0; | |
| } | |
| .samples { display: flex; flex-wrap: wrap; gap: 0.4rem; } | |
| /* Textarea -------------------------------------------------------- */ | |
| .textarea-wrap { position: relative; } | |
| textarea { | |
| width: 100%; min-height: 11rem; resize: vertical; | |
| font: inherit; font-size: 0.9rem; line-height: 1.6; | |
| color: var(--text); background: var(--surface-2); | |
| border: 1px solid var(--border); border-radius: var(--radius-sm); | |
| padding: 0.85rem 1rem; | |
| transition: border-color .15s var(--ease), box-shadow .15s var(--ease), background .15s var(--ease); | |
| } | |
| textarea::placeholder { color: var(--text-subtle); } | |
| textarea:hover { border-color: var(--border-strong); } | |
| textarea:focus { | |
| outline: none; border-color: var(--accent-2); | |
| background: var(--surface); | |
| box-shadow: 0 0 0 3px var(--accent-soft); | |
| } | |
| /* Actions / CTA --------------------------------------------------- */ | |
| .actions { display: flex; align-items: center; justify-content: space-between; gap: 1rem; flex-wrap: wrap; } | |
| .actions .meta-text { font-family: var(--mono); font-size: 0.72rem; color: var(--text-subtle); } | |
| .threshold-control { | |
| display: flex; align-items: center; gap: 0.7rem; | |
| font-family: var(--mono); font-size: 0.72rem; color: var(--text-muted); | |
| } | |
| .threshold-control .thr-label { | |
| letter-spacing: 0.08em; text-transform: uppercase; | |
| font-weight: 600; color: var(--text-subtle); white-space: nowrap; | |
| } | |
| .threshold-control input[type="range"] { | |
| flex: 1; accent-color: var(--accent-2); cursor: pointer; height: 18px; | |
| } | |
| .threshold-control .thr-val { | |
| color: var(--accent-2); font-weight: 600; min-width: 3ch; text-align: right; | |
| font-variant-numeric: tabular-nums; | |
| } | |
| .btn { | |
| display: inline-flex; align-items: center; gap: 0.55rem; | |
| font: inherit; font-weight: 600; font-size: 0.88rem; color: var(--btn-fg); | |
| background: linear-gradient(180deg, var(--accent), var(--accent-hover)); | |
| border: none; border-radius: var(--radius-sm); | |
| padding: 0.72rem 1.4rem; cursor: pointer; | |
| transition: box-shadow .2s var(--ease); | |
| box-shadow: 0 1px 2px rgba(0,0,0,.12), 0 8px 22px -8px var(--accent-glow); | |
| font-family: var(--font); | |
| letter-spacing: -0.005em; | |
| } | |
| .btn:hover:not(:disabled) { box-shadow: 0 2px 4px rgba(0,0,0,.14), 0 12px 28px -8px var(--accent-glow); } | |
| .btn:active:not(:disabled) { box-shadow: 0 1px 2px rgba(0,0,0,.12), 0 4px 12px -4px var(--accent-glow); } | |
| .btn:disabled { opacity: 0.4; cursor: not-allowed; box-shadow: none; } | |
| .btn svg { display: block; } | |
| /* Results --------------------------------------------------------- */ | |
| #results { min-height: 14rem; } | |
| .empty { | |
| display: flex; flex-direction: column; align-items: center; justify-content: center; | |
| gap: 0.7rem; padding: 2.5rem 1rem; | |
| color: var(--text-muted); text-align: center; | |
| } | |
| .empty .empty-icon { width: 42px; height: 42px; color: var(--text-subtle); opacity: 0.7; } | |
| .empty .empty-title { font-size: 0.9rem; font-weight: 600; color: var(--text-muted); } | |
| .empty .empty-sub { font-size: 0.78rem; color: var(--text-subtle); max-width: 32ch; line-height: 1.5; } | |
| /* Perf stats ------------------------------------------------------- */ | |
| .perf { | |
| display: flex; flex-wrap: wrap; gap: 0.5rem 0.9rem; align-items: center; | |
| background: var(--surface-2); border: 1px solid var(--border); | |
| border-radius: var(--radius-sm); padding: 0.65rem 0.95rem; | |
| } | |
| .perf-stat { | |
| display: inline-flex; align-items: center; gap: 0.4rem; | |
| color: var(--text-muted); font-family: var(--mono); font-size: 0.72rem; | |
| } | |
| .perf-stat b { | |
| color: var(--text); font-weight: 600; font-variant-numeric: tabular-nums; | |
| } | |
| .perf-stat .dot { width: 3px; height: 3px; border-radius: 50%; background: var(--text-subtle); } | |
| /* Legacy .stat class — emitted by main.js inline HTML, kept for compat. */ | |
| .perf .stat { display: inline-flex; align-items: center; gap: 0.4rem; color: var(--text-muted); font-family: var(--mono); font-size: 0.72rem; } | |
| .perf .stat b { color: var(--accent); font-family: var(--mono); font-weight: 700; font-variant-numeric: tabular-nums; } | |
| /* Mention card ----------------------------------------------------- */ | |
| .mention-list { display: flex; flex-direction: column; gap: 0.6rem; } | |
| .mention { | |
| display: flex; flex-direction: column; gap: 0.55rem; | |
| padding: 1rem 1.1rem; | |
| background: var(--surface); border: 1px solid var(--border); | |
| border-left: 3px solid var(--accent-2); | |
| border-radius: var(--radius-sm); | |
| transition: border-color .15s var(--ease), box-shadow .15s var(--ease); | |
| } | |
| .mention:hover { box-shadow: var(--shadow-sm); } | |
| .mention .head { display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; } | |
| .mention .name { font-weight: 600; font-size: 0.92rem; color: var(--text); } | |
| .mention .ms { color: var(--text-subtle); font-size: 0.7rem; font-family: var(--mono); margin-left: auto; } | |
| .mention .attr { | |
| font-family: var(--mono); font-size: 0.8rem; color: var(--text); | |
| padding: 0.55rem 0.75rem; | |
| background: var(--surface-2); border-radius: 6px; | |
| line-height: 1.65; | |
| } | |
| .mention .attr .k { color: var(--accent-2); font-weight: 600; } | |
| .mention .attr .v { color: var(--text); } | |
| .mention .attr .v.miss { color: var(--text-subtle); font-style: italic; } | |
| .mention .attr.streaming::after { | |
| content: "▌"; margin-left: 2px; | |
| animation: blink 1s steps(2) infinite; | |
| color: var(--accent-2); | |
| } | |
| @keyframes blink { 50% { opacity: 0; } } | |
| .mention-summary { | |
| font-size: 0.85rem; color: var(--text); line-height: 1.55; | |
| padding: 0.6rem 0.8rem; | |
| background: var(--surface-2); border-radius: 6px; | |
| border-left: 2px solid var(--border-strong); | |
| } | |
| /* Badges ----------------------------------------------------------- */ | |
| .badge { | |
| font-size: 0.6rem; font-weight: 700; letter-spacing: 0.06em; | |
| text-transform: uppercase; border-radius: 6px; padding: 0.2rem 0.55rem; | |
| font-family: var(--mono); | |
| } | |
| .badge-NAMED_DATA { background: var(--na-bg); color: var(--na); } | |
| .badge-DESCRIPTIVE_DATA { background: var(--de-bg); color: var(--de); } | |
| .badge-VAGUE_DATA { background: var(--va-bg); color: var(--va); } | |
| /* Details / log ---------------------------------------------------- */ | |
| details.log-wrap, details.models-wrap { | |
| margin-top: 1rem; | |
| background: var(--surface); border: 1px solid var(--border); | |
| border-radius: var(--radius); | |
| box-shadow: var(--shadow-sm); | |
| overflow: hidden; | |
| } | |
| details > summary { | |
| cursor: pointer; font-size: 0.7rem; font-weight: 600; | |
| color: var(--text-muted); | |
| text-transform: uppercase; letter-spacing: 0.1em; | |
| padding: 0.95rem 1.25rem; | |
| user-select: none; list-style: none; | |
| display: flex; align-items: center; gap: 0.6rem; | |
| transition: background .15s var(--ease), color .15s var(--ease); | |
| } | |
| details > summary::-webkit-details-marker { display: none; } | |
| details > summary::before { | |
| content: ""; width: 6px; height: 6px; | |
| border-right: 1.5px solid currentColor; | |
| border-bottom: 1.5px solid currentColor; | |
| transform: rotate(-45deg); transition: transform .2s var(--ease); | |
| display: inline-block; | |
| } | |
| details[open] > summary::before { transform: rotate(45deg); } | |
| details > summary:hover { background: var(--surface-2); color: var(--text); } | |
| .summary-body { padding: 0 1.25rem 1.25rem; } | |
| #log { | |
| background: var(--log-bg); color: var(--log-fg); | |
| border: 1px solid var(--border); | |
| border-radius: var(--radius-sm); | |
| padding: 0.9rem 1rem; | |
| font-family: var(--mono); font-size: 0.74rem; line-height: 1.65; | |
| max-height: 16rem; overflow-y: auto; white-space: pre-wrap; | |
| font-variant-numeric: tabular-nums; | |
| } | |
| #log .ok { color: var(--ok); } | |
| #log .warn { color: var(--warn); } | |
| #log .err { color: var(--err); } | |
| #models-info { display: grid; gap: 1rem; } | |
| .info-card { | |
| background: var(--surface-2); border: 1px solid var(--border); | |
| border-radius: var(--radius-sm); padding: 1rem 1.2rem; | |
| } | |
| .info-card h3 { | |
| margin: 0 0 0.35rem; font-size: 0.9rem; | |
| display: flex; align-items: center; gap: 0.5rem; | |
| } | |
| .info-card h3 a { color: var(--accent-2); text-decoration: none; } | |
| .info-card h3 a:hover { text-decoration: underline; } | |
| .info-card h3 svg { color: var(--text-subtle); flex: none; } | |
| .info-card .task { color: var(--text-muted); font-size: 0.82rem; margin: 0 0 0.65rem; line-height: 1.55; } | |
| .info-card .meta { | |
| font-size: 0.76rem; color: var(--text-muted); | |
| font-family: var(--mono); white-space: pre-wrap; line-height: 1.6; | |
| } | |
| /* Focus rings ------------------------------------------------------ */ | |
| .icon-btn:focus-visible, | |
| .btn:focus-visible, | |
| .chip:focus-visible, | |
| textarea:focus-visible, | |
| details > summary:focus-visible { | |
| outline: none; | |
| box-shadow: 0 0 0 3px var(--accent-soft), 0 0 0 1px var(--accent-2); | |
| } | |
| /* Reduced motion --------------------------------------------------- */ | |
| @media (prefers-reduced-motion: reduce) { | |
| *, *::before, *::after { | |
| animation-duration: 0.001ms ; | |
| animation-iteration-count: 1 ; | |
| transition-duration: 0.001ms ; | |
| } | |
| } | |
| /* Responsive ------------------------------------------------------- */ | |
| @media (max-width: 640px) { | |
| .wrap { padding: 1.1rem 1rem 3rem; } | |
| header { flex-direction: column; align-items: stretch; gap: 1rem; padding-bottom: 1rem; } | |
| .header-actions { justify-content: space-between; } | |
| .brand-text .sub { font-size: 0.7rem; } | |
| .pipeline { padding: 0.75rem 1rem; } | |
| .step-text { font-size: 0.7rem; } | |
| .step-arrow { margin: 0 0.5rem; } | |
| .step-arrow svg { width: 12px; height: 12px; } | |
| .models-strip { grid-template-columns: 1fr; } | |
| .card { padding: 1.2rem; } | |
| .loader-pct { font-size: 56px; } | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <div class="loader" id="loader" data-state="sleeping"> | |
| <button class="loader-theme-toggle theme-toggle" type="button" title="Toggle light/dark" aria-label="Toggle theme"> | |
| <svg class="theme-icon-moon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M21 12.8A9 9 0 1 1 11.2 3a7 7 0 0 0 9.8 9.8z"/></svg> | |
| <svg class="theme-icon-sun" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" style="display:none"><circle cx="12" cy="12" r="4"/><path d="M12 2v2M12 20v2M4.9 4.9l1.4 1.4M17.7 17.7l1.4 1.4M2 12h2M20 12h2M4.9 19.1l1.4-1.4M17.7 6.3l1.4-1.4"/></svg> | |
| <span class="theme-label">Dark</span> | |
| </button> | |
| <div class="loader-inner"> | |
| <div class="loader-layout"> | |
| <div class="loader-copy"> | |
| <div class="loader-brand">Data-use extraction · WebGPU</div> | |
| <div class="loader-pct num"><span id="loader-pct">0</span><i>%</i></div> | |
| <div class="loader-rule"><i id="loader-rule-fill"></i></div> | |
| <div class="loader-status" id="loader-status">Initialising</div> | |
| <div class="loader-truth" id="loader-truth">Loading models…</div> | |
| <button class="loader-cta" id="loader-cta" type="button" disabled>Get started</button> | |
| </div> | |
| <div class="loader-visual"> | |
| <svg class="cat-sculpture" viewBox="0 0 240 320" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"> | |
| <defs> | |
| <filter id="cat-glow" x="-20%" y="-20%" width="140%" height="140%"> | |
| <feGaussianBlur stdDeviation="3.5" result="blur" /> | |
| <feMerge> | |
| <feMergeNode in="blur" /> | |
| <feMergeNode in="SourceGraphic" /> | |
| </feMerge> | |
| </filter> | |
| <linearGradient id="cat-laser" x1="0" y1="0" x2="1" y2="0"> | |
| <stop offset="0%" stop-color="#7cf0de" stop-opacity="0" /> | |
| <stop offset="25%" stop-color="#7cf0de" stop-opacity="0.9" /> | |
| <stop offset="50%" stop-color="#ebfffa" stop-opacity="1" /> | |
| <stop offset="75%" stop-color="#7cf0de" stop-opacity="0.9" /> | |
| <stop offset="100%" stop-color="#7cf0de" stop-opacity="0" /> | |
| </linearGradient> | |
| <clipPath id="cat-fill-clip"> | |
| <rect id="cat-fill-rect" x="0" y="320" width="240" height="320" /> | |
| </clipPath> | |
| </defs> | |
| <!-- Base Obsidian Low-Poly Facets --> | |
| <g class="cat-base" stroke="#0e1318" stroke-width="0.8" stroke-linejoin="round"> | |
| <!-- Crown & Ears --> | |
| <polygon points="120,54 98,28 108,68" fill="#1b2028" /> | |
| <polygon points="120,54 108,68 116,78" fill="#242b36" /> | |
| <polygon points="120,54 116,78 128,78" fill="#2d3542" /> | |
| <polygon points="120,54 128,78 138,66" fill="#28303c" /> | |
| <polygon points="120,54 138,66 148,34" fill="#1f252f" /> | |
| <polygon points="148,34 138,66 156,72" fill="#161b22" /> | |
| <polygon points="98,28 108,68 88,66" fill="#14181f" /> | |
| <!-- Forehead & Eyes --> | |
| <polygon points="116,78 128,78 122,96" fill="#323b49" /> | |
| <polygon points="108,68 116,78 102,92" fill="#28303c" /> | |
| <polygon points="116,78 122,96 102,92" fill="#364050" /> | |
| <polygon points="128,78 138,66 142,88" fill="#202631" /> | |
| <polygon points="128,78 142,88 122,96" fill="#2a323f" /> | |
| <polygon points="102,92 122,96 118,110" fill="#3c4758" /> | |
| <polygon points="122,96 142,88 132,108" fill="#242b36" /> | |
| <polygon points="122,96 132,108 118,110" fill="#2e3745" /> | |
| <!-- Muzzle & Chin --> | |
| <polygon points="102,92 118,110 96,116" fill="#262d38" /> | |
| <polygon points="118,110 126,122 114,130" fill="#343e4e" /> | |
| <polygon points="118,110 132,108 126,122" fill="#2b3340" /> | |
| <polygon points="132,108 144,118 126,122" fill="#1d222b" /> | |
| <polygon points="114,130 126,122 120,138" fill="#3a4555" /> | |
| <polygon points="96,116 114,130 102,142" fill="#202630" /> | |
| <!-- Neck & Throat --> | |
| <polygon points="114,130 120,138 116,162" fill="#323c4a" /> | |
| <polygon points="102,142 114,130 116,162" fill="#272e3a" /> | |
| <polygon points="120,138 136,148 116,162" fill="#232a35" /> | |
| <polygon points="126,122 144,118 136,148" fill="#1a1f27" /> | |
| <polygon points="102,142 116,162 94,172" fill="#1e242e" /> | |
| <polygon points="88,66 102,92 84,106" fill="#12161c" /> | |
| <polygon points="84,106 96,116 78,138" fill="#10141a" /> | |
| <polygon points="78,138 102,142 94,172" fill="#151920" /> | |
| <polygon points="78,138 94,172 72,176" fill="#0f1217" /> | |
| <!-- Chest & Front Shoulders --> | |
| <polygon points="116,162 128,190 108,198" fill="#343e4e" /> | |
| <polygon points="116,162 136,148 128,190" fill="#262d39" /> | |
| <polygon points="94,172 116,162 108,198" fill="#2a323f" /> | |
| <polygon points="94,172 108,198 88,206" fill="#1d222b" /> | |
| <polygon points="72,176 94,172 88,206" fill="#14181f" /> | |
| <polygon points="128,190 146,182 138,214" fill="#1b2028" /> | |
| <polygon points="136,148 146,182 128,190" fill="#1e232c" /> | |
| <!-- Straight Forelegs --> | |
| <polygon points="108,198 128,190 120,230" fill="#384252" /> | |
| <polygon points="108,198 120,230 104,234" fill="#2b3340" /> | |
| <polygon points="88,206 108,198 104,234" fill="#202630" /> | |
| <polygon points="120,230 128,190 138,214" fill="#242b36" /> | |
| <polygon points="120,230 138,214 132,248" fill="#202631" /> | |
| <polygon points="104,234 120,230 114,272" fill="#323c4a" /> | |
| <polygon points="120,230 132,248 126,274" fill="#262d38" /> | |
| <polygon points="104,234 114,272 100,274" fill="#222832" /> | |
| <polygon points="114,272 126,274 122,306" fill="#2d3644" /> | |
| <polygon points="100,274 114,272 108,306" fill="#242b35" /> | |
| <polygon points="126,274 138,272 134,306" fill="#1a1f27" /> | |
| <!-- Seated Hindquarters (Haunches & Back) --> | |
| <polygon points="72,176 88,206 64,216" fill="#12151b" /> | |
| <polygon points="64,216 88,206 78,246" fill="#161b22" /> | |
| <polygon points="64,216 78,246 52,254" fill="#0f1217" /> | |
| <polygon points="88,206 104,234 78,246" fill="#1b2029" /> | |
| <polygon points="78,246 104,234 92,268" fill="#1f252f" /> | |
| <polygon points="52,254 78,246 62,284" fill="#11151b" /> | |
| <polygon points="78,246 92,268 76,288" fill="#181d24" /> | |
| <polygon points="62,284 76,288 68,306" fill="#14181f" /> | |
| <polygon points="76,288 92,268 86,306" fill="#1c222b" /> | |
| <polygon points="92,268 100,274 108,306" fill="#222833" /> | |
| <polygon points="92,268 108,306 86,306" fill="#1e242d" /> | |
| <!-- Tail along floor --> | |
| <polygon points="52,254 62,284 38,288" fill="#0d1014" /> | |
| <polygon points="38,288 62,284 48,304" fill="#11141a" /> | |
| <polygon points="38,288 48,304 24,302" fill="#0e1116" /> | |
| <polygon points="24,302 48,304 32,310" fill="#13171e" /> | |
| <polygon points="24,302 32,310 16,304" fill="#0b0e12" /> | |
| </g> | |
| <!-- Overlaid Glowing Energy Layer (clipped dynamically) --> | |
| <g clip-path="url(#cat-fill-clip)"> | |
| <!-- Glowing Facets --> | |
| <g stroke="#7cf0de" stroke-width="1.2" stroke-linejoin="round" opacity="0.92"> | |
| <polygon points="120,54 98,28 108,68" fill="#7cf0de" fill-opacity="0.28" /> | |
| <polygon points="120,54 108,68 116,78" fill="#7cf0de" fill-opacity="0.38" /> | |
| <polygon points="120,54 116,78 128,78" fill="#ebfffa" fill-opacity="0.45" /> | |
| <polygon points="120,54 128,78 138,66" fill="#7cf0de" fill-opacity="0.35" /> | |
| <polygon points="120,54 138,66 148,34" fill="#7cf0de" fill-opacity="0.25" /> | |
| <polygon points="148,34 138,66 156,72" fill="#38bdf8" fill-opacity="0.22" /> | |
| <polygon points="98,28 108,68 88,66" fill="#38bdf8" fill-opacity="0.22" /> | |
| <polygon points="116,78 128,78 122,96" fill="#ebfffa" fill-opacity="0.52" /> | |
| <polygon points="108,68 116,78 102,92" fill="#7cf0de" fill-opacity="0.36" /> | |
| <polygon points="116,78 122,96 102,92" fill="#7cf0de" fill-opacity="0.48" /> | |
| <polygon points="128,78 142,88 122,96" fill="#7cf0de" fill-opacity="0.4" /> | |
| <polygon points="102,92 122,96 118,110" fill="#ebfffa" fill-opacity="0.55" /> | |
| <polygon points="122,96 132,108 118,110" fill="#7cf0de" fill-opacity="0.42" /> | |
| <polygon points="102,92 118,110 96,116" fill="#38bdf8" fill-opacity="0.32" /> | |
| <polygon points="118,110 126,122 114,130" fill="#ebfffa" fill-opacity="0.5" /> | |
| <polygon points="118,110 132,108 126,122" fill="#7cf0de" fill-opacity="0.38" /> | |
| <polygon points="114,130 126,122 120,138" fill="#7cf0de" fill-opacity="0.5" /> | |
| <polygon points="96,116 114,130 102,142" fill="#38bdf8" fill-opacity="0.3" /> | |
| <polygon points="114,130 120,138 116,162" fill="#7cf0de" fill-opacity="0.46" /> | |
| <polygon points="102,142 114,130 116,162" fill="#7cf0de" fill-opacity="0.38" /> | |
| <polygon points="120,138 136,148 116,162" fill="#38bdf8" fill-opacity="0.32" /> | |
| <polygon points="102,142 116,162 94,172" fill="#38bdf8" fill-opacity="0.28" /> | |
| <polygon points="78,138 102,142 94,172" fill="#0284c7" fill-opacity="0.24" /> | |
| <polygon points="116,162 128,190 108,198" fill="#ebfffa" fill-opacity="0.5" /> | |
| <polygon points="116,162 136,148 128,190" fill="#7cf0de" fill-opacity="0.36" /> | |
| <polygon points="94,172 116,162 108,198" fill="#7cf0de" fill-opacity="0.42" /> | |
| <polygon points="94,172 108,198 88,206" fill="#38bdf8" fill-opacity="0.3" /> | |
| <polygon points="108,198 128,190 120,230" fill="#ebfffa" fill-opacity="0.52" /> | |
| <polygon points="108,198 120,230 104,234" fill="#7cf0de" fill-opacity="0.4" /> | |
| <polygon points="120,230 128,190 138,214" fill="#7cf0de" fill-opacity="0.36" /> | |
| <polygon points="104,234 120,230 114,272" fill="#7cf0de" fill-opacity="0.46" /> | |
| <polygon points="120,230 132,248 126,274" fill="#38bdf8" fill-opacity="0.35" /> | |
| <polygon points="114,272 126,274 122,306" fill="#ebfffa" fill-opacity="0.48" /> | |
| <polygon points="100,274 114,272 108,306" fill="#7cf0de" fill-opacity="0.4" /> | |
| <polygon points="64,216 88,206 78,246" fill="#0284c7" fill-opacity="0.25" /> | |
| <polygon points="88,206 104,234 78,246" fill="#38bdf8" fill-opacity="0.32" /> | |
| <polygon points="78,246 104,234 92,268" fill="#7cf0de" fill-opacity="0.35" /> | |
| <polygon points="78,246 92,268 76,288" fill="#38bdf8" fill-opacity="0.3" /> | |
| <polygon points="76,288 92,268 86,306" fill="#7cf0de" fill-opacity="0.38" /> | |
| <polygon points="92,268 100,274 108,306" fill="#ebfffa" fill-opacity="0.45" /> | |
| <polygon points="38,288 48,304 24,302" fill="#0284c7" fill-opacity="0.22" /> | |
| <polygon points="24,302 48,304 32,310" fill="#38bdf8" fill-opacity="0.25" /> | |
| </g> | |
| <!-- Glowing Meniscus / Laser Line at Liquid Boundary --> | |
| <line id="cat-meniscus" x1="10" y1="320" x2="230" y2="320" stroke="url(#cat-laser)" stroke-width="3.5" filter="url(#cat-glow)" /> | |
| </g> | |
| </svg> | |
| </div> | |
| <div class="loader-about"> | |
| <h2>While you wait</h2> | |
| <p> | |
| <b>Data-use extraction</b> runs entirely in your browser on WebGPU — | |
| no server, no uploads. It spots data mentions in research text, then | |
| attributes each with provenance and usage/impact. | |
| </p> | |
| <ul> | |
| <li><b>GLiNER</b> — detects spans, labels specificity</li> | |
| <li><b>LFM2.5-350M</b> — provenance (producer, year, geography, acronym) + usage & impact</li> | |
| </ul> | |
| <p class="privacy"> | |
| <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="3" y="11" width="18" height="11" rx="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/></svg> | |
| <span><b>Private by design.</b> Nothing is sent anywhere — your text never leaves your browser.</span> | |
| </p> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="wrap"> | |
| <header> | |
| <div class="brand"> | |
| <div class="brand-mark" aria-hidden="true"> | |
| <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> | |
| <path d="M12 2v4M12 18v4M4.93 4.93l2.83 2.83M16.24 16.24l2.83 2.83M2 12h4M18 12h4M4.93 19.07l2.83-2.83M16.24 7.76l2.83-2.83" /> | |
| <circle cx="12" cy="12" r="3" fill="currentColor" fill-opacity="0.3" /> | |
| </svg> | |
| </div> | |
| <div class="brand-text"> | |
| <h1>DATA USE EXTRACTION</h1> | |
| <p class="sub">WebGPU · GLiNER + LFM2.5 multitask</p> | |
| </div> | |
| </div> | |
| <div class="header-actions"> | |
| <div class="status-pill" id="status-pill"><span class="status-dot" aria-hidden="true"></span><span id="status">Initialising…</span></div> | |
| <button class="icon-btn theme-toggle" title="Toggle light/dark" aria-label="Toggle theme"> | |
| <svg class="theme-icon-moon" viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M21 12.8A9 9 0 1 1 11.2 3a7 7 0 0 0 9.8 9.8z"/></svg> | |
| <svg class="theme-icon-sun" viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" style="display:none"><circle cx="12" cy="12" r="4"/><path d="M12 2v2M12 20v2M4.9 4.9l1.4 1.4M17.7 17.7l1.4 1.4M2 12h2M20 12h2M4.9 19.1l1.4-1.4M17.7 6.3l1.4-1.4"/></svg> | |
| <span class="theme-label">Dark</span> | |
| </button> | |
| </div> | |
| </header> | |
| <nav class="pipeline" aria-label="Pipeline"> | |
| <div class="step active" data-step="load"> | |
| <div class="step-num">1</div> | |
| <div class="step-text">Load <b>models</b></div> | |
| </div> | |
| <div class="step-arrow" aria-hidden="true"><svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14M13 5l7 7-7 7"/></svg></div> | |
| <div class="step" data-step="input"> | |
| <div class="step-num">2</div> | |
| <div class="step-text">Paste <b>text</b></div> | |
| </div> | |
| <div class="step-arrow" aria-hidden="true"><svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14M13 5l7 7-7 7"/></svg></div> | |
| <div class="step" data-step="extract"> | |
| <div class="step-num">3</div> | |
| <div class="step-text"><b>Extract</b></div> | |
| </div> | |
| <div class="step-arrow" aria-hidden="true"><svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14M13 5l7 7-7 7"/></svg></div> | |
| <div class="step" data-step="results"> | |
| <div class="step-num">4</div> | |
| <div class="step-text">Review <b>mentions</b></div> | |
| </div> | |
| </nav> | |
| <div class="models-strip"> | |
| <a class="model-card" href="https://huggingface.co/rafmacalaba/gliner_datause_extended-onnx" target="_blank" rel="noopener"> | |
| <div class="model-card-top"> | |
| <div class="model-card-name"> | |
| <span class="model-card-name-icon" aria-hidden="true"> | |
| <svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><path d="m21 21-4.3-4.3"/></svg> | |
| </span> | |
| <span>GLiNER</span> | |
| </div> | |
| <span class="model-role">span</span> | |
| </div> | |
| <div class="model-card-repo"><span class="repo-ns">huggingface/</span>rafmacalaba/gliner_datause_extended-onnx</div> | |
| <div class="model-card-file">onnx/gliner_datause_extended_fp16.onnx</div> | |
| </a> | |
| <a class="model-card" href="https://huggingface.co/rafmacalaba/lfm2.5-350M-datause-multitask-onnx" target="_blank" rel="noopener"> | |
| <div class="model-card-top"> | |
| <div class="model-card-name"> | |
| <span class="model-card-name-icon" aria-hidden="true"> | |
| <svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 2v4M12 18v4M4.93 4.93l2.83 2.83M16.24 16.24l2.83 2.83M2 12h4M18 12h4M4.93 19.07l2.83-2.83M16.24 7.76l2.83-2.83"/></svg> | |
| </span> | |
| <span>LFM2.5-350M</span> | |
| </div> | |
| <span class="model-role">attribution</span> | |
| </div> | |
| <div class="model-card-repo"><span class="repo-ns">huggingface/</span>rafmacalaba/lfm2.5-350M-datause-multitask-onnx</div> | |
| <div class="model-card-file">onnx/lfm2_multitask_fp16_v2.onnx</div> | |
| </a> | |
| </div> | |
| <div class="status-bar"> | |
| <div class="status-readout"> | |
| <div class="status-readout-head"> | |
| <svg class="label-icon" viewBox="0 0 24 24" width="13" height="13" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4M7 10l5 5 5-5M12 15V3"/></svg> | |
| <span>WebGPU pipeline</span> | |
| <span class="status-readout-pct num" id="status-pct">0%</span> | |
| </div> | |
| <div class="status-readout-rule"><i id="status-rule-fill"></i></div> | |
| <div class="status-readout-status" id="model-status-text">Loading models…</div> | |
| </div> | |
| </div> | |
| <div class="bento"> | |
| <section class="card" aria-labelledby="input-card-title"> | |
| <div class="card-head"> | |
| <h2 id="input-card-title">Input text</h2> | |
| <span class="badge-pill">stage 2 → 3</span> | |
| </div> | |
| <p class="card-hint">Paste research text, or load a sample — real-world research excerpts or synthetic examples.</p> | |
| <div class="sample-controls"> | |
| <div class="sample-seg" role="tablist" aria-label="Sample category"> | |
| <button type="button" class="sample-seg-btn active" data-category="holdout" role="tab" aria-selected="true">REAL WORLD (14)</button> | |
| <button type="button" class="sample-seg-btn" data-category="synthetic" role="tab" aria-selected="false">SYNTHETIC (3)</button> | |
| </div> | |
| <button type="button" class="sample-shuffle-btn" id="sample-shuffle" title="Pick a random sample from active category"> | |
| <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M21.5 2v6h-6M21.34 15.57a10 10 0 1 1-.57-8.38l5.67-5.67"/></svg> | |
| <span>Random</span> | |
| </button> | |
| </div> | |
| <div class="samples-group" data-group="holdout"> | |
| <span class="samples-group-label">EXAMPLES</span> | |
| <button type="button" class="sample-chip" data-sample="3">Acronym panels (H8BS)</button> | |
| <button type="button" class="sample-chip" data-sample="4">GPS plot (EAC-I)</button> | |
| <button type="button" class="sample-chip" data-sample="5">NFHS India</button> | |
| <button type="button" class="sample-chip" data-sample="6">Spatial (DHS + GLSS)</button> | |
| <button type="button" class="sample-chip" data-sample="7">Geospatial (SRTM + GAEZ)</button> | |
| <button type="button" class="sample-chip" data-sample="8">Energy poverty (HBS)</button> | |
| <button type="button" class="sample-chip" data-sample="9">COVID NLPS r4</button> | |
| <button type="button" class="sample-chip" data-sample="10">GIS (MODIS + Lloyd's)</button> | |
| <button type="button" class="sample-chip" data-sample="11">Governance (WGI)</button> | |
| <button type="button" class="sample-chip" data-sample="12">Niger fiscal (ECVMA)</button> | |
| <button type="button" class="sample-chip" data-sample="13">Sending areas (VHLSS)</button> | |
| <button type="button" class="sample-chip" data-sample="14">Gender norms (DHS/WVS)</button> | |
| <button type="button" class="sample-chip" data-sample="15">Return (IOM Index)</button> | |
| <button type="button" class="sample-chip" data-sample="16">SEIS 2025 usage/impact</button> | |
| </div> | |
| <div class="samples-group" data-group="synthetic" hidden> | |
| <span class="samples-group-label">EXAMPLES</span> | |
| <button type="button" class="sample-chip" data-sample="0">Multiple mentions</button> | |
| <button type="button" class="sample-chip" data-sample="1">Single mention</button> | |
| <button type="button" class="sample-chip" data-sample="2">No mention</button> | |
| </div> | |
| <div class="textarea-wrap"> | |
| <textarea id="text" placeholder="Paste research text here…">the Demographic and Health Survey (DHS) by EuStatistics in 2021 is the main dataset</textarea> | |
| </div> | |
| <div class="threshold-control"> | |
| <span class="thr-label">Span threshold</span> | |
| <input type="range" id="span-threshold" min="0" max="1" step="0.05" value="0.6" aria-label="Span detection threshold"> | |
| <span class="thr-val" id="span-threshold-val">0.60</span> | |
| </div> | |
| <div class="actions"> | |
| <span class="meta-text num">WebGPU · client-side · no server</span> | |
| <button class="btn" id="run" disabled> | |
| <svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M8 5v14l11-7z"/></svg> | |
| <span>Extract</span> | |
| </button> | |
| </div> | |
| </section> | |
| <section class="card" aria-labelledby="results-card-title"> | |
| <div class="card-head"> | |
| <h2 id="results-card-title">Extracted mentions</h2> | |
| <div class="seg-toggle" role="tablist" aria-label="Output format"> | |
| <button type="button" class="seg-opt active" data-mode="pretty" role="tab" aria-selected="true">Pretty</button> | |
| <button type="button" class="seg-opt" data-mode="json" role="tab" aria-selected="false" disabled>JSON</button> | |
| <button type="button" class="seg-opt" data-mode="trace" role="tab" aria-selected="false" disabled>Trace</button> | |
| </div> | |
| </div> | |
| <p class="card-hint">Spans as a tree — provenance and usage/impact. Toggle JSON for clean extraction or Trace for timings.</p> | |
| <div id="results" class="results-host"> | |
| <div class="result-pane result-pretty" data-pane="pretty" aria-live="polite"> | |
| <div class="empty"> | |
| <svg class="empty-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><path d="M14 2v6h6M16 13H8M16 17H8M10 9H8"/></svg> | |
| <div class="empty-title">No mentions yet</div> | |
| <div class="empty-sub">Paste text or pick a sample, then press Extract.</div> | |
| </div> | |
| </div> | |
| <div class="result-pane result-json" data-pane="json" aria-live="polite" hidden> | |
| <div class="empty"> | |
| <svg class="empty-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M8 3H6a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V5a2 2 0 0 0-2-2h-2M8 3a2 2 0 0 0 2 2h4a2 2 0 0 0 2-2M8 3a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2"/><path d="M7 12h10M7 16h6"/></svg> | |
| <div class="empty-title">No JSON yet</div> | |
| <div class="empty-sub">Run Extract to populate the JSON view.</div> | |
| </div> | |
| </div> | |
| <div class="result-pane result-trace" data-pane="trace" aria-live="polite" hidden> | |
| <div class="empty"> | |
| <svg class="empty-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 17l6-5-6-5M12 19h8"/></svg> | |
| <div class="empty-title">No trace yet</div> | |
| <div class="empty-sub">Run Extract to populate the trace view.</div> | |
| </div> | |
| </div> | |
| </div> | |
| </section> | |
| </div> | |
| </div> | |
| <script> | |
| (function () { | |
| var toggles = document.querySelectorAll(".theme-toggle"); | |
| function sync() { | |
| var dark = document.documentElement.getAttribute("data-theme") === "dark"; | |
| toggles.forEach(function (btn) { | |
| var moon = btn.querySelector(".theme-icon-moon"); | |
| var sun = btn.querySelector(".theme-icon-sun"); | |
| var label = btn.querySelector(".theme-label"); | |
| if (moon) moon.style.display = dark ? "none" : "block"; | |
| if (sun) sun.style.display = dark ? "block" : "none"; | |
| if (label) label.textContent = dark ? "Light" : "Dark"; | |
| btn.title = dark ? "Switch to light mode" : "Switch to dark mode"; | |
| }); | |
| } | |
| toggles.forEach(function (btn) { | |
| btn.addEventListener("click", function () { | |
| var dark = document.documentElement.getAttribute("data-theme") === "dark"; | |
| if (dark) document.documentElement.removeAttribute("data-theme"); | |
| else document.documentElement.setAttribute("data-theme", "dark"); | |
| try { localStorage.setItem("datause-theme", dark ? "light" : "dark"); } catch (e) {} | |
| sync(); | |
| }); | |
| }); | |
| sync(); | |
| })(); | |
| </script> | |
| <script type="module" src="./main.js"></script> | |
| </body> | |
| </html> | |