@keyframes fadeIn {
    from {
        opacity: 0;
    }

    to {
        opacity: 1;
    }
}

.fade {
    animation-duration: 0.75s;
    animation-delay: 0.5s;
    animation-name: fadeIn;
    animation-timing-function: cubic-bezier(.26, .53, .74, 1.48);
    animation-fill-mode: backwards;
}

@keyframes fadeOut {
    from {
        opacity: 1;
    }

    to {
        opacity: 0;
    }
}

.fade-out {
    animation-duration: 0.5s;
    animation-name: fadeOut;
    animation-timing-function: cubic-bezier(.26, .53, .74, 1.48);
    animation-fill-mode: backwards;
}

.centered-element {
    display: block;
    margin: 0 auto;
}

.centering-container {
    align-items: center;
    display: flex;
    width: 100%;
    height: 100vh;
}

.centering-container-inapp {
    align-items: center;
    display: flex;
    width: 100%;
    height: calc(100vh - 80px);
}

#blazor-error-ui {
    background: lightyellow;
    bottom: 0;
    box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2);
    display: none;
    left: 0;
    padding: 0.6rem 1.25rem 0.7rem 1.25rem;
    position: fixed;
    width: 100%;
    z-index: 1000;
}

    #blazor-error-ui .dismiss {
        cursor: pointer;
        position: absolute;
        right: 0.75rem;
        top: 0.5rem;
    }

.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."
    }

/* ---------------------------------------------------------------------------
 * Transcript viewer (dialog on the meetings list, not the room)
 *
 * The separator was rgba(0,0,0,0.06) back when dialogs were a light surface.
 * The portal is dark now, where a black hairline is simply invisible — so it
 * matches the card border used everywhere else.
 * ------------------------------------------------------------------------- */

.transcript-view {
    max-height: 60vh;
    overflow-y: auto;
    padding-right: 4px;
}

.transcript-line {
    padding: 6px 0;
    border-bottom: 1px solid var(--card-border);
}

.transcript-line:last-child { border-bottom: none; }

.transcript-speaker {
    font-weight: 700;
    font-size: 0.8rem;
    margin-right: 8px;
}

.transcript-offset {
    font-family: monospace;
    font-size: 0.72rem;
    opacity: 0.6;
}

.transcript-text {
    font-size: 0.92rem;
    white-space: pre-wrap;
    word-break: break-word;
}

/* ---------------------------------------------------------------------------
 * Meeting room (meeting.js owns the tiles inside .meeting-grid)
 * ------------------------------------------------------------------------- */

/* MudMainContent reserves the app-bar height as top padding, so a 100vh page
   inside it overflows the viewport by exactly that much — which pushed the
   control bar (and therefore the Leave button) below the fold. Subtract the
   same variable MudBlazor pads with, so the room always fits and the controls
   are reachable without scrolling. */
.meeting-page {
    display: flex;
    flex-direction: column;
    height: calc(100vh - var(--mud-appbar-height, 64px));
    background-color: #1a1d21;
}

/* Both bars are deliberately tight. Every pixel they take is a pixel off the
   stage, and what is on the stage — a shared screen, or one of our apps being
   demonstrated — is the reason anyone is looking at the room. */
.meeting-header {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 3px 14px;
    background-color: #24272c;
    color: #fff;
    min-height: 0;
}

/* The room's title does not need to be a headline. */
.meeting-header .mud-typography-h6 {
    font-size: 0.95rem;
    line-height: 1.3;
}

.meeting-header .mud-icon-button {
    padding: 5px;
}

