feat: THE PROSECUTION β NVIDIA Nemotron argues the case in The Trial (Nemotron prize); README tags + cold-start note
4e33211 verified | /* UX Crime Scene β noir / forensic styling. Off-Brand badge bait. */ | |
| /* Fonts are loaded via <link> tags injected in app.py's Blocks(head=...) β | |
| Gradio 6 forbids @import inside its constructed stylesheet. | |
| Asset URLs (--asset-*) are injected at runtime by app.py if the PNGs exist | |
| in assets/; every one falls back gracefully to a pure-CSS version. */ | |
| :root { | |
| --paper: #ede4cf; | |
| --paper-dark: #d8caa8; | |
| --ink: #1a1a1a; | |
| --ink-soft: #2b2b2b; | |
| --blood: #c0392b; | |
| --blood-bright: #e74c3c; | |
| --evidence: #f1c40f; | |
| --redacted: #111; | |
| /* Asset hooks (--asset-*) are defined ONLY in the head <style> injected by | |
| app.py when files exist. We deliberately do NOT default them to `none` | |
| here: the css= bundle loads AFTER the head <style>, so a `none` default | |
| would override the real data-URIs. When an asset is absent, `var(--asset-x)` | |
| is simply invalid and the property falls back to its initial value. */ | |
| } | |
| /* ---------- Global ---------- */ | |
| body, .gradio-container { | |
| background: | |
| radial-gradient(ellipse at 50% -10%, #343434 0%, #1a1a1a 55%, #0b0b0b 100%) ; | |
| font-family: 'Courier Prime', 'Courier New', monospace ; | |
| color: #e9e4d4 ; | |
| } | |
| .gradio-container { max-width: 1240px ; margin: 0 auto ; } | |
| html, body { overflow-x: hidden; max-width: 100%; } /* kill stray horizontal scroll on mobile */ | |
| footer { display: none ; } | |
| /* Global film-grain + vignette over everything (subtle) */ | |
| .gradio-container::after { | |
| content: ""; | |
| position: fixed; inset: 0; | |
| pointer-events: none; | |
| z-index: 9999; | |
| background: | |
| radial-gradient(ellipse at center, transparent 55%, rgba(0,0,0,0.55) 100%); | |
| mix-blend-mode: multiply; | |
| } | |
| /* ---------- Header (left-aligned to the body grid β one spine) ---------- */ | |
| #ux-header { | |
| padding: 14px 4px 12px; /* small top padding β recover the space above */ | |
| border-bottom: 3px double var(--blood); | |
| margin-bottom: 16px; | |
| position: relative; | |
| } | |
| #ux-header .ux-head-row { | |
| display: flex; align-items: center; gap: 22px; | |
| } | |
| #ux-header .ux-head-text { text-align: left; } | |
| #ux-header .emblem { | |
| flex: 0 0 auto; | |
| width: 118px; height: 118px; | |
| background-color: #efe7d2; /* cream coin behind */ | |
| background-image: var(--asset-emblem); /* detective on top of the coin */ | |
| background-size: 96%; | |
| background-repeat: no-repeat; | |
| background-position: center; | |
| border-radius: 50%; | |
| box-shadow: 0 0 0 2px rgba(0,0,0,0.35), inset 0 0 0 4px rgba(0,0,0,0.06); | |
| filter: drop-shadow(0 0 16px rgba(192,57,43,0.45)) drop-shadow(0 5px 10px rgba(0,0,0,0.7)); | |
| display: var(--emblem-display, none); | |
| animation: flickerIn 1.3s ease-out both, plPulse 3s ease-in-out 1.3s infinite; | |
| } | |
| #ux-header .badge { | |
| display: inline-block; | |
| background: var(--blood); | |
| color: #fff; | |
| font-family: 'Oswald', sans-serif; | |
| letter-spacing: 0.35em; | |
| padding: 4px 14px; | |
| font-size: 12px; | |
| transform: rotate(-1.5deg); | |
| margin-bottom: 8px; | |
| box-shadow: 2px 2px 0 #000; | |
| } | |
| #ux-header h1 { | |
| font-family: 'Anton', 'Oswald', sans-serif; | |
| font-size: clamp(34px, 5vw, 58px); | |
| letter-spacing: 0.06em; | |
| color: var(--paper); | |
| margin: 0; | |
| /* cinematic chiaroscuro, not a flat 3D sticker */ | |
| text-shadow: 2px 2px 0 #000, 0 0 1px #000, 0 16px 28px rgba(0,0,0,0.7); | |
| animation: flickerIn 1.1s ease-out both; | |
| } | |
| #ux-header p { | |
| font-family: 'Special Elite', monospace; | |
| color: var(--paper-dark); | |
| margin: 10px 0 0; | |
| font-size: 13.5px; | |
| line-height: 1.5; | |
| letter-spacing: 0.04em; | |
| max-width: 62ch; | |
| } | |
| /* ---------- Buttons ---------- */ | |
| button.primary, button#investigate-btn { | |
| background: var(--blood) ; | |
| color: #fff ; | |
| font-family: 'Oswald', sans-serif ; | |
| letter-spacing: 0.25em ; | |
| font-weight: 700 ; | |
| border: 2px solid #000 ; | |
| border-radius: 0 ; | |
| box-shadow: 4px 4px 0 #000 ; | |
| transition: transform 0.08s ease, box-shadow 0.08s ease ; | |
| text-transform: uppercase ; | |
| } | |
| button.primary:hover, button#investigate-btn:hover { | |
| transform: translate(-2px, -2px); | |
| box-shadow: 6px 6px 0 #000 ; | |
| } | |
| button.primary:active { transform: translate(2px, 2px); box-shadow: 1px 1px 0 #000 ; } | |
| /* ---------- Upload ---------- */ | |
| .gr-image, .gr-file, [data-testid="image"] { | |
| background: #111 ; | |
| border: 2px dashed var(--blood) ; | |
| border-radius: 0 ; | |
| } | |
| label, .gr-block label, span[data-testid] { | |
| font-family: 'Oswald', sans-serif ; | |
| letter-spacing: 0.18em ; | |
| color: var(--paper) ; | |
| text-transform: uppercase ; | |
| font-size: 12px ; | |
| } | |
| /* ======================================================================= | |
| VIEWER β loading scan + interactive evidence board | |
| ======================================================================= */ | |
| .viewer { | |
| position: relative; | |
| width: 100%; | |
| min-height: 380px; | |
| background: #0c0c0c; | |
| border: 2px solid #000; | |
| box-shadow: inset 0 0 80px rgba(0,0,0,0.8), 0 12px 30px rgba(0,0,0,0.5); | |
| overflow: hidden; | |
| } | |
| .viewer-empty { | |
| display: flex; align-items: center; justify-content: center; | |
| height: 380px; | |
| font-family: 'Special Elite', monospace; | |
| color: #5a5a5a; | |
| letter-spacing: 0.15em; | |
| text-align: center; | |
| padding: 20px; | |
| } | |
| /* ---- Scanning loader ---- */ | |
| .scan-stage { position: relative; width: 100%; line-height: 0; aspect-ratio: 16 / 9; overflow: hidden; } | |
| .scan-photo { | |
| width: 100%; height: 100%; display: block; object-fit: cover; | |
| filter: grayscale(0.45) brightness(0.66) contrast(1.06); | |
| } | |
| /* FULL-SCREEN cinematic intro: covers the ENTIRE viewport while it plays. | |
| Sits above everything else; when it ends it fades out, revealing the laptop + | |
| live scan composed below. The .has-intro modifier on .sweep-viewer hides the | |
| sweep contents until the video is done. */ | |
| .intro-fullscreen { | |
| position: fixed; top: 0; left: 0; right: 0; bottom: 0; | |
| width: 100vw; height: 100vh; | |
| z-index: 10000; | |
| background: #000; | |
| display: flex; align-items: center; justify-content: center; | |
| transition: opacity 0.9s ease; | |
| } | |
| .intro-fullscreen.ended { opacity: 0; pointer-events: none; } | |
| .intro-video { | |
| width: 100vw; height: 100vh; object-fit: cover; display: block; | |
| } | |
| /* While the intro is playing, hide everything in the sweep step except the | |
| inspector character (he lives outside .sweep-viewer). */ | |
| .sweep-viewer.has-intro { visibility: hidden; } | |
| .sweep-viewer.has-intro ~ .inspector-fig { visibility: hidden; } | |
| /* Hide ALL chrome while the intro plays β no sound bubble peeking through. */ | |
| body:has(.intro-fullscreen:not(.ended)) #sound-bubble { display: none ; } | |
| /* The .viewer rectangle (dark plate w/ white inner glow) was made for the OLD | |
| monitor-bezel layout. With the laptop frame doing the framing, that plate | |
| shows around the laptop as a grey rectangle. Kill it for the sweep step. */ | |
| .sweep-viewer { | |
| background: transparent ; | |
| border: none ; | |
| box-shadow: none ; | |
| overflow: visible ; | |
| min-height: 0 ; | |
| padding: 0 ; | |
| } | |
| /* Gradio wraps gr.HTML in several padded grey blocks that show through as a | |
| grey rectangle around the laptop. Force every ancestor of the sweep view | |
| transparent and padless, so the laptop floats on the page bg directly. */ | |
| .screen-sweep, | |
| .screen-sweep > div, | |
| .screen-sweep .gr-block, | |
| .screen-sweep .gr-padded, | |
| .screen-sweep .block, | |
| .screen-sweep .form, | |
| .screen-sweep .wrap, | |
| .screen-sweep .gradio-html, | |
| .screen-sweep .prose, | |
| .screen-sweep > .gr-group, | |
| .screen-sweep .gr-group > div { | |
| background: transparent ; | |
| border: none ; | |
| box-shadow: none ; | |
| padding: 0 ; | |
| margin: 0 ; | |
| } | |
| /* Sweep step is FULL WIDTH (room for the big laptop). The verdict keeps the | |
| normal 1240px container β driven by body classes, NOT a :has() leak that | |
| also fired on the verdict step. */ | |
| body.uxc-sweep .gradio-container { max-width: none ; } | |
| .scan-stage::after { /* moving scan line */ | |
| content: ""; | |
| position: absolute; left: 0; right: 0; top: 0; height: 3px; | |
| background: linear-gradient(90deg, transparent, var(--evidence), transparent); | |
| box-shadow: 0 0 18px 4px rgba(241,196,15,0.5); | |
| animation: scanLine 2.6s ease-in-out infinite; | |
| } | |
| .magnifier { | |
| position: absolute; | |
| width: 176px; height: 176px; | |
| margin: -88px 0 0 -88px; /* center on the left/top anchor point */ | |
| left: 14%; top: 18%; | |
| animation: sweep 9s ease-in-out infinite; | |
| z-index: 6; | |
| filter: drop-shadow(0 0 24px rgba(241,196,15,0.5)); /* only the glow, no black trail */ | |
| } | |
| .magnifier::before { /* bright spotlight under the lens β gives it presence */ | |
| content: ""; position: absolute; left: 50%; top: 47%; | |
| width: 168px; height: 168px; transform: translate(-50%, -50%); border-radius: 50%; | |
| background: radial-gradient(circle, rgba(255,246,205,0.30), rgba(241,196,15,0.12) 45%, transparent 70%); | |
| mix-blend-mode: screen; pointer-events: none; | |
| } | |
| .magnifier .glass { | |
| width: 130px; height: 130px; border-radius: 50%; | |
| border: 11px solid #2b2b2b; | |
| background: | |
| radial-gradient(circle at 38% 32%, rgba(255,255,255,0.22), transparent 45%), | |
| radial-gradient(circle, rgba(241,196,15,0.16), rgba(241,196,15,0.04) 60%, transparent 70%); | |
| box-shadow: 0 0 0 3px #000, inset 0 0 22px rgba(241,196,15,0.25), 0 8px 18px rgba(0,0,0,0.6); | |
| } | |
| .magnifier.has-asset { background-image: var(--asset-magnifier); background-size: contain; background-repeat: no-repeat; } | |
| /* When the asset is present, kill BOTH the CSS glass AND the CSS handle AND | |
| the dark spotlight ::before β otherwise dark shapes trail behind the asset. */ | |
| .magnifier.has-asset .glass, | |
| .magnifier.has-asset .handle { display: none ; } | |
| .magnifier.has-asset::before { display: none ; } | |
| .magnifier .handle { | |
| position: absolute; bottom: -34px; right: 10px; | |
| width: 16px; height: 54px; | |
| background: linear-gradient(#3a3a3a, #1d1d1d); | |
| border-radius: 8px; transform: rotate(42deg); | |
| box-shadow: 0 4px 8px rgba(0,0,0,0.6); | |
| } | |
| /* ---- Monitor-style frame: REC + status live on the bezel, OFF the image ---- */ | |
| .scan-frame { | |
| border: 1px solid #2c2c2c; | |
| border-radius: 10px; | |
| background: linear-gradient(#16161a, #0c0c0e); | |
| box-shadow: 0 18px 50px rgba(0,0,0,0.6), inset 0 0 0 1px rgba(255,255,255,0.03), | |
| 0 0 0 1px #000; | |
| padding: 0; overflow: hidden; | |
| } | |
| .scan-bezel { | |
| display: flex; align-items: center; gap: 12px; | |
| padding: 9px 14px; min-height: 22px; | |
| background: linear-gradient(#1b1b1f, #131316); | |
| font-family: 'Oswald', sans-serif; letter-spacing: 0.16em; text-transform: uppercase; | |
| font-size: 12px; color: #8a857a; | |
| } | |
| .scan-bezel-top { border-bottom: 1px solid #000; } | |
| .scan-bezel-bot { border-top: 1px solid #000; } | |
| .scan-bezel .rec { display: inline-flex; align-items: center; gap: 6px; color: var(--blood-bright); font-family: 'Special Elite', monospace; } | |
| .scan-bezel .rec-dot { color: var(--blood-bright); animation: blink 1.1s step-start infinite; } | |
| .scan-bezel .scan-cap { color: #b9b2a3; flex: 0 1 auto; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } | |
| .scan-bezel .scan-ch { margin-left: auto; color: #6a665d; font-family: 'Special Elite', monospace; letter-spacing: 0.1em; } | |
| .scan-grain { /* faint scanline texture INSIDE the screen only */ | |
| position: absolute; inset: 0; z-index: 4; pointer-events: none; | |
| background: repeating-linear-gradient(0deg, rgba(0,0,0,0.10) 0 1px, transparent 1px 3px); | |
| } | |
| .scan-bezel-bot { justify-content: center; position: relative; } | |
| .scan-dots { display: inline-flex; gap: 5px; margin-left: 12px; } | |
| .scan-dots i { width: 5px; height: 5px; border-radius: 50%; background: var(--evidence); opacity: 0.3; animation: dotPulse 1.2s ease-in-out infinite; } | |
| .scan-dots i:nth-child(2){ animation-delay: 0.2s; } | |
| .scan-dots i:nth-child(3){ animation-delay: 0.4s; } | |
| @keyframes dotPulse { 0%,100%{ opacity:0.25; transform:scale(0.8);} 50%{ opacity:1; transform:scale(1);} } | |
| .scan-status { | |
| position: relative; height: 18px; min-width: 280px; text-align: center; | |
| } | |
| .scan-status span { | |
| position: absolute; left: 0; right: 0; | |
| font-family: 'Oswald', sans-serif; | |
| letter-spacing: 0.16em; text-transform: uppercase; | |
| color: var(--evidence); | |
| font-size: 12px; white-space: nowrap; | |
| text-shadow: 0 0 10px rgba(241,196,15,0.5), 1px 1px 0 #000; | |
| opacity: 0; | |
| animation: statusCycle 10s linear infinite; /* 5 messages Γ 2s each */ | |
| } | |
| .scan-status span:nth-child(1){ animation-delay: 0s; } | |
| .scan-status span:nth-child(2){ animation-delay: 2s; } | |
| .scan-status span:nth-child(3){ animation-delay: 4s; } | |
| .scan-status span:nth-child(4){ animation-delay: 6s; } | |
| .scan-status span:nth-child(5){ animation-delay: 8s; } | |
| /* ---- Interactive evidence board ---- */ | |
| .board-stage { position: relative; width: 100%; line-height: 0; } | |
| .board-photo { width: 100%; display: block; } | |
| .board-stage::before { /* faint vignette on the photo */ | |
| content: ""; position: absolute; inset: 0; z-index: 2; pointer-events: none; | |
| box-shadow: inset 0 0 120px rgba(0,0,0,0.55); | |
| } | |
| .ev-rect { | |
| position: absolute; z-index: 3; | |
| border: 3px solid var(--c); | |
| background: color-mix(in srgb, var(--c) 12%, transparent); | |
| box-shadow: 0 0 0 1px rgba(0,0,0,0.6), 0 0 16px color-mix(in srgb, var(--c) 50%, transparent); | |
| animation: stampIn 0.5s cubic-bezier(.2,1.5,.4,1) both; | |
| animation-delay: calc(var(--i) * 0.35s + 0.2s); | |
| } | |
| .ev-pin { | |
| position: absolute; z-index: 6; | |
| transform: translate(-50%, -50%); | |
| animation: stampIn 0.5s cubic-bezier(.2,1.5,.4,1) both; | |
| animation-delay: calc(var(--i) * 0.35s + 0.35s); | |
| } | |
| .ev-pin .ring { | |
| position: absolute; left: 50%; top: 50%; | |
| width: 52px; height: 52px; margin: -26px 0 0 -26px; | |
| border: 3px solid var(--c); border-radius: 50%; | |
| animation: pulse 2s ease-out infinite; | |
| } | |
| .ev-pin .num { | |
| position: relative; | |
| width: 34px; height: 34px; border-radius: 50%; | |
| background: var(--c); color: #fff; | |
| display: flex; align-items: center; justify-content: center; | |
| font-family: 'Anton', sans-serif; font-size: 18px; | |
| border: 2px solid #111; | |
| box-shadow: 2px 2px 0 #000, 0 0 14px color-mix(in srgb, var(--c) 60%, transparent); | |
| cursor: pointer; | |
| } | |
| .ev-pin .pop { | |
| position: absolute; left: 44px; top: -8px; | |
| width: 240px; | |
| background: var(--paper); color: var(--ink); | |
| border: 1px solid #000; border-left: 5px solid var(--c); | |
| padding: 10px 12px; | |
| font-family: 'Special Elite', monospace; font-size: 12.5px; line-height: 1.45; | |
| box-shadow: 4px 4px 0 rgba(0,0,0,0.5); | |
| opacity: 0; transform: translateX(-6px) scale(0.96); | |
| transition: opacity 0.15s ease, transform 0.15s ease; | |
| pointer-events: none; | |
| z-index: 8; | |
| } | |
| .ev-pin .pop b { | |
| display: block; font-family: 'Oswald', sans-serif; text-transform: uppercase; | |
| letter-spacing: 0.06em; color: var(--blood); margin-bottom: 3px; font-size: 12px; | |
| } | |
| .ev-pin:hover { z-index: 20; } | |
| .ev-pin:hover .pop { opacity: 1; transform: translateX(0) scale(1); } | |
| .ev-pin:hover .ring { animation-duration: 1s; } | |
| /* flip popup to the left when near right edge */ | |
| .ev-pin.flip .pop { left: auto; right: 44px; border-left: none; border-right: 5px solid var(--c); } | |
| /* ======================================================================= | |
| CASE FILE | |
| ======================================================================= */ | |
| .case-file { | |
| background-color: var(--paper); | |
| background-image: var(--asset-paper); /* defaults to `none` in :root */ | |
| background-size: cover; background-position: center; | |
| background-blend-mode: multiply; | |
| color: var(--ink); | |
| padding: 42px 48px 48px; | |
| /* No hard border: the torn-paper mask IS the edge. The drop-shadow filter | |
| follows the mask outline (unlike box-shadow which would render a rectangle). */ | |
| border: none; | |
| filter: drop-shadow(0 14px 28px rgba(0,0,0,0.55)) drop-shadow(0 2px 0 rgba(0,0,0,0.35)); | |
| font-family: 'Courier Prime', monospace; | |
| position: relative; | |
| overflow: visible; | |
| margin-top: 28px; | |
| animation: fileDrop 0.5s ease-out both; | |
| /* Irregular torn-paper edges via SVG turbulence mask. Smaller frequency = | |
| gentler waves; the outer 18px is the "torn" zone. */ | |
| -webkit-mask: | |
| url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='100%25' height='100%25'><filter id='r'><feTurbulence type='fractalNoise' baseFrequency='0.018' numOctaves='2' seed='4'/><feDisplacementMap in='SourceGraphic' scale='14'/></filter><rect x='14' y='14' width='calc(100%25 - 28px)' height='calc(100%25 - 28px)' fill='white' filter='url(%23r)'/></svg>") center / 100% 100% no-repeat; | |
| mask: | |
| url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='100%25' height='100%25'><filter id='r'><feTurbulence type='fractalNoise' baseFrequency='0.018' numOctaves='2' seed='4'/><feDisplacementMap in='SourceGraphic' scale='14'/></filter><rect x='14' y='14' width='calc(100%25 - 28px)' height='calc(100%25 - 28px)' fill='white' filter='url(%23r)'/></svg>") center / 100% 100% no-repeat; | |
| } | |
| .case-file::before { /* paper grain + soft inner shadow drawn INSIDE the mask */ | |
| content: ""; position: absolute; inset: 0; pointer-events: none; | |
| background: | |
| radial-gradient(ellipse at 50% 50%, transparent 60%, rgba(60,40,15,0.18) 95%, rgba(40,25,10,0.30) 100%), | |
| repeating-linear-gradient(0deg, rgba(0,0,0,0.018) 0 2px, transparent 2px 4px), | |
| radial-gradient(circle at 18% 26%, rgba(120,80,40,0.10) 0%, transparent 55%), | |
| radial-gradient(circle at 82% 74%, rgba(80,60,20,0.10) 0%, transparent 55%); | |
| opacity: 0.7; | |
| } | |
| /* CONFIDENTIAL stamp β user removed: the paper reads cleaner without it. */ | |
| .case-file .stamp-confidential { display: none ; } | |
| .case-file.has-stamp-asset .stamp-confidential { | |
| background: none; border: none; color: transparent; padding: 0; | |
| width: 280px; height: 110px; top: 14px; right: -10px; | |
| background-image: var(--asset-stamp-confidential); | |
| background-size: contain; background-repeat: no-repeat; | |
| transform: rotate(12deg); | |
| /* Make the stamp INK soak into the paper instead of sitting on top of it. */ | |
| mix-blend-mode: multiply; | |
| opacity: 0.78; | |
| filter: contrast(1.05); | |
| } | |
| .case-file .cf-meta { | |
| display: flex; justify-content: space-between; align-items: flex-end; | |
| border-bottom: 2px solid var(--ink); padding-bottom: 8px; margin-bottom: 18px; | |
| position: relative; z-index: 2; | |
| } | |
| .case-file .cf-num { font-family: 'Oswald', sans-serif; letter-spacing: 0.2em; font-size: 12px; } | |
| .case-file .cf-title { | |
| font-family: 'Anton', 'Oswald', sans-serif; font-size: 32px; letter-spacing: 0.03em; | |
| margin: 6px 0 14px; line-height: 1.05; text-transform: uppercase; position: relative; z-index: 2; | |
| } | |
| .case-file .cf-summary { | |
| font-family: 'Special Elite', monospace; font-size: 15px; margin-bottom: 22px; | |
| line-height: 1.55; position: relative; z-index: 2; | |
| } | |
| .case-file h3 { | |
| font-family: 'Oswald', sans-serif; letter-spacing: 0.25em; | |
| border-bottom: 1px dashed var(--ink); margin: 26px 0 14px; padding-bottom: 4px; | |
| font-size: 14px; text-transform: uppercase; position: relative; z-index: 2; | |
| } | |
| .evidence-item { | |
| display: grid; grid-template-columns: 44px 1fr auto; gap: 14px; align-items: start; | |
| padding: 12px 0; border-bottom: 1px dotted rgba(0,0,0,0.3); | |
| position: relative; z-index: 2; | |
| animation: rowIn 0.4s ease-out both; | |
| animation-delay: calc(var(--i, 0) * 0.12s + 0.4s); | |
| } | |
| .evidence-item .ev-num { | |
| width: 38px; height: 38px; background: var(--blood); color: #fff; border-radius: 50%; | |
| display: flex; align-items: center; justify-content: center; | |
| font-family: 'Anton', sans-serif; font-size: 20px; box-shadow: 2px 2px 0 #000; | |
| } | |
| .evidence-item .ev-crime { | |
| font-family: 'Oswald', sans-serif; font-weight: 700; letter-spacing: 0.05em; | |
| font-size: 16px; text-transform: uppercase; | |
| } | |
| .evidence-item .ev-test { font-family: 'Special Elite', monospace; font-size: 14px; margin-top: 4px; line-height: 1.45; } | |
| .evidence-item .ev-sev { | |
| font-family: 'Oswald', sans-serif; font-size: 11px; letter-spacing: 0.2em; | |
| padding: 4px 10px; border: 1.5px solid var(--ink); text-transform: uppercase; | |
| white-space: nowrap; align-self: center; | |
| } | |
| .ev-sev.capital { background: var(--blood); color: #fff; border-color: #000; } | |
| .ev-sev.high { background: var(--blood-bright); color: #fff; border-color: #000; } | |
| .ev-sev.medium { background: #e67e22; color: #fff; } | |
| .ev-sev.low { background: var(--evidence); color: var(--ink); } | |
| .case-file .cf-footer { | |
| display: grid; grid-template-columns: 1fr auto; gap: 24px; | |
| margin-top: 30px; padding-top: 18px; border-top: 3px double var(--ink); | |
| align-items: center; position: relative; z-index: 2; | |
| } | |
| .case-file .cf-verdict { font-family: 'Anton', sans-serif; font-size: 26px; letter-spacing: 0.1em; text-transform: uppercase; } | |
| .case-file .cf-closing { font-family: 'Special Elite', monospace; font-style: italic; margin-top: 8px; color: var(--ink-soft); font-size: 14px; } | |
| .case-file .cf-grade { | |
| width: 116px; height: 116px; border: 6px solid var(--blood); border-radius: 50%; | |
| display: flex; align-items: center; justify-content: center; | |
| font-family: 'Anton', sans-serif; font-size: 66px; color: var(--blood); | |
| transform: rotate(-8deg) scale(0); box-shadow: 0 0 0 3px var(--paper), 4px 4px 0 #000; | |
| background: rgba(255,255,255,0.35); | |
| animation: gradeStamp 0.55s cubic-bezier(.2,1.7,.4,1) 0.9s both; | |
| } | |
| .case-file.has-grade-asset .cf-grade { | |
| border: none; box-shadow: none; | |
| background-color: transparent; | |
| background-image: var(--asset-grade); | |
| background-size: contain; background-repeat: no-repeat; background-position: center; | |
| color: var(--blood); | |
| } | |
| .redacted { background: var(--redacted); color: var(--redacted); padding: 0 6px; user-select: none; } | |
| /* status / footer text */ | |
| .status-line { | |
| font-family: 'Special Elite', monospace; color: var(--paper-dark); | |
| letter-spacing: 0.08em; font-size: 13px; text-align: center; margin-top: 8px; | |
| } | |
| .tab-nav button { color: var(--paper) ; } | |
| /* ======================================================================= | |
| KEYFRAMES | |
| ======================================================================= */ | |
| @keyframes sweep { | |
| 0% { left: 16%; top: 20%; } | |
| 16% { left: 80%; top: 13%; } | |
| 32% { left: 44%; top: 50%; } | |
| 48% { left: 86%; top: 68%; } | |
| 64% { left: 17%; top: 74%; } | |
| 80% { left: 62%; top: 38%; } | |
| 100% { left: 16%; top: 20%; } | |
| } | |
| @keyframes scanLine { | |
| 0% { top: 2%; opacity: 0; } | |
| 10% { opacity: 1; } | |
| 90% { opacity: 1; } | |
| 100% { top: 98%; opacity: 0; } | |
| } | |
| @keyframes statusCycle { | |
| 0% { opacity: 0; transform: translateY(6px); } | |
| 2% { opacity: 1; transform: translateY(0); } | |
| 18% { opacity: 1; transform: translateY(0); } | |
| 20% { opacity: 0; transform: translateY(-6px); } | |
| 100% { opacity: 0; } | |
| } | |
| @keyframes pulse { | |
| 0% { transform: scale(0.7); opacity: 0.9; } | |
| 70% { transform: scale(1.8); opacity: 0; } | |
| 100% { transform: scale(1.8); opacity: 0; } | |
| } | |
| @keyframes stampIn { | |
| 0% { opacity: 0; transform: translate(-50%, -50%) scale(2.4) rotate(-12deg); } | |
| 60% { opacity: 1; } | |
| 100% { opacity: 1; transform: translate(-50%, -50%) scale(1) rotate(0); } | |
| } | |
| /* ev-rect uses top-left origin, not centered */ | |
| .ev-rect { transform-origin: top left; } | |
| @keyframes fileDrop { | |
| 0% { opacity: 0; transform: translateY(-18px) rotate(-1deg); } | |
| 100% { opacity: 1; transform: translateY(0) rotate(0); } | |
| } | |
| @keyframes stampSlam { | |
| 0% { opacity: 0; transform: rotate(34deg) scale(2.2); } | |
| 70% { opacity: 1; } | |
| 100% { opacity: 1; transform: rotate(34deg) scale(1); } | |
| } | |
| @keyframes gradeStamp { | |
| 0% { opacity: 0; transform: rotate(-8deg) scale(2.6); } | |
| 65% { opacity: 1; } | |
| 100% { opacity: 1; transform: rotate(-8deg) scale(1); } | |
| } | |
| @keyframes rowIn { | |
| 0% { opacity: 0; transform: translateX(-12px); } | |
| 100% { opacity: 1; transform: translateX(0); } | |
| } | |
| @keyframes flickerIn { | |
| 0%, 18%, 24%, 38% { opacity: 0.3; } | |
| 20%, 26%, 100% { opacity: 1; } | |
| } | |
| @keyframes blink { 50% { opacity: 0.25; } } | |
| /* ======================================================================= | |
| RESPONSIVE (desktop-first, but don't break narrow) | |
| ======================================================================= */ | |
| @media (max-width: 760px) { | |
| .case-file { padding: 26px 20px; } | |
| .case-file .cf-footer { grid-template-columns: 1fr; } | |
| .case-file .cf-grade { margin: 0 auto; } | |
| .ev-pin .pop { width: 180px; } | |
| } | |
| @media (prefers-reduced-motion: reduce) { | |
| *, *::before, *::after { animation: none ; } | |
| } | |
| /* ======================================================================= | |
| PAGE LOADER β noir intro overlay (pure CSS, self-dismisses) | |
| ======================================================================= */ | |
| #page-loader { | |
| position: fixed; inset: 0; z-index: 100000; | |
| display: flex; flex-direction: column; align-items: center; justify-content: center; | |
| background: radial-gradient(ellipse at center, #1c1c1c 0%, #0c0c0c 70%, #000 100%); | |
| animation: loaderOut 0.9s ease 2.8s forwards; | |
| } | |
| #page-loader::after { /* film grain flicker */ | |
| content: ""; position: absolute; inset: 0; pointer-events: none; | |
| background: repeating-linear-gradient(0deg, rgba(255,255,255,0.02) 0 1px, transparent 1px 3px); | |
| animation: plFlicker 0.12s steps(2) infinite; | |
| } | |
| #page-loader .pl-emblem { | |
| width: 150px; height: 150px; | |
| background: var(--asset-emblem) center / contain no-repeat; | |
| filter: drop-shadow(0 0 30px rgba(192,57,43,0.5)); | |
| animation: plEmblemIn 1s cubic-bezier(.2,1.4,.4,1) both, plPulse 2.2s ease-in-out 1s infinite; | |
| } | |
| #page-loader .pl-title { | |
| font-family: 'Anton', sans-serif; letter-spacing: 0.2em; font-size: 22px; | |
| color: var(--paper); margin: 22px auto 0; white-space: nowrap; | |
| width: fit-content; max-width: 92vw; overflow: hidden; | |
| animation: plReveal 1s ease 0.5s both; /* left-to-right wipe, any length */ | |
| } | |
| #page-loader .pl-sub { | |
| font-family: 'Special Elite', monospace; color: var(--blood-bright); | |
| letter-spacing: 0.25em; font-size: 12px; margin-top: 14px; | |
| animation: blink 1s step-start 1.6s infinite; | |
| } | |
| #page-loader .pl-scan { | |
| position: absolute; left: 0; right: 0; height: 2px; | |
| background: linear-gradient(90deg, transparent, var(--evidence), transparent); | |
| box-shadow: 0 0 16px 3px rgba(241,196,15,0.4); | |
| animation: plScanMove 1.6s ease-in-out infinite; | |
| } | |
| @keyframes loaderOut { to { opacity: 0; visibility: hidden; pointer-events: none; } } | |
| @keyframes plEmblemIn { 0% { opacity: 0; transform: scale(2) rotate(-12deg); } 100% { opacity: 1; transform: scale(1) rotate(0); } } | |
| @keyframes plPulse { 0%,100% { filter: drop-shadow(0 0 22px rgba(192,57,43,0.4)); } 50% { filter: drop-shadow(0 0 40px rgba(231,76,60,0.7)); } } | |
| @keyframes plReveal { from { clip-path: inset(0 100% 0 0); } to { clip-path: inset(0 0 0 0); } } | |
| @keyframes plCaret { 50% { border-color: transparent; } } | |
| @keyframes plFlicker { 50% { opacity: 0.4; } } | |
| @keyframes plScanMove { 0% { top: 12%; } 100% { top: 88%; } } | |
| /* ======================================================================= | |
| STEP WIZARD BAR | |
| ======================================================================= */ | |
| .steps { | |
| display: flex; justify-content: center; align-items: center; gap: 0; | |
| margin: 6px auto 22px; flex-wrap: wrap; | |
| } | |
| .steps .step { | |
| display: flex; align-items: center; gap: 10px; | |
| padding: 8px 18px; position: relative; | |
| } | |
| .steps .step .dot { | |
| width: 30px; height: 30px; border-radius: 50%; | |
| border: 2px solid #555; color: #777; background: #161616; | |
| display: flex; align-items: center; justify-content: center; | |
| font-family: 'Anton', sans-serif; font-size: 15px; transition: all 0.3s ease; | |
| } | |
| .steps .step .lbl { | |
| font-family: 'Oswald', sans-serif; letter-spacing: 0.18em; font-size: 12px; | |
| color: #777; text-transform: uppercase; transition: all 0.3s ease; | |
| } | |
| .steps .sep { width: 46px; height: 2px; background: #444; } | |
| .steps .step.active .dot { | |
| border-color: var(--blood); color: #fff; background: var(--blood); | |
| box-shadow: 0 0 16px rgba(192,57,43,0.6); transform: scale(1.1); | |
| } | |
| .steps .step.active .lbl { color: var(--paper); } | |
| .steps .step.done .dot { border-color: var(--evidence); color: var(--evidence); } | |
| .steps .step.done .lbl { color: var(--paper-dark); } | |
| /* ======================================================================= | |
| INVESTIGATE BUTTON β make it the hero CTA | |
| ======================================================================= */ | |
| button#investigate-btn { | |
| width: 100% ; | |
| margin-top: 14px ; | |
| padding: 18px 20px ; | |
| font-size: 18px ; | |
| letter-spacing: 0.28em ; | |
| position: relative; overflow: hidden; | |
| background: linear-gradient(180deg, #d83a2a, #a5301f) ; | |
| border: 2px solid #000 ; | |
| box-shadow: 5px 5px 0 #000, inset 0 1px 0 rgba(255,255,255,0.2) ; | |
| } | |
| button#investigate-btn::after { /* moving sheen */ | |
| content: ""; position: absolute; top: 0; left: -60%; width: 40%; height: 100%; | |
| background: linear-gradient(100deg, transparent, rgba(255,255,255,0.28), transparent); | |
| transform: skewX(-20deg); | |
| animation: btnSheen 3.2s ease-in-out infinite; | |
| } | |
| @keyframes btnSheen { 0% { left: -60%; } 55%,100% { left: 130%; } } | |
| button#investigate-btn:hover { background: linear-gradient(180deg, #e74c3c, #c0392b) ; } | |
| /* Typography refinement */ | |
| #ux-header h1 { line-height: 0.95; } | |
| .gradio-container { padding-bottom: 40px ; padding-top: 0 ; } | |
| /* Kill any top padding Gradio's main/wrap add above the header. */ | |
| .gradio-container > .main, .gradio-container main.fillable, | |
| .gradio-container .wrap.svelte-zxu34v { padding-top: 0 ; margin-top: 0 ; } | |
| /* ======================================================================= | |
| P0 FIXES β surgical review batch | |
| ======================================================================= */ | |
| /* P0-1: force English noir copy on Gradio's (locale-dependent) dropzone. | |
| font-size:0 collapses ALL descendant text (any nesting/locale); the SVG icon | |
| is hidden; our pseudo-elements re-add English copy at their own font sizes. */ | |
| /* OLD pseudo-elements that added "DROP THE EVIDENCE HERE" were lingering here | |
| and showing up under our new Polaroid. Forcibly clear them. */ | |
| #evidence-drop .wrap::before, #evidence-drop .wrap::after { content: none ; display: none ; } | |
| /* Collapse the Spanish placeholder text nodes that Gradio bakes directly into | |
| the .wrap. font-size:0 + color:transparent kills any locale's text. */ | |
| #evidence-drop .wrap:not(.default):not(.center):not(.full) { font-size: 0 ; color: transparent ; } | |
| #evidence-drop .wrap svg, #evidence-drop .wrap .icon-wrap { display: none ; } | |
| /* P0-3: idle viewer β legible, framed, intentional (not a black void) */ | |
| .viewer-empty { | |
| display: flex; align-items: center; justify-content: center; | |
| min-height: 360px; padding: 22px; | |
| } | |
| .viewer-empty .ve-frame { | |
| width: 100%; max-width: 460px; text-align: center; | |
| border: 2px dashed rgba(192,57,43,0.5); | |
| padding: 34px 26px; | |
| background: | |
| var(--asset-magnifier) center 26px / 60px no-repeat, | |
| repeating-linear-gradient(0deg, rgba(255,255,255,0.015) 0 2px, transparent 2px 4px); | |
| background-blend-mode: normal; | |
| } | |
| .viewer-empty .ve-title { | |
| margin-top: 78px; | |
| font-family: 'Anton', sans-serif; letter-spacing: 0.14em; font-size: 22px; | |
| color: #b9b0a0; | |
| } | |
| .viewer-empty .ve-sub { | |
| font-family: 'Special Elite', monospace; font-size: 13px; line-height: 1.6; | |
| color: #8c8473; /* ~4.4:1 on the dark viewer β passes AA */ | |
| margin-top: 10px; | |
| } | |
| /* P0-5/6: board popups are TEASERS; pins are links; rows flash on jump */ | |
| .viewer .board-hint { | |
| font-family: 'Special Elite', monospace; color: var(--paper-dark); | |
| letter-spacing: 0.08em; font-size: 12px; text-align: center; | |
| padding: 8px 0 2px; line-height: 1; | |
| } | |
| .ev-pin { text-decoration: none; } | |
| .ev-pin .pop { width: auto; min-width: 150px; max-width: 240px; } | |
| .ev-pin .pop b { display: block; margin-bottom: 4px; } | |
| .ev-pin .pop .pop-sev { | |
| display: inline-block; font-family: 'Oswald', sans-serif; font-size: 10px; | |
| letter-spacing: 0.18em; text-transform: uppercase; padding: 2px 8px; color: #fff; | |
| } | |
| .pop-sev.capital { background: #8e1f14; } | |
| .pop-sev.high { background: var(--blood); } | |
| .pop-sev.medium { background: #e67e22; } | |
| .pop-sev.low { background: var(--evidence); color: var(--ink); } | |
| .ev-pin:focus-within { z-index: 20; } | |
| .ev-pin:focus-within .pop { opacity: 1; transform: translateX(0) scale(1); } | |
| .evidence-item { scroll-margin-top: 80px; } | |
| .evidence-item:target { animation: flashRow 1.4s ease; } | |
| @keyframes flashRow { | |
| 0%, 100% { background: transparent; } | |
| 18% { background: rgba(241,196,15,0.45); } | |
| } | |
| /* P0-8: shareable artifact β inline, prominent */ | |
| .share-block { margin: 26px 0 6px; } | |
| .share-head { | |
| font-family: 'Oswald', sans-serif; letter-spacing: 0.2em; text-transform: uppercase; | |
| color: var(--paper); font-size: 14px; border-bottom: 1px dashed rgba(192,57,43,0.5); | |
| padding-bottom: 8px; margin-bottom: 10px; | |
| } | |
| .share-caption { | |
| font-family: 'Special Elite', monospace; color: var(--paper-dark); | |
| font-size: 13px; line-height: 1.5; margin-bottom: 12px; | |
| background: rgba(0,0,0,0.3); border-left: 3px solid var(--blood); padding: 10px 12px; | |
| } | |
| #share-img { border: 2px solid #000 ; } | |
| /* P1: severity contrast bump + capital separation */ | |
| .ev-sev.capital { background: #8e1f14 ; color: #fff; } | |
| .ev-sev.medium { background: #c85a12 ; } | |
| /* P1: wizard separators connect into one rail */ | |
| .steps .sep { flex: 1 1 auto; min-width: 24px; max-width: 60px; } | |
| .steps .step.error .dot { border-color: var(--blood); color: var(--blood); background: #2a1110; } | |
| .steps .step.error .lbl { color: var(--blood-bright); } | |
| .steps .step.done .dot { border-color: var(--evidence); } | |
| /* P1: CTA must not wrap */ | |
| button#investigate-btn { white-space: nowrap; letter-spacing: 0.18em ; font-size: 16px ; } | |
| /* ======================================================================= | |
| P0-4 (CRITICAL): reduced-motion must NOT freeze the page-loader on-screen | |
| nor leave animate-in elements stuck invisible. | |
| ======================================================================= */ | |
| @media (prefers-reduced-motion: reduce) { | |
| *, *::before, *::after { animation: none ; transition: none ; } | |
| #page-loader { display: none ; } /* loaderOut never runs β hide it */ | |
| #ux-header .emblem { opacity: 1 ; } | |
| #ux-header h1 { opacity: 1 ; } | |
| .case-file { opacity: 1 ; transform: none ; } | |
| .case-file .cf-grade { transform: rotate(-8deg) scale(1) ; opacity: 1 ; } | |
| .case-file .stamp-confidential { opacity: 1 ; transform: rotate(34deg) scale(1) ; } | |
| .evidence-item { opacity: 1 ; transform: none ; } | |
| .ev-pin, .ev-rect { opacity: 1 ; transform: translate(-50%,-50%) ; } | |
| .ev-rect { transform: none ; } | |
| } | |
| /* ======================================================================= | |
| Mobile tap targets β hover is dead on touch, so pins must be tappable | |
| and big enough; popups shrink. | |
| ======================================================================= */ | |
| @media (max-width: 760px) { | |
| #ux-header .ux-head-row { flex-direction: column; text-align: center; gap: 10px; } | |
| #ux-header .ux-head-text { text-align: center; } | |
| #ux-header p { margin-left: auto; margin-right: auto; } | |
| .ev-pin .num { width: 44px; height: 44px; font-size: 22px; } | |
| .ev-pin .ring { width: 64px; height: 64px; margin: -32px 0 0 -32px; } | |
| .ev-pin .pop { display: none; } /* on touch, tap the pin to scroll to the charge */ | |
| .steps .step { padding: 6px 8px; } | |
| .steps .lbl { display: none; } /* compact dots-only rail on phones */ | |
| } | |
| /* ======================================================================= | |
| WIZARD v2 β real 3-screen flow, fixes for paper/text/board/share | |
| ======================================================================= */ | |
| /* Gradio Group wrappers must be invisible containers */ | |
| .screen { background: transparent ; border: none ; box-shadow: none ; padding: 0 ; } | |
| /* ---- Cinematic screen transitions ----------------------------------------- | |
| Gradio toggles display:none on the .screen root when (in)visible. An element | |
| that goes display:none -> shown restarts any CSS animation defined on it, so | |
| each screen plays its entrance every time the wizard advances. */ | |
| /* fill-mode is `backwards` (NOT both/forwards): the entrance plays on mount but | |
| leaves NO lingering transform/filter at rest β a held transform/filter would | |
| turn .screen into the containing block for the position:fixed Inspector and | |
| trap him inside the (very tall) screen instead of the viewport corner. */ | |
| .screen { animation: screenIn 0.55s cubic-bezier(.22,.85,.3,1) backwards; transform-origin: top center; } | |
| .screen-upload { animation: screenInUp 0.5s ease backwards; } | |
| .screen-sweep { animation: screenFade 0.45s ease backwards; } | |
| .screen-verdict { animation: screenSlam 0.6s cubic-bezier(.2,.9,.25,1) backwards; } | |
| @keyframes screenIn { from { opacity:0; transform:translateY(14px); } to { opacity:1; transform:none; } } | |
| @keyframes screenInUp { from { opacity:0; transform:translateY(22px) scale(.985); } to { opacity:1; transform:none; } } | |
| @keyframes screenFade { from { opacity:0; } to { opacity:1; } } | |
| /* the verdict "case file slams onto the desk" */ | |
| @keyframes screenSlam { | |
| 0% { opacity:0; transform:translateY(-26px) scale(1.05) rotate(-.6deg); filter:blur(3px); } | |
| 60% { opacity:1; transform:translateY(0) scale(.995) rotate(.15deg); filter:blur(0); } | |
| 80% { transform:translateY(0) scale(1.004) rotate(0); } | |
| 100% { transform:none; } | |
| } | |
| @media (prefers-reduced-motion: reduce) { | |
| .screen, .screen-upload, .screen-sweep, .screen-verdict { animation: screenFade 0.25s ease both; } | |
| } | |
| /* Big viewer for the sweep + verdict screens (full width of the container) */ | |
| .viewer.big { min-height: 440px; } | |
| .viewer.big .board-photo { width: 100%; display: block; } | |
| /* P0: the case-file text was being overridden by the global light color | |
| (body{color:#e9e4d4 !important}). Force dark ink on the cream paper. */ | |
| .case-file, | |
| .case-file .cf-title, | |
| .case-file .cf-summary, | |
| .case-file h3, | |
| .case-file .ev-crime, | |
| .case-file .ev-test, | |
| .case-file .cf-num, | |
| .case-file .cf-verdict { color: var(--ink) ; } | |
| .case-file .cf-closing { color: var(--ink-soft) ; } | |
| .case-file .ev-sev, | |
| .case-file .ev-num, | |
| .case-file .stamp-confidential { color: #fff ; } /* badges keep white */ | |
| .case-file .ev-sev.low { color: var(--ink) ; } | |
| /* Paper fills cleanly (new texture has no dark edges) */ | |
| .case-file { | |
| background-size: cover ; | |
| background-position: center ; | |
| background-repeat: no-repeat ; | |
| } | |
| /* Share section */ | |
| .share-block { margin: 6px 0 4px; } | |
| .share-row { margin-top: 12px; } | |
| .share-btn { | |
| display: inline-flex; align-items: center; gap: 9px; | |
| font-family: 'Oswald', sans-serif; letter-spacing: 0.12em; text-transform: uppercase; | |
| font-size: 14px; padding: 12px 22px; text-decoration: none; | |
| border: 2px solid #000; box-shadow: 3px 3px 0 #000; | |
| transition: transform 0.08s ease, box-shadow 0.08s ease; | |
| } | |
| .share-btn svg { width: 18px; height: 18px; flex: 0 0 auto; display: block; } | |
| /* Kill Gradio's default blue underline / link color leaking onto our anchors */ | |
| .gradio-container a, | |
| .share-block a, .share-btn, .share-btn:visited, .share-btn:hover, | |
| .dl-btn, .dl-btn:visited, .ev-pin, .ev-pin:visited, | |
| #dossier a, .hero a { | |
| text-decoration: none ; | |
| } | |
| .share-btn, .share-btn:visited { color: #fff ; } | |
| .share-block a:hover { text-decoration: none ; } | |
| .share-btn.x { background: #111; color: #fff; } | |
| .share-btn.x:hover { transform: translate(-2px,-2px); box-shadow: 5px 5px 0 #000; background: #000; } | |
| #share-img { border: 2px solid #000 ; margin-bottom: 6px; } | |
| /* "Investigate another" β secondary noir button */ | |
| #newcase-btn { | |
| margin-top: 18px ; | |
| background: #1c1c1c ; color: var(--paper) ; | |
| font-family: 'Oswald', sans-serif ; letter-spacing: 0.2em ; | |
| border: 2px solid var(--blood) ; border-radius: 0 ; | |
| box-shadow: 4px 4px 0 #000 ; text-transform: uppercase ; | |
| } | |
| #newcase-btn:hover { background: #241413 ; transform: translate(-2px,-2px); box-shadow: 6px 6px 0 #000 ; } | |
| /* Copyable share link textbox */ | |
| #share-link { margin-top: 8px; } | |
| #share-link textarea, #share-link input { | |
| background: #111 ; color: var(--evidence) ; | |
| font-family: 'Courier Prime', monospace ; border: 1px solid var(--blood) ; | |
| } | |
| /* On the verdict screen the board image is large β bump marker size a touch */ | |
| .screen-verdict .ev-pin .num { width: 38px; height: 38px; font-size: 20px; } | |
| .screen-verdict .ev-pin .ring { width: 58px; height: 58px; margin: -29px 0 0 -29px; } | |
| /* Center & constrain the upload screen */ | |
| .screen-upload { max-width: 640px; margin: 0 auto; } | |
| /* ======================================================================= | |
| Floating sound bubble | |
| ======================================================================= */ | |
| #sound-bubble { | |
| position: fixed; right: 22px; bottom: 22px; z-index: 100001; | |
| display: flex; align-items: center; gap: 8px; | |
| padding: 11px 16px; cursor: pointer; | |
| background: #1a1a1a; color: var(--paper-dark); | |
| border: 2px solid var(--blood); border-radius: 40px; | |
| font-family: 'Oswald', sans-serif; letter-spacing: 0.18em; font-size: 11px; text-transform: uppercase; | |
| box-shadow: 0 6px 18px rgba(0,0,0,0.6), 0 0 0 4px rgba(0,0,0,0.25); | |
| transition: transform 0.12s ease, box-shadow 0.12s ease, color 0.12s ease; | |
| } | |
| #sound-bubble:hover { transform: translateY(-2px); box-shadow: 0 10px 22px rgba(0,0,0,0.7); } | |
| #sound-bubble .sb-ico { font-size: 17px; line-height: 1; } | |
| #sound-bubble.on { | |
| color: #fff; border-color: var(--evidence); | |
| box-shadow: 0 0 18px rgba(241,196,15,0.4), 0 6px 18px rgba(0,0,0,0.6); | |
| } | |
| #sound-bubble.on .sb-ico { color: var(--evidence); animation: plPulse 1.6s ease-in-out infinite; } | |
| @media (max-width: 760px){ #sound-bubble .sb-txt{ display:none; } #sound-bubble{ padding:12px; border-radius:50%; } } | |
| /* ======================================================================= | |
| Background video (fixed, dimmed, behind everything) | |
| ======================================================================= */ | |
| #bg-video-wrap { | |
| position: fixed; inset: 0; z-index: -1; overflow: hidden; pointer-events: none; | |
| background: #0b0b0b; | |
| } | |
| #bg-video { | |
| position: absolute; inset: 0; | |
| width: 100%; height: 100%; | |
| object-fit: cover; object-position: center; | |
| opacity: 0.85; | |
| filter: contrast(1.08) saturate(1.05); | |
| } | |
| #bg-video-wrap::after { /* light readability scrim only at the edges */ | |
| content: ""; position: absolute; inset: 0; | |
| background: | |
| radial-gradient(ellipse at 50% 32%, rgba(10,10,10,0.04), rgba(8,8,8,0.45) 100%), | |
| linear-gradient(180deg, rgba(8,8,8,0.20), rgba(8,8,8,0.40)); | |
| } | |
| /* Let the fixed video (z-index:-1, living inside <gradio-app>) show through: | |
| EVERY ancestor up to the root must be transparent β especially <gradio-app>, | |
| whose opaque theme background was covering the video entirely. */ | |
| html { background: #0b0b0b ; } | |
| gradio-app, | |
| body, .gradio-container, | |
| .gradio-container .main, | |
| .gradio-container .wrap, | |
| .gradio-container .contain, | |
| .main.fillable { background: transparent ; background-color: transparent ; } | |
| @media (prefers-reduced-motion: reduce) { #bg-video { display: none; } } | |
| /* ======================================================================= | |
| v3 fixes: hero image, share buttons, confidential stamp, magnifier asset | |
| ======================================================================= */ | |
| /* The annotated hero image (verdict) β large, framed */ | |
| #hero-img { border: 2px solid #000 ; box-shadow: 0 14px 34px rgba(0,0,0,0.6) ; margin-bottom: 18px; } | |
| #hero-img img { image-rendering: auto; } | |
| /* Make the magnifier ASSET fill the bigger element */ | |
| .magnifier.has-asset { background-position: center; background-size: 100% 100%; } | |
| /* Share buttons β platform colors */ | |
| .share-row { display: flex; flex-wrap: wrap; gap: 10px; } | |
| .share-btn.wa { background: #1faf54; color: #fff; } | |
| .share-btn.wa:hover { background: #169c49; transform: translate(-2px,-2px); box-shadow: 5px 5px 0 #000; } | |
| .share-btn.fb { background: #1877f2; color: #fff; } | |
| .share-btn.fb:hover { background: #0f63d6; transform: translate(-2px,-2px); box-shadow: 5px 5px 0 #000; } | |
| .share-btn.li { background: #0a66c2; color: #fff; } | |
| .share-btn.li:hover { background: #084e95; transform: translate(-2px,-2px); box-shadow: 5px 5px 0 #000; } | |
| /* Keep the CONFIDENTIAL stamp in the top-right CORNER, clear of the meta text */ | |
| .case-file.has-stamp-asset .stamp-confidential { | |
| top: 6px ; right: 18px ; | |
| width: 220px ; height: 88px ; | |
| transform: rotate(13deg) ; | |
| } | |
| .case-file .stamp-confidential { top: 8px; right: -58px; } | |
| /* ======================================================================= | |
| Verdict hero: PIL-annotated image + interactive hotspots (hover = charge) | |
| ======================================================================= */ | |
| .hero-head { | |
| font-family: 'Special Elite', monospace; color: var(--paper-dark); | |
| letter-spacing: 0.06em; font-size: 12px; margin: 2px 0 8px; text-align: center; | |
| } | |
| .hero-wrap { | |
| position: relative; line-height: 0; width: 100%; | |
| border: 2px solid #000; box-shadow: 0 14px 34px rgba(0,0,0,0.6); | |
| } | |
| .hero-photo { width: 100%; display: block; } | |
| .hotspot { | |
| position: absolute; display: block; text-decoration: none; cursor: pointer; | |
| border: 2px solid transparent; border-radius: 4px; | |
| transition: border-color 0.12s ease, background 0.12s ease; | |
| } | |
| .hotspot:hover, .hotspot:focus { | |
| border-color: var(--evidence); | |
| background: rgba(241,196,15,0.12); | |
| z-index: 20; | |
| } | |
| .hotspot .hs-pop { | |
| position: absolute; left: 100%; top: 0; margin-left: 8px; | |
| min-width: 190px; max-width: 280px; | |
| background: var(--paper); color: var(--ink); | |
| border: 1px solid #000; border-left: 5px solid var(--blood); | |
| padding: 10px 12px; box-shadow: 4px 4px 0 rgba(0,0,0,0.5); | |
| font-family: 'Special Elite', monospace; font-size: 12.5px; line-height: 1.45; | |
| opacity: 0; transform: translateX(-6px); transition: opacity 0.15s ease, transform 0.15s ease; | |
| pointer-events: none; z-index: 30; white-space: normal; | |
| } | |
| .hotspot .hs-pop b { | |
| display: block; font-family: 'Oswald', sans-serif; text-transform: uppercase; | |
| letter-spacing: 0.04em; color: var(--blood); margin-bottom: 4px; font-size: 12px; | |
| } | |
| .hotspot:hover .hs-pop, .hotspot:focus .hs-pop { opacity: 1; transform: translateX(0); } | |
| .hotspot.flip .hs-pop { left: auto; right: 100%; margin: 0 8px 0 0; border-left: none; border-right: 5px solid var(--blood); } | |
| #hero-img { margin-bottom: 16px; } | |
| /* ======================================================================= | |
| v4: CONFIDENTIAL stamp cleanup (no white text duplicate, no text collision) | |
| ======================================================================= */ | |
| /* My dark-text fix had forced the stamp TEXT white, revealing it on top of the | |
| red stamp image. Hide the text entirely when the asset is present. */ | |
| .case-file.has-stamp-asset .stamp-confidential { color: transparent ; } | |
| /* Keep the red stamp in the very top-right corner, clear of the (now left-aligned) meta. */ | |
| .case-file.has-stamp-asset .stamp-confidential { | |
| top: 2px ; right: 14px ; | |
| width: 188px ; height: 76px ; | |
| transform: rotate(9deg) ; opacity: 0.95; | |
| } | |
| .case-file .cf-meta { display: block; } /* meta is single left column now */ | |
| .cf-sub { | |
| display: block; margin-top: 3px; | |
| font-family: 'Oswald', sans-serif; letter-spacing: 0.16em; | |
| font-size: 11px; color: var(--ink-soft) ; opacity: 0.8; | |
| } | |
| /* Download-the-photo button (replaces the gr.Image native download we lost) */ | |
| .dl-btn, .dl-btn:link, .dl-btn:visited, .dl-btn:hover, .dl-btn:active { | |
| display: inline-flex; align-items: center; gap: 9px; margin-top: 12px; | |
| font-family: 'Oswald', sans-serif; letter-spacing: 0.16em; text-transform: uppercase; | |
| font-size: 13px; padding: 11px 22px; text-decoration: none ; | |
| background: #161616; color: var(--paper) ; | |
| border: 2px solid var(--evidence); box-shadow: 3px 3px 0 #000; | |
| transition: transform 0.08s ease, box-shadow 0.08s ease, background 0.08s ease, color 0.08s ease; | |
| } | |
| .dl-btn:hover { background: #241c0a; color: #fff ; border-color: #ffd633; | |
| transform: translate(-2px,-2px); box-shadow: 5px 5px 0 #000; } | |
| /* ======================================================================= | |
| Hide Gradio's "processing | Xs" timer β it's a confusing CUMULATIVE session | |
| counter, and our noir scan animation already says "working". | |
| ======================================================================= */ | |
| .progress-text, .eta-bar, .progress-level, .progress-bar, | |
| .meta-text, .meta-text-center, | |
| [class*="progress-text"], [class*="eta"] { display: none ; } | |
| /* The wrap Gradio injects over a generating component */ | |
| .screen .wrap.default.full.translucent, | |
| .screen .wrap.generating { display: none ; } | |
| /* ======================================================================= | |
| Animated evidence circles β the Inspector draws them on, one by one | |
| ======================================================================= */ | |
| .hero-svg { | |
| position: absolute; inset: 0; width: 100%; height: 100%; | |
| pointer-events: none; overflow: visible; z-index: 3; | |
| } | |
| .draw-ring { | |
| fill: none; | |
| stroke-width: 5.5; | |
| vector-effect: non-scaling-stroke; /* constant on-screen thickness at any image size */ | |
| stroke-linecap: round; | |
| stroke-dasharray: 1; stroke-dashoffset: 1; /* pathLength=1 => draw-on */ | |
| filter: drop-shadow(0 1px 2px rgba(0,0,0,0.55)); | |
| opacity: 0.97; | |
| animation: drawRing 0.6s ease forwards; | |
| animation-delay: calc(var(--i) * 0.5s + 0.25s); | |
| } | |
| @keyframes drawRing { from { stroke-dashoffset: 1; } to { stroke-dashoffset: 0; } } | |
| /* numbered placard stamps in right after its circle finishes drawing */ | |
| .hero-wrap .ev-pin { | |
| position: absolute; z-index: 6; transform: translate(-50%, -50%); | |
| text-decoration: none; | |
| animation: stampIn 0.45s cubic-bezier(.2,1.5,.4,1) both; | |
| animation-delay: calc(var(--i) * 0.5s + 0.7s); | |
| } | |
| .hero-wrap .ev-pin .num { | |
| display: flex; align-items: center; justify-content: center; | |
| width: 34px; height: 34px; border-radius: 50%; | |
| background: var(--c); color: #fff; border: 2px solid #111; | |
| font-family: 'Anton', sans-serif; font-size: 18px; | |
| box-shadow: 2px 2px 0 #000, 0 0 14px color-mix(in srgb, var(--c) 60%, transparent); | |
| cursor: pointer; | |
| } | |
| .hero-wrap .ev-pin .pop { | |
| position: absolute; left: 42px; top: -6px; width: 250px; | |
| background: var(--paper); color: var(--ink); | |
| border: 1px solid #000; border-left: 5px solid var(--c); | |
| padding: 10px 12px; box-shadow: 4px 4px 0 rgba(0,0,0,0.5); | |
| font-family: 'Special Elite', monospace; font-size: 12.5px; line-height: 1.45; | |
| opacity: 0; transform: translateX(-6px); transition: opacity .15s, transform .15s; | |
| pointer-events: none; z-index: 30; | |
| } | |
| .hero-wrap .ev-pin .pop b { display: block; font-family: 'Oswald', sans-serif; | |
| text-transform: uppercase; color: var(--blood); margin-bottom: 4px; font-size: 12px; } | |
| .hero-wrap .ev-pin:hover, .hero-wrap .ev-pin:focus { z-index: 40; } | |
| .hero-wrap .ev-pin:hover .pop, .hero-wrap .ev-pin:focus .pop { opacity: 1; transform: translateX(0); } | |
| .hero-wrap .ev-pin.flip .pop { left: auto; right: 42px; border-left: none; border-right: 5px solid var(--c); } | |
| .hero-wrap .ev-pin .num:hover { transform: scale(1.12); } | |
| @media (prefers-reduced-motion: reduce) { | |
| .draw-ring { animation: none; stroke-dashoffset: 0; } | |
| .hero-wrap .ev-pin { animation: none; } | |
| } | |
| /* ======================================================================= | |
| The Inspector character β slides into the corner and works the scene. | |
| He lives inside a .screen's HTML (so he comes/goes with that screen) but is | |
| position:fixed to anchor to the viewport corner. The entrance is DELAYED past | |
| the screen's own transition so position:fixed resolves against the viewport | |
| (a transformed ancestor would otherwise capture it). | |
| ======================================================================= */ | |
| .inspector-fig { | |
| position: fixed; left: clamp(24px, calc(50vw - 720px), 90px); bottom: 0; | |
| z-index: 45; pointer-events: none; will-change: transform, opacity; | |
| } | |
| .inspector-fig img { | |
| display: block; width: auto; height: clamp(210px, 30vh, 340px); | |
| filter: drop-shadow(6px 8px 10px rgba(0,0,0,0.55)); | |
| } | |
| /* VERDICT: stride in from the left, hold the accusing point, then exit. */ | |
| .insp-point { animation: inspPoint 5.2s cubic-bezier(.2,.8,.25,1) 0.7s both; } | |
| @keyframes inspPoint { | |
| 0% { transform: translateX(-135%) translateY(8%); opacity: 0; } | |
| 14% { transform: translateX(0) translateY(0); opacity: 1; } | |
| 19% { transform: translateX(2.5%) rotate(-1.2deg); } /* a little jab at the evidence */ | |
| 24% { transform: translateX(0) rotate(0); } | |
| 72% { transform: translateX(0); opacity: 1; } /* holds, pointing */ | |
| 100% { transform: translateX(-135%); opacity: 0; } /* slips back into the shadows */ | |
| } | |
| /* SWEEP: he stays, examining through the glass, with a slow idle bob. */ | |
| .insp-lean { animation: inspIn 0.6s ease 0.55s both, inspBob 3.6s ease-in-out 1.15s infinite; } | |
| @keyframes inspIn { from { transform: translateX(-120%); opacity: 0; } to { transform: none; opacity: 1; } } | |
| @keyframes inspBob { 0%,100% { transform: translateY(0); } 50% { transform: translateY(-7px); } } | |
| /* Mid-size laptops: not enough side margin, so make him smaller and let him | |
| straddle the left edge (mostly off-screen, arm reaching in) β keeps the | |
| "appears & points" beat without burying the case file. */ | |
| @media (min-width: 1181px) and (max-width: 1600px) { | |
| .inspector-fig { left: -22px; } | |
| .inspector-fig img { height: clamp(170px, 23vh, 250px); } | |
| } | |
| /* No room for him beside a narrow layout β fold him away. */ | |
| @media (max-width: 1180px) { .inspector-fig { display: none; } } | |
| /* ======================================================================= | |
| Inspector ROTATOR β sweep step. The detective cycles through the 4 corners | |
| OF THE LAPTOP (not the viewport), a different pose each time, hugging the | |
| laptop edges. ~4s on-screen each, 16s loop. | |
| ======================================================================= */ | |
| /* lives INSIDE .laptop-stage now, so it anchors to the laptop, not the page */ | |
| .laptop-stage .inspector-rotator { | |
| position: absolute; inset: 0; z-index: 4; pointer-events: none; | |
| } | |
| .laptop-stage .ir-slide { | |
| position: absolute; z-index: 4; pointer-events: none; | |
| height: 78%; /* proportional to the (cropped) laptop */ | |
| /* JS-driven rotation (NOT CSS animation) so EXACTLY one figure is ever | |
| visible β no edge case where all four flash at once. */ | |
| opacity: 0; transform: translateY(22px); | |
| transition: opacity 0.5s ease, transform 0.5s ease; | |
| } | |
| .laptop-stage .ir-slide.ir-on { opacity: 1; transform: translateY(0); } | |
| .laptop-stage .ir-slide img { | |
| display: block; height: 100%; width: auto; | |
| filter: drop-shadow(6px 8px 12px rgba(0,0,0,0.65)); | |
| } | |
| /* The cropped laptop fills its stage, so the stage corners ARE the laptop | |
| corners β figures hug them, peeking just outside. */ | |
| .laptop-stage .ir-tl { top: 8%; left: -12%; } | |
| .laptop-stage .ir-tr { top: 8%; right: -12%; } | |
| .laptop-stage .ir-bl { bottom: 0%; left: -12%; } | |
| .laptop-stage .ir-br { bottom: 0%; right: -12%; } | |
| /* The bottom-right figure (lean) faces right by default β flip it so it looks | |
| toward the laptop in the centre. (transform on the IMG, independent of the | |
| slide's own transform.) */ | |
| .laptop-stage .ir-br img { transform: scaleX(-1); } | |
| /* Hide the rotator while the intro full-screen video plays. */ | |
| .sweep-viewer.has-intro .inspector-rotator { display: none; } | |
| @media (max-width: 1180px) { .inspector-rotator { display: none; } } | |
| @media (prefers-reduced-motion: reduce) { | |
| .insp-point { animation: inspIn 0.4s ease 0.5s both; } | |
| .insp-lean { animation: inspIn 0.4s ease 0.5s both; } | |
| } | |
| /* ======================================================================= | |
| SWEEP step only β the detective's laptop frames the live scan. The PNG has | |
| BOTH the surround AND the screen punched out to transparent (chroma keyed in | |
| process_laptop.py). The scan goes INSIDE the screen rect computed from the | |
| asset; the laptop image stays in front so the bezel reads as a real device. | |
| ======================================================================= */ | |
| .sweep-viewer { background: transparent ; border: none ; box-shadow: none ; overflow: visible ; min-height: 0 ; } | |
| /* SWEEP step: the laptop asset is cropped (fills its stage), so NO negative | |
| margins are needed. Just keep the rail tight and let the figures overflow. */ | |
| body.uxc-sweep .steps { margin: 4px auto 2px ; } | |
| body.uxc-sweep .sweep-viewer, | |
| body.uxc-sweep .screen-sweep, | |
| body.uxc-sweep .screen-sweep > div, | |
| body.uxc-sweep .screen-sweep .gr-group, | |
| body.uxc-sweep .screen-sweep .styler, | |
| body.uxc-sweep .screen-sweep .block, | |
| body.uxc-sweep .screen-sweep .form, | |
| body.uxc-sweep .column, | |
| body.uxc-sweep .contain, | |
| body.uxc-sweep main.fillable { overflow: visible ; } | |
| /* Status bar UNDER the laptop. REC + CAMΒ·timer share the top line; the cycling | |
| status message wraps to its OWN full-width line so a long phrase can never | |
| overlap the timer. */ | |
| .scan-status-bar { | |
| display: flex; flex-wrap: wrap; align-items: center; justify-content: center; | |
| gap: 4px 22px; | |
| margin: 14px auto 0; padding: 0 14px; max-width: 900px; | |
| font-family: 'Oswald', sans-serif; letter-spacing: 0.16em; text-transform: uppercase; | |
| font-size: 12px; color: #8a857a; | |
| } | |
| .scan-status-bar .rec { display: inline-flex; align-items: center; gap: 6px; color: var(--blood-bright); font-family: 'Special Elite', monospace; } | |
| .scan-status-bar .rec-dot { color: var(--blood-bright); animation: blink 1.1s step-start infinite; } | |
| .scan-status-bar .scan-ch { color: #6a665d; font-family: 'Special Elite', monospace; letter-spacing: 0.1em; white-space: nowrap; } | |
| .scan-status-bar .scan-status { | |
| flex: 1 1 100%; /* its OWN line */ | |
| position: relative; height: 18px; min-width: 0; text-align: center; | |
| } | |
| .laptop-stage { | |
| position: relative; | |
| /* Cropped laptop asset (890x594) β it now FILLS its stage, no dead margins. */ | |
| width: min(1120px, 80vw); | |
| aspect-ratio: 890 / 594; | |
| margin: 8px auto 0; | |
| display: block; | |
| overflow: visible; | |
| } | |
| .laptop-frame-img { | |
| position: absolute; inset: 0; width: 100%; height: 100%; | |
| z-index: 3; pointer-events: none; /* the bezel sits in front, framing the screen */ | |
| filter: drop-shadow(0 28px 50px rgba(0,0,0,0.7)); | |
| } | |
| .laptop-screen { | |
| position: absolute; z-index: 2; | |
| background: #000; overflow: hidden; | |
| box-shadow: inset 0 0 28px rgba(0,0,0,0.7); | |
| border-radius: 2px; | |
| } | |
| .laptop-stage .scan-stage { aspect-ratio: auto; width: 100%; height: 100%; } | |
| .laptop-stage .scan-stage .scan-photo { width: 100%; height: 100%; object-fit: cover; display: block; } | |
| /* On tablet/phone the laptop reads as a tiny postcard β show the scan flat */ | |
| @media (max-width: 900px) { | |
| .laptop-stage { aspect-ratio: auto; } | |
| .laptop-frame-img { display: none; } | |
| .laptop-screen { position: static; width: 100%; height: auto; aspect-ratio: 16/9; } | |
| } | |
| /* ======================================================================= | |
| STEP 1 β The Detective's Desk (top-down, full viewport background) | |
| ======================================================================= */ | |
| /* THE KEY: while step 1 is visible, the body itself becomes the desk. We | |
| override the noir gradient bg from `body` !important, set the desk as the | |
| body background-image, and add a fixed vignette on top. Way more reliable | |
| than fighting Gradio's wrapper stack with ::before/::after on .screen-upload. */ | |
| body.uxc-upload { | |
| background-image: var(--asset-desk) ; | |
| background-color: #1a120c ; | |
| background-size: cover ; | |
| background-position: center ; | |
| background-attachment: fixed ; | |
| } | |
| body.uxc-upload .gradio-container, | |
| body.uxc-upload .gradio-container::after { background: transparent ; } | |
| /* vignette to focus the Polaroid */ | |
| body.uxc-upload::after { | |
| content: ""; | |
| position: fixed; inset: 0; z-index: -1; pointer-events: none; | |
| background: radial-gradient(ellipse at center, transparent 25%, rgba(0,0,0,0.55) 100%); | |
| } | |
| body.uxc-upload #ux-header, | |
| body.uxc-upload .steps { display: none ; } | |
| body.uxc-upload .gradio-container { max-width: none ; padding: 0 ; } | |
| /* Step 1 is a single fixed viewport β no scroll possible. */ | |
| body.uxc-upload { overflow: hidden ; } | |
| /* Keep the footer credits, but fix them to the viewport bottom so they don't | |
| add scroll height. Restyled to read over the wood. */ | |
| body.uxc-upload .status-line { | |
| position: fixed ; left: 0; right: 0; bottom: 0; | |
| margin: 0 ; z-index: 7; padding: 8px 12px; | |
| text-align: center; pointer-events: none; | |
| color: #e0d3ae ; | |
| background: rgba(0,0,0,0.7); | |
| box-shadow: 0 -6px 16px rgba(0,0,0,0.45); | |
| text-shadow: 0 1px 4px rgba(0,0,0,0.9); | |
| } | |
| /* CRITICAL: the fixed/full-screen treatment ONLY applies while step 1 is the | |
| ACTIVE step (body.uxc-upload). When it's NOT active, Gradio collapses the | |
| hidden upload to height 0 β we hide it hard so it can't cover the verdict. */ | |
| body:not(.uxc-upload) .screen-upload { display: none ; } | |
| /* Gradio renders the upload group as TWO nested .screen-upload divs. Make the | |
| OUTER one the fixed scroll viewport and the INNER one the centered flex column, | |
| so the desk centers when it fits and scrolls when it doesn't (shorter laptops | |
| once the cold-cases + MOST WANTED sign are in play). */ | |
| body.uxc-upload .screen-upload:has(.screen-upload) { | |
| position: fixed ; inset: 0 ; | |
| height: 100vh ; max-height: 100vh ; | |
| width: 100vw ; max-width: 100vw ; | |
| box-sizing: border-box ; | |
| display: block ; padding: 0 ; margin: 0 ; gap: 0 ; | |
| overflow-y: auto ; overflow-x: hidden ; | |
| scrollbar-width: none; | |
| background: transparent ; z-index: 1; | |
| animation: deskRise 1.1s ease-out both; | |
| } | |
| body.uxc-upload .screen-upload:has(.screen-upload)::-webkit-scrollbar { width: 0; height: 0; } | |
| body.uxc-upload .screen-upload:not(:has(.screen-upload)) { | |
| position: static ; | |
| min-height: 100% ; height: auto ; max-height: none ; | |
| width: 100% ; max-width: 100% ; | |
| display: flex ; flex-direction: column ; | |
| align-items: center ; justify-content: flex-start ; | |
| gap: 18px ; padding: 18px 0 24px ; margin: 0 ; | |
| background: transparent ; overflow: visible ; | |
| } | |
| /* Center the content block when it fits; collapse to top + scroll when it doesn't. | |
| The ::after is a real flex item (NOT padding, so it survives the scroll range) that | |
| both anchors the bottom centering AND leaves room below MOST WANTED to clear the | |
| fixed footer at scroll-end. */ | |
| body.uxc-upload .screen-upload:not(:has(.screen-upload)) > :first-child { margin-top: auto ; } | |
| body.uxc-upload .screen-upload:not(:has(.screen-upload))::after { | |
| content: ""; flex: 0 0 88px; width: 1px; margin-bottom: auto; pointer-events: none; | |
| } | |
| /* Center the inner wrappers β only while active. */ | |
| body.uxc-upload .screen-upload > div, body.uxc-upload .screen-upload .gr-group, | |
| body.uxc-upload .screen-upload .styler, body.uxc-upload .screen-upload .form, | |
| body.uxc-upload .screen-upload .column { | |
| width: 100% ; max-width: 100% ; | |
| align-self: stretch ; | |
| display: flex ; flex-direction: column ; | |
| align-items: center ; justify-content: center ; | |
| } | |
| /* The 'block' wrapper directly around #evidence-drop is display:block and won't | |
| auto-center the polaroid. Force margin auto to centre it horizontally. */ | |
| .screen-upload .block.auto-margin, | |
| .screen-upload .block { | |
| margin-left: auto ; margin-right: auto ; | |
| width: auto ; max-width: 100% ; | |
| } | |
| @keyframes deskRise { | |
| from { opacity: 0; filter: blur(8px) brightness(0.55); } | |
| to { opacity: 1; filter: none; } | |
| } | |
| /* ---- The Polaroid (wraps Gradio's gr.Image) ---- */ | |
| #evidence-drop { | |
| position: relative; | |
| width: min(520px, 46vw) ; | |
| height: auto ; | |
| flex: 0 0 auto ; | |
| background: #f6efdb ; | |
| padding: 18px 18px 60px ; | |
| border: 1px solid #b29a6c ; | |
| box-shadow: | |
| 0 28px 50px rgba(0,0,0,0.7), | |
| inset 0 0 0 1px rgba(0,0,0,0.05) ; | |
| transition: transform 0.25s ease, box-shadow 0.25s ease; | |
| border-radius: 2px; | |
| overflow: visible ; | |
| /* no rotation β straight on the desk */ | |
| } | |
| #evidence-drop:hover { | |
| transform: translateY(-4px); | |
| box-shadow: 0 36px 60px rgba(0,0,0,0.8), inset 0 0 0 1px rgba(0,0,0,0.05) ; | |
| } | |
| /* Yellow crime-scene tape strapping the polaroid: TWO diagonal strips top+bottom. */ | |
| #evidence-drop .tape-top, #evidence-drop .tape-bot { | |
| position: absolute ; | |
| left: -38px ; right: -38px ; | |
| height: 30px ; width: auto ; | |
| background-image: repeating-linear-gradient(135deg, | |
| #f1c40f 0 24px, | |
| #1a1a1a 24px 32px) ; | |
| background-color: transparent ; | |
| background-size: auto ; | |
| opacity: 0.92 ; | |
| box-shadow: 0 4px 8px rgba(0,0,0,0.55) ; | |
| pointer-events: none; | |
| z-index: 10 ; | |
| border: none ; | |
| padding: 0 ; | |
| } | |
| #evidence-drop .tape-top { top: 18px ; transform: rotate(-7deg) ; } | |
| #evidence-drop .tape-bot { bottom: 50px ; transform: rotate(8deg) ; } | |
| /* The "EVIDENCE PHOTO" field label floats over the image β hide it entirely | |
| (the desk header + the drop guide already explain everything). */ | |
| #evidence-drop .label-wrap, #evidence-drop > label, #evidence-drop label.float, | |
| #evidence-drop label[data-testid="block-label"] { display: none ; } | |
| /* Strip Gradio's grey block backgrounds INSIDE the polaroid β but DON'T touch | |
| the tape strips or the guide (they need their own background/padding). */ | |
| #evidence-drop > div:not(.tape-top):not(.tape-bot):not(.poladrop-guide), | |
| #evidence-drop .gr-block, #evidence-drop .block, | |
| #evidence-drop .preview, #evidence-drop .image-container, | |
| #evidence-drop .image-frame, #evidence-drop .form { | |
| background: transparent ; | |
| border: none ; | |
| padding: 0 ; | |
| box-shadow: none ; | |
| } | |
| /* the .wrap (the drop slot) needs its dark color; the 4/3 frame is set below */ | |
| #evidence-drop .wrap:not(.default):not(.center):not(.full) { | |
| background: #2b2b2b ; | |
| border: 2px dashed rgba(255,255,255,0.18) ; | |
| padding: 0 ; | |
| box-shadow: none ; | |
| height: auto ; min-height: 0 ; | |
| } | |
| /* When an image is uploaded, Gradio shows a preview. The slot keeps the 4/3 | |
| polaroid frame and the preview fits INSIDE it (contain) β the user's evidence | |
| is never cropped; the dark slot reads as the photo's matte. */ | |
| #evidence-drop .image-container, | |
| #evidence-drop .image-frame, | |
| #evidence-drop [data-testid="image"] { | |
| aspect-ratio: 4 / 3 ; | |
| width: 100% ; height: auto ; | |
| overflow: hidden ; border-radius: 2px; | |
| } | |
| #evidence-drop .image-container img, | |
| #evidence-drop .image-frame img, | |
| #evidence-drop [data-testid="image"] img, | |
| #evidence-drop img.svelte-1btp92j, #evidence-drop img { | |
| width: 100% ; height: 100% ; | |
| object-fit: contain ; object-position: center ; | |
| display: block ; | |
| background: #2b2b2b; | |
| } | |
| /* The clickable/droppable area inside the polaroid: aspect-square photo slot. */ | |
| #evidence-drop .wrap:not(.default):not(.center):not(.full) { | |
| position: relative ; | |
| width: 100% ; | |
| aspect-ratio: 4 / 3 ; | |
| height: auto ; | |
| min-height: 0 ; | |
| cursor: pointer; | |
| background: #2b2b2b ; /* dark photo slot (reads like an empty frame) */ | |
| border: 2px dashed rgba(255,255,255,0.18) ; | |
| } | |
| /* Gradio's default upload placeholder: hide everything inside .wrap except | |
| the file input itself. Our .poladrop-guide takes over the visual. */ | |
| #evidence-drop .wrap > * { display: none ; } | |
| #evidence-drop .wrap > input[type=file] { display: block ; | |
| position: absolute ; inset: 0 ; opacity: 0 ; | |
| width: 100% ; height: 100% ; cursor: pointer; } | |
| /* Gradio sometimes renders a button/source toolbar below the wrap β kill it. */ | |
| #evidence-drop .source-selection, #evidence-drop .controls, | |
| #evidence-drop button[aria-label*="lear"], #evidence-drop .icon-button-wrapper, | |
| #evidence-drop > .source-selection { display: none ; } | |
| /* Our own dropzone guide, perfectly centered over the dark slot. */ | |
| .poladrop-guide { | |
| position: absolute ; | |
| left: 18px ; right: 18px ; top: 18px ; | |
| bottom: 60px ; /* matches polaroid padding-bottom */ | |
| z-index: 5 ; pointer-events: none; | |
| display: flex ; align-items: center ; justify-content: center ; | |
| flex-direction: column; gap: 8px; | |
| text-align: center; padding: 0; | |
| background: transparent ; | |
| } | |
| .poladrop-guide .pg-title { | |
| font-family: 'Anton', sans-serif ; text-transform: uppercase ; | |
| font-size: 22px ; letter-spacing: 0.05em ; color: #ede4cf ; | |
| text-shadow: 0 2px 6px rgba(0,0,0,0.8) ; | |
| } | |
| .poladrop-guide .pg-sub { | |
| font-family: 'Special Elite', monospace ; font-size: 13px ; | |
| letter-spacing: 0.08em ; color: #b9b2a3 ; | |
| text-shadow: 0 1px 4px rgba(0,0,0,0.7) ; | |
| } | |
| /* When Gradio has rendered the preview image, hide the guide (it's now a CHILD | |
| of #evidence-drop after JS moves it in, so use descendant not sibling). */ | |
| #evidence-drop:has(img[src]) .poladrop-guide { display: none ; } | |
| /* The Investigate button β big red rubber stamp underneath the polaroid. | |
| Width hugs its content (NOT full-width). Gradio stretches buttons by default, | |
| so force the button AND its wrapper to shrink-to-fit. */ | |
| #investigate-btn { | |
| position: relative; | |
| margin: 0 auto ; | |
| width: auto ; min-width: 0 ; max-width: max-content ; | |
| display: inline-flex ; align-items: center; justify-content: center; | |
| background: var(--blood) ; color: #fff ; | |
| font-family: 'Anton', 'Oswald', sans-serif ; | |
| font-size: 18px ; letter-spacing: 0.3em ; | |
| padding: 16px 34px ; | |
| border: 3px solid #000 ; border-radius: 0 ; | |
| box-shadow: 5px 5px 0 #000, 0 0 24px rgba(192,57,43,0.5) ; | |
| z-index: 6; | |
| align-self: center ; | |
| } | |
| #investigate-btn:hover { transform: translateY(-2px); } | |
| #investigate-btn:disabled, #investigate-btn[disabled] { | |
| filter: grayscale(0.7) brightness(0.7); opacity: 0.55; | |
| } | |
| /* The Gradio block wrapper around the button must also shrink to content and | |
| center, otherwise the button's max-content has a full-width parent to sit in. */ | |
| .screen-upload .block:has(#investigate-btn) { | |
| width: auto ; max-width: max-content ; | |
| margin: 0 auto ; align-self: center ; | |
| } | |
| /* Make the wrapper Gradio groups invisible AND collapse their height. */ | |
| .screen-upload > div, .screen-upload .gr-group, .screen-upload .gr-group > div, | |
| .screen-upload .form, .screen-upload .gradio-html, .screen-upload .block, | |
| .screen-upload .gr-block, .screen-upload .gr-padded { | |
| background: transparent ; | |
| border: none ; | |
| box-shadow: none ; | |
| padding: 0 ; | |
| margin: 0 ; | |
| height: auto ; min-height: 0 ; | |
| flex: 0 0 auto ; | |
| } | |
| /* Body and gradio-container shouldn't add their own height while step 1 shows */ | |
| body.uxc-upload .gradio-container, body.uxc-upload main { | |
| min-height: 100vh ; | |
| padding: 0 ; margin: 0 ; | |
| } | |
| body.uxc-upload footer { display: none ; } /* Gradio's own footer only */ | |
| /* ======================================================================= | |
| INTRO VIDEO β fullscreen "alley walk" that plays ONCE on first load. | |
| ======================================================================= */ | |
| #intro-alley { | |
| position: fixed; inset: 0; z-index: 99999; | |
| background: #000; | |
| display: flex; align-items: center; justify-content: center; | |
| opacity: 1; transition: opacity 1s ease; | |
| } | |
| #intro-alley.ended { opacity: 0; pointer-events: none; } | |
| #intro-alley video { width: 100vw; height: 100vh; object-fit: cover; } | |
| #intro-alley .skip-intro { | |
| position: absolute; right: 22px; bottom: 22px; z-index: 2; | |
| background: rgba(0,0,0,0.6); color: #d6cfb8; | |
| border: 1px solid #444; border-radius: 0; | |
| padding: 8px 16px; font-family: 'Oswald', sans-serif; | |
| letter-spacing: 0.2em; text-transform: uppercase; | |
| font-size: 11px; cursor: pointer; | |
| transition: background 0.2s, color 0.2s; | |
| } | |
| #intro-alley .skip-intro:hover { background: rgba(192,57,43,0.8); color: #fff; } | |
| #intro-alley { cursor: pointer; } | |
| /* Hint that floats at the bottom-center of the intro: "Click anywhere for sound" */ | |
| #intro-alley .intro-hint { | |
| position: absolute; left: 50%; bottom: 60px; | |
| transform: translateX(-50%); | |
| z-index: 3; pointer-events: none; | |
| display: inline-flex; align-items: center; gap: 10px; | |
| background: rgba(0,0,0,0.65); | |
| color: #fff; padding: 12px 22px; | |
| border: 1px solid rgba(255,255,255,0.25); | |
| font-family: 'Oswald', sans-serif; | |
| letter-spacing: 0.22em; text-transform: uppercase; font-size: 13px; | |
| box-shadow: 0 8px 24px rgba(0,0,0,0.6), 0 0 0 2px rgba(192,57,43,0.4); | |
| animation: hintPulse 1.8s ease-in-out infinite; | |
| } | |
| #intro-alley .intro-hint .ih-icon { font-size: 18px; } | |
| @keyframes hintPulse { | |
| 0%,100% { transform: translateX(-50%) translateY(0); opacity: 0.92; } | |
| 50% { transform: translateX(-50%) translateY(-4px); opacity: 1; } | |
| } | |
| #intro-alley .intro-vignette { | |
| position: absolute; inset: 0; pointer-events: none; | |
| background: radial-gradient(ellipse at center, transparent 55%, rgba(0,0,0,0.7) 100%); | |
| } | |
| /* ======================================================================= | |
| STEP 1 onboarding header β sits above the Polaroid on the desk, tells a | |
| first-time visitor what the app does and what to drop. | |
| ======================================================================= */ | |
| .desk-intro { | |
| text-align: center; | |
| max-width: 640px; margin: 0 auto 22px; /* extra breathing room above the polaroid */ | |
| display: flex; flex-direction: column; align-items: center; gap: 6px; | |
| filter: drop-shadow(0 2px 8px rgba(0,0,0,0.8)); | |
| } | |
| .desk-emblem { | |
| width: 76px; height: 76px; margin-bottom: 2px; | |
| background-color: #efe7d2; | |
| background-image: var(--asset-emblem); | |
| background-size: 92%; background-repeat: no-repeat; background-position: center; | |
| border-radius: 50%; | |
| box-shadow: 0 0 0 2px rgba(0,0,0,0.4), 0 8px 20px rgba(0,0,0,0.6); | |
| } | |
| .desk-kicker { | |
| font-family: 'Oswald', sans-serif; letter-spacing: 0.34em; font-size: 11px; | |
| color: #f1c40f; text-transform: uppercase; | |
| background: rgba(0,0,0,0.35); padding: 3px 12px; | |
| } | |
| .desk-title { | |
| font-family: 'Anton', sans-serif; font-size: clamp(30px, 4vw, 48px); | |
| letter-spacing: 0.05em; color: #f6efdb; margin: 2px 0 0; | |
| text-shadow: 2px 2px 0 #000, 0 12px 26px rgba(0,0,0,0.8); | |
| } | |
| .desk-sub { | |
| font-family: 'Special Elite', monospace; font-size: 14px; line-height: 1.5; | |
| color: #ece3cb; margin: 4px 0 0; max-width: 560px; | |
| text-shadow: 0 1px 4px rgba(0,0,0,0.9); | |
| } | |
| .desk-sub b { color: #f1c40f; } | |
| @media (max-height: 760px) { | |
| .desk-sub { display: none; } /* tight screens: keep just the title */ | |
| .desk-emblem { width: 56px; height: 56px; } | |
| } | |
| /* ======================================================================= | |
| SOUND CONSENT GATE β the very first thing the visitor sees. | |
| ======================================================================= */ | |
| #sound-gate { | |
| position: fixed; inset: 0; z-index: 100002; | |
| display: flex; align-items: center; justify-content: center; | |
| background: #0a0a0a; | |
| overflow: hidden; | |
| transition: opacity 0.6s ease; | |
| } | |
| #sound-gate.gone { opacity: 0; pointer-events: none; } | |
| #sound-gate .sg-smoke { | |
| position: absolute; inset: 0; width: 100%; height: 100%; | |
| object-fit: cover; opacity: 0.65; filter: grayscale(0.25) brightness(0.78); | |
| } | |
| #sound-gate .sg-scrim { | |
| position: absolute; inset: 0; | |
| background: radial-gradient(ellipse at center, rgba(0,0,0,0.42) 35%, rgba(0,0,0,0.84) 100%); | |
| } | |
| #sound-gate .sg-inner { | |
| position: relative; z-index: 2; text-align: center; | |
| max-width: 600px; padding: 40px 28px; | |
| display: flex; flex-direction: column; align-items: center; gap: 14px; | |
| animation: sgRise 0.7s ease-out both; | |
| } | |
| @keyframes sgRise { from { opacity:0; transform: translateY(18px); } to { opacity:1; transform:none; } } | |
| #sound-gate .sg-emblem { | |
| width: 92px; height: 92px; | |
| background-color: #efe7d2; | |
| background-image: var(--asset-emblem); | |
| background-size: 92%; background-repeat: no-repeat; background-position: center; | |
| border-radius: 50%; | |
| box-shadow: 0 0 0 2px rgba(0,0,0,0.5), 0 0 40px rgba(192,57,43,0.4); | |
| margin-bottom: 4px; | |
| } | |
| #sound-gate .sg-kicker { | |
| font-family: 'Oswald', sans-serif; letter-spacing: 0.36em; font-size: 12px; | |
| color: #f1c40f; text-transform: uppercase; | |
| } | |
| #sound-gate h2 { | |
| font-family: 'Anton', sans-serif; font-size: clamp(28px, 4vw, 44px); | |
| letter-spacing: 0.03em; color: #f6efdb; margin: 4px 0 0; | |
| text-shadow: 2px 2px 0 #000; | |
| } | |
| #sound-gate p { | |
| font-family: 'Special Elite', monospace; font-size: 15px; line-height: 1.6; | |
| color: #d6cfb8; margin: 6px 0 10px; | |
| } | |
| #sound-gate .sg-btns { display: flex; gap: 16px; margin-top: 6px; flex-wrap: wrap; justify-content: center; align-items: stretch; } | |
| /* Both buttons: identical box model so they're exactly the same height. */ | |
| #sound-gate .sg-yes, #sound-gate .sg-no { | |
| box-sizing: border-box; height: 56px; | |
| display: inline-flex; align-items: center; justify-content: center; | |
| padding: 0 30px; border-radius: 0; cursor: pointer; | |
| } | |
| #sound-gate .sg-yes { | |
| background: var(--blood); color: #fff; | |
| font-family: 'Anton', sans-serif; font-size: 16px; letter-spacing: 0.16em; | |
| border: 3px solid #000; | |
| box-shadow: 5px 5px 0 #000, 0 0 26px rgba(192,57,43,0.55); | |
| transition: transform 0.12s ease; | |
| } | |
| #sound-gate .sg-yes:hover { transform: translateY(-2px); } | |
| #sound-gate .sg-no { | |
| background: #1a1a1a; color: #cfc7b2; | |
| font-family: 'Oswald', sans-serif; font-size: 14px; letter-spacing: 0.18em; text-transform: uppercase; | |
| border: 3px solid #000; | |
| box-shadow: 5px 5px 0 #000; /* same drop shadow as the YES button */ | |
| transition: transform 0.12s ease, background 0.15s, color 0.15s; | |
| } | |
| #sound-gate .sg-no:hover { transform: translateY(-2px); background: #262626; color: #fff; } | |
| #sound-gate .sg-no:hover { background: rgba(255,255,255,0.06); color: #fff; border-color: #888; } | |
| #sound-gate .sg-foot { | |
| font-family: 'Courier Prime', monospace; font-size: 11.5px; color: #8c856f; | |
| letter-spacing: 0.05em; margin-top: 10px; | |
| } | |
| /* Black cover dropped the instant FILE THE CASE is clicked, so the button can't | |
| be seen flashing while Gradio swaps to the sweep step + the intro mounts. */ | |
| #boot-cover { | |
| position: fixed; inset: 0; z-index: 9998; | |
| background: #000; opacity: 0; pointer-events: none; | |
| transition: opacity 0.18s ease; | |
| } | |
| #boot-cover.show { opacity: 1; pointer-events: all; } | |
| /* Overlay HTML blocks (sound gate, intro, bg video, page loader) hold only | |
| position:fixed content β collapse their Gradio wrappers to 0 height so they | |
| don't reserve empty vertical space above the header. */ | |
| .uxc-overlay, .uxc-overlay.html-container, .uxc-overlay .html-container { | |
| height: 0 ; min-height: 0 ; | |
| padding: 0 ; margin: 0 ; | |
| overflow: visible ; | |
| } | |
| /* ======================================================================= | |
| MOBILE β keep it FUNCTIONAL + a "best on desktop" notice. The heavy | |
| cinematic chrome (laptop frame, inspectors) is already hidden below ~1000px. | |
| ======================================================================= */ | |
| #desk-notice { | |
| position: fixed; left: 0; right: 0; top: 0; z-index: 100003; | |
| display: flex; align-items: center; gap: 10px; | |
| padding: 10px 12px; | |
| background: linear-gradient(#1a1a1a, #111); | |
| border-bottom: 2px solid var(--blood); | |
| box-shadow: 0 6px 18px rgba(0,0,0,0.6); | |
| font-family: 'Special Elite', monospace; font-size: 12px; line-height: 1.35; | |
| color: #e9e0c8; | |
| transform: translateY(0); transition: transform 0.35s ease, opacity 0.35s ease; | |
| } | |
| #desk-notice.gone { transform: translateY(-110%); opacity: 0; } | |
| #desk-notice .dn-ico { font-size: 18px; flex: 0 0 auto; } | |
| #desk-notice .dn-txt { flex: 1 1 auto; } | |
| #desk-notice .dn-txt b { color: var(--evidence); } | |
| #desk-notice .dn-x { | |
| flex: 0 0 auto; background: transparent; border: 1px solid #555; color: #cfc7b2; | |
| width: 26px; height: 26px; border-radius: 50%; cursor: pointer; font-size: 12px; | |
| } | |
| #desk-notice .dn-x:hover { background: var(--blood); color: #fff; border-color: var(--blood); } | |
| @media (min-width: 1025px) { #desk-notice { display: none ; } } | |
| /* The sound-gate smoke video is heavy on phones (and the renderer can hang) β | |
| drop it; the dark scrim alone reads fine. */ | |
| @media (max-width: 900px) { | |
| #sound-gate .sg-smoke { display: none ; } | |
| #sound-gate .sg-scrim { background: radial-gradient(ellipse at center, #1a1a1a 0%, #0a0a0a 100%); } | |
| } | |
| /* STEP 1 on phones: the diagonal crime-scene tape overlaps the dropzone text. | |
| Hide the tape and tighten the Polaroid so the guide is readable. */ | |
| @media (max-width: 760px) { | |
| #evidence-drop { width: min(360px, 86vw) ; padding: 14px 14px 46px ; } | |
| #evidence-drop .tape-top, #evidence-drop .tape-bot { display: none ; } | |
| .poladrop-guide { inset: 14px 14px 46px ; } | |
| .poladrop-guide .pg-title { font-size: 17px ; } | |
| .desk-intro { margin-bottom: 14px; } | |
| .desk-title { font-size: clamp(24px, 8vw, 34px); } | |
| .desk-sub { font-size: 12.5px; } | |
| body.uxc-upload .screen-upload { padding: 0 0 4vh ; gap: 16px; } | |
| } | |
| /* ======================================================================= | |
| Shared-link case loader β a clean OPAQUE "opening the case file" screen | |
| shown while a ?case=ID verdict streams in (replaces the old dim cover). | |
| ======================================================================= */ | |
| #case-loading { | |
| position: fixed; inset: 0; z-index: 100000; | |
| background: radial-gradient(ellipse at 50% 35%, #232323 0%, #141414 55%, #0a0a0a 100%); | |
| display: flex; flex-direction: column; align-items: center; justify-content: center; | |
| gap: 14px; text-align: center; | |
| transition: opacity 0.6s ease; | |
| } | |
| #case-loading.gone { opacity: 0; pointer-events: none; } | |
| #case-loading .cl-emblem { | |
| width: 96px; height: 96px; | |
| background-color: #efe7d2; background-image: var(--asset-emblem); | |
| background-size: 92%; background-repeat: no-repeat; background-position: center; | |
| border-radius: 50%; | |
| box-shadow: 0 0 0 2px rgba(0,0,0,0.5), 0 0 44px rgba(192,57,43,0.45); | |
| animation: plPulse 2.4s ease-in-out infinite; | |
| } | |
| #case-loading .cl-kicker { | |
| font-family: 'Oswald', sans-serif; letter-spacing: 0.36em; font-size: 12px; | |
| color: #f1c40f; text-transform: uppercase; | |
| } | |
| #case-loading .cl-title { | |
| font-family: 'Anton', sans-serif; font-size: clamp(24px, 3.4vw, 40px); | |
| letter-spacing: 0.04em; color: #f6efdb; text-shadow: 2px 2px 0 #000; | |
| } | |
| #case-loading .cl-dots { display: inline-flex; gap: 7px; margin-top: 4px; } | |
| #case-loading .cl-dots i { width: 8px; height: 8px; border-radius: 50%; background: var(--blood-bright); opacity: 0.3; animation: dotPulse 1.2s ease-in-out infinite; } | |
| #case-loading .cl-dots i:nth-child(2){ animation-delay: 0.2s; } | |
| #case-loading .cl-dots i:nth-child(3){ animation-delay: 0.4s; } | |
| /* ============================================================ | |
| UX/UI polish pass β legend Β· marker pulse Β· progress Β· cleared Β· a11y | |
| ============================================================ */ | |
| /* #1 β Severity legend (decodes the marker colours; only present ones shown) */ | |
| .hero-legend { | |
| display: flex; flex-wrap: wrap; gap: 18px; justify-content: center; | |
| margin: 0 0 12px; font-family: 'Oswald', sans-serif; font-size: 12px; | |
| letter-spacing: 0.14em; text-transform: uppercase; color: #c2bcae; | |
| } | |
| .hero-legend .lg-item { display: inline-flex; align-items: center; gap: 7px; } | |
| .hero-legend .lg-dot { | |
| width: 13px; height: 13px; border-radius: 50%; | |
| border: 2px solid rgba(0,0,0,.55); box-shadow: 0 0 0 1px rgba(255,255,255,.18); | |
| } | |
| /* #5 β Markers invite the hover (soft pulse ring) + keyboard focus */ | |
| .ev-pin .num::after { | |
| content: ""; position: absolute; inset: -2px; border-radius: 50%; | |
| pointer-events: none; box-shadow: 0 0 0 0 rgba(255,255,255,.5); | |
| animation: uxcPinPulse 2.8s ease-out infinite; | |
| } | |
| @keyframes uxcPinPulse { | |
| 0% { box-shadow: 0 0 0 0 rgba(255,255,255,.5); } | |
| 70%, 100% { box-shadow: 0 0 0 11px rgba(255,255,255,0); } | |
| } | |
| .ev-pin:focus-visible { outline: 3px solid #fff; outline-offset: 3px; border-radius: 50%; } | |
| .ev-pin:focus-visible .pop { opacity: 1; transform: none; } | |
| /* #2 β Indeterminate investigation progress bar (honest: shows activity, no fake ETA) */ | |
| .scan-progress { | |
| position: relative; height: 4px; margin: 10px 14px 2px; border-radius: 3px; | |
| background: rgba(255,255,255,.08); overflow: hidden; | |
| } | |
| .scan-progress .sp-bar { | |
| position: absolute; top: 0; height: 100%; width: 38%; left: -38%; | |
| background: linear-gradient(90deg, transparent, var(--blood), #e67e22, transparent); | |
| animation: uxcScanSlide 1.7s cubic-bezier(.4,0,.2,1) infinite; | |
| } | |
| @keyframes uxcScanSlide { 0% { left: -38%; } 100% { left: 100%; } } | |
| /* #3 β Cleared / "case dismissed": a genuinely clean (A/B) scene goes green, not blood */ | |
| .case-file.cleared .cf-verdict { color: #2e9e5b; } | |
| .case-file.cleared .cf-grade { | |
| background-image: none ; border: 6px solid #2e9e5b ; | |
| color: #2e9e5b ; box-shadow: 0 0 0 3px var(--paper), 4px 4px 0 #000 ; | |
| } | |
| /* #4 β Accessibility: respect reduced-motion for the new decorative animations */ | |
| @media (prefers-reduced-motion: reduce) { | |
| .ev-pin .num::after { animation: none; } | |
| .scan-progress .sp-bar { animation: none; left: 0; width: 100%; opacity: .5; } | |
| } | |
| /* Verdict masthead β the payoff (grade + title + verdict) leads the screen */ | |
| .verdict-strip { | |
| display: flex; align-items: center; gap: 18px; | |
| margin: 2px 0 14px; padding: 14px 18px; | |
| background: #161514; border: 1px solid #2c2a27; border-left: 4px solid var(--blood); | |
| } | |
| .verdict-strip .vs-grade { | |
| flex: 0 0 auto; width: 64px; height: 64px; border-radius: 50%; | |
| display: flex; align-items: center; justify-content: center; | |
| font-family: 'Anton', sans-serif; font-size: 38px; | |
| color: var(--blood); border: 4px solid var(--blood); | |
| background: rgba(192,57,43,0.08); | |
| transform: rotate(-8deg) scale(0); | |
| animation: gradeStamp 0.55s cubic-bezier(.2,1.7,.4,1) 0.35s both; | |
| } | |
| .verdict-strip .vs-text { display: flex; flex-direction: column; gap: 3px; min-width: 0; } | |
| .verdict-strip .vs-title { | |
| font-family: 'Anton', sans-serif; font-size: clamp(18px, 2.6vw, 28px); | |
| letter-spacing: 0.04em; text-transform: uppercase; color: var(--paper); line-height: 1.1; | |
| } | |
| .verdict-strip .vs-verdict { | |
| font-family: 'Oswald', sans-serif; font-size: 13px; letter-spacing: 0.22em; | |
| text-transform: uppercase; color: var(--blood-bright, #e74c3c); | |
| } | |
| .verdict-strip.cleared { border-left-color: #2e9e5b; } | |
| .verdict-strip.cleared .vs-grade { color: #2e9e5b; border-color: #2e9e5b; background: rgba(46,158,91,0.08); } | |
| .verdict-strip.cleared .vs-verdict { color: #2e9e5b; } | |
| /* Honest wait expectation under the progress bar */ | |
| .scan-eta { | |
| margin: 8px 14px 2px; font-family: 'Special Elite', monospace; | |
| font-size: 12px; color: #8d887c; text-align: center; | |
| } | |
| /* Touch devices: the hero-board popups are hover affordances β suppress them on | |
| small screens (the dossier below carries the same info), preventing 250px paper | |
| tooltips from overflowing the viewport edge on tap. */ | |
| @media (max-width: 760px) { | |
| .hero-wrap .ev-pin .pop { display: none ; } | |
| } | |
| /* Step indicator on the desk β step 1 of the same 3-step language */ | |
| .desk-steps { | |
| display: flex; align-items: center; justify-content: center; gap: 10px; | |
| margin: 10px 0 2px; font-family: 'Oswald', sans-serif; font-size: 11px; | |
| letter-spacing: 0.18em; color: #8d887c; | |
| } | |
| .desk-steps .ds-step { display: inline-flex; align-items: center; gap: 6px; white-space: nowrap; } | |
| .desk-steps .ds-step b { | |
| width: 20px; height: 20px; border-radius: 50%; display: inline-flex; | |
| align-items: center; justify-content: center; | |
| font-family: 'Anton', sans-serif; font-size: 11px; font-weight: 400; | |
| border: 2px solid #5a564d; color: #8d887c; | |
| } | |
| .desk-steps .ds-step.on { color: var(--evidence); } | |
| .desk-steps .ds-step.on b { border-color: var(--evidence); color: var(--evidence); } | |
| .desk-steps .ds-line { width: 34px; height: 1px; background: #4a463e; } | |
| /* Cold-case drawer β one-click example evidence */ | |
| .coldcase-head { | |
| margin: 20px auto 0; text-align: center; display: block; padding: 0; | |
| font-family: 'Special Elite', monospace; font-size: 12px; color: #f3ead2; | |
| background: none; border-radius: 0; backdrop-filter: none; | |
| text-shadow: 0 1px 2px #000, 0 0 7px rgba(0,0,0,0.92), 1px 1px 0 rgba(0,0,0,0.7); | |
| } | |
| #coldcase-row { display: flex; gap: 10px; justify-content: center; margin-top: 5px; flex-wrap: wrap; } | |
| #coldcase-row .coldcase-btn { | |
| flex: 0 1 auto ; min-width: 0 ; | |
| background: rgba(20,19,18,0.85) ; color: var(--paper) ; | |
| font-family: 'Oswald', sans-serif ; font-size: 12px ; | |
| letter-spacing: 0.16em ; text-transform: uppercase; | |
| border: 1px dashed rgba(241,196,15,0.55) ; border-radius: 0 ; | |
| box-shadow: 2px 2px 0 #000 ; padding: 8px 16px ; | |
| } | |
| #coldcase-row .coldcase-btn:hover { | |
| background: #241c0a ; border-style: solid ; | |
| transform: translate(-1px,-1px); box-shadow: 3px 3px 0 #000 ; | |
| } | |
| /* Remove / change the loaded evidence β appears only once a photo is in the slot */ | |
| #clear-evidence-btn { | |
| margin: 10px auto 0 ; | |
| max-width: 260px ; min-width: 0 ; | |
| background: rgba(20,19,18,0.85) ; color: var(--paper) ; | |
| font-family: 'Oswald', sans-serif ; font-size: 12px ; | |
| letter-spacing: 0.18em ; text-transform: uppercase ; | |
| border: 1px solid rgba(192,57,43,0.6) ; border-radius: 0 ; | |
| box-shadow: 2px 2px 0 #000 ; padding: 9px 18px ; | |
| } | |
| #clear-evidence-btn:hover { | |
| background: #2a1413 ; color: #fff ; | |
| border-color: var(--blood) ; | |
| transform: translate(-1px,-1px); box-shadow: 3px 3px 0 #000 ; | |
| } | |
| /* ============================================================ | |
| THE PRECINCT ARCHIVE β records-room drawer of famous booked cases | |
| ============================================================ */ | |
| .archive-details { margin-top: 16px; display: block ; } | |
| .archive-summary { | |
| display: block ; cursor: pointer; text-align: center; | |
| font-family: 'Special Elite', monospace ; font-size: 12px ; | |
| color: #c9a24a ; padding: 6px 0; transition: color .12s ease; | |
| user-select: none; letter-spacing: 0.04em; | |
| text-shadow: 0 1px 3px rgba(0,0,0,.6); | |
| } | |
| .archive-summary:hover { color: var(--evidence) ; } | |
| .archive-details.open .archive-summary { color: var(--evidence) ; } | |
| /* drawer hidden until opened via the JS toggle */ | |
| .archive-details .arch-drawer { display: none; } | |
| .archive-details.open .arch-drawer { display: block; } | |
| .arch-drawer { | |
| position: relative; margin-top: 14px; padding: 26px 18px 16px; | |
| background: #1d1c1a; border: 2px solid #34322d; border-radius: 6px; | |
| box-shadow: 0 18px 40px rgba(0,0,0,.7), inset 0 12px 26px rgba(0,0,0,.55); | |
| } | |
| .arch-drawer-tag { | |
| position: absolute; top: -12px; left: 26px; background: #0e0d0b; | |
| border: 1px solid #3a382f; color: #d9cfae; font-family: 'Special Elite', monospace; | |
| font-size: 10px; padding: 3px 12px; letter-spacing: 0.12em; | |
| } | |
| .arch-rail { | |
| display: grid; grid-template-columns: repeat(auto-fill, minmax(190px, 1fr)); | |
| gap: 18px; | |
| } | |
| .arch-folder { | |
| position: relative; display: block; margin-top: 14px; text-decoration: none ; | |
| background: #cdb98a; | |
| background-image: linear-gradient(180deg, rgba(0,0,0,.04), rgba(0,0,0,.12)); | |
| border-radius: 3px 3px 4px 4px; box-shadow: 0 7px 14px rgba(0,0,0,.5); | |
| padding: 10px 10px 9px; | |
| transition: transform .12s ease, box-shadow .12s ease; | |
| } | |
| .arch-folder:hover { transform: translateY(-4px) rotate(-0.6deg); box-shadow: 0 12px 22px rgba(0,0,0,.6); } | |
| .arch-tab { | |
| position: absolute; top: -14px; left: 10px; background: #cdb98a; | |
| padding: 2px 12px 1px; border-radius: 5px 5px 0 0; | |
| font-family: 'Courier Prime', monospace; font-weight: 700; font-size: 11px; color: #3a2f1c; | |
| box-shadow: 0 -2px 4px rgba(0,0,0,.18); | |
| } | |
| .arch-clip { | |
| position: absolute; top: -8px; right: 14px; width: 12px; height: 26px; | |
| border: 3px solid #777268; border-radius: 6px; border-bottom: none; | |
| } | |
| .arch-shot { display: block; border: 1px solid #8a7a52; height: 96px; overflow: hidden; background: #222; } | |
| .arch-shot img { width: 100%; height: 100%; object-fit: cover; display: block; } | |
| .arch-stamp { | |
| position: absolute; top: 30px; left: 50%; transform: translateX(-50%) rotate(-14deg); | |
| border: 3px solid rgba(178,34,28,.75); color: rgba(178,34,28,.8); | |
| font-family: 'Anton', sans-serif; font-size: 14px; letter-spacing: 0.2em; | |
| padding: 1px 9px; pointer-events: none; | |
| } | |
| .arch-meta { display: flex; justify-content: space-between; align-items: flex-end; margin-top: 8px; gap: 6px; } | |
| .arch-line { | |
| font-family: 'Special Elite', monospace; font-size: 10px; color: #4a3c24; line-height: 1.5; | |
| overflow: hidden; | |
| } | |
| .arch-line b { font-size: 11.5px; color: #2c2310; } | |
| .arch-seal { | |
| flex: 0 0 auto; width: 36px; height: 36px; border: 3px solid #b22; border-radius: 50%; | |
| color: #b22; font-family: 'Anton', sans-serif; font-size: 21px; | |
| display: flex; align-items: center; justify-content: center; | |
| transform: rotate(-9deg); background: rgba(255,255,255,.4); | |
| } | |
| .arch-seal.good { border-color: #2e7a4e; color: #2e7a4e; } | |
| .arch-hint { | |
| text-align: center; margin-top: 14px; | |
| font-family: 'Special Elite', monospace; font-size: 11px; color: #8d887c; | |
| } | |
| @media (max-width: 760px) { | |
| .arch-rail { grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 14px; } | |
| } | |
| /* Archive open inside the fixed desk: allow scrolling and top-align so the tall | |
| drawer isn't clipped by the desk's overflow:hidden + centered flex. */ | |
| body.uxc-upload .screen-upload:has(.archive-details.open) { | |
| overflow-y: auto ; | |
| justify-content: flex-start ; | |
| padding-top: 4vh ; | |
| } | |
| /* Keep the drawer a readable width on large screens. */ | |
| .arch-drawer { max-width: 1020px; width: min(94vw, 1020px); margin-left: auto; margin-right: auto; } | |
| .archive-details { width: 100%; } | |
| /* HARD CAP the polaroid's inner content: Gradio's transitional upload/preview | |
| states (and the post-clear placeholder) can momentarily render unconstrained | |
| and balloon the card. Nothing inside may exceed the photo slot height. */ | |
| #evidence-drop > div:not(.tape-top):not(.tape-bot):not(.poladrop-extras), | |
| #evidence-drop .wrap, | |
| #evidence-drop .upload-container, | |
| #evidence-drop .image-container, | |
| #evidence-drop .image-frame, | |
| #evidence-drop [data-testid="image"] { | |
| max-height: 380px ; | |
| overflow: hidden ; | |
| } | |
| #evidence-drop img { max-height: 380px ; } | |
| /* The Inspector's remedy β suggested correction per charge. Dark green ink on a | |
| faint green note so it reads clearly on the paper yet stands apart from the | |
| testimony. !important: the case-file paper styles override plain color. */ | |
| .ev-fix { | |
| margin-top: 8px; font-family: 'Courier Prime', monospace ; | |
| font-size: 13.5px ; font-weight: 700; | |
| color: #1f4d2a ; line-height: 1.55; | |
| background: rgba(46, 107, 63, 0.10); | |
| border-left: 4px solid #2e6b3f; border-radius: 0 3px 3px 0; | |
| padding: 6px 10px 6px 12px; display: block; | |
| } | |
| .ev-fix .ev-fix-tag { | |
| font-family: 'Oswald', sans-serif ; font-size: 10px ; | |
| font-weight: 500; letter-spacing: 0.2em; | |
| color: #f3efe2 ; background: #2e6b3f; padding: 2px 8px; | |
| margin-right: 8px; vertical-align: 1px; border-radius: 2px; | |
| } | |
| /* Gradio's status-tracker also carries class "wrap" β without this exclusion our | |
| photo-slot styling turned it into an invisible 362px block that stacked under | |
| the preview during upload/remove (the balloon flash). Kill it entirely. */ | |
| #evidence-drop .wrap.default, #evidence-drop .wrap.center, #evidence-drop .wrap.full, | |
| #evidence-drop [data-testid="status-tracker"] { | |
| display: none ; height: 0 ; min-height: 0 ; | |
| aspect-ratio: auto ; border: none ; background: none ; | |
| padding: 0 ; margin: 0 ; | |
| } | |
| /* =========================================================================== | |
| VERDICT POWER-UPS β Reconstruction (FLUX), Voice (Kokoro), Interrogation. | |
| Each is a dark dossier panel clipped under the case file, with a blood top | |
| rule and gold labels so they read as official extensions of the report. | |
| =========================================================================== */ | |
| .case-action { | |
| position: relative; margin: 22px auto 0; max-width: 860px; | |
| background: linear-gradient(180deg, #211d1a 0%, #1a1614 100%); | |
| border: 1px solid #3a322b; border-radius: 4px; | |
| box-shadow: 0 18px 40px rgba(0,0,0,0.45), inset 0 1px 0 rgba(255,255,255,0.03); | |
| padding: 20px 22px 22px; overflow: hidden; | |
| } | |
| .case-action::before { | |
| content: ""; position: absolute; top: 0; left: 0; right: 0; height: 4px; | |
| background: linear-gradient(90deg, #7a1f17, #c0392b 40%, #7a1f17); | |
| } | |
| .ca-head { | |
| font-family: 'Anton', sans-serif; letter-spacing: 0.04em; font-size: 19px; | |
| color: #ede4cf; text-transform: uppercase; line-height: 1.2; margin-bottom: 14px; | |
| } | |
| .ca-head .ca-ico { color: #c9a24a; margin-right: 8px; } | |
| .ca-head .ca-sub { | |
| display: block; font-family: 'Courier Prime', monospace; font-weight: 400; | |
| text-transform: none; letter-spacing: 0; font-size: 12.5px; | |
| color: #9c8f7d; margin-top: 5px; line-height: 1.5; | |
| } | |
| /* Shared noir action button */ | |
| .ca-btn, button.ca-btn { | |
| font-family: 'Oswald', sans-serif ; letter-spacing: 0.14em ; | |
| font-weight: 600 ; text-transform: uppercase; font-size: 13.5px ; | |
| color: #f3efe2 ; background: #2a2420 ; | |
| border: 1px solid #5a4b3c ; border-radius: 3px ; | |
| padding: 11px 18px ; transition: all .18s ease ; | |
| } | |
| .ca-btn:hover, button.ca-btn:hover { | |
| background: #c0392b ; border-color: #c0392b ; | |
| color: #fff ; transform: translateY(-1px); | |
| box-shadow: 0 8px 20px rgba(192,57,43,0.35) ; | |
| } | |
| /* ---- THE RECONSTRUCTION (before / after) ---- */ | |
| .reco-panel { margin-top: 16px; animation: recoFade .5s ease both; } | |
| .reco-panel.pending .reco-note { color: #b9a98f; } | |
| @keyframes recoFade { from { opacity: 0; transform: translateY(8px);} to { opacity:1; transform:none;} } | |
| .reco-head { | |
| font-family: 'Anton', sans-serif; font-size: 16px; letter-spacing: 0.05em; | |
| color: #c9a24a; text-transform: uppercase; margin-bottom: 4px; | |
| } | |
| .reco-sub { font-family: 'Courier Prime', monospace; font-size: 12.5px; color: #b9a98f; margin-bottom: 14px; line-height: 1.5; } | |
| .reco-grid { | |
| display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; gap: 12px; | |
| } | |
| .reco-col { margin: 0; } | |
| .reco-col img { | |
| width: 100%; border-radius: 3px; border: 1px solid #4a3f33; | |
| background: #0d0b0a; box-shadow: 0 10px 24px rgba(0,0,0,0.5); | |
| } | |
| .reco-col figcaption { | |
| margin-top: 8px; font-family: 'Courier Prime', monospace; font-size: 11.5px; | |
| color: #a89a85; line-height: 1.45; | |
| } | |
| .reco-tag { | |
| display: inline-block; font-family: 'Oswald', sans-serif; font-size: 9.5px; | |
| letter-spacing: 0.16em; font-weight: 600; padding: 2px 7px; border-radius: 2px; | |
| margin-right: 6px; vertical-align: 1px; | |
| } | |
| .reco-tag.found { background: #5a3a36; color: #f0d6d2; } | |
| .reco-tag.fixed { background: #2e6b3f; color: #eafff0; } | |
| .reco-arrow { font-size: 26px; color: #c0392b; text-align: center; } | |
| .reco-note { | |
| margin-top: 14px; font-family: 'Courier Prime', monospace; font-size: 11.5px; | |
| color: #8c7f6e; line-height: 1.5; border-top: 1px dashed #3a322b; padding-top: 12px; | |
| } | |
| @media (max-width: 640px) { | |
| .reco-grid { grid-template-columns: 1fr; } | |
| .reco-arrow { transform: rotate(90deg); } | |
| } | |
| /* ---- THE INSPECTOR'S VOICE ---- */ | |
| #verdict-voice { margin-top: 14px; background: transparent ; border: none ; } | |
| #verdict-voice audio { width: 100%; } | |
| /* ---- INTERROGATE THE INSPECTOR (chat) ---- */ | |
| #grill-chat { | |
| background: #141110 ; border: 1px solid #3a322b ; | |
| border-radius: 4px ; margin-top: 4px; | |
| } | |
| #grill-chat .message.user, #grill-chat [data-testid="user"] { | |
| background: #2a2420 ; color: #ede4cf ; | |
| border: 1px solid #4a3f33 ; font-family: 'Courier Prime', monospace ; | |
| } | |
| #grill-chat .message.bot, #grill-chat [data-testid="bot"] { | |
| background: #1c2a20 ; color: #d9e8dd ; | |
| border: 1px solid #2e4a38 ; font-family: 'Special Elite', 'Courier Prime', monospace ; | |
| } | |
| #grill-row { margin-top: 12px; gap: 8px; align-items: stretch; } | |
| #grill-input textarea, #grill-input input { | |
| background: #0f0d0c ; color: #ede4cf ; | |
| border: 1px solid #4a3f33 ; border-radius: 3px ; | |
| font-family: 'Courier Prime', monospace ; font-size: 14px ; | |
| } | |
| #grill-input textarea::placeholder { color: #6e6253 ; } | |
| #grill-send, button#grill-send { | |
| font-family: 'Oswald', sans-serif ; letter-spacing: 0.12em ; | |
| font-weight: 700 ; background: #c0392b ; color: #fff ; | |
| border: none ; border-radius: 3px ; min-width: 92px; | |
| } | |
| #grill-send:hover { background: #d8443491 ; filter: brightness(1.1); } | |
| /* =========================================================================== | |
| VERDICT BROADCAST DESK (P1-A final): masthead | feed + rail | bottom strip. | |
| Gradio Rows/Columns provide the skeleton; these styles dress each region. | |
| =========================================================================== */ | |
| /* ---- masthead ---- */ | |
| .va-top{align-items:stretch ;gap:10px ;margin-bottom:2px} | |
| .va-topbar{flex:1} | |
| .vt-bar{display:flex;align-items:center;gap:13px;background:linear-gradient(90deg,#1a1512,#241d18); | |
| border:1px solid #3a322b;border-top:3px solid #c0392b;padding:9px 16px;min-height:58px} | |
| .vt-logo{width:44px;height:44px;border-radius:50%;flex:none;display:grid;place-items:center; | |
| background:radial-gradient(circle at 38% 30%,#f3ead2,#d9c08c 70%); | |
| box-shadow:0 0 0 2px #c9a24a,0 3px 8px #000} | |
| .vt-logo img{width:82%;height:82%;object-fit:contain} | |
| .vt-brand{font-family:'Oswald',sans-serif;font-size:9px;letter-spacing:.24em;color:#8c7f6e;line-height:1.4} | |
| .vt-brand b{display:block;font-family:'Anton',sans-serif;font-size:13px;letter-spacing:.08em;color:#ede4cf} | |
| .vt-sep{width:1px;align-self:stretch;background:#3a322b;margin:0 2px} | |
| .vt-grade{font-family:'Anton',sans-serif;font-size:22px;color:#fff;background:#c0392b;width:40px;height:40px; | |
| flex:none;border-radius:50%;display:grid;place-items:center; | |
| box-shadow:0 0 0 3px #00000055,0 0 0 5px #c9a24a} | |
| .vt-grade.cleared{background:#2e9e5b} | |
| .vt-text{min-width:0} | |
| .vt-title{display:block;font-family:'Anton',sans-serif;font-size:clamp(15px,1.5vw,20px);letter-spacing:.04em; | |
| text-transform:uppercase;color:#ede4cf;white-space:nowrap;overflow:hidden;text-overflow:ellipsis} | |
| .vt-sub{display:block;font-family:'Oswald',sans-serif;font-size:10px;letter-spacing:.16em;color:#c9a24a;margin-top:2px} | |
| #newcase-btn{align-self:center;font-family:'Oswald',sans-serif ;letter-spacing:.14em ; | |
| font-weight:600 ;font-size:12px ;color:#ede4cf ;background:#2a2420 ; | |
| border:1px solid #5a4b3c ;border-radius:3px ;padding:14px 18px ; | |
| min-width:0 ;flex:none ;width:auto ;transition:all .15s ease } | |
| #newcase-btn:hover{background:#c0392b ;border-color:#c0392b } | |
| /* ---- the evidence feed ---- */ | |
| .va-feed{position:relative;background:#000;border:1px solid #3a322b;padding:10px 12px 14px ;border-radius:2px} | |
| .feed-tag{font-family:'Oswald',sans-serif;font-size:10px;letter-spacing:.2em;color:#ede4cf; | |
| background:#171310;border-left:3px solid #c0392b;padding:6px 10px;margin-bottom:8px;display:inline-block} | |
| .feed-insp{position:absolute;bottom:0;right:-6px;width:clamp(120px,11vw,190px); | |
| filter:drop-shadow(0 8px 20px #000);pointer-events:none;z-index:5} | |
| /* ---- right rail: file + interrogation ---- */ | |
| .va-rail{gap:10px } | |
| .file-panel{background:#1d1916;border:1px solid #3a322b;display:flex;flex-direction:column;min-height:0} | |
| .fp-head{font-family:'Oswald',sans-serif;font-size:11px;letter-spacing:.22em;color:#c9a24a; | |
| padding:10px 13px;border-bottom:1px solid #3a322b;background:#171310;display:flex;justify-content:space-between;align-items:center} | |
| .fp-stamp{font-family:'Anton',sans-serif;color:#e74c3c;border:2px solid #e74c3c99;padding:0 7px;font-size:11px;transform:rotate(-6deg)} | |
| .file-panel.cleared .fp-stamp{color:#2e9e5b;border-color:#2e9e5b99} | |
| .fp-scroll{overflow:auto;max-height:300px;padding:10px 14px;font-size:12.5px;line-height:1.5} | |
| .fp-summary{color:#bdae97;font-family:'Special Elite',monospace;font-size:12px;padding-bottom:6px;border-bottom:1px dashed #3a322b} | |
| .fp-charge{display:flex;gap:9px;padding:9px 0;border-bottom:1px dashed #3a322b;animation:fpIn .4s ease both;animation-delay:calc(var(--i)*.12s)} | |
| @keyframes fpIn{from{opacity:0;transform:translateY(5px)}to{opacity:1;transform:none}} | |
| .fp-num{font-family:'Anton',sans-serif;color:#fff;background:#c0392b;min-width:22px;height:22px; | |
| border-radius:50%;display:grid;place-items:center;font-size:12px;flex:none} | |
| .fp-body{min-width:0} | |
| .fp-crime{font-weight:700;color:#ede4cf} | |
| .fp-sev{font-style:normal;font-family:'Oswald',sans-serif;font-size:9px;letter-spacing:.14em;text-transform:uppercase;padding:1px 6px;border-radius:2px;vertical-align:1px} | |
| .fp-sev.capital{background:#c0392b;color:#fff}.fp-sev.high{background:#e74c3c33;color:#ff9d92} | |
| .fp-sev.medium{background:#e67e2233;color:#f3b97e}.fp-sev.low{background:#f1c40f22;color:#e8d27a} | |
| .fp-test{color:#a89a85;font-size:11.5px;font-family:'Special Elite',monospace} | |
| .fp-fix{color:#7fb88f;font-size:11px;margin-top:3px;border-left:3px solid #2e6b3f;padding-left:7px} | |
| .fp-closing{font-family:'Special Elite',monospace;font-size:11.5px;color:#bdae97;padding-top:8px} | |
| .rail-ph{font-family:'Oswald',sans-serif;font-size:11px;letter-spacing:.22em;color:#c9a24a; | |
| background:#171310;border:1px solid #3a322b;border-bottom:0;padding:9px 13px;margin-bottom:-10px} | |
| .rail-ph b{color:#c0392b;margin-right:5px} | |
| .rail-ph span{display:block;font-family:'Courier Prime',monospace;font-size:10px;letter-spacing:0;color:#8c7f6e;text-transform:none;margin-top:2px} | |
| .tw-on::after{content:"\258C";color:#c9a24a;animation:twb 1s infinite} | |
| @keyframes twb{50%{opacity:0}} | |
| /* ---- bottom strip cells ---- */ | |
| .va-bottom{align-items:stretch ;gap:10px } | |
| .va-cell{background:#1d1916 ;border:1px solid #3a322b ;border-radius:2px; | |
| padding:10px 13px 13px ;gap:9px } | |
| .cell-ph{font-family:'Oswald',sans-serif;font-size:11px;letter-spacing:.22em;color:#c9a24a} | |
| .cell-ph b{color:#c0392b;margin-right:5px} | |
| .cell-ph span{display:block;font-family:'Courier Prime',monospace;font-size:10px;letter-spacing:0;color:#8c7f6e;text-transform:none;margin-top:2px} | |
| /* reconstruction thumbnails */ | |
| .rk-strip{display:flex;gap:10px;flex-wrap:wrap} | |
| .rk{position:relative;width:170px;border:1px solid #4a3f33;overflow:hidden;cursor:pointer; | |
| transition:all .15s ease;text-decoration:none;display:block} | |
| .rk:hover{border-color:#c9a24a;transform:translateY(-2px)} | |
| .rk img{width:100%;height:92px;object-fit:cover;display:block} | |
| .rk-num{position:absolute;top:5px;left:5px;font-family:'Anton',sans-serif;font-size:11px;background:#c0392b; | |
| color:#fff;width:18px;height:18px;border-radius:50%;display:grid;place-items:center;z-index:2} | |
| .rk-zoom{position:absolute;inset:0;display:grid;place-items:center;background:rgba(10,8,6,.5);opacity:0;transition:.15s} | |
| .rk:hover .rk-zoom{opacity:1} | |
| .rk-zoom span{font-family:'Oswald',sans-serif;font-size:9px;letter-spacing:.14em;background:#000d; | |
| border:1px solid #c9a24a;color:#c9a24a;padding:4px 8px} | |
| .rk-badge{position:absolute;bottom:0;left:0;right:0;font-family:'Oswald',sans-serif;font-size:8.5px; | |
| letter-spacing:.14em;text-align:center;background:#000c;color:#7fb88f;padding:3px} | |
| .reco-note{font-family:'Courier Prime',monospace;font-size:11px;color:#8c7f6e;line-height:1.5} | |
| /* the comparator modal (:target) */ | |
| .cmp-modal{position:fixed;inset:0;display:none;place-items:center;z-index:300} | |
| .cmp-modal:target{display:grid} | |
| .cmp-bg{position:absolute;inset:0;background:rgba(8,6,4,.9)} | |
| .cmp-box{position:relative;width:min(760px,92vw);background:#1d1916;border:1px solid #c9a24a; | |
| padding:18px;box-shadow:0 40px 90px #000;z-index:2} | |
| .cmp-close{position:absolute;top:8px;right:12px;color:#8c7f6e;font-size:18px;text-decoration:none} | |
| .cmp-close:hover{color:#ede4cf} | |
| .cmp-h{font-family:'Anton',sans-serif;font-size:16px;letter-spacing:.05em;color:#c9a24a;margin-bottom:4px} | |
| .cmp-s{font-family:'Courier Prime',monospace;font-size:11px;color:#9c8f7d;margin-bottom:12px} | |
| .cmp{position:relative;width:100%;aspect-ratio:1.6;overflow:hidden;border:1px solid #4a3f33;user-select:none} | |
| .cmp img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover} | |
| .cmp .cmp-after{clip-path:inset(0 0 0 50%)} | |
| .cmp-handle{position:absolute;top:0;bottom:0;left:50%;width:3px;background:#c9a24a;box-shadow:0 0 12px #c9a24a88;pointer-events:none} | |
| .cmp-handle::after{content:"\25C2 \25B8";position:absolute;top:50%;left:50%;transform:translate(-50%,-50%); | |
| background:#c9a24a;color:#1d1916;font-size:11px;padding:6px 8px;border-radius:18px;white-space:nowrap;font-family:'Oswald',sans-serif} | |
| .cmp-lb{position:absolute;top:10px;font-family:'Oswald',sans-serif;font-size:9.5px;letter-spacing:.16em;padding:4px 9px;background:#000c} | |
| .cmp-lb.l{left:10px;color:#f0a9a0}.cmp-lb.r{right:10px;color:#9fe7b4} | |
| .cmp input.cmp-rng{position:absolute;inset:0;width:100%;height:100%;opacity:0;cursor:ew-resize;margin:0} | |
| /* share panel */ | |
| .share-panel{display:flex;flex-direction:column;gap:8px} | |
| .sp-row1{display:flex;gap:6px;align-items:center;flex-wrap:wrap} | |
| .sp-dl{display:flex;align-items:center;gap:7px;font-family:'Oswald',sans-serif;font-size:10px;letter-spacing:.12em; | |
| background:#2a2420;border:1px solid #c9a24a;color:#c9a24a ;padding:9px 12px;cursor:pointer; | |
| text-decoration:none ;transition:.15s} | |
| .sp-dl:hover{background:#c9a24a;color:#1d1916 } | |
| .sp-btn{display:grid;place-items:center;width:34px;height:34px;border-radius:3px;color:#fff ;text-decoration:none } | |
| .sp-btn svg{width:16px;height:16px;fill:currentColor} | |
| .sp-btn.x{background:#000;border:1px solid #444}.sp-btn.wa{background:#1faa53} | |
| .sp-btn.fb{background:#1668d8}.sp-btn.li{background:#0a66c2} | |
| .sp-row2{display:flex;gap:6px} | |
| .sp-link{flex:1;font-family:'Courier Prime',monospace;font-size:11.5px;color:#cbbfa8;background:#0f0d0c; | |
| border:1px solid #4a3f33;padding:9px 10px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis} | |
| .sp-copy{font-family:'Oswald',sans-serif;font-size:10px;letter-spacing:.12em;background:#c0392b;color:#fff; | |
| border:0;padding:0 14px;cursor:pointer;transition:.15s} | |
| .sp-copy.ok{background:#2e9e5b} | |
| /* the broadcast desk needs the full width */ | |
| body.uxc-verdict .screen-verdict{max-width:1560px;margin:0 auto} | |
| /* mobile: stack naturally; cap feed inspector */ | |
| @media (max-width:900px){ | |
| .vt-title{white-space:normal} | |
| .feed-insp{width:96px} | |
| .fp-scroll{max-height:240px} | |
| } | |
| /* the broadcast masthead replaces the page header + wizard on the verdict */ | |
| body.uxc-verdict #ux-header, body.uxc-verdict .steps { display: none ; } | |
| /* FULL TAKEOVER: the broadcast desk replaces the noir stage entirely */ | |
| body.uxc-verdict{background:#0d0a08 } | |
| body.uxc-verdict #bg-video-wrap, | |
| body.uxc-verdict #laptop-overlay, | |
| body.uxc-verdict .status-line, | |
| body.uxc-verdict .inspector-fig{display:none } | |
| body.uxc-verdict gradio-app,body.uxc-verdict .gradio-container{background:#0d0a08 ;max-width:100% } | |
| body.uxc-verdict .screen-verdict{max-width:1560px;margin:0 auto;padding:12px 16px 20px} | |
| /* compact the native audio player into the voice cell */ | |
| #verdict-voice{background:transparent ;border:none ;padding:0 ;max-height:96px;overflow:hidden} | |
| #verdict-voice .waveform-container,#verdict-voice canvas{max-height:40px} | |
| #verdict-voice audio{width:100%;height:36px} | |
| /* reco developing note */ | |
| .reco-note.dev{color:#c9a24a;font-family:Oswald,sans-serif;letter-spacing:.12em;font-size:11px} | |
| .reco-note.dev::after{content:"\2026";animation:twb 1.2s infinite} | |
| /* =========================================================================== | |
| POLISH ROUND β themed scrollbars, unified interrogation panel, single-row | |
| reconstruction carousel, tidy voice cell. Match the approved p1a mockup. | |
| =========================================================================== */ | |
| /* ---- noir scrollbars everywhere inside the verdict desk ---- */ | |
| .screen-verdict *::-webkit-scrollbar{width:8px;height:8px} | |
| .screen-verdict *::-webkit-scrollbar-track{background:#171310} | |
| .screen-verdict *::-webkit-scrollbar-thumb{background:#4a3f33;border-radius:4px} | |
| .screen-verdict *::-webkit-scrollbar-thumb:hover{background:#c9a24a} | |
| .screen-verdict *{scrollbar-width:thin;scrollbar-color:#4a3f33 #171310} | |
| /* ---- interrogation: chatbot + input row read as ONE panel ---- */ | |
| #grill-chat{background:#141110 ;border:1px solid #3a322b ; | |
| border-bottom:0 ;border-radius:0 } | |
| #grill-row{background:#141110;border:1px solid #3a322b;border-top:1px dashed #3a322b; | |
| padding:8px ;margin-top:-12px;gap:6px ;flex-wrap:nowrap ; | |
| align-items:stretch } | |
| #grill-input{min-width:0} | |
| #grill-input textarea{min-height:38px ;max-height:38px ;resize:none } | |
| #grill-send,button#grill-send{min-width:74px ;max-width:96px;height:38px ; | |
| align-self:center;flex:none ;padding:0 12px } | |
| /* compact noir bubbles; kill Gradio's per-message chrome */ | |
| #grill-chat .message-buttons-right,#grill-chat .message-buttons-left, | |
| #grill-chat button[title="Copy message"],#grill-chat .copy-button, | |
| #grill-chat .icon-button-wrapper{display:none } | |
| #grill-chat .message{padding:7px 10px ;font-size:12.5px ; | |
| border-radius:3px } | |
| #grill-chat .bot, #grill-chat .message.bot{font-family:'Special Elite','Courier Prime',monospace } | |
| #grill-chat .avatar-container{width:34px ;height:34px ; | |
| border:2px solid #c9a24a ;border-radius:50% ;overflow:hidden; | |
| background:#11100e;flex:none} | |
| #grill-chat .avatar-container img{object-fit:cover} | |
| #grill-chat .placeholder-content,#grill-chat .placeholder{ | |
| font-family:'Special Elite',monospace;color:#8c7f6e} | |
| /* ---- reconstruction: ONE row, horizontal carousel when crowded ---- */ | |
| .rk-strip{flex-wrap:nowrap ;overflow-x:auto;overflow-y:hidden; | |
| padding-bottom:6px;scroll-snap-type:x proximity} | |
| .rk{flex:0 0 168px;scroll-snap-align:start} | |
| /* ---- voice cell: clean compact player, no stray bars ---- */ | |
| .va-voice-cell{justify-content:flex-start} | |
| #verdict-voice{max-height:none;overflow:visible} | |
| #verdict-voice .controls,#verdict-voice .settings-wrapper, | |
| #verdict-voice .control-wrapper > .settings-wrapper{display:none } | |
| #verdict-voice .component-wrapper{padding:0 } | |
| #verdict-voice .waveform-container{background:#171310 ;border:1px solid #3a322b; | |
| border-radius:3px;padding:4px 8px} | |
| #verdict-voice ::part(cursor){border-color:#c9a24a} | |
| #verdict-voice .source-selection,#verdict-voice .icon-buttons, | |
| #verdict-voice label,#verdict-voice .download-button{display:none } | |
| #verdict-voice .play-pause-wrapper button{background:#c0392b ;border-radius:50% ; | |
| color:#fff ;border:none } | |
| #verdict-voice .timestamps,#verdict-voice .time,#verdict-voice .duration{ | |
| font-family:'Oswald',sans-serif ;font-size:9px ;color:#8c7f6e } | |
| /* ---- bottom cells: identical height rhythm ---- */ | |
| .va-bottom > div{min-height:178px} | |
| .va-cell{justify-content:flex-start } | |
| /* ---- file panel scroll area a touch taller, matches chat column ---- */ | |
| .fp-scroll{max-height:320px} | |
| /* ===== AUDIT FIXES ===== */ | |
| /* HIGH: cap the evidence feed to the viewport so the bottom strip stays above | |
| the fold on 1366x768. The wrapper shrink-wraps the image so the % -positioned | |
| pins and the SVG circles stay perfectly aligned. */ | |
| .va-feed{display:flex;flex-direction:column;align-items:center} | |
| .va-feed .feed-tag,.va-feed .hero-legend{align-self:flex-start} | |
| .hero-wrap{width:fit-content;max-width:100%;margin:0 auto} | |
| .hero-wrap img.hero-photo{max-height:56vh;width:auto;max-width:100%;display:block} | |
| /* MED: never crop the rebuilt element in the comparator */ | |
| .cmp{background:#0d0b0a} | |
| .cmp img{object-fit:contain } | |
| /* MED: the inspector stays decorative β behind the evidence, never over a marker */ | |
| .hero-wrap{position:relative;z-index:2} | |
| .feed-insp{z-index:1} | |
| /* LOW: one continuous masthead bar (button included) */ | |
| .va-top{background:linear-gradient(90deg,#1a1512,#241d18);border:1px solid #3a322b; | |
| border-top:3px solid #c0392b;padding:0 10px 0 0 } | |
| .vt-bar{background:transparent;border:none;border-top:none} | |
| /* LOW: bring back the noir vignette behind the desk */ | |
| body.uxc-verdict::before{content:"";position:fixed;inset:0;pointer-events:none;z-index:0; | |
| background:radial-gradient(ellipse at 30% 0%,rgba(201,162,74,.07),transparent 55%), | |
| radial-gradient(ellipse at 85% 100%,rgba(192,57,43,.05),transparent 50%)} | |
| /* HIGH fix part 2: the right rail also scales with the viewport, so the | |
| bottom strip stays near the fold on 1366x768 laptops. */ | |
| .fp-scroll{max-height:clamp(150px,26vh,320px)} | |
| #grill-chat{height:auto ;min-height:130px ; | |
| max-height:clamp(140px,24vh,260px) } | |
| /* HIGH fix part 3: kill the dead air above the masthead (empty overlay | |
| wrappers + container padding) so the desk starts at the top edge. */ | |
| body.uxc-verdict .gradio-container{padding-top:4px } | |
| body.uxc-verdict .uxc-overlay{display:none } | |
| body.uxc-verdict .block:has(> #ux-header), | |
| body.uxc-verdict .block:has(.steps){display:none } | |
| /* ===== MOCKUP-FAITHFUL CHAT + VOICE (custom HTML, no Gradio widgets) ===== */ | |
| #grill-chat-wrap{margin-bottom:-10px} | |
| .grill-box{background:#141110;border:1px solid #3a322b;border-bottom:0; | |
| height:clamp(140px,24vh,260px);overflow-y:auto;padding:10px 12px; | |
| display:flex;flex-direction:column;gap:9px;font-size:12.5px; | |
| font-family:'Courier Prime',monospace;color:#ede4cf} | |
| .grill-empty{font-family:'Special Elite',monospace;color:#8c7f6e;font-size:12px; | |
| margin:auto;text-align:center;padding:0 14px;line-height:1.6} | |
| .grill-box .mu{align-self:flex-end;background:#2a2420;border:1px solid #4a3f33; | |
| padding:7px 10px;border-radius:3px;max-width:86%;line-height:1.45} | |
| .grill-box .brow{display:flex;gap:8px;align-items:flex-start;max-width:92%} | |
| .grill-box .avatar{flex:none;width:34px;height:34px;border-radius:50%; | |
| border:2px solid #c9a24a;background-color:#11100e;background-size:cover; | |
| background-position:center;box-shadow:0 3px 8px #000} | |
| .grill-box .mb{background:#1c2a20;border:1px solid #2e4a38; | |
| font-family:'Special Elite','Courier Prime',monospace;padding:7px 10px; | |
| border-radius:3px;line-height:1.5;color:#d9e8dd;min-width:0} | |
| /* the custom voice player β mockup look */ | |
| .vp{display:flex;align-items:center;gap:12px;padding:4px 0} | |
| .vp-btn{width:46px;height:46px;border-radius:50%;background:#c0392b;border:none; | |
| color:#fff;font-size:16px;cursor:pointer;flex:none;display:grid;place-items:center; | |
| box-shadow:0 0 0 4px #c0392b22;transition:.15s} | |
| .vp-btn:hover{transform:scale(1.06);box-shadow:0 0 0 6px #c0392b33} | |
| .vp-wave{flex:1;display:flex;align-items:center;gap:3px;height:32px;min-width:40px} | |
| .vp-wave i{width:4px;height:8px;background:#c9a24a;border-radius:2px} | |
| .vp.playing .vp-wave i{animation:wv 1s infinite ease-in-out} | |
| .vp audio{display:none} | |
| /* ===== FAITHFUL ROUND 2: warm panels, typing dots, tape player, type scale ===== */ | |
| /* warm the chat surface to the mockup brown (no more black-on-black) */ | |
| .grill-box{background:#1d1916;border-color:#3a322b} | |
| /* typing dots while the Inspector thinks */ | |
| .typing{display:inline-flex;gap:4px;align-items:center;padding:3px 2px} | |
| .typing i{width:6px;height:6px;border-radius:50%;background:#9fc7ab;animation:tpb 1.2s infinite ease-in-out} | |
| .typing i:nth-child(2){animation-delay:.18s} | |
| .typing i:nth-child(3){animation-delay:.36s} | |
| @keyframes tpb{0%,60%,100%{opacity:.25;transform:translateY(0)}30%{opacity:1;transform:translateY(-3px)}} | |
| /* ---- the tape player v2 ---- */ | |
| .vp{display:flex;align-items:center;gap:13px;padding:6px 2px;background:transparent} | |
| .vp-btn{width:50px;height:50px;border-radius:50%;background:radial-gradient(circle at 36% 30%,#d8584a,#a32619 70%); | |
| border:1px solid #e0796d55;color:#fff;font-size:17px;cursor:pointer;flex:none; | |
| display:grid;place-items:center;box-shadow:0 4px 14px #00000080,0 0 0 4px #c0392b22;transition:.16s} | |
| .vp-btn:hover{transform:scale(1.07);box-shadow:0 6px 18px #000000a0,0 0 0 7px #c0392b33} | |
| .vp.playing .vp-btn{box-shadow:0 4px 14px #00000080,0 0 0 5px #c0392b44;animation:vppulse 1.6s infinite} | |
| @keyframes vppulse{50%{box-shadow:0 4px 14px #00000080,0 0 0 9px #c0392b1c}} | |
| .vp-main{flex:1;min-width:0} | |
| .vp-wave{display:flex;align-items:center;gap:3px;height:34px;cursor:pointer;padding:2px 0} | |
| .vp-wave i{flex:1;min-width:2.5px;max-width:5px;height:var(--h,10px);background:#4a3f33;border-radius:2px;transition:background .12s} | |
| .vp-wave i.on{background:#c9a24a;box-shadow:0 0 6px #c9a24a44} | |
| .vp-wave:hover i:not(.on){background:#5d4f3e} | |
| .vp.playing .vp-wave i.on:last-of-type{animation:wv .9s infinite ease-in-out} | |
| .vp-meta{display:flex;align-items:center;gap:8px;margin-top:4px} | |
| .vp-time,.vp-dur{font-family:'Oswald',sans-serif;font-size:9.5px;letter-spacing:.12em;color:#c9a24a;flex:none} | |
| .vp-lbl{flex:1;text-align:center;font-family:'Oswald',sans-serif;font-size:8.5px;letter-spacing:.2em; | |
| color:#8c7f6e;white-space:nowrap;overflow:hidden;text-overflow:ellipsis} | |
| /* ---- share cell: one type scale, no giant COPY ---- */ | |
| .sp-dl{font-size:9.5px;padding:8px 11px} | |
| .sp-btn{width:31px;height:31px} | |
| .sp-btn svg{width:14px;height:14px} | |
| .sp-link{font-size:11px;padding:8px 10px} | |
| .sp-copy{font-size:9.5px;padding:0 12px;letter-spacing:.1em} | |
| /* ===== PIXEL ALIGNMENT (measured with the UI inspector) ===== */ | |
| /* every block in the right rail shares the exact same left/right edges */ | |
| .va-rail .block{padding:0 } | |
| .va-rail .form{border:none ;background:transparent } | |
| #grill-row{margin:0 ;width:auto ;flex-wrap:nowrap ; | |
| background:#1d1916;border:1px solid #3a322b;border-top:1px dashed #3a322b; | |
| padding:8px ;gap:8px ;align-items:center } | |
| #grill-input{border:none ;background:transparent ;padding:0 ;min-width:0} | |
| #grill-input textarea{height:38px ;min-height:38px ;max-height:38px ; | |
| padding:9px 10px ;line-height:1.4 } | |
| #grill-send,button#grill-send{height:38px ;min-height:38px ; | |
| max-height:38px ;line-height:1 } | |
| /* the header fuses with the box below it (column gap is 10px) */ | |
| .rail-ph{margin-bottom:-10px ;border-bottom:0 } | |
| #grill-chat-wrap{margin-bottom:-10px } | |
| .grill-box{border-top:1px solid #3a322b} | |
| /* share: link field and COPY share one height and one type size */ | |
| .sp-row2{align-items:stretch} | |
| .sp-link{height:34px;display:flex;align-items:center;padding:0 10px;font-size:10.5px} | |
| .sp-copy{height:34px;font-size:9.5px} | |
| .sp-dl{height:31px;display:inline-flex;align-items:center} | |
| /* the input row tucks into the same 12px edges as the blocks above it */ | |
| #grill-row{margin:0 12px } | |
| /* ===== SEAMS & LOADERS ROUND ===== */ | |
| /* The grey showing through every gap was the Gradio Group/Row surface. | |
| Mimic the mockup: wrappers go transparent so gaps read as the page itself. */ | |
| body.uxc-verdict .screen-verdict, | |
| body.uxc-verdict .screen-verdict .row, | |
| body.uxc-verdict .screen-verdict .block, | |
| body.uxc-verdict .screen-verdict .form, | |
| body.uxc-verdict .screen-verdict .gr-group{ | |
| background:transparent ;border:none ;box-shadow:none } | |
| /* fuse the interrogation header to its body: no gap at all in the rail */ | |
| .va-rail{gap:0 } | |
| .va-rail > *{margin:0 } | |
| .rail-ph{margin:10px 0 0 0 ;border-bottom:0 } | |
| #grill-chat-wrap{margin:0 } | |
| #grill-row{margin:0 12px } | |
| /* COPY matches DOWNLOAD THE SHARE CARD exactly */ | |
| .sp-dl{height:31px ;font-size:9.5px } | |
| .sp-copy{height:31px ;font-size:9.5px ;font-family:'Oswald',sans-serif ; | |
| letter-spacing:.12em ;padding:0 11px ;display:inline-flex;align-items:center} | |
| .sp-link{height:31px;font-size:10.5px} | |
| /* the lab loader: spinning gold ring + shimmer bar */ | |
| .lab-load{display:flex;align-items:center;gap:13px;padding:6px 2px} | |
| .ll-ring{flex:none;width:30px;height:30px;border-radius:50%; | |
| border:3px solid #3a322b;border-top-color:#c9a24a;animation:llspin 1s linear infinite} | |
| @keyframes llspin{to{transform:rotate(360deg)}} | |
| .ll-txt{flex:1;min-width:0;font-family:'Oswald',sans-serif;font-size:10.5px; | |
| letter-spacing:.16em;color:#c9a24a;line-height:1.5} | |
| .ll-bar{display:block;height:3px;margin:6px 0 4px;border-radius:2px; | |
| background:linear-gradient(90deg,#3a322b 0%,#c9a24a 50%,#3a322b 100%); | |
| background-size:200% 100%;animation:llshimmer 1.5s linear infinite} | |
| @keyframes llshimmer{from{background-position:200% 0}to{background-position:-200% 0}} | |
| .ll-txt small{display:block;font-family:'Courier Prime',monospace;font-size:10px; | |
| letter-spacing:0;color:#8c7f6e;text-transform:none} | |
| /* two internal 10px paddings (block tail + wrap head) sit between the header | |
| and the chat body β pull the body up so they fuse into one panel */ | |
| #grill-chat-wrap{margin-top:0 } | |
| #grill-row{margin:-10px 12px 0 } | |
| /* ===== SECTIONED BLOCKS ROUND (user spec) ===== */ | |
| /* 1) the grey styler surface -> deep noir #100a09 */ | |
| body.uxc-verdict .styler{background:#100a09 } | |
| /* 2) masthead: each piece boxed in its own bordered block, aligned in a row */ | |
| .vt-bar{display:flex;align-items:stretch;gap:10px;background:transparent;border:none;padding:0;min-height:58px} | |
| .vt-seg{display:flex;align-items:center;gap:12px;background:linear-gradient(90deg,#1a1512,#241d18); | |
| border:1px solid #3a322b;border-top:3px solid #c0392b;padding:7px 16px} | |
| .vt-seg-case{flex:1;min-width:0} | |
| .va-top{background:transparent ;border:none ;padding:0 } | |
| #newcase-btn{border-top:3px solid #c0392b ;align-self:stretch ;height:auto } | |
| /* 3) feed letterbox fills with #100a09 (not pure black) */ | |
| .va-feed{background:#100a09 } | |
| /* 4) case file top == feed block top (the wrap adds 10px β pull it up) */ | |
| .va-file{margin-top:0 } | |
| .file-panel{position:relative;top:0;margin-bottom:0} | |
| /* 5) every section wears its border */ | |
| .rail-ph{border:1px solid #3a322b ;border-bottom:0 } | |
| .grill-box{border:1px solid #3a322b ;border-bottom:0 } | |
| #grill-row{border:1px solid #3a322b ;border-top:1px dashed #3a322b } | |
| .va-cell{border:1px solid #3a322b } | |
| .file-panel{border:1px solid #3a322b } | |
| /* ===== PIXEL GRID ROUND: one container, every row on the same axes ===== */ | |
| /* the wrapper column of reco+voice is invisible β only the grid matters */ | |
| .vb-left{padding:0 ;background:transparent ;border:none ; | |
| box-shadow:none ;min-width:0} | |
| .vb-left-row{gap:10px ;margin:0 } | |
| /* the bottom strip breathes the same 10px as file -> interrogation */ | |
| .va-bottom{margin-top:10px ;gap:10px } | |
| .va-main{gap:10px } | |
| .va-top{gap:10px ;margin-bottom:0 } | |
| /* INVESTIGATE button fills its slot: same height + red rule as its siblings */ | |
| #newcase-btn{height:100% ;min-height:58px ;margin:0 } | |
| .va-top > div:has(> #newcase-btn){display:flex;align-items:stretch} | |
| /* hard grid: both rows share IDENTICAL column tracks (13/6 = 68.42/31.58) */ | |
| body.uxc-verdict .screen-verdict .block{padding:0 } | |
| .va-rail{padding:0 } | |
| .va-feed,.vb-left{flex:0 0 calc(68.42% - 5px) ;max-width:calc(68.42% - 5px) ;min-width:0 } | |
| .va-rail,.va-share-cell{flex:0 0 calc(31.58% - 5px) ;max-width:calc(31.58% - 5px) ;min-width:0 } | |
| @media (max-width:900px){ | |
| .va-feed,.vb-left,.va-rail,.va-share-cell{flex:1 1 100% ;max-width:100% } | |
| } | |
| /* the universal 12px inset on every gr.HTML β gone inside the desk */ | |
| body.uxc-verdict .screen-verdict .html-container{padding:0 } | |
| /* sit the input a snug gap below the trial chips */ | |
| #grill-row{margin:6px 0 0 } | |
| /* ===== EQUAL HEIGHTS ROUND ===== */ | |
| /* bottom strip: the three cells always share the SAME height (tallest wins) */ | |
| .va-bottom{align-items:stretch } | |
| .vb-left{display:flex ;flex-direction:column } | |
| .vb-left-row{flex:1 ;align-items:stretch } | |
| .vb-left-row > .va-cell{height:auto ;align-self:stretch } | |
| .va-share-cell{height:auto ;align-self:stretch } | |
| .va-cell{min-height:130px} | |
| /* header: the three blocks are EXACTLY the same height, same gap below */ | |
| .vt-bar{min-height:0} | |
| .vt-seg{height:62px;box-sizing:border-box} | |
| #newcase-btn{height:62px ;min-height:62px ;max-height:62px ; | |
| align-self:flex-start } | |
| .va-top{align-items:flex-start } | |
| /* the case-file header wears the exact same uniform as its sibling headers */ | |
| .fp-head{color:#c9a24a ;font-family:'Oswald',sans-serif ; | |
| font-size:11px ;letter-spacing:.22em } | |
| .fp-head b{color:#c0392b;margin-right:5px;font-weight:inherit} | |
| /* the header SPAN itself was inheriting cream β force the mustard gold */ | |
| .fp-head span{color:#c9a24a } | |
| .fp-head span b, .fp-head b{color:#c0392b } | |
| .fp-head .fp-stamp{color:#e74c3c } | |
| .file-panel.cleared .fp-head .fp-stamp{color:#2e9e5b } | |
| /* bubble text survives any theme variant */ | |
| .grill-box .mu{color:#ede4cf } | |
| .grill-box .mb{color:#d9e8dd } | |
| /* mobile: the photo obeys the viewport (the 56vh desktop cap let it overflow) */ | |
| @media (max-width:900px){ | |
| .hero-wrap{width:100% } | |
| .hero-wrap img.hero-photo{width:100% ;max-height:none } | |
| } | |
| /* mobile: let every flex child actually shrink, wrap the long single-line bits */ | |
| @media (max-width:900px){ | |
| .screen-verdict *{min-width:0 } | |
| .feed-tag{white-space:normal ;display:block ;width:auto } | |
| .hero-legend{flex-wrap:wrap ;max-width:100% } | |
| .vt-bar{flex-wrap:wrap ;min-height:0 } | |
| .vt-seg{height:auto ;min-height:52px;width:100% ;box-sizing:border-box} | |
| #newcase-btn{width:100% ;height:48px ;min-height:48px ;max-height:none } | |
| .rk-strip{max-width:100%} | |
| } | |
| /* mobile: rows become plain block stacks β no flex min-content surprises */ | |
| @media (max-width:900px){ | |
| .va-main,.va-bottom,.vb-left-row,.va-top{display:block } | |
| .va-feed,.va-rail,.va-cell,.vb-left{display:block ;width:100% ; | |
| max-width:100% ;flex:none ;margin-bottom:10px } | |
| .screen-verdict .styler,.screen-verdict .row{width:100% ;max-width:100% } | |
| } | |
| /* mobile: Gradio nests two .screen-verdict wrappers β pin the inner one to 100% */ | |
| @media (max-width:900px){ | |
| .screen-verdict .screen-verdict, | |
| .screen-verdict .styler{width:100% ;max-width:100% ;min-width:0 } | |
| body.uxc-verdict .screen-verdict{padding:8px } | |
| } | |
| /* ===== THE TRIAL β guiding move chips (minimal, fits the tight rail) ===== */ | |
| .trial-chips{display:grid;grid-template-columns:1fr 1fr;grid-auto-rows:36px;gap:6px;margin:6px 0 0;padding:0;align-items:stretch} | |
| .trial-chip{font-family:'Oswald',sans-serif;font-size:10px;letter-spacing:.06em; | |
| background:#221c18;border:1px solid #5a4b3c;color:#cbbfa8;padding:0 8px;border-radius:3px; | |
| cursor:pointer;display:flex;align-items:center;justify-content:center;gap:5px;transition:.14s; | |
| line-height:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;height:36px;box-sizing:border-box} | |
| .trial-chip .tc-ico{line-height:1;display:inline-flex;align-items:center} | |
| .trial-chip:hover{background:#c0392b;border-color:#c0392b;color:#fff;transform:translateY(-1px)} | |
| .trial-chip .tc-ico{color:#c9a24a;font-size:11px} | |
| .trial-chip:hover .tc-ico{color:#fff} | |
| /* ========================================================================= | |
| MOST WANTED β public city board (ludic noir wall; graceful without assets) | |
| ========================================================================= */ | |
| /* MOST WANTED β the secondary entry to the public board. Bone-outline at rest so it | |
| sits clearly BELOW the red FILE THE CASE primary; on hover it ignites into an inked | |
| red stamp (warm text + red frame + glow). Compact, so the desk keeps its space. */ | |
| /* one-line teaser above the MOST WANTED button β plain readable text, no pill */ | |
| .mw-enter-sub{margin:22px auto 0;text-align:center;white-space:nowrap; | |
| font-family:'Special Elite',monospace;font-size:11px;letter-spacing:.02em;color:#dccca8; | |
| text-shadow:0 1px 2px #000,0 0 7px rgba(0,0,0,.92)} | |
| /* MOST WANTED β a filled DARK-red action (clearly active/clickable), one notch | |
| below the brighter FILE THE CASE primary. Same button family + a soft sheen. */ | |
| #mw-enter-btn{ | |
| display:block ;width:-moz-fit-content ;width:fit-content ; | |
| min-width:244px ;max-width:86% ;margin:-4px auto 0 ; | |
| min-height:0 ;height:auto ; | |
| background:linear-gradient(rgb(81 12 4), rgb(41 5 2)) ; | |
| border:1px solid #7a1f17 ;border-radius:3px ; | |
| box-shadow:0 6px 15px rgba(0,0,0,.5),inset 0 1px 0 rgba(255,255,255,.08) ; | |
| padding:12px 30px ;position:relative;overflow:hidden; | |
| font-family:'Oswald',sans-serif ;font-weight:700 ; | |
| font-size:13px ;letter-spacing:.2em ;text-transform:uppercase;text-align:center; | |
| color:#f3e0cf ; | |
| transition:background .18s ease,border-color .18s ease,box-shadow .18s ease,color .18s ease } | |
| #mw-enter-btn::after{content:"";position:absolute;top:0;left:-60%;width:38%;height:100%; | |
| background:linear-gradient(100deg,transparent,rgba(255,255,255,.22),transparent); | |
| transform:skewX(-20deg);animation:btnSheen 3.6s ease-in-out infinite;pointer-events:none} | |
| #mw-enter-btn:hover{ | |
| background:linear-gradient(rgb(81 12 4), rgb(41 5 2)) ;border-color:#c0392b ; | |
| box-shadow:0 9px 22px rgba(192,57,43,.38),inset 0 1px 0 rgba(255,255,255,.12) ; | |
| color:#fff } | |
| /* The wall is now a FIXED full-viewport body background (see body.uxc-mostwanted), | |
| so .mw-wrap is just a transparent content holder β no black fill, no seam line. | |
| NOTE: never use 100vh / min-height:100vh here β inside the Space's auto-resizing | |
| iframe it feeds back (content grows -> iframe grows -> 100vh growsβ¦) = "infinite zoom". */ | |
| .mw-wrap{position:relative;border:none;overflow:visible;min-height:560px;background:transparent} | |
| .mw-inner{position:relative;padding:24px 22px 34px;max-width:1240px;margin:0 auto} | |
| /* The real Gradio back button is hidden β the VISIBLE one lives in the board's side | |
| column (.mw-back-board, below the Inspector) and delegates its click to this. Kept | |
| absolutely positioned (not display:none) so JS .click() still fires its handler, and | |
| so the top of the board reclaims the pixels the old top button used to take. */ | |
| #mw-back-btn{position:absolute ;width:1px ;height:1px ; | |
| padding:0 ;margin:-1px ;overflow:hidden ;clip:rect(0,0,0,0) ; | |
| border:0 ;opacity:0 ;pointer-events:none } | |
| /* collapse the Gradio wrapper around it so it adds no vertical space at the top */ | |
| body.uxc-mostwanted .block:has(> #mw-back-btn){min-height:0 ;padding:0 ;margin:0 ;height:0 ;overflow:hidden } | |
| /* the prominent in-board back button β full width of the side column, hard to miss */ | |
| .mw-back-board{ | |
| display:block;width:100%;margin-top:14px;cursor:pointer; | |
| background:linear-gradient(180deg,#8f2417,#56130d); | |
| border:1px solid #7a1f17;border-radius:4px;padding:14px 16px; | |
| font-family:'Oswald',sans-serif;font-weight:700;font-size:12.5px;letter-spacing:.16em; | |
| text-transform:uppercase;color:#f3e0cf;text-align:center;line-height:1.3; | |
| box-shadow:0 6px 16px rgba(0,0,0,.5),inset 0 1px 0 rgba(255,255,255,.08); | |
| transition:background .18s ease,border-color .18s ease,box-shadow .18s ease,color .18s ease} | |
| .mw-back-board:hover{background:linear-gradient(180deg,#b0301d,#7a1f17);border-color:#c0392b;color:#fff; | |
| box-shadow:0 9px 22px rgba(192,57,43,.4)} | |
| .mw-back-board:active{transform:translateY(1px)} | |
| /* header */ | |
| .mw-head{text-align:center;margin-bottom:18px} | |
| /* !important: gr.HTML lives inside Gradio's .prose, whose `img{max-width:100%}` rule | |
| otherwise overrides these and blows the sign up + breaks the auto-margin centering. */ | |
| .mw-sign{max-width:360px ;width:58% ;display:block ; | |
| margin:0 auto ;filter:drop-shadow(0 6px 16px #000)} | |
| .mw-title{font-family:'Anton',sans-serif;font-size:clamp(34px,6vw,58px);letter-spacing:.05em;color:#ede4cf; | |
| text-shadow:0 0 26px rgba(192,57,43,.4);margin:0} | |
| .mw-title::before{content:"β ";color:#c0392b} | |
| .mw-sub{font-family:'Oswald',sans-serif;font-size:11px;letter-spacing:.28em;color:#d8b25a; | |
| display:table;margin:15px auto 0;padding:5px 16px;border-radius:11px;background:rgba(8,6,4,.6); | |
| text-shadow:0 1px 3px #000,0 0 10px rgba(0,0,0,.85)} | |
| .mw-stats{display:inline-flex;justify-content:center;gap:0;margin-top:22px;flex-wrap:wrap; | |
| background:rgba(13,10,8,.86);border:1px solid #3a322b;border-top:2px solid #c0392b;border-radius:4px; | |
| padding:12px 8px;box-shadow:0 7px 20px rgba(0,0,0,.45)} | |
| .mw-stat{padding:2px 30px} | |
| .mw-stat + .mw-stat{border-left:1px solid #3a322b} | |
| .mw-stat b{display:block;font-family:'Anton',sans-serif;font-size:27px;color:#e8584a;line-height:1} | |
| .mw-stat span{font-family:'Oswald',sans-serif;font-size:9px;letter-spacing:.18em;color:#b3a691} | |
| /* grid: board + side report */ | |
| .mw-grid{display:grid;grid-template-columns:1.7fr 1fr;gap:14px;align-items:start} | |
| .mw-bh{font-family:'Oswald',sans-serif;font-size:10.5px;letter-spacing:.2em;color:#c9a24a;margin-bottom:9px; | |
| display:inline-block;padding:5px 12px;border-radius:11px;background:rgba(8,6,4,.6); | |
| text-shadow:0 1px 3px #000,0 0 10px rgba(0,0,0,.85)} | |
| /* a booked record = a wanted poster row */ | |
| .mw-rec{display:flex;gap:13px;align-items:center;background:linear-gradient(180deg,#211b18,#181311); | |
| border:1px solid #3a322b;border-left:4px solid #c0392b;padding:10px 13px;margin-bottom:9px; | |
| text-decoration:none ;transition:all .15s ease;color:inherit} | |
| .mw-rec:hover{border-left-color:#c9a24a;transform:translateX(3px);box-shadow:0 8px 22px rgba(0,0,0,.45)} | |
| .mw-rank{font-family:'Anton',sans-serif;font-size:24px;color:#fff;background:#3a2c1a;width:42px;height:42px; | |
| flex:none;border-radius:50%;display:grid;place-items:center;box-shadow:0 0 0 2px #5a4b3c} | |
| .mw-rank.r1{background:#c0392b;box-shadow:0 0 0 2px #c9a24a}.mw-rank.r2{background:#7a1f17;box-shadow:0 0 0 2px #c9a24a} | |
| .mw-rank.r3{background:#5a2018;box-shadow:0 0 0 2px #c9a24a} | |
| .mw-shot{position:relative;flex:none;width:118px;height:64px;border:1px solid #4a3f33;overflow:hidden;background:#0d0b0a} | |
| .mw-shot img{width:100%;height:100%;object-fit:cover;filter:grayscale(.35) contrast(1.05)} | |
| .mw-meta{flex:1;min-width:0;display:flex ;flex-direction:column;justify-content:center} | |
| .mw-site{font-family:'Oswald',sans-serif;font-weight:700;font-size:15px;letter-spacing:.03em;color:#ede4cf;display:block} | |
| .mw-charge{font-family:'Special Elite',monospace;font-size:11.5px;color:#cdbfa6;display:block;margin-top:3px; | |
| white-space:nowrap;overflow:hidden;text-overflow:ellipsis} | |
| .mw-charge i{font-family:'Oswald',sans-serif;font-style:normal;font-size:8.5px;letter-spacing:.16em; | |
| color:#e0584a;margin-right:6px;vertical-align:1px} | |
| .mw-count{flex:none;text-align:center;min-width:56px;padding:0 10px;border-left:1px solid #312824} | |
| .mw-count b{display:block;font-family:'Anton',sans-serif;font-size:26px;color:#e8584a;line-height:1} | |
| .mw-count span{font-family:'Oswald',sans-serif;font-size:8px;letter-spacing:.14em;color:#9c8f7d;text-transform:uppercase} | |
| .mw-seal{font-family:'Anton',sans-serif;font-size:20px;width:40px;height:40px;flex:none;border-radius:50%; | |
| display:grid;place-items:center;color:#fff;border:2px solid #c9a24a} | |
| .mw-seal.g-f{background:#7a1f17}.mw-seal.g-d{background:#a83227}.mw-seal.g-c{background:#b06a1e}.mw-seal.g-clear{background:#2e9e5b} | |
| .mw-view{font-family:'Oswald',sans-serif;font-size:9px;letter-spacing:.16em;color:#c9a24a;flex:none} | |
| /* side: AI city report + crime bars */ | |
| .mw-report{background:linear-gradient(180deg,#1d1916,#141110);border:1px solid #3a322b;padding:14px} | |
| .mw-rh{font-family:'Oswald',sans-serif;font-size:11px;letter-spacing:.2em;color:#c9a24a} | |
| .mw-rh b{color:#c0392b} | |
| .mw-body{font-family:'Special Elite',monospace;font-size:12.5px;line-height:1.6;color:#cdbfa6;margin-top:8px} | |
| .mw-body em{color:#c9a24a;font-style:normal} | |
| .mw-epi{display:flex;align-items:center;gap:8px;margin:6px 0;font-size:11.5px} | |
| .mw-en{flex:0 0 118px;color:#cbbfa8} | |
| .mw-eb{flex:1;height:9px;background:#3a322b;border-radius:5px;overflow:hidden} | |
| .mw-eb i{display:block;height:100%;background:linear-gradient(90deg,#7a1f17,#c0392b)} | |
| .mw-ec{font-family:'Oswald',sans-serif;font-size:10px;color:#c9a24a;flex:none;width:26px;text-align:right} | |
| /* the Inspector himself fills the space under the city report */ | |
| .mw-mug{margin-top:14px;background:linear-gradient(180deg,#1d1916,#141110);border:1px solid #3a322b; | |
| border-top:2px solid #7a1f17;padding:14px 12px 12px;text-align:center;position:relative;overflow:hidden} | |
| .mw-mug::before{content:"";position:absolute;inset:0; | |
| background:radial-gradient(ellipse at 50% 18%,rgba(192,57,43,.12),transparent 60%);pointer-events:none} | |
| .mw-mug img{position:relative;width:auto;max-width:90%;max-height:236px;display:block;margin:0 auto; | |
| transform:scaleX(-1);filter:contrast(1.04) drop-shadow(0 8px 16px rgba(0,0,0,.55))} | |
| .mw-mug span{position:relative;display:block;font-family:'Oswald',sans-serif;font-size:9px; | |
| letter-spacing:.22em;color:#9c8f7d;margin-top:8px} | |
| @media (max-width:900px){.mw-grid{grid-template-columns:1fr}.mw-shot{width:90px;height:52px}.mw-mug img{max-height:200px}} | |
| /* MOST WANTED is its own full screen β kill the desk overlays that belong to the home */ | |
| body.uxc-mostwanted #laptop-overlay, | |
| body.uxc-mostwanted #intro-alley, | |
| body.uxc-mostwanted #bg-video-wrap, | |
| body.uxc-mostwanted #sound-gate, | |
| body.uxc-mostwanted #ux-header, | |
| body.uxc-mostwanted .steps, | |
| body.uxc-mostwanted .inspector-fig, | |
| body.uxc-mostwanted .status-line{display:none } | |
| /* full-screen wall: the precinct wall is a FIXED viewport background (with the dark | |
| scrim + red glow layered on top) so it covers the ENTIRE screen β back button, | |
| margins and all β with no black strip behind it. Fixed = no iframe zoom feedback. */ | |
| body.uxc-mostwanted{ | |
| background: | |
| radial-gradient(ellipse at 50% 38%, rgba(8,6,4,0) 30%, rgba(8,6,4,.48) 70%, rgba(8,6,4,.92) 100%), | |
| radial-gradient(ellipse at 50% 5%, rgba(192,57,43,.15), transparent 50%), | |
| var(--mw-wall, none) center center / cover no-repeat fixed, | |
| #0d0a08 ; | |
| } | |
| /* Gradio paints a default gray block fill (#3f3f46) on its .styler / group wrappers, | |
| which would sit OVER the body wall β force them transparent so the wall shows. */ | |
| body.uxc-mostwanted .styler, | |
| body.uxc-mostwanted .gr-group, | |
| body.uxc-mostwanted .gradio-container .block { background: transparent ; } | |
| /* full-bleed: the precinct wall fills the whole screen, content stays centred inside */ | |
| body.uxc-mostwanted .gradio-container{padding:0 ;max-width:none ;margin:0 } | |
| body.uxc-mostwanted .gradio-container > .main, | |
| body.uxc-mostwanted .main.fillable{max-width:none ;width:100% ;margin:0 } | |
| .screen-mostwanted{position:relative;z-index:2} | |
| /* opt-in publish to MOST WANTED */ | |
| #publish-btn{width:100%;margin-top:8px ;font-family:'Oswald',sans-serif ; | |
| letter-spacing:.12em ;font-size:11px ;color:#ede4cf ; | |
| background:linear-gradient(180deg,#2a1614,#1a0f0d) ;border:1px solid #7a1f17 ; | |
| border-radius:3px ;padding:10px ;transition:all .15s ease } | |
| #publish-btn:hover{background:#c0392b ;border-color:#c0392b } | |
| /* SEE IT ON THE BOARD β same dark-red treatment + sheen as the home MOST WANTED button */ | |
| #mw-view-btn{width:100% ;margin-top:8px ; | |
| background:linear-gradient(rgb(81 12 4), rgb(41 5 2)) ; | |
| border:1px solid #7a1f17 ;border-radius:3px ; | |
| box-shadow:0 6px 15px rgba(0,0,0,.5),inset 0 1px 0 rgba(255,255,255,.08) ; | |
| padding:12px 16px ;position:relative;overflow:hidden; | |
| font-family:'Oswald',sans-serif ;font-weight:700 ; | |
| font-size:12px ;letter-spacing:.16em ;text-transform:uppercase;color:#f3e0cf ; | |
| transition:background .18s ease,border-color .18s ease,box-shadow .18s ease,color .18s ease } | |
| #mw-view-btn::after{content:"";position:absolute;top:0;left:-60%;width:38%;height:100%; | |
| background:linear-gradient(100deg,transparent,rgba(255,255,255,.22),transparent); | |
| transform:skewX(-20deg);animation:btnSheen 3.6s ease-in-out infinite;pointer-events:none} | |
| #mw-view-btn:hover{background:linear-gradient(rgb(81 12 4), rgb(41 5 2)) ; | |
| border-color:#c0392b ;color:#fff ; | |
| box-shadow:0 9px 22px rgba(192,57,43,.38),inset 0 1px 0 rgba(255,255,255,.12) } | |
| .pub-note{font-family:'Courier Prime',monospace;font-size:11px;color:#9c8f7d;margin-top:7px;line-height:1.5} | |
| .pub-note.ok{color:#9fe7b4} .pub-note.ok b{color:#c9a24a} | |
| .mw-fresh{position:absolute;top:4px;right:4px;font-family:'Oswald',sans-serif;font-size:8px; | |
| letter-spacing:.12em;background:#c0392b;color:#fff;padding:2px 5px;border-radius:2px} | |
| /* ββ THE PROSECUTION β its own section, BEFORE The Trial. Styled as a TWIN of the | |
| other panels (same #171310 gold header + #1d1916 bordered body as the case file / | |
| THE TRIAL header), with a 10px gap so it never mounts onto the case file above. ββ */ | |
| .prosecution-slot{padding:0 ;margin:0 ;border:0 ; | |
| background:transparent ;min-height:0 } | |
| .prosecution-box{margin:10px 0 0 } | |
| /* header strip β identical to .rail-ph (THE TRIAL) and .fp-head (case file) */ | |
| .prosecution-box .pb-head{ | |
| font-family:'Oswald',sans-serif;font-size:11px;letter-spacing:.22em;text-transform:uppercase; | |
| color:#c9a24a;background:#171310;border:1px solid #3a322b;border-bottom:0;padding:9px 13px} | |
| .prosecution-box .pb-seal{color:#c0392b;margin-right:5px} | |
| .prosecution-box .pb-head small{ | |
| display:block;letter-spacing:0;text-transform:none;font-size:10px;margin-top:2px; | |
| color:#8c7f6e;font-family:'Courier Prime',monospace} | |
| /* body β the bordered noir card the statement sits in */ | |
| .prosecution-box .pb-body{ | |
| margin:0 ;padding:11px 13px;border:1px solid #3a322b;border-top:0;background:#1d1916; | |
| font-style:italic;line-height:1.5;font-size:11.5px;color:#cdbfa6; | |
| max-height:172px;overflow-y:auto} | |
| .prosecution-box .pb-body::-webkit-scrollbar{width:6px} | |
| .prosecution-box .pb-body::-webkit-scrollbar-track{background:transparent} | |
| .prosecution-box .pb-body::-webkit-scrollbar-thumb{background:rgba(201,162,74,.35);border-radius:3px} | |
| /* ===== VERDICT LAYOUT v2 (user spec) β one body row, tall right rail ===== */ | |
| /* LEFT col (68.42%) = evidence feed on top + the three utility cards (recon Β· | |
| voice Β· share) along the bottom. RIGHT col (31.58%) = a single tall rail | |
| (case file β prosecution β trial chat) stretched to the left column's height, | |
| so the chat fills the leftover space and nothing feels cramped. Appended last | |
| so it overrides the old .va-main/.va-bottom grid rules above. */ | |
| .va-body{display:flex ;align-items:stretch ;gap:10px ;margin-top:10px } | |
| .va-left{flex:0 0 calc(68.42% - 5px) ;max-width:calc(68.42% - 5px) ; | |
| min-width:0 ;display:flex ;flex-direction:column ;gap:10px } | |
| .va-body > .va-rail{flex:0 0 calc(31.58% - 5px) ;max-width:calc(31.58% - 5px) ; | |
| min-width:0 ;display:flex ;flex-direction:column ;gap:0 } | |
| /* the EXHIBIT A feed absorbs the column's extra height (it grows); the utility row | |
| stays at its NATURAL height and gets pushed to the bottom β so reco/share fill | |
| their own content with no void and still bottom-align with the chat */ | |
| .va-left > .va-feed{flex:1 1 auto ;max-width:none ;min-height:300px} | |
| .va-left > .va-utilities{flex:0 0 auto } | |
| /* three utility cards share one row at the bottom of the left column */ | |
| .va-utilities{display:flex ;align-items:stretch ;gap:10px ;margin:0 } | |
| .va-utilities > .va-cell{min-width:0 ;max-width:none ;align-self:stretch ; | |
| min-height:150px} | |
| /* reconstruction thumbnails scroll HORIZONTALLY if there are many (so the cell | |
| can be narrow without wrapping into a tall stack) */ | |
| .va-utilities .va-reco-cell .rk-strip{flex-wrap:nowrap ;overflow-x:auto;padding-bottom:4px} | |
| .va-utilities .va-reco-cell .rk{flex:0 0 auto} | |
| .va-reco-cell .rk-strip::-webkit-scrollbar{height:6px} | |
| .va-reco-cell .rk-strip::-webkit-scrollbar-thumb{background:rgba(201,162,74,.4);border-radius:3px} | |
| /* the rail: case file + prosecution at natural height; the CHAT grows to fill | |
| the rest so the right column matches the tall left column ("more air") */ | |
| .va-body > .va-rail > #grill-chat-wrap{flex:1 1 auto ;min-height:74px ; | |
| display:flex ;flex-direction:column } | |
| .va-body > .va-rail > #grill-chat-wrap .grill-box{flex:1 1 auto ;overflow-y:auto;min-height:0} | |
| .va-body > .va-rail .grill-box::-webkit-scrollbar{width:6px} | |
| .va-body > .va-rail .grill-box::-webkit-scrollbar-thumb{background:rgba(58,50,43,.9);border-radius:3px} | |
| /* responsive: stack everything on narrow screens */ | |
| @media (max-width:900px){ | |
| .va-body{display:block } | |
| .va-left,.va-body > .va-rail{flex:1 1 100% ;max-width:100% ;width:100% ; | |
| display:block } | |
| .va-utilities{display:block } | |
| .va-utilities > .va-cell{width:100% ;margin-bottom:10px } | |
| .va-left > .va-feed{min-height:0 } | |
| .va-body > .va-rail > #grill-chat-wrap{min-height:200px } | |
| } | |
| /* ===== UTILITY ROW β TWO cards (reconstruction Β· share) side by side, 50/50 width, | |
| each at its OWN natural COMPACT height: content packed at the TOP, NO stretching, | |
| NO min-height, NO centering, NO voids. THE VOICE lives up in the right rail. ===== */ | |
| .va-utilities{align-items:stretch } | |
| .va-utilities > .va-cell{min-height:0 ;align-self:stretch ; | |
| justify-content:flex-start } | |
| /* RECONSTRUCTION: the FLUX thumbnails grow VERTICALLY to fill the (now equal-height) | |
| card β object-fit:cover keeps them undistorted; the horizontal strip stays aligned */ | |
| .va-reco-cell .rk-strip{flex:1 1 auto ;align-items:stretch ;min-height:0 } | |
| .va-reco-cell .rk{height:auto } | |
| .va-reco-cell .rk img{height:100% ;min-height:92px } | |
| .va-utilities .cell-ph{padding-bottom:8px ;border-bottom:1px solid rgba(201,162,74,.16) } | |
| /* 50/50 widths (override the old 31.58% cap that constrained .va-share-cell) */ | |
| .va-utilities > .va-reco-cell{flex:1 1 0 ;max-width:none ;min-width:200px } | |
| .va-utilities > .va-share-cell{flex:1 1 0 ;max-width:none ;min-width:200px } | |
| /* SHARE: X joins the other socials (download takes the whole first line); the MOST | |
| WANTED button sits right after the link/copy row β no gap */ | |
| .va-share-cell .sp-row1{gap:8px } | |
| .va-share-cell .sp-dl{flex:1 1 100% ;width:100% ;justify-content:center } | |
| /* SHARE: pack the MOST WANTED button snug under the link/copy row. The gradio block | |
| wrappers inside the utility cells carry a stray ~34px min-height (zeroed in the rail | |
| but not here) which was opening the void β kill it so each block hugs its content. */ | |
| .va-cell .block, .va-cell .html-container, .va-cell .form{min-height:0 ;padding:0 } | |
| .va-share-cell{gap:7px ;justify-content:flex-start } | |
| /* the share blocks must NOT flex-grow (gradio gives them flex:1, which expanded the | |
| share-panel block and dropped the MOST WANTED button ~40px). Pin them to content | |
| size so the button sits right under the link/copy row; any slack falls below it. */ | |
| .va-share-cell > *{margin:0 ;flex:0 0 auto } | |
| #publish-btn{margin-top:7px } | |
| /* ===== THE VOICE β a slim player bar at the TOP of the right rail. The header | |
| fuses with the player box below it (case-file look); the waveform is strictly | |
| CONTAINED (fixed box + overflow clipped + bars capped) so it can NEVER spill. === */ | |
| .va-voice-head{margin-top:0 } /* first item in the rail β flush to the top */ | |
| .va-voice-out{margin:0 } | |
| .va-voice-out .vp{border:1px solid #3a322b;border-top:0;background:#1d1916; | |
| padding:9px 13px;margin:0;border-radius:0} | |
| .va-voice-out .vp-wave{height:34px ;overflow:hidden ;align-items:center } | |
| .va-voice-out .vp-wave i{max-height:30px } | |
| /* a clean ~10px visible gap above the case file (the voice block contributes its | |
| own ~5px, so 5px here lands the box-to-box gap at 10px like the others) */ | |
| .va-rail .va-file{margin-top:5px } | |
| /* trim the case-file scroll + prosecution body a touch to make room for the voice bar */ | |
| .va-rail .fp-scroll{max-height:clamp(120px,19vh,220px) } | |
| .va-rail .prosecution-box .pb-body{max-height:148px } | |
| /* ===== URGENT FINAL FIXES ===== */ | |
| /* 1) THE VOICE loading state ("clearing his throat") must sit INSIDE the bordered | |
| box with the shimmer bar clipped β it was overflowing the right border. */ | |
| .va-voice-out .lab-load{border:1px solid #3a322b ;border-top:0 ; | |
| background:#1d1916 ;padding:10px 13px ;margin:0 ; | |
| overflow:hidden ;border-radius:0 ;max-width:100% ;box-sizing:border-box} | |
| .va-voice-out .ll-bar,.va-voice-out .ll-txt{max-width:100% ;min-width:0 } | |
| /* 2) the chat area must be noir β kill the grey Gradio surface showing through the | |
| empty chat space above the chips. */ | |
| .va-body > .va-rail > #grill-chat-wrap{background:#141110 } | |
| .va-body > .va-rail > #grill-chat-wrap > *, | |
| .va-body > .va-rail > #grill-chat-wrap .grill-box{flex:1 1 auto ; | |
| background:#141110 ;min-height:0 } | |
| .va-rail .styler,.va-rail .gr-group,.va-rail .block{background:transparent } | |
| /* 3) the 4 TRIAL move chips were showing the grey Gradio button fill β force NOIR */ | |
| .trial-chips .trial-chip,button.trial-chip{background:#221c18 ; | |
| border:1px solid #5a4b3c ;color:#cbbfa8 ;box-shadow:none } | |
| .trial-chips .trial-chip:hover,button.trial-chip:hover{background:#2f2620 ;border-color:#c9a24a } | |