/* =====================================================================
 * Tutorials — the video series index.
 *
 * Hero archetype (§8.1) opening into an editorial shelf list, the same
 * shape /downloads uses. One stage carries the page, so the type above
 * it is deliberately short and its vertical padding deliberately tight:
 * the player, not the headline, is what has to clear the fold.
 *
 * All colour flows from design tokens, and the aura is the page's single
 * iridescent moment (DESIGN.md §1), built from the brand RGB twins. Two
 * literals survive on purpose, both of them sitting ON media rather than
 * on a surface: the duration badge (stage.css's recipe verbatim — it
 * rides a photograph, so it must not swap with the theme) and the black
 * behind a mounted player. Korean keep-all throughout; motion mirrors
 * downloads.css and honours prefers-reduced-motion.
 * ===================================================================== */

/* Collapse the centered content wrapper so the page bleeds full-width,
   matching the About / Downloads long-form archetype. */
#wrapper-contents:has(#tutorials-page) {
    padding: 0;
    margin: 0;
    display: block;
    float: none;
    align-items: initial;
    justify-content: initial;
    background-color: var(--global-body-background);
    overflow-x: clip;
}

#tutorials-page {
    --tu-ease: cubic-bezier(0.22, 0.61, 0.36, 1);
    --tu-ease-spring: cubic-bezier(0.16, 1, 0.3, 1);
    --tu-pad-x: clamp(20px, 5vw, 80px);
    --tu-content-max: 1080px;

    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: clamp(28px, 4vh, 44px);
    width: 100%;
    min-height: calc(100vh - var(--header-height) - var(--footer-height));
    /* The shell's `margin-top: var(--header-height)` is dropped by the opt-out
       above (the aura has to bleed under the translucent header), so the page
       owns its own clearance. Downloads gets away with not saying this because
       its hero padding alone is 64-128px; ours is deliberately a third of that
       — every pixel here is a pixel of the player pushed below the fold — and
       32px is LESS than the 47px header, which put the eyebrow underneath it. */
    padding: calc(var(--header-height) + clamp(24px, 3.4vh, 40px))
             var(--tu-pad-x)
             clamp(72px, 12vh, 140px);
    box-sizing: border-box;
    color: var(--global-text-color);
    font-family: 'Pretendard Variable', Pretendard, -apple-system, BlinkMacSystemFont, system-ui, sans-serif;
    overflow-x: clip;
    word-break: keep-all;
    overflow-wrap: anywhere;
    isolation: isolate;
}

/* ---------- Jewel aura — §2.4 recipe, ending above the stage ---------- */
.tu-aura {
    position: absolute;
    inset: 0 0 auto 0;
    height: 62vh;
    z-index: -1;
    pointer-events: none;
    background:
        radial-gradient(38% 48% at 22% 30%, rgba(var(--brand-iris-rgb),     0.16), transparent 70%),
        radial-gradient(34% 42% at 78% 22%, rgba(var(--brand-mulberry-rgb), 0.13), transparent 72%),
        radial-gradient(40% 46% at 62% 72%, rgba(var(--brand-lichen-rgb),   0.13), transparent 70%),
        radial-gradient(36% 40% at 18% 78%, rgba(var(--brand-brass-rgb),    0.11), transparent 72%);
    filter: blur(76px) saturate(104%);
    opacity: 0.58;
    animation: tu-aura-drift 26s ease-in-out infinite alternate;
}
@keyframes tu-aura-drift {
    0%   { transform: translate3d(-3%, -2%, 0) scale(1); }
    100% { transform: translate3d( 3%,  1%, 0) scale(1.05); }
}

/* Shared quiet link — the only interactive text on the page (§3.4). */
.tu-cue {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-size: 13px;
    font-weight: 500;
    letter-spacing: -0.005em;
    color: var(--global-text-muted);
    text-decoration: none;
    transition: color 0.3s var(--tu-ease), gap 0.3s var(--tu-ease-spring);
}
.tu-cue::after { content: '→'; font-size: 12px; }
.tu-cue:hover { color: var(--global-text-color); gap: 10px; }
.tu-cue:focus-visible { outline: 2px solid var(--focus-outline-color); outline-offset: 3px; border-radius: 4px; }
.tu-cue[target='_blank']::after { content: '↗'; }

/* =====================================================================
 * 01 · MARQUEE
 * ===================================================================== */
