/*
    Dialogs: what has to be true wherever one can open.

    Two bugs live here, both of which showed up as "the screen looks wrong when
    a dialog opens", and neither of which belongs to any one screen. This file
    is loaded by every layout — staff, member, phone and the signed-out pages —
    so a dialog behaves the same wherever it appears.

    This solution uses two dialog libraries. SweetAlert does almost all of it
    (38 views); Bootstrap's modal is used exactly once, for the student profile
    popup on People ▸ Öğrenciler and Coach ▸ Öğrencilerim.
*/

/* =========================================================================
   1. Opening a dialog must not move the page
   ========================================================================= */

/*  Measured on a window with an 11px scrollbar, opening the profile popup:

        before   scrollbar 11px   content 208..1269
        after    scrollbar  0px   content 208..1271   body padding-right 11px

    Bootstrap hides the page's overflow so the background cannot scroll behind
    the dialog. That takes the scrollbar away, and it then pads the body by the
    width it just removed to make up for it. Two things happen at once — an
    11px strip of scrollbar vanishes, and the compensation does not land
    exactly, because it is written in CSS pixels and the bar's zoom scales them
    — so the page visibly jumps as the dialog appears.

    Reserving the scrollbar's space permanently means there is nothing to take
    away and nothing to compensate for. The layout is the same width whether a
    dialog is open or not; the scrollbar just becomes inert instead of
    vanishing.

    `!important` because Bootstrap writes the padding as an inline style.
    SweetAlert is named too: it does not pad, but it does force the scrollbar
    back with `overflow-y: scroll`, which a reserved gutter makes pointless. */
html {
    scrollbar-gutter: stable;
}

body.modal-open,
body.swal2-shown {
    padding-right: 0 !important;
}

/* =========================================================================
   2. Overlays must not be sized in viewport units
   ========================================================================= */

/*  The top bar's zoom sets `zoom` on <html>. That reflows the page, which is
    why it was chosen over a transform — but it also scales anything measured
    in `vw`/`vh`, **including elements that are `position: fixed`**. Measured
    in Chrome on a 1280x650 window:

        fixed; width:100vw; height:100vh
            zoom 0.8 -> 1024x520     zoom 1.2 -> 1536x780

        fixed; inset: 0
            1280x650 at every zoom

    Bootstrap sizes its backdrops the first way. At 80% the backdrop covered
    only the top-left 1024x520 of the screen, so the page was dimmed in a
    rectangle with a visible edge down the right and across the bottom instead
    of evenly. Above 100% it ran past the window and forced scrollbars.

    Sized by their edges instead, which no viewport unit can distort. All of
    this is identical to the original at 100%.

    SweetAlert already uses `inset: 0` and was never affected. */
.modal-backdrop,
.offcanvas-backdrop {
    inset: 0;
    width: auto;
    height: auto;
}

/* The staff sidebar had `height: 100vh`, so it stopped short of the bottom
   below 100% and overran it above. (`.member-sidebar` was already written with
   top/bottom and was always right.) */
.sidebar {
    height: auto;
    bottom: 0;
}

/* The screen-share overlay goes full-screen the same way, both when expanded
   and on a phone. */
.screen-share-overlay.fullscreen,
.floating-chat-panel.fullscreen {
    inset: 0 !important;
    width: auto !important;
    height: auto !important;
    transform: none !important;
}

@media (max-width: 768px) {
    .screen-share-overlay {
        inset: 0 !important;
        width: auto !important;
        height: auto !important;
        transform: none !important;
    }
}

/* =========================================================================
   3. A dialog built out of a Bootstrap grid must not scroll sideways
   ========================================================================= */

/*  Most of the admin dialogs lay their fields out with `<div class="row g-2">`.
    A Bootstrap row is built to sit inside a container that pads it: it carries
    a negative margin of half the gutter on each side and relies on that
    padding to absorb it. SweetAlert's body is not that container, so the row
    comes out a gutter wider than the box holding it -- measured at 706 against
    702 -- and the dialog grows a horizontal scrollbar along the bottom for
    four pixels of nothing.

    It went unnoticed while the fields were all plain inputs that could shrink.
    It became visible on the coach form, where the phone field has a fixed
    column in it.

    Taking the negative margin off is enough; the columns keep their own
    padding, so the spacing between fields is unchanged. */
.swal2-html-container > .row {
    margin-left: 0;
    margin-right: 0;
}


/* =========================================================================
   4. The dialog's buttons are the page's buttons
   ========================================================================= */

