:root {
    --main-width: 86%;
    --main-height: 86%;
    --main-box-shadow: 0px 0px 11px 0px rgba(0, 0, 0, 0.50);
    --box-shadow2: 10px 10px 25px 8px rgb(0, 0, 0, 0.75);
    --box-shadow3: 10px 10px 25px 8px rgba(201, 240, 224, 0.72);
    --box-shadow4: 10px 10px 25px 8px rgba(219, 255, 242, 0.72);
    --box-shadow5: 10px 10px 25px 8px rgb(0, 0, 0, 0.45);
    --box-shadow6: 8px 8px 15px 8px rgba(23, 242, 153, 0.72);
    --box-shadow-tab-original: 0 4px 6px 0 rgba(0, 0, 0, 0.77);
    --box-shadow-inset1: inset 0 0 6px rgba(0, 0, 0, 0.5);
    --box-shadow-inset2: inset 5px 7px 7px 5px rgba(219, 255, 242);
    /*background-color: #DBFFF233;*/
    /*background: #556cd6; //for buttons */
}

body {
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    background: url(../images/beach.jpg) no-repeat center center fixed;
    -webkit-background-size: cover;
    -moz-background-size: cover;
    -o-background-size: cover;
    background-size: cover;
    font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto',
    'Helvetica Neue', 'Ubuntu', sans-serif;
    height: 100vh;
    margin: 0;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
}

.baseFrame {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    background-color: #00000000;
    width: 88%;
    height: 86%;
    border-radius: 7px;
    box-shadow: var(--box-shadow2);
}

.homepageFrame {
    margin-top: 2%;
    background: #00000000;
    color: black;
}

.baseScreen {
    display: flex;
    flex-direction: column;
    height: 93%;
    width: 96%;
    overflow-y: auto;
    scrollbar-width: thin;
    justify-content: flex-start;
    align-items: center;
    background: #ffffff99;
    box-sizing: border-box;
    padding: 0 1% 0 1%;
    border-radius: 7px;
    border: 3px inset #cccccc;
    box-shadow: var(--box-shadow-inset1);
}


/* Footer */
.footerContent li {
    display: inline-block; /* Makes list items behave like inline elements but allows width/height/margins */
    margin-right: 1em; /* Adds some space between "bullet points" */
}

.footerContent {
    margin-top: 10px;
    margin-bottom: 7px;
    padding: 0; /* ul's default left padding (for list markers, unused here) would otherwise throw off centering below */
    text-align: center; /* no visible effect on desktop's single line (already exactly content-width); centers each
                            line when it wraps to 3 lines on mobile, instead of left-aligning within the widest line */
}

.footer {
    display: flex;
    flex-direction: column;
    flex-shrink: 0;
    position: absolute;
    bottom: 0;
    left: 0;
    right: 0;
    font-weight: 500;
    justify-content: center;
    align-items: center;
}

a {
    display: inline;
    color: revert;
}

.pseudoLinkBase {
    display: inline;
    cursor: pointer;
    margin: 0 3px 0 3px;
    text-decoration: underline;
}

.pseudoLink2 {
    display: inline;
    cursor: pointer;
    font-weight: bold;
}

.bottomMargin {
    margin-bottom: 1em;
}


.flexRowBase {
    display: flex;
    flex-direction: row;
    width: 100%; /* .baseScreen's align-items:center would otherwise shrink this to its content's natural size
                    instead of the available width (pre-existing on desktop too, not just mobile) */
    justify-content: center;
    align-items: center;
}

.flexColumnBase {
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    gap: 10px;
}


/* Credits */
.creditGrid {
    display: flex; /* not CSS grid: grid's justify-content only centers the track set as a whole, so an incomplete
                       last row (e.g. 6 credits in 4 columns) stays packed against the start instead of centering -
                       flexbox's per-line justify-content centers each wrapped row independently */
    flex-wrap: wrap;
    width: 100%; /* .baseScreen is a flex container with align-items:center, which would otherwise shrink this to its
                    content's natural size instead of the available width */
    justify-content: center; /* centers each row (including a partial last row) as a group */
    gap: 13px 20px; /* Adds space between grid items */
}

.creditGridItem {
    display: flex;
    flex-direction: row;
    align-items: center;
    gap: 12px; /* was 3 overlapping elements held together with negative margins/z-index - real gap+flex sizing
                  below is far more robust than lining up magic-number offsets by eye */
    flex: 0 0 300px; /* fixed card width (was 260px - too narrow, clipping the last character of some credit
                         codes depending on which characters they contained) - see @media override for the
                         single-column mobile width */
    height: 56px; /* fixed - without this, revealing a code (toggling the input's type between password/text)
                     could very slightly change its rendered line height depending on the browser/font, which
                     would then grow this whole row since align-items:center doesn't clip - a fixed height on
                     both this and .creditCodePasswordBox below makes that impossible regardless of content */
    box-sizing: border-box;
    padding: 0 14px;
    background: rgba(255, 255, 255, 0.75);
    border: 1px solid var(--acct-border);
    border-radius: var(--acct-radius-md);
    box-shadow: 0 6px 16px rgba(10, 7, 4, 0.12);
}

.showHideCreditButton {
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    width: 30px;
    height: 30px;
    background-color: rgba(0, 0, 0, 0.04);
    border: none;
    border-radius: 50%;
    cursor: pointer;
    transition: background-color 0.15s ease;
}

.showHideCreditButton:hover {
    background-color: rgba(0, 0, 0, 0.08);
}

.showCreditIcon, .hideCreditIcon {
    width: 17px;
    height: 17px;
    vertical-align: middle;
}

/* Sizing lives on this plain <span> wrapper, not the <input> itself: flex-basis:0 and even an explicit px/calc()
   width on the input directly still weren't enough, because Chromium gives input[type=password] and
   input[type=text] genuinely different intrinsic/min-content widths at the SAME declared width - the browser's
   own form-control layout can override an author-specified width with that intrinsic minimum, so the box kept
   visibly resizing every time revealCode() toggled the type. A plain, non-form-control <span> has no such
   type-dependent intrinsic sizing quirk, so fixing size here and having the input just fill it at 100% sidesteps
   the problem entirely regardless of which type is currently set. */
.creditCodeWrap {
    flex: none;
    width: calc(100% - 80px); /* 100% of .creditGridItem's content box (border-box, so its own padding/border are
                                  already excluded) minus the icon (26px) + eye button (30px) + the two 12px gaps
                                  between them = 80px - self-adapts to both the desktop 260px card and the mobile
                                  full-width one, instead of a value hardcoded to one specific item width */
    height: 34px;
    overflow: hidden; /* belt-and-suspenders: clips the input instead of letting the wrapper grow, even if some
                          future change reintroduces an oversized intrinsic minimum on the input again */
    border-radius: var(--acct-radius-sm);
}

.creditCodePasswordBox {
    width: 100%;
    height: 100%;
    box-sizing: border-box;
    text-align: center;
    letter-spacing: 0.06em;
    font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', monospace; /* reads as an activation code, not prose */
    font-size: 0.85em;
    padding: 0 6px;
    color: var(--acct-text-primary);
    background: #faf8f5;
    border: 1px solid var(--acct-border);
    border-radius: var(--acct-radius-sm);
}

.creditIcon {
    width: 26px;
    height: 26px;
    flex-shrink: 0;
}


.baseButton {
    height: 34px;
    background: #66d9ff;
    color: white;
    width: 60%;
    font-size: 15px;
    border: 0;
    font-weight: 500;
    cursor: pointer;
    letter-spacing: 1px;
    border-radius: 0 0 6px 6px;
    transition: all 0.3s ease;
    box-shadow: 0 4px 5px 0 rgba(0, 0, 0, 0.77);
}

.baseButton:hover {
    opacity: 0.7;
}

.baseButton:active {
    opacity: 0.7;
    /*transform: translateY(3px);*/
}

.centeredButton {
    display: block;
    width: 50%; /* Or any specific width */
    margin: 0 auto;
}

.loginButton {
    border-radius: 6px 6px 6px 6px;
    margin-bottom: 1em;
    margin-top: 1em;
    width: 25%;
    font-weight: 700;
    letter-spacing: 1px; /* add extra letter spacing, kinda like position:relative */
    box-shadow: 4px 4px 5px 2px rgba(0, 0, 0, 0.57);
}

.loginButton:hover {
    opacity: 0.8;
}


.blurb {
    padding: 0 4% 0 4%;

}

.blurb2 {
    padding: 1% 5% 1% 5%;
    border-radius: 7px;
    background-color: white;
    box-shadow: var(--box-shadow2);
}

.historyList {
    display: flex;
    flex-direction: column;
    width: 100%; /* .baseScreen/.modalBox both have align-items:center, which would otherwise shrink this to its
                    content's natural width instead of the available width (same shrink-to-fit pattern as
                    .creditGrid/.flexRowBase elsewhere in this file) */
    gap: 10px;
    padding-right: 14px; /* .baseScreen scrolls (overflow-y:auto) with no padding of its own, so without this
                             the rows sit flush against the scrollbar */
    box-sizing: border-box;
}

.historyRow {
    display: flex;
    flex-direction: row; /* one line per activity on desktop - see the @media override below for narrow screens,
                             where badge/timestamp/description/button can't all fit on one line */
    align-items: center;
    gap: 16px;
    background: #ffffff;
    box-shadow: var(--box-shadow2);
    border-radius: 7px;
    padding: 10px 20px;
}

.historyRowHeader {
    display: flex;
    flex-direction: row;
    align-items: center;
    gap: 10px;
    font-weight: bold;
    flex-shrink: 0; /* keep the badge+timestamp at their natural width instead of being squeezed by the description */
}

