/*
 * Competition calendar month grid.
 *
 * This file only styles the calendar itself. Everything around it — the page
 * head, the card, buttons, chips, the empty state, the "upcoming" list rows —
 * is the shared system: .surface / .section-head / .btn / .chip / .package-line
 * / partials/empty-state. Keep it that way; a bespoke control here is a control
 * that will drift from the rest of the site.
 *
 * Every colour comes from a theme token so the same file serves light,
 * light-new and dark-new without per-theme overrides. Do not hardcode hex
 * values here — the dark-mode audit flags them.
 *
 * The one trick worth knowing: category colours are never used raw. Each tone
 * is mixed toward --ink, which is dark in the light themes and light in the
 * dark themes, so the same declaration desaturates the palette in one
 * direction and brightens it in the other. That is why the tones stay legible
 * across every theme with no @media or [data-theme] branch.
 */

/* --- Month header (sits in a .section-head) ----------------------- */

.df-cal-head {
    align-items: center;
}

.df-cal-head-main {
    display: flex;
    align-items: center;
    gap: var(--sp-3);
    min-width: 0;
}

.df-cal-head-main .section-title {
    margin: 0;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

/* The ‹ › glyphs are oversized for .btn-sm's line box; centre them optically. */
.df-cal-step {
    padding: 1px var(--sp-3);
    font-size: var(--text-lg);
    line-height: 1.3;
}

.df-cal-head-actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--sp-2);
}

/* --- Weekday header ----------------------------------------------- */

.df-cal-weekdays,
.df-cal-grid {
    display: grid;
    grid-template-columns: repeat(7, minmax(0, 1fr));
    /* The header must use the same 1px gap as the grid or the two sets of
       columns drift apart by the last column. */
    gap: 1px;
}

.df-cal-grid {
    background: var(--border);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    overflow: hidden;
}

.df-cal-weekdays {
    margin-bottom: var(--sp-2);
    background: transparent;
}

.df-cal-weekdays span {
    padding: 0 0 var(--sp-2);
    text-align: center;
    font-size: var(--text-xs);
    font-weight: 600;
    color: var(--ink-muted);
    letter-spacing: 0.08em;
    border-bottom: 1px solid var(--border);
}

.df-cal-weekdays span.is-weekend {
    color: var(--ink-faint);
}

/* --- Month grid --------------------------------------------------- */

.df-cal-cell {
    /* No horizontal padding: event chips are inset by .df-cal-events so that a
       multi-day band can reach the cell wall and meet its neighbour.
       The height is a floor, not a target: most days carry no event at all, so
       a taller cell spends its extra pixels on empty space and pushes the month
       below the fold. Three chips still fit without scrolling. */
    min-height: 92px;
    padding: 5px 0 6px;
    background: var(--surface);
    display: flex;
    flex-direction: column;
    gap: 3px;
    transition: background-color 0.12s ease;
}

/* Order matters — later rules win at equal specificity. */
.df-cal-cell.is-weekend {
    background: color-mix(in srgb, var(--surface-alt) 60%, var(--surface));
}

.df-cal-cell.is-outside {
    background: var(--surface-alt);
}

.df-cal-cell.is-today {
    background: color-mix(in srgb, var(--accent) 6%, var(--surface));
}

.df-cal-cell.is-outside .df-cal-daynum {
    color: var(--ink-faint);
}

.df-cal-daynum {
    align-self: flex-start;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 20px;
    height: 20px;
    margin: 0 7px 1px;
    padding: 0 6px;
    border-radius: var(--radius-pill);
    font-size: var(--text-xs);
    font-weight: 600;
    color: var(--ink-3);
    font-variant-numeric: tabular-nums;
}

.df-cal-cell.is-today .df-cal-daynum {
    /* --surface is the page's base surface colour, which sits opposite --accent
       in every theme (light on dark blue, dark on light blue). There is no
       --on-accent token in the system, so this is the intended pair. */
    background: var(--accent);
    color: var(--surface);
}

.df-cal-events {
    display: flex;
    flex-direction: column;
    gap: 3px;
    min-width: 0;
    padding: 0 3px;
}

/* --- Event chips -------------------------------------------------- */