/*  Section 16 of elbe-look gives every button on a signed-in screen one size:
    7px by 12px, 10px corners, 12.5px at 700. A dialog sits outside that
    region -- SweetAlert appends its popup to <body> -- so its buttons kept
    Bootstrap-era proportions: 10px by 17.6px at 16px, half again as large as
    the Kaydet on the page behind them.

    The same size here, so pressing Kaydet in a dialog looks like pressing
    Kaydet anywhere else.

    Colour is still each dialog's own, passed as `confirmButtonColor` at the
    call. Those were eight different values across 54 calls -- three reds, two
    blues -- and are now three, from the palette:

        #8A6A00   brass, the affirmative      (white on it: 5.1:1)
        #D63B2A   wine, deleting              (4.6:1)
        #157C43   felt, restoring             (4.8:1)

    Deep brass rather than the page's `#FFC200`, because SweetAlert writes its
    button text white and white on #FFC200 is 1.6:1. */
.swal2-popup .swal2-styled {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 7px;
    min-height: 36px;
    padding: 9px 18px;
    margin: 0 4px;
    border-radius: 10px;
    border: 1px solid transparent;
    font-size: 13.5px;
    font-weight: 700;
    line-height: 1.2;
    box-shadow: none;
}

/*  Cancel is the ghost, the way it is on the page: no fill, ink lettering, a
    faint edge. `cancelButtonColor` was dropped from all 40 calls that set it
    so there is no inline colour left to fight -- SweetAlert's own grey is a
    stylesheet rule and this outranks it.

    `!important` on the fill, because the classroom's dialogs came across from
    MyChessClub still passing `cancelButtonColor` -- SweetAlert writes that as
    an inline background on the button, and slate under this rule's ink
    lettering made Cancel unreadable. The ghost wins over any passed colour. */
.swal2-popup .swal2-cancel.swal2-styled {
    background: transparent !important;
    color: #1C1814;                          /* 16.4:1 on the dialog */
    border-color: rgba(28, 22, 8, 0.18);
}

.swal2-popup .swal2-cancel.swal2-styled:hover {
    background: #FBF7EC !important;
    color: #1C1814;
    border-color: rgba(28, 22, 8, 0.30);
}

.swal2-popup .swal2-styled:focus-visible {
    outline: 2px solid #8A6A00;
    outline-offset: 2px;
    box-shadow: none;
}


/* =========================================================================
   5. A dialog is meant to fit the window
   ========================================================================= */

/*  The standing rule for every dialog in this application: the whole of it is
    on the screen without scrolling, unless the content genuinely cannot be.
    Reaching for the wheel to find the Kaydet button is the failure.

    SweetAlert's own proportions are written for a dialog holding a sentence,
    not a form. Measured on *PGN ile Ekle* -- eight fields in a `row g-2`,
    which is as tight as the markup gets -- the dialog came to 753px against
    the 731 the window had, and the container scrolled:

        title            60px   (30px lettering, 24px of padding above and below)
        gap              18px
        body            598px   (18px lettering, so every label and field with it)
        gap              20px
        buttons          32px
        gap              20px

    A third of the overflow was chrome. Taken down here, once, so every dialog
    in the application gains it and no view has to be touched:

        title            30px lettering -> 19px, and the padding with it
        body             18px -> 13.5px, which is the size the forms behind the
                         dialog are set in anyway
        the gaps         18/20/20 -> 8/12/14

    That is about 120px off any form dialog, and the PGN one now fits.

    Where a dialog is genuinely longer than the window -- a long list, a table
    of results -- it is the *body* that scrolls, not the dialog: the title
    stays at the top and the buttons stay at the bottom, where they can be seen
    and reached. */

/*  The popup can be as tall as the container, which is `position: fixed` with
    its edges pinned, and therefore the window -- not `100vh`, which the top
    bar's zoom scales (section 2). */
.swal2-container {
    padding: 10px;
}

/*  The container is a three-row grid -- one row for a dialog pinned to the
    top, one for a centred one, one for the bottom -- and all three are `auto`,
    so the middle row grows to whatever the dialog is. `max-height: 100%` on
    the dialog then measures itself against that row, which is its own height,
    and caps nothing: the puzzle form came out 1081px inside a 731px window and
    the container scrolled.

    Bounding the middle row to the container gives the percentage below
    something real to measure against. The outer two stay content-sized, so a
    `position: top` dialog is unaffected. */
.swal2-container.swal2-center,
.swal2-container.swal2-top,
.swal2-container.swal2-bottom {
    grid-template-rows: auto minmax(0, 1fr) auto;
}

/*  A column rather than SweetAlert's grid.

    The dialog's rows are `auto`, and an `auto` grid row will not shrink below
    its content when the box it is in is limited by `max-height` rather than
    `height` — so capping the dialog above moved the overflow inside it instead
    of removing it: the puzzle form's body stayed 981px tall inside a 712px
    dialog and its buttons hung off the bottom. A flex column does shrink, and
    the children are in document order either way.

    `!important` because SweetAlert writes `display: grid` inline as it opens.
    Safe: it closes by taking the container out of the DOM, not by hiding the
    dialog, so there is nothing this could keep on the screen. */
