﻿html, body {
    font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
}

a, .btn-link {
    color: #006bb7;
}

.btn-primary {
    color: #fff;
    background-color: #1b6ec2;
    border-color: #1861ac;
}

.btn:focus, .btn:active:focus, .btn-link.nav-link:focus, .form-control:focus, .form-check-input:focus {
  box-shadow: 0 0 0 0.1rem white, 0 0 0 0.25rem #258cfb;
}

.content {
    padding-top: 1.1rem;
}

h1:focus {
    outline: none;
}

.valid.modified:not([type=checkbox]) {
    outline: 1px solid #26b050;
}

.invalid {
    outline: 1px solid #e50000;
}

.validation-message {
    color: #e50000;
}

.blazor-error-boundary {
    background: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTYiIGhlaWdodD0iNDkiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIG92ZXJmbG93PSJoaWRkZW4iPjxkZWZzPjxjbGlwUGF0aCBpZD0iY2xpcDAiPjxyZWN0IHg9IjIzNSIgeT0iNTEiIHdpZHRoPSI1NiIgaGVpZ2h0PSI0OSIvPjwvY2xpcFBhdGg+PC9kZWZzPjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMCkiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yMzUgLTUxKSI+PHBhdGggZD0iTTI2My41MDYgNTFDMjY0LjcxNyA1MSAyNjUuODEzIDUxLjQ4MzcgMjY2LjYwNiA1Mi4yNjU4TDI2Ny4wNTIgNTIuNzk4NyAyNjcuNTM5IDUzLjYyODMgMjkwLjE4NSA5Mi4xODMxIDI5MC41NDUgOTIuNzk1IDI5MC42NTYgOTIuOTk2QzI5MC44NzcgOTMuNTEzIDI5MSA5NC4wODE1IDI5MSA5NC42NzgyIDI5MSA5Ny4wNjUxIDI4OS4wMzggOTkgMjg2LjYxNyA5OUwyNDAuMzgzIDk5QzIzNy45NjMgOTkgMjM2IDk3LjA2NTEgMjM2IDk0LjY3ODIgMjM2IDk0LjM3OTkgMjM2LjAzMSA5NC4wODg2IDIzNi4wODkgOTMuODA3MkwyMzYuMzM4IDkzLjAxNjIgMjM2Ljg1OCA5Mi4xMzE0IDI1OS40NzMgNTMuNjI5NCAyNTkuOTYxIDUyLjc5ODUgMjYwLjQwNyA1Mi4yNjU4QzI2MS4yIDUxLjQ4MzcgMjYyLjI5NiA1MSAyNjMuNTA2IDUxWk0yNjMuNTg2IDY2LjAxODNDMjYwLjczNyA2Ni4wMTgzIDI1OS4zMTMgNjcuMTI0NSAyNTkuMzEzIDY5LjMzNyAyNTkuMzEzIDY5LjYxMDIgMjU5LjMzMiA2OS44NjA4IDI1OS4zNzEgNzAuMDg4N0wyNjEuNzk1IDg0LjAxNjEgMjY1LjM4IDg0LjAxNjEgMjY3LjgyMSA2OS43NDc1QzI2Ny44NiA2OS43MzA5IDI2Ny44NzkgNjkuNTg3NyAyNjcuODc5IDY5LjMxNzkgMjY3Ljg3OSA2Ny4xMTgyIDI2Ni40NDggNjYuMDE4MyAyNjMuNTg2IDY2LjAxODNaTTI2My41NzYgODYuMDU0N0MyNjEuMDQ5IDg2LjA1NDcgMjU5Ljc4NiA4Ny4zMDA1IDI1OS43ODYgODkuNzkyMSAyNTkuNzg2IDkyLjI4MzcgMjYxLjA0OSA5My41Mjk1IDI2My41NzYgOTMuNTI5NSAyNjYuMTE2IDkzLjUyOTUgMjY3LjM4NyA5Mi4yODM3IDI2Ny4zODcgODkuNzkyMSAyNjcuMzg3IDg3LjMwMDUgMjY2LjExNiA4Ni4wNTQ3IDI2My41NzYgODYuMDU0N1oiIGZpbGw9IiNGRkU1MDAiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvZz48L3N2Zz4=) no-repeat 1rem/1.8rem, #b32121;
    padding: 1rem 1rem 1rem 3.7rem;
    color: white;
}

    .blazor-error-boundary::after {
        content: "An error has occurred."
    }

.darker-border-checkbox.form-check-input {
    border-color: #929292;
}

.form-floating > .form-control-plaintext::placeholder, .form-floating > .form-control::placeholder {
    color: var(--bs-secondary-color);
    text-align: end;
}