.df-cal-event {
    --cal-tone: var(--accent);
    position: relative;
    z-index: 1;
    display: flex;
    align-items: center;
    padding: 2px 6px;
    border-radius: var(--radius);
    background: color-mix(in srgb, var(--cal-tone) 12%, var(--surface));
    color: color-mix(in srgb, var(--cal-tone) 68%, var(--ink));
    font-size: var(--text-xs);
    font-weight: 500;
    line-height: 1.4;
    text-decoration: none;
    min-width: 0;
    transition: background-color 0.12s ease, color 0.12s ease;
}

.df-cal-event:hover {
    background: color-mix(in srgb, var(--cal-tone) 26%, var(--surface));
    color: color-mix(in srgb, var(--cal-tone) 82%, var(--ink));
}

.df-cal-event.is-featured {
    background: color-mix(in srgb, var(--cal-tone) 20%, var(--surface));
    font-weight: 600;
}

.df-cal-event.is-featured:hover {
    background: color-mix(in srgb, var(--cal-tone) 34%, var(--surface));
}

/* A multi-day event is drawn as one band: flat on whichever side carries on
   into the neighbouring cell, so a run of days reads as a single event rather
   than N identical chips.
   The negative margin is the .df-cal-events inset (3px) plus one extra pixel to
   step over the grid's own 1px gap — without that extra pixel the cells'
   background shows through and cuts a hairline across the band. */
.df-cal-event.is-band {
    border-radius: 0;
}

.df-cal-event.is-band.is-start {
    border-radius: var(--radius) 0 0 var(--radius);
    margin-right: -4px;
}

.df-cal-event.is-band.is-mid {
    margin: 0 -4px;
}

.df-cal-event.is-band.is-end {
    border-radius: 0 var(--radius) var(--radius) 0;
    margin-left: -4px;
}

/* Continuation cells past the first of the week repeat the band but not the
   label, so a long event does not shout its name in every column. The label is
   hidden with visibility rather than display: the chip's height comes from the
   text's line box, and collapsing it would make the band thinner mid-run. */
.df-cal-event.is-continues .df-cal-event-title {
    visibility: hidden;
}

.df-cal-event-title {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Tones are categorical, not semantic — red here means "CTF", not "error".
   Each is mixed toward --ink at the point of use (see the chip rules above).

   Two disciplines need hues the theme token set does not carry. They are
   declared here rather than in the per-theme stylesheets so the calendar stays
   a self-contained surface: this file owns the tone vocabulary, and adding a
   discipline should not mean editing three theme files to get a colour. Each
   needs a dark value because the tone is mixed against --surface, which flips —
   a single mid-tone reads fine on white and goes muddy on near-black. */
body[data-theme-area="frontend"] {
    --cal-hue-violet: #7c3aed;
    --cal-hue-teal: #0f766e;
}

body.theme-dark[data-theme-area="frontend"] {
    --cal-hue-violet: #a78bfa;
    --cal-hue-teal: #2dd4bf;
}

.tone-platform { --cal-tone: var(--accent); }
.tone-forensics { --cal-tone: var(--cal-hue-violet); }
.tone-ctf { --cal-tone: var(--negative); }
.tone-conference { --cal-tone: var(--accent-2); }
.tone-training { --cal-tone: var(--positive); }
.tone-certification { --cal-tone: var(--cal-hue-teal); }
.tone-exercise { --cal-tone: var(--warning); }
.tone-other { --cal-tone: var(--ink-muted); }

/* --- "+N more" popover (no JS beyond closing siblings) -------------- */

.df-cal-more {
    position: relative;
}

.df-cal-more > summary {
    cursor: pointer;
    list-style: none;
    margin-top: 1px;
    padding: 1px 7px;
    border-radius: var(--radius);
    font-size: var(--text-xs);
    color: var(--ink-muted);
}

.df-cal-more > summary:hover {
    background: var(--surface-sunken);
    color: var(--ink-3);
}

.df-cal-more > summary::-webkit-details-marker {
    display: none;
}

.df-cal-more[open] > summary {
    background: var(--surface-sunken);
    color: var(--ink);
}

.df-cal-more-list {
    position: absolute;
    z-index: 20;
    top: 100%;
    left: 3px;
    min-width: 210px;
    display: flex;
    flex-direction: column;
    gap: 3px;
    padding: var(--sp-2);
    background: var(--surface);
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-lg);
}

/* --- Legend ------------------------------------------------------- */

