/*
 * Visual (background) theme layer — Phase 11, layer 2 of the two-layer
 * theme system. Completely independent of the color theme (tokens.css /
 * ThemeService::activeCssVariables()): this file only ever sets
 * `--visual-*` variables and the decorative layer elements below. It never
 * sets `--primary` or any other color-theme variable, and nothing in
 * tokens.css/components.css/layout.css depends on `data-visual-theme` —
 * that is what keeps the two axes independent instead of exploding into
 * 8 x 4 combination stylesheets (see ThemeService's class docblock).
 *
 * Markup contract (see layouts/app.php, auth.php, public.php — NOT
 * print.php, which never carries a decorative background at all):
 *
 *   <body data-visual-theme="batik" data-visual-intensity="subtle">
 *     <div class="theme-background" aria-hidden="true"></div>
 *     <div class="theme-overlay" aria-hidden="true"></div>
 *     <div class="app-shell"> ... real content ... </div>
 *   </body>
 *
 * `.theme-background`/`.theme-overlay` are `position: fixed`, behind
 * everything (z-index 0) and `pointer-events: none` — they can never
 * intercept a click/tap/keyboard focus, and `aria-hidden="true"` keeps
 * assistive technology from ever announcing them. Every actual content
 * container in this app (.sidebar, .topbar, .card, .official-paper,
 * .auth-card, ...) already has its own solid background (tokens.css), so
 * the pattern can only ever be visible in the page's own margins/gutters —
 * never behind readable text (Bagian 9/18).
 *
 * The SAME `[data-visual-theme="…"] .theme-background` rules below also
 * apply, unmodified, to `.visual-preview-bg` inside a small
 * `[data-visual-theme]` swatch on the appearance settings page (Bagian
 * 13/16) — only the positioning differs (fixed+viewport vs
 * absolute+small-box), so the picker preview is pixel-for-pixel the same
 * pattern/tint/density the page itself will show, never a guess.
 */

.theme-background,
.theme-overlay,
.visual-preview-bg {
    pointer-events: none;
}

.theme-background,
.theme-overlay {
    position: fixed;
    inset: 0;
    z-index: 0;
}

.theme-background,
.visual-preview-bg {
    background-repeat: repeat;
    transition: opacity var(--duration-slow, 300ms) var(--ease-standard, ease);
}
.theme-background { opacity: calc(var(--visual-opacity, 0) * var(--visual-intensity, 0.35)); }
/* The preview swatch always renders at full strength (intensity 1) — its
   whole job is showing what the pattern itself looks like, independent of
   whichever page-context intensity happens to be selected elsewhere. */
.visual-preview-bg { position: absolute; inset: 0; opacity: var(--visual-opacity, 0); }

.theme-overlay {
    background: var(--background);
    opacity: calc(var(--visual-overlay-opacity, 0) * var(--visual-intensity, 0.35));
}

/* Real content always sits above the two decorative layers. */
.app-shell,
.auth-shell,
.public-shell {
    position: relative;
    z-index: 1;
}

/* ---------- Visual themes ----------
   Deliberately scoped to `body[data-visual-theme="…"]` (the real page) and
   `.visual-preview[data-visual-theme="…"] > .visual-preview-bg` (one static
   swatch on the appearance picker) as two SEPARATE, non-overlapping
   selector families — not a generic `[data-visual-theme="…"] .foo`
   descendant selector. The picker's live preview works by changing
   `data-visual-theme` on <body> itself (see app.js), and since every swatch
   card also carries its OWN fixed `data-visual-theme` a few levels further
   down the very same <body>, a plain descendant selector would match a
   swatch through EITHER ancestor and let the live-previewed theme bleed
   into every other swatch's static preview. Keeping the two prefixes
   distinct (tag+attribute vs class+attribute) makes that impossible: only
   <body> can ever match `body[data-visual-theme]`, and CSS custom
   properties set directly on a `.visual-preview` element always win over
   one merely inherited from an ancestor such as <body>. */

/* Minimal (default): no pattern, no overlay — plain neutral surface. */
body[data-visual-theme="minimal"] .theme-background,
.visual-preview[data-visual-theme="minimal"] > .visual-preview-bg { background-image: none; }
body[data-visual-theme="minimal"],
.visual-preview[data-visual-theme="minimal"] { --visual-opacity: 0; --visual-overlay-opacity: 0; }

/* Batik Nusantara: original kawung-inspired geometric abstraction (see
   patterns/batik-kawung.svg's own docblock), recolored to the ACTIVE color
   theme's primary via a CSS mask rather than shipping 8 pre-tinted copies. */