.meeting-header .mud-typography { color: #fff; }

/* Header actions sit on #24272c, where MudBlazor's default text colour is very
   nearly the background. Lightened explicitly, with a hover surface so they
   read as controls rather than labels. */
.meeting-header-button {
    color: #dfe3e8 !important;
    transition: background-color 0.15s ease, color 0.15s ease;
}

.meeting-header-button:hover {
    background-color: rgba(255, 255, 255, 0.10) !important;
    color: #fff !important;
}

.meeting-header-button.is-active {
    background-color: rgba(30, 111, 235, 0.22) !important;
    color: #7fb0ff !important;
}

/* The grid is a column of two regions: .meeting-strip (participant cameras)
   above .meeting-stage (shared screens). With nothing shared the stage is
   hidden and the strip expands into the ordinary tile grid, so the normal
   case is unchanged. When someone shares, this flips to the Zoom/Teams shape:
   a short filmstrip of faces on top, the shared screen taking the rest. */
.meeting-grid {
    flex: 1;
    display: flex;
    flex-direction: column;
    min-height: 0;
    gap: 12px;
    padding: 12px;
    overflow: hidden;
}

.meeting-strip {
    flex: 1;
    min-height: 0;
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
    grid-auto-rows: minmax(200px, 1fr);
    gap: 12px;
    overflow-y: auto;
    align-content: center;
}

.meeting-stage { display: none; }

/* --- Presenting --------------------------------------------------------- */

.meeting-grid.is-presenting .meeting-strip {
    /* A band of faces, kept short: the stage is what people are here to see. */
    flex: 0 0 auto;
    height: 15vh;
    min-height: 84px;
    max-height: 148px;
    display: flex;
    gap: 12px;
    overflow-x: auto;
    overflow-y: hidden;
    align-content: stretch;
    /* Centred: a couple of faces belong in the middle of the band, not shoved
       against the left edge with the rest of it empty. */
    justify-content: center;
    position: relative;
}

/* Moving the people lives on the people. Hidden until the strip is hovered, and
   only while something is on the stage — in the ordinary grid view there is no
   filmstrip to move. */
.meeting-strip-move {
    display: none;
    position: absolute;
    top: 4px;
    right: 6px;
    z-index: 5;
    padding: 3px 9px;
    border: 1px solid rgba(255, 255, 255, 0.18);
    border-radius: 999px;
    background-color: rgba(20, 22, 26, 0.82);
    color: #dfe3e8;
    font-family: 'Lato', sans-serif;
    font-size: 0.68rem;
    cursor: pointer;
    opacity: 0;
    transition: opacity 0.15s ease, background-color 0.15s ease;
}

.meeting-grid.is-presenting .meeting-strip-move { display: block; }
.meeting-grid.is-presenting .meeting-strip:hover .meeting-strip-move { opacity: 1; }
.meeting-strip-move:hover { background-color: rgba(40, 44, 52, 0.95); color: #fff; }

/* Faces down the side instead of across the top. A wide stage is usually short
   of height rather than width — a 16:10 app in a 16:9 room letterboxes against
   the height — so moving the filmstrip to a column hands the stage back the
   vertical space it was missing and costs width it had spare. */
.meeting-grid.is-presenting.strip-side {
    flex-direction: row-reverse;
}

.meeting-grid.is-presenting.strip-side .meeting-strip {
    height: auto;
    max-height: none;
    flex: 0 0 clamp(150px, 15vw, 260px);
    flex-direction: column;
    overflow-x: hidden;
    overflow-y: auto;
}

.meeting-grid.is-presenting.strip-side .meeting-strip .meeting-tile {
    width: 100%;
    height: auto;
    flex: 0 0 auto;
}

.meeting-grid.is-presenting .meeting-strip .meeting-tile {
    flex: 0 0 auto;
    height: 100%;
    min-height: 0;
    aspect-ratio: 4 / 3;
}

/* Filmstrip tiles are small: keep the stats readout to a single clipped line
   so it cannot wrap over the participant's name. */
.meeting-grid.is-presenting .meeting-strip .meeting-tile-stats {
    font-size: 0.6rem;
    max-width: calc(100% - 16px);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.meeting-grid.is-presenting .meeting-stage {
    display: flex;
    flex: 1;
    min-height: 0;
    gap: 12px;
}

.meeting-grid.is-presenting .meeting-stage .meeting-tile {
    flex: 1;
    min-height: 0;
}

.meeting-tile {
    position: relative;
    background-color: #000;
    border-radius: 12px;
    overflow: hidden;
    min-height: 200px;
    display: flex;
    align-items: center;
    justify-content: center;
}

.meeting-tile video {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.meeting-tile.tile-screen video {
    object-fit: contain;
    background-color: #000;
}

/* Camera off: hide the (black) video entirely and let the avatar show through,
   so a participant with their camera down still reads as present. */
.meeting-tile.tile-cam-off video { opacity: 0; }

.meeting-tile-avatar {
    position: absolute;
    inset: 0;
    display: none;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 10px;
    background-color: #23272e;
    pointer-events: none;
}

.meeting-tile.tile-cam-off .meeting-tile-avatar { display: flex; }

.meeting-tile-initials {
    width: 84px;
    height: 84px;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    background: linear-gradient(145deg, #3c4250, #2b3038);
    color: #e8ecf1;
    font-family: 'Montserrat', sans-serif;
    font-size: 1.9rem;
    font-weight: 700;
    letter-spacing: 0.04em;
    border: 1px solid #454c57;
}

.meeting-tile-avatar-name {
    color: #c8cdd4;
    font-family: 'Lato', sans-serif;
    font-size: 0.9rem;
}

/* In the presentation filmstrip the tiles are small — shrink the avatar to match. */
.meeting-grid.is-presenting .meeting-strip .meeting-tile-initials {
    width: 46px;
    height: 46px;
    font-size: 1.05rem;
}

.meeting-grid.is-presenting .meeting-strip .meeting-tile-avatar-name { display: none; }

.meeting-tile.tile-disconnected { outline: 2px solid #d32f2f; }

.meeting-tile-label {
    position: absolute;
    left: 8px;
    bottom: 8px;
    padding: 2px 10px;
    border-radius: 10px;
    background-color: rgba(0, 0, 0, 0.6);
    color: #fff;
    font-family: 'Lato', sans-serif;
    font-size: 0.85rem;
}

.meeting-tile-stats {
    position: absolute;
    right: 8px;
    top: 8px;
    padding: 1px 8px;
    border-radius: 8px;
    background-color: rgba(0, 0, 0, 0.6);
    color: #9be27d;
    font-family: monospace;
    font-size: 0.7rem;
}

/* The client's room does not show the read-out. It is an operating instrument —
   ours to watch, and Lens's to assert on — not something a client should have to
   look past to see the person they came to talk to. */
.meeting-grid.no-tile-stats .meeting-tile-stats { display: none; }

/* Staff-only speaker-count picker, sat under the stats readout in the tile's
   top-right. Semi-transparent until hovered so a room full of tiles is not a
   wall of chrome. */
.meeting-tile-speakercount {
    position: absolute;
    right: 8px;
    top: 32px;
    display: flex;
    align-items: center;
    gap: 5px;
    padding: 2px 8px;
    border-radius: 8px;
    background-color: rgba(0, 0, 0, 0.6);
    color: #d7c07a;
    font-family: 'Lato', sans-serif;
    font-size: 0.7rem;
    cursor: pointer;
    opacity: 0.55;
    transition: opacity 120ms ease-in-out;
}

.meeting-tile:hover .meeting-tile-speakercount,
.meeting-tile.tile-shared-mic .meeting-tile-speakercount {
    opacity: 1;
}

.meeting-tile-speakercount select {
    background-color: transparent;
    color: #d7c07a;
    border: 1px solid #6b5c2e;
    border-radius: 3px;
    font-family: 'Lato', sans-serif;
    font-size: 0.7rem;
    padding: 0 2px;
    cursor: pointer;
}

/* The dropdown list itself renders with the OS palette, so the options need a
   readable background of their own rather than inheriting the tile's. */
.meeting-tile-speakercount select option { background-color: #23272e; color: #e6e6e6; }

/* A flagged tile gets a warm border so it is identifiable at a glance, matching
   the "Person N" badge colour in the transcript. */
.meeting-tile.tile-shared-mic { outline: 2px solid #6b5c2e; outline-offset: -2px; }

.meeting-lobby {
    position: fixed;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    background-color: rgba(26, 29, 33, 0.85);
    z-index: 10;
    padding: 16px;
    overflow-y: auto;
}

/* --- Green room (pre-join check) ---------------------------------------- */

.lobby-card {
    min-width: 320px;
    width: 100%;
    max-width: 460px;
}

.lobby-preview {
    position: relative;
    width: 100%;
    aspect-ratio: 16 / 9;
    background-color: #14171a;
    border-radius: 10px;
    overflow: hidden;
}

.lobby-preview video {
    width: 100%;
    height: 100%;
    object-fit: cover;
    /* Mirrored: people expect a mirror when looking at themselves, the same
       way every other meeting tool does it. Only the preview is flipped —
       what participants receive is never mirrored. */
    transform: scaleX(-1);
}

.lobby-preview-overlay {
    position: absolute;
    inset: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    background-color: #14171a;
    color: #c8cdd4;
    text-align: center;
}

.lobby-meter-row {
    display: flex;
    align-items: center;
    gap: 10px;
}

.lobby-meter {
    flex: 1;
    height: 8px;
    border-radius: 4px;
    background-color: rgba(0, 0, 0, 0.12);
    overflow: hidden;
}

/* Width is driven straight from meeting.js's analyser loop — no Blazor
   round-trip, so it tracks the voice smoothly. */
.lobby-meter-fill {
    width: 0%;
    height: 100%;
    border-radius: 4px;
    background: linear-gradient(90deg, #50aa31, #8fd14f);
    transition: width 0.06s linear;
}

.lobby-hint {
    display: block;
    margin-top: 4px;
    opacity: 0.7;
}

.lobby-toggles {
    display: flex;
    gap: 10px;
    justify-content: center;
    flex-wrap: wrap;
}

/* Media server state. Switched by hand; the chip reports it and the meetings
   page carries the switch. */
.media-server-indicator {
    display: inline-flex;
    align-items: center;
    gap: 2px;
}

.lobby-media-server {
    display: flex;
    justify-content: center;
}

.lobby-backgrounds {
    text-align: center;
}

.lobby-bg-options {
    display: flex;
    gap: 8px;
    justify-content: center;
    flex-wrap: wrap;
    margin-top: 4px;
}

.meeting-controls {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 3px 10px;
    background-color: #24272c;
    border-top: 1px solid #33373d;
    transition: max-height 0.18s ease, padding 0.18s ease, opacity 0.15s ease;
    max-height: 70px;
    overflow: hidden;
}

/* Three zones. The centre is what you are doing to the room and stays centred in
   the window regardless of how wide the side zones grow, which is why the sides
   are equal-basis flex rather than auto. */
.meeting-controls-left,
.meeting-controls-right {
    flex: 1 1 0;
    display: flex;
    align-items: center;
    gap: 10px;
}

.meeting-controls-right { justify-content: flex-end; }

.meeting-controls-center {
    flex: 0 1 auto;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 10px;
}

/* Collapsed by the person sharing, who needs the room's height more than they
   need a row of buttons they are not currently pressing. Height rather than
   display:none so it slides, and so the handle that brings it back never moves. */
.meeting-controls.is-collapsed {
    max-height: 0;
    padding-top: 0;
    padding-bottom: 0;
    opacity: 0;
    border-top-color: transparent;
}

/* The sliver that puts the bar back. Always present while sharing, so there is
   never a moment where the controls are gone and nothing says how to return. */
.meeting-controls-handle {
    display: flex;
    justify-content: center;
    align-items: center;
    gap: 6px;
    padding: 1px 0 2px 0;
    background-color: #24272c;
    border-top: 1px solid #33373d;
    color: #aeb6c0;
    font-family: 'Lato', sans-serif;
    font-size: 0.66rem;
    letter-spacing: 0.03em;
    cursor: pointer;
    user-select: none;
}

.meeting-controls-handle:hover { color: #fff; background-color: #2b2f35; }

/* State lives on .is-off / .is-active rather than MudBlazor Color values. The
   previous blanket `.meeting-controls .mud-icon-button { color: #fff }` won
   against MudBlazor's own colour classes, which silently flattened the red
   hang-up button and the muted-mic state into the same white as everything
   else — the whole bar read as one row of identical grey glyphs. */
.meeting-control {
    background-color: #343941 !important;
    color: #f2f4f7 !important;
    width: 31px;
    height: 31px;
    padding: 5px;
    border: none;
    cursor: pointer;
    transition: background-color 0.15s ease, color 0.15s ease, transform 0.15s ease;
}

/* Size.Large asks MudBlazor for a large glyph; the button itself is deliberately
   small, so the icon is brought back in proportion rather than overflowing it. */
.meeting-control .mud-icon-root {
    font-size: 1.15rem;
}

/* The bar's own controls, as opposed to the icon-only ones on the annotation
   toolbar. The caption used to be a sibling of the button, which meant the
   target was 31px while the words underneath it — the part people actually read
   to find the control — were not pressable at all, and the bar still paid the
   height for them. Folding the label inside buys a 46px target in a bar that is
   shorter than it was. Native <button> rather than MudIconButton because
   MudIconButton has no slot for anything but the glyph. */
.meeting-control.is-labelled {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 1px;
    position: relative;
    width: auto;
    min-width: 56px;
    height: 46px;
    padding: 4px 10px;
    border-radius: 12px;
    font-family: 'Lato', sans-serif;
}

.meeting-control.is-labelled .mud-icon-root {
    font-size: 1.3rem;
}

.meeting-control:hover {
    background-color: #454c57 !important;
    transform: translateY(-1px);
}

/* Muted mic / camera off — the states you must be able to spot instantly. */
.meeting-control.is-off {
    background-color: #b3261e !important;
    color: #fff !important;
}

.meeting-control.is-off:hover { background-color: #c9392f !important; }

/* Screen share currently active. */
.meeting-control.is-active {
    background-color: #1e6feb !important;
    color: #fff !important;
}

.meeting-control.is-active:hover { background-color: #3785f5 !important; }

/* Labels make the bar readable at a glance instead of asking people to decode
   icons — the same reason Zoom and Teams caption theirs. The colour is inherited
   so a muted or active button carries its caption with it rather than leaving a
   grey word sitting on a red background. */
.meeting-control-label {
    font-size: 0.6rem;
    line-height: 1;
    color: inherit;
    opacity: 0.8;
    letter-spacing: 0.02em;
    user-select: none;
    white-space: nowrap;
}

.meeting-control:hover .meeting-control-label { opacity: 1; }

/* Unread chat, on the button rather than beside it — a badge outside the button
   would put the count back in the dead space the label just vacated. */
.meeting-control-badge {
    position: absolute;
    top: 3px;
    right: 5px;
    min-width: 15px;
    height: 15px;
    padding: 0 4px;
    border-radius: 8px;
    background-color: #b3261e;
    color: #fff;
    font-size: 0.55rem;
    font-weight: 700;
    line-height: 15px;
    text-align: center;
}

/* Split control: the button toggles the device, the caret beside it opens
   that device's menu — the shape Zoom and Teams both use. */
.meeting-control-split {
    display: flex;
    align-items: center;
    gap: 2px;
}

.meeting-caret {
    width: 22px !important;
    height: 46px !important;
    min-width: 22px !important;
    padding: 0 !important;
    border-radius: 0 12px 12px 0 !important;
    background-color: #343941 !important;
    color: #c8cdd4 !important;
    transition: background-color 0.15s ease, color 0.15s ease;
}

.meeting-caret:hover {
    background-color: #454c57 !important;
    color: #fff !important;
}

/* Round the toggle's right edge off so the pair reads as one control. */
.meeting-control-split .meeting-control {
    border-radius: 12px 0 0 12px !important;
}

.meeting-device-menu {
    min-width: 260px;
    max-width: 340px;
}

.meeting-menu-heading {
    display: block;
    padding: 8px 16px 2px;
    opacity: 0.6;
    text-transform: uppercase;
    letter-spacing: 0.06em;
}

.meeting-controls-divider {
    width: 1px;
    height: 30px;
    margin: 0 6px;
    background-color: #3d434c;
}

/* Deliberately not shaped like the toggles beside it — a pill, not a rounded
   square — so the one button that ends your presence in the room is never
   mistaken for one that flips a setting. Same height so the row still reads as
   a row. */
.meeting-leave {
    background-color: #b3261e !important;
    color: #fff !important;
    height: 46px;
    min-width: 0 !important;
    padding: 0 22px !important;
    border-radius: 23px !important;
    font-size: 0.8rem !important;
    font-weight: 700;
    letter-spacing: 0.02em;
    transition: background-color 0.15s ease, transform 0.15s ease;
}

.meeting-leave:hover {
    background-color: #c9392f !important;
    transform: translateY(-1px);
}

/* End meeting — staff only. Outlined red beside the filled-red Leave: related
   to leaving, clearly not the same thing. */
.meeting-end {
    color: #ff8a80 !important;
    border: 1.5px solid rgba(255, 138, 128, 0.55) !important;
    height: 52px;
    padding: 0 20px !important;
    border-radius: 26px !important;
    font-weight: 700;
    letter-spacing: 0.02em;
    transition: background-color 0.15s ease;
}

.meeting-end:hover {
    background-color: rgba(179, 38, 30, 0.28) !important;
}

/* Meeting side panel (chat + transcript) */

.meeting-main {
    flex: 1;
    display: flex;
    min-height: 0;
    position: relative;   /* anchors the captions overlay over the video area */
}

.meeting-main .meeting-grid { flex: 1; }

/* The panel must never grow the page. A flex item defaults to
   min-height: auto, which means it expands to fit its content — that is what
   let a long transcript push the panel off the bottom of the viewport and
   behind the control bar. Every wrapper between the panel and the scrolling
   list needs min-height: 0 for the height limit to actually reach the list. */
.meeting-panel {
    width: 360px;
    min-width: 300px;
    display: flex;
    flex-direction: column;
    min-height: 0;
    overflow: hidden;
    background-color: #24272c;
    border-left: 1px solid #33373d;
}

.meeting-panel-body {
    display: flex;
    flex-direction: column;
    flex: 1;
    min-height: 0;
    overflow: hidden;
}

/* The panel's tab strip. This was MudTabs, and replacing it with markup fixed
   three things at once. MudTabs sets an unqualified `transition: .3s` on its
   panel container and its tab-bar wrapper, so every property animated — opening
   the panel spent a third of a second going from nothing to readable. It laid
   the strip out as a `width: max-content` wrapper, so tabs took their natural
   width and bunched at the left with dead space beside them, or overflowed into
   scroll arrows when there were four. And it positioned its active-tab underline
   from a JS measurement, which pointed at the wrong tab as soon as the widths
   were overridden.

   Every one of those was something being fought rather than used. The state is a
   single int this page already owns, so the tabs are buttons and the underline is
   a border on whichever one is active. Even shares of the strip, no animation,
   no measuring. */
.meeting-panel-tabs {
    display: flex;
    flex: 0 0 auto;
    border-bottom: 1px solid #33373d;
}

.meeting-panel-tab {
    flex: 1 1 0;
    min-width: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 3px;
    padding: 7px 4px;
    background: none;
    border: none;
    border-bottom: 2px solid transparent;
    color: #aeb6c0;
    font-family: 'Lato', sans-serif;
    font-size: 0.6rem;
    line-height: 1;
    letter-spacing: 0.05em;
    text-transform: uppercase;
    white-space: nowrap;
    cursor: pointer;
    transition: color 0.12s ease, background-color 0.12s ease;
}

.meeting-panel-tab .mud-icon-root { font-size: 1.15rem; }

.meeting-panel-tab:hover {
    color: #e8ecf1;
    background-color: rgba(255, 255, 255, 0.05);
}

.meeting-panel-tab.is-active {
    color: var(--mud-palette-primary);
    border-bottom-color: var(--mud-palette-primary);
}


.meeting-messages {
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    display: flex;
    flex-direction: column-reverse; /* newest pinned at the bottom, no scroll JS */
    padding: 8px 12px;
    gap: 8px;
}

.meeting-chat-line, .meeting-transcript-line { color: #e6e6e6; }

.meeting-chat-name {
    font-weight: 700;
    font-size: 0.8rem;
    color: #9be27d;
    margin-right: 8px;
}

.meeting-chat-time { font-size: 0.7rem; color: #9a9a9a; }

/* "Person 1" / "Person 2" within a shared microphone. Deliberately quieter
   than the account name it sits beside: the account is who we know, the person
   number is only who we can tell apart. */
.meeting-subspeaker {
    font-size: 0.7rem;
    font-weight: 600;
    color: #d7c07a;
    border: 1px solid #6b5c2e;
    border-radius: 3px;
    padding: 0 4px;
    margin-right: 8px;
    white-space: nowrap;
}

.meeting-chat-text { font-size: 0.9rem; white-space: pre-wrap; word-break: break-word; }

.meeting-transcript-partial .meeting-chat-text { font-style: italic; color: #b9b9b9; }

.meeting-chat-input {
    display: flex;
    align-items: center;
    gap: 4px;
    padding: 8px;
    border-top: 1px solid #33373d;
}

.meeting-chat-input .mud-input-control { flex: 1; }

.meeting-panel .mud-input-slot, .meeting-panel .mud-input { color: #e6e6e6 !important; }

@media (max-width: 800px) {
    .meeting-panel { position: absolute; right: 0; top: 48px; bottom: 56px; z-index: 5; }
}

/* ---------------------------------------------------------------------------
 * In-meeting parity: active speaker, hand, reactions, pin, tile actions
 * ------------------------------------------------------------------------- */

/* Active speaker — a green ring on whoever is talking. box-shadow (inset) rather
   than outline so it never fights the outline-based disconnected/shared-mic
   states, and reads through the tile's rounded corners. */
.meeting-tile.is-speaking {
    box-shadow: inset 0 0 0 3px #57c98a;
}

/* Pinned tile (on the stage) gets a quiet blue ring to say "this is here on
   purpose", distinct from the green speaking ring. */
.meeting-tile.tile-pinned {
    box-shadow: inset 0 0 0 2px #1e6feb;
}

/* Hover actions cluster (fullscreen, pin), top-left so it clears the stats and
   speaker-count chrome on the right. Faint until the tile is hovered. */
.meeting-tile-actions {
    position: absolute;
    left: 8px;
    top: 8px;
    display: flex;
    gap: 4px;
    opacity: 0;
    transition: opacity 120ms ease-in-out;
    z-index: 2;
}

.meeting-tile:hover .meeting-tile-actions { opacity: 1; }

.meeting-tile-action {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 26px;
    height: 26px;
    border: none;
    border-radius: 7px;
    background-color: rgba(0, 0, 0, 0.6);
    color: #fff;
    font-size: 0.85rem;
    line-height: 1;
    cursor: pointer;
    transition: background-color 0.12s ease;
}

.meeting-tile-action:hover { background-color: rgba(30, 111, 235, 0.85); }
.meeting-tile-action.is-on { background-color: #1e6feb; }

/* Floating emoji reaction — rises and fades over the sender's tile. */
.meeting-reaction-float {
    position: absolute;
    left: 50%;
    bottom: 16px;
    transform: translateX(-50%);
    font-size: 2.4rem;
    pointer-events: none;
    animation: reaction-rise 2.4s ease-out forwards;
    z-index: 3;
}

@keyframes reaction-rise {
    0%   { opacity: 0; transform: translate(-50%, 10px) scale(0.6); }
    15%  { opacity: 1; transform: translate(-50%, 0) scale(1.1); }
    30%  { transform: translate(-50%, -6px) scale(1); }
    100% { opacity: 0; transform: translate(-50%, -90px) scale(1); }
}

/* Live-captions overlay — one band across the bottom of the video area, the way
   Zoom/Teams render CC. Sits above the grid, below the control bar. */
.meeting-captions {
    position: absolute;
    left: 50%;
    bottom: 16px;
    transform: translateX(-50%);
    max-width: min(900px, 80%);
    display: flex;
    flex-direction: column;
    gap: 4px;
    padding: 10px 16px;
    border-radius: 10px;
    background-color: rgba(0, 0, 0, 0.72);
    color: #fff;
    pointer-events: none;
    z-index: 4;
}

.meeting-caption-line { font-size: 1.05rem; line-height: 1.35; }
.meeting-caption-line .meeting-caption-who { font-weight: 700; color: #9be27d; margin-right: 8px; }
.meeting-caption-partial { opacity: 0.75; font-style: italic; }

/* People / roster tab */
.meeting-roster { display: flex; flex-direction: column; padding: 6px 0; overflow-y: auto; }

.meeting-roster-row {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 8px 12px;
    border-bottom: 1px solid #2c3037;
}

.meeting-roster-name { flex: 1; color: #e6e6e6; font-size: 0.9rem; }
.meeting-roster-name .meeting-roster-you { color: #9a9a9a; font-size: 0.78rem; margin-left: 4px; }

/* Mic/cam/hand state icons on a roster row. Muted-red when off. */
.meeting-roster-state { display: flex; align-items: center; gap: 6px; color: #aeb6c0; }
.meeting-roster-state .is-off { color: #e57373; }

/* Host controls on a roster row — quiet until the row is hovered. */
.meeting-roster-actions { display: flex; align-items: center; gap: 2px; opacity: 0.5; transition: opacity 120ms ease; }
.meeting-roster-row:hover .meeting-roster-actions { opacity: 1; }

/* "Mute all" header action above the roster. */
.meeting-roster-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 8px 12px;
    border-bottom: 1px solid #33373d;
}

/* Reaction picker — a compact row of emoji in the control bar's menu. */
.meeting-reaction-picker { display: flex; gap: 4px; padding: 6px 8px; }

.meeting-reaction-picker button {
    border: none;
    background: transparent;
    font-size: 1.4rem;
    line-height: 1;
    padding: 4px;
    border-radius: 8px;
    cursor: pointer;
    transition: background-color 0.12s ease, transform 0.12s ease;
}

.meeting-reaction-picker button:hover { background-color: rgba(255, 255, 255, 0.12); transform: scale(1.15); }

/* In-meeting assistant (staff-only tab) */
.meeting-assistant { display: flex; flex-direction: column; flex: 1; min-height: 0; overflow: hidden; }

.meeting-assistant-controls {
    padding: 10px 12px;
    border-bottom: 1px solid #33373d;
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.meeting-assistant-modes { display: flex; gap: 8px; }
.meeting-assistant-hint { color: #9aa0a8; }

.meeting-assistant-input { display: flex; align-items: center; gap: 4px; }
.meeting-assistant-input .mud-input-control { flex: 1; }

.meeting-assistant-list {
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    padding: 10px 12px;
    display: flex;
    flex-direction: column;
    gap: 12px;
}

.meeting-assistant-item { background-color: #2b2f36; border-radius: 10px; padding: 8px 10px; }

.meeting-assistant-q {
    font-weight: 700;
    color: #e6e6e6;
    font-size: 0.88rem;
    margin-bottom: 6px;
    display: flex;
    align-items: center;
    gap: 6px;
}

.meeting-assistant-badge {
    font-size: 0.65rem;
    font-weight: 700;
    color: #c9a0ff;
    border: 1px solid #6b4fa0;
    border-radius: 4px;
    padding: 0 5px;
    text-transform: uppercase;
    letter-spacing: 0.05em;
}

.meeting-assistant-a { color: #cfd4da; font-size: 0.9rem; white-space: pre-wrap; word-break: break-word; }
.meeting-assistant-thinking { display: flex; align-items: center; gap: 8px; color: #9aa0a8; }

/* Meeting paused because the media server went away. Sits over the video area,
   deliberately hard to miss: while this is up nothing is being carried or
   recorded, and the room must not look healthy. */
.meeting-media-paused {
    position: absolute;
    top: 16px;
    left: 50%;
    transform: translateX(-50%);
    z-index: 20;
    display: flex;
    align-items: center;
    gap: 10px;
    max-width: min(720px, calc(100% - 32px));
    padding: 10px 16px;
    border-radius: 10px;
    background-color: rgba(120, 40, 40, 0.94);
    color: #fff;
    font-size: 0.85rem;
    line-height: 1.35;
    box-shadow: 0 6px 20px rgba(0, 0, 0, 0.45);
}

/* ===========================================================================
 * Delve Group brand
 *
 * The palette lives in DelveTheme.cs (MudBlazor consumes it there); these are
 * the same values as CSS variables for the handful of places raw CSS is the
 * right tool, plus the chrome and page furniture that MudBlazor has no opinion
 * about. Values trace to delve-website/BRAND_GUIDE.md — keep them in step.
 * ========================================================================= */

:root {
    --primary-color: #0a0f14;
    --secondary-color: #151d26;
    --tertiary-color: #1a242f;
    --background-dark: #0d1318;

    --accent-color: #d4af7d;
    --accent-color-dark: #c49a6c;
    --accent-color-light: #e8c99b;

    --white: #f5f5f5;
    --text-light: rgba(245, 245, 245, 0.75);
    --text-muted: rgba(245, 245, 245, 0.55);

    --card-bg: rgba(245, 245, 245, 0.05);
    --card-border: rgba(245, 245, 245, 0.12);

    --gradient-accent: linear-gradient(135deg, #d4af7d 0%, #c49a6c 100%);
    --gradient-primary: linear-gradient(165deg, #0a0f14 0%, #151d26 50%, #1a242f 100%);
}

/* The app shell sits on the brand gradient rather than a flat fill. Fixed
   attachment so scrolling a long list does not drag the gradient with it. */
body {
    background: var(--primary-color);
    background-image: var(--gradient-primary);
    background-attachment: fixed;
}

/* The error strip was `lightyellow`, which on a dark portal reads as a rendering
   fault rather than an error. */
#blazor-error-ui {
    background: #3a2a1a;
    color: var(--white);
    border-top: 1px solid var(--accent-color);
}

/* --- App bar ------------------------------------------------------------- */

.portal-appbar {
    background-color: rgba(13, 19, 24, 0.92) !important;
    backdrop-filter: blur(8px);
    border-bottom: 1px solid var(--card-border);
}

.portal-wordmark {
    font-family: Montserrat, system-ui, sans-serif;
    font-size: 1.15rem;
    font-weight: 700;
    letter-spacing: -0.02em;
    color: var(--white);
}

/* The dot is the one piece of gold in the chrome — enough to brand the bar
   without the guide's "overuse the gold accent" failure mode. */
.portal-wordmark::after {
    content: "";
    display: inline-block;
    width: 5px;
    height: 5px;
    margin-left: 4px;
    vertical-align: 2px;
    border-radius: 50%;
    background: var(--gradient-accent);
}

.portal-topnav-link {
    color: var(--text-light) !important;
    font-weight: 600;
    padding: 6px 14px;
    border-radius: 8px;
    transition: color 0.2s ease, background-color 0.2s ease;
}

.portal-topnav-link:hover {
    color: var(--white) !important;
    background-color: rgba(245, 245, 245, 0.06);
}

.portal-topnav-link-active {
    color: var(--accent-color) !important;
    background-color: rgba(212, 175, 125, 0.12);
}

.portal-appbar-user {
    color: var(--text-muted);
}

/* --- Manage rail --------------------------------------------------------- */

.manage-drawer {
    background-color: var(--background-dark) !important;
    border-right: 1px solid var(--card-border);
}

.manage-drawer-eyebrow {
    display: block;
    color: var(--accent-color);
    text-transform: uppercase;
    line-height: 1.2;
}

.manage-drawer .mud-nav-link.active {
    color: var(--accent-color) !important;
    background-color: rgba(212, 175, 125, 0.1);
    border-right: 2px solid var(--accent-color);
}

/* --- Page furniture ------------------------------------------------------ */

/* Every page opens the same way: a small gold eyebrow, a title, and one line
   saying what the page is for. Consistency here is most of what separates a
   product from a set of screens. */
.page-shell {
    padding: 32px 32px 64px 32px;
    max-width: 1360px;
}

.page-eyebrow {
    display: block;
    color: var(--accent-color);
    text-transform: uppercase;
    margin-bottom: 4px;
}

.page-title {
    margin-bottom: 6px;
}

.page-subtitle {
    color: var(--text-muted);
    max-width: 780px;
    margin-bottom: 28px;
}

.section-label {
    display: block;
    color: var(--text-muted);
    text-transform: uppercase;
    margin-bottom: 12px;
}

/* --- Cards --------------------------------------------------------------- */

.delve-card {
    background-color: var(--card-bg) !important;
    border: 1px solid var(--card-border);
    border-radius: 16px;
    background-image: none;
    transition: transform 0.25s ease, border-color 0.25s ease, box-shadow 0.25s ease;
}

/* Lift only where the whole card is a link — a hover animation on something
   that cannot be clicked reads as a bug. */
.delve-card-interactive {
    cursor: pointer;
}

.delve-card-interactive:hover {
    transform: translateY(-4px);
    border-color: rgba(212, 175, 125, 0.3);
    box-shadow: 0 15px 40px rgba(0, 0, 0, 0.3);
}

.delve-card-accent {
    border-color: rgba(212, 175, 125, 0.28);
}

/* --- Stat tiles ---------------------------------------------------------- */

.stat-tile {
    display: flex;
    flex-direction: column;
    gap: 2px;
    padding: 18px 20px;
    background-color: var(--card-bg);
    border: 1px solid var(--card-border);
    border-radius: 14px;
    min-width: 150px;
}

.stat-value {
    font-family: Montserrat, system-ui, sans-serif;
    font-size: 1.9rem;
    font-weight: 700;
    line-height: 1.1;
    letter-spacing: -0.02em;
    color: var(--white);
}

.stat-label {
    font-size: 0.75rem;
    font-weight: 600;
    letter-spacing: 0.05em;
    text-transform: uppercase;
    color: var(--text-muted);
}

.stat-hint {
    font-size: 0.8rem;
    color: var(--text-muted);
    margin-top: 2px;
}

/* --- Status dots --------------------------------------------------------- */

/* A coloured dot plus a word. The dot alone would be the only carrier of
   meaning, which fails for anyone who cannot separate the hues. */
.status-dot {
    display: inline-block;
    width: 9px;
    height: 9px;
    border-radius: 50%;
    margin-right: 8px;
    flex: 0 0 auto;
}

.status-dot-ok { background-color: #6fbf73; }
.status-dot-warn { background-color: #e0b050; }
.status-dot-bad { background-color: #e5736b; }
.status-dot-idle { background-color: rgba(245, 245, 245, 0.3); }

/* Reserved for genuinely live state (the media server starting). Anything that
   pulses permanently just becomes noise. */
.status-dot-live {
    background-color: #6fbf73;
    animation: statusPulse 2s ease-in-out infinite;
}

@keyframes statusPulse {
    0%, 100% { opacity: 1; transform: scale(1); }
    50% { opacity: 0.5; transform: scale(1.25); }
}

/* --- Tags ---------------------------------------------------------------- */

.delve-tag {
    display: inline-block;
    background: rgba(212, 175, 125, 0.15);
    color: var(--accent-color);
    font-size: 12px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    padding: 4px 12px;
    border-radius: 100px;
}

.delve-tag-quiet {
    background: rgba(245, 245, 245, 0.08);
    color: var(--text-muted);
}

/* --- Tables -------------------------------------------------------------- */

/* MudBlazor's dark table is nearly borderless, which makes a dense list hard to
   scan. A hairline per row and a legible header is the whole fix. */
.delve-table {
    background-color: transparent !important;
}

.delve-table th {
    font-family: Montserrat, system-ui, sans-serif;
    font-size: 0.72rem !important;
    font-weight: 600 !important;
    letter-spacing: 0.05em;
    text-transform: uppercase;
    color: var(--text-muted) !important;
    border-bottom: 1px solid var(--card-border) !important;
}

.delve-table td {
    border-bottom: 1px solid rgba(245, 245, 245, 0.06) !important;
}

.delve-table tbody tr:hover {
    background-color: rgba(245, 245, 245, 0.04);
}

/* --- Login --------------------------------------------------------------- */

.login-card {
    width: 460px;
    max-width: calc(100vw - 32px);
    background-color: rgba(21, 29, 38, 0.92) !important;
    border: 1px solid var(--card-border);
    border-radius: 16px;
    box-shadow: 0 24px 60px rgba(0, 0, 0, 0.45);
    background-image: none;
}

.login-brand {
    font-family: Montserrat, system-ui, sans-serif;
    font-size: 1.6rem;
    font-weight: 700;
    letter-spacing: -0.02em;
    color: var(--white);
}

.login-rule {
    width: 44px;
    height: 3px;
    border-radius: 2px;
    background: var(--gradient-accent);
    margin: 14px auto 18px auto;
}

.login-hint {
    color: var(--text-muted);
    font-size: 0.85rem;
}

.login-error { color: #e5736b; font-size: 0.85rem; }
.login-success { color: #6fbf73; font-size: 0.85rem; }

/* --- Chat ---------------------------------------------------------------- */

/* Two columns filling the viewport under the app bar. The message list is the
   only thing that scrolls — a chat page where the whole document scrolls loses
   the composer exactly when you want it. */
.chat-shell {
    display: flex;
    height: calc(100vh - 48px);
    overflow: hidden;
}

.chat-sidebar {
    flex: 0 0 268px;
    background-color: var(--background-dark);
    border-right: 1px solid var(--card-border);
    overflow-y: auto;
    padding-bottom: 24px;
}

.chat-sidebar-head {
    padding: 16px 16px 8px 16px;
}

.chat-section-label {
    padding: 18px 16px 6px 16px;
    font-family: Montserrat, system-ui, sans-serif;
    font-size: 0.7rem;
    font-weight: 600;
    letter-spacing: 0.05em;
    text-transform: uppercase;
    color: var(--text-muted);
}

.chat-channel {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 6px 16px;
    cursor: pointer;
    color: var(--text-light);
    font-size: 0.9rem;
    transition: background-color 0.15s ease, color 0.15s ease;
}

.chat-channel:hover {
    background-color: rgba(245, 245, 245, 0.05);
    color: var(--white);
}

.chat-channel.is-current {
    background-color: rgba(212, 175, 125, 0.12);
    color: var(--accent-color);
    box-shadow: inset 2px 0 0 var(--accent-color);
}

/* People you have not messaged yet sit quietly below the real conversations. */
.chat-channel-muted { color: var(--text-muted); }

.chat-channel-hash {
    color: var(--text-muted);
    font-weight: 600;
}

.chat-channel-name {
    flex: 1 1 auto;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.chat-unread-dot {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--gradient-accent);
    flex: 0 0 auto;
}

.chat-main {
    flex: 1 1 auto;
    display: flex;
    flex-direction: column;
    min-width: 0;
}

.chat-head {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 12px 20px;
    border-bottom: 1px solid var(--card-border);
    flex: 0 0 auto;
}

.chat-messages {
    flex: 1 1 auto;
    overflow-y: auto;
    padding: 16px 20px;
}

.chat-more { text-align: center; margin-bottom: 8px; }

.chat-message { margin-bottom: 14px; }

.chat-message-head {
    display: flex;
    align-items: baseline;
    gap: 8px;
}

.chat-author {
    font-family: Montserrat, system-ui, sans-serif;
    font-weight: 600;
    font-size: 0.85rem;
    color: var(--white);
}

.chat-time {
    font-size: 0.7rem;
    color: var(--text-muted);
}

/* Messages keep their line breaks and wrap long tokens, so a pasted URL does
   not push the whole column sideways. */
.chat-body {
    font-size: 0.92rem;
    color: var(--text-light);
    white-space: pre-wrap;
    overflow-wrap: anywhere;
}

.chat-system {
    font-size: 0.8rem;
    color: var(--text-muted);
    font-style: italic;
    margin-bottom: 10px;
}

.chat-composer {
    display: flex;
    flex-direction: column;
    gap: 8px;
    padding: 12px 20px 16px 20px;
    border-top: 1px solid var(--card-border);
    flex: 0 0 auto;
}

.chat-composer-row {
    display: flex;
    align-items: flex-end;
    gap: 10px;
}

.chat-input {
    flex: 1 1 auto;
    resize: none;
    padding: 10px 14px;
    border-radius: 10px;
    border: 1px solid var(--card-border);
    background-color: rgba(245, 245, 245, 0.05);
    color: var(--white);
    font-family: Lato, system-ui, sans-serif;
    font-size: 0.92rem;
    line-height: 1.5;
    outline: none;
}

.chat-input:focus { border-color: rgba(212, 175, 125, 0.5); }

/* Attachments on a message: images and video render inline, other files show as
   a download chip. Capped so a big image does not take over the scroll. */
.chat-attachments {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin-top: 6px;
}

.chat-attach-image img,
.chat-attach-video {
    max-width: min(420px, 100%);
    max-height: 320px;
    border-radius: 10px;
    border: 1px solid var(--card-border);
    display: block;
}

.chat-attach-image { display: inline-block; line-height: 0; }

.chat-attach-file {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 8px 12px;
    border-radius: 10px;
    border: 1px solid var(--card-border);
    background-color: rgba(245, 245, 245, 0.05);
    color: var(--white);
    text-decoration: none;
    max-width: 320px;
}

.chat-attach-file:hover { background-color: rgba(245, 245, 245, 0.09); }
.chat-attach-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.chat-attach-size { color: var(--text-muted); font-size: 0.8rem; flex: 0 0 auto; }

/* Files staged in the composer, before the message is sent. */
.chat-pending {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}

.chat-pending-item {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 4px 6px 4px 10px;
    border-radius: 8px;
    border: 1px solid var(--card-border);
    background-color: rgba(245, 245, 245, 0.05);
    font-size: 0.85rem;
    max-width: 260px;
}

.chat-pending-busy { color: var(--text-muted); padding-right: 12px; }

/* A file being dragged over the message pane. */
.chat-main.is-dropping {
    outline: 2px dashed rgba(212, 175, 125, 0.6);
    outline-offset: -8px;
    background-color: rgba(212, 175, 125, 0.04);
}

.chat-empty {
    flex: 1 1 auto;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    color: var(--text-muted);
}

/* --- Wrapped browser ----------------------------------------------------- */

/* The whole viewport below the app bar. MudMainContent already reserves the
   app-bar height, so 100% here is the space that is actually left. */
.wrap-page {
    display: flex;
    flex-direction: column;
    height: calc(100vh - 48px);
    background-color: var(--primary-color);
}

.wrap-bar {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 8px 12px;
    background-color: var(--background-dark);
    border-bottom: 1px solid var(--card-border);
    flex: 0 0 auto;
}

/* A plain input rather than a MudTextField: this is browser chrome, and it
   should read as an address bar, not as a form field on a page. */
.wrap-url {
    flex: 1 1 auto;
    min-width: 200px;
    padding: 7px 12px;
    border-radius: 8px;
    border: 1px solid var(--card-border);
    background-color: rgba(245, 245, 245, 0.05);
    color: var(--white);
    font-family: Lato, system-ui, sans-serif;
    font-size: 0.85rem;
    outline: none;
}

.wrap-url:focus {
    border-color: rgba(212, 175, 125, 0.5);
}

.wrap-status {
    display: flex;
    align-items: center;
    font-size: 0.75rem;
    color: var(--text-muted);
    white-space: nowrap;
    margin-left: 4px;
}

.wrap-surface {
    position: relative;
    flex: 1 1 auto;
    display: flex;
    align-items: flex-start;
    justify-content: center;
    overflow: auto;
    padding: 12px;
    outline: none;
}

/* The remote viewport is a fixed size; this scales it to fit while keeping its
   aspect ratio, which is what makes normalized input coordinates correct. */
.wrap-frame {
    max-width: 100%;
    max-height: 100%;
    border-radius: 10px;
    border: 1px solid var(--card-border);
    box-shadow: 0 18px 50px rgba(0, 0, 0, 0.45);
    background-color: #fff;
}

/* The shared-app tile while you are the one driving it: a cursor that says the
   picture is clickable, and a rim so it is obvious which stage item takes your
   input. Everyone else sees an ordinary screen-share tile. */
.meeting-tile.is-driving {
    outline: 2px solid rgba(212, 175, 125, 0.75);
    outline-offset: -2px;
}

.meeting-tile.is-driving video {
    cursor: default;
}

/* The <video> shares the frame's sizing but starts hidden; testbench.js reveals
   it and hides the <img> once the media track attaches. */
.wrap-video {
    display: none;
}

/* Two cursors in video mode, on purpose.
   The remote browser draws a cursor into the picture so that anyone watching the
   stream — a client in a demo — can see where the pointer is and what was
   clicked. But that one is a round trip behind the operator's hand, which feels
   like lag to the person actually driving. So the local pointer stays visible on
   top: the operator gets native, instant feedback, and the drawn one carries the
   same movement to everyone else. Hiding the local cursor was the earlier
   behaviour and it made driving the browser feel sluggish. */
.wrap-surface.is-video {
    cursor: default;
}

.wrap-placeholder {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    text-align: center;
    color: var(--text-muted);
}

/* --- Coach: the trail rail and the marker -------------------------------- */

/* The surface and the rail sit side by side, and the surface keeps its own
   sizing rules — the rail takes width from it rather than overlaying it, so the
   picture is never partly hidden behind the thing explaining it. */
.wrap-body {
    display: flex;
    flex: 1 1 auto;
    min-height: 0;
}

.coach-rail {
    flex: 0 0 320px;
    display: flex;
    flex-direction: column;
    background-color: var(--background-dark);
    border-left: 1px solid var(--card-border);
    overflow: hidden;
}

.coach-rail-head {
    padding: 10px 12px;
    border-bottom: 1px solid var(--card-border);
    flex: 0 0 auto;
}

.coach-rail-body {
    overflow-y: auto;
    padding: 6px 0;
    flex: 1 1 auto;
}

.coach-trail {
    padding: 8px 12px;
    border-bottom: 1px solid rgba(245, 245, 245, 0.06);
    cursor: pointer;
}

.coach-trail:hover {
    background-color: rgba(212, 175, 125, 0.08);
}

.coach-step {
    display: flex;
    gap: 8px;
    padding: 8px 12px;
    border-left: 3px solid transparent;
    cursor: pointer;
    font-size: 0.8rem;
    line-height: 1.35;
    color: var(--text-muted);
}

.coach-step:hover {
    background-color: rgba(245, 245, 245, 0.04);
}

/* The current step is the only one that gets the accent. Everything else stays
   quiet, because a list where every row shouts is a list nobody reads mid-demo. */
.coach-step.is-current {
    border-left-color: rgba(212, 175, 125, 0.9);
    background-color: rgba(212, 175, 125, 0.10);
    color: var(--white);
}

.coach-step.is-done {
    opacity: 0.5;
}

.coach-step-n {
    flex: 0 0 22px;
    font-variant-numeric: tabular-nums;
    opacity: 0.65;
}

.coach-note {
    margin-top: 4px;
    padding-left: 2px;
    border-left: 2px solid rgba(212, 175, 125, 0.35);
    padding-left: 8px;
    font-size: 0.75rem;
    color: var(--text-muted);
    white-space: pre-wrap;
}

.coach-missing {
    font-size: 0.75rem;
    color: #ffb4a2;
    padding: 6px 12px;
}

/* The marker itself: this window only. It is deliberately not drawn into the
   captured page — see testbench.js. Fixed positioning because it is placed from
   getBoundingClientRect, which is viewport-relative. */
.coach-marker {
    position: fixed;
    z-index: 1400;
    pointer-events: none;
    border: 2px solid rgba(255, 149, 0, 0.95);
    border-radius: 6px;
    box-shadow: 0 0 0 3px rgba(255, 149, 0, 0.22), 0 0 14px rgba(255, 149, 0, 0.35);
    transition: left .12s ease-out, top .12s ease-out, width .12s ease-out, height .12s ease-out;
}

/* Off-screen: a band at the edge it lies beyond, rather than a box drawn at a
   coordinate that is not on the picture. */
.coach-marker-edge {
    align-items: center;
    justify-content: center;
    border-radius: 0;
    box-shadow: none;
    border: none;
    background-color: rgba(255, 149, 0, 0.85);
    color: #1a1a1a;
    font-family: Lato, system-ui, sans-serif;
    font-size: 0.75rem;
    font-weight: 700;
    letter-spacing: 0.02em;
}

/* --- Empty states -------------------------------------------------------- */

.empty-state {
    padding: 48px 24px;
    text-align: center;
    border: 1px dashed var(--card-border);
    border-radius: 16px;
    color: var(--text-muted);
}

/* --- Meeting tools console ------------------------------------------------
   The second-window operating view. Laid out for a window parked beside the
   meeting rather than for the app shell: two columns, both scrolling
   independently, so the transcript can be long without pushing the controls off
   screen. Denser than the rest of the portal on purpose — this surface is read
   at a glance mid-sentence, not browsed. */

.tools-warning {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 6px 16px;
    background-color: #5a1f1f;
    border-bottom: 1px solid #7a2b2b;
    color: #ffd9d9;
    font-family: 'Lato', sans-serif;
    font-size: 0.75rem;
    letter-spacing: 0.02em;
}

.tools-shell {
    display: flex;
    flex-direction: column;
    height: calc(100vh - 96px);
    padding: 16px 20px 12px 20px;
    gap: 12px;
}

.tools-header {
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    gap: 16px;
    flex-wrap: wrap;
}

.tools-title { margin: 0; }

.tools-header-right {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
}

.tools-source-select { min-width: 240px; }

/* Status pills. Live/demo and warm/cold are load-bearing, not decorative — a
   cold cache is the difference between a two-second answer and a ten-second one,
   and demo-vs-live decides whether you can trust what you are reading. */
.tools-stat {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 4px 10px;
    border: 1px solid var(--card-border);
    border-radius: 14px;
    background-color: var(--card-bg);
    color: var(--text-light);
    font-family: 'Lato', sans-serif;
    font-size: 0.72rem;
    white-space: nowrap;
}

.tools-stat-dot {
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background-color: currentColor;
}

.tools-stat.is-live { color: #6ddf8f; border-color: rgba(109, 223, 143, 0.4); }
.tools-stat.is-demo { color: var(--accent-color); border-color: rgba(212, 175, 125, 0.4); }
.tools-stat.is-cold { color: #e0a44a; border-color: rgba(224, 164, 74, 0.4); }

.tools-body {
    display: flex;
    gap: 14px;
    flex: 1;
    min-height: 0;
}

.tools-col {
    display: flex;
    flex-direction: column;
    gap: 12px;
    min-height: 0;
    overflow-y: auto;
    padding-right: 4px;
}

.tools-col-ask { flex: 1; min-width: 0; }
.tools-col-transcript { flex: 1.05; min-width: 0; }
.tools-col-answers { flex: 1; min-width: 0; }

/* Three columns is the intended shape and holds down to a fairly narrow window —
   a 1440px laptop gets three. The columns simply get narrower and the chip rows
   wrap to two lines, which is a cheaper trade than shrinking the type.
   Below this, the answers column drops to its own row rather than being squeezed
   into something unreadable; it is the one read after a press rather than during. */
@media (max-width: 1150px) {
    .tools-body { flex-wrap: wrap; }
    .tools-col-ask { flex: 1 1 46%; }
    .tools-col-transcript { flex: 1 1 46%; }
    .tools-col-answers { flex: 1 1 100%; max-height: 420px; }
}

@media (max-width: 900px) {
    .tools-body { flex-direction: column; }
    .tools-shell { height: auto; }
    .tools-col { overflow-y: visible; }
    .tools-col-answers { max-height: none; }
}

.tools-card {
    border: 1px solid var(--card-border);
    border-radius: 14px;
    background-color: var(--card-bg);
    padding: 14px 16px;
}

.tools-card-fill {
    display: flex;
    flex-direction: column;
    flex: 1;
    min-height: 0;
}

.tools-card-head { margin-bottom: 10px; }
.tools-muted { color: var(--text-muted); display: block; }

.tools-field { margin-bottom: 12px; }

.tools-field-label {
    display: block;
    color: var(--text-muted);
    font-family: 'Lato', sans-serif;
    font-size: 0.68rem;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    margin-bottom: 6px;
}

.tools-chiprow {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
}

/* Native buttons rather than MudChip: these are toggles that need a pressed
   state and a keyboard focus ring, and dressing a chip up as a control fights
   the component. */
.tools-chip {
    padding: 5px 11px;
    border: 1px solid var(--card-border);
    border-radius: 13px;
    background-color: transparent;
    color: var(--text-light);
    font-family: 'Lato', sans-serif;
    font-size: 0.75rem;
    cursor: pointer;
    transition: background-color 0.12s ease, border-color 0.12s ease, color 0.12s ease;
}

.tools-chip:hover { background-color: rgba(245, 245, 245, 0.07); }

.tools-chip.is-on {
    background-color: var(--accent-color);
    border-color: var(--accent-color);
    color: #1a1a1a;
    font-weight: 700;
}

.tools-primary { margin-top: 4px; }

/* --- candidates --- */

.tools-candidates { display: flex; flex-direction: column; gap: 8px; }

.tools-candidate {
    display: block;
    width: 100%;
    text-align: left;
    padding: 9px 11px;
    border: 1px solid var(--card-border);
    border-radius: 10px;
    background-color: transparent;
    cursor: pointer;
    transition: background-color 0.12s ease, border-color 0.12s ease;
}

.tools-candidate:hover:not(:disabled) {
    background-color: rgba(245, 245, 245, 0.06);
    border-color: var(--accent-color);
}

.tools-candidate:disabled { opacity: 0.5; cursor: default; }

.tools-candidate-top {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-bottom: 3px;
    font-family: 'Lato', sans-serif;
    font-size: 0.68rem;
    color: var(--text-muted);
}

.tools-candidate-at { font-variant-numeric: tabular-nums; }
.tools-candidate-who { color: var(--text-light); font-weight: 700; }
.tools-candidate-who.is-us { color: var(--accent-color); }
.tools-candidate-conf { margin-left: auto; font-variant-numeric: tabular-nums; }

.tools-candidate-text {
    color: var(--white);
    font-size: 0.83rem;
    line-height: 1.35;
}

.tools-candidate-note {
    margin-top: 3px;
    color: var(--text-muted);
    font-size: 0.68rem;
}

/* --- voice --- */

.tools-recordrow { display: flex; align-items: center; gap: 12px; }

.tools-reclive {
    display: flex;
    align-items: center;
    gap: 7px;
    color: #ff6b6b;
    font-family: 'Lato', sans-serif;
    font-size: 0.75rem;
}

.tools-recdot {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background-color: #ff3b30;
    animation: tools-pulse 1s ease-in-out infinite;
}

@keyframes tools-pulse {
    0%, 100% { opacity: 1; }
    50% { opacity: 0.25; }
}

/* --- answers --- */

.tools-answers {
    flex: 1;
    min-height: 0;
    overflow-y: auto;
}

.tools-answer {
    border: 1px solid var(--card-border);
    border-left: 3px solid var(--accent-color);
    border-radius: 10px;
    padding: 10px 12px;
    margin-bottom: 10px;
    background-color: rgba(245, 245, 245, 0.03);
}

.tools-answer-head {
    display: flex;
    align-items: center;
    gap: 8px;
    font-family: 'Lato', sans-serif;
    font-size: 0.66rem;
    color: var(--text-muted);
    margin-bottom: 6px;
}

.tools-answer-kind {
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--accent-color);
    font-weight: 700;
}

.tools-answer-latency, .tools-answer-cost {
    font-variant-numeric: tabular-nums;
}

.tools-answer-cost { margin-left: auto; }

.tools-answer-scope {
    color: var(--text-muted);
    font-family: 'Lato', sans-serif;
    font-size: 0.64rem;
    margin-bottom: 4px;
}

.tools-answer-q {
    color: var(--text-muted);
    font-size: 0.72rem;
    font-style: italic;
    margin-bottom: 6px;
    line-height: 1.3;
}

/* The line that gets read out loud, so it is the only thing at full size. */
.tools-answer-headline {
    color: var(--white);
    font-size: 0.95rem;
    font-weight: 700;
    line-height: 1.4;
}

/* Pinned: the answer to the thing you just asked, held at the top while you are
   probably still talking about it. Sticky rather than merely first, so scrolling
   the column to read an older one does not lose it. */
.tools-answer.is-pinned {
    position: sticky;
    top: 0;
    z-index: 1;
    background-color: #23262b;
    border-color: var(--accent-color);
    box-shadow: 0 6px 14px rgba(0, 0, 0, 0.45);
}

.tools-answer-pin {
    padding: 1px 6px;
    border-radius: 8px;
    background-color: var(--accent-color);
    color: #1a1a1a;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
}

/* Auto-detected: nobody asked for this one. Different edge colour and a muted
   headline so it can never be mistaken at a glance for the answer you requested
   — the whole risk of an unbidden feed is that it gets read as a reply. */
.tools-answer.is-auto {
    border-left-color: #e0a44a;
    background-color: rgba(224, 164, 74, 0.05);
}

.tools-answer.is-auto .tools-answer-kind { color: #e0a44a; }
.tools-answer.is-auto .tools-answer-headline { font-weight: 600; color: var(--text-light); }

.tools-answer-meta {
    display: flex;
    flex-wrap: wrap;
    gap: 5px;
    margin-top: 8px;
}

.tools-prov, .tools-conf {
    padding: 2px 7px;
    border-radius: 9px;
    font-family: 'Lato', sans-serif;
    font-size: 0.64rem;
    border: 1px solid var(--card-border);
    color: var(--text-light);
}

.tools-conf {
    background-color: rgba(109, 223, 143, 0.12);
    border-color: rgba(109, 223, 143, 0.35);
    color: #a9e8bf;
}

.tools-answer-detail {
    margin-top: 8px;
    color: var(--text-light);
    font-size: 0.8rem;
    line-height: 1.5;
}

.tools-answer-caveat {
    display: flex;
    align-items: flex-start;
    gap: 6px;
    margin-top: 7px;
    color: #e0a44a;
    font-size: 0.72rem;
    line-height: 1.4;
}

.tools-answer-more {
    margin-top: 6px;
    padding: 0;
    border: none;
    background: none;
    color: var(--accent-color);
    font-family: 'Lato', sans-serif;
    font-size: 0.7rem;
    cursor: pointer;
}

/* --- recurring --- */

.tools-recur {
    border-top: 1px solid var(--card-border);
    padding: 9px 0 4px 0;
}

.tools-recur:first-of-type { border-top: none; }
.tools-recur-text { color: var(--white); font-size: 0.83rem; line-height: 1.35; }

.tools-recur-meta { display: flex; gap: 5px; margin-top: 5px; }

.tools-recur-date {
    padding: 1px 6px;
    border-radius: 8px;
    background-color: rgba(224, 164, 74, 0.14);
    border: 1px solid rgba(224, 164, 74, 0.3);
    color: #e8c08a;
    font-family: 'Lato', sans-serif;
    font-size: 0.62rem;
    font-variant-numeric: tabular-nums;
}

.tools-recur-why {
    margin-top: 4px;
    color: var(--text-muted);
    font-size: 0.7rem;
}

/* --- transcript --- */

.tools-transcript-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    flex-wrap: wrap;
}

.tools-transcript-actions {
    display: flex;
    align-items: center;
    gap: 7px;
}

.tools-selcount {
    color: var(--accent-color);
    font-family: 'Lato', sans-serif;
    font-size: 0.72rem;
    font-weight: 700;
}

.tools-transcript {
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    display: flex;
    flex-direction: column;
    gap: 2px;
}

/* One turn = one button. Selection is the highest-precision way to say "the
   question is here", and it has to survive being clicked in a hurry, so the
   whole row is the target rather than a checkbox on the end of it. */
.tools-turn {
    display: grid;
    grid-template-columns: 42px 88px 1fr;
    gap: 9px;
    align-items: start;
    width: 100%;
    text-align: left;
    padding: 5px 8px;
    border: 1px solid transparent;
    border-radius: 7px;
    background-color: transparent;
    cursor: pointer;
    font-family: 'Lato', sans-serif;
    transition: background-color 0.1s ease;
}

.tools-turn:hover { background-color: rgba(245, 245, 245, 0.06); }

.tools-turn.is-selected {
    background-color: rgba(212, 175, 125, 0.16);
    border-color: var(--accent-color);
}

/* Outside the chosen lookback: dimmed rather than hidden, so widening the window
   is an obvious next move instead of a guess. */
.tools-turn.is-outside { opacity: 0.38; }

.tools-turn-at {
    color: var(--text-muted);
    font-size: 0.66rem;
    font-variant-numeric: tabular-nums;
    padding-top: 2px;
}

.tools-turn-who {
    color: var(--text-light);
    font-size: 0.7rem;
    font-weight: 700;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.tools-turn.is-us .tools-turn-who { color: var(--accent-color); }

.tools-turn-text {
    color: var(--white);
    font-size: 0.8rem;
    line-height: 1.4;
}

/* --- prompt inspector --- */

.tools-part {
    border: 1px solid var(--card-border);
    border-radius: 9px;
    padding: 8px 10px;
    margin-bottom: 7px;
}

.tools-part.is-cached { border-left: 3px solid #6ddf8f; }
.tools-part.is-fresh { border-left: 3px solid #e0a44a; }

.tools-part-head {
    display: flex;
    align-items: center;
    gap: 9px;
    font-family: 'Lato', sans-serif;
    font-size: 0.68rem;
    margin-bottom: 4px;
}

.tools-part-name { color: var(--white); font-weight: 700; }
.tools-part-tokens { color: var(--text-muted); font-variant-numeric: tabular-nums; }
.tools-part-tag { margin-left: auto; color: var(--text-muted); }

.tools-part-body {
    color: var(--text-light);
    font-size: 0.74rem;
    line-height: 1.45;
}

/* Not-in-a-meeting: the console's most common resting state, so it explains
   itself and what will happen rather than showing an empty pane. */
.tools-empty {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 8px;
    padding: 40px 20px;
    text-align: center;
    color: var(--text-light);
}

.tools-empty .mud-icon-root {
    font-size: 2rem;
    color: var(--text-muted);
}

/* --- Tools activity (review surface, its own tab) ------------------------- */

/* The two overlap numbers get their own treatment because they are the point of
   the page: everything else is context for reading them. */
.tools-overlap {
    display: flex;
    gap: 14px;
    flex-wrap: wrap;
}

.tools-overlap-card {
    flex: 1 1 320px;
    display: flex;
    flex-direction: column;
    gap: 4px;
    padding: 18px 20px;
    border: 1px solid var(--card-border);
    border-left: 3px solid var(--accent-color);
    border-radius: 14px;
    background-color: var(--card-bg);
}

.tools-overlap-value {
    font-size: 2.4rem;
    font-weight: 700;
    line-height: 1;
    color: var(--accent-color);
    font-variant-numeric: tabular-nums;
}

.tools-overlap-label { color: var(--white); font-size: 0.9rem; }
.tools-overlap-note { color: var(--text-muted); font-size: 0.75rem; line-height: 1.45; }

.tools-statgrid {
    display: flex;
    gap: 10px;
    flex-wrap: wrap;
}

.tools-statbox {
    flex: 1 1 150px;
    display: flex;
    flex-direction: column;
    gap: 2px;
    padding: 12px 14px;
    border: 1px solid var(--card-border);
    border-radius: 12px;
    background-color: var(--card-bg);
}

.tools-statbox-value {
    font-size: 1.4rem;
    font-weight: 700;
    color: var(--white);
    font-variant-numeric: tabular-nums;
}

.tools-statbox-label { color: var(--text-muted); font-size: 0.72rem; }

/* Which door gets used. A bar rather than a number because the comparison
   between them is the whole question, and eyes read bars faster. */
.tools-kinds { display: flex; flex-direction: column; gap: 8px; max-width: 620px; }

.tools-kind-head {
    display: flex;
    justify-content: space-between;
    font-family: 'Lato', sans-serif;
    font-size: 0.76rem;
    margin-bottom: 3px;
}

.tools-kind-name { color: var(--white); }
.tools-kind-count { color: var(--text-muted); font-variant-numeric: tabular-nums; }

.tools-kind-bar {
    height: 7px;
    border-radius: 4px;
    background-color: rgba(245, 245, 245, 0.07);
    overflow: hidden;
}

.tools-kind-fill {
    height: 100%;
    background-color: var(--accent-color);
    border-radius: 4px;
}

.tools-log { display: flex; flex-direction: column; gap: 8px; }

.tools-logrow {
    border: 1px solid var(--card-border);
    border-left: 3px solid var(--accent-color);
    border-radius: 10px;
    padding: 10px 12px;
    background-color: var(--card-bg);
}

.tools-logrow.is-auto {
    border-left-color: #e0a44a;
    background-color: rgba(224, 164, 74, 0.04);
}

.tools-logrow-head {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
    font-family: 'Lato', sans-serif;
    font-size: 0.66rem;
    color: var(--text-muted);
    margin-bottom: 5px;
}

.tools-log-kind {
    text-transform: uppercase;
    letter-spacing: 0.06em;
    font-weight: 700;
    color: var(--accent-color);
}

.tools-logrow.is-auto .tools-log-kind { color: #e0a44a; }
.tools-log-who { color: var(--text-light); font-weight: 700; }
.tools-log-conf { font-variant-numeric: tabular-nums; }
.tools-log-when { margin-left: auto; font-variant-numeric: tabular-nums; }

/* The overlap flag is the finding, so it is the one thing here that is coloured
   like a result rather than metadata. */
.tools-log-flag.is-overlap {
    padding: 1px 7px;
    border-radius: 8px;
    background-color: rgba(109, 223, 143, 0.14);
    border: 1px solid rgba(109, 223, 143, 0.35);
    color: #a9e8bf;
    font-weight: 700;
}

.tools-log-q { color: var(--white); font-size: 0.85rem; line-height: 1.4; }

.tools-log-a {
    margin-top: 4px;
    color: var(--text-light);
    font-size: 0.78rem;
    line-height: 1.4;
}

.tools-log-meta {
    display: flex;
    gap: 12px;
    margin-top: 6px;
    color: var(--text-muted);
    font-family: 'Lato', sans-serif;
    font-size: 0.66rem;
}

/* Duplicate flag on the answer card itself, so the redundancy shows in the
   moment rather than only in the log afterwards. */
.tools-answer-dupe {
    padding: 1px 6px;
    border-radius: 8px;
    background-color: rgba(109, 223, 143, 0.14);
    border: 1px solid rgba(109, 223, 143, 0.35);
    color: #a9e8bf;
    font-weight: 700;
}

/* Verdict buttons. Four rather than a thumbs pair, because the three ways a
   detection can be wrong are different bugs and want telling apart. Only the
   chosen one is coloured — an unrated row should look unrated at a glance, since
   the good-catch rate means nothing until most rows are rated. */
.tools-verdicts {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 6px;
    margin-top: 9px;
}

.tools-verdict {
    padding: 4px 10px;
    border: 1px solid var(--card-border);
    border-radius: 12px;
    background-color: transparent;
    color: var(--text-light);
    font-family: 'Lato', sans-serif;
    font-size: 0.72rem;
    cursor: pointer;
    transition: background-color 0.12s ease, border-color 0.12s ease, color 0.12s ease;
}

.tools-verdict:hover:not(:disabled) { background-color: rgba(245, 245, 245, 0.07); }
.tools-verdict:disabled { opacity: 0.5; cursor: default; }

.tools-verdict.is-on.is-good {
    background-color: rgba(109, 223, 143, 0.9);
    border-color: rgba(109, 223, 143, 0.9);
    color: #10240f;
    font-weight: 700;
}

.tools-verdict.is-on.is-bad {
    background-color: #b3261e;
    border-color: #b3261e;
    color: #fff;
    font-weight: 700;
}

.tools-verdict-by {
    margin-left: 4px;
    color: var(--text-muted);
    font-family: 'Lato', sans-serif;
    font-size: 0.66rem;
}