.df-cal-legend {
    display: flex;
    flex-wrap: wrap;
    gap: var(--sp-2);
    margin-top: var(--sp-4);
    padding-top: var(--sp-4);
    border-top: 1px solid var(--border);
}

/* Looks like a .chip row because that is what the rest of the site uses for a
   key, but is deliberately not one. .chip is globally reset to bare inline text
   on the public index routes (metadata-system.css), which stripped this legend's
   tint, border AND its dots — the dots are sized by width/height, which do not
   apply to an inline box, so the key lost its colours entirely. This selector is
   under .df-cal-* and therefore out of that reset's reach; keep it that way and
   do not "simplify" it back to .chip. */
.df-cal-legend-item {
    /* No --cal-tone default here on purpose: .tone-* is declared earlier in this
       file at equal specificity, so a default written here would win over it and
       flatten the whole key to one colour. The tone class is always present. */
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 3px 10px;
    border: 1px solid color-mix(in srgb, var(--cal-tone) 28%, var(--border));
    border-radius: var(--radius-pill);
    background: color-mix(in srgb, var(--cal-tone) 10%, var(--surface));
    color: color-mix(in srgb, var(--cal-tone) 68%, var(--ink));
    font-size: var(--text-xs);
    font-weight: 500;
    line-height: 1.4;
    white-space: nowrap;
}

.df-cal-legend-item i {
    flex: 0 0 auto;
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: var(--cal-tone);
}

/* The calendar is the one surface where the key has to survive on a phone: the
   month grid collapses to coloured bars there, so the legend is the only place
   the colours are still explained. It wraps to a second line rather than
   dropping entries. */
@media (max-width: 768px) {
    .df-cal-legend {
        gap: var(--sp-1) var(--sp-2);
    }

    .df-cal-legend-item {
        padding: 2px 8px;
    }
}

/* --- Upcoming list (built on .package-line) ------------------------ */

/* Stands in for .contest-list-cover: the same leading square tile, carrying a
   date instead of cover art. */
.df-cal-tile {
    flex: 0 0 auto;
    /* frontend-polish.css stretches .package-archive rows; the contest archive
       pins its cover tile with the same rule, so pin this one to match. */
    align-self: flex-start;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    width: 64px;
    aspect-ratio: 1;
    border: 1px solid color-mix(in srgb, var(--cal-tone) 26%, var(--border));
    border-radius: 6px;
    background: color-mix(in srgb, var(--cal-tone) 10%, var(--surface));
    line-height: 1.15;
}

.df-cal-tile strong {
    font-size: var(--text-2xl);
    font-weight: 800;
    color: color-mix(in srgb, var(--cal-tone) 72%, var(--ink));
    font-variant-numeric: tabular-nums;
}

.df-cal-tile em {
    font-style: normal;
    font-size: var(--text-xs);
    color: var(--ink-muted);
}

.df-cal-line {
    color: inherit;
    text-decoration: none;
}

/* .package-line-main and .package-title are divs and headings on the contest
   archive; here the card is one <a>, so they arrive as spans and need block. */
.df-cal-line .package-line-main {
    display: flex;
    flex-direction: column;
    gap: var(--sp-1);
}

.df-cal-line .package-title {
    display: block;
    margin: 0;
    transition: color 0.15s ease;
}

.df-cal-line:hover .package-title {
    color: var(--accent);
}

/* Mirrors what frontend-polish.css does for the contest archive's
   .package-start-link, so the two archives' buttons sit identically. */
.df-cal-line .package-line-aside {
    justify-content: flex-start;
}

.df-cal-line .package-line-aside .btn {
    width: 100%;
    justify-content: center;
    white-space: nowrap;
}

/* --- Homepage month strip ----------------------------------------- */

/* A month at a glance for the home page, not a working calendar: the whole strip
   is a single link to the calendar page. It is loaded with this file, so it
   shares the .tone-* palette and a colour means the same thing here as it does
   in the grid above. */
.df-mini-cal {
    display: block;
    color: inherit;
    text-decoration: none;
}

.df-mini-cal-weekdays,
.df-mini-cal-grid {
    display: grid;
    grid-template-columns: repeat(7, minmax(0, 1fr));
    gap: 4px;
}

.df-mini-cal-weekdays {
    margin-bottom: 4px;
}

.df-mini-cal-weekdays span {
    text-align: center;
    font-size: var(--text-xs);
    font-weight: 600;
    color: var(--ink-muted);
    letter-spacing: 0.06em;
}

