/* Skeleton placeholders for card grids and lists.
 *
 * Shared by every student and teacher page. Two jobs:
 *
 *  1. Hold the layout. A grid that is empty while its fetch is in flight
 *     collapses -- `auto-fit` tracks fold to one column, and cards sized by
 *     their content render short and then jump to full height when the data
 *     lands. A skeleton that occupies the real card's box means nothing moves
 *     when the content arrives.
 *  2. Say "loading" without a spinner, by showing the shape of what is coming.
 *
 * Injected by js/utlis/skeleton.js -- see there for the markup contract.
 *
 * MUST be linked *before* the page's own stylesheet. A skeleton card carries
 * the page's real card class alongside .sk-card, and both are single-class
 * selectors, so it is stylesheet order that decides which surface, radius and
 * padding win. The page's card has to win -- that is the whole reason the
 * placeholder ends up the same size as the real thing.
 */

.sk-card {
    /* A plain surface, deliberately weak: it is only what a container with no
       data-skeleton-class falls back to. Any page card class linked after this
       file overrides all of it. */
    background: var(--light-gray, #f1f5f9);
    border-radius: 12px;
    pointer-events: none;
    overflow: hidden;
}

/* The grey blocks themselves. The sweep is what makes it read as loading rather
   than as broken content -- a static grey card looks like a render bug.
 *
 * Both layers are translucent rather than fixed greys, so a block is always a
 * veil over whatever card it sits on. That is what keeps it visible on a white
 * student card, on the dashboard's #2a2a2a dark card, and on a teacher-themed
 * surface that could be any colour at all -- a hardcoded grey would vanish
 * against the ones it happened to match. */
.sk-block {
    /* Explicit, because callers place these on <span> too (a placeholder next
       to real inline text) and height does not apply to an inline box. */
    display: block;
    background-color: rgba(125, 140, 145, .22);
    background-image: linear-gradient(90deg,
            rgba(255, 255, 255, 0) 35%,
            rgba(255, 255, 255, .5) 50%,
            rgba(255, 255, 255, 0) 65%);
    background-size: 280% 100%;
    background-repeat: no-repeat;
    border-radius: 8px;
    /* RTL: the highlight travels right-to-left, with the text. */
    animation: sk-sweep 1.5s linear infinite;
}

[data-theme="dark"] .sk-block {
    background-color: rgba(170, 190, 195, .15);
    background-image: linear-gradient(90deg,
            rgba(255, 255, 255, 0) 35%,
            rgba(255, 255, 255, .13) 50%,
            rgba(255, 255, 255, 0) 65%);
}

@keyframes sk-sweep {
    from {
        background-position: -90% 0;
    }

    to {
        background-position: 190% 0;
    }
}

/* Respect the OS setting. The placeholder still has to be visible, so the
   animation stops rather than the block disappearing. */
@media (prefers-reduced-motion: reduce) {
    .sk-block {
        animation: none;
        background-image: none;
    }
}

/* ---- parts ---- */

.sk-media {
    width: 100%;
    height: var(--sk-media-h, 160px);
    border-radius: 0;
}

.sk-body {
    padding: 1rem;
    display: flex;
    flex-direction: column;
    gap: .7rem;
}

.sk-line {
    height: 12px;
}

.sk-line.sk-title {
    height: 17px;
    width: 70%;
}

.sk-line.sk-short {
    width: 45%;
}

.sk-foot {
    display: flex;
    justify-content: space-between;
    gap: .5rem;
    margin-top: .35rem;
}

.sk-pill {
    height: 22px;
    width: 68px;
    border-radius: 999px;
}

.sk-avatar {
    width: 48px;
    height: 48px;
    border-radius: 50%;
    flex-shrink: 0;
}

/* ---- row variant: list items and table-less rows ---- */

.sk-row {
    display: flex;
    align-items: center;
    gap: 1rem;
    padding: 1rem;
    pointer-events: none;
}

.sk-row .sk-row-text {
    flex: 1;
    display: flex;
    flex-direction: column;
    gap: .55rem;
    min-width: 0;
}

/* ---- table variant ---- */

tr.sk-tr {
    pointer-events: none;
}

tr.sk-tr td {
    padding: .9rem 1rem;
}

/* ---- stat tiles ---- */

.sk-stat {
    padding: 1.25rem;
    display: flex;
    flex-direction: column;
    gap: .75rem;
    pointer-events: none;
}

.sk-stat .sk-line.sk-title {
    width: 50%;
    height: 26px;
}

/* =========================================================================
   Veils — a skeleton over an element the page already renders.
   =========================================================================

   The grid placeholders above fill an *empty* container. A dashboard has the
   opposite problem: the cover, the avatar, the name and the stat numbers are
   all static markup that is already on screen, holding stale or placeholder
   content ("مرحباً بك، [اسم المعلم]!", a stat reading 0) until the profile
   fetch lands. There is nothing empty to fill — the wrong content is the
   thing to hide.

   So a veil is an opaque shimmering ::after over the element. Opt in with one
   attribute, in the markup rather than from script, so it is painted with the
   first frame instead of appearing after DOMContentLoaded:

       <div class="welcome-cover-container" id="coverContainer" data-sk-veil>

   Removing the attribute reveals — js/utlis/skeleton.js does that the moment
   the element's own subtree changes, and pages can call Skeleton.reveal() for
   the fields that may legitimately never change (an avatar the user never
   set).

   ::after does not render on a replaced element, so never put data-sk-veil on
   an <img> — veil its wrapper. */

[data-sk-veil] {
    position: relative;
    /* --sk-veil-h sizes the *element*, not the veil, so it only matters for an
       element that is empty (and therefore 0-high) while it loads. The veil
       itself always spans the full box — see the note on `inset-block` below. */
    min-height: var(--sk-veil-h, 1em);
    /* Contains the veil's z-index.
     *
     * Without it the veil competes in the *root* stacking context, and the
     * dashboard avatar — a sibling that overlaps the cover by -80px at
     * z-index 2 — lost to it, so the cover's veil sliced the avatar in half.
     * The veil still has to beat things inside its own element (.welcome-content
     * is z-index 2 there), so it cannot simply be lowered; isolating is what
     * lets it win inside and stay out of the way outside. */
    isolation: isolate;
}

[data-sk-veil]::after {
    content: '';
    position: absolute;
    /* Always the full height of the element. It used to take --sk-veil-h, and
       a stat counter styled at 2.2rem is ~35px tall while the veil was 30px —
       so the bottom of the "0" underneath showed as a little circle poking out
       from under the placeholder. A veil that does not cover its element is
       worse than no veil. */
    inset-block: 0;
    inset-inline-start: 0;
    width: var(--sk-veil-w, 100%);
    /* --sk-veil-w is a *hint* at how wide the finished content will be, not a
       licence to spill. Without the cap it did: the header name span is only
       as wide as the word inside it, so a 90px veil hung out past its start
       edge and sat on top of the avatar beside it. */
    max-width: 100%;
    z-index: 20;
    /* The buttons underneath (change cover, edit avatar) stay clickable the
       instant the veil lifts; while it is up they are invisible anyway. */
    pointer-events: none;
    /* Follows the element it covers — a circular avatar wrapper, a rounded
       cover. Inherits the element's own computed radius. */
    border-radius: inherit;

    /* Opaque, unlike .sk-block: a veil has to *hide* what is underneath, and a
       translucent one leaves the placeholder name legible through it.
     *
     * But opaque does not have to mean a fixed grey. Every dashboard here is
     * teacher-themed — dashboard-theme.js repaints these variables — and a flat
     * slate slab dropped on a purple page reads as a broken image, not as
     * loading. So a *neutral* grey is mixed into the page's own surface colour
     * (`--white`, which is the card surface and flips with the theme): still
     * unmistakably a grey placeholder, but sitting in the page's light range
     * instead of on top of it. The grey is deliberately fixed rather than
     * derived from the palette — pulling the teacher's hue in would make a
     * loading state look like a coloured panel.
     *
     * The flat value below it is the fallback wherever color-mix is missing. */
    background-color: #e3e8ea;
    background-color: color-mix(in srgb, #64748b 22%, var(--white, #f1f4f6));
    background-image: linear-gradient(90deg,
            rgba(255, 255, 255, 0) 35%,
            rgba(255, 255, 255, .5) 50%,
            rgba(255, 255, 255, 0) 65%);
    background-size: 280% 100%;
    background-repeat: no-repeat;
    animation: sk-sweep 1.5s linear infinite;
}

[data-theme="dark"] [data-sk-veil]::after {
    /* Lifted well clear of the surface. A dark dashboard's `--white` is already
       near-black, so a small mix produced a placeholder that was invisible —
       shapes you could only just make out, which reads as a rendering fault
       rather than as loading. It has to be plainly lighter than what it sits
       on. */
    background-color: #3b4147;
    background-color: color-mix(in srgb, #cbd5e1 22%, var(--white, #2d2d2d));
    background-image: linear-gradient(90deg,
            rgba(255, 255, 255, 0) 35%,
            rgba(255, 255, 255, .16) 50%,
            rgba(255, 255, 255, 0) 65%);
}

@media (prefers-reduced-motion: reduce) {
    [data-sk-veil]::after {
        animation: none;
        background-image: none;
    }
}