.swal2-popup:not(.swal2-toast) {
    display: flex !important;
    flex-direction: column;
    max-height: 100%;
    padding: 0 22px;
    /* A message must not come out as a slip of paper: every dialog opens at
       least this wide, capped by the window on phones. */
    min-width: min(440px, 92vw);
}

.swal2-popup:not(.swal2-toast) > * {
    flex: 0 0 auto;
}

.swal2-popup:not(.swal2-toast) .swal2-title {
    font-size: 22px;
    line-height: 1.3;
    padding: 20px 10px 2px;
    margin: 0;
}

/*  The one part that gives: it takes what the title and the buttons leave, and
    scrolls inside itself when that is not enough. `min-height: 0` because a
    flex item will not shrink below its content without it. */
.swal2-popup:not(.swal2-toast) .swal2-html-container {
    flex: 1 1 auto;
    margin: 10px 6px 0;
    padding: 0;
    font-size: 15px;
    line-height: 1.5;
    min-height: 0;
    overflow-x: hidden;
    overflow-y: auto;
}

.swal2-popup:not(.swal2-toast) .swal2-actions {
    margin: 12px 0 14px;
    gap: 8px;
}

/*  The icon is gone. See section 8.

    `!important` because SweetAlert writes `display: flex` onto the icon inline
    as it opens it, the same way it writes `display: grid` onto the popup above.
    The element stays in the markup — section 8 reads its class to know what
    kind of dialog this is. */
.swal2-popup:not(.swal2-toast) .swal2-icon {
    display: none !important;
}

/*  The fields inside. A dialog is a form in a small box: the label sits close
    to the field it names, and both are set at the size the forms on the page
    behind are set in. */
.swal2-html-container .form-label {
    margin-bottom: 2px;
    font-size: 11.5px;
    font-weight: 600;
    opacity: 0.85;
}

.swal2-html-container .form-control,
.swal2-html-container .form-select {
    font-size: 13px;
    padding: 5px 9px;
    min-height: 0;
    border-radius: 8px;
}

.swal2-html-container textarea.form-control {
    line-height: 1.4;
}

/*  `row g-2` is 8px between fields; 6px is enough and gives back a row's worth
    over eight fields. */
.swal2-html-container .row.g-2 {
    --bs-gutter-y: 6px;
    --bs-gutter-x: 8px;
}

.swal2-html-container > :last-child {
    margin-bottom: 0;
}

/*  A board in a dialog takes the whole width it is given, and at 560px wide
    that is 560px of squares — more than the window has to spare, and the
    fields under it went below the fold. 340px is the size the original draws
    its own editor at, and it leaves the form beside it on the screen. */
.swal2-html-container .elbe-board {
    max-width: 340px;
    margin-left: auto;
    margin-right: auto;
}


/*  The one Bootstrap dialog left in the application, the student's profile,
    keeps to the same rule: as tall as the window and no taller, and its body
    scrolls rather than the page behind it. */
.modal-dialog-scrollable .modal-content,
.modal .modal-content {
    max-height: calc(100% - 20px);
}

.modal .modal-body {
    overflow-y: auto;
}


/* =========================================================================
   6. The calendar says when it is finished
   ========================================================================= */

/*  flatpickr closes on a click outside and keeps whatever was clicked, which
    leaves the person picking a date with nothing that says «done» and no way
    to change their mind. `datepicker-init.js` gives every calendar two
    buttons; this is the strip they sit in.

    Inside the calendar's own box, so it moves with it and cannot be left
    behind on a scroll. */
.flatpickr-calendar .fp-footer {
    display: flex;
    justify-content: flex-end;
    gap: 8px;
    padding: 8px 10px;
    border-top: 1px solid var(--elbe-line, rgba(28, 22, 8, 0.12));
    background: inherit;
}

/*  The calendar is drawn on <body>, outside `.content-area`, so section 16's
    one button size does not reach it. Stated again here rather than widened
    there: the rest of the page has no business restyling a library's popup. */
.flatpickr-calendar .fp-footer .btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-height: 30px;
    padding: 6px 12px;
    border-radius: 9px;
    border: 1px solid transparent;
    font-size: 12.5px;
    font-weight: 700;
    line-height: 1.2;
    white-space: nowrap;
}


/* =========================================================================
   7. A dialog is a light surface on every theme
   ========================================================================= */