.tu-marquee {
    position: relative;
    z-index: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: clamp(10px, 1.4vh, 16px);
    max-width: 720px;
    text-align: center;
}
.tu-eyebrow {
    margin: 0;
    font-size: 13px;
    font-weight: 500;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    color: var(--global-text-color);
    line-height: 1;
}
.tu-title {
    margin: 0;
    font-size: clamp(28px, 4vw, 44px);
    font-weight: 800;
    letter-spacing: -0.028em;
    line-height: 1.1;
}
/* The most persuasive line on the page: how much there is, and therefore
   that it can be finished. Tabular figures so it does not shimmer. */
.tu-stat {
    margin: 0;
    font-size: 13px;
    font-weight: 500;
    font-variant-numeric: tabular-nums;
    letter-spacing: -0.005em;
    color: var(--global-text-color);
}
.tu-note {
    margin: 0;
    max-width: 44ch;
    font-size: 13px;
    line-height: 1.7;
    letter-spacing: -0.005em;
    color: var(--global-text-muted);
}

/* =====================================================================
 * 02 · STAGE
 * ===================================================================== */
.tu-stage {
    position: relative;
    z-index: 1;
    width: 100%;
    max-width: var(--tu-content-max);
    aspect-ratio: 16 / 9;
    border-radius: 22px;
    overflow: hidden;
    /* Token ground, not a black literal: the poster is what fills this box
       for almost the whole visit, and #000 would punch an opaque hole in
       light mode that no value swap could reach. The player brings its own
       black once it is actually mounted. */
    background: var(--global-card-background);
    box-shadow:
        0 30px 80px rgba(var(--global-text-color-rgb), 0.14),
        0 0 0 1px var(--global-border-color);
}
.tu-stage.is-playing { background: #000; }
.tu-stage-poster,
.tu-stage iframe {
    display: block;
    width: 100%;
    height: 100%;
    border: 0;
}
.tu-stage-poster { object-fit: cover; }

/* The `hidden` attribute is only a UA-stylesheet `display: none`, so any author
   `display` on the same element silently beats it — and every element this page
   hides (the poster and button while a film plays, the duration chip when a
   runtime is unknown, the 35 films not on stage) has one. Say it explicitly, or
   the whole catalog renders at once and pressing play leaves the poster on top
   of the player. */
#tutorials-page [hidden] { display: none; }

/* The page's one button. Neutral dark fill — the §7.1 primary language,
   not iridescence; this surface already spends its rainbow on the aura. */
.tu-play {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    height: 100%;
    padding: 0;
    border: 0;
    background: none;
    cursor: pointer;
}
.tu-play svg {
    width: 72px;
    height: 72px;
    padding: 23px 20px 23px 26px;
    box-sizing: border-box;
    border-radius: 50%;
    color: var(--global-button-text-color);
    background: var(--global-button-background-color);
    /* The brand-tinted ground shadow (§6.2), plus a paper hairline: the fill is
       a deep charcoal and the posters it sits on are near-black, so without the
       ring the page's only control dissolves into its own artwork. Over-media
       elements carry their own scale here, the way the duration chip does. */
    box-shadow:
        0 12px 40px rgba(var(--brand-iris-rgb), 0.22),
        0 0 0 1px rgba(255, 255, 255, 0.18);
    transition: transform 0.4s var(--tu-ease-spring), opacity 0.3s var(--tu-ease);
}
.tu-play:hover svg { transform: scale(1.06); opacity: 0.92; }
.tu-play:focus-visible { outline: 2px solid var(--focus-outline-color); outline-offset: -4px; border-radius: 22px; }

.tu-stage-duration {
    position: absolute;
    right: 14px;
    bottom: 14px;
    padding: 0 10px;
    height: 22px;
    display: inline-flex;
    align-items: center;
    border-radius: 999px;
    font-size: 10.5px;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    letter-spacing: 0.08em;
    color: #fff;
    background: rgba(15, 15, 18, 0.55);
    pointer-events: none;
}
/* §6.1 — backdrop-filter only where it is supported, never as the thing
   the legibility depends on. (stage.css ships this recipe unwrapped; the
   copy is corrected on the way in.) */
@supports (backdrop-filter: blur(8px)) {
    .tu-stage-duration {
        background: rgba(15, 15, 18, 0.38);
        backdrop-filter: blur(8px) saturate(140%);
    }
}

.tu-stage-fallback {
    position: relative;
    z-index: 1;
    margin-top: calc(clamp(28px, 4vh, 44px) * -0.6);
}

/* =====================================================================
 * 03 · NOW PLAYING
 * ===================================================================== */
.tu-now {
    position: relative;
    z-index: 1;
    width: 100%;
    max-width: var(--tu-content-max);
}
.tu-now-film {
    display: flex;
    flex-direction: column;
    gap: 10px;
    animation: tu-now-in 0.26s var(--tu-ease);
}
@keyframes tu-now-in { from { opacity: 0; } to { opacity: 1; } }
/* Season label. §3.4's stat-label variant (12px / .12em), NOT the 13px
   eyebrow — the eyebrow is already spoken once above, and a second one
   here would read as a competing heading. */
.tu-now-eyebrow {
    margin: 0;
    font-size: 12px;
    font-weight: 500;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    font-variant-numeric: tabular-nums;
    color: var(--global-text-muted);
    opacity: 0.6;
    line-height: 1;
}
.tu-now-title {
    margin: 0;
    font-size: clamp(24px, 3.4vw, 34px);
    font-weight: 700;
    letter-spacing: -0.028em;
    line-height: 1.2;
}
.tu-now-summary {
    margin: 0;
    max-width: 56ch;
    font-size: clamp(14px, 1.4vw, 16px);
    line-height: 1.75;
    letter-spacing: -0.005em;
    color: var(--global-text-muted);
    text-wrap: pretty;
}
.tu-now-next { margin-top: 4px; align-self: flex-start; }

/* =====================================================================
 * 04 · SHELVES
 * ===================================================================== */
.tu-shelves {
    position: relative;
    z-index: 1;
    width: 100%;
    max-width: var(--tu-content-max);
    display: flex;
    flex-direction: column;
    gap: clamp(44px, 7vh, 80px);
    margin-top: clamp(16px, 3vh, 32px);
}
.tu-shelf {
    /* Anchor target: clear the sticky header when jumped to. */
    scroll-margin-top: calc(var(--header-height) + 24px);
}
.tu-shelf-head {
    display: grid;
    grid-template-columns: auto 1fr auto;
    align-items: baseline;
    column-gap: 14px;
    row-gap: 10px;
    padding-bottom: clamp(18px, 2.6vh, 24px);
    margin-bottom: clamp(20px, 3vh, 30px);
    border-bottom: 1px solid rgba(var(--global-text-color-rgb), 0.14);
}
/* Season ordinal — the same quiet numeral About uses on its pillars. */
.tu-shelf-index {
    font-size: 12px;
    font-weight: 500;
    letter-spacing: 0.12em;
    font-variant-numeric: tabular-nums;
    color: var(--global-text-muted);
    opacity: 0.6;
    line-height: 1;
}
/* A section divider has to outrank the cards it divides. As a 13px eyebrow it
   was two points SMALLER than the episode titles beneath it, so the shelves
   read as a run of tiles with faint labels floating in them. */
.tu-shelf-title {
    margin: 0;
    font-size: clamp(20px, 2.2vw, 26px);
    font-weight: 700;
    letter-spacing: -0.024em;
    line-height: 1.25;
    color: var(--global-text-color);
}
.tu-shelf-meta {
    margin: 0;
    justify-self: end;
    font-size: 12px;
    font-weight: 500;
    font-variant-numeric: tabular-nums;
    color: var(--global-text-muted);
}
.tu-shelf-caption,
.tu-shelf-playlist { grid-column: 2 / -1; }
.tu-shelf-caption {
    margin: 0;
    max-width: 46ch;
    font-size: 13.5px;
    line-height: 1.7;
    letter-spacing: -0.005em;
    color: var(--global-text-muted);
}

.tu-grid {
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
    gap: clamp(14px, 1.4vw, 22px);
}
.tu-tile-link {
    display: flex;
    flex-direction: column;
    gap: 10px;
    text-decoration: none;
    color: inherit;
    border-radius: 14px;
    transition: transform 0.5s var(--tu-ease-spring);
}
.tu-tile-art {
    display: block;
    aspect-ratio: 16 / 9;
    overflow: hidden;
    border-radius: 14px;
    background: var(--global-card-background);
    border: 1px solid var(--global-border-color);
    transition: border-color 0.5s var(--tu-ease), box-shadow 0.5s var(--tu-ease);
}
.tu-tile-art img {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
    transition: transform 0.7s var(--tu-ease-spring);
}
@media (hover: hover) {
    .tu-tile-link:hover { transform: translateY(-3px); }
    .tu-tile-link:hover .tu-tile-art {
        border-color: rgba(var(--global-text-color-rgb), 0.04);
        /* §6.3 ambient bloom, one step down for tiles — matches main's surfaces. */
        box-shadow:
            -22px -14px 50px -10px rgba(var(--brand-iris-rgb),     0.18),
             22px -14px 50px -10px rgba(var(--brand-mulberry-rgb), 0.16),
             22px  22px 56px -10px rgba(var(--brand-brass-rgb),    0.14),
            -22px  22px 56px -10px rgba(var(--brand-lichen-rgb),   0.12),
              0   28px 56px -24px rgba(var(--global-text-color-rgb), 0.16);
    }
    .tu-tile-link:hover .tu-tile-art img { transform: scale(1.04); }
}
.tu-tile-link:focus-visible { outline: 2px solid var(--focus-outline-color); outline-offset: 3px; }

.tu-tile-meta {
    display: flex;
    align-items: baseline;
    gap: 8px;
    font-size: 12px;
    font-weight: 500;
    font-variant-numeric: tabular-nums;
    letter-spacing: 0.12em;
    color: var(--global-text-muted);
    opacity: 0.6;
    line-height: 1;
}
.tu-tile-title {
    font-size: clamp(15px, 1.1vw, 17px);
    font-weight: 600;
    letter-spacing: -0.018em;
    line-height: 1.45;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
    word-break: keep-all;
}
/* The film currently on stage. A mark and a firmer edge — no colour, so
   the shelf stays monochrome and the aura keeps its monopoly. */
.tu-tile.is-playing .tu-tile-index::before { content: '▸ '; }
.tu-tile.is-playing .tu-tile-art { border-color: rgba(var(--global-text-color-rgb), 0.28); }

/* =====================================================================
 * 05 · CLOSE
 * ===================================================================== */
.tu-close {
    position: relative;
    z-index: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 14px;
    margin-top: clamp(24px, 4vh, 48px);
    text-align: center;
}
.tu-close-doors {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: clamp(18px, 3vw, 36px);
}
.tu-close-note {
    margin: 0;
    max-width: 46ch;
    font-size: 13px;
    line-height: 1.7;
    letter-spacing: -0.005em;
    color: var(--global-text-muted);
}

/* Empty catalog — a designed state, not a skeleton. Reached when every
   season is hidden, and when Mongo is unreachable (the route serves 200
   with chrome rather than a 500). */
.tu-empty {
    position: relative;
    z-index: 1;
    margin: clamp(24px, 6vh, 64px) 0;
    max-width: 46ch;
    text-align: center;
    font-size: 14px;
    line-height: 1.7;
    color: var(--global-text-muted);
}

/* ---------- Reveal mechanic (§5.3) ---------- */
#tutorials-page [data-reveal] {
    opacity: 0;
    transform: translateY(24px);
    transition:
        opacity 0.9s var(--tu-ease),
        transform 0.9s var(--tu-ease-spring);
}
#tutorials-page [data-reveal].is-revealed { opacity: 1; transform: translateY(0); }
#tutorials-page [data-reveal-stagger="1"] { transition-delay: 0.08s; }
#tutorials-page [data-reveal-stagger="2"] { transition-delay: 0.16s; }
#tutorials-page [data-reveal-stagger="3"] { transition-delay: 0.24s; }