.historyDescription {
    flex: 1 1 auto; /* fills the remaining space between the header and the button so everything lines up on one row */
    min-width: 0; /* without this, a flex item won't shrink below its text's natural (unwrapped) width, defeating the
                     white-space:nowrap + ellipsis truncation below */
    white-space: nowrap; /* a long description truncates with an ellipsis instead of wrapping the row onto extra
                             lines - see the @media override, which restores normal wrapping once the row itself
                             goes back to a stacked column layout on mobile */
    overflow: hidden;
    text-overflow: ellipsis;
}

.historyIpAddress {
    flex-shrink: 0; /* same reasoning as .historyRowHeader - keeps its own width instead of being squeezed */
    font-size: 0.85em;
    color: var(--acct-text-secondary);
}

.historyPagination {
    display: none; /* JS shows this (display:flex) only when there's more than one page - see account.html */
    align-items: center;
    justify-content: center;
    gap: 16px;
    width: 100%;
    margin-top: 14px;
    box-sizing: border-box;
}

/* .acctTheme .baseButton.historyPageButton (not just .historyPageButton alone): .acctTheme .baseButton (2
   classes) otherwise beats a plain 1-class .historyPageButton on padding regardless of source order - same
   specificity-tie issue documented for .secondaryButton above. */
.acctTheme .baseButton.historyPageButton {
    width: auto;
    flex: none;
    padding: 8px 18px;
}

.historyPageButton:disabled {
    opacity: 0.4;
    cursor: default;
}

.historyPageIndicator {
    font-size: 0.9em;
    color: var(--acct-text-secondary);
    white-space: nowrap;
}

.historyTypeBadge {
    display: inline-block;
    padding: 2px 10px;
    border-radius: 12px;
    font-size: 0.8em;
    font-weight: 600;
    color: white;
    letter-spacing: 0.3px;
}

.historyTypeBadge.purchase {
    background-color: #2e9e5b;
}

.historyTypeBadge.redemption {
    background-color: #3178c6;
}

.historyTypeBadge.session {
    background-color: #8452d5;
}

.rankBadge {
    display: inline-block;
    min-width: 26px;
    padding: 2px 8px;
    margin-right: 8px;
    border-radius: 12px;
    font-size: 0.8em;
    font-weight: 700;
    text-align: center;
    color: white;
    background-color: #888;
}

.rankBadge.gold {
    background-color: #d4af37;
}

.rankBadge.silver {
    background-color: #a8a8a8;
}

.rankBadge.bronze {
    background-color: #b06b3a;
}

.pillButtonLink {
    display: inline-block;
    flex-shrink: 0; /* keeps its own width instead of being squeezed by .historyDescription in the one-line desktop row */
    cursor: pointer;
    padding: 4px 14px;
    font-size: 0.85em;
    font-weight: 600;
    color: white;
    background-color: #66d9ff;
    border: none;
    border-radius: 14px;
    text-decoration: none;
    transition: opacity 0.2s ease;
}

.pillButtonLink:hover {
    opacity: 0.75;
}

.backLink {
    align-self: flex-start; /* .baseScreen centers children by default - this one reads better left-aligned under the content above it */
    margin-top: 12px;
}

.errorBanner {
    padding: 1% 4% 1% 4%;
    margin: 0 4% 2% 4%;
    border-radius: 7px;
    background-color: #fdecea;
    color: #611a15;
    border: 1px solid #f5c6cb;
}





.gridScheduling {
    background: rgba(255, 255, 255, 0.75);
    border: 1px solid var(--acct-border);
    box-shadow: 0 10px 26px rgba(10, 7, 4, 0.12);
    border-radius: var(--acct-radius-md);
    margin: 16px auto 0 auto;
    width: 90%;
    height: auto; /* was a fixed 70% - forced a big empty box even for a single row; sizing to content instead */
    padding: 10px 20px;
    display: grid;
    grid-template-columns: 1fr 1fr 1fr max-content max-content;
    align-items: center;
    gap: 6px 10px;
}

.gridHeaderScheduling {
    padding: 4px 8px;
    text-align: center;
    font-weight: 700;
    font-size: 0.85em;
    letter-spacing: 0.3px;
    text-transform: uppercase;
    color: var(--acct-text-secondary);
    text-decoration: none;
    border-bottom: 2px solid var(--acct-border);
    align-self: end;
    padding-bottom: 6px;
}

.gridItemScheduling {
    padding: 4px 6px;
    text-align: center;
    align-self: center;
    justify-self: center;
}

/* Small, standard-looking circular icon buttons for the Schedule tab's Edit/Delete actions - replaces the old
   yellow/red edit30.png/delete30.png images, which looked out of place next to the rest of the glass theme. */
.gridIconButton {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 30px;
    height: 30px;
    padding: 0;
    background: rgba(0, 0, 0, 0.05);
    border: none;
    border-radius: 50%;
    color: var(--acct-text-secondary);
    cursor: pointer;
    transition: background-color 0.15s ease, color 0.15s ease;
}

.gridIconButton svg {
    width: 15px;
    height: 15px;
}

.gridIconButton:hover {
    background: rgba(var(--acct-accent-rgb), 0.14);
    color: var(--acct-accent-dark);
}

.gridIconButtonDelete:hover {
    background: rgba(190, 40, 40, 0.14);
    color: #b91c1c;
}

.accountLocationsSection {
    width: 80%;
    margin-top: 10px;
    text-align: center;
}

.accountLocationsSection h4 {
    margin: 0 0 8px 0;
    color: var(--acct-text-primary);
}

.innerGrid {
    display: grid;
    grid-template-columns: auto auto;
    background: rgba(255, 255, 255, 0.6);
    border: 1px solid var(--acct-border);
    border-radius: var(--acct-radius-md);
    box-shadow: none;
    width: 80%;
    padding: 18px 24px;
    gap: 3%;
    animation: fadeIn 0.4s ease;
    justify-content: space-between;
    align-items: center;
    box-sizing: border-box;
}

.gridItem {
    display: flex;
    flex-direction: column;
    border: none;
    box-shadow: none;
    width: 100%;
    height: 98%;
    overflow-y: scroll;
    gap: 3%;
    animation: fadeIn 2s;
    justify-content: flex-start;
    align-items: center;
    box-sizing: border-box;
}

.innerL2 {
    background: rgba(255, 255, 255, 0.7);
    border: 1px solid var(--acct-border);
    box-shadow: 0 10px 26px rgba(10, 7, 4, 0.12);
    border-radius: var(--acct-radius-md);
    padding: 20px 40px 30px 40px;
    width: 60%;
}

.innerL2 h5 {
    text-align: center; /* centers it over .centeredButton below, which is also margin:auto-centered within
                            this same card */
}

/* ============================================================================
   ACCOUNT PAGE - GROUND-UP REDESIGN (account.html only)
   This entire nav system (.tabBar/.tabBarButton/.tabBarButtonActive/.tabBarIcon/
   .hamburgerButton/.mobileBrandBanner/.tabBarOverlay) is exclusive to account.html
   (no other template references it), so it's redesigned directly in place rather
   than needing the .acctTheme scoping used further down for classes shared with
   other pages. Desktop: a collapsed icon-only rail flush against the active
   page's card (body.acctTheme's gap:0 + matching one-sided border-radius below
   make the two read as one merged panel with an internal divider, rather than
   two separate floating cards). Mobile: the existing off-canvas drawer mechanism
   is untouched (position:fixed + .open, toggled by the same JS) - just reskinned
   (and expanded back to icon+label - see the @media override) to match. */
.tabBar {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    position: static; /* was absolute/full-width top bar - now a normal flex item (the sidebar) inside
                          body.acctTheme's row layout; see the @media override for mobile's off-canvas drawer */
    width: 72px; /* collapsed - icon-only, see .tabBarButton's font-size:0 label-hiding trick below */
    flex-shrink: 0;
    height: calc(96vh - 51px); /* matches .acctTheme .baseFrame's height exactly (same formula, same reasoning
                                   comment there) so the sidebar and the active page's card stay the same height -
                                   they're meant to read as one continuous merged panel, not two mismatched ones */
    gap: 4px;
    padding: 22px 8px;
    box-sizing: border-box;
    background: var(--acct-glass-bg);
    backdrop-filter: blur(26px) saturate(180%);
    -webkit-backdrop-filter: blur(26px) saturate(180%);
    border: 1px solid var(--acct-glass-border);
    border-right: none; /* the active page's card supplies the matching divider border on its own left edge instead -
                            avoids a doubled-thickness line exactly at the seam between the two elements */
    border-radius: var(--acct-radius-lg) 0 0 var(--acct-radius-lg); /* rounded only on the outer (left) corners -
                                                                        the inner corners butt flush against the
                                                                        content card, so together they read as one
                                                                        continuous panel rather than two */
    box-shadow: var(--acct-shadow);
}

.acctSidebarBrand {
    display: none; /* no room for a text wordmark in a 72px icon rail - re-shown in the expanded mobile drawer,
                       see the @media override below */
}

.tabBarButton {
    display: flex;
    flex-direction: row;
    justify-content: center; /* was flex-start (icon+label) - centers the now-solo icon in the collapsed rail */
    align-items: center;
    background-color: transparent;
    transition: background-color 0.2s ease, color 0.2s ease, border-color 0.2s ease;
    font-size: 0; /* collapses the button's own text node ("Account", "Software", ...) to zero size, leaving only
                     the icon (which has its own explicit pixel width/height, so it's unaffected) visible - the
                     text is still there for accessibility, just not painted. See each button's new title="..."
                     attribute in account.html for the hover tooltip this trades away visually. */
    font-weight: 600;
    letter-spacing: 0.2px;
    color: var(--acct-text-secondary);
    height: auto;
    width: 100%;
    padding: 11px 0;
    border: none;
    border-left: 3px solid transparent; /* reserves space so the active indicator below doesn't shift layout */
    border-radius: var(--acct-radius-sm);
    box-shadow: none;
    outline: none;
    cursor: pointer;
}

