/*
 * Global component classes intended to be usable on plain markup (not just the matching Blazor
 * component), e.g. `<a class="torch-button torch-button--primary">` for a styled CTA link.
 * Scoped .razor.css files (TorchCard, TorchBadge, …) are used for anything only ever rendered
 * through the matching Razor component; button styles live here instead, globally, because raw
 * anchors need the same classes and Blazor's CSS isolation would otherwise scope these rules to
 * elements rendered by TorchButton alone.
 */

/* ---------------------------------------------------------------- buttons */

.torch-button {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--torch-space-2);
    padding: var(--torch-space-2) var(--torch-space-4);
    border-radius: var(--torch-radius-md);
    border: 1px solid transparent;
    font-family: var(--torch-font-body);
    font-size: var(--torch-text-base);
    font-weight: 600;
    line-height: 1.4;
    letter-spacing: 0.01em;
    text-decoration: none;
    white-space: nowrap;
    cursor: pointer;
    transition: background var(--torch-duration-fast) var(--torch-ease-out),
        border-color var(--torch-duration-fast) var(--torch-ease-out),
        color var(--torch-duration-fast) var(--torch-ease-out),
        box-shadow var(--torch-duration-fast) var(--torch-ease-out),
        transform var(--torch-duration-fast) var(--torch-ease-out);
}

.torch-button:disabled,
.torch-button[aria-disabled="true"] {
    opacity: 0.45;
    cursor: not-allowed;
    transform: none;
    box-shadow: none;
}

/*
 * The primary action is a forged plate, not a gold swatch. An earlier pass filled it with the
 * accent at full strength and finished it with a white inset highlight and a permanent glow,
 * which read as plastic for four reasons worth recording so they do not come back:
 *
 *  - A white specular is light from a source that exists nowhere else in this product. The only
 *    warm light in the hero art is torch fire, and it is dim and orange.
 *  - A two-stop light-to-dark ramp is the canonical glossy-button cliche. Metal has a reflectance
 *    curve, not a linear one.
 *  - With no border, a saturated fill sits *on* the hero photograph like a sticker instead of *in*
 *    the scene.
 *  - An ambient halo (the old --torch-shadow-glow at rest) makes a control look backlit.
 *
 * So the plate is cut from the tower's own material and gold goes back to being an accent — the
 * rim, the label, and a low heat bloom rising from the bottom edge, as if lit by the same embers
 * as the scene behind it. Hover heats the metal rather than lightening it uniformly. This also
 * settles the contradiction where components.css was spending the accent as a full fill while
 * tokens.css called for it "used sparingly".
 */
.torch-button--primary {
    background: var(--torch-plate-face);
    color: var(--torch-plate-label);
    border-color: var(--torch-plate-rim);
    text-shadow: 0 0 16px rgba(224, 160, 80, 0.4);
    box-shadow: var(--torch-plate-shadow);
}

.torch-button--primary:not(:disabled):hover {
    background: var(--torch-plate-face-hot);
    border-color: var(--torch-plate-rim-hot);
    color: var(--torch-plate-label-hot);
    box-shadow: var(--torch-plate-shadow-hot);
    transform: translateY(-1px);
}

/* The plate carries far less luminance than the old gold fill did, so the shared 0.45 opacity
   would sink a disabled primary into the surface behind it. Kill the heat instead: an unlit,
   flat plate reads as inert without becoming invisible. */
