/*
 * Schildwache Captcha by webiate GmbH — Privacy-friendly Proof-of-Work CAPTCHA
 * (c) 2026 webiate GmbH <wasniewski@webiate.de>
 * Source-available commercial license — see LICENSE
 */

:host {
    --schildwache-captcha-bg: #ffffff;
    --schildwache-captcha-fg: #1a1f2b;
    --schildwache-captcha-fg-muted: #5a6478;
    --schildwache-captcha-border: #d6dae3;
    --schildwache-captcha-accent: #1d4ed8;
    --schildwache-captcha-radius: 8px;
    --schildwache-captcha-shadow: 0 1px 2px rgba(15, 23, 42, 0.06), 0 1px 3px rgba(15, 23, 42, 0.04);
    --schildwache-captcha-success: #047857;
    --schildwache-captcha-error: #b91c1c;
    --schildwache-captcha-progress-bg: #e6e9f0;
    --schildwache-captcha-button-bg: #1d4ed8;
    --schildwache-captcha-button-fg: #ffffff;
    --schildwache-captcha-font:
        system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;

    display: inline-block;
    box-sizing: border-box;
    font-family: var(--schildwache-captcha-font);
    font-size: 14px;
    line-height: 1.4;
    color: var(--schildwache-captcha-fg);
    color-scheme: light dark;
}

:host([data-display="block"]),
:host([data-display="block"]) .wc-root {
    display: block;
    width: 100%;
}

/* ──────────────────────────────────────────────────────────────────────
 * Invisible mode — reCAPTCHA-v3-style transparent UX.
 *
 * Widget is rendered but visually hidden. PoW runs eagerly on connect
 * (the component forces data-auto="eager"). Token injection happens
 * normally; the user sees no captcha UI on the happy path.
 *
 * On `failed` or `expired`, CSS auto-reveals the widget so the user can
 * recover. The .is-revealed class is reserved for future programmatic
 * control; integrators can toggle it from outside the shadow DOM via
 * `host.shadowRoot.querySelector('.wc-root').classList.add('is-revealed')`
 * — ::part(root) is also exposed but cannot apply this class from the
 * outside, so JS access is the recommended path. (The component itself
 * does NOT toggle this class today; CSS drives reveal via [data-state].)
 *
 * Important: the widget remains in the accessibility tree, so screen
 * readers still announce status when the state changes. tabindex is
 * controlled by the inner native <button>, not by this rule.
 * ────────────────────────────────────────────────────────────────────── */
:host([data-display="invisible"]) .wc-root {
    position: absolute;
    left: -9999px;
    top: auto;
    width: 1px;
    height: 1px;
    overflow: hidden;
    opacity: 0;
    pointer-events: none;
}

:host([data-display="invisible"]) .wc-root[data-state="failed"],
:host([data-display="invisible"]) .wc-root[data-state="expired"],
:host([data-display="invisible"]) .wc-root.is-revealed {
    position: static;
    left: auto;
    top: auto;
    width: auto;
    height: auto;
    overflow: visible;
    opacity: 1;
    pointer-events: auto;
}

:host *,
:host *::before,
:host *::after {
    box-sizing: border-box;
}

/* --- Dark theme: explicit attribute --- */
:host([data-theme="dark"]),
:host([data-theme-resolved="dark"]) {
    --schildwache-captcha-bg: #0f172a;
    --schildwache-captcha-fg: #f1f5f9;
    --schildwache-captcha-fg-muted: #94a3b8;
    --schildwache-captcha-border: #334155;
    --schildwache-captcha-accent: #60a5fa;
    --schildwache-captcha-success: #34d399;
    --schildwache-captcha-error: #f87171;
    --schildwache-captcha-progress-bg: #1e293b;
    --schildwache-captcha-button-bg: #2563eb;
    --schildwache-captcha-button-fg: #f8fafc;
    --schildwache-captcha-shadow: 0 1px 2px rgba(0, 0, 0, 0.3), 0 1px 3px rgba(0, 0, 0, 0.2);
}

/* --- Auto theme: follow system preference --- */
@media (prefers-color-scheme: dark) {
    :host([data-theme="auto"]),
    :host([data-theme-resolved="auto"]),
    :host(:not([data-theme])) {
        --schildwache-captcha-bg: #0f172a;
        --schildwache-captcha-fg: #f1f5f9;
        --schildwache-captcha-fg-muted: #94a3b8;
        --schildwache-captcha-border: #334155;
        --schildwache-captcha-accent: #60a5fa;
        --schildwache-captcha-success: #34d399;
        --schildwache-captcha-error: #f87171;
        --schildwache-captcha-progress-bg: #1e293b;
        --schildwache-captcha-button-bg: #2563eb;
        --schildwache-captcha-button-fg: #f8fafc;
        --schildwache-captcha-shadow: 0 1px 2px rgba(0, 0, 0, 0.3), 0 1px 3px rgba(0, 0, 0, 0.2);
    }
}