.tabBarButton:hover {
    background-color: rgba(var(--acct-accent-rgb), 0.08);
    color: var(--acct-text-primary);
}

.tabBarButton:active {
    background-color: rgba(var(--acct-accent-rgb), 0.14);
}

.tabBarButtonActive {
    background-color: rgba(var(--acct-accent-rgb), 0.12);
    color: var(--acct-accent-dark);
    border-left-color: var(--acct-accent);
}

.tabBarButtonActive:hover {
    background-color: rgba(var(--acct-accent-rgb), 0.18);
}

#logoutTabButton {
    margin-top: auto; /* pins Logout to the bottom of the sidebar's flex column, separated from the nav list above */
    border-top: 1px solid var(--acct-border);
    border-radius: 0;
    padding-top: 16px;
    margin-bottom: -4px;
}

.tabBarIcon {
    vertical-align: middle;
    width: 20px;
    height: 20px;
    margin-right: 0; /* was 12px (icon-to-label gap) - nothing to space out now that the label is visually collapsed */
    flex-shrink: 0;
}

.hamburgerButton {
    display: none; /* shown only below the mobile breakpoint - see @media rule */
    align-items: center;
    justify-content: center;
    position: fixed;
    top: 2%;
    left: 3%;
    z-index: 1001;
    width: 40px;
    height: 40px; /* explicit, fixed, and shared with .mobileBrandBanner below (both also at the same "top: 2%")
                     so the two line up on exact vertical centers regardless of either one's font metrics */
    box-sizing: border-box;
    background: var(--acct-glass-bg);
    backdrop-filter: blur(18px) saturate(180%);
    -webkit-backdrop-filter: blur(18px) saturate(180%);
    color: var(--acct-text-primary);
    border: 1px solid var(--acct-glass-border);
    border-radius: var(--acct-radius-sm);
    box-shadow: var(--acct-shadow);
    font-size: 24px;
    line-height: 1;
    padding: 0;
    cursor: pointer;
}

.mobileBrandBanner {
    display: none; /* shown only below the mobile breakpoint - see @media rule */
}

.tabBarOverlay {
    display: none;
    position: fixed;
    inset: 0;
    /* Matches .tabBar's own open width (65%, capped at 280px) exactly via the same min() expression, so the dark
       overlay only ever covers the page BEHIND the open drawer, never the drawer's own area. z-index alone
       (.tabBar's 1000 vs this rule's 999) only controls paint order/click-through, not what .tabBar's own
       backdrop-filter:blur() samples - blur always renders based on whatever is actually painted behind the
       element regardless of z-index, so with the overlay previously spanning the full screen, the drawer's own
       translucent glass panel was rendering a blurred copy of the DARKENED page through itself, reading as a
       dimmed/backgrounded panel instead of one sitting clearly on top. */
    left: min(65%, 280px);
    background-color: rgba(0, 0, 0, 0.5);
    z-index: 999;
}

.tabBarOverlay.open {
    display: block;
}

/* Set on <body> while the logout confirmation modal is open (see account.html's logout()/cancelLogout()) - hides
   every other piece of page chrome so the confirmation is the only thing visible, restoring automatically on
   cancel since removing the class just lets each element's own normal (and possibly breakpoint-dependent)
   display value re-apply, rather than JS having to remember and restore each one's "shown" value itself. */
body.loggingOut #tabBar,
body.loggingOut .baseFrame,
body.loggingOut .footer,
body.loggingOut .supportFabButton,
body.loggingOut #hamburgerButton,
body.loggingOut .mobileBrandBanner {
    display: none !important; /* openTab() sets the active .baseFrame's display via inline style
                                  ("element.style.display = 'flex'"), which otherwise beats any plain stylesheet
                                  rule regardless of specificity - only another inline style or an !important
                                  stylesheet rule can override an inline style */
}



.modalBackground {
    display: none; /* Hidden by default */
    position: fixed; /* Stay in place */
    z-index: 1; /* Sit on top */
    padding-top: 100px; /* Location of the box */
    left: 0;
    top: 0;
    width: 100%; /* Full width */
    height: 100%; /* Full height */
    overflow: auto; /* Enable scroll if needed */
    background-color: rgba(10, 7, 4, 0.6); /* darker than a plain 50% black - the road.jpg backdrop is already busy,
                                               so the dimming needs to be stronger to keep the modal the clear focus */
}

/* Modal Content */
.modalBox {
    display: flex;
    flex-direction: column;
    align-items: center;
    position: relative;
    top: 8%;
    background: var(--acct-glass-bg);
    backdrop-filter: blur(30px) saturate(180%);
    -webkit-backdrop-filter: blur(30px) saturate(180%);
    margin: auto;
    padding: 30px;
    width: 50%;
    max-height: 80vh; /* belt-and-suspenders against any modal's content running off the bottom of the screen -
                          .modalScrollArea below scrolls internally instead, regardless of viewport height or
                          content length */
    overflow: hidden; /* the actual scrolling happens on .modalScrollArea now (see below) - this box is just the
                          bordered/padded card around it, same division of labor as .baseFrame/.baseScreen on the
                          main panel. Previously this element did both jobs at once, which put the scrollbar
                          flush against ITS OWN border (no inset, unlike the main panel's scrollbar sitting well
                          inside .baseFrame's separate padding) - not just a "make it thin" fix, a structural one. */
    box-sizing: border-box;
    border: 1px solid var(--acct-glass-border);
    box-shadow: var(--acct-shadow-modal);
    border-radius: var(--acct-radius-lg);
    animation: acctModalIn 0.22s ease; /* the JS still just flips display:none -> block (unchanged) - this restarts
                                          automatically every time that happens, turning an instant snap into a
                                          quick fade/scale-in */
}

.modalScrollArea {
    display: flex;
    flex-direction: column;
    align-items: center;
    width: 100%;
    flex: 1 1 auto;
    min-height: 0; /* lets this actually shrink below its content's height within the flex column, instead of
                      forcing .modalBox to grow past max-height - the same min-width:0 shrink-to-fit lesson
                      documented elsewhere in this file, just on the cross axis instead of the main axis */
    overflow-y: auto;
    padding-right: 14px; /* breathing room between the scrollbar and the content, matching .historyList's own
                             right padding for the same reason (rows/cards otherwise sit flush against it) */
    box-sizing: border-box;
}

/* The address-entry modal's fields now sit in a wider grid (see .addressFieldset above) instead of one full-width
   field per line, so it needs more horizontal room than the other (much simpler) modals to lay 2-4 fields per row. */
#myModal .modalBox {
    width: 74%;
    max-width: 640px;
}

@keyframes acctModalIn {
    from {
        opacity: 0;
        transform: translateY(-12px) scale(0.98);
    }
    to {
        opacity: 1;
        transform: translateY(0) scale(1);
    }
}

/* Support modal: truly centered in the viewport (the shared .modalBox above instead sits at a fixed "top: 8%",
   which on a short/small screen reads as noticeably lower than center) - position:fixed + a translate(-50%,-50%)
   centering trick instead of the shared rule's "top:8%; margin:auto" scheme. Needs its own keyframe (rather than
   the shared .modalBox's acctModalIn) because both animate "transform", and acctModalIn's own translateY/scale
   would otherwise overwrite the centering translate the moment the animation finishes. */
#supportModal .modalBox {
    position: fixed;
    top: 50%;
    left: 50%;
    margin: 0;
    transform: translate(-50%, -50%); /* static fallback/resting state - animation-fill-mode:forwards below
                                          should keep the keyframe's own matching "to" transform applied once the
                                          animation ends, but without this the box has no transform at all until
                                          then (or if the animation is ever skipped/interrupted), snapping its
                                          top-left corner to viewport center instead of actually centering it */
    animation: acctModalInCentered 0.22s ease forwards;
}

@keyframes acctModalInCentered {
    from {
        opacity: 0;
        transform: translate(-50%, calc(-50% - 12px)) scale(0.98);
    }
    to {
        opacity: 1;
        transform: translate(-50%, -50%) scale(1);
    }
}

.modalCloseX {
    position: absolute; /* parent container needs to be set to relative */
    right: 5%;
    top: 4%;
    color: var(--acct-text-secondary);
    font-size: 30px;
    font-weight: 300;
    line-height: 1;
    transition: color 0.15s ease;
}

.modalCloseX:hover, .modalCloseX:focus {
    color: var(--acct-accent-dark);
    text-decoration: none;
    cursor: pointer;
}

.logoutModalText {
    text-align: center;
    color: var(--acct-text-secondary);
    margin: 4px 0 18px 0;
}

.logoutModalActions {
    display: flex;
    gap: 12px;
    width: 100%;
    justify-content: center;
}

.logoutModalActions .baseButton {
    width: auto;
    flex: 1 1 0;
    max-width: 160px;
}

/* Floating support button - fixed to the viewport (the common "chat bubble" pattern), not tied to any one tab
   or .baseFrame, so it stays put across every tab and isn't touched by openTab()'s display:none toggling. */