/* ---------- Mobile (§4.7 — the single 640px breakpoint) ---------- */
@media (max-width: 640px) {
    .tu-stage { border-radius: 18px; }
    .tu-play svg { width: 64px; height: 64px; padding: 20px 17px 20px 23px; }

    /* Two up rather than one: thirty-six 16:9 stills stacked singly turns
       the close band into a scroll expedition, and at 150px a poster is
       still readable. */
    .tu-grid { grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); }

    /* The head stops being a row and becomes a stack: ordinal + title on one
       line, then everything else flush left under it. Leaving the caption and
       the playlist link indented to the title's column while the meta sat at
       the margin put three lines on two different left edges. */
    .tu-shelf-head { grid-template-columns: auto 1fr; }
    .tu-shelf-meta,
    .tu-shelf-caption,
    .tu-shelf-playlist { grid-column: 1 / -1; justify-self: start; }
}

/* ---------- Reduced motion (§5.7) ---------- */
@media (prefers-reduced-motion: reduce) {
    .tu-aura { animation: none; }
    .tu-now-film { animation: none; }
    #tutorials-page [data-reveal] { opacity: 1; transform: none; transition: none; }
    .tu-cue,
    .tu-play svg,
    .tu-tile-link,
    .tu-tile-art,
    .tu-tile-art img { transition: none; }
}