/* --- Layout (reCAPTCHA-style: trigger spans the whole widget) --- */
.wc-root {
    display: grid;
    grid-template-columns: 1fr;
    grid-template-areas:
        "trigger"
        "branding";
    gap: 0.5rem;
    padding: 0.625rem 0.875rem;
    min-width: 16rem;
    max-width: 26rem;
    background: var(--schildwache-captcha-bg);
    color: var(--schildwache-captcha-fg);
    border: 1px solid var(--schildwache-captcha-border);
    border-radius: var(--schildwache-captcha-radius);
    box-shadow: var(--schildwache-captcha-shadow);
    transition: background-color 150ms ease, border-color 150ms ease, box-shadow 150ms ease;
    cursor: pointer;
}

/* In non-interactive states the widget reads as a passive status pill */
.wc-root[data-state="verifying"],
.wc-root[data-state="loading"],
.wc-root[data-state="solved"] {
    cursor: default;
}

/* Hover the WHOLE widget when it's in an interactive state. Disabled
   states (verifying / solved) skip the hover styling — there's nothing
   to click. The hover surface is the entire .wc-root including the
   branding row, but the branding link still has its own cursor:pointer
   and click target so the link behaviour is unchanged. */
.wc-root[data-state="idle"]:hover,
.wc-root[data-state="failed"]:hover,
.wc-root[data-state="expired"]:hover {
    background-color: var(--schildwache-captcha-progress-bg);
    border-color: var(--schildwache-captcha-accent);
}

:host([data-display="block"]) .wc-root {
    max-width: none;
}

.wc-trigger {
    grid-area: trigger;
    /* Native button reset — looks/feels like a row, not a button */
    appearance: none;
    background: transparent;
    border: 0;
    padding: 0;
    margin: 0;
    font: inherit;
    color: inherit;
    text-align: left;
    width: 100%;
    cursor: pointer;
    /* Layout inside the trigger.
       Two-column grid: indicator (auto width) on the left, body on the right.
       Progress bar is grid-column: 1 / -1 so when it's display:block it spans
       the full width on a new row beneath. When display:none it generates no
       row, leaving indicator and status aligned on a single row. */
    display: grid;
    grid-template-columns: auto 1fr;
    align-items: center;
    column-gap: 0.75rem;
    row-gap: 0.25rem;
    border-radius: calc(var(--schildwache-captcha-radius) - 2px);
}

/* Trigger has no own hover background — the whole .wc-root handles
   hover feedback so the entire widget reacts as one surface. */

.wc-trigger:focus-visible {
    outline: 2px solid var(--schildwache-captcha-accent);
    outline-offset: 2px;
}

.wc-trigger:disabled {
    cursor: default;
}

/* On success the trigger is non-interactive. Hover suppression for
   solved/verifying happens at the .wc-root level (no rule lists those
   states), so nothing extra needed here. */
[data-state="solved"] .wc-trigger {
    cursor: default;
}

.wc-indicator {
    width: 1.25rem;
    height: 1.25rem;
    border-radius: 50%;
    background: var(--schildwache-captcha-progress-bg);
    border: 2px solid var(--schildwache-captcha-border);
    flex-shrink: 0;
    position: relative;
    transition: background-color 150ms ease, border-color 150ms ease;
}