.form-floating > .form-control-plaintext:focus::placeholder, .form-floating > .form-control:focus::placeholder {
    text-align: start;
}
/*
    The date picker (wwwroot/js/date-picker.js).

    Global rather than scoped: the calendar is parented to document.body, so it is outside
    every component and no scoped stylesheet can reach it.

    Colors come from the theme's --cm-* tokens, which is what makes the calendar follow the
    twelve light and seven dark themes without a rule per theme. Each one carries a literal
    fallback for the case where no theme row is loaded at all.
*/
.cm-datepicker {
    position: absolute;
    z-index: 1080; /* Above Bootstrap's dropdowns (1000) and sticky headers. */
    width: 17rem;
    padding: 0.5rem;
    border: 1px solid var(--cm-border, #d6d5d5);
    border-radius: 0.375rem;
    background: var(--cm-surface, #ffffff);
    color: var(--cm-text, #212529);
    box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.18);
    font-size: 0.875rem;
}

.cm-dp-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.25rem;
    margin-bottom: 0.35rem;
}

.cm-dp-title {
    font-weight: 600;
    text-align: center;
    flex: 1 1 auto;
}

.cm-dp-nav,
.cm-dp-action {
    border: 1px solid var(--cm-border, #d6d5d5);
    border-radius: 0.25rem;
    background: var(--cm-raised, #f7f7f7);
    color: var(--cm-text, #212529);
    line-height: 1;
    cursor: pointer;
}

.cm-dp-nav {
    padding: 0.15rem 0.5rem;
    font-size: 1.1rem;
}

.cm-dp-action {
    padding: 0.2rem 0.6rem;
}

    .cm-dp-nav:hover,
    .cm-dp-action:hover,
    .cm-dp-day:hover {
        background: var(--cm-accent, #1b6ec2);
        color: var(--cm-accent-text, #ffffff);
    }

.cm-dp-grid {
    width: 100%;
    border-collapse: collapse;
    table-layout: fixed;
}

    .cm-dp-grid th {
        padding: 0.15rem 0;
        font-weight: 600;
        font-size: 0.75rem;
        text-align: center;
        color: var(--cm-muted, #6c757d);
    }

    .cm-dp-grid td {
        padding: 1px;
    }

.cm-dp-day {
    width: 100%;
    padding: 0.25rem 0;
    border: 1px solid transparent;
    border-radius: 0.25rem;
    background: none;
    color: inherit;
    cursor: pointer;
}

    /* Days either side of the month on show stay legible but clearly secondary. */
    .cm-dp-day.cm-dp-outside {
        color: var(--cm-muted, #6c757d);
        opacity: 0.65;
    }

    .cm-dp-day.cm-dp-today {
        border-color: var(--cm-accent, #1b6ec2);
        font-weight: 600;
    }

    .cm-dp-day.cm-dp-selected {
        background: var(--cm-accent, #1b6ec2);
        color: var(--cm-accent-text, #ffffff);
        font-weight: 600;
    }

    .cm-dp-day:focus-visible,
    .cm-dp-nav:focus-visible,
    .cm-dp-action:focus-visible {
        outline: 2px solid var(--cm-focus, #258cfb);
        outline-offset: 1px;
    }

.cm-dp-foot {
    display: flex;
    justify-content: space-between;
    margin-top: 0.4rem;
}

/*
    A calendar glyph on the fields that have a picker, so they read as more than a text box.
    Drawn as an inline SVG data URI because the theme stylesheets are the only other place a
    color could come from, and background images cannot take a custom property as a color.
*/
input[data-cm-datepicker] {
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%236c757d'%3E%3Cpath d='M5.5 0a.5.5 0 0 1 .5.5V1h4V.5a.5.5 0 0 1 1 0V1h1a2 2 0 0 1 2 2v10a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V3a2 2 0 0 1 2-2h1V.5a.5.5 0 0 1 .5-.5zM3 5v8a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1V5H3z'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right 0.4rem center;
    background-size: 0.8rem;
    padding-right: 1.6rem;
}

/*
    The password reveal button (Components/Shared/PasswordEye.razor, wwwroot/js/password-eye.js).

    Global, because the same control appears on the account pages and on the profile pages, and
    a scoped stylesheet only reaches one of them.

    Two containers, one appearance. On the account pages the field is a Bootstrap .form-floating,
    whose box is exactly the input, so the eye can span its full height. Elsewhere the label sits
    above the input, so the input and the eye are wrapped in .cm-password to give the eye that
    same box to sit in.
*/
.cm-password {
    position: relative;
}

.form-floating:has(> .cm-eye) {
    position: relative;
}

.cm-password > .cm-eye,
.form-floating > .cm-eye {
    position: absolute;
    top: 0;
    bottom: 0;
    right: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 2.25rem;
    padding: 0;
    border: 0;
    background: none;
    color: var(--cm-muted, #6c757d);
    cursor: pointer;
}

    .cm-eye:hover {
        color: var(--cm-text, #212529);
    }

    .cm-eye:focus-visible {
        outline: 2px solid var(--cm-focus, #258cfb);
        outline-offset: -2px;
        border-radius: 0.25rem;
    }

    .cm-eye svg {
        width: 1rem;
        height: 1rem;
        fill: currentColor;
    }

    /* One glyph at a time: an open eye to reveal, a struck-through one to hide again. */
    .cm-eye .cm-eye-hide,
    .cm-eye[aria-pressed="true"] .cm-eye-show {
        display: none;
    }

    .cm-eye[aria-pressed="true"] .cm-eye-hide {
        display: block;
    }

/*
    Room for the icon, so a long password does not run under it. Keyed off the eye being present
    rather than off a class on the input, because the input's type changes as it is revealed and
    nothing should have to keep a class in step with that.

    .form-control is repeated to win a tie rather than to be emphatic. A page's scoped rule for
    its own inputs compiles to `.cm-profile[b-hash] .form-control` - two classes AND the scope
    attribute, (0,3,0) - which is exactly what `.cm-password:has(> .cm-eye) > .form-control`
    scores, and ConferenceManagement.styles.css is linked after this file, so the scoped rule
    took the tie and the profile password boxes kept their 0.5rem. Repeating the class makes it
    (0,4,0). Verified by reading the matched rules in the browser, not by eye.
*/
.cm-password:has(> .cm-eye) > .form-control.form-control,
.form-floating:has(> .cm-eye) > .form-control.form-control {
    padding-right: 2.5rem;
}


/* Set by wwwroot/js/modal-panel.js while a panel is open over the page, so the page behind it
   does not scroll under the pointer. */
body.cm-modal-is-open {
    overflow: hidden;
}

/* The same, for a panel the server rendered open rather than one the script opened - it never
   passed through the script, so it never got the class. */
body:has(.cm-modal:not([hidden])) {
    overflow: hidden;
}

/* ---- Rendered page content ---------------------------------------------------------------
   One set of rules for content written in the home page editor, wherever it appears: inside
   the editor, on the preview page, and on the home page itself. Global rather than scoped to a
   component, because the editor builds its content at runtime and a component's scoped styles
   only reach markup that was there at compile time - which is why the editor used to look
   nothing like the page.

   .cm-rendered marks the content; .cm-rendered .ql-editor is the same content while it is
   being edited. Both are listed on every rule for that reason. */

.cm-rendered,
.cm-rendered .ql-editor {
    line-height: 1.6;
    /* A word or web address longer than the frame is wide is broken rather than left running
       off its side (2026-09-28: "The text should wrap in the home page frames"). */
    overflow-wrap: break-word;
}

/* Nothing is ever wider than the column it is in. */
.cm-rendered img,
.cm-rendered .ql-editor img,
.cm-rendered iframe,
.cm-rendered .ql-editor iframe {
    max-width: 100%;
}

/* A logo a merge field put there (2026-09-30, Services/MergeTokenResolver.cs) carries its width
   and height for mail programs; narrowed by the column, it keeps its shape. */
.cm-rendered img.cm-merge-logo {
    height: auto;
}

/* Video keeps its shape rather than whatever height it was embedded with. */
.cm-rendered iframe,
.cm-rendered .ql-editor iframe {
    width: 100%;
    aspect-ratio: 16 / 9;
    height: auto;
    border: 0;
}

/* The venue map {{Events.PrimaryVenueMap}} becomes (2026-09-28): the column's width, a little
   taller than a video, with the linked address under it. */
.cm-rendered .cm-venue-map iframe {
    aspect-ratio: 3 / 2;
}

.cm-rendered .cm-venue-map-address {
    margin-top: 0.25rem;
    /* Centered under the map, which runs the column's width (2026-10-02: "The address under the map
       from the mailmerge field Events.PrimaryVenueMap should be centered under the map"). */
    text-align: center;
}

/* A paragraph holding more than one image is a row of photographs - the three across the top
   of the home page are exactly that. They share the row from a zero basis so their natural
   sizes do not decide the split, and are cropped to one height so the row is not ragged. */
.cm-rendered p:has(img + img),
.cm-rendered .ql-editor p:has(img + img) {
    display: flex;
    flex-wrap: nowrap;
    gap: 0;
}

.cm-rendered p:has(img + img) img,
.cm-rendered .ql-editor p:has(img + img) img {
    flex: 1 1 0;
    min-width: 0;
    height: clamp(110px, 17vw, 260px);
    object-fit: cover;
    /* block, or the line box around an inline image adds a few pixels underneath. */
    display: block;
}

/* Artwork rather than a photograph: cropping cuts the words off, so it is fitted whole. The
   class is kept on the image through the editor, so it survives being edited and saved. */
.cm-rendered p:has(img + img) img.cm-hero-graphic,
.cm-rendered .ql-editor p:has(img + img) img.cm-hero-graphic {
    object-fit: contain;
}

/* A single image on its own line is shown at its own size, up to the column. */
.cm-rendered p > img:only-child,
.cm-rendered .ql-editor p > img:only-child {
    height: auto;
}

/* Alignment and indent as the editor applies them. Quill writes these as classes and styles
   them only inside .ql-editor, so without this the same content reads centred while it is being
   written and left-aligned once it is saved. */
.cm-rendered .ql-align-center { text-align: center; }
.cm-rendered .ql-align-right { text-align: right; }
.cm-rendered .ql-align-justify { text-align: justify; }

.cm-rendered .ql-indent-1 { padding-left: 3em; }
.cm-rendered .ql-indent-2 { padding-left: 6em; }
.cm-rendered .ql-indent-3 { padding-left: 9em; }
.cm-rendered .ql-indent-4 { padding-left: 12em; }
.cm-rendered .ql-indent-5 { padding-left: 15em; }
.cm-rendered .ql-indent-6 { padding-left: 18em; }
.cm-rendered .ql-indent-7 { padding-left: 21em; }
.cm-rendered .ql-indent-8 { padding-left: 24em; }

/* Lines one under another, as the editor shows them (2026-10-01: "there is a blank line between
   Presented by and the sponsor name"). Quill draws paragraphs and headings with no margins, so the
   only blank lines are the ones the author typed; the page used to add Bootstrap's margins too,
   a line's worth under every paragraph. A typed blank line is saved as an empty paragraph or
   heading, which is given a line's height here as the editor gives it. */
.cm-rendered :is(p, h1, h2, h3, h4, h5, h6) {
    margin-block: 0;
}

.cm-rendered :is(p, h1, h2, h3, h4, h5, h6):empty::before {
    content: "\00a0";
}

/* A row of photographs is a band of pictures rather than a line of text, and keeps room above and
   below it - in the editor too - as it had before lines lost their margins. */
.cm-rendered p:has(img + img),
.cm-rendered .ql-editor p:has(img + img) {
    margin-block: 0.75rem;
}

.cm-rendered p:has(img + img):first-child,
.cm-rendered .ql-editor p:has(img + img):first-child {
    margin-block-start: 0;
}

/* Tables, as the editor inserts them and as the page shows them. Quill's own table styling is
   scoped to .ql-editor, so without this a table would have lines while it was being written and
   none once it was saved. */
.cm-rendered table,
.cm-rendered .ql-editor table {
    border-collapse: collapse;
    width: 100%;
    margin: 0.75rem 0;
}

.cm-rendered th,
.cm-rendered td,
.cm-rendered .ql-editor th,
.cm-rendered .ql-editor td {
    border: 1px solid var(--cm-border, rgba(0, 0, 0, 0.25));
    padding: 0.35rem 0.5rem;
    vertical-align: top;
}

.cm-rendered th,
.cm-rendered .ql-editor th {
    text-align: left;
    font-weight: 600;
    background: rgba(0, 0, 0, 0.04);
}

/* A table written in an editor (2026-09-28: "2 rows and 2 columns, 100 px wide x 100 px high, for
   each row and column, with a 1px border for all"): every cell 100px square with a 1px border,
   and the table as wide as its columns rather than the page. Quill marks each cell it makes with
   data-row; a table a merge field builds - the sponsorship levels - has none, and keeps the rules
   above. A cell grows only for content that cannot fit in it. Last, so it wins the ties. */
.ql-editor table:has(> tbody > tr > td[data-row]),
.cm-rendered table:has(> tbody > tr > td[data-row]) {
    width: auto;
    table-layout: auto;
}

.ql-editor td[data-row],
.cm-rendered td[data-row] {
    box-sizing: border-box;
    border: 1px solid currentColor;
}

/* The 100px is for a cell nobody has sized. A width or height dragged in the editor is the cell's
   own inline-size or block-size (wwwroot/js/quill-editor.js), which an inline style wins over
   this; and a merged cell is as big as what it spans. */
.ql-editor td[data-row]:not([colspan]),
.cm-rendered td[data-row]:not([colspan]) {
    width: 100px;
}

.ql-editor td[data-row]:not([colspan]):not([style*="inline-size"]),
.cm-rendered td[data-row]:not([colspan]):not([style*="inline-size"]) {
    min-width: 100px;
}

.ql-editor td[data-row]:not([rowspan]),
.cm-rendered td[data-row]:not([rowspan]) {
    height: 100px;
}

/* A table without borders (the right click menu's Hide Borders): none on the page, and a faint
   dashed line in the editor, so its cells can still be found to type in. Important, because a
   border color and width chosen for the table (2026-09-30) are the cells' own inline styles, and
   hidden has to win over them; they come back with Show Borders. */
.cm-rendered td[data-row].cm-tableborder-none {
    border-color: transparent !important;
    border-width: 1px !important;
}

.ql-editor td[data-row].cm-tableborder-none {
    border: 1px dashed rgba(128, 128, 128, 0.5) !important;
}

/* A table centered on the page (the right click menu's Center on the Page, 2026-09-28): the class
   is on each of its cells, since Quill's formats belong to a cell's line. */
.ql-editor table:has(td[data-row].cm-tablealign-center),
.cm-rendered table:has(td[data-row].cm-tablealign-center) {
    margin-left: auto;
    margin-right: auto;
}

/* "Add a Table at the Cursor Location" (2026-09-28), a link in the toolbar - a button, since it
   acts rather than goes anywhere. */
.ql-toolbar .cm-table-group {
    display: inline-flex;
    align-items: center;
}

.ql-snow.ql-toolbar button.cm-table-insert,
.ql-snow .ql-toolbar button.cm-table-insert {
    width: auto;
    padding: 0 0.4rem;
    font-size: 0.8rem;
    color: var(--cm-accent, #1b6ec2);
    text-decoration: underline;
    white-space: nowrap;
}

/* Greyed while the cursor is in a table, where it would put a table inside a table. Still
   pressable: it says why. */
.ql-toolbar button.cm-table-insert[aria-disabled="true"] {
    opacity: 0.45;
    cursor: not-allowed;
}

/* ---- the editors' quarter-inch grid (2026-10-06) ----------------------------------------------
   "every grid editor with a 1/4" grid and a show/hide grid button", and "the background and/or
   background color can't hide it": a layer over the writing area rather than a background, which
   clicks pass through, each line dark beside light so it shows on any color, picture or highlight.
   wwwroot/js/quill-editor.js (addGridToggle) adds it and its button, and moves it as the text
   scrolls. It's beside the content, never in it, so nothing saved carries it, and print leaves it
   out. */
.cm-grid-overlay {
    display: none;
    position: absolute;
    inset: 0;
    pointer-events: none;
    background-image:
        linear-gradient(to right, rgba(0, 0, 0, 0.3) 1px, rgba(255, 255, 255, 0.5) 1px, rgba(255, 255, 255, 0.5) 2px, transparent 2px),
        linear-gradient(to bottom, rgba(0, 0, 0, 0.3) 1px, rgba(255, 255, 255, 0.5) 1px, rgba(255, 255, 255, 0.5) 2px, transparent 2px);
    background-size: 0.25in 0.25in;
}

.cm-editor-grid > .cm-grid-overlay {
    display: block;
}

@media print {
    .cm-grid-overlay {
        display: none !important;
    }
}

.ql-toolbar .cm-grid-group {
    display: inline-flex;
    align-items: center;
}

.ql-snow.ql-toolbar button.cm-grid-toggle,
.ql-snow .ql-toolbar button.cm-grid-toggle {
    width: auto;
    padding: 0 0.4rem;
    font-size: 0.8rem;
    color: var(--cm-accent, #1b6ec2);
    text-decoration: underline;
    white-space: nowrap;
}

/* ---- an On Calendar Only item's page (2026-09-29) ---------------------------------------------
   Everything on it but the box, Save Item and Cancel is locked by wwwroot/js/item-calendar.js,
   which marks each control it locks with data-cm-lock-added. Grayed here the way a disabled control
   is, but still clickable - the click says why. Text boxes, number boxes and dates look as the
   event profile draws any aria-disabled box. */
[data-cm-lock-added].form-control {
    background-color: var(--bs-secondary-bg, #e9ecef);
    color: var(--cm-muted, #6c757d);
    cursor: not-allowed;
}

[data-cm-lock-added].form-select,
[data-cm-lock-added].form-check-input,
[data-cm-lock-added].btn,
[data-cm-lock-added].cm-binbutton {
    opacity: 0.55;
    cursor: not-allowed;
}

/* An editor made read only: its toolbar faded, its page gray. */
.ql-toolbar.cm-locked-editor {
    opacity: 0.45;
}

.ql-container.cm-locked-editor,
.ql-container.cm-locked-editor .ql-editor {
    background-color: var(--bs-secondary-bg, #e9ecef);
    cursor: not-allowed;
}

/* The table's right click menu - on the page itself, above the editor's window. */
.cm-table-menu {
    position: fixed;
    z-index: 1090;
    min-width: 12rem;
    padding: 0.25rem 0;
    background: var(--cm-raised, #ffffff);
    color: var(--bs-body-color, #212529);
    border: 1px solid rgba(0, 0, 0, 0.2);
    border-radius: 0.35rem;
    box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.2);
}

.cm-table-menu-item {
    display: block;
    width: 100%;
    padding: 0.3rem 0.9rem;
    border: 0;
    background: none;
    color: inherit;
    text-align: left;
    font-size: 0.9rem;
}

/* The window a table's border color and width are chosen in, from the right click menu
   (2026-09-30). wwwroot/js/quill-editor.js builds it, so it is styled here, after the
   application's own questions (Components/Shared/ConfirmDialog.razor.css). */
.cm-table-borders {
    padding: 0;
    border: 0;
    background: transparent;
    width: min(24rem, calc(100% - 3rem));
    max-width: none;
    overflow: visible;
}

.cm-table-borders::backdrop {
    background: rgba(0, 0, 0, 0.5);
}

.cm-table-borders-panel {
    background: var(--cm-surface, #ffffff);
    color: var(--cm-text, #212529);
    border-radius: 0.5rem;
    box-shadow: 0 1rem 3rem rgba(0, 0, 0, 0.35);
    padding: 1.25rem 1.5rem 1.5rem;
}

.cm-table-borders-title {
    margin: 0 0 0.75rem;
    font-size: 1.15rem;
}

.cm-table-borders-fields {
    display: grid;
    grid-template-columns: auto 6rem;
    align-items: center;
    gap: 0.5rem 1rem;
}

.cm-table-borders-fields label {
    font-weight: 600;
}

.cm-table-borders-problem {
    margin: 0.75rem 0 0;
    color: var(--bs-danger, #dc3545);
}

.cm-table-borders-buttons {
    display: flex;
    gap: 0.75rem;
    margin-top: 1.25rem;
}

.cm-table-borders-buttons .btn {
    min-width: 6rem;
}

.cm-table-menu-item:hover,
.cm-table-menu-item:focus-visible {
    background: rgba(27, 110, 194, 0.12);
    outline: none;
}

.cm-table-menu-item[aria-disabled="true"] {
    opacity: 0.45;
    cursor: not-allowed;
}

.cm-table-menu-line {
    height: 1px;
    margin: 0.25rem 0;
    background: rgba(0, 0, 0, 0.15);
}

/* The line that follows the pointer while a column's width or a row's height is dragged. */
.cm-quill .cm-table-guide {
    position: absolute;
    z-index: 3;
    pointer-events: none;
    background: var(--cm-accent, #1b6ec2);
}

.cm-quill .cm-table-guide-width {
    width: 2px;
    margin-left: -1px;
}

.cm-quill .cm-table-guide-height {
    height: 2px;
    margin-top: -1px;
}

/* A list set in two columns, for content that asks for it - a banquet menu, say. A class
   rather than a style attribute because the sanitizer keeps classes and allows only color
   through style, so this is what survives being saved. */
/* Quill rewrites every list as an ol carrying data-list, so both shapes are covered. A list
   that arrives already two-column keeps its class; one that has been through the editor is
   matched by the attribute. */
.cm-rendered .cm-two-column,
.cm-rendered .ql-editor .cm-two-column {
    columns: 2;
    column-gap: 2rem;
}

.cm-rendered .cm-two-column li,
.cm-rendered .ql-editor .cm-two-column li {
    /* Keeps an item from being split down the middle across the two columns. */
    break-inside: avoid;
}

@media (max-width: 36rem) {
    .cm-rendered .cm-two-column,
    .cm-rendered .ql-editor .cm-two-column {
        columns: 1;
    }
}

/* ---- The help panel -------------------------------------------------------------------------
   The Help link, last among the header's links, and the box it opens over the page. The link was
   a question mark until 2026-09-27 ("Change the help icon to help as the last link on the
   header"); it is a button, since it opens a panel rather than going anywhere, dressed as the
   links beside it: bold italic, two pixels smaller than the row. */

.cm-help-link {
    padding: 0;
    border: 0;
    background: transparent;
    color: var(--cm-link, #1b6ec2);
    font-weight: 700;
    font-style: italic;
    font-size: calc(1em - 2px);
    line-height: inherit;
    white-space: nowrap;
    cursor: pointer;
}

.cm-help-link:hover,
.cm-help-link:focus-visible {
    text-decoration: underline;
}

/* The dim over the page. Fixed, so it covers what is scrolled out of sight as well. */
.cm-help-panel {
    position: fixed;
    inset: 0;
    z-index: 1080;
    display: flex;
    align-items: flex-start;
    justify-content: center;
    padding: 4rem 1rem 1rem;
    background: rgba(0, 0, 0, 0.35);
    overflow-y: auto;
}

.cm-help-box {
    width: min(48rem, 100%);
    max-height: calc(100vh - 6rem);
    overflow-y: auto;
    padding: 1rem 1.25rem 1.25rem;
    border-radius: 0.5rem;
    background: var(--cm-surface, #ffffff);
    color: var(--cm-text, #212529);
    box-shadow: 0 1rem 3rem rgba(0, 0, 0, 0.3);
}

.cm-help-bar {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 1rem;
    margin-bottom: 0.75rem;
    border-bottom: 1px solid var(--cm-border, rgba(0, 0, 0, 0.175));
}

.cm-help-bar h2 {
    margin: 0 0 0.5rem;
    font-size: 1.15rem;
}

.cm-help-close {
    border: none;
    background: transparent;
    color: inherit;
    font-size: 1.5rem;
    line-height: 1;
    cursor: pointer;
}

.cm-help-content > :last-child {
    margin-bottom: 0;
}

.cm-help-actions {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin-top: 1rem;
}

/* Nothing behind the panel scrolls while it is open. */
body:has(.cm-help-panel:not([hidden])) {
    overflow: hidden;
}

/* The skip link: out of sight until a keyboard reaches it, then the first thing on the page.
   Not display:none, which would take it out of the tab order and defeat the point. */
.cm-skip-link {
    position: absolute;
    left: -100vw;
    top: 0;
    z-index: 2000;
    padding: 0.5rem 1rem;
    background: var(--cm-surface, #ffffff);
    color: var(--cm-text, #212529);
    border: 2px solid var(--cm-accent, #1b6ec2);
    border-radius: 0 0 0.375rem 0;
    text-decoration: none;
}

.cm-skip-link:focus {
    left: 0;
}

/* ---- Headings ------------------------------------------------------------------------------
   Every page is titled with h1 and works downwards - which is what a screen reader reads as the
   outline, and why the titles are not h3 any more. The sizes below keep the look the h3 titles
   had: h1 shows at what h3 was, h2 at what h4 was, and so on down the scale. Change a number
   here to resize every title at once; do not change the tags. */

h1 {
    font-size: 1.75rem;
}

h2 {
    font-size: 1.5rem;
}

h3 {
    font-size: 1.3rem;
}

h4 {
    font-size: 1.15rem;
}

/* The home page's greeting: one heading, two lines. "Welcome To" above the application's name,
   which is what the two separate headings used to do. */
.cm-intro-title {
    margin-bottom: 0.5rem;
    text-align: center;
}

.cm-intro-title .cm-welcome,
.cm-intro-title .cm-intro-name {
    display: block;
}

/* ---- Pagers ---------------------------------------------------------------------------------
   Under a grid: previous, the numbers, next, and the row count. Links, not buttons - see the
   Pager component for why. */

.cm-pager {
    display: flex;
    align-items: center;
    gap: 0.25rem;
    margin: 0.5rem 0 1rem;
    font-size: 0.85rem;
}

.cm-pager-page,
.cm-pager-step {
    min-width: 1.9rem;
    padding: 0.15rem 0.4rem;
    border: 1px solid var(--cm-border, rgba(0, 0, 0, 0.175));
    border-radius: 0.25rem;
    color: inherit;
    text-align: center;
    text-decoration: none;
}

.cm-pager-page:hover,
.cm-pager-step:hover {
    background-color: color-mix(in srgb, var(--cm-accent, #1b6ec2) 12%, transparent);
}

/* The page being shown: marked, and not a link to where you already are. */
.cm-pager-on {
    font-weight: 700;
    background-color: var(--cm-surface, #ffffff);
}

/* The step that has nowhere to go. Shown rather than removed, so the pager does not change
   width as it is used. */
.cm-pager-off {
    opacity: 0.35;
}

.cm-pager-count {
    margin: 0 0 0 0.5rem;
    font-size: 0.85rem;
    opacity: 0.8;
}

p.cm-pager-count {
    margin: 0.5rem 0 1rem;
}

/* "this event" beside an overridden field, so a default and an override read apart. */
.cm-badge {
    display: inline-block;
    margin-left: 0.4rem;
    padding: 0.05rem 0.35rem;
    border-radius: 0.75rem;
    background-color: color-mix(in srgb, var(--cm-accent, #1b6ec2) 15%, transparent);
    font-size: 0.7rem;
    text-transform: uppercase;
    letter-spacing: 0.02em;
}

/* ---- two-factor authentication ----------------------------------------------------------- */

/* The QR code. Capped rather than stretched: a scanner wants a crisp square, and a code blown
   up to the width of a desktop column is harder to point a phone at, not easier. */
.cm-qr-frame {
    max-width: 15rem;
    margin: 0 0 1rem;
    padding: 0.5rem;
    background-color: #ffffff;
    border: 1px solid rgba(0, 0, 0, 0.15);
    border-radius: 0.35rem;
}

.cm-qr-frame .cm-qr {
    display: block;
    width: 100%;
    height: auto;
}

/* The key for anybody typing it in by hand, and the recovery codes. Both get read off the
   screen a character at a time, so both are monospaced and spaced out. */
.cm-shared-key {
    padding: 0.3rem 0.5rem;
    font-size: 1rem;
    letter-spacing: 0.08em;
}

.cm-recovery-codes {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr));
    gap: 0.35rem 1rem;
    max-width: 26rem;
    margin-bottom: 1.25rem;
}

.cm-recovery-codes code {
    font-size: 1.05rem;
    letter-spacing: 0.06em;
}

.cm-2fa-actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem;
}

/* The formatted address box. Four lines is the whole of an address as this schema writes one, so
   the box is that tall and stays there - Bootstrap's reboot makes every textarea draggable, which
   on a read-only box built by the application is a handle that does nothing useful. */
.cm-address {
    resize: none;
    white-space: pre-wrap;
}

/* ---- the item color ---------------------------------------------------------------------- */

/* The picker. A color input is the whole control - it shows the color, and clicking it opens
   the platform picker - so it is sized like a swatch rather than stretched like a text box. */
.cm-color {
    width: 3.25rem;
    min-width: 3.25rem;
    height: 2.25rem;
    padding: 0.15rem;
    cursor: pointer;
}

/* Beside "Item Order" on the same line, so the two read as one row of small fields. */
.cm-color-label {
    margin-left: 1rem;
}

/* The same color in a grid, where there is nothing to pick - just the color itself. */
.cm-swatch {
    display: inline-block;
    width: 1.25rem;
    height: 1.25rem;
    border: 1px solid rgba(0, 0, 0, 0.3);
    border-radius: 0.2rem;
    vertical-align: middle;
}

/* ---- the event calendar ---------------------------------------------------------------------

   FullCalendar draws it. Everything below points its classic palette at this site's own colors,
   so the calendar follows whatever theme the organization is on rather than sitting in its
   default blue - see Components/App.razor for where the library itself is loaded. */

.cm-eventcalendar {
    /* Only variables this site's themes actually define, each with the library's own default
       behind it. An invented name here is worse than none: --cm-accent-strong did not exist, so
       every pressed button fell through to the fallback and the calendar sat there in blue on a
       pink theme. */
    --fc-classic-primary: var(--cm-accent, #1b6ec2);
    --fc-classic-primary-foreground: var(--cm-accent-text, #fff);
    --fc-classic-button: var(--cm-accent, #1b6ec2);
    --fc-classic-button-border: var(--cm-accent, #1b6ec2);
    --fc-classic-button-strong: var(--cm-accent-hover, #1559a0);
    --fc-classic-button-strong-border: var(--cm-accent-hover, #1559a0);
    --fc-classic-button-foreground: var(--cm-accent-text, #fff);
    --fc-classic-event: var(--cm-accent, #1b6ec2);
    --fc-classic-event-contrast: var(--cm-accent-text, #fff);
    --fc-classic-background: var(--cm-surface, #ffffff);
    --fc-classic-foreground: var(--cm-text, #030712);
    --fc-classic-border: var(--cm-border, #ddd);
    --fc-classic-muted-foreground: var(--cm-muted, #6b7280);
    --fc-classic-today: color-mix(in srgb, var(--cm-accent, #1b6ec2) 10%, transparent);
    --fc-classic-ring-color: var(--cm-focus, var(--cm-accent, #1b6ec2));
    font-size: 0.9rem;
}

/* A day out of dbo.EventDates is a whole day and carries no color of its own, so it takes the
   theme's; an entry off the schedule arrives with its item setting's color already on it. */
.cm-eventcalendar .cm-fc-day {
    --fc-event-color: var(--cm-accent, #1b6ec2);
}

/* A day the public are not invited to - setup, load-out - reads quieter than a public day. */
.cm-eventcalendar .cm-fc-private {
    opacity: 0.75;
    border-style: dashed;
}


/* An address the application built for copying: monospaced, because it is read a character at a
   time when somebody checks it, and it does not pretend to be editable. */
.cm-copyable {
    font-family: var(--bs-font-monospace);
    font-size: 0.85rem;
    cursor: text;
    background-color: rgba(0, 0, 0, 0.03);
}

/* A home page's full address, shown as the link it is (2026-09-26) under the profile's home page
   buttons. On a line of its own and broken anywhere, because an event's address with its token is
   longer than the column is wide. */
.cm-address-link {
    display: block;
    overflow-wrap: anywhere;
    font-family: var(--bs-font-monospace);
    font-size: 0.85rem;
}

/* ---- the terms agreement gate ------------------------------------------------------------- */

/* The note beside Save when the Terms of Use have not been agreed to. A warning, not an error:
   nothing has gone wrong, there is simply a box still to tick. */
.cm-terms-note {
    max-width: 34rem;
    margin-bottom: 0.5rem;
    padding: 0.5rem 0.75rem;
    border-left: 3px solid #b8860b;
    background-color: rgba(184, 134, 11, 0.08);
    font-size: 0.9rem;
    line-height: 1.45;
}

/* The link beside the Agree box that opens the copy of the terms this organization agreed to.
   A button, because href="#" navigates to the home page in this app, dressed as a link so it
   reads as one beside the checkbox label. */
.cm-terms-review-open {
    margin-left: 0.75rem;
    padding: 0;
    border: none;
    background: transparent;
    color: var(--cm-link, #0d6efd);
    font-size: 0.9rem;
    text-decoration: underline;
    cursor: pointer;
}

.cm-terms-review-open:hover,
.cm-terms-review-open:focus-visible {
    text-decoration: none;
}

/* The popup itself, built like the help panel so the two behave alike: a fixed dim over the
   whole page, and a panel that holds its own scrolling. */
.cm-terms-review {
    position: fixed;
    inset: 0;
    z-index: 1080;
    display: flex;
    align-items: flex-start;
    justify-content: center;
    padding: 3rem 1rem 1rem;
    background: rgba(0, 0, 0, 0.35);
}

.cm-terms-review[hidden] {
    display: none;
}

.cm-terms-review-panel {
    position: relative;
    width: min(52rem, 100%);
    max-height: calc(100vh - 5rem);
    display: flex;
    flex-direction: column;
    padding: 1rem 1.25rem 1.25rem;
    border-radius: 0.5rem;
    background: var(--cm-surface, #ffffff);
    color: var(--cm-text, #212529);
    box-shadow: 0 1rem 3rem rgba(0, 0, 0, 0.3);
}

.cm-terms-review-panel h2 {
    margin: 0 2rem 0.75rem 0;
    padding-bottom: 0.5rem;
    border-bottom: 1px solid var(--cm-border, rgba(0, 0, 0, 0.175));
    font-size: 1.15rem;
}

/* Top right, clear of the heading. */
.cm-terms-review-close {
    position: absolute;
    top: 0.5rem;
    right: 0.75rem;
    border: none;
    background: transparent;
    color: inherit;
    font-size: 1.5rem;
    line-height: 1;
    cursor: pointer;
}

/* The scrolling region. The terms run to several thousand characters, so this is what scrolls -
   not the page behind it. */
.cm-terms-review-scroll {
    overflow-y: auto;
    padding-right: 0.5rem;
}

/* Plain text, as it was stored: preserved line breaks, wrapped rather than scrolled sideways. */
.cm-terms-review-text {
    margin: 0;
    font-family: var(--bs-font-monospace);
    font-size: 0.85rem;
    line-height: 1.5;
    white-space: pre-wrap;
    overflow-wrap: anywhere;
}

/* ---- Grid headings and form labels ------------------------------------------------------------

   Both asked for across every page, so both live here rather than in a dozen scoped stylesheets.
   A heading and a label are what somebody reads to find their way around a page; the values
   beside them are what they came for, and weight is how the two are told apart. */

/* Every grid's headings, including the filter row's own header cells. */
.cm-grid thead th,
table.table thead th {
    font-weight: 700;
}

/* Every form's labels. .cm-field is this application's own field wrapper; .form-label and
   .form-check-label are Bootstrap's, which the checkbox rows use. */
.cm-field > label,
.form-label,
.form-check-label,
fieldset > legend {
    font-weight: 700;
}

/* The help text under a field is not a label, and neither is a hint beside a grid. Said
   explicitly so the rule above cannot be read as applying to them. */
.cm-field .form-text,
.cm-hint,
.cm-note {
    font-weight: 400;
}

/* ---- What the membership API said about the number just entered ------------------------------ */
/* Written by wwwroot/js/membership-check.js. Empty - and so taking no room - until a number has
   been entered. Not hidden by the field-tips setting: it is an answer, not a tip. */

.cm-membership-result {
    font-size: 0.875em;
    margin-top: 0.25rem;
}

.cm-membership-result:empty {
    display: none;
}

.cm-membership-checking {
    opacity: 0.75;
    font-style: italic;
}

.cm-membership-found {
    color: var(--bs-success, #198754);
    font-weight: 600;
}

.cm-membership-missing {
    color: var(--bs-danger, #dc3545);
    font-weight: 600;
}

.cm-membership-error {
    opacity: 0.8;
}

/* ---- A strip of tabs ---------------------------------------------------------------------- */
/* System Settings and the organization profile draw their tabs with these. The event profile has
   the same rules in its own scoped stylesheet, which wins there and says the same thing. They are
   links - a tab is an address - and on the organization profile a script switches them in place.
   Declared here rather than in each page's scoped stylesheet, because a scoped rule reaches only
   its own page's markup and three copies would drift. */

.cm-tabs {
    display: flex;
    flex-wrap: wrap;
    column-gap: 0.25rem;
    row-gap: 2px;
    border-bottom: 2px solid var(--cm-border, rgba(0, 0, 0, 0.175));
    margin-bottom: 1rem;
}

.cm-tab {
    padding: 0.25rem 0.55rem;

    /* Every tab is drawn, in the same line and color the open one uses, so the strip reads as a
       row of tabs rather than as words with one box among them. */
    border: 1px solid var(--cm-border, rgba(0, 0, 0, 0.175));
    border-bottom: none;
    border-radius: 0.375rem 0.375rem 0 0;
    color: inherit;
    text-decoration: none;
    white-space: nowrap;
    font-size: 0.67rem;
    font-weight: 700;

    /* Sits on top of the strip's own border, so the open tab joins the panel below it. */
    margin-bottom: -2px;
}

.cm-tab:hover {
    color: inherit;
    background-color: color-mix(in srgb, var(--cm-accent, #1b6ec2) 10%, transparent);
}

.cm-tab-on {
    border-bottom: 2px solid var(--cm-surface, #ffffff);
    background-color: var(--cm-surface, #ffffff);
}

.cm-tab:focus-visible {
    outline: 2px solid var(--cm-accent, #1b6ec2);
    outline-offset: 1px;
}

/* A system administrator's switch at the top of a tab that an organization's own users may not
   be shown - set apart from the tab's own fields, because it is about the tab, not about them. */
.cm-tab-switch {
    margin-bottom: 0.9rem;
    padding-bottom: 0.7rem;
    border-bottom: 1px dashed var(--cm-border, rgba(0, 0, 0, 0.175));
}

/* ---- The calculated dates beside the item form's two offsets ---------------------------------- */

.cm-offset-date {
    display: inline-flex;
    align-items: baseline;
    gap: 0.4rem;
    margin-left: 0.75rem;
    white-space: nowrap;
}

.cm-offset-date .cm-offset-label {
    font-weight: 700;
}

.cm-offset-date output {
    font-variant-numeric: tabular-nums;
    min-width: 6rem;
}

/* ---- Dragging a row --------------------------------------------------------------------------- */

/* A row that can be dragged says so under the pointer. The grids that cannot be dragged are
   unaffected: this only matches a row carrying the id the reorder script needs. */
[data-cm-reorder] tr[data-cm-row-id][draggable="true"] {
    cursor: grab;
}

[data-cm-reorder] tr[data-cm-row-id][draggable="true"]:active {
    cursor: grabbing;
}

/* ---- Money -------------------------------------------------------------------------------------

   A number input cannot carry a currency symbol in its own value - the browser would refuse the
   value as not a number - so the sign sits beside the box. Money that is only being read is
   formatted with "C" and carries its own sign. */
.cm-money {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
}

.cm-money-sign {
    font-weight: 700;
    opacity: 0.8;
}

/* The box keeps the width it had; the sign is beside it, not inside it. */
.cm-money input {
    text-align: right;
    font-variant-numeric: tabular-nums;
}

/* The date the Terms of Use last changed, beside the link to them in the footer. Quieter than
   the link: it is a fact about the terms, not a second thing to click. */
.cm-footer-date {
    opacity: 0.75;
    font-size: 0.9em;
    margin-left: 0.3rem;
}

/* The asterisk beside Contact Messages while some are unopened. To the right of the label, and
   in the accent color so it reads as a mark rather than as part of the words. */
.cm-unread {
    margin-left: 0.35rem;
    font-weight: 700;
    font-size: 1.1em;
    line-height: 1;
    vertical-align: text-top;
}

/* ---- files dropped into a rich text editor ----------------------------------------------------
   wwwroot/js/quill-editor.js adds cm-quill-dropping while a file is over an editor that accepts
   one, and inserts a cm-file-video player for a dropped video. Both classes only ever appear on
   the editors that carry an image button. */

.cm-quill.cm-quill-dropping {
    outline: 2px dashed var(--cm-accent, #1b6ec2);
    outline-offset: -2px;
    background: var(--cm-raised, #f7f7f7);
}

.cm-quill .ql-editor video.cm-file-video,
.cm-comments-readonly video.cm-file-video,
video.cm-file-video {
    display: block;
    max-width: 100%;
    /* A player with no size is a 300x150 black box in most browsers until the metadata loads,
       and nothing here preloads metadata. */
    height: auto;
    margin: 0.5rem 0;
    background: #000;
}

.cm-quill .ql-editor img {
    max-width: 100%;
    height: auto;
    cursor: pointer;
}

/* A picture chosen by clicking it. wwwroot/js/quill-editor.js draws this frame over the picture
   rather than marking the <img>, which is content and would be saved with the mark. The frame lets
   clicks through to the editor underneath; only its button takes them. */
.cm-quill .cm-quill-picture-frame {
    position: absolute;
    z-index: 2;
    outline: 3px solid var(--cm-accent, #1b6ec2);
    outline-offset: -3px;
    pointer-events: none;
}

.cm-quill .cm-quill-picture-delete {
    position: absolute;
    top: 0.5rem;
    right: 0.5rem;
    pointer-events: auto;
    white-space: nowrap;
    line-height: 1;
    padding: 0.35rem 0.6rem;
    box-shadow: 0 1px 4px rgba(0, 0, 0, 0.35);
}

/* The Bootstrap Icons bin, drawn as a mask so it takes the button's text color - the same shape
   as the grids' .cm-trash-icon, which is scoped to its pages and cannot reach a button this
   script builds. */
.cm-quill-trash {
    display: inline-block;
    width: 1rem;
    height: 1rem;
    vertical-align: -0.15em;
    background-color: currentColor;
    -webkit-mask: no-repeat center / contain url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 16 16'%3E%3Cpath d='M5.5 5.5A.5.5 0 0 1 6 6v6a.5.5 0 0 1-1 0V6a.5.5 0 0 1 .5-.5Zm2.5 0a.5.5 0 0 1 .5.5v6a.5.5 0 0 1-1 0V6a.5.5 0 0 1 .5-.5Zm3 .5a.5.5 0 0 0-1 0v6a.5.5 0 0 0 1 0V6Z'/%3E%3Cpath d='M14.5 3a1 1 0 0 1-1 1H13v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V4h-.5a1 1 0 0 1-1-1V2a1 1 0 0 1 1-1H6a1 1 0 0 1 1-1h2a1 1 0 0 1 1 1h3.5a1 1 0 0 1 1 1v1ZM4.118 4 4 4.059V13a1 1 0 0 0 1 1h6a1 1 0 0 0 1-1V4.059L11.882 4H4.118ZM2.5 3h11V2h-11v1Z'/%3E%3C/svg%3E");
    mask: no-repeat center / contain url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 16 16'%3E%3Cpath d='M5.5 5.5A.5.5 0 0 1 6 6v6a.5.5 0 0 1-1 0V6a.5.5 0 0 1 .5-.5Zm2.5 0a.5.5 0 0 1 .5.5v6a.5.5 0 0 1-1 0V6a.5.5 0 0 1 .5-.5Zm3 .5a.5.5 0 0 0-1 0v6a.5.5 0 0 0 1 0V6Z'/%3E%3Cpath d='M14.5 3a1 1 0 0 1-1 1H13v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V4h-.5a1 1 0 0 1-1-1V2a1 1 0 0 1 1-1H6a1 1 0 0 1 1-1h2a1 1 0 0 1 1 1h3.5a1 1 0 0 1 1 1v1ZM4.118 4 4 4.059V13a1 1 0 0 0 1 1h6a1 1 0 0 0 1-1V4.059L11.882 4H4.118ZM2.5 3h11V2h-11v1Z'/%3E%3C/svg%3E");
}

/* ---- adding your own organization ---------------------------------------------------------------
   The invitation on the front page, the honeypot that has to be invisible to people but present
   to anything reading the markup, and the terms panel. */

.cm-testdrive {
    margin: 0 0 1rem 0;
    padding: 0.75rem 1rem;
    border: 1px solid var(--cm-border, #d6d5d5);
    border-radius: 0.4rem;
    background: var(--cm-raised, #f7f7f7);
    font-size: 1.05rem;
}

/* Off screen rather than display:none or hidden: something deciding which fields to fill in can
   see both of those, and skipping the trap is the one thing it must not do. */
.cm-hp {
    position: absolute;
    left: -9999px;
    width: 1px;
    height: 1px;
    overflow: hidden;
}

/* The terms panel. Opened by the address - #cm-terms - so it needs no script, and closed by a
   link back to # . */
.cm-termsmodal {
    display: none;
    position: fixed;
    inset: 0;
    z-index: 1000;
    background: rgba(0, 0, 0, 0.55);
    padding: 2rem 1rem;
    overflow: auto;
}

/* Opened by the checkbox beside it rather than by the address: a fragment link would be an
   enhanced navigation, and the half-filled form would not survive it. */
.cm-termstoggle {
    position: absolute;
    left: -9999px;
    width: 1px;
    height: 1px;
}

.cm-termstoggle:checked + .cm-termsmodal {
    display: block;
}

/* The label is what people press, so it has to look and behave like the button it is - including
   showing focus when the checkbox behind it is focused by keyboard. */
.cm-termsopen {
    cursor: pointer;
}

.cm-termstoggle:focus-visible + .cm-termsmodal,
.cm-termstoggle:focus-visible ~ .cm-profilebar .cm-termsopen {
    outline: 2px solid var(--cm-focus, #258cfb);
    outline-offset: 2px;
}

.cm-termsmodal-panel {
    max-width: 52rem;
    margin: 0 auto;
    padding: 1.25rem 1.5rem;
    border-radius: 0.5rem;
    background: var(--cm-surface, #ffffff);
    color: var(--cm-text, #212529);
    box-shadow: 0 1rem 3rem rgba(0, 0, 0, 0.4);
}

.cm-termsmodal-body {
    max-height: 60vh;
    overflow-y: auto;
    padding-right: 0.5rem;
    border-bottom: 1px solid var(--cm-border, #d6d5d5);
}

.cm-termsmodal-body p {
    margin: 0 0 0.75rem 0;
}

/* The tick goes at the foot of the panel, where somebody who has read to the bottom finds it. */
.cm-termsmodal-accept {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    padding-top: 0.85rem;
}

.cm-signedup {
    max-width: 40rem;
}


/* While a document editor is open over the page, the page behind it does not scroll. Set on the
   body by wwwroot/js/content-dialog.js. */
body.cm-dialog-showing {
    overflow: hidden;
}

/* ---- windows that can be resized ---------------------------------------------------------------
   wwwroot/js/window-size.js gives the editors' windows - the home page panel, the content dialogs
   and the help panel while it is being edited - a Maximize / Normal button beside the close cross
   and a handle along every edge. Here rather than in the pages' own stylesheets, because the
   script builds these and scoped styles never reach them. */

.cm-resizable {
    position: relative;
}

.cm-window-tools {
    display: inline-flex;
    align-items: center;
    gap: 0.15rem;
    margin-left: auto;
}

.cm-window-tool {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border: 0;
    border-radius: 0.25rem;
    background: transparent;
    color: inherit;
    padding: 0.3rem;
    line-height: 1;
    cursor: pointer;
    opacity: 0.7;
}

.cm-window-tool:hover,
.cm-window-tool:focus-visible {
    opacity: 1;
    background: rgba(0, 0, 0, 0.07);
}

/* Drawn in outline, like a desktop window's own button. */
.cm-window-tool svg {
    display: block;
    width: 1rem;
    height: 1rem;
    fill: none;
    stroke: currentColor;
    stroke-width: 1.5;
}

/* The handles: thin strips along the sides and small squares at the corners, above whatever the
   window holds, and invisible apart from the cursor they give. */
.cm-window-edge {
    position: absolute;
    z-index: 5;
    touch-action: none;
}

.cm-window-edge[data-cm-window-edge="n"],
.cm-window-edge[data-cm-window-edge="s"] {
    left: 0.75rem;
    right: 0.75rem;
    height: 0.45rem;
    cursor: ns-resize;
}

.cm-window-edge[data-cm-window-edge="e"],
.cm-window-edge[data-cm-window-edge="w"] {
    top: 0.75rem;
    bottom: 0.75rem;
    width: 0.45rem;
    cursor: ew-resize;
}

.cm-window-edge[data-cm-window-edge="n"] { top: 0; }
.cm-window-edge[data-cm-window-edge="s"] { bottom: 0; }
.cm-window-edge[data-cm-window-edge="e"] { right: 0; }
.cm-window-edge[data-cm-window-edge="w"] { left: 0; }

.cm-window-edge[data-cm-window-edge="ne"],
.cm-window-edge[data-cm-window-edge="nw"],
.cm-window-edge[data-cm-window-edge="se"],
.cm-window-edge[data-cm-window-edge="sw"] {
    width: 0.75rem;
    height: 0.75rem;
}

.cm-window-edge[data-cm-window-edge="ne"] { top: 0; right: 0; cursor: nesw-resize; }
.cm-window-edge[data-cm-window-edge="sw"] { bottom: 0; left: 0; cursor: nesw-resize; }
.cm-window-edge[data-cm-window-edge="nw"] { top: 0; left: 0; cursor: nwse-resize; }
.cm-window-edge[data-cm-window-edge="se"] { bottom: 0; right: 0; cursor: nwse-resize; }

/* While an edge is being dragged the cursor stays the edge's wherever it goes, and the text under
   it is not selected on the way. */
body.cm-window-resizing {
    user-select: none;
}

body.cm-window-resizing[data-cm-window-edge="n"],
body.cm-window-resizing[data-cm-window-edge="s"] { cursor: ns-resize; }
body.cm-window-resizing[data-cm-window-edge="e"],
body.cm-window-resizing[data-cm-window-edge="w"] { cursor: ew-resize; }
body.cm-window-resizing[data-cm-window-edge="ne"],
body.cm-window-resizing[data-cm-window-edge="sw"] { cursor: nesw-resize; }
body.cm-window-resizing[data-cm-window-edge="nw"],
body.cm-window-resizing[data-cm-window-edge="se"] { cursor: nwse-resize; }

/* Once a window has been given a size, the document editor in it grows into the room rather than
   leaving it empty below. The certificate is left alone: it is a sheet of letter paper, and its
   window scrolls round it. */
.cm-window-sized .cm-dialog-body:not(.cm-certificate-body),
.cm-window-sized .cm-modal-body {
    display: flex;
    flex-direction: column;
}

.cm-window-sized .cm-dialog-body > .cm-quill-document {
    flex: 1 0 auto;
}

.cm-window-sized .cm-modal-body > .cm-homepage-form {
    display: flex;
    flex-direction: column;
    flex: 1 0 auto;
}

.cm-window-sized .cm-homepage-form > .cm-homepage-editing {
    flex: 1 0 auto;
}

/* The help panel scrolls as one box. Once it can be resized only what is under its bar scrolls, so
   the bar and the handles stay put rather than scrolling away with the text. */
.cm-help-box.cm-resizable {
    display: flex;
    flex-direction: column;
    overflow: hidden;
}

.cm-help-box.cm-resizable > form {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
}

.cm-help-bar .cm-window-tools {
    align-self: center;
}

/* And given a size, the help text's editor takes the room. */
.cm-window-sized.cm-help-box > form {
    display: flex;
    flex-direction: column;
}

.cm-window-sized.cm-help-box .cm-field:has(> .cm-quill) {
    display: flex;
    flex-direction: column;
    flex: 1 0 auto;
}

.cm-window-sized.cm-help-box .cm-field > .cm-quill {
    flex: 1 0 auto;
}


/* ---- the editors' fonts ----------------------------------------------------------------------

   Not here any more. Every face the toolbar offers - the rule that draws it and the rule that
   names it in the dropdown - is built from one list, Services/EditorFonts.cs, and written into
   the page by Components/App.razor. That list is what the printed invitation reads too
   (Services/InvitationPdf.cs), so screen and paper cannot drift apart. Add a font there. */

/* Quill's huge size is 2.5em, which is the size an invitation wants for the names. Stated here
   as well, because the theme's own rule only applies inside an editor and a preview rendered
   from the database is not always one. */
.cm-rendered .ql-size-huge {
    font-size: 2.5em;
}

.cm-rendered .ql-size-large {
    font-size: 1.5em;
}

.cm-rendered .ql-align-center {
    text-align: center;
}


/* ---- a two-column list --------------------------------------------------------------------

   Written into saved content as <ul class="cm-two-columns"> - see the Why Use Us page. CSS
   columns rather than two lists side by side, so the two halves balance themselves as bullets
   are added or removed, and one list is what an editor is easy to work in.

   The class survives a save because Services/RichText.cs allows class; the same rule written as
   an inline style would not, since only color and background-color are kept there.

   Both selectors: the rendered page, and the editor's own content area, so what is written looks
   like what is published. */

.cm-rendered .cm-two-columns,
.ql-editor .cm-two-columns {
    columns: 2;
    column-gap: 2.5rem;
}

.cm-rendered .cm-two-columns > li,
.ql-editor .cm-two-columns > li {
    /* A bullet is not split across the column break: half a sentence at the foot of one column
       and half at the head of the next is unreadable. */
    break-inside: avoid;
    margin-bottom: 0.6rem;
}

/* One column on a narrow screen - two columns of this width on a phone would be a word each. */
@media (max-width: 47rem) {
    .cm-rendered .cm-two-columns,
    .ql-editor .cm-two-columns {
        columns: 1;
    }
}

/* ---- field tips ------------------------------------------------------------------------------

   The short notes under the fields, which every form on this site carries as .form-text. A user
   who clears Show Field Tips on their profile gets cm-no-fieldtips on the page - see
   Components/Layout/MainLayout.razor - and the notes are not shown to them.

   Hidden rather than not rendered: the pages are statically rendered and the markup is the same
   for everybody, so this is the one place the setting has to be applied. Validation messages are
   a different class and are never hidden - a tip is advice, and an error is not. */
.cm-no-fieldtips .form-text {
    display: none;
}

/* ---- the editor background control -----------------------------------------------------------

   A color well and a clear button on every Quill toolbar that is not a plain text editor's, added
   by wwwroot/js/quill-editor.js. Quill sizes its own buttons; these have to be told, or the well
   renders at whatever height the browser feels like and pushes the toolbar row apart. */
.cm-backing {
    display: inline-flex;
    align-items: center;
    gap: 0.15rem;
}

.cm-backing-label {
    display: inline-flex;
    margin: 0;
    cursor: pointer;
}

.cm-backing-well {
    width: 24px;
    height: 24px;
    padding: 0;
    border: 1px solid var(--cm-border, rgba(0, 0, 0, 0.175));
    border-radius: 0.2rem;
    background: transparent;
    cursor: pointer;
}

/* The swatch inside the well, which each browser wraps in its own padding. */
.cm-backing-well::-webkit-color-swatch-wrapper {
    padding: 2px;
}

.cm-backing-well::-webkit-color-swatch {
    border: 0;
    border-radius: 0.1rem;
}

.cm-backing-clear {
    border: 0;
    background: transparent;
    line-height: 1;
    padding: 0 0.2rem;
    font-size: 0.85rem;
    color: var(--cm-muted, #6c757d);
    cursor: pointer;
}

.cm-backing-clear:hover {
    color: var(--cm-text, #212529);
}

/* The text color and highlight wells beside them (2026-09-28), each an "A" with the color under
   it - or behind it, for a highlight - and the browser's color well laid over it, unseen, to take
   the click. */
.cm-text-colors {
    display: inline-flex;
    align-items: center;
    gap: 0.15rem;
}

.cm-text-color {
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 24px;
    height: 24px;
    margin: 0;
    border: 1px solid var(--cm-border, rgba(0, 0, 0, 0.175));
    border-radius: 0.2rem;
    cursor: pointer;
}

.cm-text-color-mark {
    font-weight: 700;
    font-size: 0.95rem;
    line-height: 1;
    padding: 0 0.15rem 1px;
    color: #212529;
    border-bottom: 4px solid var(--cm-text-color, #000000);
}

.cm-text-color-background .cm-text-color-mark {
    border-bottom: 0;
    padding: 2px 0.2rem;
    background: var(--cm-text-color, transparent);
    outline: 1px dashed rgba(0, 0, 0, 0.3);
}

.cm-text-color-well {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    padding: 0;
    border: 0;
    opacity: 0;
    cursor: pointer;
}

.cm-text-color:focus-within {
    outline: 2px solid var(--cm-accent, #0d6efd);
    outline-offset: 1px;
}

/* ---- the theme preview panel -----------------------------------------------------------------

   /CSSPreview shown in a frame on the forms that choose a theme - system settings, the
   organization profile, the event profile. A frame rather than the stylesheet loaded into the
   page, because a theme restyles body, the sidebar and every control, and loading it here would
   repaint the page being edited.

   Global rather than scoped to a page: it was written twice, in SystemSettings.razor.css and
   OrganizationProfile.razor.css, and the event profile had neither - so the frame there fell back
   to what an iframe is without styling, 300 by 150 pixels in the corner of the page. One copy,
   and every page that opens the panel gets a preview the width of the page. */
.cm-preview-panel {
    border: 1px solid var(--cm-border, #d6d5d5);
    border-radius: 0.375rem;
    margin-bottom: 1rem;
    overflow: hidden;
}

.cm-preview-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.5rem;
    padding: 0.4rem 0.7rem;
    border-bottom: 1px solid var(--cm-border, #d6d5d5);
    font-weight: 600;
}

/* The width of whatever holds it - which on all three pages is the page - and tall enough to
   judge a theme by: a header, a form and a table at once. */
.cm-preview-frame {
    display: block;
    width: 100%;
    height: 38rem;
    border: 0;
}

/* ---- Address Line 1 suggestions - wwwroot/js/address-lookup.js ----------------------------
   Global rather than scoped: the list is created by the script beside whichever form's box asked,
   and a page's scoped stylesheet never reaches an element it did not render. */
.cm-address-suggest {
    position: absolute;
    z-index: 1060;
    max-height: 16rem;
    overflow-y: auto;
    margin-top: 2px;
    border: 1px solid var(--cm-border, #d6d5d5);
    border-radius: 0.375rem;
    background: var(--cm-surface, #ffffff);
    color: var(--cm-text, #212529);
    box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);
}

.cm-address-option {
    padding: 0.35rem 0.6rem;
    cursor: pointer;
    white-space: normal;
    line-height: 1.3;
}

.cm-address-option + .cm-address-option {
    border-top: 1px solid var(--cm-border, #eeeeee);
}

.cm-address-option:hover,
.cm-address-option.cm-address-active {
    background: var(--cm-raised, #e9f2ff);
}

/* The credit under each of those boxes - Components/Shared/GeoapifyCredit.razor. */
.cm-geoapify {
    margin: 0.35rem 0 0;
    font-size: 0.8em;
    opacity: 0.75;
    text-align: right;
}


/* ---- online chat ----------------------------------------------------------------------------
   The window a visitor talks in - wwwroot/js/online-chat.js - and the Online Chats page staff
   answer from - wwwroot/js/online-chat-staff.js (2026-09-26). Both are built by script, so their
   styles live here, where scoped styles are not needed to reach them. */

.cm-chat-window {
    position: fixed;
    z-index: 1070;
    left: 0;
    top: 0;
    width: 340px;
    max-width: calc(100vw - 16px);
    height: 460px;
    max-height: calc(100vh - 16px);
    display: flex;
    flex-direction: column;
    background: var(--cm-surface, #ffffff);
    color: var(--cm-text, #212529);
    border: 1px solid var(--cm-border, rgba(0, 0, 0, 0.175));
    border-radius: 0.5rem;
    box-shadow: 0 0.75rem 2rem rgba(0, 0, 0, 0.3);
    overflow: hidden;
    font-size: 0.9rem;
}

.cm-chat-window[hidden] {
    display: none;
}

/* Minimized, it is its title bar alone - still there, still movable, still counting replies. */
.cm-chat-window.cm-chat-minimized {
    height: auto;
}

.cm-chat-window.cm-chat-minimized .cm-chat-body {
    display: none;
}

.cm-chat-head {
    display: flex;
    align-items: center;
    gap: 0.35rem;
    padding: 0.45rem 0.6rem 0.45rem 0.8rem;
    background: var(--cm-accent, #1b6ec2);
    color: #ffffff;
    cursor: move;
    user-select: none;
    touch-action: none;
}

.cm-chat-title {
    flex: 1 1 auto;
    font-weight: 700;
}

.cm-chat-head button {
    border: 0;
    background: transparent;
    color: inherit;
    font-size: 1.15rem;
    line-height: 1;
    padding: 0.1rem 0.35rem;
    border-radius: 0.25rem;
    cursor: pointer;
    opacity: 0.85;
}

.cm-chat-head button:hover,
.cm-chat-head button:focus-visible {
    opacity: 1;
    background: rgba(255, 255, 255, 0.18);
}

.cm-chat-unread {
    min-width: 1.25rem;
    padding: 0 0.35rem;
    border-radius: 0.65rem;
    background: #dc3545;
    font-size: 0.75rem;
    line-height: 1.25rem;
    text-align: center;
}

.cm-chat-body {
    flex: 1 1 auto;
    min-height: 0;
    display: flex;
    flex-direction: column;
}

.cm-chat-start {
    padding: 0.75rem;
    overflow-y: auto;
}

.cm-chat-start label {
    display: block;
    margin-top: 0.5rem;
    font-weight: 600;
}

.cm-chat-intro {
    margin: 0 0 0.25rem;
}

.cm-chat-begin {
    margin-top: 0.75rem;
}

.cm-chat-talk {
    flex: 1 1 auto;
    min-height: 0;
    display: flex;
    flex-direction: column;
}

.cm-chat-talk[hidden],
.cm-chat-start[hidden] {
    display: none;
}

.cm-chat-lines {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    padding: 0.5rem 0.75rem;
    background: rgba(0, 0, 0, 0.035);
}

.cm-chat-line {
    max-width: 85%;
    margin: 0.4rem 0;
}

.cm-chat-who {
    margin-bottom: 0.1rem;
    font-size: 0.72rem;
    color: #6c757d;
}

.cm-chat-text {
    display: inline-block;
    padding: 0.35rem 0.6rem;
    border-radius: 0.6rem;
    background: #ffffff;
    color: #212529;
    white-space: pre-wrap;
    overflow-wrap: anywhere;
    text-align: left;
    box-shadow: 0 1px 1px rgba(0, 0, 0, 0.08);
}

/* Your own lines on the right, in the accent color - the visitor's in their window, staff's on
   the answering page. */
.cm-chat-visitor,
.cm-chat-staffside-staff {
    margin-left: auto;
    text-align: right;
}

.cm-chat-visitor .cm-chat-text,
.cm-chat-staffside-staff .cm-chat-text {
    background: var(--cm-accent, #1b6ec2);
    color: #ffffff;
}

.cm-chat-system {
    max-width: 100%;
    text-align: center;
    font-size: 0.8rem;
    font-style: italic;
    color: #6c757d;
}

.cm-chat-system .cm-chat-text {
    background: transparent;
    box-shadow: none;
    padding: 0;
    color: inherit;
    text-align: center;
}

.cm-chat-send {
    display: flex;
    align-items: flex-end;
    gap: 0.4rem;
    padding: 0.5rem 0.75rem 0;
}

.cm-chat-send[hidden],
.cm-chat-foot[hidden],
.cm-chat-done[hidden] {
    display: none;
}

.cm-chat-send textarea {
    flex: 1 1 auto;
    resize: none;
}

.cm-chat-foot {
    display: flex;
    justify-content: flex-end;
    padding: 0.15rem 0.5rem 0.35rem;
}

.cm-chat-error {
    margin: 0.35rem 0.75rem 0;
    font-size: 0.85rem;
    color: #b02a37;
}

.cm-chat-start .cm-chat-error {
    margin: 0.5rem 0 0;
}

.cm-chat-done {
    padding: 0.5rem 0.75rem 0.75rem;
}

.cm-chat-done-text {
    margin: 0 0 0.5rem;
}

body.cm-chat-dragging {
    cursor: move;
    user-select: none;
}

/* The Online Chats page: the list on the left, the chat chosen on the right. */
.cm-chatdesk {
    display: grid;
    grid-template-columns: minmax(14rem, 22rem) 1fr;
    gap: 1rem;
    align-items: start;
}

@media (max-width: 767.98px) {
    .cm-chatdesk {
        grid-template-columns: 1fr;
    }
}

.cm-chatdesk-list {
    display: flex;
    flex-direction: column;
    gap: 0.4rem;
    max-height: 70vh;
    overflow-y: auto;
}

.cm-chatdesk-item {
    display: flex;
    flex-direction: column;
    gap: 0.1rem;
    padding: 0.5rem 0.65rem;
    border: 1px solid var(--cm-border, rgba(0, 0, 0, 0.175));
    border-radius: 0.4rem;
    background: var(--cm-surface, #ffffff);
    color: inherit;
    text-align: left;
    cursor: pointer;
}

.cm-chatdesk-item:hover,
.cm-chatdesk-item:focus-visible {
    border-color: var(--cm-accent, #1b6ec2);
}

.cm-chatdesk-selected {
    border-color: var(--cm-accent, #1b6ec2);
    box-shadow: inset 3px 0 0 var(--cm-accent, #1b6ec2);
}

.cm-chatdesk-item-top {
    display: flex;
    justify-content: space-between;
    gap: 0.5rem;
}

.cm-chatdesk-badge {
    flex: 0 0 auto;
    padding: 0 0.45rem;
    border-radius: 0.65rem;
    background: #e9ecef;
    font-size: 0.75rem;
    line-height: 1.35rem;
}

.cm-chatdesk-waiting .cm-chatdesk-badge {
    background: #dc3545;
    color: #ffffff;
}

.cm-chatdesk-ended {
    opacity: 0.7;
}

.cm-chatdesk-where,
.cm-chatdesk-when {
    font-size: 0.8rem;
    color: #6c757d;
}

.cm-chatdesk-chat {
    display: flex;
    flex-direction: column;
    min-height: 24rem;
    border: 1px solid var(--cm-border, rgba(0, 0, 0, 0.175));
    border-radius: 0.5rem;
    background: var(--cm-surface, #ffffff);
    overflow: hidden;
}

.cm-chatdesk-chat > .cm-empty {
    padding: 1rem;
}

.cm-chatdesk-head {
    padding: 0.6rem 0.9rem;
    border-bottom: 1px solid var(--cm-border, rgba(0, 0, 0, 0.175));
}

.cm-chatdesk-head h2 {
    margin: 0 0 0.2rem;
    font-size: 1.1rem;
}

.cm-chatdesk-facts {
    margin: 0;
    font-size: 0.85rem;
    color: #6c757d;
}

.cm-chatdesk-lines {
    height: 22rem;
    flex: 0 0 auto;
}

.cm-chatdesk-reply {
    padding: 0.6rem 0.9rem 0;
}

.cm-chatdesk-end {
    align-self: flex-end;
    margin: 0.5rem 0.9rem 0.75rem;
}

.cm-chatdesk-end[hidden],
.cm-chatdesk-ended-note[hidden],
.cm-chatdesk-reply[hidden] {
    display: none;
}

.cm-chatdesk-ended-note {
    margin: 0.75rem 0.9rem;
    font-style: italic;
    color: #6c757d;
}

/* A profile's Logos field (2026-09-27: "Make Organization & Event Logos drag and drop. Allow
   multiple"). The logos as tiles in their order, the first marked as the one heading the home
   pages, each dragged to a new place; under them the place to drop files. Global rather than the
   profiles' own, since wwwroot/js/logo-list.js draws the tiles again after every change. */
.cm-logo-list {
    list-style: none;
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    margin: 0 0 0.5rem;
    padding: 0;
}

.cm-logo-tile {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 8rem;
    height: 4.75rem;
    padding: 0.35rem 0.35rem 1.1rem;
    background: #fff;
    border: 1px solid var(--cm-border, #d6d5d5);
    border-radius: 0.375rem;
}

.cm-logo-tile[draggable="true"] {
    cursor: grab;
}

.cm-logo-tile img {
    max-width: 100%;
    max-height: 100%;
    object-fit: contain;
}

.cm-logo-tile.cm-dragging {
    opacity: 0.5;
}

.cm-logo-tile.cm-drop-before {
    box-shadow: inset 4px 0 0 var(--cm-accent, #1b6ec2);
}

.cm-logo-tile.cm-drop-after {
    box-shadow: inset -4px 0 0 var(--cm-accent, #1b6ec2);
}

.cm-logo-badge {
    position: absolute;
    left: 0.3rem;
    bottom: 0.2rem;
    padding: 0 0.3rem;
    font-size: 0.65rem;
    font-weight: 600;
    color: #fff;
    background: var(--cm-accent, #1b6ec2);
    border-radius: 0.25rem;
}

.cm-logo-remove {
    position: absolute;
    top: 0.15rem;
    right: 0.15rem;
    width: 1.4rem;
    height: 1.4rem;
    padding: 0;
    border: 0;
    border-radius: 50%;
    font-size: 1rem;
    line-height: 1;
    color: var(--bs-danger, #dc3545);
    background: rgba(255, 255, 255, 0.9);
}

.cm-logo-none {
    margin: 0 0 0.5rem;
    font-style: italic;
    opacity: 0.75;
}

.cm-logo-drop {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem;
    padding: 0.6rem;
    border: 2px dashed var(--cm-border, #c9c9c9);
    border-radius: 0.375rem;
}

.cm-logo-drop input[type="file"] {
    flex: 1 1 14rem;
    max-width: 22rem;
}

.cm-logos.cm-logo-dropping .cm-logo-drop {
    border-color: var(--cm-accent, #1b6ec2);
    background: rgba(27, 110, 194, 0.06);
}

.cm-logos[data-cm-busy] {
    opacity: 0.7;
}

.cm-logo-saved {
    margin-top: 0.25rem;
    font-weight: 600;
}

/* The home page editor's Photos list (2026-09-27), beside the editor when it is open: the
   editor's toolbar and content in the first column, the list down the second. On a narrow
   screen the list goes under the editor. Global, since the toolbar is Quill's and the list's
   new entries are drawn by wwwroot/js/photo-list.js. */
.cm-homepage-tools {
    display: flex;
    justify-content: flex-end;
    margin-bottom: 0.35rem;
}

.cm-homepage-editing {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    grid-template-rows: auto 1fr;
    column-gap: 0.75rem;
}

.cm-homepage-editing > :not(.cm-photo-list) {
    grid-column: 1;
}

.cm-homepage-editing > .ql-toolbar {
    grid-row: 1;
}

.cm-homepage-editing > .cm-homepage-quill {
    grid-row: 2;
}

.cm-homepage-editing > .cm-photo-list {
    grid-column: 2;
    grid-row: 1 / span 2;
    width: 16rem;
    max-height: 40rem;
    overflow-y: auto;
    padding: 0.5rem;
    background: var(--cm-surface, #fafafa);
    border: 1px solid var(--cm-border, #d6d5d5);
    border-radius: 0.375rem;
}

@media (max-width: 760px) {
    .cm-homepage-editing {
        grid-template-columns: minmax(0, 1fr);
    }

    .cm-homepage-editing > .cm-photo-list {
        grid-column: 1;
        grid-row: auto;
        width: auto;
        margin-top: 0.5rem;
    }
}

.cm-photo-hint {
    margin: 0 0 0.5rem;
    font-size: 0.8rem;
    opacity: 0.8;
}

.cm-photo-empty {
    margin: 0 0 0.5rem;
    font-size: 0.85rem;
    font-style: italic;
}

.cm-photo-items {
    display: grid;
    gap: 0.5rem;
    margin: 0;
    padding: 0;
    list-style: none;
}

.cm-photo-item {
    display: grid;
    grid-template-columns: 4.5rem minmax(0, 1fr);
    gap: 0.5rem;
    align-items: center;
}

.cm-photo-thumb {
    width: 4.5rem;
    height: 3.5rem;
    object-fit: cover;
    background: #fff;
    border: 1px solid var(--cm-border, #d6d5d5);
    border-radius: 0.25rem;
    cursor: grab;
}

.cm-photo-meta {
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
    min-width: 0;
}

.cm-photo-insert {
    align-self: flex-start;
    padding: 0;
}

.cm-photo-status {
    min-height: 1em;
    margin: 0.5rem 0 0;
    font-size: 0.8rem;
}

/* The resize handle on a chosen picture's frame (2026-09-27: "Photos should be resizeable in the
   editors"). The frame takes no pointer events; the handle does. While it is dragged the frame
   shows the size the picture will take when it is let go. */
.cm-quill .cm-quill-picture-resize {
    position: absolute;
    right: -7px;
    bottom: -7px;
    width: 14px;
    height: 14px;
    border: 2px solid #fff;
    border-radius: 3px;
    background: var(--cm-accent, #1b6ec2);
    box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.25);
    cursor: nwse-resize;
    pointer-events: auto;
    touch-action: none;
}

.cm-quill .cm-quill-picture-frame.cm-quill-picture-sizing {
    outline-style: dashed;
    background: rgba(27, 110, 194, 0.08);
}

/* An event's home page before anybody has written one (2026-09-28): what the event says
   about itself - title, tag line, days, description - centered, and its way in. */
.cm-event-starter {
    max-width: 46rem;
    margin: 2rem auto;
    text-align: center;
}

.cm-event-starter h1 {
    margin-bottom: 0.5rem;
}

.cm-event-starter-tagline {
    font-size: 1.25rem;
    font-style: italic;
}

.cm-event-starter-days {
    font-size: 1.1rem;
    font-weight: 600;
}

.cm-event-starter-description {
    white-space: pre-line;
    text-align: left;
}

/* The editors' font sizes, in pixels (2026-09-28: "In quill I want font sizes in px ... append px to
   each ... in 2px increments up to 48 px"). Quill's own dropdown names only its four; these show
   each size as it is, "14px", and the page's own size as Default. The list is long, so it scrolls. */
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value]::before,
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value]::before {
    content: attr(data-value);
}

.ql-snow .ql-picker.ql-size .ql-picker-label:not([data-value])::before,
.ql-snow .ql-picker.ql-size .ql-picker-item:not([data-value])::before {
    content: 'Default';
}

.ql-snow .ql-picker.ql-size .ql-picker-options {
    max-height: 18rem;
    overflow-y: auto;
}

/* An event page's list of items (2026-09-28) - HomePageContents.ItemListHtml, where the page has
   {{Events.ListItems}}: "Divide the items evenly by 3 and put the list in a table the full width of
   the page. Make the list an unordered list. List each item on its own line. The table does not
   need borders." Three equal columns, left aligned whatever the page around them is, and one
   column on a phone. More particular than .cm-rendered's table rules above, which it overrides. */
.cm-rendered table.cm-item-list {
    width: 100%;
    table-layout: fixed;
    margin: 0.75rem 0;
    border: 0;
    text-align: left;
}

.cm-rendered table.cm-item-list td {
    border: 0;
    padding: 0 1rem 0 0;
    vertical-align: top;
    background: none;
}

.cm-rendered table.cm-item-list ul {
    margin: 0;
    padding-left: 1.25rem;
}

.cm-rendered table.cm-item-list li {
    margin: 0 0 0.35rem;
}

@media (max-width: 575.98px) {
    .cm-rendered table.cm-item-list td {
        display: block;
        width: auto;
        padding-right: 0;
    }
}

/* {{Events.SponsorList}} (2026-10-01): a row of sponsors for each level, "evenly spaced in the center
   50% of the page" - MergeTokenResolver.SponsorListAsync. It writes everything inline for the mail
   programs, but a page sanitizes the merged HTML, which keeps only the font sizes and the cells'
   inline-size; these rules are the rest of it there. The whole width on a phone. */
.cm-sponsor-list {
    inline-size: 50%;
    margin: 0 auto;
}

/* Equal columns, so a row's sponsors are evenly spaced. */
.cm-rendered table.cm-sponsor-level {
    width: 100%;
    table-layout: fixed;
    border-collapse: collapse;
    border: 0;
    margin: 0 0 0.5em;
}

/* Tight (2026-10-01: "They also need to be tighter vertically"). */
.cm-rendered table.cm-sponsor-level th,
.cm-rendered table.cm-sponsor-level td {
    border: 0;
    background: none;
    text-align: center;
    vertical-align: top;
    padding: 0.15em 0.4em;
    line-height: 1.15;
}

.cm-rendered table.cm-sponsor-level th {
    padding: 0 0 0.15em;
}

.cm-sponsor-logo {
    display: block;
    max-width: 100%;
    height: auto;
    margin: 0 auto 0.15em;
}

/* A sponsor's column is a container, so its name can be no larger than the column holds: the
   row's size where it fits (Platinum's and Gold's), a little smaller in a crowded row - four
   to a row in half the page - rather than broken inside a word. */
.cm-sponsor-card {
    container-type: inline-size;
}

.cm-rendered .cm-sponsor-name {
    font-weight: 700;
    font-size: min(1em, 14cqi);
    overflow-wrap: break-word;
}

.cm-sponsor-details {
    line-height: 1.3;
    margin-top: 0.1em;
    overflow-wrap: anywhere;
}

@media (max-width: 767.98px) {
    .cm-sponsor-list {
        width: 100% !important;
        inline-size: 100% !important;
    }
}

/* ---- a drop box for an upload (wwwroot/js/file-drop.js) ----------------------------------------
   First the RSVP spreadsheet import's (2026-09-23), and since 2026-10-02 every upload's: "any place
   where an image, csv, txt, rtf, pdf, xls, xlsx, doc or docx file is uploaded". The real file input
   sits inside, so the picker and the keyboard still work; dragging is the shortcut. */
.cm-filedrop {
    border: 2px dashed var(--cm-border, rgba(0, 0, 0, 0.25));
    border-radius: 0.375rem;
    padding: 0.75rem 1rem;
    text-align: center;
    transition: border-color 0.15s ease-in-out, background-color 0.15s ease-in-out;
}

/* While a file is over it. Mixed from the theme's accent so it is right in every theme. */
.cm-filedrop-over {
    border-color: var(--cm-accent, #1b6ec2);
    background-color: color-mix(in srgb, var(--cm-accent, #1b6ec2) 10%, transparent);
}

.cm-filedrop-say {
    margin: 0 0 0.5rem;
    font-weight: 700;
}

.cm-filedrop input[type="file"] {
    max-width: 28rem;
    margin: 0 auto;
}

/* A box holding the file and its Upload button on one row. */
.cm-filedrop .cm-rowbar {
    justify-content: center;
}

.cm-filedrop-chosen {
    margin: 0.5rem 0 0;
    font-size: 0.95em;
    font-style: italic;
}

/* A file of a kind the box doesn't take. Said, not refused - the server decides. */
.cm-filedrop-wrong {
    font-style: normal;
    font-weight: 700;
    color: var(--cm-bad, #b02a37);
}

/* A dropped or chosen picture, before it is saved. */
.cm-filedrop-preview {
    display: block;
    max-width: 100%;
    max-height: 6rem;
    margin: 0.5rem auto 0;
}

.cm-filedrop-preview[hidden] {
    display: none;
}

/* An event's title sponsor's logo, on a line of its own between "Presented By" and its name wherever
   the event's title is shown (2026-10-02, EventTitles): three times the title's font size tall, and
   inline, so it follows the title's alignment. It carries this inline for mail programs too, but a
   page's sanitizer drops that style. */
img.cm-title-sponsor-logo {
    height: 3em;
    width: auto;
    max-width: 100%;
    vertical-align: middle;
}

/* ---- a home page's header, sidebar and footer bands (2026-09-30) ---------------------------------
   "I also want the header, footer, and sidebars to have an option for a light or dark background from
   their existing CSS Style sheet. If light is selected I want the color used for the CSS fonts. If dark
   is selected I want a white font." Light is the theme's own tint, --cm-raised, under its font color,
   --cm-text; dark is the theme's dark gradient - the one its nav bar wears - under white. The header's
   rules are pitched above the theme's `body .page > main > .top-row`, (0,2,2). See
   Components/Layout/MainLayout.razor and Services/HomePageLayouts.cs. */

body .page > main > .top-row.cm-homesite-band-light {
    background-color: var(--cm-raised);
    color: var(--cm-text);
}

body .page > main > .top-row.cm-homesite-band-light .cm-homesite-menu > .cm-homesite-item > a {
    color: var(--cm-text);
}

body .page > main > .top-row.cm-homesite-band-dark {
    background-color: var(--cm-sidebar-to);
    background-image: linear-gradient(90deg, var(--cm-sidebar-from) 0%, var(--cm-sidebar-to) 100%);
    border-bottom-color: var(--cm-sidebar-top-border);
    color: #ffffff;
}

body .page > main > .top-row.cm-homesite-band-dark .cm-homesite-menu > .cm-homesite-item > a,
body .page > main > .top-row.cm-homesite-band-dark .cm-help-link,
body .page > main > .top-row.cm-homesite-band-dark .cm-profile-link,
body .page > main > .top-row.cm-homesite-band-dark .cm-homesite-menu-button,
body .page > main > .top-row.cm-homesite-band-dark .cm-homesite-toggle {
    color: #ffffff;
}

/* The sidebar beside the page, on the left or the right; above it on a phone. A column of its own,
   flush with the edge of the window, whose background runs from the header down to the footer like
   the application's own nav bar (2026-10-01: "I want the sidebar background to run the height of
   the page, not just the menu items like it does in the main app"). main is made a column so the
   sidebar and the page fill whatever height the header and the footers leave, however short the
   page; the menu itself stays in view below the sticky header as the page scrolls. */
main.cm-homesite-with-sidebar {
    display: flex;
    flex-direction: column;
}

/* The page's wrapper when there is no sidebar beside it (2026-10-06): there only so the page keeps one
   place in the layout's markup - see MainLayout - and taking no part in how it's laid out. */
.cm-homesite-plain {
    display: contents;
}

.cm-homesite-columns {
    flex: 1 0 auto;
    display: flex;
    align-items: stretch;
}

.cm-homesite-columns.cm-homesite-sidebar-right {
    flex-direction: row-reverse;
}

.cm-homesite-main {
    flex: 1 1 auto;
    min-width: 0;
}

.cm-homesite-sidebar {
    flex: 0 0 15rem;
    padding: 1rem 0.5rem;
}

.cm-homesite-sidebar > nav {
    position: sticky;
    top: 4.5rem;
}

/* On the light background, a line where the sidebar meets the page. */
.cm-homesite-sidebar-left > .cm-homesite-sidebar.cm-homesite-band-light {
    border-right: 1px solid var(--cm-border, #dee2e6);
}

.cm-homesite-sidebar-right > .cm-homesite-sidebar.cm-homesite-band-light {
    border-left: 1px solid var(--cm-border, #dee2e6);
}

/* The footer band meets the sidebar's foot, so it runs flush across the window beneath it. */
main.cm-homesite-with-sidebar > .cm-homesite-footer {
    margin: 0;
    border-radius: 0;
}

.cm-homesite-sidebar.cm-homesite-band-light,
.cm-homesite-footer.cm-homesite-band-light {
    background-color: var(--cm-raised);
    color: var(--cm-text);
}

.cm-homesite-sidebar.cm-homesite-band-dark,
.cm-homesite-footer.cm-homesite-band-dark {
    background-color: var(--cm-sidebar-to);
    background-image: linear-gradient(180deg, var(--cm-sidebar-from) 0%, var(--cm-sidebar-to) 100%);
    color: #ffffff;
}

.cm-homesite-sidebar.cm-homesite-band-light a,
.cm-homesite-sidebar.cm-homesite-band-light summary,
.cm-homesite-footer.cm-homesite-band-light a {
    color: var(--cm-text);
}

.cm-homesite-sidebar.cm-homesite-band-dark a,
.cm-homesite-sidebar.cm-homesite-band-dark summary,
.cm-homesite-footer.cm-homesite-band-dark a {
    color: #ffffff;
}

/* The sidebar's menu: a page, or a collapsing panel of a page and the pages under it. */
.cm-homesite-side-menu,
.cm-homesite-side-menu ul {
    list-style: none;
    margin: 0;
    padding: 0;
}

.cm-homesite-side-menu a,
.cm-homesite-side-panel > summary {
    display: block;
    padding: 0.4rem 0.75rem;
    border-radius: 0.35rem;
    font-weight: 600;
    text-decoration: none;
}

.cm-homesite-side-menu a:hover,
.cm-homesite-side-menu a:focus-visible,
.cm-homesite-side-panel > summary:hover {
    background-color: rgba(127, 127, 127, 0.16);
    text-decoration: underline;
}

.cm-homesite-side-menu a.cm-homesite-current {
    text-decoration: underline;
    text-underline-offset: 0.25em;
}

.cm-homesite-side-panel > summary {
    cursor: pointer;
    list-style: none;
    position: relative;
    padding-right: 2rem;
}

.cm-homesite-side-panel > summary::-webkit-details-marker {
    display: none;
}

.cm-homesite-side-panel > summary::after {
    content: "";
    position: absolute;
    right: 0.85rem;
    top: 50%;
    width: 0.5rem;
    height: 0.5rem;
    border-right: 2px solid currentColor;
    border-bottom: 2px solid currentColor;
    transform: translateY(-70%) rotate(45deg);
    transition: transform 0.15s ease;
}

.cm-homesite-side-panel[open] > summary::after {
    transform: translateY(-30%) rotate(225deg);
}

.cm-homesite-side-panel > ul a {
    padding-left: 1.5rem;
    font-weight: 500;
}

/* A system administrator's own pages on organization 0's sidebar (2026-10-01), "after a blank
   line": a line's height of space above them. */
.cm-homesite-administration {
    margin-top: 1.5em;
}

/* How many chats wait on a reply, beside Online Chats - the nav bar's badge, which is scoped to
   NavMenu and so is repeated here. */
.cm-homesite-administration .cm-nav-count {
    display: inline-block;
    min-width: 1.25rem;
    margin-left: 0.4rem;
    padding: 0 0.35rem;
    border-radius: 0.65rem;
    background: #dc3545;
    color: #ffffff;
    font-size: 0.75rem;
    line-height: 1.25rem;
    text-align: center;
}

/* A page that signs the visitor out - organization 0's Logout (2026-10-01) - is a form's button,
   since a link cannot sign anybody out. In the header it is dressed as the links beside it; in the
   sidebar, as the sidebar's. */
.cm-homesite-signout {
    display: inline;
    margin: 0;
}

.cm-homesite-signout button {
    padding: 0;
    border: 0;
    background: transparent;
    color: var(--cm-link, #1b6ec2);
    font: inherit;
    font-weight: 700;
    font-style: italic;
    font-size: calc(1em - 2px);
    line-height: inherit;
    white-space: nowrap;
    cursor: pointer;
}

.cm-homesite-signout button:hover,
.cm-homesite-signout button:focus-visible {
    text-decoration: underline;
}

.cm-homesite-side-menu .cm-homesite-signout {
    display: block;
}

.cm-homesite-side-menu .cm-homesite-signout button {
    display: block;
    width: 100%;
    padding: 0.4rem 0.75rem;
    border-radius: 0.35rem;
    color: inherit;
    font-size: inherit;
    font-style: normal;
    font-weight: 600;
    text-align: left;
}

body .page > main > .top-row.cm-homesite-band-light .cm-homesite-signout button {
    color: var(--cm-text);
}

body .page > main > .top-row.cm-homesite-band-dark .cm-homesite-signout button {
    color: #ffffff;
}

/* Organization 0's header starts with Help as a question mark (2026-10-01): ahead of the logo
   (order -2) and the links (-1), which MainLayout.razor.css orders in a row laid out from the right. */
.cm-help-link.cm-help-icon {
    order: -3;
    display: inline-flex;
    align-items: center;
    margin-right: 1rem;
    font-size: inherit;
}

.cm-help-link.cm-help-icon svg {
    width: 1.35rem;
    height: 1.35rem;
}

/* The owner's footer band, above the site's footer. */
.cm-homesite-footer {
    display: flex;
    flex-wrap: wrap;
    gap: 1rem 3rem;
    align-items: flex-start;
    justify-content: space-between;
    margin: 1.5rem 1.5rem 0;
    padding: 1.25rem 1.5rem;
    border-radius: 0.5rem;
}

.cm-homesite-footer-who,
.cm-homesite-footer-reach {
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
}

.cm-homesite-footer-name {
    font-size: 1.1rem;
}

/* The social media icons, always in the band's lower right corner (2026-10-01), beside a written
   footer or the details, or on a line of their own below them when there is no room. */
.cm-homesite-footer-social {
    display: flex;
    gap: 0.75rem;
    margin-left: auto;
    align-self: flex-end;
}

.cm-homesite-footer-social svg {
    width: 1.4rem;
    height: 1.4rem;
    fill: currentColor;
}

/* The footer the owner wrote (2026-10-01: "Add a footer editor"): what room the icons leave, in the
   band's own colors unless the writing gives its own. */
.cm-homesite-footer-written {
    flex: 1 1 20rem;
    min-width: 0;
}

.cm-homesite-footer-written > :last-child {
    margin-bottom: 0;
}

@media (max-width: 767.98px) {
    .cm-homesite-columns,
    .cm-homesite-columns.cm-homesite-sidebar-right {
        flex-direction: column;
        align-items: stretch;
    }

    /* Above the page, as tall as its menu. */
    .cm-homesite-sidebar {
        flex: 0 0 auto;
    }

    .cm-homesite-sidebar > nav {
        position: static;
    }

    .cm-homesite-sidebar-left > .cm-homesite-sidebar.cm-homesite-band-light,
    .cm-homesite-sidebar-right > .cm-homesite-sidebar.cm-homesite-band-light {
        border-left: 0;
        border-right: 0;
        border-bottom: 1px solid var(--cm-border, #dee2e6);
    }
}

/* ---- editor panels (.cm-modal) - the Home Page Editor's and the Blog tab's; moved here from
   Shared/HomePageEditor.razor.css on 2026-10-01 so both can use them ------------------------------------------------------------------------- */

.cm-modal {
    position: fixed;
    inset: 0;
    z-index: 1050;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 1.5rem;
}

/* [hidden] has to beat the display:flex above, which is more specific than the browser's own
   rule for the attribute. */
.cm-modal[hidden] {
    display: none;
}

.cm-modal-backdrop {
    position: absolute;
    inset: 0;
    background: rgba(0, 0, 0, 0.5);
}

/* The panel is a column: a head that stays put, a body that scrolls, and whatever the body
   puts at its end. min-height:0 on the body is what actually lets it scroll - without it a
   flex child refuses to shrink below its content and the whole panel grows instead. */
.cm-modal-panel {
    position: relative;
    display: flex;
    flex-direction: column;
    width: min(60rem, 100%);
    max-height: min(85vh, 60rem);
    background: var(--cm-surface, #ffffff);
    color: var(--cm-text, #212529);
    border-radius: 0.5rem;
    box-shadow: 0 1rem 3rem rgba(0, 0, 0, 0.35);
    overflow: hidden;
}

.cm-modal-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    padding: 0.75rem 1rem;
    border-bottom: 1px solid var(--cm-border, rgba(0, 0, 0, 0.175));
}

.cm-modal-title {
    margin: 0;
    font-size: 1.15rem;
}

.cm-modal-x {
    border: 0;
    background: transparent;
    color: inherit;
    font-size: 1.6rem;
    line-height: 1;
    padding: 0 0.4rem;
    cursor: pointer;
    opacity: 0.7;
}

.cm-modal-x:hover,
.cm-modal-x:focus-visible {
    opacity: 1;
}

.cm-modal-body {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    padding: 1rem;
}

.cm-modal-foot {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    margin-top: 1rem;
}

.cm-modal-foot-top {
    margin-top: 0;
    margin-bottom: 1rem;
}

/* The Blog tab's panel (Shared/BlogTab.razor, 2026-10-01) holds a form around its body and its
   foot, so the form is the panel's column: the body scrolls, the Save row stays put. Here rather than
   in the tab's own stylesheet because EditForm draws the form element. */
.cm-modal-panel > .cm-blogtab-form {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
    min-height: 0;
}