.torch-button--primary:disabled,
.torch-button--primary[aria-disabled="true"] {
    opacity: 1;
    background: linear-gradient(180deg, #232120 0%, #1a1817 100%);
    color: #6d6455;
    border-color: #332d24;
    text-shadow: none;
    box-shadow: inset 0 1px 0 rgba(255, 221, 163, 0.05);
}

/* The same correction as the primary, one step quieter: a flat matte face and a chiselled groove
   instead of a light-to-dark ramp under a white specular. This is the control that read most
   plainly as "grey web button" — it is stone now, and the rim is the only thing that warms. */
.torch-button--secondary {
    background-color: var(--torch-surface-2);
    color: var(--torch-text-primary);
    border-color: var(--torch-border);
    box-shadow: var(--torch-shadow-sm), var(--torch-chisel);
}

.torch-button--secondary:not(:disabled):hover {
    background-color: var(--torch-surface-3);
    border-color: var(--torch-border-strong);
    color: var(--torch-text-primary);
    box-shadow: var(--torch-shadow-md), var(--torch-chisel);
    transform: translateY(-1px);
}

.torch-button--ghost {
    background: transparent;
    color: var(--torch-text-secondary);
}

.torch-button--ghost:not(:disabled):hover {
    color: var(--torch-text-primary);
    background: rgba(255, 235, 205, 0.06);
}

.torch-button--danger {
    background: transparent;
    color: var(--torch-danger);
    border-color: var(--torch-danger);
}

.torch-button--danger:not(:disabled):hover {
    background: var(--torch-danger);
    color: var(--torch-text-primary);
}

.torch-button:not(:disabled):active {
    transform: translateY(0) scale(0.985);
}

/*
 * The one CTA on a full-bleed cinematic scene. It is looked at long before it is read, so it
 * needs stance more than it needs decoration: a wide minimum width so a four-letter Czech verb
 * still occupies the centre of the composition, generous padding, and the display face tracked
 * out far enough to read as a legend stamped into the plate rather than as a word in a box.
 *
 * The inner rim is the one addition beyond size — a real forged fitting has a bevel set in from
 * its edge, and a single hairline at `inset: 3px` is enough to imply the thickness of the metal.
 * Deliberately *not* added: any resting glow. See the note on .torch-button--primary above; a
 * halo at rest reads as backlit plastic, and making the hero button bigger does not change that.
 */
.torch-button--hero {
    position: relative;
    min-width: 13rem;
    padding: var(--torch-space-4) var(--torch-space-12);
    font-family: var(--torch-font-display);
    font-size: var(--torch-text-md);
    letter-spacing: 0.14em;
    text-transform: uppercase;
}

.torch-button--hero::before {
    content: "";
    position: absolute;
    inset: 3px;
    border: 1px solid rgba(224, 180, 99, 0.16);
    border-radius: calc(var(--torch-radius-md) - 2px);
    pointer-events: none;
    transition: border-color var(--torch-duration-fast) var(--torch-ease-out);
}

.torch-button--hero:not(:disabled):hover::before {
    border-color: rgba(240, 205, 140, 0.3);
}

.torch-button--hero:disabled::before,
.torch-button--hero[aria-disabled="true"]::before {
    border-color: rgba(224, 180, 99, 0.06);
}

/* ---------------------------------------------------------------- prose */

/*
 * Rendered Markdown (news post bodies, via Markdig -> MarkupString) is injected as raw HTML,
 * which Blazor's CSS scoping cannot see or stamp with a scope attribute — style it globally via
 * this wrapper class instead of a page-scoped .razor.css rule, which would silently never match.
 */
.torch-markdown {
    color: var(--torch-text-secondary);
    line-height: var(--torch-leading-body);
}

.torch-markdown > *:first-child {
    margin-top: 0;
}

.torch-markdown > *:last-child {
    margin-bottom: 0;
}

.torch-markdown h1,
.torch-markdown h2,
.torch-markdown h3 {
    font-size: var(--torch-text-md);
    color: var(--torch-text-primary);
    margin: var(--torch-space-6) 0 var(--torch-space-2);
}

.torch-markdown a {
    color: var(--torch-accent-strong);
}

.torch-markdown blockquote {
    margin: var(--torch-space-4) 0;
    padding-left: var(--torch-space-4);
    border-left: 2px solid var(--torch-accent-muted);
    color: var(--torch-text-muted);
}

.torch-markdown pre {
    background: var(--torch-surface-2);
    border: 1px solid var(--torch-border);
    border-radius: var(--torch-radius-sm);
    padding: var(--torch-space-3);
    overflow-x: auto;
}

.torch-markdown img {
    border-radius: var(--torch-radius-md);
    border: 1px solid var(--torch-border);
}

/* ---------------------------------------------------------------- scene effects */

/*
 * Shared full-bleed scene effects (hero background pan, glowing logo) — reused by both the
 * landing hero and the Unity WebGL loading overlay, so they live here globally rather than
 * duplicated per page.
 */
@keyframes torch-bg-pan {
    0% {
        transform: scale(1.08) translate(0, 0);
    }

    50% {
        transform: scale(1.17) translate(-1.5%, -1%);
    }

    100% {
        transform: scale(1.08) translate(0, 0);
    }
}

.torch-bg-pan {
    animation: torch-bg-pan 52s ease-in-out infinite;
}

/* Faster pace for the Unity WebGL loading screen — it's a short-lived overlay, not a page
   background, so the original (livelier) speed still applies here. */
.torch-splash-bg-pan {
    animation: torch-bg-pan 26s ease-in-out infinite;
}

/*
 * Dialled back to roughly half its original strength. The rising embers are what should carry the
 * heat in a hero — they move, they are physical, and they are the same fire as the scene. A halo
 * baked around the wordmark competes with them for the same job while staying perfectly still,
 * and at the old values it won, flattening the particles into background noise.
 *
 * Kept rather than removed: at this strength it reads as the mark being lit *by* the embers
 * instead of emitting on its own.
 */
@keyframes torch-logo-glow {

    0%,
    100% {
        filter: drop-shadow(0 0 7px rgba(255, 148, 64, 0.22)) drop-shadow(0 0 16px rgba(255, 100, 40, 0.12));
        transform: scale(1);
    }

    50% {
        filter: drop-shadow(0 0 11px rgba(255, 160, 74, 0.32)) drop-shadow(0 0 22px rgba(255, 108, 42, 0.18));
        transform: scale(1.008);
    }
}

.torch-logo-glow {
    animation: torch-logo-glow 5.5s ease-in-out infinite;
}

@keyframes torch-progress-shimmer {
    0% {
        transform: translateX(-60%) skewX(-12deg);
    }

    100% {
        transform: translateX(220%) skewX(-12deg);
    }
}

.torch-progress-shimmer {
    animation: torch-progress-shimmer 1.8s linear infinite;
}

@keyframes torch-tip-fade {
    0% {
        opacity: 0;
        transform: translateY(4px);
    }

    12% {
        opacity: 1;
        transform: translateY(0);
    }

    85% {
        opacity: 1;
        transform: translateY(0);
    }

    100% {
        opacity: 0;
        transform: translateY(-4px);
    }
}

.torch-tip-fade {
    animation: torch-tip-fade 3.2s ease-in-out;
}

/*
 * Hero entrance: each element rises into place in turn instead of the whole block appearing at
 * once. Choreography is most of what separates a game landing page from a web page — the eye is
 * led logo -> promise -> action rather than handed all three simultaneously.
 *
 * `both` fill mode is load-bearing twice: it holds the pre-state through the delay (without it
 * every element flashes at full opacity before its turn), and it leaves the final state applied
 * after the animation ends. Delay comes from a custom property so the order lives in the markup,
 * next to the elements it sequences, rather than as nth-child rules that break when an
 * <AuthorizeView> branch changes the child count.
 *
 * Under prefers-reduced-motion the shared reset in base.css collapses both the duration and the
 * delay, so everything lands immediately at its final state rather than staying invisible for
 * the length of a delay that no longer has an animation behind it.
 */
@keyframes torch-rise-in {
    from {
        opacity: 0;
        transform: translateY(14px);
    }

    to {
        opacity: 1;
        transform: none;
    }
}

.torch-rise {
    animation: torch-rise-in var(--torch-duration-slow) var(--torch-ease-out) both;
    animation-delay: var(--torch-rise-delay, 0ms);
}

/* ---------------------------------------------------------------- accent panel */

/*
 * A feature panel: raised a step above the page, lit faintly from above, and carrying the
 * geometric texture. This is the *only* place the pattern appears. Persistent chrome — the site
 * header, the footer, the admin app bar — stays a flat surface with a hairline, because a
 * texture that is always on stops reading as an accent and starts reading as wallpaper.
 *
 * `background-attachment: fixed` ties the tile grid to the viewport rather than to each
 * element's own box, so two textured panels on one page show two windows onto a single
 * continuous backdrop instead of two independently-tiled patches that seam at their edges.
 */
.torch-panel {
    position: relative;
    background-color: var(--torch-surface-1);
    border-top: 1px solid var(--torch-border);
    border-bottom: 1px solid var(--torch-border);
    box-shadow: inset 0 1px 0 rgba(255, 235, 205, 0.045), inset 0 -1px 0 rgba(0, 0, 0, 0.35);
}

.torch-textured {
    background-image: url("../images/pattern-geometric.svg");
    background-repeat: repeat;
    background-size: 480px 480px;
    background-position: center;
    background-attachment: fixed;
}

/*
 * Vignette over the texture so the pattern is strongest at the panel's centre and fades out
 * before its edges — without it, tiles get visibly cut by the panel border and the whole thing
 * reads as a cropped wallpaper rather than as material catching the light.
 */
.torch-panel.torch-textured::before {
    content: "";
    position: absolute;
    inset: 0;
    pointer-events: none;
    background: radial-gradient(120% 80% at 50% 50%,
            transparent 0%,
            transparent 45%,
            var(--torch-surface-1) 100%);
}

.torch-panel > * {
    position: relative;
}

/* ---------------------------------------------------------------- flanked ornaments */

/*
 * One ornament in three volumes — a centred element with hairlines growing out to fill the
 * remaining width on both sides, echoing the divider under the wordmark in the Torch logo:
 *
 *   .torch-section-heading  loud    an <h2> in display type, flanked by diamonds
 *   .torch-rule             quiet   the bare ornament, no label (the hero's breath mark)
 *   .torch-rule-link        quiet   a small tracked link where the heading would be
 *
 * Geometry and flank colour are shared here so the three always read as one family; each class
 * only overrides its own scale and loudness below. `--torch-rule-flank` is a custom property so
 * a hover state can warm the hairlines without restating the gradients.
 */
.torch-section-heading,
.torch-rule,
.torch-rule-link {
    --torch-rule-flank: var(--torch-border-strong);
    --torch-rule-flank-max: 12rem;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--torch-space-4);
}