.wc-status {
    font-weight: 500;
    color: var(--schildwache-captcha-fg);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.wc-progress {
    grid-column: 1 / -1;
    height: 4px;
    border-radius: 2px;
    background: var(--schildwache-captcha-progress-bg);
    overflow: hidden;
    display: none;
}

[data-state="loading"] .wc-progress,
[data-state="verifying"] .wc-progress {
    display: block;
}

.wc-progress-bar {
    height: 100%;
    background: var(--schildwache-captcha-accent);
    transform-origin: left center;
    transform: scaleX(0);
    transition: transform 120ms ease-out;
    will-change: transform;
}

.wc-branding {
    grid-area: branding;
    justify-self: end;
    display: inline-flex;
    align-items: baseline;
    gap: 0.25em;
    font-size: 0.6875rem;
    color: var(--schildwache-captcha-fg-muted);
    text-decoration: none;
    letter-spacing: 0.01em;
    transition: color 150ms ease;
}

/* Hover/focus underline lives on the text span only so the SVG icon
   sits cleanly to the right without being underlined. */
.wc-branding:hover,
.wc-branding:focus-visible {
    color: var(--schildwache-captcha-accent);
}

.wc-branding:hover .wc-branding-label,
.wc-branding:focus-visible .wc-branding-label {
    text-decoration: underline;
    text-underline-offset: 2px;
}

.wc-branding:focus-visible {
    outline: 2px solid var(--schildwache-captcha-accent);
    outline-offset: 2px;
    border-radius: 2px;
}

.wc-branding-icon {
    flex-shrink: 0;
    /* Optical baseline alignment — the SVG's geometric baseline sits a
       hair below the text x-height, so nudge it up slightly. */
    transform: translateY(1px);
    color: currentColor;
}

/* --- State styling --- */
[data-state="idle"] .wc-indicator {
    background: var(--schildwache-captcha-progress-bg);
    border-color: var(--schildwache-captcha-border);
}

[data-state="loading"] .wc-indicator,
[data-state="verifying"] .wc-indicator {
    background: var(--schildwache-captcha-progress-bg);
    border-color: var(--schildwache-captcha-accent);
    animation: wc-pulse 1.4s ease-in-out infinite;
}

[data-state="solved"] .wc-indicator {
    background: var(--schildwache-captcha-success);
    border-color: var(--schildwache-captcha-success);
}

[data-state="solved"] .wc-indicator::after {
    content: "";
    position: absolute;
    inset: 0;
    background-image: var(--schildwache-captcha-icon-success, url("../Icons/check.svg"));
    background-repeat: no-repeat;
    background-position: center;
    background-size: 80%;
}

[data-state="solved"] .wc-status {
    color: var(--schildwache-captcha-success);
}

[data-state="failed"] .wc-indicator,
[data-state="expired"] .wc-indicator {
    background: var(--schildwache-captcha-error);
    border-color: var(--schildwache-captcha-error);
}

[data-state="failed"] .wc-indicator::after,
[data-state="expired"] .wc-indicator::after {
    content: "";
    position: absolute;
    inset: 0;
    background-image: var(--schildwache-captcha-icon-error, url("../Icons/cross.svg"));
    background-repeat: no-repeat;
    background-position: center;
    background-size: 75%;
}

[data-state="failed"] .wc-status,
[data-state="expired"] .wc-status {
    color: var(--schildwache-captcha-error);
}

@keyframes wc-pulse {
    0%, 100% {
        opacity: 1;
        transform: scale(1);
    }
    50% {
        opacity: 0.6;
        transform: scale(1.08);
    }
}

@media (prefers-reduced-motion: reduce) {
    .wc-indicator,
    .wc-progress-bar,
    .wc-trigger {
        transition: none;
        animation: none !important;
    }
    [data-state="loading"] .wc-indicator,
    [data-state="verifying"] .wc-indicator {
        animation: none;
    }
}

/* --- Forced colors / Windows high contrast --- */
@media (forced-colors: active) {
    .wc-root {
        border: 1px solid CanvasText;
    }
    .wc-indicator {
        forced-color-adjust: none;
        border-color: CanvasText;
    }
    .wc-trigger:focus-visible {
        outline: 2px solid Highlight;
    }
}

/* Compact narrow viewport: layout already stacks via the single-column root,
   no overrides needed. */

/* ──────────────────────────────────────────────────────────────────────
 * Honeypot (light DOM, NOT inside the shadow root).
 *
 * Rendered by every Fluid partial as a sibling of <schildwache-captcha>.
 * Must be invisible to humans and assistive tech, but present in the
 * DOM tree (NOT display:none) so naive scrapers/bots fill it. The
 * server-side validator rejects submissions where this field is non-
 * empty. !important guards against integrator stylesheets that try to
 * style * span / * input — losing visibility here would expose a real
 * input to real users.
 *
 * The component itself never renders a honeypot — that lives in the
 * partials. This CSS rule supports both the partial-rendered honeypot
 * and the optional safety-net honeypot injected by the component when
 * authors hand-write <schildwache-captcha> outside a partial (see
 * component.ts → ensureHoneypotInjected).
 * ────────────────────────────────────────────────────────────────────── */
.schildwache-honeypot {
    position: absolute !important;
    left: -9999px !important;
    top: auto !important;
    width: 1px !important;
    height: 1px !important;
    overflow: hidden !important;
    opacity: 0 !important;
    pointer-events: none !important;
}

/* ──────────────────────────────────────────────────────────────────────
 * No-JS fallback notice.
 *
 * Rendered inside <noscript> in the partials, so it lives in the LIGHT DOM
 * (outside the component's shadow root) and CANNOT read the --schildwache-captcha-*
 * custom properties, which are scoped to :host. It therefore carries its own
 * self-contained palette, with a prefers-color-scheme dark variant. Sized to
 * match the widget (.wc-root: max-width 26rem, same padding, radius and font)
 * so it reads as part of the same control rather than raw browser text.
 * ────────────────────────────────────────────────────────────────────── */
.schildwache-captcha-noscript {
    display: flex;
    align-items: flex-start;
    gap: 0.5rem;
    box-sizing: border-box;
    max-width: 26rem;
    margin: 0;
    padding: 0.625rem 0.875rem;
    font-family:
        system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
    font-size: 14px;
    line-height: 1.4;
    color: #7a4f01;
    background: #fff8eb;
    border: 1px solid #f3d28a;
    border-left: 3px solid #d97706;
    border-radius: 8px;
}

/* Decorative warning glyph; the message text already conveys the meaning,
   so the icon is purely visual and stays out of the accessibility tree. */
.schildwache-captcha-noscript::before {
    content: "\26A0";
    flex: 0 0 auto;
    font-size: 1rem;
    line-height: 1.4;
}

@media (prefers-color-scheme: dark) {
    .schildwache-captcha-noscript {
        color: #fde2a7;
        background: #2a2009;
        border-color: #5c4a1f;
        border-left-color: #f59e0b;
    }
}