.supportFabButton {
    display: flex;
    align-items: center;
    justify-content: center;
    position: fixed;
    right: 28px;
    bottom: 28px;
    width: 56px;
    height: 56px;
    padding: 0;
    color: white;
    background: var(--acct-accent);
    border: none;
    border-radius: 50%;
    box-shadow: 0 10px 26px rgba(var(--acct-accent-rgb), 0.45);
    cursor: pointer;
    z-index: 500;
    transition: background-color 0.2s ease, box-shadow 0.2s ease, transform 0.2s ease;
}

.supportFabButton:hover {
    background-color: var(--acct-accent-dark);
    box-shadow: 0 14px 32px rgba(var(--acct-accent-rgb), 0.55);
    transform: translateY(-2px);
}

.supportFabButton svg {
    width: 28px;
    height: 28px;
}

.supportOptionList {
    display: flex;
    flex-direction: column;
    width: 100%;
    gap: 10px;
}

.supportOptionRow {
    display: flex;
    flex-direction: row;
    align-items: center;
    gap: 14px;
    width: 100%;
    box-sizing: border-box;
    padding: 12px 16px;
    text-align: left;
    text-decoration: none;
    color: var(--acct-text-primary);
    background: rgba(255, 255, 255, 0.6);
    border: 1px solid var(--acct-border);
    border-radius: var(--acct-radius-md);
    font-family: inherit;
    font-size: 1em;
    cursor: pointer;
    transition: background-color 0.15s ease, box-shadow 0.15s ease, transform 0.15s ease;
}

.supportOptionRow:hover {
    background: rgba(255, 255, 255, 0.92);
    box-shadow: 0 6px 16px rgba(10, 7, 4, 0.1);
    transform: translateY(-1px);
}

.supportOptionIcon {
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    width: 38px;
    height: 38px;
    color: var(--acct-accent-dark);
    background: rgba(var(--acct-accent-rgb), 0.12);
    border-radius: 50%;
}

.supportOptionIcon svg {
    width: 19px;
    height: 19px;
}

.supportOptionText {
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.supportOptionTitle {
    font-weight: 600;
}

.supportOptionSubtitle {
    font-size: 0.85em;
    color: var(--acct-text-secondary);
}

/* #checkoutForm is a block-level flex item inside .baseScreen's align-items:center, which sizes it via
   fit-content instead of stretching it - and a flex-wrap:wrap row's (.productPickerRow) max-content contribution
   to that calculation comes out far narrower than the available space, so without an explicit width the whole
   form (and the custom select inside it) collapsed to a fraction of the card's width. Same shrink-to-fit class
   of bug as .blurb/.creditGrid/.historyList elsewhere in this file - a real width fixes it the same way. */
#checkoutForm {
    width: 100%;
    box-sizing: border-box;
}

/* Form controls (the "Add Location/Schedule" modal, the Purchase tab's product picker) were plain unstyled browser
   defaults. fieldset/legend/select/input[type=text] are exclusive to account.html so are safe to style directly;
   bare "label" is also used by deleteaccount.html, so its rule is scoped under .acctTheme further down. */
fieldset {
    border: 1px solid var(--acct-border);
    border-radius: var(--acct-radius-md);
    padding: 14px 18px 18px 18px;
    margin: 0 0 14px 0;
}

legend {
    padding: 0 6px;
    font-weight: 700;
    color: var(--acct-text-primary);
}

input[type="text"], input[type="email"], select {
    box-sizing: border-box;
    padding: 8px 10px;
    font-size: 0.95em;
    font-family: inherit;
    color: var(--acct-text-primary);
    background: #ffffff;
    border: 1px solid #d8cfc2;
    border-radius: var(--acct-radius-sm);
    transition: border-color 0.15s ease, box-shadow 0.15s ease;
}

input[type="text"], input[type="email"] {
    width: 100%; /* stacked full-width under their own <label> in the Schedule modal - select stays content-sized
                    (the Purchase tab's #product picker doesn't want to stretch to the full card width) */
}

/* Address form (Add Location/Schedule modal): a 12-column grid so related fields share one row like a typical
   address form (name on its own line; address line 1+2 together; city/state/zip/country together) instead of
   one full-width field per line, which was both needlessly tall and why the modal ran off the bottom of the
   screen - see #myModal .modalBox and .modalBox's max-height/overflow-y below for the other half of that fix. */
.addressFieldset {
    display: grid;
    grid-template-columns: repeat(12, 1fr);
    gap: 2px 16px;
}

.addressFieldset legend {
    grid-column: 1 / -1;
}

.formField {
    display: flex;
    flex-direction: column;
    min-width: 0; /* lets the grid track (not the field's own content) determine its width, same shrink-to-fit
                     issue documented elsewhere in this file for flex/grid children */
}

.formFieldFull {
    grid-column: span 12;
}

.formFieldSpan7 {
    grid-column: span 7;
}

.formFieldSpan5 {
    grid-column: span 5;
}

.formFieldSpan4 {
    grid-column: span 4;
}

.formFieldSpan3 {
    grid-column: span 3;
}

.formFieldSpan2 {
    grid-column: span 2;
}

input[type="text"]:focus, input[type="email"]:focus, select:focus {
    outline: none;
    border-color: var(--acct-accent);
    box-shadow: 0 0 0 3px rgba(var(--acct-accent-rgb), 0.18);
}

/* Custom-styled dropdown for the Purchase tab's product picker (see account.html's #productCustomSelect):
   a native <select>'s OPEN option-list panel is OS-native chrome that CSS can't restyle in any browser, so the
   only way to make it "look modern" instead of the default browser popup is to replace it with a themed
   trigger button + an absolutely-positioned panel built from the (visually hidden but still form-submitting)
   real <select>'s own options. */
.customSelect {
    position: relative;
    display: inline-block;
    width: 100%;
    max-width: 560px; /* wide enough for the longest optgroup label ("Self-Hosted Trivia Subscription (1 session
                         per week)") to fit on one line on desktop, instead of wrapping */
    flex: 1 1 260px;
}

.customSelectTrigger {
    display: flex;
    align-items: center;
    justify-content: space-between;
    width: 100%;
    box-sizing: border-box;
    padding: 10px 14px;
    font-size: 0.95em;
    font-family: inherit;
    text-align: left;
    color: var(--acct-text-primary);
    background: #ffffff;
    border: 1px solid #d8cfc2;
    border-radius: var(--acct-radius-sm);
    cursor: pointer;
    transition: border-color 0.15s ease, box-shadow 0.15s ease;
}

.customSelectTrigger:hover {
    border-color: var(--acct-accent);
}

.customSelect.open .customSelectTrigger {
    outline: none;
    border-color: var(--acct-accent);
    box-shadow: 0 0 0 3px rgba(var(--acct-accent-rgb), 0.18);
}

.customSelectArrow {
    margin-left: 10px;
    font-size: 11px;
    color: var(--acct-text-secondary);
    transition: transform 0.15s ease;
}

.customSelect.open .customSelectArrow {
    transform: rotate(180deg);
}

.customSelectPanel {
    display: none;
    position: absolute;
    left: 0;
    right: 0;
    top: calc(100% + 6px);
    z-index: 1200; /* once open, JS detaches this to be a direct child of <body> (see account.html) so it can
                       escape .baseScreen's scroll clipping and .baseFrame's backdrop-filter containing block -
                       that also means it now competes directly with .tabBar (1000) / .hamburgerButton (1001) in
                       the root stacking context instead of being trapped under .baseFrame's own local one, so it
                       needs a z-index comfortably above those rather than the old low value that only worked by
                       virtue of being nested inside .baseFrame the whole time */
    max-height: 280px;
    overflow-y: auto;
    background: #fffdf9;
    border: 1px solid var(--acct-border);
    border-radius: var(--acct-radius-md);
    box-shadow: var(--acct-shadow-modal);
    padding: 6px;
    box-sizing: border-box;
}

.customSelect.open .customSelectPanel {
    display: block;
}

.customSelectGroupLabel {
    padding: 8px 10px 4px 10px;
    font-size: 0.85em;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.4px;
    color: var(--acct-text-primary);
    white-space: nowrap; /* the wider .customSelect above gives this room to fit on one line on desktop */
}

.customSelectOption {
    padding: 9px 10px 9px 20px; /* extra left padding (vs the group label's 10px) visually nests options a
                                    level under their group label */
    border-radius: var(--acct-radius-sm);
    font-size: 0.92em;
    color: var(--acct-text-primary);
    cursor: pointer;
}

.customSelectOption:hover {
    background: rgba(var(--acct-accent-rgb), 0.1);
}

.customSelectOption.selected {
    background: rgba(var(--acct-accent-rgb), 0.16);
    font-weight: 600;
    color: var(--acct-accent-dark);
}

/* Purchase tab: dropdown + quantity sit side by side, with a swappable product preview image between the
   picker row and the Checkout button (see account.html's #productImagePreviewImg / productImagesByValue). */
.productPickerRow {
    display: flex;
    flex-direction: row;
    align-items: center;
    justify-content: center; /* centers the dropdown+qty cluster within the row - the row itself is full-width
                                 (see width:100% below), so without this the cluster just hugs the left edge */
    gap: 16px;
    flex-wrap: wrap;
    width: 100%;
    box-sizing: border-box;
    margin: 1em 0; /* a <div> (needed so the customSelect <div> inside it is valid HTML - a <p> auto-closes
                       before any block child, which silently breaks it out of the flex layout entirely) doesn't
                       get a <p>'s default vertical margin, so it's set explicitly here to match the spacing of
                       the other <p>-based rows in this form */
}

.quantityField {
    display: flex;
    flex-direction: row; /* "Qty:" label sits beside its spinner, not stacked above it, so the whole cluster
                             stays on the same row as the dropdown instead of being taller than it and wrapping */
    align-items: center;
    gap: 8px;
}

