Files
scrying-pool/styles/scrying-pool.css
T
uberwald 06cf740aa3 Fix: Move CSS to root styles/ folder for FoundryVTT compatibility
The issue: CSS was in dist/styles/ but FoundryVTT expects module CSS
at the root level or in a standard location.

Changes:
- Build CSS to styles/scrying-pool.css (root level) instead of dist/styles/
- Update module.json to reference styles/scrying-pool.css
- Update .gitignore to track styles/scrying-pool.css
- Update build script in package.json

This ensures FoundryVTT can find and load the CSS file properly in live sessions.

Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
2026-05-24 14:12:44 +02:00

1838 lines
53 KiB
CSS
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* styles/scrying-pool.less — Entry point (@imports only)
*
* Build: npm run build → dist/styles/scrying-pool.css
* Watch: npm run watch (chokidar detects changes in @import-ed partials)
*
* Import order: tokens (base → states → motion → focus) → components
*/
/**
* styles/tokens/_base.less
*
* Layer 1 — SP Semantic Alias Tokens
*
* Thin alias layer mapping to Foundry CSS tokens in one place.
* If Foundry renames or shifts token semantics between versions,
* only this layer needs updating.
*
* RULE: All Foundry --color-* / --font-* / --border-* tokens are FORBIDDEN
* inside .scrying-pool CSS. Always use --sp-* aliases. This is the sole
* enforcement point for the semantic layer.
*
* Every token includes a hardcoded fallback for environments where the
* upstream Foundry token is absent.
*/
:root {
/* Surface & structure */
--sp-bg: var(--sp-theme-bg, var(--color-bg, hsl(220, 15%, 12%)));
--sp-surface: var(--sp-theme-surface, var(--color-bg-option, #141618));
--sp-surface-raised: var(--sp-theme-surface-raised, #1c1f22);
--sp-surface-elevated: var(--sp-theme-surface-elevated, var(--sp-surface-raised, #1c1f22));
--sp-border: var(--sp-theme-border, var(--color-border, #282c30));
/* Typography */
--sp-text-primary: var(--sp-theme-text-primary, var(--color-text-primary, #dde2e8));
--sp-text-secondary: var(--sp-theme-text-secondary, var(--color-text-secondary, #7a8390));
--sp-text-muted: var(--sp-theme-text-muted, #555d66);
/* Accent & interaction */
--sp-accent: var(--sp-theme-accent, var(--color-warm-2, #4a9e6b));
--sp-surface-interactive: var(--sp-theme-interactive, #242830);
--sp-control-bg: var(--sp-theme-control, #1a1d20);
/* Focus ring — module-wide keyboard navigation anchor */
--sp-focus: var(--sp-theme-focus, var(--color-focus-outline, #63c287));
--sp-focus-ring: 0 0 0 2px var(--sp-focus);
/* Badge */
--sp-badge-bg: rgba(0, 0, 0, 0.72);
--sp-badge-text: var(--sp-text-primary);
/* Background operations = no toast ever (silent by design) */
}
/* Theme overrides — dark theme defaults */
.scrying-pool,
:root[data-color-scheme="dark"] {
--sp-theme-bg: hsl(220, 15%, 12%);
--sp-theme-surface: #141618;
--sp-theme-surface-raised: #1c1f22;
--sp-theme-surface-elevated: #1c1f22;
--sp-theme-border: #282c30;
--sp-theme-text-primary: #dde2e8;
--sp-theme-text-secondary: #7a8390;
--sp-theme-text-muted: #555d66;
--sp-theme-accent: #4a9e6b;
--sp-theme-interactive: #242830;
--sp-theme-control: #1a1d20;
--sp-theme-focus: #63c287;
--sp-theme-urgency: #c8982a;
}
/**
* styles/tokens/_spacing.less
*
* Layer 1 — SP Spacing Tokens
*
* Semantic spacing tokens for consistent layout.
* Maps to Foundry's spacing scale where available.
*/
:root {
--sp-spacing-xxs: 2px;
--sp-spacing-xs: 4px;
--sp-spacing-sm: 8px;
--sp-spacing-md: 12px;
--sp-spacing-lg: 16px;
--sp-spacing-xl: 24px;
--sp-spacing-2xl: 32px;
/* Border radius */
--sp-border-radius: 4px;
--sp-border-radius-lg: 8px;
/* Legacy aliases for preset-import-export.less */
--sp-space-xs: var(--sp-spacing-xs, 4px);
--sp-space-sm: var(--sp-spacing-sm, 8px);
--sp-space-m: var(--sp-spacing-md, 12px);
--sp-space-l: var(--sp-spacing-lg, 16px);
--sp-space-xl: var(--sp-spacing-xl, 24px);
}
/**
* styles/tokens/_states.less
*
* Layer 2 — SP Participant State Tokens
*
* All 8 participant states + 1 pending state (9 total).
* Each state provides three CSS custom properties:
* --sp-state-{name}-text — foreground / icon colour
* --sp-state-{name}-border — ring / border colour
* --sp-state-{name}-bg — background tint colour
*
* SECOND-SIGNAL RULE (WCAG):
* Every state conveys meaning via THREE independent channels:
* colour + icon (Font Awesome codepoint) + shape (ring variant).
* States marked ⚠️ below have low contrast ratios and MUST NOT
* appear as text or small-pill foreground — icon + shape carry the signal.
*
* State precedence (VisibilityManager/RoleRenderer resolves; CSS never handles multi-state):
* pending > cam-lost > reconnecting > offline > never-connected > self-muted > hidden > ghost > active
*
* LESS state map — single source of truth for loop-generated component CSS.
*/
/* ─── State colour variables ─────────────────────────────────────────────── */
:root {
/* active — Intentional / positive */
/* ✅ WCAG AA safe */
--sp-state-active-text: #4a9e6b;
--sp-state-active-border: #4a9e6b;
--sp-state-active-bg: rgba(74, 158, 107, 0.12);
/* hidden — Intentional / deliberate (GM action) */
/* ⚠️ Low contrast (~3.75:1) — icon + dashed ring carry the signal */
--sp-state-hidden-text: #6b7280;
--sp-state-hidden-border: #6b7280;
--sp-state-hidden-bg: rgba(107, 114, 128, 0.1);
/* self-muted — Self / player's own choice */
/* ✅ WCAG AA safe */
--sp-state-self-muted-text: #8b92a5;
--sp-state-self-muted-border: #8b92a5;
--sp-state-self-muted-bg: rgba(139, 146, 165, 0.1);
/* offline — Technical / disconnected */
/* ⚠️ Low contrast (~2.4:1) — icon + no-ring shape carry the signal */
--sp-state-offline-text: #4b5563;
--sp-state-offline-border: #4b5563;
--sp-state-offline-bg: rgba(75, 85, 99, 0.08);
/* cam-lost — Technical / camera failure */
/* ✅ WCAG AA safe */
--sp-state-cam-lost-text: #9ca3af;
--sp-state-cam-lost-border: #9ca3af;
--sp-state-cam-lost-bg: rgba(156, 163, 175, 0.1);
/* reconnecting — Technical / in-progress */
/* ✅ WCAG AA safe */
--sp-state-reconnecting-text: #c8982a;
--sp-state-reconnecting-border: #c8982a;
--sp-state-reconnecting-bg: rgba(200, 152, 42, 0.12);
/* never-connected — Passive / never joined */
/* ⚠️ Low contrast (~1.76:1) — empty circle + no icon carries the signal */
--sp-state-never-connected-text: #374151;
--sp-state-never-connected-border: #374151;
--sp-state-never-connected-bg: rgba(55, 65, 81, 0.06);
/* ghost — Passive / placeholder slot */
/* ⚠️ Very low contrast (~1.24:1) — ghost icon + dotted ring, lowest opacity */
--sp-state-ghost-text: #1f2937;
--sp-state-ghost-border: #1f2937;
--sp-state-ghost-bg: rgba(31, 41, 55, 0.04);
/* pending — Optimistic UI in-flight (transient; never persisted) */
--sp-state-pending-text: #7a8390;
--sp-state-pending-border: #7a8390;
--sp-state-pending-bg: rgba(122, 131, 144, 0.1);
}
/* ─── Font Awesome icon codepoints (used in component CSS via content: "\f...") ── */
/*
active: '\f06e' (eye)
hidden: '\f070' (eye-slash)
self-muted: '\f131' (microphone-slash)
offline: '\f00d' (times / user-slash)
cam-lost: '\f03d' (video-slash / film)
reconnecting: '\f021' (sync/spinner)
never-connected: '\f068' (minus / em-dash)
ghost: '\f2be' (ghost / user-secret)
pending: '\f110' (spinner)
*/
/* ─── State ring shape variants (applied via sp-state-ring--* modifier) ──── */
/*
solid → active, self-muted
dashed → hidden, cam-lost
pulse → reconnecting, pending (animation in _motion.less)
dotted → ghost
none → offline, never-connected
*/
/**
* styles/tokens/_motion.less
*
* Layer 3/4 — SP Urgency Tier & Motion Tokens
*
* ALL animated token usages MUST be inside:
* @media (prefers-reduced-motion: no-preference) { ... }
*
* Fallback (reduced motion): instant state change with icon/state signal only.
* No layout/size animations — only opacity, background-color, border-color.
*
* Motion tokens:
* --sp-fade-hide : Player client opacity fade on hide (300500ms ease-out)
* --sp-pulse-reconnecting : StateRing pulse for reconnecting state (lighthouse rhythm)
* --sp-shimmer-degraded : cam-lost shimmer (single blink, not looping)
* --sp-toast-delay : Director-cue toast delay after hide action
*/
/* ─── Motion token values ─────────────────────────────────────────────────── */
:root {
--sp-fade-hide: 300ms ease-out;
/* Player only — GM sees instant state change */
--sp-pulse-reconnecting: 1.5s ease-in-out infinite;
--sp-shimmer-degraded: 800ms ease-in-out 1;
/* single blink, not looping */
--sp-toast-delay: 1s;
/* Director-cue toast delay */
--sp-transition-state: 200ms ease-out;
/* Generic state token transition */
/* Urgency tokens (Layer 3 per AC7) — NEVER inherit Foundry error/warn colours */
/* Director cues = deliberate stage direction, not a failure. */
--sp-urgency-director: var(--sp-theme-urgency, #c8982a);
--sp-urgency-awareness: var(--sp-text-secondary);
}
/* ─── Keyframe animations ─────────────────────────────────────────────────── */
@media (prefers-reduced-motion: no-preference) {
@keyframes sp-pulse {
0%,
100% {
opacity: 1;
}
50% {
opacity: 0.45;
}
}
@keyframes sp-shimmer {
0% {
opacity: 1;
}
50% {
opacity: 0.3;
}
100% {
opacity: 1;
}
}
@keyframes sp-fade-out {
from {
opacity: 1;
}
to {
opacity: 0;
}
}
/* Reconnecting ring pulse — applied via .sp-state-ring--pulse */
.sp-state-ring--pulse {
animation: sp-pulse var(--sp-pulse-reconnecting);
}
/* cam-lost shimmer — applied via .sp-state-cam-lost */
.sp-state-cam-lost .sp-state-ring--dashed {
animation: sp-shimmer var(--sp-shimmer-degraded);
}
}
/* ─── Reduced motion overrides (global) ──────────────────────────────────── */
@media (prefers-reduced-motion: reduce) {
/* Target specific animated elements instead of universal selector */
.sp-state-ring--pulse,
.sp-state-cam-lost .sp-state-ring--dashed {
animation: none;
transition: none;
}
}
/* ─── Allowed transitions (opacity, background-color, border-color only) ─── */
/*
Transitions on layout properties (width, height, max-height, transform) are
forbidden except for the ScryingPoolStrip collapsed ↔ expanded toggle which
uses max-width exclusively (never width animation).
*/
/**
* styles/tokens/_focus.less
*
* Module-wide focus ring pattern.
*
* High-contrast outer ring + inner offset that must survive all 9 state
* background combinations and both Foundry dark/light themes.
* Never rely on browser default focus outline alone.
*
* Applied via: .scrying-pool *:focus-visible
*/
.scrying-pool {
/* Elevated contrast for interactive elements with state backgrounds */
}
.scrying-pool *:focus-visible {
outline: none;
/* suppress browser default - visible fallback via box-shadow */
box-shadow: var(--sp-focus-ring), 0 0 0 4px var(--sp-surface);
/* Inner offset (--sp-surface) creates separation so the ring is visible
against any state background. The outer ring uses --sp-focus (#63c287).
NOTE: Parent containers must NOT have overflow:hidden to avoid clipping. */
}
.scrying-pool [role="button"]:focus-visible,
.scrying-pool button:focus-visible {
outline: none;
box-shadow: 0 0 0 2px var(--sp-surface), /* inner offset */ 0 0 0 4px var(--sp-focus);
/* outer ring */
}
/**
* styles/components/_participant-card.less
*
* 80×100px card tile used in the Director's Board grid.
* All selectors scoped under .scrying-pool.
* Uses --sp-* tokens only — no Foundry --color-* / --font-* / --border-* tokens.
*/
.scrying-pool .participant-card {
width: 80px;
height: 100px;
position: relative;
display: flex;
flex-direction: column;
align-items: center;
border: 2px solid var(--sp-border);
border-radius: 4px;
background: var(--sp-surface);
cursor: pointer;
overflow: hidden;
transition: border-color var(--sp-transition-state), background-color var(--sp-transition-state);
}
.scrying-pool .participant-card.sp-state-active {
border-color: var(--sp-state-active-border);
border-style: solid;
background: var(--sp-state-active-bg);
}
.scrying-pool .participant-card.sp-state-hidden {
border-color: var(--sp-state-hidden-border);
border-style: dashed;
background: var(--sp-state-hidden-bg);
}
.scrying-pool .participant-card.sp-state-self-muted {
border-color: var(--sp-state-self-muted-border);
border-style: solid;
background: var(--sp-state-self-muted-bg);
}
.scrying-pool .participant-card.sp-state-offline {
border-color: var(--sp-state-offline-border);
border-style: none;
background: var(--sp-state-offline-bg);
}
.scrying-pool .participant-card.sp-state-cam-lost {
border-color: var(--sp-state-cam-lost-border);
border-style: dashed;
background: var(--sp-state-cam-lost-bg);
}
.scrying-pool .participant-card.sp-state-reconnecting {
border-color: var(--sp-state-reconnecting-border);
border-style: solid;
background: var(--sp-state-reconnecting-bg);
}
.scrying-pool .participant-card.sp-state-never-connected {
border-color: var(--sp-state-never-connected-border);
border-style: none;
background: var(--sp-state-never-connected-bg);
}
.scrying-pool .participant-card.sp-state-ghost {
border-color: var(--sp-state-ghost-border);
border-style: dotted;
background: var(--sp-state-ghost-bg);
}
.scrying-pool .participant-card.sp-state-pending {
border-color: var(--sp-state-pending-border);
border-style: solid;
background: var(--sp-state-pending-bg);
}
.scrying-pool .participant-card__avatar {
width: 48px;
height: 48px;
margin: 8px auto 4px;
flex-shrink: 0;
position: relative;
}
.scrying-pool .participant-card__avatar img {
width: 100%;
height: 100%;
border-radius: 50%;
object-fit: cover;
display: block;
}
.scrying-pool .participant-card__avatar-badge {
position: absolute;
width: 16px;
height: 16px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: 8px;
border: 1px solid var(--sp-surface);
box-shadow: 0 0 0 2px var(--sp-surface);
}
.scrying-pool .participant-card__avatar-badge i {
font-size: 10px;
color: var(--sp-text-primary);
}
.scrying-pool .participant-card__avatar-badge--reaction-cam {
background: var(--sp-accent);
bottom: 0;
right: 0;
cursor: help;
}
.scrying-pool .participant-card__name {
font-size: 12px;
line-height: 1.2;
text-align: center;
color: var(--sp-text-primary);
overflow: hidden;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
padding: 0 4px;
margin: 0;
width: 100%;
word-break: break-word;
}
.scrying-pool .participant-card__toggle {
position: absolute;
inset: 0;
display: flex;
align-items: center;
justify-content: center;
background: var(--sp-badge-bg);
color: var(--sp-badge-text);
border: none;
border-radius: 2px;
cursor: pointer;
opacity: 0;
transition: opacity var(--sp-transition-state);
font-size: 18px;
padding: 0;
}
.scrying-pool .participant-card__toggle:focus-visible {
opacity: 1;
}
.scrying-pool .participant-card:hover .scrying-pool .participant-card__toggle,
.scrying-pool .participant-card:focus-within .scrying-pool .participant-card__toggle {
opacity: 1;
}
.scrying-pool .participant-card:focus-visible {
outline: none;
box-shadow: var(--sp-focus-ring), 0 0 0 4px var(--sp-surface);
}
@media (prefers-reduced-motion: reduce) {
.scrying-pool .participant-card {
transition: none;
}
.scrying-pool .participant-card__toggle {
transition: none;
}
}
:root {
--sp-state-active: hsl(140, 60%, 55%);
--sp-state-hidden: hsl(0, 0%, 50%);
--sp-state-self-muted: hsl(200, 60%, 55%);
--sp-state-cam-lost: hsl(30, 80%, 55%);
--sp-state-pending: hsl(50, 90%, 55%);
--sp-urgency-director: hsl(38, 90%, 55%);
--sp-state-color: hsl(140, 60%, 55%);
}
.scrying-pool-strip {
position: relative;
display: flex;
flex-direction: column;
align-items: center;
max-width: 44px;
overflow: hidden;
transition: max-width 200ms ease-in-out;
background: var(--sp-bg, hsl(220, 15%, 12%));
border-radius: 8px;
}
.scrying-pool-strip.is-expanded {
max-width: 240px;
}
.sp-strip__toggle {
width: 44px;
height: 44px;
display: flex;
align-items: center;
justify-content: center;
background: none;
border: none;
cursor: pointer;
color: var(--sp-text, hsl(0, 0%, 80%));
flex-shrink: 0;
}
.sp-strip__participants {
list-style: none;
margin: 0;
padding: 0;
width: 100%;
display: flex;
flex-direction: column;
gap: 4px;
}
.sp-strip__first-tip {
font-size: 0.75rem;
color: var(--sp-text-muted, hsl(0, 0%, 60%));
padding: 4px 8px;
margin: 0;
}
.sp-participant-avatar {
position: relative;
width: 44px;
height: 44px;
display: flex;
align-items: center;
justify-content: flex-start;
background: none;
border: none;
cursor: pointer;
padding: 6px;
border-radius: 4px;
gap: 8px;
overflow: hidden;
}
.sp-participant-avatar:focus-visible {
outline: 2px solid var(--sp-focus-ring, hsl(200, 80%, 60%));
outline-offset: 2px;
}
.is-expanded .sp-participant-avatar {
width: 100%;
padding: 6px 8px;
}
.sp-participant-video {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
overflow: hidden;
z-index: 1;
}
.sp-avatar__img {
width: 32px;
height: 32px;
border-radius: 50%;
object-fit: cover;
flex-shrink: 0;
}
.sp-participant-video__element {
width: 100%;
height: 100%;
object-fit: cover;
border-radius: 50%;
background: hsl(220, 15%, 18%);
}
.is-expanded .sp-participant-video__element {
border-radius: 4px;
}
.sp-participant-video:not(:empty) ~ .sp-avatar__img {
display: none;
}
.sp-avatar__corner-badge {
position: absolute;
bottom: 2px;
right: 2px;
width: 12px;
height: 12px;
border-radius: 50%;
background: var(--sp-state-color);
font-size: 8px;
display: flex;
align-items: center;
justify-content: center;
}
.sp-avatar__name {
font-size: 0.85rem;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
color: var(--sp-text, hsl(0, 0%, 85%));
}
.sp-avatar__state-label {
font-size: 0.7rem;
color: var(--sp-text-muted, hsl(0, 0%, 60%));
}
.sp-participant-avatar.sp-state-active,
.sp-participant-avatar.sp-state-self-muted {
--sp-state-color: var(--sp-state-active);
}
.sp-participant-avatar.sp-state-active .sp-avatar__img,
.sp-participant-avatar.sp-state-self-muted .sp-avatar__img {
box-shadow: 0 0 0 2px var(--sp-state-color);
}
.sp-participant-avatar.sp-state-hidden,
.sp-participant-avatar.sp-state-cam-lost {
--sp-state-color: var(--sp-state-hidden);
}
.sp-participant-avatar.sp-state-hidden .sp-avatar__img,
.sp-participant-avatar.sp-state-cam-lost .sp-avatar__img {
outline: 2px dashed var(--sp-state-color);
outline-offset: 2px;
}
.sp-participant-avatar.sp-state-pending {
--sp-state-color: var(--sp-state-pending);
}
.sp-participant-avatar.sp-state-pending .sp-avatar__img {
box-shadow: 0 0 0 2px var(--sp-state-color);
}
@media (prefers-reduced-motion: no-preference) {
.sp-participant-avatar.sp-state-pending .sp-avatar__img {
animation: sp-pulse 2s ease-in-out infinite;
}
@keyframes sp-pulse {
0%,
100% {
opacity: 1;
}
50% {
opacity: 0.4;
}
}
.sp-participant-avatar.sp-state-revert .sp-avatar__img {
animation: sp-revert-flash 200ms ease-out forwards;
}
@keyframes sp-revert-flash {
0% {
box-shadow: 0 0 0 3px var(--sp-urgency-director);
}
100% {
box-shadow: 0 0 0 2px var(--sp-state-color);
}
}
}
.sp-strip__empty-state {
display: flex;
flex-direction: column;
align-items: center;
padding: 16px 8px;
gap: 8px;
color: var(--sp-text-muted, hsl(0, 0%, 60%));
}
.sp-empty__icon {
font-size: 1.5rem;
display: block;
}
.sp-empty__text {
font-size: 0.75rem;
text-align: center;
}
@media (prefers-reduced-motion: no-preference) {
.sp-empty__icon {
animation: sp-breathe 3s ease-in-out infinite;
}
@keyframes sp-breathe {
0%,
100% {
opacity: 0.6;
transform: scale(1);
}
50% {
opacity: 1;
transform: scale(1.05);
}
}
}
.sp-lock-overlay {
position: absolute;
inset: 0;
display: flex;
align-items: center;
justify-content: center;
background: hsla(0, 0%, 0%, 0.45);
pointer-events: none;
z-index: 10;
}
.sp-lock-overlay::before {
content: '\f023';
font-family: 'Font Awesome 6 Free';
font-weight: 900;
font-size: 1.2rem;
color: hsl(0, 0%, 85%);
}
.camera-view.sp-state-hidden {
opacity: 0.55;
position: relative;
}
.sp-portrait-fallback {
position: absolute;
inset: 0;
background: var(--sp-bg, hsl(220, 15%, 18%)) center / cover no-repeat;
pointer-events: none;
}
.sp-context-menu {
background: var(--sp-bg, hsl(220, 15%, 15%));
border: 1px solid hsl(0, 0%, 30%);
border-radius: 4px;
padding: 4px 0;
min-width: 160px;
z-index: 1000;
box-shadow: 0 4px 12px hsla(0, 0%, 0%, 0.4);
}
.sp-context-menu .sp-context-menu__item {
display: flex;
align-items: center;
gap: 8px;
width: 100%;
padding: 6px 12px;
background: none;
border: none;
cursor: pointer;
color: var(--sp-text, hsl(0, 0%, 85%));
font-size: 0.875rem;
text-align: left;
}
.sp-context-menu .sp-context-menu__item:hover,
.sp-context-menu .sp-context-menu__item:focus-visible {
background: hsla(200, 60%, 55%, 0.15);
}
.sp-action-popover {
background: var(--sp-bg, hsl(220, 15%, 15%));
border: 1px solid hsl(0, 0%, 30%);
border-radius: 6px;
padding: 12px;
min-width: 160px;
box-shadow: 0 4px 16px hsla(0, 0%, 0%, 0.5);
color: var(--sp-text, hsl(0, 0%, 85%));
}
.sp-action-popover .sp-action-popover__cta {
display: block;
width: 100%;
padding: 8px 16px;
background: hsl(200, 60%, 40%);
border: none;
border-radius: 4px;
cursor: pointer;
color: hsl(0, 0%, 95%);
font-size: 0.875rem;
}
.sp-action-popover .sp-action-popover__cta:hover:not(:disabled) {
background: hsl(200, 60%, 50%);
}
.sp-action-popover .sp-action-popover__cta:disabled {
opacity: 0.45;
cursor: not-allowed;
}
/**
* styles/components/_directors-board.less
*
* Layout for the Director's Board ApplicationV2 window.
* All selectors scoped under .scrying-pool.
* Uses --sp-* tokens only — no Foundry --color-* / --font-* / --border-* tokens.
*/
.scrying-pool.directors-board {
background: var(--sp-surface);
color: var(--sp-text-primary);
}
.scrying-pool.directors-board .directors-board__content {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(80px, 1fr));
gap: 8px;
padding: 12px;
overflow-y: auto;
flex: 1 1 auto;
list-style: none;
margin: 0;
}
.scrying-pool.directors-board .directors-board__empty {
grid-column: 1 / -1;
text-align: center;
color: var(--sp-text-muted);
font-size: 13px;
padding: 24px 0;
margin: 0;
}
.scrying-pool.directors-board .directors-board__bulk-bar {
display: flex;
align-items: center;
gap: 6px;
padding: 6px 12px;
border-top: 1px solid var(--sp-border);
flex-shrink: 0;
flex-wrap: wrap;
}
.scrying-pool.directors-board .directors-board__bulk-btn {
font-size: 12px;
background: var(--sp-accent, #4a6f9c);
color: #fff;
border: none;
border-radius: 3px;
padding: 4px 10px;
cursor: pointer;
transition: opacity 0.15s;
}
.scrying-pool.directors-board .directors-board__bulk-btn:hover {
opacity: 0.85;
}
.scrying-pool.directors-board .directors-board__bulk-btn:active {
opacity: 0.7;
}
.scrying-pool.directors-board .directors-board__bulk-btn--undo {
background: transparent;
color: var(--sp-text-muted);
border: 1px solid var(--sp-border);
}
.scrying-pool.directors-board .directors-board__bulk-btn--undo:hover {
color: var(--sp-text, inherit);
border-color: currentColor;
}
.scrying-pool.directors-board .directors-board__bulk-btn--restore {
background: var(--sp-spotlight-accent, #7b4fa6);
}
.scrying-pool.directors-board .directors-board__help-btn {
margin-left: auto;
width: 22px;
height: 22px;
border-radius: 50%;
border: 1px solid var(--sp-border);
background: transparent;
color: var(--sp-text-muted);
font-size: 12px;
font-weight: bold;
line-height: 1;
cursor: pointer;
flex-shrink: 0;
display: flex;
align-items: center;
justify-content: center;
}
.scrying-pool.directors-board .directors-board__help-btn:hover {
background: var(--sp-accent, #4a6f9c);
color: #fff;
border-color: transparent;
}
.scrying-pool.directors-board .directors-board__footer {
display: flex;
gap: 8px;
padding: 8px 12px;
border-top: 1px solid var(--sp-border);
flex-shrink: 0;
}
.scrying-pool.directors-board .directors-board__footer-btn {
flex: 1;
font-size: 12px;
background: var(--sp-accent, #4a6f9c);
color: #fff;
border: none;
border-radius: 3px;
padding: 4px 8px;
cursor: pointer;
transition: opacity 0.15s;
}
.scrying-pool.directors-board .directors-board__footer-btn:hover {
opacity: 0.85;
}
.scrying-pool.directors-board .directors-board__footer-btn:active {
opacity: 0.7;
}
.scrying-pool.directors-board .directors-board__footer-btn[disabled] {
cursor: not-allowed;
opacity: 0.5;
background: transparent;
color: var(--sp-text-muted);
border: 1px solid var(--sp-border);
}
.directors-board__preset-panel {
background-color: var(--sp-surface);
border: 1px solid var(--sp-border);
border-radius: 6px;
padding: 12px;
margin-top: 12px;
display: flex;
flex-direction: column;
gap: 8px;
font-size: 14px;
line-height: 1.4;
color: var(--sp-text-primary);
}
.directors-board__preset-panel-header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 4px;
padding-bottom: 8px;
border-bottom: 1px solid var(--sp-border-subtle);
}
.directors-board__preset-panel-title {
margin: 0;
font-size: 15px;
font-weight: 600;
color: var(--sp-text-primary);
}
.directors-board__preset-panel-body {
display: flex;
flex-direction: column;
gap: 10px;
}
.directors-board__preset-panel-row {
display: flex;
align-items: center;
gap: 8px;
}
.directors-board__preset-panel-row--hint {
font-size: 12px;
color: var(--sp-text-secondary);
margin-top: 4px;
padding-top: 8px;
border-top: 1px solid var(--sp-border-subtle);
}
.directors-board__preset-panel-label {
display: flex;
align-items: center;
gap: 8px;
cursor: default;
user-select: none;
flex-wrap: wrap;
align-items: flex-start;
}
.directors-board__preset-panel-toggle {
background: transparent;
border: none;
padding: 0;
margin: 0;
cursor: pointer;
width: 18px;
height: 18px;
border: 2px solid var(--sp-border);
border-radius: 4px;
background-color: var(--sp-surface);
position: relative;
transition: background-color 150ms ease, border-color 150ms ease;
}
.directors-board__preset-panel-toggle:checked {
background-color: var(--sp-accent);
border-color: var(--sp-accent);
}
.directors-board__preset-panel-toggle:after {
content: '';
position: absolute;
top: 1px;
left: 1px;
width: 12px;
height: 12px;
background-color: var(--sp-surface);
border-radius: 2px;
transition: transform 150ms ease, background-color 150ms ease;
}
.directors-board__preset-panel-toggle:checked:after {
transform: translateX(100%);
background-color: var(--sp-surface-inverse, white);
}
.directors-board__preset-panel-toggle:focus {
outline: 2px solid var(--sp-focus);
outline-offset: 2px;
}
.directors-board__preset-panel-toggle:hover:not(:checked) {
background-color: var(--sp-surface-hover, rgba(0, 0, 0, 0.05));
}
.directors-board__preset-panel-select {
background: transparent;
border: 1px solid var(--sp-border);
padding: 6px 8px;
margin: 0;
cursor: pointer;
font-family: inherit;
font-size: 14px;
color: var(--sp-text-primary);
border-radius: 4px;
transition: border-color 150ms ease, box-shadow 150ms ease;
}
.directors-board__preset-panel-select:hover:not(:disabled) {
border-color: var(--sp-border-hover, var(--sp-accent));
}
.directors-board__preset-panel-select:focus {
outline: none;
border-color: var(--sp-focus);
box-shadow: 0 0 0 2px rgba(var(--sp-focus-rgb, 0, 0, 255), 0.2);
}
.directors-board__preset-panel-select:disabled {
opacity: 0.5;
cursor: not-allowed;
}
.directors-board__preset-panel-slider {
-webkit-appearance: none;
appearance: none;
width: 120px;
height: 6px;
background: var(--sp-surface-subtle, rgba(0, 0, 0, 0.1));
border-radius: 3px;
outline: none;
cursor: pointer;
}
.directors-board__preset-panel-slider::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
width: 16px;
height: 16px;
background: var(--sp-accent);
border-radius: 50%;
cursor: pointer;
transition: transform 150ms ease;
}
.directors-board__preset-panel-slider::-webkit-slider-thumb:hover {
transform: scale(1.1);
}
.directors-board__preset-panel-slider::-moz-range-thumb {
width: 16px;
height: 16px;
background: var(--sp-accent);
border-radius: 50%;
cursor: pointer;
border: none;
transition: transform 150ms ease;
}
.directors-board__preset-panel-slider::-moz-range-thumb:hover {
transform: scale(1.1);
}
.directors-board__preset-panel-slider:focus {
outline: none;
}
.directors-board__preset-panel-delay-value {
display: inline-block;
min-width: 40px;
text-align: right;
font-family: monospace;
font-size: 12px;
color: var(--sp-text-secondary);
padding: 0 4px;
}
.directors-board__preset-panel-message {
margin: 0;
color: var(--sp-text-secondary);
font-style: italic;
text-align: center;
padding: 8px 0;
}
@media (prefers-reduced-motion: reduce) {
.directors-board__preset-panel-toggle,
.directors-board__preset-panel-select,
.directors-board__preset-panel-slider::-webkit-slider-thumb,
.directors-board__preset-panel-slider::-moz-range-thumb {
transition: none;
}
.directors-board__preset-panel-slider::-webkit-slider-thumb:hover,
.directors-board__preset-panel-slider::-moz-range-thumb:hover {
transform: none;
}
}
.sp-visibility-badge {
transition: none;
animation: none;
}
:root {
--sp-badge-bg: hsl(220, 15%, 10%);
--sp-badge-text: hsl(0, 0%, 85%);
--sp-badge-border: hsl(220, 15%, 25%);
--sp-badge-font-size: 0.6875rem;
--sp-badge-letter-sp: 0.02em;
--sp-chip-bg: hsl(220, 15%, 15%);
--sp-chip-text: hsl(0, 0%, 75%);
}
.sp-visibility-badge {
position: absolute;
top: 0;
left: 50%;
transform: translateX(-50%);
z-index: 10;
display: inline-flex;
align-items: center;
gap: 4px;
padding: 2px 6px;
background: var(--sp-badge-bg);
color: var(--sp-badge-text);
border: 1px solid var(--sp-badge-border);
border-radius: 4px;
cursor: pointer;
white-space: nowrap;
}
.sp-visibility-badge__label {
font-size: var(--sp-badge-font-size);
letter-spacing: var(--sp-badge-letter-sp);
line-height: 1.2;
}
.sp-first-encounter-panel {
position: fixed;
z-index: 100;
bottom: 80px;
left: 50%;
transform: translateX(-50%);
max-width: 280px;
background: var(--sp-badge-bg);
color: var(--sp-badge-text);
border: 1px solid var(--sp-badge-border);
border-radius: 6px;
padding: 12px 16px;
overflow: hidden;
max-height: 200px;
}
.sp-first-encounter-panel__title {
font-size: 0.75rem;
font-weight: 600;
margin: 0 0 6px;
}
.sp-first-encounter-panel__body {
font-size: 0.6875rem;
margin: 0 0 10px;
}
.sp-first-encounter-panel__got-it {
font-size: 0.6875rem;
padding: 4px 10px;
cursor: pointer;
border-radius: 3px;
}
.sp-visibility-chip {
position: fixed;
z-index: 100;
bottom: 80px;
left: 50%;
transform: translateX(-50%);
display: inline-flex;
align-items: center;
padding: 2px 8px;
background: var(--sp-chip-bg);
color: var(--sp-chip-text);
border: 1px solid var(--sp-badge-border);
border-radius: 12px;
font-size: var(--sp-badge-font-size);
cursor: pointer;
}
.sp-visibility-chip:focus-visible {
outline: 2px solid var(--sp-state-active, hsl(220, 80%, 60%));
outline-offset: 2px;
}
dialog.sp-visibility-details-panel {
background: var(--sp-badge-bg);
color: var(--sp-badge-text);
border: 1px solid var(--sp-badge-border);
border-radius: 8px;
padding: 20px 24px;
max-width: 320px;
width: 100%;
}
dialog.sp-visibility-details-panel__state {
font-size: 0.875rem;
font-weight: 600;
margin: 0 0 10px;
}
dialog.sp-visibility-details-panel__reassurance,
dialog.sp-visibility-details-panel__audio-note {
font-size: 0.75rem;
margin: 0 0 10px;
}
dialog.sp-visibility-details-panel__stale {
font-size: 0.6875rem;
opacity: 0.6;
margin: 0 0 10px;
font-style: italic;
}
dialog.sp-visibility-details-panel__close {
display: block;
margin-top: 12px;
padding: 6px 14px;
cursor: pointer;
border-radius: 4px;
font-size: 0.75rem;
}
dialog.sp-visibility-details-panel::backdrop {
background: hsla(0, 0%, 0%, 0.4);
}
@media (prefers-reduced-motion: no-preference) {
.sp-first-encounter-panel {
transition: max-height 300ms ease-out, opacity 300ms ease-out;
}
.sp-first-encounter-panel--collapsing {
max-height: 0;
opacity: 0;
}
}
.scrying-pool .sp-strip__overlay-layer {
z-index: 10;
}
.scrying-pool .sp-strip__overlay-layer > * {
pointer-events: auto;
}
.scrying-pool__confirmation-bar {
position: absolute;
bottom: 0;
left: 0;
right: 0;
padding: 12px 16px;
border-radius: 4px 4px 0 0;
box-shadow: 0 -2px 8px rgba(0, 0, 0, 0.3);
z-index: 100;
font-size: 14px;
line-height: 1.4;
display: flex;
align-items: center;
gap: 12px;
transition: opacity 200ms ease-out;
opacity: 1;
user-select: none;
}
.scrying-pool__confirmation-bar--default {
background-color: var(--sp-surface);
border-top: 1px solid var(--sp-border);
color: var(--sp-text-primary);
}
.scrying-pool__confirmation-bar--default .sp-confirmation-bar__message {
color: var(--sp-text-primary);
}
.scrying-pool__confirmation-bar--amber {
background-color: var(--sp-surface);
border-top: 1px solid var(--sp-border-warning);
}
.scrying-pool__confirmation-bar--amber .sp-confirmation-bar__message {
color: var(--sp-text-warning);
}
.scrying-pool .sp-confirmation-bar__message {
flex: 1;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.scrying-pool .sp-confirmation-bar__undo-btn {
background: transparent;
border: none;
padding: 6px 12px;
margin: 0;
cursor: pointer;
font-family: inherit;
font-size: inherit;
font-weight: 600;
text-decoration: none;
color: var(--sp-accent);
border-radius: 4px;
transition: background-color 200ms ease, color 200ms ease;
}
.scrying-pool .sp-confirmation-bar__undo-btn:hover {
background-color: rgba(0, 0, 0, 0.1);
color: var(--sp-accent-emphasis, var(--sp-accent));
}
.scrying-pool .sp-confirmation-bar__undo-btn:active {
background-color: rgba(0, 0, 0, 0.2);
}
.scrying-pool .sp-confirmation-bar__undo-btn:focus {
outline: 2px solid var(--sp-focus);
outline-offset: 2px;
}
.scrying-pool .sp-confirmation-bar__undo-btn:disabled {
opacity: 0.5;
cursor: not-allowed;
}
@keyframes sp-confirmation-bar-slide-up {
from {
opacity: 0;
transform: translateY(100%);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes sp-confirmation-bar-slide-down {
from {
opacity: 1;
transform: translateY(0);
}
to {
opacity: 0;
transform: translateY(100%);
}
}
@media (prefers-reduced-motion: no-preference) {
.scrying-pool__confirmation-bar {
animation: sp-confirmation-bar-slide-up 200ms ease-out;
}
.scrying-pool.is-hiding {
animation: sp-confirmation-bar-slide-down 200ms ease-in forwards;
}
}
@media (prefers-reduced-motion: reduce) {
.scrying-pool__confirmation-bar {
animation: none;
transition: none;
}
}
.scrying-pool.dialog.preset-export,
.scrying-pool.dialog.preset-import {
background: var(--sp-surface);
color: var(--sp-text-primary);
}
.scrying-pool.dialog.preset-export .sp-dialog-content,
.scrying-pool.dialog.preset-import .sp-dialog-content {
padding: var(--sp-space-m);
color: var(--sp-text-primary);
}
.scrying-pool.dialog.preset-export .sp-dialog-buttons,
.scrying-pool.dialog.preset-import .sp-dialog-buttons {
display: flex;
justify-content: flex-end;
gap: var(--sp-space-xs);
padding: var(--sp-space-m);
border-top: 1px solid var(--sp-border);
background: var(--sp-surface);
}
.scrying-pool.dialog.preset-export .sp-export-description,
.scrying-pool.dialog.preset-import .sp-export-description,
.scrying-pool.dialog.preset-export .sp-import-description,
.scrying-pool.dialog.preset-import .sp-import-description {
margin: 0 0 var(--sp-space-m) 0;
color: var(--sp-text-secondary);
line-height: 1.5;
}
.scrying-pool.dialog.preset-export .sp-form-group,
.scrying-pool.dialog.preset-import .sp-form-group {
margin-bottom: var(--sp-space-m);
}
.scrying-pool.dialog.preset-export .sp-form-group:last-child,
.scrying-pool.dialog.preset-import .sp-form-group:last-child {
margin-bottom: 0;
}
.scrying-pool.dialog.preset-export .sp-form-label,
.scrying-pool.dialog.preset-import .sp-form-label {
display: block;
margin-bottom: var(--sp-space-xs);
font-weight: 600;
color: var(--sp-text-primary);
font-size: var(--sp-font-size-sm);
text-transform: uppercase;
letter-spacing: 0.05em;
}
.scrying-pool.dialog.preset-export .sp-export-info,
.scrying-pool.dialog.preset-import .sp-export-info,
.scrying-pool.dialog.preset-export .sp-import-info,
.scrying-pool.dialog.preset-import .sp-import-info {
display: flex;
align-items: center;
gap: var(--sp-space-xs);
margin-bottom: var(--sp-space-xs);
padding: var(--sp-space-xs) var(--sp-space-sm);
background: var(--sp-surface-subtle);
border-radius: var(--sp-radius-sm);
font-size: var(--sp-font-size-sm);
}
.scrying-pool.dialog.preset-export .sp-info-label,
.scrying-pool.dialog.preset-import .sp-info-label {
color: var(--sp-text-secondary);
font-weight: 600;
}
.scrying-pool.dialog.preset-export .sp-info-value,
.scrying-pool.dialog.preset-import .sp-info-value {
color: var(--sp-text-primary);
}
.scrying-pool.dialog.preset-export .sp-filename,
.scrying-pool.dialog.preset-import .sp-filename {
font-family: monospace;
font-size: 0.85em;
word-break: break-all;
}
.scrying-pool.dialog.preset-export .sp-btn,
.scrying-pool.dialog.preset-import .sp-btn {
display: inline-flex;
align-items: center;
justify-content: center;
gap: var(--sp-space-xs);
padding: var(--sp-space-xs) var(--sp-space-m);
border: none;
border-radius: var(--sp-radius-sm);
font-size: var(--sp-font-size-sm);
font-weight: 500;
cursor: pointer;
transition: all 0.15s ease;
}
.scrying-pool.dialog.preset-export .sp-btn:disabled,
.scrying-pool.dialog.preset-import .sp-btn:disabled {
opacity: 0.5;
cursor: not-allowed;
}
.scrying-pool.dialog.preset-export .sp-btn i,
.scrying-pool.dialog.preset-import .sp-btn i {
font-size: 0.9em;
}
.scrying-pool.dialog.preset-export .sp-btn-primary,
.scrying-pool.dialog.preset-import .sp-btn-primary {
background: var(--sp-accent);
color: var(--sp-accent-text);
}
.scrying-pool.dialog.preset-export .sp-btn-primary:hover:not(:disabled),
.scrying-pool.dialog.preset-import .sp-btn-primary:hover:not(:disabled) {
background: var(--sp-accent-hover);
}
.scrying-pool.dialog.preset-export .sp-btn-primary:active:not(:disabled),
.scrying-pool.dialog.preset-import .sp-btn-primary:active:not(:disabled) {
background: var(--sp-accent-active);
}
.scrying-pool.dialog.preset-export .sp-btn-secondary,
.scrying-pool.dialog.preset-import .sp-btn-secondary {
background: var(--sp-surface-subtle);
color: var(--sp-text-primary);
border: 1px solid var(--sp-border);
}
.scrying-pool.dialog.preset-export .sp-btn-secondary:hover:not(:disabled),
.scrying-pool.dialog.preset-import .sp-btn-secondary:hover:not(:disabled) {
background: var(--sp-surface);
}
.scrying-pool.dialog.preset-export .sp-btn-danger,
.scrying-pool.dialog.preset-import .sp-btn-danger {
background: var(--sp-color-red);
color: white;
}
.scrying-pool.dialog.preset-export .sp-btn-danger:hover:not(:disabled),
.scrying-pool.dialog.preset-import .sp-btn-danger:hover:not(:disabled) {
background: var(--sp-color-red-dark);
}
.scrying-pool.dialog.preset-export .sp-file-upload,
.scrying-pool.dialog.preset-import .sp-file-upload {
position: relative;
overflow: hidden;
display: inline-block;
}
.scrying-pool.dialog.preset-export .sp-file-input,
.scrying-pool.dialog.preset-import .sp-file-input {
position: absolute;
left: 0;
top: 0;
opacity: 0;
width: 100%;
height: 100%;
cursor: pointer;
z-index: 2;
pointer-events: none;
}
.scrying-pool.dialog.preset-export .sp-file-label,
.scrying-pool.dialog.preset-import .sp-file-label {
display: inline-flex;
align-items: center;
gap: var(--sp-space-xs);
padding: var(--sp-space-sm) var(--sp-space-m);
background: var(--sp-surface-subtle);
border: 1px dashed var(--sp-border);
border-radius: var(--sp-radius-sm);
cursor: pointer;
color: var(--sp-text-secondary);
transition: all 0.15s ease;
}
.scrying-pool.dialog.preset-export .sp-file-label:hover,
.scrying-pool.dialog.preset-import .sp-file-label:hover {
border-color: var(--sp-accent);
color: var(--sp-accent);
background: var(--sp-surface);
}
.scrying-pool.dialog.preset-export .sp-file-label i,
.scrying-pool.dialog.preset-import .sp-file-label i {
font-size: 1.1em;
}
.scrying-pool.dialog.preset-export .sp-file-selected,
.scrying-pool.dialog.preset-import .sp-file-selected {
display: flex;
align-items: center;
gap: var(--sp-space-xs);
margin-top: var(--sp-space-xs);
padding: var(--sp-space-xs) var(--sp-space-sm);
background: var(--sp-color-green-subtle);
border-radius: var(--sp-radius-sm);
font-size: var(--sp-font-size-sm);
color: var(--sp-color-green);
}
.scrying-pool.dialog.preset-export .sp-file-selected i,
.scrying-pool.dialog.preset-import .sp-file-selected i {
font-size: 0.9em;
}
.scrying-pool.dialog.preset-export .sp-radio-group,
.scrying-pool.dialog.preset-import .sp-radio-group {
display: flex;
flex-direction: column;
gap: var(--sp-space-xs);
}
.scrying-pool.dialog.preset-export .sp-radio-label,
.scrying-pool.dialog.preset-import .sp-radio-label {
display: flex;
align-items: flex-start;
gap: var(--sp-space-sm);
padding: var(--sp-space-xs) var(--sp-space-sm);
border-radius: var(--sp-radius-sm);
cursor: pointer;
transition: background 0.15s ease;
}
.scrying-pool.dialog.preset-export .sp-radio-label:hover,
.scrying-pool.dialog.preset-import .sp-radio-label:hover {
background: var(--sp-surface-subtle);
}
.scrying-pool.dialog.preset-export .sp-radio-label input[type="radio"],
.scrying-pool.dialog.preset-import .sp-radio-label input[type="radio"] {
margin-top: 0.2em;
accent-color: var(--sp-accent);
}
.scrying-pool.dialog.preset-export .sp-radio-label .sp-radio-text,
.scrying-pool.dialog.preset-import .sp-radio-label .sp-radio-text {
font-weight: 500;
color: var(--sp-text-primary);
}
.scrying-pool.dialog.preset-export .sp-radio-label .sp-radio-hint,
.scrying-pool.dialog.preset-import .sp-radio-label .sp-radio-hint {
display: block;
font-size: 0.85em;
color: var(--sp-text-secondary);
margin-top: 0.1em;
}
.scrying-pool.dialog.preset-export .sp-preview-section,
.scrying-pool.dialog.preset-import .sp-preview-section {
margin-top: var(--sp-space-m);
padding-top: var(--sp-space-m);
border-top: 1px solid var(--sp-border);
}
.scrying-pool.dialog.preset-export .sp-preview-title,
.scrying-pool.dialog.preset-import .sp-preview-title {
margin: 0 0 var(--sp-space-sm) 0;
font-size: var(--sp-font-size-sm);
font-weight: 600;
color: var(--sp-text-primary);
text-transform: uppercase;
letter-spacing: 0.05em;
}
.scrying-pool.dialog.preset-export .sp-preview-list,
.scrying-pool.dialog.preset-import .sp-preview-list {
list-style: none;
margin: 0;
padding: 0;
max-height: 200px;
overflow-y: auto;
border: 1px solid var(--sp-border);
border-radius: var(--sp-radius-sm);
background: var(--sp-surface);
}
.scrying-pool.dialog.preset-export .sp-preview-item,
.scrying-pool.dialog.preset-import .sp-preview-item {
display: flex;
align-items: center;
gap: var(--sp-space-sm);
padding: var(--sp-space-xs) var(--sp-space-sm);
border-bottom: 1px solid var(--sp-border-subtle);
}
.scrying-pool.dialog.preset-export .sp-preview-item:last-child,
.scrying-pool.dialog.preset-import .sp-preview-item:last-child {
border-bottom: none;
}
.scrying-pool.dialog.preset-export .sp-preview-item i,
.scrying-pool.dialog.preset-import .sp-preview-item i {
font-size: 0.9em;
flex-shrink: 0;
}
.scrying-pool.dialog.preset-export .sp-preview-item .sp-valid,
.scrying-pool.dialog.preset-import .sp-preview-item .sp-valid {
color: var(--sp-color-green);
}
.scrying-pool.dialog.preset-export .sp-preview-item .sp-invalid,
.scrying-pool.dialog.preset-import .sp-preview-item .sp-invalid {
color: var(--sp-color-red);
}
.scrying-pool.dialog.preset-export .sp-preview-item .sp-preview-name,
.scrying-pool.dialog.preset-import .sp-preview-item .sp-preview-name {
flex-grow: 1;
font-size: var(--sp-font-size-sm);
color: var(--sp-text-primary);
}
.scrying-pool.dialog.preset-export .sp-preview-item .sp-preview-error,
.scrying-pool.dialog.preset-import .sp-preview-item .sp-preview-error {
font-size: 0.8em;
color: var(--sp-color-red);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
max-width: 200px;
}
.scrying-pool.dialog.preset-export .sp-preview-item--invalid,
.scrying-pool.dialog.preset-import .sp-preview-item--invalid {
background: rgba(var(--sp-color-red-rgb), 0.05);
}
.scrying-pool.dialog.preset-export .sp-warning-box,
.scrying-pool.dialog.preset-import .sp-warning-box {
display: flex;
align-items: flex-start;
gap: var(--sp-space-sm);
padding: var(--sp-space-sm);
margin-bottom: var(--sp-space-m);
background: var(--sp-color-yellow-subtle);
border-radius: var(--sp-radius-sm);
color: var(--sp-color-yellow);
font-size: var(--sp-font-size-sm);
}
.scrying-pool.dialog.preset-export .sp-warning-box i,
.scrying-pool.dialog.preset-import .sp-warning-box i {
font-size: 1.1em;
flex-shrink: 0;
margin-top: 0.1em;
}
.scrying-pool.dialog.preset-export .sp-confirmation-section,
.scrying-pool.dialog.preset-import .sp-confirmation-section {
margin-top: var(--sp-space-m);
padding: var(--sp-space-sm);
background: var(--sp-color-red-subtle);
border-radius: var(--sp-radius-sm);
}
.scrying-pool.dialog.preset-export .sp-confirmation-warning,
.scrying-pool.dialog.preset-import .sp-confirmation-warning {
display: flex;
align-items: flex-start;
gap: var(--sp-space-sm);
color: var(--sp-color-red);
font-size: var(--sp-font-size-sm);
font-weight: 500;
}
.scrying-pool.dialog.preset-export .sp-confirmation-warning i,
.scrying-pool.dialog.preset-import .sp-confirmation-warning i {
font-size: 1.1em;
flex-shrink: 0;
margin-top: 0.1em;
}
.scrying-pool.dialog.preset-export .fas.fa-spinner.fa-spin,
.scrying-pool.dialog.preset-import .fas.fa-spinner.fa-spin {
animation: sp-spin 0.8s linear infinite;
}
@keyframes sp-spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
@media (max-width: 768px) {
.scrying-pool.dialog.preset-export,
.scrying-pool.dialog.preset-import {
width: 90vw;
max-width: 500px;
}
.sp-dialog-buttons {
flex-wrap: wrap;
gap: var(--sp-space-sm);
}
.sp-dialog-buttons .sp-btn {
flex: 1 1 100%;
}
}
/**
* Player Privacy Panel styles.
*
* Uses SP (Scrying Pool) semantic token system.
* All colors and spacing come from SP tokens, not Foundry tokens directly.
*/
.scrying-pool .player-privacy-panel {
background: var(--sp-surface);
color: var(--sp-text-primary);
}
.scrying-pool .player-privacy-panel__container {
display: flex;
flex-direction: column;
min-width: 300px;
max-width: 400px;
}
.scrying-pool .player-privacy-panel__header {
padding: var(--sp-spacing-sm, 8px) var(--sp-spacing-md, 12px);
border-bottom: 1px solid var(--sp-border);
background: var(--sp-surface);
}
.scrying-pool .player-privacy-panel__title {
margin: 0;
font-size: 1.1em;
font-weight: 600;
color: var(--sp-text-primary);
text-align: center;
}
.scrying-pool .player-privacy-panel__body {
padding: var(--sp-spacing-md, 12px);
background: var(--sp-surface);
}
.scrying-pool .player-privacy-panel__notice {
padding: var(--sp-spacing-sm, 8px) var(--sp-spacing-md, 12px);
margin-bottom: var(--sp-spacing-md, 12px);
border-radius: var(--sp-border-radius, 4px);
font-size: 0.85em;
text-align: center;
}
.scrying-pool .player-privacy-panel__notice--readonly {
background: var(--sp-urgency-awareness);
color: var(--sp-text-secondary);
border: 1px solid var(--sp-border);
}
.scrying-pool .player-privacy-panel__section {
margin-bottom: var(--sp-spacing-md, 12px);
}
.scrying-pool .player-privacy-panel__section-header {
margin: 0 0 var(--sp-spacing-xs, 4px) 0;
font-size: 0.95em;
font-weight: 600;
color: var(--sp-text-primary);
}
.scrying-pool .player-privacy-panel__section-description {
margin: 0 0 var(--sp-spacing-md, 12px) 0;
font-size: 0.85em;
color: var(--sp-text-secondary);
line-height: 1.4;
}
.scrying-pool .player-privacy-panel__effects-list {
display: flex;
flex-direction: column;
gap: var(--sp-spacing-md, 12px);
}
.scrying-pool .player-privacy-panel__effect {
padding: var(--sp-spacing-sm, 8px);
border: 1px solid var(--sp-border);
border-radius: var(--sp-border-radius, 4px);
background: var(--sp-surface-elevated);
}
.scrying-pool .player-privacy-panel__effect-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: var(--sp-spacing-xs, 4px);
}
.scrying-pool .player-privacy-panel__effect-label {
margin: 0;
font-size: 0.9em;
font-weight: 500;
color: var(--sp-text-primary);
}
.scrying-pool .player-privacy-panel__effect-description {
margin: 0;
font-size: 0.8em;
color: var(--sp-text-secondary);
line-height: 1.4;
}
.scrying-pool .player-privacy-panel__toggle {
display: flex;
align-items: center;
}
.scrying-pool .player-privacy-panel__toggle-label {
display: flex;
align-items: center;
gap: var(--sp-spacing-xs, 4px);
cursor: pointer;
user-select: none;
font-size: 0.85em;
}
.scrying-pool .player-privacy-panel__toggle-input {
position: absolute;
opacity: 0;
width: 0;
height: 0;
}
.scrying-pool .player-privacy-panel__toggle-input:focus-visible + .player-privacy-panel__toggle-text {
outline: 2px solid var(--sp-focus);
outline-offset: 2px;
}
.scrying-pool .player-privacy-panel__toggle-input:disabled + .player-privacy-panel__toggle-text {
opacity: 0.6;
cursor: not-allowed;
}
.scrying-pool .player-privacy-panel__toggle-text {
display: inline-block;
padding: var(--sp-spacing-xs, 4px) var(--sp-spacing-sm, 8px);
border: 1px solid var(--sp-border);
border-radius: var(--sp-border-radius, 4px);
background: var(--sp-surface);
color: var(--sp-text-primary);
font-weight: 500;
transition: all 0.15s ease;
}
.player-privacy-panel__toggle-input:checked + .scrying-pool .player-privacy-panel__toggle-text {
background: var(--sp-accent);
color: white;
border-color: var(--sp-accent);
}
.player-privacy-panel__toggle-input:disabled + .scrying-pool .player-privacy-panel__toggle-text {
background: var(--sp-surface);
border-color: var(--sp-border);
}
.player-privacy-panel__toggle-input:checked:disabled + .scrying-pool .player-privacy-panel__toggle-text {
background: var(--sp-accent);
color: white;
opacity: 0.6;
}
.scrying-pool .player-privacy-panel__portrait-container {
display: flex;
flex-direction: column;
gap: var(--sp-spacing-sm, 8px);
}
.scrying-pool .player-privacy-panel__portrait-preview {
width: 100px;
height: 100px;
border: 2px solid var(--sp-border);
border-radius: var(--sp-border-radius, 4px);
overflow: hidden;
background: var(--sp-surface-elevated);
display: flex;
align-items: center;
justify-content: center;
}
.scrying-pool .player-privacy-panel__portrait-image {
max-width: 100%;
max-height: 100%;
object-fit: cover;
}
.scrying-pool .player-privacy-panel__portrait-actions {
display: flex;
gap: var(--sp-spacing-sm, 8px);
flex-wrap: wrap;
}
.scrying-pool .player-privacy-panel__portrait-choose,
.scrying-pool .player-privacy-panel__portrait-remove {
font-size: 0.85em;
padding: var(--sp-spacing-xs, 4px) var(--sp-spacing-sm, 8px);
}
/*
* VisibilityBadge :root exception
* ─────────────────────────────────────────────────────────────────────────────
* PlayerStatusBadge (FR-22) is mounted directly onto Foundry's AV tile DOM,
* OUTSIDE the .scrying-pool root element. Its state tokens must therefore be
* declared on :root rather than scoped under .scrying-pool.
*
* This is an intentional architectural exception — all other module CSS MUST
* remain scoped under .scrying-pool. Do not add additional :root declarations
* without documenting the architectural reason here.
*
* The badge tokens are a subset of the Layer 2 state tokens declared in
* _states.less, re-exported on :root for badge accessibility outside the root.
*/
:root {
--sp-badge-state-active-bg: var(--sp-state-active-bg);
--sp-badge-state-active-text: var(--sp-state-active-text);
--sp-badge-state-hidden-bg: var(--sp-state-hidden-bg);
--sp-badge-state-hidden-text: var(--sp-state-hidden-text);
--sp-badge-state-self-muted-bg: var(--sp-state-self-muted-bg);
--sp-badge-state-self-muted-text: var(--sp-state-self-muted-text);
--sp-badge-state-offline-bg: var(--sp-state-offline-bg);
--sp-badge-state-offline-text: var(--sp-state-offline-text);
--sp-badge-state-cam-lost-bg: var(--sp-state-cam-lost-bg);
--sp-badge-state-cam-lost-text: var(--sp-state-cam-lost-text);
--sp-badge-state-reconnecting-bg: var(--sp-state-reconnecting-bg);
--sp-badge-state-reconnecting-text: var(--sp-state-reconnecting-text);
/* Badge surface & text (badge mounts outside .scrying-pool root) */
--sp-badge-surface: var(--sp-badge-bg, rgba(0, 0, 0, 0.72));
--sp-badge-color: var(--sp-badge-text, #dde2e8);
}
#av {
display: none !important;
}
.camera-view {
display: none !important;
}