/* Local media viewer. Structure comes from the Claude Design source `webar/media-viewer.html` (project 83401f51-8016-4697-b600-b4d6e1ac8d35): accent rail, corner brackets, glass card, chip rows, the plan-view screen gizmo, the striped experimental banner. Colour and type read this bundle's OWN tokens (ui/panels.css) rather than the design system's --omega-* names, so the panel matches the eight WebAR surfaces already shipped around it instead of introducing a second palette mid-session. The token divergence between the two is a real, separate finding and is named in the report — not silently reconciled here under a flagship. */ #media-viewer-panel { position: fixed; inset: 0; z-index: 120; display: none; flex-direction: column; background: var(--bg-darker); color: var(--text-primary); font: var(--font-body, 400 15px/1.45 var(--font)); pointer-events: auto; } #media-viewer-panel.mv-open { display: flex; } .mv-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; padding: calc(14px + env(safe-area-inset-top)) 16px 12px; border-bottom: 1px solid var(--glass-border); background: var(--glass-bg); backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate)); } .mv-eyebrow { margin: 0 0 4px; font: 600 11px/1 var(--font); letter-spacing: 0.22em; text-transform: uppercase; color: var(--accent); } .mv-title { margin: 0; font: 600 19px/1.2 var(--font); letter-spacing: 0.01em; } .mv-close { flex: none; width: 40px; height: 40px; /* 44px-class target with the icon inset */ display: grid; place-items: center; border-radius: var(--glass-radius-sm); background: var(--glass-bg-hover); border: 1px solid var(--glass-border); color: var(--text-secondary); cursor: pointer; } .mv-close:hover { color: var(--text-primary); background: var(--glass-bg-active); } .mv-close svg { width: 15px; height: 15px; } .mv-body { flex: 1; overflow-y: auto; padding: 4px 16px calc(40px + env(safe-area-inset-bottom)); } .mv-cap { margin: 20px 0 8px; font: 600 10.5px/1 var(--font); letter-spacing: 0.2em; text-transform: uppercase; color: var(--text-tertiary); } .mv-card { position: relative; margin: 0 0 12px; padding: 15px 15px 15px 18px; border-radius: var(--glass-radius); border: 1px solid var(--glass-border); background: var(--glass-bg); backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate)); overflow: hidden; } /* Accent rail — the shared OMEGA panel signature. */ .mv-card::before { content: ''; position: absolute; left: 0; top: 12px; bottom: 12px; width: 2px; background: linear-gradient(180deg, transparent, var(--accent), transparent); opacity: 0.85; } .mv-brk { position: absolute; width: 13px; height: 13px; border: 1.5px solid var(--accent); opacity: 0.36; pointer-events: none; } .mv-brk.tr { top: 8px; right: 8px; border-left: 0; border-bottom: 0; border-radius: 0 5px 0 0; } .mv-brk.bl { bottom: 8px; left: 8px; border-right: 0; border-top: 0; border-radius: 0 0 0 5px; } .mv-h { margin: 0 0 3px; font: 600 14px/1.3 var(--font); letter-spacing: 0.01em; } .mv-h-gap { margin-top: 16px; } .mv-sub { margin: 0 0 12px; font: 400 12.5px/1.5 var(--font); color: var(--text-secondary); } .mv-note { margin: 9px 0 0; font: 400 12px/1.5 var(--font); color: var(--text-tertiary); } /* Not colour-alone: the advisory state also gains a left rule and a bolder weight. */ .mv-note-warn { color: var(--amber); font-weight: 500; border-left: 2px solid var(--amber); padding-left: 9px; } /* ---- picker ---- */ .mv-drop { border: 1.5px dashed var(--glass-border-strong); border-radius: var(--glass-radius); padding: 26px 18px; text-align: center; background: radial-gradient(120% 90% at 50% 0%, var(--accent-glow), transparent 62%); cursor: pointer; transition: border-color 0.18s ease, background 0.18s ease; } .mv-drop:hover { border-color: var(--accent); } .mv-drop-icon { width: 30px; height: 30px; color: var(--accent); margin-bottom: 9px; } .mv-drop-big { font: 600 16px/1.2 var(--font); letter-spacing: 0.1em; text-transform: uppercase; color: var(--text-primary); } .mv-drop-small { margin-top: 5px; font: 400 12px/1.45 var(--font); color: var(--text-tertiary); } .mv-btn { display: inline-block; margin-top: 13px; padding: 10px 20px; min-height: 44px; border-radius: var(--glass-radius-sm); background: var(--glass-bg-active); border: 1px solid var(--glass-border-strong); color: var(--text-primary); font: 600 13px/1.4 var(--font); letter-spacing: 0.13em; text-transform: uppercase; cursor: pointer; } .mv-btn:hover { border-color: var(--accent); } .mv-detected { display: flex; gap: 9px; align-items: flex-start; margin-top: 13px; padding: 11px 12px; border-radius: var(--glass-radius-sm); background: rgba(92, 224, 168, 0.08); border: 1px solid rgba(92, 224, 168, 0.3); } .mv-detected p { margin: 0; font: 400 12.5px/1.5 var(--font); color: var(--text-secondary); } .mv-detected b { color: var(--text-primary); font-weight: 600; } .mv-ok-icon { width: 15px; height: 15px; flex: none; margin-top: 1px; color: var(--success); } /* ---- chips ---- */ .mv-row { display: flex; flex-wrap: wrap; gap: 7px; } .mv-modes { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 7px; } .mv-chip { min-height: 44px; padding: 8px 13px; border-radius: 10px; background: var(--glass-bg-hover); border: 1px solid var(--glass-border); color: var(--text-secondary); font: 600 12.5px/1.2 var(--font); letter-spacing: 0.1em; text-transform: uppercase; white-space: nowrap; cursor: pointer; transition: background 0.16s ease, border-color 0.16s ease, color 0.16s ease; } .mv-chip:hover { background: var(--glass-bg-active); color: var(--text-primary); } /* Selection is never colour-alone: the border weight and the inner ring change too. */ .mv-chip[aria-pressed='true'] { background: var(--glass-bg-active); border-color: var(--accent); color: var(--text-primary); box-shadow: inset 0 0 0 1px var(--accent-glow), 0 0 18px -6px var(--accent); } .mv-chip:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; } .mv-auto { display: inline-block; margin-left: 6px; font-size: 9px; letter-spacing: 0.14em; color: var(--accent); } .mv-mode { display: flex; align-items: center; justify-content: flex-start; gap: 7px; } .mv-mode svg { width: 14px; height: 14px; flex: none; } /* ---- screen gizmo ---- */ .mv-gizmo { position: relative; height: 176px; border-radius: var(--glass-radius-sm); border: 1px solid var(--glass-border); background: var(--bg-darker); overflow: hidden; touch-action: none; /* the handles own the drag, not the scroller */ } .mv-grid { position: absolute; inset: 0; background-image: linear-gradient(rgba(120, 220, 255, 0.07) 1px, transparent 1px), linear-gradient(90deg, rgba(120, 220, 255, 0.07) 1px, transparent 1px); background-size: 26px 26px; /* 26px == 1 metre, matching the drag ratio */ } .mv-wedge { position: absolute; left: 50%; bottom: 24px; width: 210px; height: 118px; transform: translateX(-50%); background: linear-gradient(0deg, var(--accent-glow), transparent); clip-path: polygon(50% 100%, 4% 0%, 96% 0%); } .mv-viewer { position: absolute; left: 50%; bottom: 18px; transform: translateX(-50%); width: 13px; height: 13px; border-radius: 50%; background: var(--amber); box-shadow: 0 0 14px var(--amber-glow); } .mv-viewer-lbl { position: absolute; left: 50%; bottom: 2px; transform: translateX(-50%); font: 600 9.5px/1 var(--font); letter-spacing: 0.16em; color: var(--text-tertiary); } .mv-screen { position: absolute; left: 50%; top: 34px; transform: translateX(-50%); width: 200px; height: 34px; pointer-events: none; } .mv-screen path { fill: none; stroke: var(--accent); stroke-width: 3.5; stroke-linecap: round; filter: drop-shadow(0 0 7px var(--accent-glow)); } .mv-handle { position: absolute; width: 15px; height: 15px; border-radius: 50%; background: var(--bg-darker); border: 2px solid var(--accent); cursor: grab; touch-action: none; } /* Generous invisible hit area — a 15px dot is not a touch target on a phone. */ .mv-handle::after { content: ""; position: absolute; inset: -16px; } .mv-handle:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; } .mv-handle.l { left: calc(50% - 107px); top: 52px; cursor: ew-resize; } .mv-handle.r { left: calc(50% + 93px); top: 52px; cursor: ew-resize; } .mv-handle.d { left: calc(50% - 7px); top: 30px; cursor: ns-resize; } .mv-readouts { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 7px; margin-top: 10px; } .mv-ro { padding: 8px 9px; border-radius: 9px; background: var(--glass-bg-hover); border: 1px solid var(--glass-border); } .mv-k { font: 600 9.5px/1 var(--font); letter-spacing: 0.16em; text-transform: uppercase; color: var(--text-tertiary); } .mv-v { margin-top: 3px; font: 500 13px/1.2 var(--font-mono); color: var(--text-primary); } /* ---- toggles ---- */ .mv-tog { display: flex; align-items: center; justify-content: space-between; gap: 14px; padding: 12px 0; border-top: 1px solid var(--glass-border); } .mv-tog:first-of-type { border-top: 0; padding-top: 2px; } .mv-lab { font: 500 13px/1.3 var(--font); color: var(--text-primary); } .mv-hint { margin-top: 3px; font: 400 11.5px/1.45 var(--font); color: var(--text-tertiary); } .mv-sw { flex: none; position: relative; width: 44px; height: 26px; border-radius: 14px; /* The visible track is 26px tall — deliberately, because a 44px-tall pill looks wrong next to 13px label text. The TOUCH target is widened to 44px with an invisible inset instead, so the control meets the target size without the switch itself having to be oversized. Caught by a live layout measurement, not by looking at it. */ background: var(--glass-bg-hover); border: 1px solid var(--glass-border); cursor: pointer; padding: 0; } .mv-sw::after { content: ""; position: absolute; left: 0; right: 0; top: -12px; bottom: -12px; } .mv-sw i { position: absolute; top: 2px; left: 2px; width: 20px; height: 20px; border-radius: 50%; background: var(--text-tertiary); transition: left 0.2s cubic-bezier(0.2, 0.9, 0.3, 1.2), background 0.2s ease; } .mv-sw[aria-checked='true'] { background: var(--glass-bg-active); border-color: var(--accent); } .mv-sw[aria-checked='true'] i { left: 22px; background: var(--accent); } .mv-sw.warn[aria-checked='true'] { border-color: var(--amber); background: rgba(255, 180, 84, 0.2); } .mv-sw.warn[aria-checked='true'] i { background: var(--amber); } .mv-sw:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; } /* ---- quality readout ---- */ .mv-q { display: grid; grid-template-columns: 1fr auto; gap: 6px 14px; margin: 0; padding: 4px 0; } .mv-q dt { font: 600 11px/1.3 var(--font); letter-spacing: 0.09em; text-transform: uppercase; color: var(--text-tertiary); } .mv-q dd { margin: 0; text-align: right; font: 500 12.5px/1.3 var(--font-mono); color: var(--text-primary); } .mv-q dd.ok { color: var(--success); } .mv-q dd.warn { color: var(--warning); } /* ---- the persistent experimental label ---- Deliberately outside the panel and above everything: the requirement is that the user can tell what they are looking at was partly invented WITHOUT opening a menu. Hazard striping plus the amber token plus an icon plus the word "Experimental" — four independent signals, none of them colour alone. */ #mv-experimental-label { position: fixed; left: 50%; top: calc(12px + env(safe-area-inset-top)); transform: translateX(-50%); z-index: 260; display: flex; align-items: center; gap: 9px; max-width: min(92vw, 460px); padding: 9px 14px; border-radius: var(--glass-radius-sm); border: 1px solid var(--amber); background: repeating-linear-gradient(45deg, rgba(255, 180, 84, 0.16) 0 9px, rgba(255, 180, 84, 0.07) 9px 18px), var(--bg-darker); pointer-events: none; } #mv-experimental-label svg { width: 16px; height: 16px; flex: none; color: var(--amber); } #mv-experimental-label p { margin: 0; font: 600 12px/1.35 var(--font); letter-spacing: 0.1em; text-transform: uppercase; color: var(--amber); } @media (max-width: 380px) { .mv-modes { grid-template-columns: repeat(2, minmax(0, 1fr)); } .mv-readouts { grid-template-columns: repeat(2, minmax(0, 1fr)); } } @media (prefers-reduced-motion: reduce) { .mv-sw i, .mv-chip, .mv-drop { transition: none; } }