/* ============================================================
   Overlays — modals, toasts, popovers, reconnect
   docs/08-design-system-v2.md §4 (geometry, shadows), §6 (modal shape, focus)

   Fomantic is linked before this file (App.razor), so a selector of *equal*
   specificity written here already wins on source order. Where Fomantic outranks
   us it is because it uses a longer selector, and the fix is to match that
   selector rather than to escalate — which is why this file needs no !important
   at all. Each rule that mirrors a Fomantic selector says which one and why.
   ============================================================ */

/* ── Modals ───────────────────────────────────────────────── */
/* §4: --tm-radius-md is the shape of a dialog — 12px and up reads as a toy —
   and --tm-shadow-lg is the elevation. --tm-shadow-xl was one step deeper than
   anything §4 defines and made a form modal look like it was floating off the
   page. Every corner-rounding rule below follows the same token. */
.ui.modal {
    border-radius: var(--tm-radius-md);
    box-shadow: var(--tm-shadow-lg);
    border: 1px solid var(--tm-border);
    background: var(--tm-surface);
}

/* Surface, rule and padding. Kept apart from the type rule below on purpose: the
   type rule has to reach five classes to beat Fomantic's per-size overrides, and
   a `padding` shorthand at that weight would then outrank the padding-right
   reservation further down and let long titles slide back under the close icon. */
.ui.modal > .header {
    background: var(--tm-surface);
    color: var(--tm-text);
    border-bottom: 1px solid var(--tm-border);
    padding: var(--tm-space-4) var(--tm-space-5);
    letter-spacing: -0.01em;
}

/* Type only. Fomantic sets the title's size from .ui.modal > .header:not(.ui)
   and then re-sets it per modal size — .ui.tiny.modal > .header:not(.ui) and its
   seven siblings, five classes each — so a Tiny modal's title rendered at 1.3em
   no matter what the four-class rule said. Every size variant the framework ships
   is listed, so one title size holds across all of them.
   Weight is semibold, not the previous 700 — §3.3 drops 700 and 800 entirely. */
.ui.modal > .header:not(.ui),
.ui.mini.modal > .header:not(.ui),
.ui.tiny.modal > .header:not(.ui),
.ui.small.modal > .header:not(.ui),
.ui.large.modal > .header:not(.ui),
.ui.big.modal > .header:not(.ui),
.ui.huge.modal > .header:not(.ui),
.ui.massive.modal > .header:not(.ui) {
    /* --tm-text-lg: §2 gives card headers that step, and a modal title is one.
       The scale was renumbered, so --tm-text-md now means "body". */
    font-size: var(--tm-text-lg);
    line-height: var(--tm-leading-lg);
    font-weight: var(--tm-weight-semibold);
}

/* Fomantic rounds whichever element sits at the top of the panel to its own
   0.28571429rem — via .ui.modal > :first-child:not(.close):not(.dimmer) (five
   classes) and .ui.modal > i.icon:first-child + * — and both outrank
   .ui.modal > .header. SemModal always renders the close icon first, so in this
   application it is the second of the two that applies; both shapes are matched
   here so the corner follows --tm-radius-md either way. */
.ui.modal > .header:first-child:not(.ui),
.ui.modal > i.close.icon:first-child + .header {
    border-top-left-radius: var(--tm-radius-md);
    border-top-right-radius: var(--tm-radius-md);
}

/* Reserve the close button's column so a long title never runs underneath it.
   Written with Fomantic's own selector shapes: it sets padding-right: 2.25rem on
   .ui.modal > .close + .header inside its ≤991.98px and ≤767.98px blocks, and on
   .ui.modal > .close.inside + .header:not(.centered):not(.center):not(.icon) —
   eight classes — at every width. 2.25rem is narrower than the button plus its
   offset, which is what let a long title slide under the close icon. */
.ui.modal > .close + .header,
.ui.modal > .close.inside + .header:not(.centered):not(.center):not(.icon),
.ui.fullscreen.modal > .close + .header:not(.centered):not(.center):not(.icon) {
    padding-right: var(--tm-space-7);
}

.ui.modal > .content {
    background: var(--tm-surface);
    color: var(--tm-text);
    padding: var(--tm-space-5);
    font-size: var(--tm-text-md);
    line-height: var(--tm-leading-md);
}

/* §6: the footer loses Fomantic's grey bar (#f9fafb). The actions sit on the
   same surface as the content, separated by a single rule, primary on the
   right. */
.ui.modal > .actions {
    background: var(--tm-surface);
    border-top: 1px solid var(--tm-border);
    padding: var(--tm-space-4) var(--tm-space-5);
}

/* .ui.modal > :last-child rounds the bottom corners to Fomantic's radius; one
   extra class here is enough to take it over. */