.acctTheme .quantityField label {
    /* .acctTheme label (further down this file) is the same specificity as a plain ".quantityField label" -
       this compound selector guarantees it wins regardless of source order, matching this file's established
       .acctTheme-scoping convention for overriding shared/general rules. */
    margin: 0;
}

.quantityField input {
    width: 90px;
    box-sizing: border-box;
    padding: 10px 10px;
    font-size: 0.95em;
    font-family: inherit;
    color: var(--acct-text-primary);
    background: #ffffff;
    border: 1px solid #d8cfc2;
    border-radius: var(--acct-radius-sm);
    transition: border-color 0.15s ease, box-shadow 0.15s ease;
}

.quantityField input:focus {
    outline: none;
    border-color: var(--acct-accent);
    box-shadow: 0 0 0 3px rgba(var(--acct-accent-rgb), 0.18);
}

.productImagePreview {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 10px;
    width: 100%;
    max-width: 320px;
    padding: 16px;
    margin: 6px auto 18px auto; /* centers it - it's a block child of #checkoutForm (not a flex item of
                                    .baseScreen, which is where the page's other centering comes from), so it
                                    needs its own auto side-margins rather than hugging the left edge */
    background: #ffffff;
    border: 1px solid var(--acct-border);
    border-radius: var(--acct-radius-md);
    box-sizing: border-box;
}

.productImagePreviewLabel {
    font-weight: 600;
    font-size: 0.95em;
    text-align: center;
    color: var(--acct-text-primary);
}

.productImagePreview img {
    max-width: 100%;
    height: auto;
}

.visuallyHiddenSelect {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}


/* Keyframes are like Tweens in Flutter - basically points along an animation curve */
@keyframes fadeIn {
    from {
        opacity: 0;
    }
    to {
        opacity: 1;
    }
}


@media screen and (max-width: 800px) {
    body {
        justify-content: flex-start; /* so .baseFrame's margin-top/height below control its position exactly, instead of being recentered around them */
        /* Needs to stay a DEFINITE height (not "auto" + min-height) - flex-grow/shrink below can only actually
           compute against a definite container size; with an auto height, the browser just grows body to fit
           content instead of shrinking .baseFrame to fit body, which was the whole point and exactly why the
           page grew a scrollbar of its own even after switching .baseFrame/.footer to flex-grow/normal flow. */
        height: 100vh; /* vh fallback for browsers without dvh support */
        height: 100dvh; /* mobile browsers show/hide their address bar chrome, which changes how much of 100vh is
                            actually visible on screen - 100dvh (dynamic viewport height) tracks the real visible
                            area instead, which a fixed-pixel calc() below could never account for consistently
                            across devices */
    }

    .baseFrame {
        width: 90%;
        flex: 1 1 auto; /* was an explicit height: calc(100vh - 70px - 130px) - a brittle guess at exactly how
                            tall the footer below it would render, which was wrong on some devices (footer
                            overlapping the panel) and left a leftover page-level scrollbar on others. Growing to
                            fill whatever space is actually left in the body's flex column - after the fixed
                            margin-top below and the footer's own real height further down - fits correctly
                            regardless of device/footer content, with no magic numbers to keep in sync. */
        min-height: 0; /* lets this actually shrink to fit within the flex column instead of forcing the whole
                          page taller - .baseScreen still scrolls internally for its own content as before */
        margin-top: 70px; /* clears the fixed hamburger button with a little breathing room */
    }

    .footer {
        /* Every current template actually carries the "acctTheme" class too (directly, or via "acctThemeSolo"),
           and its own unconditional (non-media-gated) ".acctTheme .footer" rule sets "margin: 0" at the same
           2-class specificity as a ".acctTheme .footer" override would need here - on a specificity tie, source
           order decides, and that unconditional rule sits LATER in the file than this media block, so it would
           keep winning regardless of what's written here. See the acctTheme-specific mobile block further down
           (after that base rule, in its own "@media (max-width:800px)") for the actual position/margin override -
           this plain, lower-specificity rule only still matters for a hypothetical template with no acctTheme
           class at all. */
        position: static;
        flex-shrink: 0;
    }

    .hamburgerButton {
        display: flex;
    }

    .mobileBrandBanner {
        /* Plain text, like the footer - no glass pill/box. Vertical centering matches .hamburgerButton exactly
           (same "top: 2%" + same explicit "height: 40px"); horizontally it's centered within left:70px..right:3%,
           i.e. the space between the hamburger button and the right margin. A text-shadow (rather than a
           background) keeps it legible over whatever part of the beach.jpg photo happens to be behind it, same
           reasoning as .acctTheme .footer. */
        display: flex;
        align-items: center;
        justify-content: center;
        position: fixed;
        top: 2%;
        left: 70px; /* right after the hamburger button + a gap */
        right: 3%; /* mirrors the hamburger's own left:3%, so both ends read as intentional matching margins */
        height: 40px;
        box-sizing: border-box;
        z-index: 500; /* below .tabBarOverlay (999) and the open .tabBar (1000), unlike the hamburger button -
                          when the menu slides out, the banner should get dimmed by the overlay along with the
                          rest of the page (and be covered by the drawer itself where they overlap) instead of
                          staying bright on top of everything */
        font-size: 19px;
        font-weight: 700;
        letter-spacing: 0.5px;
        color: var(--acct-text-primary);
        text-shadow: 0 1px 3px rgba(255, 250, 240, 0.7), 0 1px 8px rgba(60, 50, 30, 0.25);
        background: none;
        border: none;
        border-radius: 0;
        box-shadow: none;
    }

    #softwareTabButton {
        display: none; /* downloading a Windows installer doesn't make sense on a phone */
    }

    .tabBar {
        position: fixed;
        top: 0;
        left: -75%;
        width: 65%;
        max-width: 280px;
        height: 100%;
        flex-direction: column;
        justify-content: flex-start;
        align-items: stretch;
        gap: 2px;
        padding: 15% 3% 3% 3%;
        background: var(--acct-glass-bg);
        backdrop-filter: blur(26px) saturate(180%);
        -webkit-backdrop-filter: blur(26px) saturate(180%);
        box-shadow: var(--acct-shadow);
        border: none;
        border-radius: 0;
        box-sizing: border-box;
        overflow-y: auto;
        z-index: 1000;
        transition: left 0.3s ease;
    }

    .tabBar.open {
        left: 0;
    }

    .tabBarButton {
        justify-content: flex-start;
        width: 100%;
        height: auto;
        padding: 12px 10px;
        box-shadow: none;
        border: none;
        border-left: 3px solid transparent;
        border-bottom: 1px solid var(--acct-border);
        border-radius: 0;
        font-size: 2.2vh;
    }

    .tabBarButtonActive {
        border-left-color: var(--acct-accent);
    }

    #logoutTabButton {
        margin-top: 0; /* the mobile drawer lists every tab in one flat scrollable column - no bottom-pinning */
        border-top: none;
        padding-top: 12px;
    }

    .acctSidebarBrand {
        display: block; /* hidden in the desktop collapsed icon rail (no room) - the mobile drawer has plenty of
                            width, so it doubles as the drawer's own header here */
    }

    .tabBarIcon {
        margin-right: 12px; /* desktop's collapsed rail has no visible label to space out from (margin-right:0) -
                                the mobile drawer shows icon+label again, so it needs the gap back */
    }

    .creditGrid {
        gap: 16px;
    }

    .creditGridItem {
        flex: 0 0 100%; /* one credit per row - a 3-5 column grid doesn't fit a phone screen */
        height: 64px; /* a bit taller than desktop's 34px - the larger font-size below needs the extra room */
    }

    .creditCodeWrap {
        height: 40px;
    }

    .creditCodePasswordBox {
        font-size: 1.15em;
    }

    .historyRow {
        flex-direction: column; /* badge+timestamp+description+button don't all fit on one line on a phone screen */
        align-items: stretch;
        gap: 6px;
    }

    .historyDescription {
        white-space: normal; /* full text wraps normally again now that each field has its own line to itself */
        overflow: visible;
        text-overflow: clip;
    }

    .pillButtonLink {
        align-self: flex-start;
        margin-top: 6px;
    }

    .modalBox {
        width: 90%; /* 50% of a phone screen is too cramped for the session-results modal's team name + points rows */
    }

    #myModal .modalBox {
        width: 90%; /* overrides the wider desktop-only address-form sizing below */
    }

    .customSelectGroupLabel {
        white-space: normal; /* desktop's one-line nowrap doesn't fit a phone-width panel */
    }

    .productPickerRow {
        flex-direction: column;
        align-items: stretch;
    }

    .customSelect {
        /* flex-basis sets HEIGHT (not width) once the row above switches to flex-direction:column - the
           desktop-only "flex: 1 1 260px" was reserving ~260px of vertical space regardless of the trigger's real
           ~42px height, leaving a large empty gap before .quantityField, and pushing .customSelectPanel (whose
           "top: calc(100% + 6px)" is relative to that inflated height) down far enough to run off small screens. */
        flex: none;
        max-width: none;
    }

    .quantityField input {
        width: 100%;
    }

    .formFieldFull, .formFieldSpan7, .formFieldSpan5, .formFieldSpan4, .formFieldSpan3, .formFieldSpan2 {
        grid-column: span 12; /* one field per line - a phone screen can't fit 2-4 address fields side by side */
    }
}


.rowContainer {
    max-width: 30%;
    min-height: 20%;
    /*position: relative;*/
    margin: 25px auto auto;
    box-sizing: border-box;
    padding: 15px;
    background-color: white;
    box-shadow: var(--box-shadow2);
    border-radius: 7px;
}

