/*
 * A calm, modern "dashboard card" look (inspired by a referenced SaaS scheduling-dashboard
 * design) rather than bare unstyled form controls: a soft elevated surface, a shared week
 * navigator, subtle grid lines, and small color-coded accents per team. Still deliberately
 * restrained - one small fixed palette (see TEAM_COLOR_PALETTE in viewer.js), no decorative
 * motion beyond the transitions that were already here.
 *
 * Every physical pitch's own weekly calendar is stacked vertically inside one shared card,
 * rather than switched between via tabs - a club comparing pitch usage wants to see every
 * resource at once, not one at a time. One nav bar (.djk-pitch-calendar__nav, below) replaces
 * FullCalendar's own per-instance prev/next/today/title chrome (disabled via headerToolbar:
 * false in viewer.js) and drives every stacked calendar to the same week together.
 */

/* Phase 7's vendored Tabler icon glyphs (see ICON_PATHS/buildIcon, viewer.js) - deliberately a
   bare top-level rule, not scoped under .djk-pitch-calendar, since the detail modal (appended
   straight to document.body, see .djk-event-modal below) also uses these icons and lives outside
   that container. Sized via `1em` so every call site scales automatically with its own
   surrounding font-size instead of needing a pixel value hardcoded per location; color comes from
   `currentColor` (stroke), so each call site tints it just by setting `color`. */
.djk-icon {
    width: 1em;
    height: 1em;
    fill: none;
    stroke: currentColor;
    stroke-width: 2;
    stroke-linecap: round;
    stroke-linejoin: round;
    vertical-align: -0.125em;
}

/* Visually hidden but still announced by screen readers (the standard clip-rect pattern, same
   shape as WP core's own .screen-reader-text / Bootstrap's .sr-only) - this plugin defines its
   own copy rather than relying on the active theme to provide one, since it's embedded in
   whatever theme a site happens to run and can't assume that class exists. Used (setIconText,
   viewer.js) for a text label dropped from VISIBLE display once an icon already conveys the same
   meaning to a sighted user - the icon itself is aria-hidden (decorative), so without this a
   screen-reader user would lose that context entirely. */
