/* shared/elevation.css — on-page admin-elevation toggle. elevation.js appends this control to ONLY for users the server says can_elevate (sudo-style opt-in). It's a fixed bottom- right switch so it works in any tool without a header slot and stays clear of the top "admin mode is on" banner. Arming is per-page: the cookie is session-scoped and cleared on pagehide. */ .elevation-toggle { position: fixed; right: 0.9rem; bottom: 0.9rem; z-index: 9300; /* above the is-elevated frame (9200) so it stays clickable */ display: inline-flex; align-items: center; gap: 0.3rem; font-size: 0.78rem; color: var(--text-muted); user-select: none; cursor: pointer; padding: 0.2rem 0.5rem; border: 1px solid var(--border); border-radius: var(--radius); background: var(--bg); box-shadow: 0 1px 4px rgba(0, 0, 0, 0.14); transition: background 0.12s, border-color 0.12s, color 0.12s; } .elevation-toggle:hover { background: var(--bg-hover); border-color: var(--border-dark); } .elevation-toggle input[type="checkbox"] { margin: 0; cursor: pointer; accent-color: var(--danger); } .elevation-toggle__label { cursor: pointer; letter-spacing: 0.02em; } /* Active state — when elevation is ON, the toggle reads as "armed" so the user can't miss that admin powers are currently live. :has(:checked) lets us style the wrapper based on the inner checkbox without JS. */ .elevation-toggle:has(input:checked) { background: rgba(220, 53, 69, 0.12); border-color: var(--danger); color: var(--danger); font-weight: 600; } /* Page-wide chrome when admin mode is active. The toggle alone is easy to miss; these add an inescapable visual cue: 1. Thin red border around the entire viewport — peripheral- vision reminder regardless of which tool / scroll position. 2. Sticky banner across the top with a one-click "Drop admin" button so the user can disarm without hunting for the toggle. Both rendered ONLY when the zddc-elevate cookie is set; the shared/elevation.js init() syncs the body class on every page load and tears it down when elevation is cleared. Frame uses fixed positioning + pointer-events:none so it doesn't reflow content or steal clicks. An inset outline on was tried first but overdrew content in tools whose root layout butts right up to the viewport edge (browse split-pane, archive grid). */ body.is-elevated::after { content: ""; position: fixed; inset: 0; border: 3px solid var(--danger, #dc3545); pointer-events: none; z-index: 9200; /* above banner (9100) so the frame paints on top */ } .elevation-banner { display: flex; align-items: center; gap: 0.75rem; padding: 0.4rem 0.9rem; background: rgba(220, 53, 69, 0.95); color: #fff; font-size: 0.85rem; font-weight: 500; letter-spacing: 0.01em; position: sticky; top: 0; z-index: 9100; /* above modal-overlay (9000) so it's never hidden */ box-shadow: 0 1px 4px rgba(0, 0, 0, 0.18); } .elevation-banner__dot { width: 0.5rem; height: 0.5rem; background: #fff; border-radius: 50%; box-shadow: 0 0 0 0 rgba(255, 255, 255, 0.7); animation: elev-pulse 1.6s infinite; flex-shrink: 0; } @keyframes elev-pulse { 0% { box-shadow: 0 0 0 0 rgba(255, 255, 255, 0.7); } 70% { box-shadow: 0 0 0 8px rgba(255, 255, 255, 0); } 100% { box-shadow: 0 0 0 0 rgba(255, 255, 255, 0); } } .elevation-banner__msg { flex: 1 1 auto; } .elevation-banner__off { background: rgba(255, 255, 255, 0.18); border: 1px solid rgba(255, 255, 255, 0.7); color: #fff; padding: 0.18rem 0.65rem; border-radius: var(--radius, 4px); font-size: 0.78rem; font-weight: 600; letter-spacing: 0.02em; cursor: pointer; flex-shrink: 0; } .elevation-banner__off:hover { background: rgba(255, 255, 255, 0.3); }