/* ==========================================================================
   sorting-hat.css — THE ONE stylesheet for the Sorting Hat stage.
   Loaded by: sorting-hat-landing.php (/hogwarts-house-picker), the /w/ shared
   page (partials/shared/engine-css.php, 'sorting-hat') and embed-frame.php.

   ⛔ WHY ONE FILE (2026-09-27). The stage rules used to live inline in three
   views as three copies. They drifted: the /w/ copy (style-sorting-hat.php)
   lost its `@keyframes hat-shake {` / `hat-glow-pulse {` wrappers, so the
   keyframe bodies parsed as junk and the hat on every shared sort link never
   moved — measured: 0 hat keyframes in document.styleSheets on /w/. Page-
   specific SIZES stay on each view; everything else lives here.

   The show (harry-potter-engine.js drives it, winner-first):
     idle   — .is-idle      slow sway; every ~6 s, taking turns: .is-twitch (a stretch)
                             and .is-itch (squashes down and wiggles, scratching an itch)
     wake   — .is-hop       squash-and-stretch hop
     think  — JS leans .hat-wrap; .hat-aura cycles the house colours, slowing
     hush   — aura dims, sparks die, the hat stands still
     shout  — .is-shout jolt, .hat-ring burst, [data-house] tint + pennant + name
   prefers-reduced-motion: no transform animation at all (engine also skips
   the particles and the lean; confetti-engine.js already makes none).
   ========================================================================== */

/* ── House inks — one table, three themes ────────────────────────────────
   Light (no data-theme attribute = the site's light state) on the cream card;
   dark on the midnight card. The name is large text
   (≥ 24px), so AA is 3:1 — every ink below clears 4.5:1 anyway. The old inks
   (#8B2E2E · #1a3a6e · #1A472A) read 2.2 · 1.7 · 1.8 : 1 on the dark card. */
.hat-stage-host {
    --hw-ink-gryffindor: #8B2E2E;
    --hw-ink-hufflepuff: #7A5A06;
    --hw-ink-ravenclaw:  #1a3a6e;
    --hw-ink-slytherin:  #1A472A;
    --hw-ink-other:      #7A5A06;
}
body[data-theme="dark"] .hat-stage-host {
    --hw-ink-gryffindor: #E88080;
    --hw-ink-hufflepuff: #F0C840;
    --hw-ink-ravenclaw:  #86ADEB;
    --hw-ink-slytherin:  #6CC495;
    --hw-ink-other:      #E0BE4A;
}
/* ⛔ No high-contrast inks: that theme paints every .card white and forces ALL text
   inside it to #000 with !important (themes.css, `body[data-theme="high-contrast"]
   .card *`), so the house name is black on white there — its intent, measured 21:1.
   Rules here could never apply. */