.djk-sr-only {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

/* Typography pass: previously this widget set no font-family of its own at all, silently
   inheriting whatever body font the host theme happened to use (and the modal below, appended
   straight to document.body, inherited a possibly DIFFERENT font again) - the actual "generic/
   templated" gap this pass addresses, more than any one font-size. Deliberately still a system
   stack, not a vendored webfont: this widget already follows a strict "vendor exactly what's
   used, nothing pulled from a CDN" rule for FullCalendar (see Plugin.php), and a font file is a
   second asset + a flash-of-invisible-text risk for one small embedded card - not worth it here.
   The distinctive part of this pass is the discipline applied on top of that plain stack, not the
   typeface itself: one clean scale (the rem steps below, reused literally everywhere a font-size
   is set - see the per-rule comments), tabular figures on every time-ish number so a stack of
   kickoff times lines up like a scoreboard rather than wobbling with each digit's natural width,
   uppercase+tracked labels for the day-of-week header (the same "tag" language the cancelled
   badge already used), and tightened letter-spacing on the two large bold headings (the toolbar
   title, the modal's team name) - small things that read as considered rather than inherited.
   Scale used throughout (rem): 0.62 / 0.7 / 0.78 / 0.85 / 0.95 / 1 / 1.15 / 1.3 - not expressed as
   custom properties, since the modal lives outside this element's cascade (same reason its colors
   already fall back to hardcoded literals below) and a parallel set of root-scoped variables would
   leak into the host page for no real benefit at this widget's size. */
.djk-pitch-calendar {
    --djk-accent: #1f9d55;
    --djk-accent-dark: #167a42;
    --djk-accent-soft: #e9f8ef;
    --djk-border: #e8eaee;
    --djk-text: #1f2430;
    --djk-text-muted: #6b7280;
    --djk-surface: #ffffff;
    --djk-surface-muted: #f6f7f9;
    --djk-radius: 16px;
    font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial,
        sans-serif;
    font-size: 0.95rem;
    line-height: 1.45;
    color: var(--djk-text);
    background: var(--djk-surface);
    border: 1px solid var(--djk-border);
    border-radius: var(--djk-radius);
    box-shadow: 0 1px 2px rgba(16, 24, 40, 0.04), 0 12px 28px rgba(16, 24, 40, 0.06);
    padding: 1.25rem;
}

/* The shared week navigator - replaces FullCalendar's own per-instance prev/next/today/title
   toolbar (disabled via headerToolbar: false in viewer.js) so every stacked pitch calendar moves
   to the same week together from one control, rather than N independently-scrolled toolbars that
   could drift onto different weeks.

   The track + meta sit close together on the left, not "buttons left, heading stranded far right
   with a dead gap between" (an earlier pass, corrected after review: a row of 3 separate flat
   gray boxes with a big empty middle is the generic default any component library produces
   unprompted, not a choice made for this widget) - the date range is what the buttons actually
   change, so it reads as one connected control when it sits right next to them. */
.djk-pitch-calendar__nav {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 0.85rem;
    margin-bottom: 0.85rem;
}

/* A fused segmented "track" - the same language this widget's old per-pitch tab row used before
   the stacked-layout redesign removed it (one light-gray groove, buttons floating borderless
   inside it) - rather than 3 individually bordered, evenly-spaced boxes. "Heute" reads as the
   track's own anchor point (today), styled like a raised, currently-active pill so it doesn't get
   lost between the two plain chevrons either side of it. */
.djk-pitch-calendar__nav-track {
    display: flex;
    align-items: center;
    gap: 0.15rem;
    background: var(--djk-surface-muted);
    border-radius: 999px;
    padding: 0.25rem;
}

.djk-pitch-calendar__nav-btn {
    border: none;
    border-radius: 999px;
    background: transparent;
    color: var(--djk-text-muted);
    cursor: pointer;
    padding: 0.45rem 0.8rem;
    font-size: 0.85rem;
    font-weight: 600;
    line-height: 1;
    transition: background-color 0.15s ease, color 0.15s ease, box-shadow 0.15s ease;
}

.djk-pitch-calendar__nav-btn:hover {
    color: var(--djk-text);
}

.djk-pitch-calendar__nav-btn:focus,
.djk-pitch-calendar__nav-btn:focus-visible {
    outline: none;
    box-shadow: 0 0 0 3px var(--djk-accent-soft);
}

.djk-pitch-calendar__nav-btn--today {
    background: var(--djk-surface);
    color: var(--djk-text);
    box-shadow: 0 1px 2px rgba(16, 24, 40, 0.08);
}

.djk-pitch-calendar__nav-btn--today:hover {
    color: var(--djk-accent-dark);
}

/* The prev/next chevrons are a touch narrower than the "Heute"/"Today" text button next to them -
   a fixed min-width keeps all three buttons from looking randomly mismatched in size. */
.djk-pitch-calendar__nav-track .djk-pitch-calendar__nav-btn:not(.djk-pitch-calendar__nav-btn--today) {
    min-width: 2.2rem;
    text-align: center;
}

.djk-pitch-calendar__nav-meta {
    display: flex;
    flex-direction: column;
    gap: 0.1rem;
}

/* The current week's date range (FullCalendar's own view.title, written here by handleDatesSet
   in viewer.js) - same "biggest bold text in the widget" treatment the old per-instance toolbar
   title had, now applied once for the whole stack instead of once per pitch, and sitting right
   next to the track that actually changes it rather than stranded at the far edge of the card. */
.djk-pitch-calendar__nav-title {
    margin: 0;
    font-size: 1.15rem;
    font-weight: 700;
    letter-spacing: -0.01em;
    font-variant-numeric: tabular-nums;
    color: var(--djk-text);
}

/* Hidden by default (updateSharedStatusDisplay, viewer.js) - shown only once every stacked
   pitch's own "last synced" timestamp actually agrees, in which case each per-section status
   line (.djk-pitch-calendar__status) is hidden in favor of this single shared one; falls back to
   the per-section lines whenever they genuinely differ. */
.djk-pitch-calendar__nav-status {
    margin: 0;
    color: var(--djk-text-muted);
    font-size: 0.72rem;
}

/* The vertical stack of per-pitch sections (renderPitchSections, viewer.js) - every physical
   pitch's own calendar renders here at once, in document order, rather than being switched
   between. */
.djk-pitch-calendar__pitches {
    display: flex;
    flex-direction: column;
    gap: 1.75rem;
}

/* A plain top divider between stacked sections (none on the first) rather than a second nested
   card per pitch - the widget itself is already one card (see .djk-pitch-calendar above); giving
   every section its own bordered box on top of that would read as boxes-within-a-box rather than
   one calm surface listing several resources. Tinted per pitch (--djk-pitch-accent, set inline by
   renderPitchSections in viewer.js, see PITCH_ACCENT_PALETTE there) rather than the plain neutral
   gray every divider used at first - confirmed live that 3+ stacked weekly grids otherwise look
   pixel-identical apart from their text label, with nothing to anchor "which section am I
   scrolled into" while skimming a long page. 3px (not the original 1px) so this thin colored line
   is actually perceptible as a deliberate marker rather than reading as a slightly-tinted hairline
   rule. */
.djk-pitch-calendar__pitch-section {
    padding-top: 1.5rem;
    border-top: 3px solid var(--djk-pitch-accent, var(--djk-border));
}

.djk-pitch-calendar__pitch-section:first-child {
    padding-top: 0;
    border-top: none;
}

/* flex-start, not baseline: a pitch name long enough to wrap onto two lines (a real case on a
   narrow screen, e.g. "Kunstrasenplatz" / "Jugend") otherwise baseline-aligns the status text
   against only the wrapped name's FIRST line, leaving the second line visually orphaned
   underneath with nothing next to it. */
.djk-pitch-calendar__pitch-header {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 0.75rem;
    margin-bottom: 0.6rem;
}

.djk-pitch-calendar__pitch-name {
    margin: 0;
    font-size: 1rem;
    font-weight: 700;
    letter-spacing: -0.005em;
    color: var(--djk-text);
    transition: color 0.15s ease, opacity 0.15s ease;
}

/* Same --djk-pitch-accent as the section's own top divider (set inline by renderPitchSections,
   viewer.js) - but the FIRST stacked section has no top divider at all (see :first-child below,
   no border needed right under the filter/highlight bar), which would otherwise leave it as the
   one section with no visible color identity. A small dot directly in the heading carries that
   same per-pitch color regardless of position in the stack. Independent of the has-match color
   change on the name's own text color above - this dot always shows WHICH pitch, the text color
   separately signals whether it currently matches a filter/highlight. */
.djk-pitch-calendar__pitch-name::before {
    content: '';
    display: inline-block;
    width: 8px;
    height: 8px;
    margin-right: 0.5em;
    border-radius: 999px;
    background: var(--djk-pitch-accent, var(--djk-border));
    vertical-align: middle;
}

.djk-pitch-calendar__status {
    margin: 0;
    color: var(--djk-text-muted);
    font-size: 0.72rem;
    white-space: nowrap;
}

/* The same "highlight other pitches with a matching event, fade the rest" affordance the old tab
   row gave (see updatePitchHighlighting, viewer.js), now applied to each stacked section's own
   heading - useful once there are more pitch sections than fit on one screen at a glance. With
   nothing active, neither class is set, so every heading stays plain/neutral. */
.djk-pitch-calendar__pitch-section.has-match .djk-pitch-calendar__pitch-name {
    color: var(--djk-accent);
}

/* A colored left bar, not just a text-color change - confirmed live that a heading's text color
   alone barely registers on a quick scroll past 3+ stacked sections, which defeats the whole
   point of this signal (the old tab row's bolder pill+ring treatment never had this problem,
   since it was a small isolated button, not a full-width heading). margin-left/padding-left
   cancel out so the heading's own text doesn't actually shift - only the bar itself appears, in
   the gutter that opens up to its left, like a small flag at the section's edge. */
.djk-pitch-calendar__pitch-section.has-match .djk-pitch-calendar__pitch-header {
    margin-left: -0.6rem;
    padding-left: 0.45rem;
    border-left: 3px solid var(--djk-accent);
}

.djk-pitch-calendar__pitch-section.no-match .djk-pitch-calendar__pitch-header {
    opacity: 0.45;
}

/* The day-of-week header row fades too, not just the section's own heading above it - a visitor
   scrolling past several stacked weeks should read "this pitch doesn't matter right now" from
   the grid itself, not only from a small heading that's easy to scroll straight past without
   registering. Individual events are already dimmed by the existing per-event .djk-event-dimmed
   rule; this just extends the same "this whole pitch is irrelevant right now" read to the one
   piece of grid chrome that wasn't covered by that. */
.djk-pitch-calendar__pitch-section.no-match .fc-col-header-cell-cushion {
    opacity: 0.45;
}

.djk-pitch-calendar__filters {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    margin-bottom: 0.85rem;
}

.djk-pitch-calendar__filter {
    padding: 0.5rem 0.75rem;
    border: 1px solid var(--djk-border);
    border-radius: 10px;
    background: var(--djk-surface-muted);
    color: var(--djk-text);
    font-size: 0.85rem;
    flex: 1 1 auto;
    min-width: 8rem;
    transition: border-color 0.15s ease, box-shadow 0.15s ease;
}

.djk-pitch-calendar__filter:hover {
    border-color: var(--djk-accent);
}

.djk-pitch-calendar__filter:focus {
    outline: none;
    border-color: var(--djk-accent);
    box-shadow: 0 0 0 3px var(--djk-accent-soft);
}

/* Every option in the gender filter - the "no filter" default (GENDER_ALL_GLYPH, "♀/♂") included
   - is a single Unicode Mars/Venus glyph (GENDER_GLYPHS/GENDER_ALL_GLYPH, viewer.js), not a word;
   there's deliberately no "All genders" text option any more. At the filter row's normal 0.85rem
   text size these read thin and small (most UI fonts don't draw them as bold pictographs),
   reported as "barely visible" even at the 1.3rem this rule used to be. Sizes the OPEN dropdown
   list's option rows - confirmed (real headless-Chrome screenshot, not assumed) that Chrome,
   unlike the popular assumption repeated in this rule's own earlier revision, does NOT carry an
   <option>'s own font-size into the CLOSED <select> box's rendered text at all - that part needs
   the separate select-level rule below instead. */
.djk-pitch-calendar__filter-option--glyph {
    font-size: 1.8rem;
    font-weight: 700;
}

/* The closed-box fix for the same problem the rule above only solves for the open dropdown list
   (see its comment) - sizes the <select> element itself, scoped to just the gender filter via its
   own data-filter attribute rather than a class, so it stays a one-off without a new JS-side hook.
   Safe to do for this filter specifically (unlike bumping every filter's font-size, which would
   visibly mismatch the row) because every one of its options, including the "no filter" default,
   is a short glyph rather than a word that could wrap or overflow at this size. */
.djk-pitch-calendar__filter[data-filter="gender"] {
    font-size: 1.3rem;
    font-weight: 700;
}

/* Fixed-height, both rows - the Clear pill AND the hint paragraph below it - always reserve
   their final space whether or not either is currently shown, so selecting/clearing a highlight
   never changes this bar's total height at all. Column layout to stack the two. Both children
   toggle via opacity/visibility (see each one's own rule below), never [hidden]/display: an
   earlier version had the hint toggle via [hidden], which - unlike the pill, already fixed this
   way - DID collapse its own space when shown/hidden, so selecting a highlight visibly pushed
   the calendar grid down a bit and clearing it pulled it back up. Reported live as "that
   behaviour is not good" - the exact same class of bug the pill's own opacity/visibility
   treatment was already written to avoid, just missed on the second element added below it. */
/* Reserved-space pattern matching .djk-pitch-calendar__clear-highlight: always holds its
   min-height in the layout so filter badges appearing/disappearing never shift the calendars
   down. Same approach as the clear-highlight button's own opacity/visibility trick. */
.djk-pitch-calendar__active-filters {
    display: flex;
    flex-wrap: wrap;
    align-content: flex-start;
    gap: 0.4rem;
    min-height: 2.3rem;
    box-sizing: border-box;
    margin-bottom: 0.4rem;
}

.djk-pitch-calendar__filter-badge {
    padding: 0.5rem 0.9rem;
    border: 1px solid transparent;
    border-radius: 10px;
    background: var(--djk-accent-soft);
    color: var(--djk-accent-dark);
    font-weight: 600;
    font-size: 0.85rem;
    cursor: pointer;
    transition: background-color 0.15s ease;
}

.djk-pitch-calendar__filter-badge:hover {
    background: var(--djk-accent);
    color: #fff;
}

.djk-pitch-calendar__highlight-bar {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    margin-bottom: 0.75rem;
}

.djk-pitch-calendar__highlight-bar > .djk-pitch-calendar__clear-highlight {
    min-height: 2.3rem;
    box-sizing: border-box;
}

/* Explains the two-step click interaction (first click highlights, second click - on the SAME,
   now-highlighted event - opens the detail modal) right at the moment it becomes relevant: found
   live, not in the original design, that nothing in the UI ever said a second click does
   something different, so a first-time visitor's single click produced an unexplained highlight
   with no obvious next step. Reserves its own line height (min-height, box-sizing) even while
   invisible - see the comment on .djk-pitch-calendar__highlight-bar above for why that's
   non-negotiable here, not just a nice-to-have. */
.djk-pitch-calendar__highlight-hint {
    margin: 0.4rem 0 0;
    min-height: 1.3em;
    box-sizing: content-box;
    font-size: 0.78rem;
    line-height: 1.3;
    color: var(--djk-text-muted);
    opacity: 0;
    visibility: hidden;
    transition: opacity 0.15s ease;
}

.djk-pitch-calendar__highlight-hint.is-visible {
    opacity: 1;
    visibility: visible;
}

/* Hidden via opacity/visibility, not display - visibility: hidden also correctly removes it from
   the tab order and the accessibility tree (same practical effect as [hidden] for assistive tech)
   without collapsing its reserved space in .djk-pitch-calendar__highlight-bar above. */
.djk-pitch-calendar__clear-highlight {
    padding: 0.5rem 0.9rem;
    border: 1px solid transparent;
    border-radius: 10px;
    background: var(--djk-accent-soft);
    color: var(--djk-accent-dark);
    font-weight: 600;
    font-size: 0.85rem;
    cursor: pointer;
    opacity: 0;
    visibility: hidden;
    transition: opacity 0.15s ease, background-color 0.15s ease;
}

.djk-pitch-calendar__clear-highlight:hover {
    background: var(--djk-accent);
    color: #fff;
}

.djk-pitch-calendar__clear-highlight.is-visible {
    opacity: 1;
    visibility: visible;
}

/* Plain text, shown once up front (not just during a scroll gesture) whenever the table is wider
   than its container at all - see updateScrollAffordance's own comment (viewer.js) for why this
   exists: found live that a phone showed only Monday's column with no visible scrollbar and
   nothing else hinting the rest of the week is one swipe away. Sits above the grid, not inside
   .djk-pitch-calendar__grid itself - that element is FullCalendar's own mount point and its
   contents get wiped out and rebuilt by FullCalendar on every render. */
.djk-pitch-calendar__scroll-hint {
    margin: 0 0 0.6rem;
    font-size: 0.78rem;
    color: var(--djk-text-muted);
}

.djk-pitch-calendar__grid {
    position: relative;
    transition: opacity 0.15s ease;
}

/* The dynamic half of the same scroll affordance: a soft fade at whichever edge still has more
   content past it, tracking the live scroll position (djk-has-scroll-left/right, toggled by
   updateScrollAffordance in viewer.js on scroll/resize/re-render) - the standard "there's more
   this way" cue, e.g. a horizontally scrolling list. Positioned on .djk-pitch-calendar__grid (a
   plain, never-recreated ancestor of the actual scrolling element, .fc-view-harness below) rather
   than on the scrolling element itself, so the fade stays correctly pinned to the *visible*
   edge regardless of how far the content has scrolled underneath it. pointer-events: none so the
   fade never blocks clicking the day headers/events it's drawn on top of. The gradient's solid
   end uses the card's own surface color so it convincingly fades into the card background rather
   than appearing as a flat tinted bar. */
.djk-pitch-calendar__grid::before,
.djk-pitch-calendar__grid::after {
    content: '';
    position: absolute;
    top: 0;
    bottom: 0;
    width: 28px;
    z-index: 2;
    pointer-events: none;
    opacity: 0;
    transition: opacity 0.15s ease;
}

.djk-pitch-calendar__grid::before {
    left: 0;
    background: linear-gradient(to right, var(--djk-surface), transparent);
}

.djk-pitch-calendar__grid::after {
    right: 0;
    background: linear-gradient(to left, var(--djk-surface), transparent);
}

.djk-pitch-calendar__grid.djk-has-scroll-left::before {
    opacity: 1;
}

.djk-pitch-calendar__grid.djk-has-scroll-right::after {
    opacity: 1;
}

/* overflow-x: auto, not hidden/visible: the actual minimum width that keeps event boxes legible
   (set on table.fc-scrollgrid via applyMinColumnWidth in viewer.js) can exceed a narrow phone
   screen's width on a busy week - intentionally, since shrinking columns indefinitely to avoid
   any scrolling is what made event text spill out past its own box's bounds in the first place
   (a real, reported bug). Scrolling horizontally on a phone is an accepted tradeoff for keeping
   the event boxes themselves readable.
   Deliberately scoped to .fc-view-harness (the day headers + grid body) rather than the whole
   .djk-pitch-calendar__grid/.fc element: putting it on the wider ancestor - as an earlier version
   of this did - made the header toolbar (prev/next/today + the date range title) scroll out of
   view right along with the grid, since it's a sibling INSIDE that same scrollable box, even
   though the toolbar itself never needed the extra width (user-reported: "the buttons and week
   descriptor above the calendar must stay in place"). Scoping the scroll to .fc-view-harness
   specifically leaves the toolbar - a sibling, not a descendant of it - completely unaffected. */
.djk-pitch-calendar__grid .fc-view-harness {
    overflow-x: auto;
}

/* FullCalendar applies its own ".fc" class - with "display: flex" - directly to this same
   element, injected via a dynamically-created <style> tag at construction time, which loads later
   than this stylesheet and ties the browser's own "[hidden] { display: none }" rule in
   specificity - the exact same bug class as the event modal above, hit a second time. !important
   here is deliberate: FullCalendar's own injected CSS is out of this project's control, so a
   plain higher-specificity rule isn't a reliable enough guarantee against whatever it does next. */
.djk-pitch-calendar__grid[hidden],
/* Same reasoning, applied preemptively this time: an empty week now hides just
   .fc-view-harness (the day headers + grid body), not the whole calendarEl, so the header
   toolbar's prev/next/today buttons stay usable - see compressEmptyRegions in viewer.js. */
.djk-pitch-calendar__grid .fc-view-harness[hidden] {
    display: none !important;
}

/* No "display" property here on purpose - a previous rule that set display unconditionally on a
   [hidden]-toggled element silently overrode the browser's own "[hidden] { display: none }" rule
   (equal specificity, this stylesheet loads later) and made that element permanently visible
   regardless of its hidden attribute - confirmed as a real, reported bug on the event modal.
   This element stays block-level (a <p>'s default), so [hidden] keeps working untouched. */
.djk-pitch-calendar__empty {
    padding: 3rem 1.5rem;
    text-align: center;
    color: var(--djk-text-muted);
    background: var(--djk-surface-muted);
    border: 1px dashed var(--djk-border);
    border-radius: 12px;
}

/* The next-upcoming-event icon (appendEventTypeIcon, viewer.js) sits inline with the surrounding
   centered text - this element deliberately stays block-level, not flex (see the comment above),
   so the icon needs its own margin-right for breathing room instead of a flex `gap`. */
.djk-pitch-calendar__empty .djk-icon {
    margin-right: 0.3em;
}

/* The combined empty-state (updateCombinedEmptyState/renderCombinedEmptyMessage, viewer.js) -
   replaces every stacked section's own .djk-pitch-calendar__empty box entirely, in favor of ONE
   shared box, whenever every pitch is empty the same week. Left-aligned (unlike the per-section
   box's centered single sentence above) since this one holds a heading plus a list - centered
   text reads awkwardly once it's no longer a single short sentence. */
.djk-pitch-calendar__all-empty {
    padding: 2rem 1.75rem;
    color: var(--djk-text-muted);
    background: var(--djk-surface-muted);
    border: 1px dashed var(--djk-border);
    border-radius: 12px;
}

.djk-pitch-calendar__all-empty-heading {
    margin: 0 0 1.25rem;
    color: var(--djk-text);
    font-size: 1rem;
    font-weight: 700;
}

.djk-pitch-calendar__all-empty-list-label {
    margin: 0 0 0.5rem;
    font-size: 0.7rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    color: var(--djk-text-muted);
}

.djk-pitch-calendar__all-empty-list {
    margin: 0;
    padding: 0;
    list-style: none;
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
}

.djk-pitch-calendar__all-empty-list li {
    display: flex;
    align-items: baseline;
    flex-wrap: wrap;
    gap: 0.2rem;
}

.djk-pitch-calendar__all-empty-list strong {
    color: var(--djk-text);
    font-weight: 700;
}

.djk-pitch-calendar__all-empty-list .djk-icon {
    margin: 0 0.2em;
}

/* FullCalendar's own elements are touch-friendly out of the box; just tone down default chrome
   to fit a calmer look and make tap targets a bit more generous on phones/tablets. */
.djk-pitch-calendar .fc {
    --fc-border-color: var(--djk-border);
    --fc-today-bg-color: var(--djk-accent-soft);
    --fc-now-indicator-color: var(--djk-accent);
    --fc-page-bg-color: transparent;
    --fc-neutral-bg-color: var(--djk-surface-muted);
    font-family: inherit;
}

/* The day-of-week header row - restyled away from FullCalendar's default saturated-blue
   borders toward the same flat, muted-surface language as the rest of this widget (filters, the
   shared nav bar), so the whole thing reads as one deliberately designed piece rather than "our
   controls" bolted onto "FullCalendar's defaults". The toolbar (prev/next/today + title) itself
   is disabled per-instance (headerToolbar: false, viewer.js) in favor of this widget's own shared
   .djk-pitch-calendar__nav bar above, so there's no .fc-toolbar-title/.fc-button to restyle here
   any more. */
.djk-pitch-calendar .fc-col-header-cell {
    background: var(--djk-surface-muted);
}

/* Uppercase + letter-spacing reads as a "label" rather than a "value" - the same tagging
   convention this widget already uses for the cancelled badge (also 0.03em) - which is exactly
   the role a day-of-week header plays (a column label, not data); the date number inside it
   benefits from the same tabular-nums treatment as the toolbar title above. */
.djk-pitch-calendar .fc-col-header-cell-cushion {
    padding: 0.6rem 0.4rem;
    color: var(--djk-text);
    font-weight: 700;
    font-size: 0.78rem;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    font-variant-numeric: tabular-nums;
    text-decoration: none;
}

/* tabular-nums so a stacked column of time labels (09:00, 09:15, 09:30, ...) lines up like a
   scoreboard instead of each digit claiming a slightly different width. */
.djk-pitch-calendar .fc-timegrid-slot-label-cushion {
    color: var(--djk-text-muted);
    font-size: 0.78rem;
    font-variant-numeric: tabular-nums;
}

/* FullCalendar default is 1.5em per 30-minute slot. At the calendar's ~15px base font that gives
   only ~57px for a 75-minute event — not enough for the time, title, location AND badge rows
   (which the .fc-event overflow:hidden comment below explains gets clipped when content won't fit).
   A title like "B-Juniorinnen-2" wraps to two lines in narrow columns, pushing the badge below
   the clipping boundary. 3em/slot gives ~91px for a 60-minute event and ~114px for 75 minutes,
   enough for all content rows even when the title wraps. */
.djk-pitch-calendar .fc .fc-timegrid-slot {
    height: 3em;
}

/* Color-coded per team via .djk-event-palette-N (assigned in eventClassNames, viewer.js) - a left
   accent border plus a softly tinted background, rather than one flat default color for every
   event, so a visitor can visually group a team's sessions across the week at a glance (the
   single biggest "looks dated" gap versus the referenced dashboard design: every event there was
   colour-coded, ours all looked identical). The custom properties default to the plain accent
   green so an event somehow missing a palette class (shouldn't happen, but no reason to render
   broken) still looks intentional rather than transparent/invisible. */
/* overflow: hidden here, not just on .djk-event-content below - found live on a narrow phone
   column: FullCalendar gives THIS element a fixed height computed from the event's actual time
   duration (it has to - that's what keeps the box aligned with the time-axis gridlines), but
   .djk-event-content has no height of its own, just `overflow: hidden` on itself - which clips
   nothing, since nothing overflows ITS OWN box; it simply grows to fit a narrow lane's wrapped
   time/title/location lines. Without a height constraint on THIS element too, that taller content
   box was rendering past .fc-event's own bottom edge with the default `overflow: visible` - fully
   legible text, just sitting in the plain grid background below the colored box it belonged to,
   looking exactly like a layout bug (reported live: "event descriptions go outside their boxes").
   `overflow: hidden` here clips any excess at the box's own edge instead - the colored background
   (and its rounded corners, since border-radius + overflow:hidden on the same element clips
   children to the rounded shape too) always fully contains whatever it's actually showing. A
   clipped bottom line (almost always the least-critical location annotation) is the accepted
   trade: the same info is always available via this element's own hover tooltip (eventDidMount)
   and the full detail modal on a second click, so nothing is actually lost, just not duplicated
   on-grid when there's no room for it. */
.djk-pitch-calendar .fc-event {
    cursor: pointer;
    border: none;
    border-left: 3px solid var(--djk-event-accent, var(--djk-accent));
    border-radius: 8px;
    background: var(--djk-event-bg, var(--djk-accent-soft));
    overflow: hidden;
    transition: opacity 0.15s ease, transform 0.15s ease, box-shadow 0.15s ease;
}

.djk-pitch-calendar .fc-event:hover {
    transform: translateY(-1px);
    box-shadow: 0 4px 10px rgba(16, 24, 40, 0.12);
}

.djk-event-palette-0 { --djk-event-accent: #2f9e6e; --djk-event-bg: #e7f7ef; }
.djk-event-palette-1 { --djk-event-accent: #6c5ce7; --djk-event-bg: #efedfd; }
.djk-event-palette-2 { --djk-event-accent: #e08e2f; --djk-event-bg: #fdf1e3; }
.djk-event-palette-3 { --djk-event-accent: #e0527a; --djk-event-bg: #fdebf0; }
.djk-event-palette-4 { --djk-event-accent: #2f8fe0; --djk-event-bg: #e7f2fd; }
.djk-event-palette-5 { --djk-event-accent: #14b8a6; --djk-event-bg: #e3faf7; }
.djk-event-palette-6 { --djk-event-accent: #a35ce0; --djk-event-bg: #f4ecfd; }
.djk-event-palette-7 { --djk-event-accent: #c2861a; --djk-event-bg: #fbf1de; }

/* Filtered-out or not-matching-the-current-highlight events fade rather than disappear (see
   eventClassNames in viewer.js) - keeps the week's spatial layout intact so a visitor can still
   see when/where everything else is happening, per the project plan's visual-design constraint
   ("fading out non-matching events on team-highlight" - extended here to filters too, same
   visual language for both). */
.djk-pitch-calendar .djk-event-dimmed {
    opacity: 0.18;
    cursor: default;
}

/* Cancelled (see eventClassNames/EventNormalizer's CANCELLED_TITLE_PREFIX in viewer.js) is a
   property of the session itself, not of the visitor's filter/highlight state - kept visually
   distinct from .djk-event-dimmed above (plain fade) so the two are never confused: a struck-
   through, desaturated chip that's still fully legible, not faded out of view. Stays at full
   opacity/size deliberately (see the project plan) - the point is showing "this would normally be
   training, but it's cancelled", not making the slot look empty. */
.djk-pitch-calendar .djk-event-cancelled {
    filter: saturate(0.35);
}

/* Targets the dedicated text spans (viewer.js), not .djk-event-title/.djk-event-location
   themselves - both elements can also hold a leading icon (gender, map-pin - see their own .djk-
   icon rules below), and text-decoration should only ever cross the text, never the glyph next
   to it. */
.djk-pitch-calendar .djk-event-cancelled .djk-event-title__text,
.djk-pitch-calendar .djk-event-cancelled .djk-event-location__text {
    text-decoration: line-through;
}

/* Training session displaced by a match on the same pitch: same desaturation as cancelled
   (pitch is unavailable either way) plus strikethrough, but a blue badge labelled "Spiel"
   instead of the grey "Cancelled" badge — makes clear WHY it's displaced. */
.djk-pitch-calendar .djk-event-displaced {
    filter: saturate(0.35);
}

.djk-pitch-calendar .djk-event-displaced .djk-event-time,
.djk-pitch-calendar .djk-event-displaced .djk-event-title__text,
.djk-pitch-calendar .djk-event-displaced .djk-event-location__text {
    text-decoration: line-through;
}

.djk-pitch-calendar .djk-event-displaced-badge {
    display: inline-flex;
    align-items: center;
    gap: 3px;
    margin-top: 2px;
    padding: 1px 6px;
    border-radius: 999px;
    background: #1d4ed8;
    color: #fff;
    font-size: 0.62rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.03em;
}

.djk-pitch-calendar .djk-event-displaced-badge .djk-icon {
    width: 0.95em;
    height: 0.95em;
    stroke-width: 3;
}

/* Phase 7: a real icon glyph (see ICON_PATHS/buildIcon in viewer.js), not the plain-text-only
   badge this used to be - kept the pill shape and "Cancelled" text alongside it rather than going
   icon-only, since a glyph alone would be ambiguous at this size with no established convention
   yet for what "cancelled" looks like. */
.djk-pitch-calendar .djk-event-cancelled-badge {
    display: inline-flex;
    align-items: center;
    gap: 3px;
    margin-top: 2px;
    padding: 1px 6px;
    border-radius: 999px;
    background: #4b5563;
    color: #fff;
    font-size: 0.62rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.03em;
}

/* Tiny badge context: a 1em icon at this font-size is only ~10px, where the icon set's normal
   2px stroke starts to look thin/muddy - thickened here so the glyph stays legible instead of
   shrinking proportionally with the text. */
.djk-pitch-calendar .djk-event-cancelled-badge .djk-icon {
    width: 0.95em;
    height: 0.95em;
    stroke-width: 3;
}

/* Custom event content (see viewer.js's eventContent): wraps instead of the default single-line
   truncation, since a narrow-but-tall column (the overlapping-events case this was written for)
   has the vertical room to show time/team/location stacked, where one truncated line couldn't. */
.djk-pitch-calendar .djk-event-content {
    padding: 2px 6px;
    line-height: 1.25;
    overflow: hidden;
    white-space: normal;
    /* overflow-wrap, not word-break: break-word - wraps at spaces first, only breaking mid-word
       (e.g. "Train" / "ing") as a last resort when a single word can't fit at all. */
    overflow-wrap: break-word;
}

/* Colored to match the event's own accent (the same variable driving .fc-event's left border
   above) - mirrors the referenced dashboard's pattern of a colored label line atop a neutral,
   bold detail line. Leading clock icon (Phase 7) inherits this same color automatically via
   currentColor - no separate icon color rule needed, unlike the title/location below where the
   icon deliberately wants its OWN opacity independent of the text. */
.djk-pitch-calendar .djk-event-time {
    display: flex;
    align-items: baseline;
    gap: 3px;
    font-size: 0.7rem;
    font-weight: 700;
    letter-spacing: 0.01em;
    font-variant-numeric: tabular-nums;
    color: var(--djk-event-accent, var(--djk-accent));
}

.djk-pitch-calendar .djk-event-title {
    display: flex;
    align-items: baseline;
    gap: 3px;
    font-size: 0.78rem;
    font-weight: 700;
    color: var(--djk-text);
}

/* Leading gender glyph (Phase 7, viewer.js's appendGenderIcon) - tinted with the SAME accent that
   colors this chip's left border and time label (.djk-event-time above, .djk-event-palette-N),
   not a generic gray, so even this small metadata mark reads as part of the team's own color
   identity rather than an unrelated system icon. Slightly translucent so it stays a secondary
   mark, never competing with the bold team name sitting right next to it. flex-shrink:0 keeps it
   from being squeezed if the name itself has to wrap in a narrow column. */
.djk-pitch-calendar .djk-event-title .djk-icon {
    flex-shrink: 0;
    color: var(--djk-event-accent, var(--djk-accent));
    opacity: 0.8;
}

.djk-pitch-calendar .djk-event-location {
    display: flex;
    align-items: baseline;
    gap: 3px;
    font-size: 0.7rem;
    color: var(--djk-text-muted);
}

.djk-pitch-calendar .djk-event-time .djk-icon,
.djk-pitch-calendar .djk-event-location .djk-icon {
    flex-shrink: 0;
    opacity: 0.85;
}

/* Event-category icon (Phase 7, appendEventTypeIcon) - overrides the per-team accent color the
   title/team-name's other icon (gender) uses, deliberately marking this one as a neutral,
   category-level fact rather than a team-specific one. Matched on specificity to reliably beat
   both the chip's .djk-event-title .djk-icon rule and the modal's .djk-event-modal__team .djk-icon
   rule above regardless of source order. Falls back to a hardcoded gray (matching --djk-text-
   muted's own value) since the modal lives outside .djk-pitch-calendar and can't read that custom
   property. */
.djk-pitch-calendar .djk-event-title .djk-icon--category,
.djk-event-modal__team .djk-icon--category {
    color: var(--djk-text-muted, #6b7280);
    opacity: 0.85;
}

@media (max-width: 699px) {
    .djk-pitch-calendar {
        padding: 1rem;
        border-radius: 12px;
    }

    .djk-pitch-calendar__nav-title {
        font-size: 1rem;
    }
}

/* Appended to document.body (not nested under .djk-pitch-calendar), so it overlays the whole
   page regardless of the calendar container's own size/overflow. */
.djk-event-modal {
    position: fixed;
    inset: 0;
    z-index: 1000;
    display: flex;
    align-items: center;
    justify-content: center;
}

/* The browser's own default stylesheet has a same-specificity "[hidden] { display: none }" rule
   - whichever rule comes later in the cascade wins a specificity tie, and since this stylesheet
   loads after the UA default, the unconditional "display: flex" above silently overrode it,
   making the modal permanently visible (and its close button/Escape/backdrop-click all
   ineffective, since they only ever set the hidden *attribute* - confirmed as the real cause by
   reproducing the "constant overlay, close button does nothing" report). This rule's higher
   specificity (an attribute selector chained onto the class) restores hidden's actual effect. */
.djk-event-modal[hidden] {
    display: none;
}

.djk-event-modal__backdrop {
    position: absolute;
    inset: 0;
    background: rgba(20, 20, 20, 0.5);
}

/* --djk-modal-accent is set inline by openModal (viewer.js) to the same per-team color driving
   that team's event chips on the grid (see .djk-event-palette-N above) - ties the popped-open
   detail view visually back to "which colored chip did I just click", the same continuity the
   referenced dashboard's colored "Coach: Name" label gives its own popover. Falls back to the
   plain accent green if somehow unset rather than rendering an invisible/transparent accent. */
/* font-family/line-height repeated here, not just relied on from .djk-pitch-calendar - this
   element is appended straight to document.body (see the comment above .djk-event-modal), so it
   sits outside that element's cascade entirely and would otherwise silently fall back to the host
   theme's own body font, the exact inconsistency the rest of this typography pass exists to
   close. */
.djk-event-modal__box {
    position: relative;
    background: #fff;
    border-radius: 18px;
    border-left: 5px solid var(--djk-modal-accent, #1f9d55);
    padding: 1.75rem;
    max-width: 90vw;
    width: 380px;
    max-height: 85vh;
    overflow-y: auto;
    font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial,
        sans-serif;
    line-height: 1.45;
    box-shadow: 0 24px 48px -12px rgba(16, 24, 40, 0.22), 0 4px 12px rgba(16, 24, 40, 0.08);
    animation: djk-modal-in 0.18s ease;
}

@keyframes djk-modal-in {
    from { opacity: 0; transform: translateY(8px); }
    to { opacity: 1; transform: translateY(0); }
}

.djk-event-modal__close {
    position: absolute;
    top: 0.85rem;
    right: 0.85rem;
    width: 28px;
    height: 28px;
    display: flex;
    align-items: center;
    justify-content: center;
    border: none;
    border-radius: 999px;
    background: #f3f4f6;
    font-size: 1.3rem;
    line-height: 1;
    cursor: pointer;
    color: #6b7280;
    transition: background-color 0.15s ease, color 0.15s ease;
}

.djk-event-modal__close:hover {
    background: #e5e7eb;
    color: #1f2430;
}

/* 1.3rem (this widget's largest scale step, also used by the gender-glyph filter option) rather
   than the previous one-off 1.25rem, and tightened to match the toolbar title's identical
   "biggest bold text in the widget" treatment above. */
.djk-event-modal__team {
    display: flex;
    align-items: baseline;
    gap: 5px;
    margin: 0 1.75rem 0.6rem 0;
    font-size: 1.3rem;
    font-weight: 700;
    letter-spacing: -0.01em;
    line-height: 1.25;
    color: var(--djk-modal-accent, #1f2430);
}

/* Same accent as the title text itself here (unlike the on-grid chip's more muted version) -
   the modal already gives the team name its full accent color, so the icon just shares it
   outright rather than needing its own opacity treatment to read as "secondary". */
.djk-event-modal__team .djk-icon {
    flex-shrink: 0;
}

/* Toggled in openModal (viewer.js) alongside .djk-event-modal__cancelled's `hidden` attribute -
   crosses out the team-name text span specifically (not .djk-event-modal__team itself, which can
   also hold the leading gender icon above) - mirrors the on-grid chip's identical
   .djk-event-cancelled .djk-event-title__text treatment. */
.djk-event-modal__team--cancelled .djk-event-modal__team-text {
    text-decoration: line-through;
}

/* Mirror of the cancelled modifier above, but for displaced: cross out all detail lines
   (team name, time, pitch, location) so the whole modal reads as "this slot is blocked". */
.djk-event-modal--displaced .djk-event-modal__team-text,
.djk-event-modal--displaced .djk-event-modal__datetime,
.djk-event-modal--displaced .djk-event-modal__pitch,
.djk-event-modal--displaced .djk-event-modal__location {
    text-decoration: line-through;
}

/* Blue notice badge — same structure/sizing as .djk-event-modal__cancelled but blue
   (matches the on-chip displaced badge color) and variable text (set per-event in
   openModal, viewer.js) so no static text content is baked in here. */
.djk-event-modal__displaced {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    margin: 0 0 0.6rem 0;
    padding: 2px 8px;
    border-radius: 999px;
    background: #1d4ed8;
    color: #fff;
    font-size: 0.7rem;
    font-weight: 700;
    letter-spacing: 0.03em;
}

.djk-event-modal__displaced[hidden] {
    display: none;
}

/* Phase 7: a real icon glyph (see ICON_PATHS/buildIcon, viewer.js), same as the on-grid badge.
   This element is always present in the modal markup and toggled via the `hidden` attribute
   (openModal, viewer.js) rather than added/removed from the DOM - so it needs an explicit
   [hidden] override below: a bare `.djk-event-modal__cancelled { display: inline-block }` has the
   exact same specificity as the browser's own `[hidden] { display: none }` rule, and author
   styles always win that tie regardless of source order, which made the badge render for every
   event regardless of whether it was actually cancelled (a real bug, caught by the user reporting
   it, not by review). */
.djk-event-modal__cancelled {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    margin: 0 0 0.6rem 0;
    padding: 2px 8px;
    border-radius: 999px;
    background: #4b5563;
    color: #fff;
    font-size: 0.7rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.03em;
}

.djk-event-modal__cancelled[hidden] {
    display: none;
}

/* 0.95rem, not the slightly-off 0.92rem this used to read - matching this widget's own root
   font-size exactly rather than an arbitrary near-neighbor of it. */
.djk-event-modal__datetime,
.djk-event-modal__pitch,
.djk-event-modal__location {
    margin: 0.35rem 0;
    color: #4b5563;
    font-size: 0.95rem;
}

.djk-event-modal__datetime {
    font-variant-numeric: tabular-nums;
}

/* Leading clock/soccer-field/map-pin icon (Phase 7). .djk-event-modal__pitch uses a literal
   football-pitch glyph (soccer-field), not another map-pin - it names the physical venue itself
   ("Pitch: <name>"), a genuinely different fact from .djk-event-modal__location's pin, which
   marks WHERE within that pitch the booked sub-unit sits. Two different pin-shaped icons for
   those two different things would have read as one repeated, confusing "where" glyph; a
   dedicated pitch glyph keeps them visually distinct instead. */
.djk-event-modal__datetime,
.djk-event-modal__pitch,
.djk-event-modal__location {
    display: flex;
    align-items: baseline;
    gap: 5px;
}

.djk-event-modal__datetime .djk-icon,
.djk-event-modal__pitch .djk-icon,
.djk-event-modal__location .djk-icon {
    flex-shrink: 0;
    opacity: 0.85;
}

.djk-event-modal__schematic {
    margin-top: 1.25rem;
}

.djk-pitch-schematic {
    width: 100%;
    height: auto;
    border-radius: 10px;
    background: #f0fbf4;
}

.djk-pitch-outline {
    fill: none;
    stroke: #1f9d55;
    stroke-width: 2;
}

.djk-pitch-highlight {
    fill: #1f9d55;
    fill-opacity: 0.55;
}

.djk-event-modal__schematic-caption {
    margin: 0.6rem 0 0;
    font-size: 0.78rem;
    color: #6b7280;
}

/* The real Phase 4 satellite view (see buildPhotoOverlay in viewer.js). Percentage-based left/
   top/width on an absolutely positioned element resolve against its *containing block* (the
   nearest positioned ancestor) - those percentages track the image correctly because the image
   itself is rendered at one fixed CSS width (no more zoom-toggle resize - see below), so its
   containing block's rendered size never changes.
   .djk-photo-overlay is now a fixed-size, non-scrolling "window" (overflow: hidden, a set width)
   - this is deliberate: the modal box around it must never change size, including during the
   zoom animation below, so the only thing allowed to move/scale is the INNER
   .djk-photo-overlay__scroll element via `transform` (which doesn't affect layout size at all);
   anything that scales past the window's edges is simply clipped by overflow: hidden. */
.djk-photo-overlay {
    border-radius: 10px;
    width: 320px;
    max-width: 100%;
    overflow: hidden;
}

/* Replaces the old tap/click-to-zoom toggle (removed per feedback - not discoverable, and it
   resized .djk-photo-overlay itself, which leaked into the modal box around it). The loop itself
   is driven entirely from JS (buildPhotoOverlay's startZoomLoop(), via requestAnimationFrame),
   not a CSS `@keyframes` animation - tried that first, but a CSS keyframe referencing a custom
   property via var() can only pick up this element's *computed* zoom target after it's been laid
   out, i.e. after the animation would already have started, and browsers differ on whether a
   later change to that custom property still updates an already-running animation (some resolve
   it once at start and never revisit it) - confirmed as a real no-op in at least one browser.
   Animating `transform` directly via JS, rather than width/height, is what keeps every ancestor's
   box - including the event modal - a fixed size throughout: a CSS transform is purely visual and
   never participates in layout. transform-origin is set by startZoomLoop() to center the zoom on
   the actual highlighted pitch; `center center` here is just a safe pre-JS default. */
.djk-photo-overlay__scroll {
    position: relative;
    display: inline-block;
    transform-origin: center center;
}

.djk-photo-overlay__image {
    display: block;
    width: 320px;
    height: auto;
}

/* Rotated to match the pitch's own drawn outline (see buildPhotoOverlay's layoutFrame) -
   transform-origin: top left matches how its left/top/width/height are set (the un-rotated
   origin corner), the same convention admin-geometry.js's preview uses while drawing. */
.djk-photo-overlay__frame {
    position: absolute;
    top: 0;
    left: 0;
    box-sizing: border-box;
    transform-origin: top left;
    pointer-events: none;
}

/* A plain child of the (already rotated) frame above - its own percentage left/top/width/height
   resolve against the frame's box, so it inherits the frame's rotation automatically with no
   extra rotation math needed here at all; only the frame itself needs that. border-box, not the
   default content-box - otherwise the border would add to the percentage-based width/height
   instead of rendering within them, leaving the highlight a few pixels larger than the unit it's
   meant to mark (confirmed previously by measuring 116px/124px rendered vs the 112px/120px the
   fractional math actually computed, before this fix).
   Color is deliberately NOT this stylesheet's usual --djk-accent green - a real satellite photo of
   a football pitch is itself mostly green grass, so a green highlight barely stands out against
   it. #e0218a is green's rough complement (opposite it on the color wheel), chosen specifically
   for contrast against grass rather than to match the site's own accent color. */
.djk-photo-overlay__highlight {
    position: absolute;
    box-sizing: border-box;
    border: 2px solid #e0218a;
    background: rgba(224, 33, 138, 0.35);
    pointer-events: none;
}

/* Planning mode: "Freie Plätze" toggle button - sits in the filter bar alongside the <select>
   dropdowns. Styled as a pill that matches the selects' height/border-radius but fills with the
   pitch accent color when active (is-active) so it reads as a distinct mode toggle, not just
   another filter. aria-pressed tracks the toggle state for screen readers. */
.djk-pitch-calendar__free-pitches-btn {
    padding: 0.5rem 0.9rem;
    border: 1.5px solid var(--djk-accent);
    border-radius: 10px;
    background: transparent;
    color: var(--djk-accent-dark);
    font-size: 0.85rem;
    font-weight: 600;
    cursor: pointer;
    white-space: nowrap;
    transition: background-color 0.15s ease, color 0.15s ease, box-shadow 0.15s ease;
}

.djk-pitch-calendar__free-pitches-btn:hover {
    background: var(--djk-accent-soft);
}

.djk-pitch-calendar__free-pitches-btn:focus,
.djk-pitch-calendar__free-pitches-btn:focus-visible {
    outline: none;
    box-shadow: 0 0 0 3px var(--djk-accent-soft);
}

.djk-pitch-calendar__free-pitches-btn.is-active {
    background: var(--djk-accent);
    color: #fff;
    border-color: var(--djk-accent);
}

.djk-pitch-calendar__free-pitches-btn.is-active:hover {
    background: var(--djk-accent-dark);
    border-color: var(--djk-accent-dark);
}

/* Free-slot background events (FullCalendar display:'background'): semi-transparent green with a
   dashed border so they read as "available space", not a booked session. cursor:pointer signals
   they're clickable (opens the free-pitch detail modal). The !important on background overrides
   FullCalendar's own .fc-bg-event background-color inline style, which is always set and would
   otherwise take precedence over this class-based rule. */
.fc-bg-event.djk-free-slot {
    background: rgba(44, 182, 125, 0.32) !important;
    border-left: 3px dashed #2cb67d;
    border-right: 3px dashed #2cb67d;
    border-top: 2px dashed #2cb67d;
    border-bottom: 2px dashed #2cb67d;
    cursor: pointer;
    transition: background-color 0.12s ease;
}

.fc-bg-event.djk-free-slot:hover {
    background: rgba(44, 182, 125, 0.48) !important;
}