body[data-visual-theme="batik"] .theme-background,
.visual-preview[data-visual-theme="batik"] > .visual-preview-bg {
    background-color: var(--primary);
    background-image: none;
    -webkit-mask-image: url('../img/patterns/batik-kawung.svg');
    mask-image: url('../img/patterns/batik-kawung.svg');
    -webkit-mask-repeat: repeat;
    mask-repeat: repeat;
    -webkit-mask-size: 80px 80px;
    mask-size: 80px 80px;
}
body[data-visual-theme="batik"],
.visual-preview[data-visual-theme="batik"] { --visual-opacity: 0.07; --visual-overlay-opacity: 0.7; }

/* Merah Putih: fixed red/white identity, independent of the color theme
   (see patterns/merah-putih.svg's own docblock — an abstract fabric-like
   motif, never a flag graphic). */
body[data-visual-theme="merah-putih"] .theme-background,
.visual-preview[data-visual-theme="merah-putih"] > .visual-preview-bg {
    background-image: url('../img/patterns/merah-putih.svg');
    background-size: 120px 120px;
}
body[data-visual-theme="merah-putih"],
.visual-preview[data-visual-theme="merah-putih"] { --visual-opacity: 0.6; --visual-overlay-opacity: 0.55; }

/* Nusantara: original tumpal-inspired geometric abstraction, also
   color-theme-tinted the same way as Batik. */
body[data-visual-theme="nusantara"] .theme-background,
.visual-preview[data-visual-theme="nusantara"] > .visual-preview-bg {
    background-color: var(--primary);
    background-image: none;
    -webkit-mask-image: url('../img/patterns/nusantara-tumpal.svg');
    mask-image: url('../img/patterns/nusantara-tumpal.svg');
    -webkit-mask-repeat: repeat;
    mask-repeat: repeat;
    -webkit-mask-size: 60px 60px;
    mask-size: 60px 60px;
}
body[data-visual-theme="nusantara"],
.visual-preview[data-visual-theme="nusantara"] { --visual-opacity: 0.09; --visual-overlay-opacity: 0.65; }

/* ---------- Page-specific intensity (Bagian 17) ----------
   Set by each layout via `data-visual-intensity` on <body> (views can
   override the default per layout by setting $pageVisualIntensity before
   `$this->extend(...)`, same convention as $pageTitle/$activeMenu). The
   voting flow in particular stays at "minimal" so a background pattern can
   never compete with candidate recognition (Bagian 18/36). */
body[data-visual-intensity="strong"]  { --visual-intensity: 1; }
body[data-visual-intensity="medium"]  { --visual-intensity: 0.6; }
body[data-visual-intensity="subtle"]  { --visual-intensity: 0.35; }
body[data-visual-intensity="minimal"] { --visual-intensity: 0.15; }
body[data-visual-intensity="none"]    { --visual-intensity: 0; }

/* ---------- Appearance settings: visual theme picker ---------- */
.visual-theme-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(11rem, 1fr));
    gap: var(--space-3);
}
.visual-swatch { position: relative; display: block; cursor: pointer; }
.visual-swatch input { position: absolute; opacity: 0; }
.visual-swatch-card {
    display: block;
    border: 2px solid var(--border);
    border-radius: var(--radius-md);
    overflow: hidden;
    transition: border-color var(--duration-fast) var(--ease-standard), box-shadow var(--duration-fast) var(--ease-standard);
}
.visual-swatch input:checked + .visual-swatch-card {
    border-color: var(--primary);
    box-shadow: 0 0 0 3px var(--primary-soft);
}
.visual-swatch input:focus-visible + .visual-swatch-card { outline: 3px solid var(--focus); outline-offset: 2px; }
.visual-preview {
    position: relative;
    height: 4.5rem;
    background: var(--surface-alt);
    border-bottom: 1px solid var(--border);
    overflow: hidden;
}
.visual-swatch-body { padding: var(--space-2) var(--space-3) var(--space-3); }
.visual-swatch-name {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    font-size: var(--text-sm);
    font-weight: var(--font-semibold);
    color: var(--text);
}
/* Selected state is never color-only (Bagian 16/28): a checkmark word,
   not just a colored border, appears once chosen. */
.visual-swatch-selected { display: none; font-size: var(--text-xs); font-weight: var(--font-medium); color: var(--primary); }
.visual-swatch input:checked ~ .visual-swatch-card .visual-swatch-selected { display: inline; }
.visual-swatch-desc { display: block; margin-top: 2px; font-size: var(--text-xs); color: var(--text-muted); }

/* Reduced motion (Bagian 21): the layers are static already (no keyframes,
   no background-position animation) — this only removes the fade used when
   JS live-previews a different visual theme on the appearance page. */
@media (prefers-reduced-motion: reduce) {
    .theme-background,
    .visual-preview-bg { transition: none; }
}

/* Print (Bagian 24): never waste ink on a decorative background, and never
   let one interfere with an official, formal document. */
@media print {
    .theme-background,
    .theme-overlay {
        display: none !important;
    }
}