.ui.modal > .actions:last-child {
    border-bottom-left-radius: var(--tm-radius-md);
    border-bottom-right-radius: var(--tm-radius-md);
}

/* ── Modal close button ───────────────────────────────────── */
/* §6: Fomantic parks .ui.modal > .close at top: -2.5rem / right: -2.5rem —
   *outside* the panel, painted white on the dimmed overlay. It reads as a
   rendering bug rather than as a control.
   .ui.modal is position: absolute, so re-anchoring the icon to positive offsets
   puts it inside the panel's own top-right corner with no markup change. It is
   anchored to the panel and not to the header, which is what makes it hold for a
   modal that renders no header text: the icon still lands inside the dialog
   instead of floating on the dimmer.
   .close.inside is listed alongside because Fomantic gives that variant its own
   four-class rule with different offsets; SemModal defaults to the "outside"
   variant, but a caller may switch it. */
.ui.modal > .close,
.ui.modal > .close.inside {
    top: var(--tm-space-3);
    right: var(--tm-space-3);
    bottom: auto;
    left: auto;
    width: var(--tm-space-6);
    height: var(--tm-space-6);
    margin: 0;
    padding: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: var(--tm-radius-sm);
    background: transparent;
    /* --tm-text-secondary rather than --tm-text-muted: the glyph is a non-text
       graphic and owes WCAG 1.4.11 a 3:1 ratio. --tm-text-secondary measures
       6.18:1 on --tm-surface; --tm-text-muted would be 2.55:1 and fail. */
    color: var(--tm-text-secondary);
    opacity: 1;
    font-size: var(--tm-text-md);
    line-height: 1;
    text-shadow: none;
    transition: background var(--tm-transition), color var(--tm-transition);
}

/* From 992px up, Fomantic draws a four-way dark text-shadow on the close glyph
   (.ui.dimmer > .ui.modal:not(.fullscreen) > .close:not(.inside), seven classes)
   so it stays legible against the dimmer. Now that the icon sits on the panel
   the shadow only looks smudged, and nothing shorter can clear it.
   Only text-shadow is reset here. Fomantic's rule sets nothing else, and
   repeating `color` at seven classes would outrank the :hover rule below and
   freeze the glyph's colour on hover. */
.ui.dimmer > .ui.modal:not(.fullscreen) > .close:not(.inside) {
    text-shadow: none;
}

.ui.modal > .close:hover,
.ui.modal > .close:focus,
.ui.modal > .close.inside:hover,
.ui.modal > .close.inside:focus {
    background: var(--tm-border-light);
    color: var(--tm-text);
    opacity: 1;
}

/* Focus ring identical to the one buttons.css, forms.css and navigation.css
   draw — one focus treatment across the app (§6), and never removed.
   Known gap: SemModal renders the control as <i class="close icon">, and an <i>
   takes no keyboard focus without a tabindex. Making it reachable is a markup
   change and belongs to phase 3; the rule is written now so the ring appears the
   moment the element becomes focusable. Mouse users are unaffected — the icon
   stays clickable, Fomantic's modal module binds the click on .close. */
.ui.modal > .close:focus-visible,
.ui.modal > .close.inside:focus-visible {
    outline: none;
    box-shadow: 0 0 0 3px var(--tm-primary-light);
}

/* ── Toast Notification Panel ─────────────────────────────── */
/* Anchored bottom-right, deliberately. Top-right put toasts directly on top of
   the page-header action buttons (Create…, Back, Edit), so for the toast's
   lifetime — up to 10 s for an error — those buttons could not be clicked.
   pointer-events keeps the container itself click-through; only the toast
   bodies take input, so its empty area never swallows a click either.

   The five !important here are the exception §4 allows, and they are aimed at a
   named rule: SemanticBlazor ships its own
   .notifications { position: fixed; top: 60px; right: 20px; width: 350px }
   in _content/SemanticBlazor/SemanticBlazor.css. It is a single class, the same
   weight as this rule, so which one wins would come down to whichever stylesheet
   the package happens to inject first — and that is not something this file can
   control. The geometry above is a decision, not a preference, so it is pinned. */
.notification-panel,
.notifications {
    position: fixed !important;
    bottom: var(--tm-space-4) !important;
    right: var(--tm-space-4) !important;
    top: auto !important;
    left: auto !important;
    z-index: 1001;
    max-width: 400px;
    pointer-events: none;
}

.notification-panel > *,
.notifications > * {
    pointer-events: auto;
}

/* Appearance only — the geometry above is load-bearing, see the comment there.
   SemanticBlazor's NotificationPanel renders each toast as
   <div class="ui raised {color} segment">, so the segment is what actually needs
   the treatment; the .ui.message selectors are kept for any caller that renders a
   message instead. Nothing here touches background or text colour — the severity
   palette belongs to feedback.css. */