.torch-section-heading::before,
.torch-section-heading::after,
.torch-rule::before,
.torch-rule::after,
.torch-rule-link::before,
.torch-rule-link::after {
    content: "";
    flex: 1 1 auto;
    height: 1px;
    max-width: var(--torch-rule-flank-max);
    background: linear-gradient(90deg, transparent, var(--torch-rule-flank));
    transition: background var(--torch-duration-fast) var(--torch-ease-out);
}

.torch-section-heading::after,
.torch-rule::after,
.torch-rule-link::after {
    background: linear-gradient(90deg, var(--torch-rule-flank), transparent);
}

/*
 * The diamond sits on *both* flanks. It was originally a lead-in mark on the left only, which
 * left the composition off-balance now that hairlines run to both sides — and the logo's own
 * divider is symmetric, so the ornament this echoes was symmetric all along.
 */
.torch-section-heading__diamond,
.torch-rule__diamond {
    flex: 0 0 auto;
    width: 0.5rem;
    height: 0.5rem;
    background: var(--torch-accent);
    box-shadow: 0 0 10px rgba(201, 151, 63, 0.55);
    transform: rotate(45deg);
}

.torch-section-heading {
    margin-bottom: var(--torch-space-8);
}

.torch-section-heading h2 {
    flex: 0 0 auto;
    margin: 0;
}