.qrImage {
    width: 200px;
    max-width: 100%; /* belt-and-suspenders in case the mobile override below is ever missed */
    height: auto;
}


/* Slideshow container */
/* https://www.w3schools.com/howto/howto_js_slideshow.asp */
.slideshow-container {
    max-width: 40%;
    position: relative;
    margin: 25px auto auto;
    box-sizing: border-box;
    padding: 15px;
    background-color: white;
    box-shadow: var(--box-shadow2);
    border-radius: 7px;
}

/* Hide the images by default */
.mySlides {
    display: none;
    box-sizing: border-box;
}

/* Next & previous buttons */
.prev, .next {
    cursor: pointer;
    position: absolute;
    top: 50%;
    width: auto;
    margin-top: -22px;
    padding: 16px;
    color: white;
    font-weight: bold;
    font-size: 18px;
    transition: 0.6s ease;
    border-radius: 0 3px 3px 0;
    user-select: none;
    box-sizing: border-box;
}

/* Position the "next button" to the right */
.next {
    right: 0;
    border-radius: 3px 0 0 3px;
    box-sizing: border-box;
}
/*
.prev {
    left: 0;
    border-radius: 3px 0 0 3px;
    box-sizing: border-box;
}*/

/* On hover, add a black background color with a little bit see-through */
.prev:hover, .next:hover {
    background-color: rgba(0, 0, 0, 0.8);
    box-sizing: border-box;
}

/* The dots/bullets/indicators */
.dot {
    cursor: pointer;
    height: 15px;
    width: 15px;
    margin-top: -50px;
    background-color: #999;
    border-radius: 50%;
    display: inline-block;
    transition: background-color 0.6s ease;
    box-sizing: border-box;
}

.activeSlide, .dot:hover {
    background-color: #414141;
    box-sizing: border-box;
}

/* Fading animation */
.fade {
    animation-name: fade;
    animation-duration: 1.5s;
}

@keyframes fade {
    from {
        opacity: .4
    }
    to {
        opacity: 1
    }
}




/* FAQ */
.faqQuestion {
    background: rgba(255, 255, 255, 0.75);
    color: var(--acct-text-primary);
    cursor: pointer;
    padding: 16px 28px 16px 28px;
    width: 90%;
    text-align: left;
    border: 1px solid var(--acct-border);
    border-radius: var(--acct-radius-sm);
    outline: none;
    transition: background-color 0.25s ease, box-shadow 0.25s ease;
    margin: 6px 0 3px 0;
    box-shadow: 0 2px 8px rgba(10, 7, 4, 0.08);
}

.faqQuestion:hover {
    background-color: rgba(255, 255, 255, 0.92);
}

/* .faqQuestion.faqActive (2 classes) rather than plain .faqActive (1 class): .faqQuestion:hover above is also
   2 classes/pseudo-classes, i.e. equal specificity, so a lone .faqActive rule lost that tie to :hover any time
   the cursor was still over the button right after a click - :hover's near-white background kept showing while
   .faqActive's color:white already applied, making the text invisible until the mouse moved off. Matching
   specificity here (and staying after :hover in source order) lets the active teal background win instead. */
.faqQuestion.faqActive {
    background-color: var(--acct-accent);
    color: white;
    border-color: var(--acct-accent);
    box-shadow: 0 8px 20px rgba(var(--acct-accent-rgb), 0.35);
    border-radius: var(--acct-radius-sm) var(--acct-radius-sm) 0 0;
}

.faqQuestion.faqActive:hover {
    background-color: var(--acct-accent-dark);
}

.faqQuestion:after {
    content: '\025B6'; /* Unicode character for right arrow */
    font-size: 11px;
    color: inherit;
    float: left;
    margin-top: 4px;
    margin-right: 20px;
}

.faqActive:after {
    content: "\025BC"; /* Unicode character for down arrow  */
}

.faqAnswer {
    box-sizing: border-box;
    padding: 0 26px 0 26px;
    background: rgba(255, 255, 255, 0.6);
    max-height: 0;
    width: 90%;
    border-radius: 0 0 var(--acct-radius-sm) var(--acct-radius-sm);
    overflow: hidden; /* change via JS to show one */
    transition: max-height 0.2s ease-out;
}


/* home.html mobile overrides - deliberately placed after the .flexRowBase/.rowContainer/.slideshow-container/
   .qrImage/.loginButton base rules above (rather than in the earlier @media block near the top of this file):
   with equal specificity, source order decides ties, so a mobile override placed BEFORE its own base rule loses
   the cascade the moment the base rule is unconditional (not itself inside a competing media query). */
@media screen and (max-width: 800px) {
    /* the iOS QR / Play Store QR / slideshow columns don't fit side-by-side on a phone screen */
    .flexRowBase {
        flex-direction: column;
    }

    .flexColumnBase {
        width: 100%; /* same shrink-to-fit issue: .slideshow-container's own 90% below needs a real width to resolve against */
    }

    .rowContainer, .slideshow-container {
        max-width: 90%;
        width: 90%;
    }

    .qrImage {
        width: 150px;
    }

    .loginButton {
        width: 70%;
    }
}


/* ============================================================================
   ACCOUNT PAGE THEME TOKENS + SHARED-CLASS OVERRIDES
   account.html's <body> carries class="acctTheme" (nothing else does). A few of
   its elements reuse classes that OTHER templates also use with a different,
   already-established look (baseFrame/baseScreen/blurb/footer/footerContent/
   baseButton/errorBanner/historyRow/pillButtonLink/label) - rather than edit
   those shared rules in place and risk changing home.html/privacy.html/
   deleteaccount.html/confirmDeletion.html/sessionResults.html too, every override
   here is written as ".acctTheme <selector>", a strictly higher-specificity
   compound selector that only ever matches inside account.html's own DOM. Custom
   properties (--acct-*) are declared once on body.acctTheme and inherited by
   everything beneath it - including the plain (unscoped, account-exclusive)
   rules edited in place further up this file, since inheritance follows the DOM,
   not the selector text. */
body.acctTheme {
    background: url(../images/beach.jpg) no-repeat center center fixed;
    -webkit-background-size: cover;
    -moz-background-size: cover;
    -o-background-size: cover;
    background-size: cover;
    flex-direction: row; /* sidebar (.tabBar) + whichever tab's .baseFrame is visible, side by side - see the
                            @media override earlier in this file, which reverts this to column on mobile */
    gap: 0; /* the sidebar and the active page now sit flush against each other, reading as one merged panel -
               see .tabBar/.acctTheme .baseFrame's matching one-sided border-radius + divider border below */
    align-items: flex-start; /* was "center" (inherited from the base body rule) - that split the space above and
                                 below the panel evenly; decoupling it from the panel's own height (see
                                 padding-top below) lets the top gap shrink independently, while the freed space
                                 moves to the bottom where it's needed for the footer (see .acctTheme .footer) */
    padding-top: 4vh;
    box-sizing: border-box; /* keeps body's total height at exactly the base rule's 100vh - without this, the
                                padding-top above would add to it instead of eating into it, adding a few vh of
                                unwanted page scroll */

    /* Tropical teal, drawn from the ocean water in beach.jpg, with warm sand-toned neutrals for text/glass -
       replaces the "moonlight blue over a dark forest road" scheme from the road.jpg version. */
    --acct-accent-rgb: 13, 148, 136;
    --acct-accent: rgb(var(--acct-accent-rgb));
    --acct-accent-dark: #115e59;
    --acct-text-primary: #2e2a22;
    --acct-text-secondary: #6e6659;
    --acct-border: rgba(46, 42, 34, 0.14);
    --acct-glass-bg: rgba(255, 250, 240, 0.4); /* warm sandy-white glass, at the same ~40% opacity the road.jpg
                                                    version settled on */
    --acct-glass-border: rgba(255, 255, 255, 0.6);
    /* Much softer/warmer than the road.jpg version's shadow - that one was tuned for a dark photo where the glass
       panels needed a strong shadow to read as elevated; beach.jpg is bright, so a heavy dark shadow here would
       look out of place - a soft, warm-toned shadow is enough to lift the panels off the photo. */
    --acct-shadow: 0 20px 50px rgba(60, 50, 30, 0.18), 0 6px 18px rgba(60, 50, 30, 0.12);
    --acct-shadow-modal: 0 30px 80px rgba(40, 32, 15, 0.3), 0 10px 30px rgba(40, 32, 15, 0.18);
    --acct-radius-sm: 10px;
    --acct-radius-md: 16px;
    --acct-radius-lg: 24px;
}

.logoutRow {
    margin-top: 24px;
}

/* ============================================================================
   HOST PORTAL THEME TOKENS
   Host portal pages carry class="acctTheme acctThemeSolo hostTheme" - same glass-card mechanics as the customer
   portal above, just re-tinted warm amber/copper (drawn from host.jpg's brick/sandstone street scene) instead of
   teal, and relying on .acctThemeSolo's plain centered-card layout since the host portal has no sidebar (yet).
   Written as "body.acctTheme.hostTheme" (two classes), not just ".hostTheme", so it always wins over the plain
   body.acctTheme block above regardless of source order - both match body with a single class otherwise, which
   would make "whichever rule sets --acct-accent last" a coin-flip. */