/*  SweetAlert's popup is white -- `background: #fff`, from the library, on all
    nine themes -- and the calendar flatpickr opens is white for the same
    reason. Neither is inside the page: both are appended to <body>, so they
    wear the theme class and inherit every colour the theme declares, while
    standing on a ground the theme knows nothing about.

    That is a contradiction, and it shipped as one. adminlayout.css styles the
    page's text with rules that name no container at all -- `p`, `small`,
    `.text-muted`, `.form-label`, `a`, `.form-control`, `.table` -- so they
    reach inside the popup and paint it in the page's colours. Measured in the
    running site on Blue Sky, the dark theme the school is set to, in the
    "put this backup back" dialog:

        p                #f1f5f9 on #ffffff ....... 1.10:1   invisible
        small / .small   #94a3b8 on #ffffff ....... 2.56:1
        .text-muted      #94a3b8 on #ffffff ....... 2.56:1
        .form-label      #94a3b8 on #ffffff ....... 2.56:1
        a                #60a5fa on #ffffff ....... 2.54:1

    The first line is the bug as it was reported: the dialog asked whether to
    replace the whole database and both of its sentences -- the warning and the
    file name -- were white on white. The rest were the same mistake waiting to
    be noticed, and they are in every dialog in the application, not this one.

    Overriding those rules one at a time would fix today's list and none of
    tomorrow's. The colours are asked for *by name*, so the answer is to give
    the dialog its own answers: the theme's palette, restated here with values
    measured on the dialog's own white ground. Every rule that reaches inside
    then resolves correctly without knowing it is in a dialog, no `!important`
    is needed anywhere, and a rule or a dialog added later is covered before it
    is written.

    The values are the light side's, because the surface is light. They are the
    same ones the Elbe theme uses, and this file's own sections already use
    them for the buttons and the microphone wizard -- so a dialog now agrees
    with itself throughout.

    Only the popup and the calendar. The Bootstrap modal is NOT here: it draws
    its surface from `--theme-card-bg-solid`, so it is genuinely the theme's
    dark card and its light lettering is correct.  */