/* The hero's breath mark between the tagline and the call to action: shorter flanks, a smaller
   and cooler diamond. It separates two lines of copy, so it must not outshine either. */
.torch-rule {
    --torch-rule-flank: var(--torch-border);
    --torch-rule-flank-max: 4.5rem;
    gap: var(--torch-space-3);
}

.torch-rule__diamond {
    width: 0.375rem;
    height: 0.375rem;
    background: var(--torch-accent-muted);
    box-shadow: 0 0 8px rgba(201, 151, 63, 0.35);
}

/*
 * The quiet sibling of .torch-section-heading: the same flanked composition, but the label is a
 * small tracked link rather than a display heading, and it carries no diamond — the diamonds
 * belong to the heading that opens the section, and repeating them at the foot would close it
 * with equal weight. A filled button here competed with the hero CTA for the same attention
 * while doing far less work; this reads as a way onward, not as a second call to action.
 */
.torch-rule-link {
    --torch-rule-flank-max: 8rem;
    font-family: var(--torch-font-display);
    font-size: var(--torch-text-xs);
    font-weight: 600;
    letter-spacing: var(--torch-tracking-eyebrow);
    text-transform: uppercase;
    color: var(--torch-text-muted);
    text-decoration: none;
    transition: color var(--torch-duration-fast) var(--torch-ease-out);
}

.torch-rule-link:hover {
    --torch-rule-flank: var(--torch-accent-muted);
    color: var(--torch-accent-strong);
}

/* The global :focus-visible ring is drawn on the element's own box, which for a full-width flex
   ornament is a letterbox spanning the column. Offset it back onto the label instead. */
.torch-rule-link:focus-visible {
    box-shadow: none;
    outline: 2px solid var(--torch-accent);
    outline-offset: var(--torch-space-2);
}

/* An all-caps, wide-tracked label above a heading. Used on status pages, section intros and the
   admin page header. */
.torch-eyebrow {
    font-family: var(--torch-font-display);
    font-size: var(--torch-text-xs);
    font-weight: 600;
    letter-spacing: var(--torch-tracking-eyebrow);
    text-transform: uppercase;
    color: var(--torch-accent);
    margin: 0 0 var(--torch-space-2);
}
