/* =============================================================================
   Organic Calendar
   Month grid of organic blobs + expanded "event universe" day view.

   Paired with widgets/OrganicCalendarWidget.php and web/js/organic-calendar.js.

   Theming: everything reads the shared tokens from variables.css, so light and
   dark come for free. Only the field backdrop and a couple of glows need an
   explicit [data-theme="dark"] tweak, because they are luminance effects rather
   than flat colours.

   Sizing: each day carries its own --oc-d (desktop) and --oc-m (mobile) blob
   diameter as inline custom properties, computed server-side. The grid carries
   --oc-max-d / --oc-max-m so a row can reserve height for the largest possible
   blob plus its badge, which is what stops a busy day from overlapping the row
   below it.
   ============================================================================= */

.organic-calendar {
    --oc-gap: 0.5rem;
    --oc-badge: 22px;
    --oc-empty-bg: var(--bg-tertiary, #f4f4f5);
    --oc-empty-border: var(--border-muted, #f1f1f2);
    --oc-active-bg: color-mix(in srgb, var(--color-primary-500, #6366f1) 18%, transparent);
    --oc-active-border: color-mix(in srgb, var(--color-primary-500, #6366f1) 55%, transparent);
    --oc-active-glow: color-mix(in srgb, var(--color-primary-500, #6366f1) 22%, transparent);

    position: relative;
    color: var(--text-primary, #18181b);
}

/* Browsers without color-mix still need a usable calendar. */
@supports not (color: color-mix(in srgb, red 50%, blue)) {
    .organic-calendar {
        --oc-active-bg: rgba(99, 102, 241, 0.18);
        --oc-active-border: rgba(99, 102, 241, 0.55);
        --oc-active-glow: rgba(99, 102, 241, 0.22);
    }
}

/* -----------------------------------------------------------------------------
   Header: month nav, running total, legend
   -------------------------------------------------------------------------- */

.organic-calendar .oc-head {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.75rem 1.25rem;
    margin-bottom: 1.25rem;
}

.organic-calendar .oc-head-left {
    display: flex;
    align-items: baseline;
    gap: 0.75rem;
    min-width: 0;
}

.organic-calendar .oc-monthbar {
    display: flex;
    align-items: center;
    gap: 0.35rem;
}

.organic-calendar .oc-month-label {
    font-size: 1.15rem;
    font-weight: var(--font-weight-semibold, 600);
    min-width: 9ch;
}

.organic-calendar .oc-total {
    color: var(--text-muted, #71717a);
    font-size: 0.9rem;
    white-space: nowrap;
}

.organic-calendar .oc-nav {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    border: 1px solid var(--border-default, #e4e4e7);
    border-radius: 50%;
    background: transparent;
    color: inherit;
    cursor: pointer;
    transition: background-color 0.15s ease, border-color 0.15s ease;
}

.organic-calendar .oc-nav:hover:not(:disabled) {
    background: var(--control-bg-hover, #fafafa);
    border-color: var(--border-strong, #d4d4d8);
}

.organic-calendar .oc-nav:disabled {
    opacity: 0.35;
    cursor: default;
}

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

.organic-calendar .oc-legend {
    display: flex;
    align-items: center;
    gap: 0.35rem 0.85rem;
    flex-wrap: wrap;
    margin-inline-start: auto;
}

.organic-calendar .oc-legend-item {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    padding: 0.25rem 0.5rem;
    border: 1px solid transparent;
    border-radius: 999px;
    background: transparent;
    color: var(--text-secondary, #52525b);
    font-size: 0.85rem;
    line-height: 1.2;
    white-space: nowrap;
}

button.oc-legend-item {
    cursor: pointer;
    transition: background-color 0.15s ease, opacity 0.15s ease;
}

button.oc-legend-item:hover {
    background: var(--control-bg-hover, #fafafa);
}

/* A filtered-out category is dimmed AND struck through, so the state never
   depends on colour alone. */
button.oc-legend-item[aria-pressed="false"] {
    opacity: 0.45;
}

button.oc-legend-item[aria-pressed="false"] .oc-legend-label {
    text-decoration: line-through;
}

.organic-calendar .oc-legend-dot {
    width: 10px;
    height: 10px;
    border-radius: 50%;
    flex: none;
}

/* Legend beside the grid on wide screens.

   The rail is a sibling of the views (not a child of the header), so the root
   becomes a two-column grid and every block is placed by area. The preview card
   is position:absolute and therefore never becomes a grid item. */
@media (min-width: 992px) {
    .organic-calendar.oc-legend-side {
        display: grid;
        grid-template-columns: minmax(0, 1fr) max-content;
        grid-template-areas:
            "head   legend"
            "month  legend"
            "day    legend";
        column-gap: 1.5rem;
        align-items: start;
    }

    .organic-calendar.oc-legend-side .oc-head {
        grid-area: head;
    }

    .organic-calendar.oc-legend-side .oc-legend-rail {
        grid-area: legend;
        flex-direction: column;
        align-items: flex-start;
        gap: 0.35rem;
        margin-inline-start: 0;
        position: sticky;
        top: 1rem;
    }

    .organic-calendar.oc-legend-side [data-oc-view="month"] {
        grid-area: month;
    }

    .organic-calendar.oc-legend-side [data-oc-view="day"] {
        grid-area: day;
    }

    /* Standalone fullscreen rows span the whole width rather than fighting the
       rail for a column. */
    .organic-calendar.oc-legend-side .oc-fullscreen-row {
        grid-column: 1 / -1;
    }
}

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

.organic-calendar .oc-dow,
.organic-calendar .oc-grid {
    display: grid;
    grid-template-columns: repeat(7, minmax(0, 1fr));
    gap: var(--oc-gap);
}

.organic-calendar .oc-dow {
    margin-bottom: 0.5rem;
}

.organic-calendar .oc-dow-cell {
    text-align: center;
    font-size: 0.8rem;
    color: var(--text-muted, #71717a);
}

.organic-calendar .oc-dow-narrow {
    display: none;
}

/* Reserve room for the biggest blob plus the badge that hangs off its corner,
   so neighbouring rows can never collide. */
.organic-calendar .oc-grid {
    grid-auto-rows: minmax(calc(var(--oc-max-d, 92px) + 0.75rem), auto);
}

.organic-calendar .oc-cell {
    display: flex;
    align-items: center;
    justify-content: center;
    min-width: 0;
}

.organic-calendar .oc-day {
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    /* The configured diameter is a ceiling, not a promise: seven columns of a
       narrow container can be thinner than the busiest blob, and a blob wider
       than its cell would overlap its neighbours.
       --oc-rd is this day's share of the largest blob, so when pixels do not
       fit the ladder degrades to a proportion of the cell instead of every
       blob flattening to the same clamped width - the size encoding is the
       whole point, and it has to survive a 320px screen. */
    width: min(var(--oc-d, 42px), calc(var(--oc-rd, 1) * 100%));
    height: auto;
    aspect-ratio: 1 / 1;
    border-radius: var(--oc-shape, 50%);
    padding: 0;
    font-variant-numeric: tabular-nums;
    line-height: 1;
}

.organic-calendar .oc-day-num {
    position: relative;
    z-index: 1;
    font-size: clamp(0.75rem, calc(var(--oc-d, 42px) * 0.28), 1.15rem);
    font-weight: var(--font-weight-medium, 500);
}

/* Empty days: small, quiet, inert. */
.organic-calendar .oc-day-empty {
    background: var(--oc-empty-bg);
    border: 1px solid var(--oc-empty-border);
    color: var(--text-tertiary, #a1a1aa);
    border-radius: 50%;
}

/* Active days: the organic blob.

   --oc-fill / --oc-stroke are written per day from the categories it holds:
   a flat tint for a single-category day, a conic gradient split by event count
   for a mixed one. They fall back to the primary tint when the calendar has no
   category data to colour by. */
.organic-calendar .oc-day-active {
    background: var(--oc-fill, var(--oc-active-bg));
    border: 1px solid var(--oc-stroke, var(--oc-active-border));
    color: var(--text-primary, #18181b);
    cursor: pointer;
    box-shadow: 0 0 0 0 var(--oc-active-glow);
    transition: transform 0.25s ease, box-shadow 0.25s ease, background-color 0.2s ease;
}

.organic-calendar .oc-day-active:hover,
.organic-calendar .oc-day-active:focus-visible {
    transform: scale(1.06);
    box-shadow: 0 0 0 6px var(--oc-active-glow);
}

.organic-calendar .oc-day-active:focus-visible {
    outline: 2px solid var(--focus-ring, #6366f1);
    outline-offset: 3px;
}

/* Today reads as a ring rather than a fill, so it cannot be confused with the
   "has events" state. */
.organic-calendar .oc-day-today::after {
    content: "";
    position: absolute;
    inset: -4px;
    border-radius: inherit;
    border: 1px dashed var(--color-primary-500, #6366f1);
    opacity: 0.7;
    pointer-events: none;
}

/* A day filtered out by the legend stays in place (the grid must not reflow)
   but recedes. */
.organic-calendar .oc-day-active.oc-day-dimmed {
    opacity: 0.25;
    filter: saturate(0.3);
}

/* Count badge ----------------------------------------------------------- */

.organic-calendar .oc-badge {
    position: absolute;
    top: -6px;
    right: -6px;
    z-index: 2;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    /* Floors, not proportions: the badge on a 1-event blob must stay readable
       even though its parent is at the small end of the scale. */
    min-width: var(--oc-badge);
    height: var(--oc-badge);
    padding: 0 5px;
    border-radius: 45% 55% 52% 48% / 50% 48% 52% 50%;
    background: var(--color-primary-500, #6366f1);
    color: #fff;
    font-size: 0.72rem;
    font-weight: var(--font-weight-semibold, 600);
    line-height: 1;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25);
}

/* Moon marker ------------------------------------------------------------
   A satellite chip mirroring the count badge's corner (top-left instead of
   top-right), so the two read as siblings of one system. Quiet by design -
   it is ambient sky data, not something the visitor is counting, so it uses
   the same muted surface as an empty-day blob rather than the accent colour
   the count badge earns. Both active AND empty days can carry one. */
.organic-calendar .oc-moon {
    position: absolute;
    top: -6px;
    left: -6px;
    z-index: 2;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: var(--oc-badge);
    height: var(--oc-badge);
    padding: 0 3px;
    /* Mirror of .oc-badge's border-radius, so the two shapes look like the
       same capsule flipped rather than two unrelated blobs. */
    border-radius: 55% 45% 48% 52% / 48% 50% 50% 52%;
    background: var(--oc-empty-bg);
    border: 1px solid var(--oc-empty-border);
    font-size: 0.72rem;
    line-height: 1;
    cursor: help;
}

/* -----------------------------------------------------------------------------
   Expanded day: the event universe
   -------------------------------------------------------------------------- */

.organic-calendar .oc-expanded[hidden] {
    display: none;
}

.organic-calendar .oc-expanded-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    margin-bottom: 1rem;
}

.organic-calendar .oc-back {
    display: inline-flex;
    align-items: center;
    padding: 0.4rem 0.9rem;
    border: 1px solid var(--border-default, #e4e4e7);
    border-radius: 999px;
    background: transparent;
    color: inherit;
    cursor: pointer;
    font-size: 0.9rem;
}

.organic-calendar .oc-back:hover {
    background: var(--control-bg-hover, #fafafa);
}

.organic-calendar .oc-expanded-meta {
    text-align: right;
    line-height: 1.3;
}

.organic-calendar .oc-day-title {
    display: block;
    font-size: 1.05rem;
}

.organic-calendar .oc-day-count {
    color: var(--text-muted, #71717a);
    font-size: 0.85rem;
}

.organic-calendar .oc-day-sun {
    display: block;
    color: var(--text-muted, #71717a);
    font-size: 0.8rem;
    margin-top: 0.15rem;
}

.organic-calendar .oc-day-sun[hidden] {
    display: none;
}

/* The field: a soft, deep backdrop the bubbles float in. */
.organic-calendar .oc-field {
    position: relative;
    width: 100%;
    /* Capped and centred: stretched to a 1400px viewport the field becomes a
       very flat ellipse and the constellation reads as a wide band rather than
       a small world. */
    max-width: 760px;
    margin-inline: auto;
    min-height: 420px;
    /* A rounded field rather than a true ellipse. A 50%/42% ellipse cuts its
       own corners off, and bubbles placed on the outer ring at 45 degrees end
       up straddling the edge. The decorative rings inside stay elliptical. */
    border-radius: 28% / 22%;
    background:
        radial-gradient(circle at 50% 50%,
            color-mix(in srgb, var(--color-primary-500, #6366f1) 12%, transparent) 0%,
            transparent 70%),
        var(--bg-secondary, #fafafa);
    overflow: hidden;
}

@supports not (color: color-mix(in srgb, red 50%, blue)) {
    .organic-calendar .oc-field {
        background: radial-gradient(circle at 50% 50%, rgba(99, 102, 241, 0.12) 0%, transparent 70%), var(--bg-secondary, #fafafa);
    }
}

/* Faint orbit rings - decoration only, hidden from assistive tech. */
.organic-calendar .oc-field-ring {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    border: 1px solid var(--border-muted, #f1f1f2);
    border-radius: 50%;
    opacity: 0.6;
    pointer-events: none;
}

.organic-calendar .oc-field-ring-1 {
    width: 46%;
    height: 46%;
}

.organic-calendar .oc-field-ring-2 {
    width: 74%;
    height: 74%;
}

/* The date at the centre of its own little world. */
.organic-calendar .oc-core {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    width: 118px;
    height: 118px;
    border-radius: 50%;
    background: var(--color-primary-400, #818cf8);
    color: #fff;
    text-align: center;
    font-weight: var(--font-weight-semibold, 600);
    line-height: 1.2;
    pointer-events: none;
}

.organic-calendar .oc-core-day {
    font-size: 1.5rem;
}

.organic-calendar .oc-core-month {
    font-size: 0.85rem;
    font-weight: var(--font-weight-normal, 400);
}

.organic-calendar .oc-bubbles {
    list-style: none;
    margin: 0;
    padding: 0;
    position: absolute;
    inset: 0;
}

.organic-calendar .oc-bubble-item {
    position: absolute;
    /* left/top are written by JS as percentages of the field. */
    transform: translate(-50%, -50%);
}

.organic-calendar .oc-bubble {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    width: var(--oc-bubble, 128px);
    height: var(--oc-bubble, 128px);
    padding: 0.5rem;
    border-radius: var(--oc-shape, 50%);
    border: 2px solid var(--oc-cat, #6366f1);
    background: color-mix(in srgb, var(--oc-cat, #6366f1) 22%, var(--bg-primary, #fff));
    color: var(--text-primary, #18181b);
    text-align: center;
    text-decoration: none;
    line-height: 1.2;
    transition: transform 0.2s ease, box-shadow 0.2s ease;
}

@supports not (color: color-mix(in srgb, red 50%, blue)) {
    .organic-calendar .oc-bubble {
        background: var(--bg-primary, #fff);
    }
}

.organic-calendar .oc-bubble:hover,
.organic-calendar .oc-bubble:focus-visible {
    transform: scale(1.05);
    box-shadow: 0 6px 18px rgba(0, 0, 0, 0.18);
}

.organic-calendar .oc-bubble:focus-visible {
    outline: 2px solid var(--focus-ring, #6366f1);
    outline-offset: 3px;
}

.organic-calendar .oc-bubble-title {
    font-size: 0.85rem;
    font-weight: var(--font-weight-semibold, 600);
    /* Clamp rather than shrink: the brief forbids text below an accessible
       size, so a long title truncates and the full text lives in the preview
       and the accessible name. */
    display: -webkit-box;
    -webkit-line-clamp: 3;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.organic-calendar .oc-bubble-time {
    margin-top: 0.2rem;
    font-size: 0.75rem;
    opacity: 0.85;
}

.organic-calendar .oc-hint {
    margin: 0.75rem 0 0;
    text-align: center;
    color: var(--text-muted, #71717a);
    font-size: 0.85rem;
}

/* List arrangement - used by the `list` layout and by every small screen. */
.organic-calendar .oc-bubbles.oc-bubbles-list {
    position: static;
    display: flex;
    flex-direction: column;
    gap: 0.6rem;
    padding: 0.75rem;
}

.organic-calendar .oc-bubbles-list .oc-bubble-item {
    position: static;
    transform: none;
}

.organic-calendar .oc-bubbles-list .oc-bubble {
    flex-direction: row;
    align-items: center;
    justify-content: flex-start;
    gap: 0.75rem;
    width: 100%;
    height: auto;
    min-height: 56px;
    padding: 0.7rem 0.9rem;
    border-radius: 14px;
    text-align: left;
}

.organic-calendar .oc-bubbles-list .oc-bubble-title {
    -webkit-line-clamp: 2;
    flex: 1 1 auto;
}

.organic-calendar .oc-bubbles-list .oc-bubble-time {
    margin-top: 0;
    flex: none;
    font-variant-numeric: tabular-nums;
}

/* -----------------------------------------------------------------------------
   Hover / focus preview
   -------------------------------------------------------------------------- */

.organic-calendar .oc-preview {
    position: absolute;
    z-index: 30;
    width: min(280px, 80vw);
    padding: 0.75rem 0.9rem;
    border: 1px solid var(--border-default, #e4e4e7);
    border-radius: var(--radius-lg, 12px);
    background: var(--bg-primary, #fff);
    box-shadow: var(--shadow-lg, 0 10px 24px rgba(0, 0, 0, 0.15));
    font-size: 0.85rem;
    line-height: 1.45;
    pointer-events: none;
}

.organic-calendar .oc-preview[hidden] {
    display: none;
}

.organic-calendar .oc-preview-title {
    display: block;
    font-weight: var(--font-weight-semibold, 600);
    margin-bottom: 0.25rem;
}

.organic-calendar .oc-preview-cat {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    margin-bottom: 0.35rem;
    color: var(--text-secondary, #52525b);
}

.organic-calendar .oc-preview-row {
    display: block;
    color: var(--text-secondary, #52525b);
}

.organic-calendar .oc-preview-price {
    display: inline-block;
    margin-top: 0.35rem;
    font-weight: var(--font-weight-medium, 500);
}

/* EVC-015: Detail font. --oc-detail-font is set inline on .organic-calendar
   (widgets/OrganicCalendarWidget.php) only when config[detailFont] resolves
   to a role; unset falls through to "inherit" - i.e. whatever font already
   applies here (the section's Body font, or the site default). Covers both
   the constellation bubble titles/times and the tapped-day preview panel -
   the two places event detail text renders. */
.organic-calendar .oc-bubble-title,
.organic-calendar .oc-bubble-time,
.organic-calendar .oc-preview-title,
.organic-calendar .oc-preview-cat,
.organic-calendar .oc-preview-row,
.organic-calendar .oc-preview-price {
    font-family: var(--oc-detail-font, inherit);
}

/* -----------------------------------------------------------------------------
   Chrome
   -------------------------------------------------------------------------- */

.organic-calendar .oc-fullscreen-row {
    display: flex;
    justify-content: flex-end;
    margin-bottom: 0.75rem;
}

.organic-calendar .oc-loading {
    opacity: 0.5;
    transition: opacity 0.15s ease;
}

.organic-calendar .oc-error {
    margin-top: 0.75rem;
    color: var(--color-danger-600, #dc2626);
    font-size: 0.85rem;
    text-align: center;
}

/* Visually hidden but reachable by assistive tech. Used for the live region
   that announces month and day changes. */
.organic-calendar .oc-sr {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

/* -----------------------------------------------------------------------------
   Dark theme
   Tokens flip on their own; these are the luminance effects that do not.
   -------------------------------------------------------------------------- */

[data-theme="dark"] .organic-calendar {
    --oc-empty-bg: rgba(255, 255, 255, 0.04);
    --oc-empty-border: rgba(255, 255, 255, 0.08);
}

[data-theme="dark"] .organic-calendar .oc-field {
    background:
        radial-gradient(circle at 50% 45%, rgba(129, 140, 248, 0.22) 0%, transparent 65%),
        rgba(255, 255, 255, 0.03);
}

[data-theme="dark"] .organic-calendar .oc-field-ring {
    border-color: rgba(255, 255, 255, 0.08);
}

[data-theme="dark"] .organic-calendar .oc-bubble {
    background: color-mix(in srgb, var(--oc-cat, #6366f1) 30%, #1c1c22);
    color: #f4f4f5;
}

[data-theme="dark"] .organic-calendar .oc-badge {
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.5);
}

/* =============================================================================
   Mobile and touch

   Two independent axes, deliberately not conflated:
     - width  (max-width: 767.98px) decides layout and sizing;
     - pointer (hover: none) decides interaction.
   A touch laptop is wide but has no hover; a narrow desktop window has hover
   but no room. Each gets the right treatment.
   ============================================================================= */

@media (max-width: 767.98px) {
    .organic-calendar {
        --oc-gap: 0.35rem;
        --oc-badge: 18px;
    }

    .organic-calendar .oc-head {
        gap: 0.5rem 0.75rem;
        margin-bottom: 0.9rem;
    }

    .organic-calendar .oc-month-label {
        font-size: 1rem;
    }

    /* Three "Mon Tue Wed" headers do not fit 320px; the narrow form does. */
    .organic-calendar .oc-dow-short {
        display: none;
    }

    .organic-calendar .oc-dow-narrow {
        display: inline;
    }

    .organic-calendar .oc-day {
        width: min(var(--oc-m, 35px), calc(var(--oc-rm, 1) * 100%));
    }

    .organic-calendar .oc-day-num {
        font-size: clamp(0.7rem, calc(var(--oc-m, 35px) * 0.32), 0.95rem);
    }

    .organic-calendar .oc-grid {
        grid-auto-rows: minmax(calc(var(--oc-max-m, 50px) + 0.6rem), auto);
    }

    .organic-calendar .oc-badge {
        top: -5px;
        right: -5px;
        font-size: 0.65rem;
        padding: 0 4px;
    }

    .organic-calendar .oc-moon {
        top: -5px;
        left: -5px;
        font-size: 0.62rem;
        padding: 0 2px;
    }

    /* The legend becomes one swipeable row rather than three wrapped lines. */
    .organic-calendar .oc-legend {
        flex-wrap: nowrap;
        overflow-x: auto;
        scroll-snap-type: x proximity;
        -webkit-overflow-scrolling: touch;
        scrollbar-width: none;
        margin-inline-start: 0;
        width: 100%;
        padding-bottom: 0.15rem;
    }

    .organic-calendar .oc-legend::-webkit-scrollbar {
        display: none;
    }

    .organic-calendar .oc-legend-item {
        scroll-snap-align: start;
        flex: none;
    }

    /* legendPosition=side has no room to be a rail down here - it collapses to
       the same scrollable chip row as the top placement. */
    .organic-calendar.oc-legend-side {
        display: block;
    }

    .organic-calendar .oc-legend-rail {
        position: static;
        flex-direction: row;
        order: -1;
        margin-bottom: 0.75rem;
    }

    .organic-calendar .oc-field {
        min-height: 0;
        border-radius: var(--radius-lg, 12px);
    }

    /* A 320px constellation either overlaps or shrinks text below an accessible
       size, so small screens always get the readable stack. */
    .organic-calendar .oc-field-ring,
    .organic-calendar .oc-core {
        display: none;
    }

    .organic-calendar .oc-hint {
        display: none;
    }
}

/* Touch input: no hover, so tap targets must carry the interaction. */
@media (hover: none), (pointer: coarse) {
    /* The blob stays visually small; the target does not. A transparent inset
       overlay lifts every active day to the 44px minimum without disturbing the
       grid rhythm. */
    .organic-calendar .oc-day-active::before {
        content: "";
        position: absolute;
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%);
        width: max(44px, 100%);
        height: max(44px, 100%);
        border-radius: 50%;
    }

    /* Hover transforms are meaningless without a pointer and leave elements
       stuck in the hovered state after a tap. */
    .organic-calendar .oc-day-active:hover,
    .organic-calendar .oc-bubble:hover {
        transform: none;
        box-shadow: none;
    }

    .organic-calendar .oc-bubbles-list .oc-bubble {
        min-height: 60px;
    }

    /* The bubble a first tap selected, waiting for the second tap to open. */
    .organic-calendar .oc-bubble.is-armed {
        outline: 2px solid var(--focus-ring, #6366f1);
        outline-offset: 2px;
    }
}

/* The host the open sheet is lifted into (web/js/organic-calendar.js,
   ensureSheetHost). It sits at the end of <body> and carries a copy of the
   calendar root's classes, so every `.organic-calendar ...` rule below - and
   the --oc-* custom properties declared at the top of this file - still apply
   to the surfaces inside it. It has no box of its own: everything it holds is
   position: fixed.

   It must never gain `transform`, `filter`, `contain` or `will-change` - any of
   those would make it a containing block for its own fixed children, which is
   the exact trap the lift exists to escape. */
.oc-sheet-host {
    position: static;
}

/* Bottom sheet: the mobile presentation of an expanded day. ---------------- */

@media (max-width: 767.98px) {
    .organic-calendar.oc-mobile-sheet .oc-expanded {
        position: fixed;
        left: 0;
        right: 0;
        bottom: 0;
        z-index: 1055;
        max-height: 85dvh;
        display: flex;
        flex-direction: column;
        border-radius: 18px 18px 0 0;
        background: var(--bg-primary, #fff);
        box-shadow: 0 -8px 32px rgba(0, 0, 0, 0.28);
        /* dvh, not vh: vh does not shrink when mobile browser chrome appears,
           which clips the bottom of the sheet. */
        padding: 0.75rem 1rem calc(0.75rem + env(safe-area-inset-bottom));
        animation: oc-sheet-up 0.22s ease;
    }

    /* `display: flex` above ties on specificity with the generic
       `.organic-calendar .oc-expanded[hidden]` rule and, coming later in the
       file, wins - which left an empty sheet pinned to the bottom of every
       mobile viewport from page load. Restate the hidden case here, where it
       outranks the rule that broke it. */
    .organic-calendar.oc-mobile-sheet .oc-expanded[hidden] {
        display: none;
    }

    .organic-calendar.oc-mobile-sheet .oc-expanded::before {
        content: "";
        position: absolute;
        top: 6px;
        left: 50%;
        transform: translateX(-50%);
        width: 40px;
        height: 4px;
        border-radius: 2px;
        background: var(--border-strong, #d4d4d8);
    }

    .organic-calendar.oc-mobile-sheet .oc-expanded-head {
        margin-top: 0.5rem;
        flex: none;
    }

    .organic-calendar.oc-mobile-sheet .oc-field {
        flex: 1 1 auto;
        overflow-y: auto;
        -webkit-overflow-scrolling: touch;
        /* Keep a flick at the end of the list inside the sheet instead of
           handing it to the page behind. */
        overscroll-behavior: contain;
        background: transparent;
    }

    /* Backdrop behind the sheet. */
    .organic-calendar .oc-sheet-backdrop {
        position: fixed;
        inset: 0;
        z-index: 1050;
        background: var(--overlay-bg, rgba(0, 0, 0, 0.5));
    }

    .organic-calendar .oc-sheet-backdrop[hidden] {
        display: none;
    }

    /* The preview is a pinned strip at the top of the sheet on touch, not a
       floating card chasing a cursor that does not exist. */
    .organic-calendar.oc-touch-preview .oc-preview {
        position: fixed;
        left: 0.75rem;
        right: 0.75rem;
        bottom: calc(85dvh + 0.5rem);
        width: auto;
        z-index: 1056;
    }
}

@keyframes oc-sheet-up {
    from {
        transform: translateY(12%);
        opacity: 0;
    }

    to {
        transform: translateY(0);
        opacity: 1;
    }
}

/* Body scroll lock while the sheet is open: `body.oc-sheet-open`.
   The lock itself is applied in JS (web/js/organic-calendar.js, lockPageScroll)
   with the "position: fixed body" technique, NOT with `overflow: hidden` here:
   this site sets `html { overflow-x: hidden }` (web/css/site.css), so body's
   overflow no longer propagates to the viewport and hiding it collapses the
   page's scroll range instead - clamping scrollTop to 0 and stranding the
   visitor at the top of the page. This class is left as a state hook for
   anything that needs to style the page behind an open sheet. */

/* -----------------------------------------------------------------------------
   Reduced motion
   The brief asks for no transition at all when the visitor requests it - the
   blob "growing into a world" is exactly the kind of motion that triggers
   vestibular symptoms.
   -------------------------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {

    .organic-calendar .oc-day-active,
    .organic-calendar .oc-bubble,
    .organic-calendar .oc-nav,
    .organic-calendar .oc-loading {
        transition: none;
    }

    .organic-calendar .oc-day-active:hover,
    .organic-calendar .oc-day-active:focus-visible,
    .organic-calendar .oc-bubble:hover,
    .organic-calendar .oc-bubble:focus-visible {
        transform: none;
    }

    .organic-calendar.oc-mobile-sheet .oc-expanded {
        animation: none;
    }
}

/* Print: the month overview is the useful part; the interactive shell is not. */
@media print {

    .organic-calendar .oc-nav,
    .organic-calendar .oc-fullscreen-row,
    .organic-calendar .oc-preview,
    .organic-calendar .oc-hint {
        display: none !important;
    }

    .organic-calendar .oc-day-active {
        box-shadow: none;
    }
}