body.acctTheme.hostTheme {
    background: url(../images/host.jpg) no-repeat center center fixed;
    -webkit-background-size: cover;
    -moz-background-size: cover;
    -o-background-size: cover;
    background-size: cover;

    --acct-accent-rgb: 176, 106, 53;
    --acct-accent: rgb(var(--acct-accent-rgb));
    --acct-accent-dark: #7a4520;
    --acct-text-primary: #2e2a22;
    --acct-text-secondary: #6e6659;
    --acct-border: rgba(46, 42, 34, 0.14);
    --acct-glass-bg: rgba(255, 247, 235, 0.45);
    --acct-glass-border: rgba(255, 255, 255, 0.6);
    --acct-shadow: 0 20px 50px rgba(60, 40, 20, 0.2), 0 6px 18px rgba(60, 40, 20, 0.14);
    --acct-shadow-modal: 0 30px 80px rgba(45, 28, 10, 0.32), 0 10px 30px rgba(45, 28, 10, 0.2);
    --acct-radius-sm: 10px;
    --acct-radius-md: 16px;
    --acct-radius-lg: 24px;
}

.acctTheme .baseFrame {
    flex: 1 1 auto; /* fills the remaining width beside the sidebar */
    width: auto; /* overrides the shared .baseFrame rule's width:88% - flex-basis:auto (from "1 1 auto" above) would
                    otherwise resolve against that inherited 88% instead of sizing purely from flex-grow/max-width */
    max-width: 1064px; /* 40% wider than the original 760px cap */
    height: calc(96vh - 51px); /* body.acctTheme's padding-top:4vh already accounts for the top gap, leaving 96vh
                                   of remaining height below it - this fills nearly all of that, reserving only
                                   51px at the bottom for a MINIMAL footer zone (roughly a 10px gap + the footer's
                                   own ~31px height + another 10px gap - see .acctTheme .footer's "bottom" below),
                                   rather than the previous fixed 82vh, which left a large, un-shrinking gap around
                                   the footer regardless of how much room the top-gap change freed up */
    align-items: stretch;
    justify-content: flex-start;
    background: var(--acct-glass-bg);
    backdrop-filter: blur(26px) saturate(180%);
    -webkit-backdrop-filter: blur(26px) saturate(180%);
    border: 1px solid var(--acct-glass-border);
    border-left: 1px solid var(--acct-border); /* the sidebar's own border-right is removed instead (see .tabBar) -
                                                   this one line is the divider between rail and page, avoiding a
                                                   doubled-thickness seam where the two elements meet */
    border-radius: 0 var(--acct-radius-lg) var(--acct-radius-lg) 0; /* rounded only on the outer (right) corners,
                                                                        matching .tabBar's mirrored radius so the
                                                                        pair reads as one continuous panel */
    box-shadow: var(--acct-shadow);
    padding: 28px 34px;
    box-sizing: border-box;
}

.acctTheme .baseScreen {
    background: transparent; /* .baseFrame above is now the visible glass card - this is just its scrollable
                                 inner content area, not a second layer of glass stacked on top */
    border: none;
    box-shadow: none;
    width: 100%;
    height: 100%;
    padding: 0;
    border-radius: 0;
}

/* Chromium/Safari's default scrollbar (thin scrollbar-width above only affects Firefox) renders a solid,
   square-edged gray track flush against whatever content is scrolling - next to rounded cards like .historyRow
   that reads as an oddly "darkened, squared-off container" around otherwise rounded content. A themed, rounded,
   translucent thumb on a transparent track blends into the glass panel instead. Shared with .modalBox (below) so
   every modal dialog scrolls the same way as the main panel, instead of each one falling back to its own browser
   default. */
.acctTheme .baseScreen::-webkit-scrollbar, .modalBox::-webkit-scrollbar {
    width: 8px;
}

.acctTheme .baseScreen::-webkit-scrollbar-track, .modalBox::-webkit-scrollbar-track {
    background: transparent;
}

.acctTheme .baseScreen::-webkit-scrollbar-thumb, .modalBox::-webkit-scrollbar-thumb {
    background-color: rgba(var(--acct-accent-rgb), 0.35);
    border-radius: 8px;
}

.acctTheme .baseScreen::-webkit-scrollbar-thumb:hover, .modalBox::-webkit-scrollbar-thumb:hover {
    background-color: rgba(var(--acct-accent-rgb), 0.5);
}

.acctTheme .blurb {
    /* Flex items are blockified regardless of the <span>'s own inline display, so max-width DOES apply here -
       the original 62ch cap (~550-620px) inside a card that's up to ~996px wide was leaving ~20% empty margin
       on EACH side (on top of the 4% padding below), reading as a ~40-45% total margin instead of a deliberate
       reading-width constraint. Letting it fill the card (minus the 6% side padding below) reads as intentional
       10-15% margins instead. */
    max-width: 100%;
    width: 100%;
    box-sizing: border-box;
    padding: 0 6%;
    margin-bottom: 24px; /* a flex item's margin is never collapsed with the next sibling's (unlike normal block
                             flow), so this reliably puts the same gap under the blurb on every tab regardless of
                             what follows - some tabs' own blurb-adjacent element (fieldset, .faqQuestion, etc.)
                             also carries its own small margin/padding on top of this, which is fine */
    line-height: 1.6;
    color: var(--acct-text-secondary);
}

.acctTheme .footer {
    /* Just a single line of plain text sitting directly on the beach.jpg background - no glass pill/box, unlike
       the shared .footer rule's look on other pages. A soft text-shadow (rather than a background) keeps it
       readable regardless of what part of the photo happens to be behind it. */
    /* Desktop only (see the @media override below for mobile, which resets this to flush "bottom:0" the way it
       always was): .acctTheme .baseFrame's height already reserves just enough room below it for this minimal
       10px gap + the footer's own ~31px height + another 10px gap before the viewport edge - lifting it off the
       edge by that same 10px keeps the space above and below the footer itself small and roughly equal, instead
       of using up whatever much larger gap happens to be left over below the panel. */
    bottom: 10px;
    left: 0;
    right: 0;
    width: auto;
    margin: 0;
    padding: 8px 0;
    font-size: 0.8em;
    color: var(--acct-text-primary);
    text-shadow: 0 1px 3px rgba(255, 250, 240, 0.7), 0 1px 8px rgba(60, 50, 30, 0.25);
    background: none;
    border: none;
    border-radius: 0;
    box-shadow: none;
}

.acctTheme .baseButton {
    height: auto;
    padding: 13px 0;
    background: var(--acct-accent);
    border-radius: var(--acct-radius-md); /* was "0 0 6px 6px" (flat top, rounded bottom only) - looked unintentional */
    font-weight: 600;
    letter-spacing: 0.4px;
    box-shadow: 0 8px 20px rgba(var(--acct-accent-rgb), 0.35);
    transition: background-color 0.2s ease, box-shadow 0.2s ease, transform 0.2s ease;
}

.acctTheme .baseButton:hover {
    background-color: var(--acct-accent-dark);
    box-shadow: 0 10px 24px rgba(var(--acct-accent-rgb), 0.45);
    transform: translateY(-1px);
}

.acctTheme .baseButton:active {
    background-color: var(--acct-accent-dark);
    box-shadow: 0 4px 10px rgba(var(--acct-accent-rgb), 0.4);
    transform: translateY(0);
}

/* Logout modal's "Cancel" button - an outline twin of .baseButton. Needs the extra .baseButton compound
   (not just .secondaryButton alone) to out-specificity .acctTheme .baseButton:hover/:active above, since a
   plain .secondaryButton:hover would otherwise lose that tie to the filled-button hover styles. */
.acctTheme .baseButton.secondaryButton {
    background: transparent;
    color: var(--acct-accent-dark);
    box-shadow: none;
    border: 1px solid var(--acct-border);
}

.acctTheme .baseButton.secondaryButton:hover {
    background-color: rgba(var(--acct-accent-rgb), 0.08);
    box-shadow: none;
    transform: none;
}

.acctTheme .baseButton.secondaryButton:active {
    background-color: rgba(var(--acct-accent-rgb), 0.14);
    box-shadow: none;
    transform: none;
}

.acctTheme .errorBanner {
    border-radius: var(--acct-radius-sm);
}

.acctTheme .historyRow {
    background: rgba(255, 255, 255, 0.78);
    border: 1px solid var(--acct-border);
    border-radius: var(--acct-radius-md);
    box-shadow: 0 10px 26px rgba(10, 7, 4, 0.14);
    transition: box-shadow 0.2s ease, transform 0.2s ease;
}

.acctTheme .historyRow:hover {
    box-shadow: 0 16px 36px rgba(10, 7, 4, 0.2);
    transform: translateY(-1px);
}

.acctTheme .pillButtonLink {
    background-color: var(--acct-accent);
    box-shadow: 0 4px 12px rgba(var(--acct-accent-rgb), 0.35);
    transition: background-color 0.2s ease, box-shadow 0.2s ease, transform 0.2s ease;
}

.acctTheme .pillButtonLink:hover {
    background-color: var(--acct-accent-dark);
    box-shadow: 0 6px 16px rgba(var(--acct-accent-rgb), 0.45);
    transform: translateY(-1px);
}

.acctTheme label {
    display: block;
    margin: 10px 0 4px 0;
    font-size: 0.9em;
    color: var(--acct-text-secondary);
}