.notifications > .ui.segment,
.notification-panel .ui.message,
.notifications .ui.message {
    border-radius: var(--tm-radius-md);
    box-shadow: var(--tm-shadow-lg);
    font-size: var(--tm-text-md);
    line-height: var(--tm-leading-md);
    animation: tm-slide-in var(--tm-transition-slow);
}

/* Fomantic paints .ui.segment with a literal hairline; the toast keeps a border
   because it floats over arbitrary page content and needs its own edge. The
   coloured top stripe that .ui.{color}.segment adds is the severity signal and
   is deliberately left to Fomantic. */
.notifications > .ui.segment {
    border: 1px solid var(--tm-border);
    background: var(--tm-surface);
    padding: var(--tm-space-4);
}

@keyframes tm-slide-in {
    from {
        opacity: 0;
        transform: translateX(20px) scale(0.95);
    }
    to {
        opacity: 1;
        transform: translateX(0) scale(1);
    }
}

/* ── Error UI (fixed bar pinned over the page) ────────────── */
#blazor-error-ui {
    display: none;
    position: fixed;
    bottom: 0;
    left: 0;
    right: 0;
    z-index: 1000;
    box-shadow: var(--tm-shadow-lg);
}

#blazor-error-ui .ui.message {
    margin: 0;
    border-radius: 0;
}

#blazor-error-ui[style] {
    display: block;
}

/* ── Row-actions overflow menu (§6) ───────────────────────────
   The panel behind the `⋮` in every list row — Shared/RowActions.razor. The trigger and the
   items live in buttons.css; this file owns where the panel is drawn, because that is the one
   hard part.

   Why it is drawn in the browser's top layer: tables.css puts `overflow-x: auto` on the
   `.ui.basic.segment` that SemDataTable wraps every table in, so that a wide table scrolls
   instead of clipping its Actions column. A scroll container clips on BOTH axes, so an
   absolutely positioned panel opened on the last row would be cut off inside the table. The
   same problem, and the same fix, as TM-93 on the attendance sheet: cell-popover.js gives the
   panel a `popover` attribute, which paints it outside every overflow, stacking context and
   z-index on the page, and then supplies viewport coordinates because the top layer has no
   anchoring of its own.

   The rules below therefore come in two halves: the in-flow fallback (before the script takes
   over, and on any browser without `showPopover`), and the promoted panel. */

.tm-c-row-menu {
    position: relative;
    display: inline-flex;
}

/* A full-screen catcher is the whole click-outside handling, and the element cell-popover.js
   clicks when Esc is pressed. It is transparent — the menu is not modal and dimming the page
   behind a three-item list would be theatre. */
.tm-c-row-menu-backdrop {
    position: fixed;
    inset: 0;
    z-index: 90;
}

.tm-c-row-menu-panel {
    position: absolute;
    top: calc(100% + var(--tm-space-1));
    /* Anchored by its right edge: the Actions column is the last one in the table, so a panel
       hanging rightwards would leave the page. Matches the 'end' alignment RowActions passes
       to cell-popover.js, so the fallback and the promoted panel agree. */
    right: 0;
    z-index: 100;
    min-width: 12rem;
    padding: var(--tm-space-1) 0;
    background: var(--tm-surface);
    border: 1px solid var(--tm-border);
    border-radius: var(--tm-radius-md);
    box-shadow: var(--tm-shadow-lg);
    text-align: left;
    white-space: nowrap;
}

/* Once promoted, the script supplies left/top in viewport coordinates, so the browser's own
   centring of a top-layer element has to be undone. */
.tm-c-row-menu-panel[popover] {
    position: fixed;
    inset: auto;
    margin: 0;
    transform: none;
    max-width: min(20rem, calc(100vw - var(--tm-space-4)));
    max-height: calc(100vh - var(--tm-space-4));
    overflow: auto;
    color: inherit;
}

/* Below 700px cell-popover.js deliberately does not promote — see the constant in that file.
   An in-flow panel there would be clipped by the table's own horizontal scroll box, so the
   panel becomes a sheet pinned to the bottom of the viewport instead. `position: fixed`
   escapes the scroll container's clipping, which `position: absolute` does not. */
@media only screen and (max-width: 699px) {
    .tm-c-row-menu-panel {
        position: fixed;
        inset: auto 0 0 0;
        top: auto;
        border-radius: var(--tm-radius-md) var(--tm-radius-md) 0 0;
        border-bottom: none;
        max-height: 60vh;
        overflow: auto;
        white-space: normal;
    }

    /* With the panel pinned to the viewport, the backdrop is what says the rest of the page is
       inactive — so here it does dim. */
    .tm-c-row-menu-backdrop {
        background: color-mix(in srgb, var(--tm-text) 35%, transparent);
    }
}