.df-mini-cal-cell {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 4px;
    min-height: 42px;
    padding: 5px 2px 4px;
    border: 1px solid transparent;
    border-radius: var(--radius);
    font-size: var(--text-xs);
    font-weight: 500;
    color: var(--ink-3);
    font-variant-numeric: tabular-nums;
}

.df-mini-cal-cell.is-outside {
    color: var(--ink-faint);
}

.df-mini-cal-cell.is-today {
    border-color: color-mix(in srgb, var(--accent) 40%, var(--border));
    background: color-mix(in srgb, var(--accent) 8%, var(--surface));
    color: var(--accent);
    font-weight: 700;
}

/* The dots sit in a fixed-height row so a day with no event still lines up with
   one that has three. */
.df-mini-cal-tones {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 2px;
    height: 5px;
}

.df-mini-cal-tones i {
    width: 5px;
    height: 5px;
    border-radius: 50%;
    background: var(--cal-tone);
}

/* Hovering somewhere in the strip previews the whole strip, because the whole
   strip is the target. `:not(.is-today)` keeps today's accent tint rather than
   letting the hover wash it out. */
@media (hover: hover) and (pointer: fine) {
    .df-mini-cal:hover .df-mini-cal-cell:not(.is-today) {
        background: var(--surface-alt);
    }
}

.df-mini-cal-note {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--sp-2);
    margin: var(--sp-3) 0 0;
    padding-top: var(--sp-3);
    border-top: 1px solid var(--border);
    font-size: var(--text-sm);
    color: var(--ink-muted);
}

@media (max-width: 768px) {
    .df-mini-cal-weekdays,
    .df-mini-cal-grid {
        gap: 2px;
    }

    .df-mini-cal-cell {
        min-height: 36px;
        gap: 3px;
        padding: 4px 0 3px;
    }
}

/* --- Detail page -------------------------------------------------- */

.df-cal-hero-chips {
    display: flex;
    flex-wrap: wrap;
    gap: var(--sp-2);
    margin-bottom: var(--sp-3);
}

.df-cal-side {
    display: flex;
    flex-direction: column;
    align-self: start;
}

.df-cal-facts {
    display: grid;
    grid-template-columns: auto 1fr;
    gap: var(--sp-2) var(--sp-4);
    margin: var(--sp-4) 0 0;
}

.df-cal-facts dt {
    font-size: var(--text-sm);
    color: var(--ink-muted);
}

.df-cal-facts dd {
    margin: 0;
    font-size: var(--text-sm);
    color: var(--ink);
}

/* --- Responsive --------------------------------------------------- */

/* Matches frontend-polish.css's archive breakpoint so the month grid and the
   upcoming rows never switch layouts at different widths. */
@media (max-width: 768px) {
    .df-cal-head {
        align-items: flex-start;
        gap: var(--sp-3);
    }

    .df-cal-head-main {
        gap: var(--sp-2);
    }

    .df-cal-head-main .section-title {
        font-size: var(--text-lg);
    }

    .df-cal-cell {
        min-height: 64px;
        padding: 4px 0 5px;
        gap: 3px;
    }

    .df-cal-daynum {
        min-width: 18px;
        height: 18px;
        margin: 0 6px 1px;
        padding: 0 5px;
    }

    .df-cal-events {
        padding: 0 2px;
    }

    /* The month grid is a density overview on a phone — the upcoming list below
       is the readable view, so chips collapse to coloured bars. */
    .df-cal-event {
        height: 6px;
        padding: 0;
        border-radius: 3px;
        background: color-mix(in srgb, var(--cal-tone) 55%, var(--surface));
    }

    .df-cal-event.is-band.is-start { margin-right: -3px; }
    .df-cal-event.is-band.is-mid { margin: 0 -3px; }
    .df-cal-event.is-band.is-end { margin-left: -3px; }

    .df-cal-event-title {
        display: none;
    }

    .df-cal-more > summary {
        text-align: center;
    }

    .df-cal-more-list {
        position: fixed;
        inset: auto var(--sp-4) var(--sp-4) var(--sp-4);
    }

    /* The whole row is already a link, so the button is a second affordance for
       the same target — drop it and give the title the width instead. */
    .df-cal-line .package-line-aside {
        display: none;
    }

    .df-cal-tile {
        width: 52px;
    }
}