@media screen and (max-width: 800px) {
    body.acctTheme {
        flex-direction: column; /* undoes the desktop sidebar+content row layout above - back to a single
                                    full-width page, with .tabBar becoming the off-canvas drawer instead of a
                                    permanent sidebar. Must live in THIS media block (after the desktop
                                    body.acctTheme rule in source order) rather than the earlier one near the top
                                    of the file - same specificity (0,1,1) either way, so source order decides,
                                    and a mobile override placed before its own base rule loses the cascade even
                                    while its media condition matches (see the .flexRowBase/.historyRow comments
                                    elsewhere in this file for the same lesson learned the hard way). */
        align-items: center; /* was "stretch" - with .baseFrame's own explicit width:90% (less than the container),
                                 "stretch" resolves to flex-start instead of centering the item, which pinned the
                                 panel flush against the left edge (all 10% of the leftover space landing on the
                                 right instead of being split evenly) */
        padding-top: 0;
    }

    .acctTheme .baseFrame {
        flex: 1 1 auto; /* was an explicit height calc() reserving a fixed number of pixels for the footer below -
                            see the generic .baseFrame mobile rule above for why that was replaced with flex-grow
                            instead (same reasoning applies here) */
        min-height: 0;
        max-width: none;
        width: 90%;
        margin-top: 70px;
        padding: 20px 16px;
        border-left: 1px solid var(--acct-glass-border); /* back to a normal border on all sides - the sidebar
                                                              is an overlay drawer on mobile, not an adjacent
                                                              panel, so there's no seam to divide */
        border-radius: var(--acct-radius-lg); /* all four corners again, instead of desktop's right-side-only
                                                   radius (which assumed the collapsed rail sitting flush to its left) */
    }

    .acctTheme .historyRow {
        flex-direction: column;
        align-items: stretch;
        gap: 6px;
    }

    .acctTheme .pillButtonLink {
        align-self: flex-start;
        margin-top: 6px;
    }

    .acctTheme .footer {
        position: static; /* was absolute, anchored to the bottom of the (variable-height) document - see the
                              plain ".footer" mobile rule above for why this override has to live down here
                              instead, and .acctTheme .baseFrame above for the flex-grow that makes this necessary:
                              as a normal flex item right after .baseFrame, the footer now always sits exactly one
                              small gap below the panel, whatever the actual rendered heights turn out to be,
                              rather than both being independently positioned via guessed pixel math that could
                              (and did) end up overlapping or leaving a large gap depending on the device. */
        bottom: auto;
        flex-shrink: 0;
        margin: 8px 0;
    }
}


/* ============================================================================
   SOLO PAGES (home.html, privacy.html, deleteaccount.html, confirmDeletion.html,
   sessionResults.html) - simple single-card pages, reskinned to the same
   acctTheme beach/glass/teal look as account.html (body carries both
   class="acctTheme acctThemeSolo"), reusing all of acctTheme's tokens and
   shared-class overrides (.blurb/.footer/.baseButton/.errorBanner/.historyRow/
   .pillButtonLink/label) as-is. The plain .acctTheme rules above assume a
   .tabBar sidebar sits flush to .baseFrame's left (asymmetric border-radius,
   a border-left divider instead of a full border, a height formula reserving
   space next to the sidebar) - none of that applies to a page with no sidebar,
   so this modifier resets just those layout specifics back to a plain,
   fully-rounded, centered card. Two classes on <body> (0,0,2,0) naturally
   outrank the single-class-plus-element ".acctTheme .baseFrame" selectors
   (0,0,1,1) regardless of source order, so this can safely sit at the very end
   of the file. */
.acctThemeSolo.acctTheme {
    justify-content: center;
    align-items: center;
    padding-top: 0;
}

.acctThemeSolo .baseFrame {
    max-width: 820px;
    border: 1px solid var(--acct-glass-border);
    border-radius: var(--acct-radius-lg);
}

/* deleteaccount.html/confirmDeletion.html use plain <input type="submit"> (unlike account.html/home.html's own
   <button class="baseButton">), so they'd otherwise stay unstyled browser defaults sitting inside an
   otherwise fully-reskinned glass card - restyled to look like .baseButton without needing to touch their markup. */
.acctThemeSolo input[type="submit"] {
    display: block;
    height: auto;
    margin: 0 auto;
    padding: 13px 24px;
    background: var(--acct-accent);
    color: white;
    width: auto;
    min-width: 50%;
    font-size: 15px;
    font-family: inherit;
    border: 0;
    font-weight: 600;
    letter-spacing: 0.4px;
    cursor: pointer;
    border-radius: var(--acct-radius-md);
    box-shadow: 0 8px 20px rgba(var(--acct-accent-rgb), 0.35);
    transition: background-color 0.2s ease, box-shadow 0.2s ease, transform 0.2s ease;
}

.acctThemeSolo input[type="submit"]:hover {
    background-color: var(--acct-accent-dark);
    box-shadow: 0 10px 24px rgba(var(--acct-accent-rgb), 0.45);
    transform: translateY(-1px);
}

.acctThemeSolo input[type="submit"]:active {
    background-color: var(--acct-accent-dark);
    box-shadow: 0 4px 10px rgba(var(--acct-accent-rgb), 0.4);
    transform: translateY(0);
}

@media screen and (max-width: 800px) {
    .acctThemeSolo .baseFrame {
        margin-top: 20px; /* the plain .acctTheme mobile override's 70px clears a hamburger button that solo
                              pages don't have */
        /* height comes from the generic .baseFrame mobile rule's flex:1 1 auto/min-height:0 now (see there for
           why the previous explicit height calc() was replaced) - nothing solo-page-specific needed here beyond
           the smaller margin-top above. */
    }
}

/* mfa.html visually matching the real Keycloak login page's panel size/fonts - derived from the actual source
   values in AccountServer/themes/custom1/login/resources/css/styles.css and PatternFly's own login-container
   CSS variables, rather than a live "computed style" copy (nothing here can reach the real running Keycloak):
   the login card is a fixed 34rem (544px) wide (".pf-v5-c-login__container { grid-template-columns: 34rem; }"),
   its in-card heading uses "Red Hat Display" 700/30px (".red-hat-display-header"), and its body text uses
   "Red Hat Text" 400/18px (".red-hat-text-400-18") - both fonts imported in mfa.html's <head>. The glass
   card look itself (background/blur/border/radius) already matches exactly without any extra rules here, since
   both stylesheets were built from the same --acct-* token values. */
.mfaPage .baseFrame {
    max-width: 544px;
}

@media screen and (min-width: 801px) {
    /* Explicit fixed width (not just the max-width above) on desktop specifically: .acctTheme .baseFrame (which
       this page also matches, being both acctTheme and acctThemeSolo) sets "flex: 1 1 auto" for account.html's
       sidebar layout - harmless here since max-width still clamps the grown size, but a real Keycloak login card
       is a fixed 34rem via PatternFly's own grid-template-columns, not a stretchy item capped by a ceiling - this
       makes that explicit instead of relying on the grow+cap combination happening to land on the same number.
       Scoped to desktop only: mobile's own width:90% (see the .acctTheme/.acctThemeSolo mobile rules) needs to
       keep working unchanged on small screens. */
    .mfaPage .baseFrame {
        flex: none;
        width: 544px;
        /* .acctTheme .baseFrame (which this page also matches) sets a fixed "height: calc(96vh - 51px)" -
           account.html's sidebar layout wants its panel to fill nearly the full viewport height, but this page
           is just a short form and should pack to its own content height like the real Keycloak login card
           does, not stretch to match a completely unrelated page's height formula. */
        height: auto;
    }

    .mfaPage .baseScreen {
        /* .acctTheme .baseScreen sets "height: 100%" to fill that tall parent - with the parent now auto-height
           above, this is redundant (100% of an auto-sized parent has no effect) but explicit is clearer than
           relying on that fallback behavior. Its own overflow-y:auto is now moot too (nothing to internally
           scroll when both this and its parent size to content instead of a fixed viewport-relative height) -
           if this ever needs to scroll, the whole page scrolls instead, same as the real login page would. */
        height: auto;
    }
}

.mfaPage h3 {
    font-family: "Red Hat Display", sans-serif;
    font-weight: 700;
    font-size: 30px;
    color: #000000;
}

.mfaPage .blurb {
    font-family: "Red Hat Text", sans-serif;
    font-size: 18px;
    color: #000000;
}

.mfaPage label {
    color: #000000;
}

/* mfa.html's OTP entry boxes - this page is NOT rendered by Keycloak (see AuthHandler's /verifyOtp handling), it's
   a plain Javalin-served page reusing the same .acctThemeSolo look as the other standalone pages, so it no longer
   needs its own separate PatternFly-based stylesheet/framework just for this one input widget. */
.otpContainer {
    display: flex;
    gap: 10px;
    justify-content: center;
    margin: 10px 0;
}

.otpContainer input {
    width: 45px;
    height: 50px;
    box-sizing: border-box;
    font-size: 24px;
    font-family: inherit;
    text-align: center;
    color: var(--acct-text-primary);
    background: #ffffff;
    border: 1px solid #d8cfc2;
    border-radius: var(--acct-radius-sm);
    outline: none;
    transition: border-color 0.15s ease, box-shadow 0.15s ease;
}

.otpContainer input:focus {
    border-color: var(--acct-accent);
    box-shadow: 0 0 0 3px rgba(var(--acct-accent-rgb), 0.18);
}

@media screen and (max-width: 800px) {
    /* 6 boxes at the desktop size (45px + 10px gaps = 320px total) ran wider than the available content width on
       a small phone (.baseFrame's 90%, minus its own mobile padding, comes out well under 320px), clipping the
       outermost boxes on both sides. Smaller boxes/gap keep it well within even the narrowest common phone width. */
    .otpContainer {
        gap: 6px;
    }

    .otpContainer input {
        width: 34px;
        height: 40px;
        font-size: 18px;
    }
}

.otpRememberRow {
    margin-top: 15px;
    text-align: center;
}

.otpMessage {
    margin-top: 15px;
    text-align: center;
    font-weight: 600;
}