/* Home page (UI-05): the intro and the hero's mini timetable.
   Layout and colour are Tailwind utilities in templates/home.html; only what a
   utility cannot say (keyframes, a grid placed from variables, pseudo-elements)
   is here. */

/* ---------------------------------------------------------------------------
   The intro: the logo turns in the middle of a navy curtain, then the curtain
   opens on the page. About 1.1 s, once per visit.

   Three pseudo-elements and no markup: nothing for a screen reader to meet,
   nothing to remove afterwards. They exist only under `html.intro-play`, the
   class shared/boot.js adds before first paint when the intro should run.

   The safety rule: THE RESTING STATE IS "NOT THERE". Each layer is invisible
   and off screen in its own rule, and only the keyframes bring it in. If the
   animation never starts (an old browser, a blocked stylesheet feature), the
   page is simply not covered. Do not move a visible state into the base rule.
   --------------------------------------------------------------------------- */
html.intro-play::before,
html.intro-play::after,
html.intro-play body::before {
    content: "";
    position: fixed;
    pointer-events: none;
    visibility: hidden;
}

/* The curtain's two halves. Each is a hair wider than half so no seam shows. */
html.intro-play::before,
html.intro-play::after {
    top: 0;
    bottom: 0;
    width: 50.5vw;
    z-index: 200;
    background: #06121f;
}

html.intro-play::before {
    left: 0;
    transform: translateX(-101%);
    animation: intro-left 1.15s cubic-bezier(0.7, 0, 0.2, 1) both;
}

html.intro-play::after {
    right: 0;
    transform: translateX(101%);
    animation: intro-right 1.15s cubic-bezier(0.7, 0, 0.2, 1) both;
}

/* The logo, on top of the curtain. */
html.intro-play body::before {
    top: 50%;
    left: 50%;
    width: 6rem;
    height: 5.25rem;
    margin: -2.625rem 0 0 -3rem;
    z-index: 201;
    opacity: 0;
    background: url("../assets/brand/LOGO-dark.b29d1713188f.svg") center / contain no-repeat;
    animation: intro-logo 1.15s ease both;
}

@keyframes intro-left {
    0%, 60% { transform: translateX(0); visibility: visible; }
    100% { transform: translateX(-101%); visibility: visible; }
}

@keyframes intro-right {
    0%, 60% { transform: translateX(0); visibility: visible; }
    100% { transform: translateX(101%); visibility: visible; }
}

@keyframes intro-logo {
    0% { opacity: 0; transform: rotate(-120deg) scale(0.6); visibility: visible; }
    18% { opacity: 1; }
    58% { opacity: 1; transform: rotate(360deg) scale(1); }
    100% { opacity: 0; transform: rotate(360deg) scale(1.5); visibility: visible; }
}

/* boot.js already skips the class under reduced motion; this is the second lock. */
@media (prefers-reduced-motion: reduce) {
    html.intro-play::before,
    html.intro-play::after,
    html.intro-play body::before {
        animation: none;
    }
}

/* ---------------------------------------------------------------------------
   The hero's mini timetable. A picture of the product drawn in CSS: Monday to
   Friday, six hours, the default course colours. Each block is placed from
   variables on its own tag (--c column, --r row, --s rows spanned, --bg).

   The finished timetable IS the base style. The animation only describes how
   it gets there (`backwards`: hidden until its turn, then the base style), so
   reduced motion, a slow device or no animation support all show the result.
   --------------------------------------------------------------------------- */
.hero-tt {
    --start: 0.3s;
    --step: 0.16s;
    /* One row plus one gap: how far the clashing block travels per row. */
    --row: 2.75rem;
}

/* Wait for the curtain to open before the blocks start to fall. */
html.intro-play .hero-tt {
    --start: 1.1s;
}

.hero-tt__grid {
    display: grid;
    grid-template-columns: 1.5rem repeat(5, minmax(0, 1fr));
    grid-template-rows: auto repeat(6, 2.5rem);
    gap: 0.25rem;
    font-size: 0.625rem;
    font-weight: 600;
    line-height: 1.2;
}

.hero-tt__day {
    text-align: center;
    padding-bottom: 0.25rem;
}

.hero-tt__hour {
    grid-column: 1;
    grid-row: var(--r);
    font-weight: 400;
}

.hero-tt__block {
    grid-column: var(--c);
    grid-row: var(--r) / span var(--s, 1);
    background: var(--bg);
    /* Fixed, not themed: the course colours are light in both themes. */
    color: #1f2937;
    border-radius: 0.375rem;
    padding: 0.25rem 0.3rem;
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
}

.hero-tt__block--clash {
    position: relative;
    z-index: 1;
}

@media (min-width: 640px) {
    .hero-tt__grid {
        grid-template-columns: 2rem repeat(5, minmax(0, 1fr));
        font-size: 0.6875rem;
    }

    .hero-tt__block {
        padding: 0.3rem 0.4rem;
    }
}

@media (prefers-reduced-motion: no-preference) {
    .hero-tt__block {
        animation: hero-tt-drop 0.45s cubic-bezier(0.2, 0.9, 0.3, 1.2) backwards;
        animation-delay: calc(var(--start) + var(--d, 0) * var(--step));
    }

    /* The last course lands two rows up, on a slot that is taken, is flagged,
       and moves down to the free one. */
    .hero-tt__block--clash {
        animation: hero-tt-clash 1.5s ease backwards;
        animation-delay: calc(var(--start) + 5 * var(--step));
    }

    /* The credit count and "No conflicts" settle once the clash is resolved. */
    .hero-tt__pill {
        animation: hero-tt-settle 0.4s ease backwards;
        animation-delay: calc(var(--start) + 5 * var(--step) + 1.5s);
    }

    /* Out of sight at load (under the hero's text on a phone), the timetable
       waits: reveal.js adds `play-pending` and takes it off once enough of
       it is on screen (UI-36). Paused at the start, `backwards` shows each
       block's first frame, so it plays from the beginning when seen. With no
       script the class never comes and it plays at load, as before. */
    .hero-tt.play-pending .hero-tt__block,
    .hero-tt.play-pending .hero-tt__pill {
        animation-play-state: paused;
    }
}

@keyframes hero-tt-drop {
    from { opacity: 0; transform: translateY(-0.75rem) scale(0.92); }
}

@keyframes hero-tt-clash {
    0% { opacity: 0; transform: translateY(calc(var(--row) * -2 - 0.75rem)) scale(0.92); box-shadow: 0 0 0 0 rgba(220, 38, 38, 0); }
    18% { opacity: 1; transform: translateY(calc(var(--row) * -2)) scale(1); box-shadow: 0 0 0 2px #dc2626; }
    30% { transform: translateY(calc(var(--row) * -2)) translateX(-3px); }
    42% { transform: translateY(calc(var(--row) * -2)) translateX(3px); }
    54% { opacity: 1; transform: translateY(calc(var(--row) * -2)); box-shadow: 0 0 0 2px #dc2626; }
    100% { opacity: 1; transform: translateY(0); box-shadow: 0 0 0 0 rgba(220, 38, 38, 0); }
}

@keyframes hero-tt-settle {
    from { opacity: 0; transform: translateY(0.25rem); }
}