/* Per-house: ink, the two pennant colours, the aura and the stage tint. */
.hat-stage-host[data-house="gryffindor"] { --hw-ink: var(--hw-ink-gryffindor); --hw-c1: #AE0001; --hw-c2: #EEBA30; --hw-tint: rgba(174, 0, 1, 0.14); }
.hat-stage-host[data-house="hufflepuff"] { --hw-ink: var(--hw-ink-hufflepuff); --hw-c1: #ECB939; --hw-c2: #372E29; --hw-tint: rgba(236, 185, 57, 0.18); }
.hat-stage-host[data-house="ravenclaw"]  { --hw-ink: var(--hw-ink-ravenclaw);  --hw-c1: #222F5B; --hw-c2: #946B2D; --hw-tint: rgba(60, 100, 200, 0.16); }
.hat-stage-host[data-house="slytherin"]  { --hw-ink: var(--hw-ink-slytherin);  --hw-c1: #1A472A; --hw-c2: #AAAAAA; --hw-tint: rgba(42, 130, 70, 0.16); }
.hat-stage-host[data-house="other"]      { --hw-ink: var(--hw-ink-other);      --hw-c1: #C9A227; --hw-c2: #6b2418; --hw-tint: rgba(201, 162, 39, 0.16); }

/* ── The stage-scoped tint (what body.house-* was meant to be — no rule
   anywhere ever matched those body classes). Sits behind everything. */
.hat-stage-host { position: relative; isolation: isolate; }
.hat-stage-host::before {
    content: '';
    position: absolute;
    inset: -8px;
    z-index: -1;
    border-radius: 12px;
    pointer-events: none;
    /* closest-side: the ellipse reaches transparent AT the nearest edge (the top, 42%
       down). With the default farthest-corner it was still ~half strength at the top
       edge, so the shade ended in a hard straight cut there (owner, 2026-09-28). */
    background: radial-gradient(closest-side ellipse at 50% 42%, var(--hw-tint, transparent) 0%, transparent 100%);
    opacity: 0;
    transition: opacity 0.8s ease;
}
.hat-stage-host.is-won::before { opacity: 1; }

/* ── Stage layers ────────────────────────────────────────────────────── */
.hat-stage { position: relative; cursor: pointer; user-select: none; outline: none; }
.hat-stage:focus-visible { outline: 2px solid #C9A227; outline-offset: 6px; border-radius: 12px; }
.hat-stage .hat-wrap {
    position: absolute;
    inset: 0;
    z-index: 2;
    transform-origin: 50% 85%;
    will-change: transform;
}
.hat-stage .hat-wrap > .hat-svg { display: block; }
.hat-stage .hat-aura {
    position: absolute;
    left: 50%;
    top: 55%;
    width: 120%;
    aspect-ratio: 1;
    transform: translate(-50%, -50%);
    border-radius: 50%;
    z-index: 1;
    pointer-events: none;
    background: radial-gradient(circle, var(--hw-aura, rgba(201, 162, 39, 0.5)) 0%, transparent 65%);
    opacity: 0;
    transition: opacity 0.35s ease;
}
.hat-stage .hat-ring {
    position: absolute;
    left: 50%;
    top: 50%;
    width: 60px;
    height: 60px;
    margin: -30px 0 0 -30px;
    border-radius: 50%;
    border: 4px solid var(--hw-c1, #C9A227);
    z-index: 1;
    opacity: 0;
    pointer-events: none;
}
.hat-stage .hat-ring.is-go { animation: hat-ring 0.9s cubic-bezier(0.2, 0.7, 0.3, 1) forwards; }
/* Sparks: a little room above and beside the hat for the rising sparks — no
   longer the old 180px sheet that lay over the card title. */
.hat-stage .hat-particles {
    position: absolute;
    left: -30px;
    top: -40px;
    width: calc(100% + 60px);
    height: calc(100% + 40px);
    z-index: 3;
    pointer-events: none;
}
/* The whispers sit in the gap above the stage. */
.hat-stage .hat-whisper {
    position: absolute;
    left: -40px;
    right: -40px;
    top: -26px;
    z-index: 4;
    text-align: center;
    font-family: Georgia, 'Times New Roman', serif;
    font-style: italic;
    font-size: 0.95rem;
    line-height: 1.3;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    color: var(--theme-muted, #6b5c41);
    opacity: 0;
    transform: translateY(6px);
    transition: opacity 0.35s ease, transform 0.35s ease;
    pointer-events: none;
}
.hat-stage .hat-whisper.is-on { opacity: 1; transform: none; }
/* ⛔ PHONES (owner, 2026-09-28: "fix the whisper overlap on phones"). The whisper lives in the
   gap above the stage and needs ~20px. site.css drops .spin-container's 20px padding to 0 at
   max-width: 576px, which leaves 16px there — measured, the line overlapped the card title by
   4px at 320–576px (36px of room from 577px up). Give the line its room back at that same
   breakpoint. The tool page only: /w/ (same body class, plus .page-shared-wheel) and the
   embed measured clear without it (36px / 24.8px), so they keep their layout. Out-specifies site.css's one class whatever the load order. */
@media (max-width: 576px) {
    body.page-hogwarts-house-picker:not(.page-shared-wheel) .spin-container.hat-stage-host { padding-top: 22px; }
}
body.page-hogwarts-house-picker .hat-stage .hat-whisper { color: #6b5c41; }
body.page-hogwarts-house-picker[data-theme="dark"] .hat-stage .hat-whisper { color: #b9ac8e; }

/* ── Beats ───────────────────────────────────────────────────────────── */
.hat-stage.is-idle .hat-wrap  { animation: hat-sway 4.2s ease-in-out infinite; }
.hat-stage.is-twitch .hat-svg { animation: hat-twitch 0.6s ease-in-out; }
/* the itch squashes onto the brim, so it pivots low — at rest the origin changes nothing */
.hat-stage.is-itch .hat-svg   { transform-origin: 50% 85%; animation: hat-itch 0.95s ease-in-out; }
.hat-stage.is-hop .hat-wrap   { animation: hat-hop 0.42s cubic-bezier(0.3, 0.6, 0.4, 1) forwards; }
.hat-stage.is-shout .hat-wrap { animation: hat-shout 0.55s cubic-bezier(0.2, 1.4, 0.4, 1); }

/* ⭐ NO JUMPS (owner, 2026-09-28: the tip "appears suddenly from another fixed point").
   hat-sway starts and ends at REST, so entering idle after a sort is seamless (it used
   to start at -1.4deg — a visible hop of the tip). hat-hop has NO 0% keyframe: the
   engine pins the hat's live sway pose inline first, and the browser builds the start
   frame from it — so leaving idle mid-sway is seamless too. `forwards` holds the rest
   pose until the engine clears the pin, instead of flashing back to it. */
@keyframes hat-sway   { 0%, 100% { transform: none; } 25% { transform: rotate(-1.4deg); } 75% { transform: rotate(1.6deg) translateY(-3px); } }
@keyframes hat-twitch { 0%, 100% { transform: none; } 30% { transform: skewX(-3deg) scaleY(1.03); } 60% { transform: skewX(2deg); } }
/* owner, 2026-09-28: "make the shrink like its itching". Squash down, scratch side to side
   (fast skews), shake it off with a little stretch, settle. Starts and ends at rest. */
@keyframes hat-itch   { 0%, 100% { transform: none; }
                        14% { transform: scale(1.05, 0.9); }
                        24% { transform: scale(1.05, 0.9) skewX(5deg); }
                        34% { transform: scale(1.05, 0.9) skewX(-5deg); }
                        44% { transform: scale(1.05, 0.9) skewX(4deg); }
                        54% { transform: scale(1.04, 0.91) skewX(-4deg); }
                        64% { transform: scale(1.03, 0.93) skewX(2deg); }
                        80% { transform: scale(0.98, 1.04); } }
@keyframes hat-hop    { 25% { transform: scale(1.08, 0.88); } 55% { transform: translateY(-18px) scale(0.95, 1.07); } 100% { transform: none; } }
@keyframes hat-shout  { 0% { transform: none; } 30% { transform: translateY(-16px) scale(1.07) rotate(-2deg); } 100% { transform: none; } }
@keyframes hat-ring   { 0% { transform: scale(0.4); opacity: 0.9; } 100% { transform: scale(6.5); opacity: 0; border-width: 1px; } }
@keyframes hat-pop    { 0% { opacity: 0; transform: scale(0.55); filter: blur(4px); } 60% { opacity: 1; transform: scale(1.1); filter: blur(0); } 100% { opacity: 1; transform: none; filter: none; } }

/* ── Result — HEIGHT RESERVED, so the reveal moves nothing (§A2).
   Before 2026-09-27 the area was 0px until the name arrived: measured on prod
   the hat rose 10px and the shield row dropped 27px on every sort. The pennant,
   the name and the trait now each own a fixed box whether empty or filled. */
.hat-result-area {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: flex-start;
    gap: 0.25rem;
    margin-top: 0.75rem;
}
.hat-pennant {
    display: flex;
    justify-content: center;
    height: 28px;
    opacity: 0;
    transform: scaleY(0.2);
    transform-origin: top;
    transition: opacity 0.3s ease, transform 0.45s cubic-bezier(0.2, 1.5, 0.4, 1);
}
.hat-pennant > span {
    width: 20px;
    height: 28px;
    clip-path: polygon(0 0, 100% 0, 100% 100%, 50% 78%, 0 100%);
    background: var(--hw-c1, #C9A227);
}
.hat-pennant > span:nth-child(2) { background: var(--hw-c2, #6b2418); }
.hat-stage-host.is-won .hat-pennant { opacity: 1; transform: none; }

.hat-result-name {
    font-family: 'Harry P', Georgia, serif;
    font-size: clamp(1.8rem, 4vw, 2.6rem);
    line-height: 1.25;
    min-height: 1.25em;
    letter-spacing: 0.05em;
    color: var(--hw-ink, #C9A227);
    text-align: center;
    opacity: 0;
}
/* ⚠️ NOT `.visible` — that is a Bootstrap utility (visibility: visible !important),
   and the engine's old class name collided with it. */
.hat-result-name.is-shown { animation: hat-pop 0.6s cubic-bezier(0.2, 1.5, 0.4, 1) forwards; }
.hat-result-trait {
    font-size: 0.88rem;
    font-style: italic;
    line-height: 1.5;
    min-height: 1.5em;
    text-align: center;
    opacity: 0;
    transition: opacity 0.5s ease 0.35s;
}
.hat-result-trait.is-shown { opacity: 1; }

/* ── Reduced motion: no movement, no pops — the name simply fades in. ── */
@media (prefers-reduced-motion: reduce) {
    .hat-stage.is-idle .hat-wrap,
    .hat-stage.is-twitch .hat-svg,
    .hat-stage.is-itch .hat-svg,
    .hat-stage.is-hop .hat-wrap,
    .hat-stage.is-shout .hat-wrap,
    .hat-stage .hat-ring.is-go { animation: none; }
    .hat-pennant { transform: none; transition: opacity 0.4s ease; }
    .hat-result-name.is-shown { animation: none; opacity: 1; transition: opacity 0.5s ease; }
}