.swal2-container,
.flatpickr-calendar {
    /* Lettering. Measured on #FFFFFF. */
    --theme-text: #1C1814;                  /* 16.4:1 */
    --theme-text-primary: #1C1814;
    --bs-body-color: #1C1814;
    --theme-text-muted: #5E584C;            /* 7.1:1 -- held at 7, not 4.5,
                                               because captions and table cells
                                               are set in it */
    --theme-text-secondary: #5E584C;
    --elbe-ivory-dim: #5E584C;

    /* The accent as lettering: links, icons, emphasis. Brass on white is
       #8A6A00 -- raw #FFC200 is 1.6:1 there and fills only. */
    --theme-accent: #8A6A00;                /* 5.1:1 */
    --theme-accent-primary: #8A6A00;
    --elbe-brass-text: #8A6A00;
    --theme-accent-light: #6B5200;          /* 7.4:1 -- the hover, which goes
                                               darker on a light ground, not
                                               lighter as it does on a dark one */
    --theme-accent-secondary: #6B5200;
    --elbe-eyebrow: #B58900;                /* 4.6:1 */

    /* The semantic four as lettering, at the light side's strengths. A dark
       theme lifts these to read on its own cards (#6BD79B, #F58B7C), which is
       about 1.9:1 here. */
    --elbe-felt-text: #14663A;              /* 6.3:1 */
    --elbe-wine-text: #9B2A1D;              /* 6.1:1 */
    --elbe-sky-text: #1F5C86;               /* 6.2:1 */
    --elbe-violet-text: #6B2F94;            /* 6.6:1 */

    /* Surfaces. The dialog is white, so a field or a card drawn on it is white
       and the secondary ground is the school's ivory. Without these a text box
       inside the dialog took the page's #0f172a and came out a black slot in a
       white box. */
    --bs-body-bg: #FFFFFF;
    --theme-bg-primary: #FFFFFF;
    --theme-card-bg: #FFFFFF;
    --theme-card-bg-solid: #FFFFFF;
    --theme-input-bg: #FFFFFF;
    --bs-tertiary-bg: #FBF7EC;
    --theme-bg-secondary: #FBF7EC;
    --theme-table-header-bg: #FBF7EC;
    --theme-table-header-text: #1C1814;     /* 15.9:1 on the ivory header */

    /* Edges and states, dark on a light ground rather than the other way. */
    --elbe-line: rgba(28, 22, 8, 0.12);
    --theme-border: rgba(28, 22, 8, 0.18);
    --theme-card-border: rgba(28, 22, 8, 0.18);
    --theme-input-border: rgba(28, 22, 8, 0.18);
    --theme-hover-bg: rgba(28, 22, 8, 0.05);
    --theme-card-hover: rgba(28, 22, 8, 0.05);
    --theme-active-bg: rgba(28, 22, 8, 0.08);
    --theme-table-row-hover: rgba(28, 22, 8, 0.05);
    --theme-glow: rgba(138, 106, 0, 0.22);

    /* The accent as a FILL, and what is written on it. */
    --theme-brass: #FFC200;
    --elbe-brass: #FFC200;
    --theme-on-brass: #1C1814;              /* 11.1:1 on #FFC200 */
    --theme-on-accent: #1C1814;
    --theme-on-accent-fill: #1C1814;
    --theme-sidebar-accent: linear-gradient(135deg, #FFC200, #FFD34D);
    --elbe-shadow: 0 14px 34px -16px rgba(120, 86, 10, 0.28);

    /*  The washes have to be restated, not just the brass they are mixed from.
        A custom property is resolved where it is declared: theme-base mixes
        these on `body`, so they arrive here already mixed from the page's
        accent, and a re-declared `--theme-brass` alone would not reach them.
        Mixed again here, they take this block's brass instead.

        This is what `.badge.bg-secondary` is drawn from -- a wash behind
        `--theme-accent` lettering. On Blue Sky's wash over white that pairing
        came to 4.2:1; on brass it is 4.7:1. */
    --theme-wash-06: color-mix(in srgb, var(--theme-brass) 6%, transparent);
    --theme-wash-10: color-mix(in srgb, var(--theme-brass) 10%, transparent);
    --theme-wash-16: color-mix(in srgb, var(--theme-brass) 16%, transparent);
    --theme-wash-22: color-mix(in srgb, var(--theme-brass) 22%, transparent);
}


/* =========================================================================
   7b. The themed dialog — the standard DARK surface, opt-in
   ========================================================================= */

/*  Section 7's answer is one ivory card on every theme. Some dialogs are
    asked to follow the reader's side instead — dark card on a dark theme,
    the ivory card on a light one. That is THIS standard, opted into at the
    call site:

        Swal.fire({ customClass: { container: 'swal-themed' }, ... })

    On a light theme nothing here fires and section 7 stands. On a dark theme
    the card becomes ONE fixed dark surface — not each theme's own, for the
    same reason section 7 chose one ivory: one ground, one set of measured
    inks, and a dialog added later is covered before it is written.

    Measured on the card #1A2332:
        title / labels   #ECF1F8 ..... 13.5:1
        body             #C7D1DE ..... 10.1:1
        muted            #93A1B5 ...... 5.6:1
        felt (green)     #6BD79B ...... 8.7:1
        wine (red)       #F58B7C ...... 6.6:1  */
body[data-bs-theme="dark"] .swal2-container.swal-themed {
    --theme-text: #ECF1F8;
    --theme-text-primary: #ECF1F8;
    --bs-body-color: #ECF1F8;
    --theme-text-muted: #93A1B5;
    --theme-text-secondary: #93A1B5;
    --elbe-ivory-dim: #93A1B5;

    --elbe-felt-text: #6BD79B;
    --elbe-wine-text: #F58B7C;
    --elbe-sky-text: #7CB8E8;
    --elbe-violet-text: #C39BE8;

    --bs-body-bg: #1A2332;
    --theme-bg-primary: #1A2332;
    --theme-card-bg: #202B3D;
    --theme-card-bg-solid: #202B3D;
    --theme-input-bg: #202B3D;
    --bs-tertiary-bg: #202B3D;
    --theme-bg-secondary: #202B3D;

    --elbe-line: rgba(148, 163, 184, 0.18);
    --theme-border: rgba(148, 163, 184, 0.28);
    --theme-card-border: rgba(148, 163, 184, 0.28);
    --theme-input-border: rgba(148, 163, 184, 0.28);
    --theme-hover-bg: rgba(255, 255, 255, 0.06);
}

body[data-bs-theme="dark"] .swal2-container.swal-themed .swal2-popup:not(.swal2-toast) {
    background: linear-gradient(180deg, #1E2939 0%, #16202F 100%);
    border-color: rgba(148, 163, 184, 0.30);
    box-shadow: 0 24px 70px -22px rgba(0, 0, 0, 0.75);
}

body[data-bs-theme="dark"] .swal2-container.swal-themed .swal2-title { color: #ECF1F8; }
body[data-bs-theme="dark"] .swal2-container.swal-themed .swal2-html-container { color: #C7D1DE; }
/*  The dark card's own ink for the bare ✕ used to live here. The ✕ is not
    bare any more — it carries its own pale face on every card in the solution
    (see "The one way out of a popup" below), so an ink that only made sense
    against a dark ground would now be light-on-light. Removed 2026-08-31. */

/* =============================================================================
   The one way out of a popup
   -----------------------------------------------------------------------------
   Every SweetAlert in the solution closes by the same button (Kamal,
   2026-08-31): a small round ✕ in the card's top corner. SweetAlert's own is
   two thin grey lines floating with no shape at all — easy to miss, and on a
   phone easy to miss twice.

   It is written here, bare, so it reaches EVERY popup on EVERY screen without
   a single `Swal.fire` call having to ask for it. Four different hand-made
   versions of this button existed before — one on the dashboard, one on the
   standings, one on the About card and one added for the tournament room —
   and all four have been deleted in favour of this.

   WHY THESE VALUES, AND WHY THEY HOLD ON EVERY CARD IN THE SOLUTION

   The button lands on at least five different grounds here: the white profile
   card in the hall, the ivory dialog card this stylesheet draws, the dark card
   a dark theme gives a themed dialog, the About card's navy, and the black
   behind a video. One set has to survive all five, so the FACE is pale and the
   EDGE is what does the work where the face cannot:

     ink  #334155 on #F1F5F9            8.4:1   — the same pair the standings
                                                  card was already using
     face #F1F5F9 on #FFFFFF            1.10:1  — fails on its own, by design
     edge #94A3B8 on #FFFFFF            2.56:1  — READ OFF THE RUNNING APP.
                                                  #CBD5E1 was tried first and
                                                  measured 1.48 — present, but
                                                  not a shape
     edge #94A3B8 on ivory  #F3EDDE     2.21:1  — carries it there too
     face #F1F5F9 on navy   #2C4A6E     7.90:1  — on any dark card the pale
                                                  face is the silhouette and
                                                  the edge is a bonus

   Hover turns it wine — #991B1B on #FEE2E2, edged #EF4444, which is 3.95:1 on
   white and 3.4:1 on a dark card, so the shape survives the hover too.
   ============================================================================= */
.swal2-close {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    margin: 6px 6px 0 0;
    padding: 0;
    border-radius: 50%;
    background: #F1F5F9;
    border: 1px solid #94A3B8;
    color: #334155;
    /*  The ✕ is the icon font's cross, not SweetAlert's "×" character: the
        character sits off the circle's centre in every font it falls back to
        (seen on the player's card, 2026-09-07). The text is kept for a screen
        reader but drawn at nothing; the icon takes the middle. */
    font-size: 0;
    line-height: 1;
    font-weight: 700;
    box-shadow: none;
    transition: background 0.15s, border-color 0.15s, color 0.15s;
}

.swal2-close::before {
    content: "\f659";                    /* bi-x-lg */
    font-family: "bootstrap-icons";
    font-size: 15px;
    font-weight: 400;
    line-height: 1;
    display: block;
}

/*  Hover ONLY, never focus. SweetAlert puts the focus on this button the
    moment a popup opens, so grouping `:focus` in here painted it wine at rest
    on every phone — the card looked as though the ✕ were already pressed
    (seen in the app, 2026-08-31). */
.swal2-close:hover {
    background: #FEE2E2;
    border-color: #EF4444;
    color: #991B1B;
}

/*  Focus keeps the resting face and loses SweetAlert's own pink halo. A
    keyboard still gets a ring, because `:focus-visible` fires for the keyboard
    and not for a tap. */
.swal2-close:focus {
    box-shadow: none;
    outline: none;
}

.swal2-close:focus-visible {
    outline: 2px solid #94A3B8;
    outline-offset: 2px;
}

/*  The ghost Cancel of section 4 was inked for ivory; on the dark card it
    turns its colours around. */
body[data-bs-theme="dark"] .swal2-container.swal-themed .swal2-cancel.swal2-styled {
    color: #ECF1F8;
    border-color: rgba(255, 255, 255, 0.28);
}
body[data-bs-theme="dark"] .swal2-container.swal-themed .swal2-cancel.swal2-styled:hover {
    background: rgba(255, 255, 255, 0.07) !important;
    color: #ECF1F8;
}

/*  The page's outline buttons inside such a dialog (the replay's arrows)
    keep a visible edge and light ink on the dark card. */
body[data-bs-theme="dark"] .swal2-container.swal-themed .btn-outline-secondary {
    color: #ECF1F8;
    border-color: rgba(255, 255, 255, 0.28);
}


/* ===== The microphone wizard ================================

   Three steps in a dialog: permission, which microphone, and does it actually
   work. Dialogs in this solution are the ivory surface whichever theme the
   reader is on, so these colours are measured on #FBF7EC and are fixed rather
   than themed — the same reasoning as the rest of this file. */

.mic-wizard-popup {
    max-width: 460px;
}

.mic-wizard-step {
    text-align: center;
    color: #1C1814;                     /* on the dialog: 16.5:1 */
}

.mic-wizard-icon {
    font-size: 40px;
    line-height: 1;
    margin-bottom: 10px;
    color: #8A6A00;                     /* brass as lettering on ivory: 5.1:1 */
}

.mic-wizard-icon.ok {
    color: #14663A;                     /* green as lettering on ivory: 6.3:1 */
}

/* The "how to allow it" steps, and the "no microphone found" note. */
.mic-wizard-help {
    background: #FFFFFF;
    border: 1px solid rgba(28, 22, 8, 0.14);
    border-radius: 10px;
    padding: 10px 12px;
    font-size: 12.5px;
    color: #1C1814;                     /* on #FFFFFF: 17.8:1 */
}

/* One microphone to choose from. A row, not a radio button, because the label
   can be long and wants the whole width. */
.mic-device-card {
    display: flex;
    align-items: center;
    gap: 4px;
    width: 100%;
    margin-bottom: 6px;
    padding: 9px 11px;
    border: 1px solid rgba(28, 22, 8, 0.16);
    border-radius: 10px;
    background: #FFFFFF;
    color: #1C1814;                     /* on #FFFFFF: 17.8:1 */
    font-size: 13px;
    text-align: start;
    cursor: pointer;
    transition: border-color 0.15s, background 0.15s;
}

.mic-device-card:hover {
    background: #FBF7EC;
    color: #1C1814;
    border-color: rgba(28, 22, 8, 0.30);
}

.mic-device-card.selected {
    border-color: #FFC200;
    background: #FFFBEB;                /* amber-50 */
    color: #1C1814;                     /* on #FFFBEB: 16.2:1 */
}

.mic-device-card .bi-check-circle-fill {
    color: #14663A;                     /* 6.3:1 on the card */
}

.mic-level-container {
    height: 14px;
    margin: 4px 8px;
    border-radius: 7px;
    background: rgba(28, 22, 8, 0.12);
    overflow: hidden;
}

.mic-level-bar {
    height: 100%;
    width: 0%;
    border-radius: 7px;
    background: #9aa3ae;
    transition: width 0.1s ease-out;
}

.mic-level-label {
    margin: 6px 0 12px;
    font-size: 12.5px;
    color: #5E584C;                     /* muted on ivory: 7.1:1 */
}

.mic-test-btn {
    border-radius: 10px;
}

/* The chip in the top bar. Optional — the wizard works without it — but it is
   how somebody sets their microphone up before anybody rings them, rather than
   discovering the problem in the middle of a call.

   It is only ever there when something is wrong (Kamal, 2026-08-30). A
   microphone that works needs nothing said about it, and a green tick sitting
   in the bar all day teaches people to stop reading the bar. So the button
   starts hidden — no state class in the markup, so a working microphone never
   flashes red on the way in — and mic-setup.js gives it .mic-not-setup only
   when permission is missing, refused, or no microphone has been chosen. */
.mic-status-btn {
    display: none;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    border: none;
    border-radius: 9px;
    background: transparent;
    color: var(--theme-navbar-text, #E8EDF2);
    cursor: pointer;
    transition: background 0.15s, color 0.15s;
}

.mic-status-btn:hover {
    background: var(--theme-hover-bg, rgba(127, 127, 127, 0.15));
    color: var(--theme-text, inherit);
}

/* Needs setting up: the school's own wine, which every theme defines as
   lettering measured on that theme's card — the top bar's own background.
   Light themes #9B2A1D on #FFFFFF (6.1:1); the Elbe dark #F58B7C on #241F19
   (7.2:1). Nothing is drawn behind it, so the lettering is the whole chip. */
.mic-status-btn.mic-not-setup {
    display: inline-flex;
    color: var(--elbe-wine-text, #9B2A1D);
}

/* The warning must not turn into ordinary text under the pointer. */
.mic-status-btn.mic-not-setup:hover {
    color: var(--elbe-wine-text, #9B2A1D);
}

/* .mic-ready gets no rule: a working microphone shows nothing at all. */

/* =========================================================================
   8. What a dialog is about, said quietly
   ========================================================================= */

/*  SweetAlert announces the kind of dialog with a circle: 80px of outlined
    exclamation mark, question mark or cross, drawn above the sentence that
    already says the same thing in words. Section 5 had taken it to 54px, which
    made it smaller without making it useful — «Bu rapor kaldırılsın mı?» does
    not need a ? the height of four lines of text sitting over it, and on the
    short ones the icon was the largest thing in the dialog.

    Taken out, and the same meaning given to the dialog's own top edge: a 3px
    band in the colour the kind of dialog already owns, with the title in that
    colour beneath it. A destructive question reads wine, a success reads felt
    green, and a plain one has neither — which is more colour information than
    the circle carried, in none of the height.

    Keyed off the icon SweetAlert still puts in the markup, so no view has to
    pass anything new and the 179 calls that name an icon keep working. The
    icon element is hidden, not removed, precisely so it can be read from here.

    The four colours are this file's own (section 7), measured on the dialog's
    white ground, so a title is legible before it is meaningful:

        felt   #14663A ... 6.3:1     wine  #9B2A1D ... 6.1:1
        brass  #8A6A00 ... 5.1:1     sky   #1F5C86 ... 6.2:1

    A dialog with no icon at all keeps the plain ink title and no band, which
    is what a form dialog wants — «Rapor Yaz» is not an event, it is a page. */

/*  A border rather than a bar laid over the top: it follows the popup's own
    corner radius without the popup having to clip anything, so the calendar
    and the select lists that open out of a dialog are left alone. */
.swal2-popup:not(.swal2-toast):has(.swal2-icon) {
    border-top: 3px solid var(--elbe-dialog-accent, transparent);
}

/*  Each kind names its colour once; the band and the title both take it. */
.swal2-popup:has(.swal2-icon.swal2-success) { --elbe-dialog-accent: var(--elbe-felt-text); }
.swal2-popup:has(.swal2-icon.swal2-error) { --elbe-dialog-accent: var(--elbe-wine-text); }
.swal2-popup:has(.swal2-icon.swal2-warning) { --elbe-dialog-accent: var(--theme-accent); }
.swal2-popup:has(.swal2-icon.swal2-question) { --elbe-dialog-accent: var(--theme-accent); }
.swal2-popup:has(.swal2-icon.swal2-info) { --elbe-dialog-accent: var(--elbe-sky-text); }

/*  The title takes the same colour, and the breathing room the icon's own
    margin used to provide above it. */
.swal2-popup:not(.swal2-toast):has(.swal2-icon) .swal2-title {
    color: var(--elbe-dialog-accent, var(--theme-text));
    padding-top: 20px;
}


/* =========================================================================
   9. The dialog's dress
   ========================================================================= */

/*  What every dialog wears, wherever it opens — the look MyChessClub's most
    liked cards had (a bordered, rounded, softly tinted panel), restated in
    this school's palette. One rule for all 179 calls; nothing is passed at
    the call site.

    The surface is a barely-there ivory gradient rather than flat white, the
    edge is brass at low opacity with a faint golden halo, and the ground
    behind dims and blurs so the card floats. The type-coloured 3px top band
    from section 8 sits on top of this and keeps saying what the dialog is
    about. All lettering rules from section 7 still measure on white/ivory,
    so nothing loses contrast: title #1C1814 ≈ 16:1, muted #5E584C ≈ 7:1. */
.swal2-popup:not(.swal2-toast) {
    background: linear-gradient(180deg, #FFFFFF 0%, #FDF8EC 100%);
    border: 1px solid rgba(181, 137, 0, 0.35);
    border-radius: 18px;
    box-shadow:
        0 24px 70px -22px rgba(28, 22, 8, 0.55),
        0 0 0 5px rgba(255, 194, 0, 0.08);
}

/*  The type band of section 8 keeps its meaning on the new shell. */
.swal2-popup:not(.swal2-toast):has(.swal2-icon) {
    border-top-width: 3px;
}

/*  The ground behind: darker, and nothing else. It used to blur too, but
    blurring the whole page forces it to repaint as the dialog fades in,
    which showed as a flicker — Kamal asked for the page behind a dialog
    to hold perfectly still (2026-08-26). */
.swal2-container.swal2-backdrop-show {
    background: rgba(18, 15, 8, 0.55) !important;
}

/*  A quieter second line inside a dialog — who else is already in the
    conversation you are being invited to, and the like.

    It was written into the markup as `color:#888`, which is 3.5:1 on the dialog's
    white and therefore under the line for text this size; and being inline, no
    change to a stylesheet could reach it. #5E584C is the muted ink this file uses
    everywhere else: 7.1:1 on #FFFFFF. */
.swal2-popup .chat-dialog-note {
    font-size: 12.5px;
    color: #5E584C;
    margin-bottom: 0;
}

/* =========================================================================
   The daily puzzle's "solved" dialog on a phone (Kamal, 2026-09-11): a
   quarter narrower than the full-width every dialog gets there. Same dialog
   for a clean solve and a solve after mistakes; the floor above is lifted.
   ========================================================================= */
@media (max-width: 768px) {
    .swal2-container .swal2-popup.dd-swal {
        width: 75% !important;
        min-width: 0 !important;
        /* Off centre: half the gap on the left it would have had centred (12.5%),
           on the same physical side whichever way the language runs. The top
           gap is trimmed by a quarter in student-home.js, since only the
           opened dialog knows its own height. */
        justify-self: left;
        margin-left: 6.25%;
    }
}

/*  The noise-removal choice on the wizard's last step (Kamal, 2026-09-11):
    a label and three buttons on one row, on the wizard's ivory surface. */
.mic-noise-row {
    display: flex;
    align-items: center;
    justify-content: center;
    flex-wrap: wrap;
    gap: 8px 12px;
    margin-top: 14px;
}
.mic-noise-label { font-size: 12.5px; font-weight: 600; color: #5E584C; }
.mic-noise-row .btn-outline-secondary { color: #3f3a31; border-color: #8f8778; background: transparent; }
.mic-noise-row .btn-outline-secondary.active,
.mic-noise-row .btn-outline-secondary:hover { background: #1F9D57; border-color: #1F9D57; color: #fff; }   /* 4.6:1 */
.mic-noise-row .btn-outline-secondary:focus-visible { outline: 2px solid #1F9D57; outline-offset: 2px; }
