/* Base */
html {
    scroll-padding-top: calc(var(--nav-h, 68px) + var(--ticker-h, 36px));
}

/* Every navigation here is a real full-page load (no SPA/component swap),
   which browsers otherwise render as a hard cut with a blank flash between
   documents. This opts into the browser's native cross-document View
   Transition, cross-fading old/new page instead — no JS, no build step,
   and it's silently ignored (today's plain instant navigation) in any
   browser that doesn't support it yet. */
@view-transition {
    navigation: auto;
}

@media (prefers-reduced-motion: no-preference) {
    html { scroll-behavior: smooth; }
}

/* Sticky footer. Short pages (Visa, Accommodation, Publication) otherwise end
   mid-viewport on a tall screen, leaving the footer floating with dead
   background beneath it. Every overlay — navbar, ticker, quick-links, back-to-
   top — is position:fixed and so out of flow, which leaves the page sections as
   the only flex children and makes `margin-top:auto` on the footer safe. */
body {
    font-family: var(--font-body);
    background-color: var(--bg);
    color: var(--text);
    padding-top: calc(var(--nav-h, 68px) + var(--ticker-h, 36px));
    min-height: 100vh;
    display: flex;
    flex-direction: column;
}

h1, h2, h3, h4, h5, h6 {
    font-family: var(--font-heading);
}

/* Navbar — light glass-morphism */
.site-navbar {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    z-index: 1030;
    height: var(--nav-h, 68px);
    display: flex;
    align-items: center;
    background-color: rgba(255, 255, 255, 0.72);
    backdrop-filter: blur(16px);
    -webkit-backdrop-filter: blur(16px);
    border-bottom: 1px solid rgba(12, 110, 166, 0.12);
    transition: background-color var(--motion-normal) var(--ease-standard),
                border-color var(--motion-normal) var(--ease-standard),
                box-shadow var(--motion-normal) var(--ease-standard);
}

.site-navbar.scrolled {
    background-color: rgba(255, 255, 255, 0.97);
    border-bottom-color: var(--border);
    box-shadow: 0 2px 12px rgba(0, 0, 0, 0.07);
}

.site-navbar .navbar-brand {
    color: var(--primary);
    font-weight: 800;
    letter-spacing: -0.03em;
}

.site-navbar .navbar-brand .brand-accent {
    color: var(--accent);
}

.site-navbar .nav-link {
    color: rgba(30, 58, 95, 0.68);
    font-size: 0.815rem;
    font-weight: 500;
    padding: 0.35rem 0.6rem;
    position: relative;
    transition: color var(--motion-fast) var(--ease-standard);
}

.site-navbar .nav-link:hover,
.site-navbar .nav-link:focus,
.site-navbar .nav-link.active {
    color: var(--primary);
}

.site-navbar .nav-item:not(.dropdown) > .nav-link:not(.btn-nav-login)::after {
    content: '';
    position: absolute;
    left: 0.6rem;
    right: 0.6rem;
    bottom: 0;
    height: 2px;
    background-color: var(--accent);
    transform: scaleX(0);
    transform-origin: center;
    transition: transform var(--motion-fast) var(--ease-standard);
}

.site-navbar .nav-item:not(.dropdown) > .nav-link:not(.btn-nav-login):hover::after,
.site-navbar .nav-item:not(.dropdown) > .nav-link:not(.btn-nav-login):focus-visible::after {
    transform: scaleX(1);
}

.site-navbar .dropdown-menu {
    background-color: var(--card-bg);
    border: 1px solid var(--border);
    border-radius: 0.5rem;
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.09);
}

@media (prefers-reduced-motion: no-preference) {
    .site-navbar .dropdown-menu.show {
        animation: dropdownIn var(--motion-normal) var(--ease-standard);
    }
}

/* Opacity only — Bootstrap positions this menu via Popper's own inline
   transform, and animating transform here fought that: the menu rendered at
   the animation's transform (ignoring Popper's offset) until the animation
   ended, then snapped to its real position. That snap was the stagger. */
@keyframes dropdownIn {
    from { opacity: 0; }
    to   { opacity: 1; }
}

.site-navbar .dropdown-item {
    color: var(--text);
    font-size: 0.9rem;
    transition: color var(--motion-fast) var(--ease-standard),
                background-color var(--motion-fast) var(--ease-standard);
}

.site-navbar .dropdown-item:hover,
.site-navbar .dropdown-item:focus {
    background-color: var(--bg-alt);
    color: var(--primary);
}

/* Compound selector deliberately matches `.site-navbar .nav-link`'s
   specificity so the amber pill's white text wins the cascade. */
.site-navbar .nav-link.btn-nav-login {
    background-color: var(--accent);
    color: var(--on-color);
    border: none;
    border-radius: 0.375rem;
    padding: 0.4rem 1.1rem;
    font-weight: 600;
    transition: background-color var(--motion-fast) var(--ease-standard),
                transform var(--motion-fast) var(--ease-standard),
                box-shadow var(--motion-fast) var(--ease-standard);
    text-decoration: none;
}

.site-navbar .nav-link.btn-nav-login:hover,
.site-navbar .nav-link.btn-nav-login:focus {
    background-color: var(--accent-dark);
    color: var(--on-color);
    transform: translateY(-1px);
    box-shadow: 0 4px 12px rgba(230, 126, 34, 0.3);
}

/* The logged-in-user nav block mixes bare <a>/<span> items with one
   <div class="nav-item dropdown"> (My Account) — no shared wrapper type,
   so without this Bootstrap's own .navbar-nav defaults are all that
   apply, which don't keep these particular items evenly spaced. */
.navbar-nav.ms-auto {
    display: flex;
    align-items: center;
    gap: 0.5rem;
}

/* Keeps the caption and the id pill from splitting across a line break
   on narrow viewports — they only make sense as one unit. */
.navbar-cf9-id-wrap {
    display: inline-flex;
    align-items: center;
    white-space: nowrap;
    font-size: 0.78rem;
    color: var(--text-muted);
    margin-right: 0.25rem;
}

/* Plain bold text, not a badge — a bordered pill sitting right next to its
   own label read as two competing treatments in one small caption. Weight
   alone is enough to set the value apart from the muted label before it. */
.navbar-cf9-id {
    font-weight: 700;
    color: var(--text);
    margin-left: 0.3rem;
}

/* Outlined, button-like treatment for admins — previously a bare text
   link indistinguishable from the other nav items despite being the entry
   point to the whole admin section. */
.nav-link.nav-link-admin {
    border: 1px solid var(--primary);
    border-radius: 1.5rem;
    padding: 0.3rem 0.9rem !important;
    margin: 0 0.25rem;
}

.nav-link.nav-link-admin:hover,
.nav-link.nav-link-admin:focus-visible {
    background-color: var(--bg-alt);
}

/* Easter egg, deliberately — visible only to the operator account (the two
   people running this site), never admins. Everything here is scoped to
   .nav-link-operator so it can't bleed into any other nav-link. */
.nav-link.nav-link-operator {
    position: relative;
    overflow: hidden;
    display: inline-flex;
    align-items: center;
    padding: 0.35rem 1rem !important;
    margin: 0 0.35rem;
    border-radius: 1.5rem;
    background: linear-gradient(120deg, #ff6ec4, #7873f5, #4ade80, #ff6ec4);
    background-size: 300% 300%;
    color: #fff !important;
    font-weight: 700;
    letter-spacing: 0.02em;
    box-shadow: 0 2px 14px rgba(120, 115, 245, 0.45);
}

@media (prefers-reduced-motion: no-preference) {
    .nav-link.nav-link-operator {
        animation: operator-gradient-shift 6s ease infinite;
    }

    .nav-link.nav-link-operator:hover {
        animation-duration: 1.5s;
    }
}

@keyframes operator-gradient-shift {
    0%   { background-position: 0% 50%; }
    50%  { background-position: 100% 50%; }
    100% { background-position: 0% 50%; }
}

.nav-link-operator-glow {
    position: absolute;
    inset: -40%;
    background: radial-gradient(circle, rgba(255, 255, 255, 0.35) 0%, transparent 60%);
    pointer-events: none;
}

.nav-link-operator-label {
    position: relative;
}

/* Matches the underline-sweep selector's own specificity (site.css:79) to
   actually win the cascade — this pill has its own animation going on
   already and doesn't need the standard nav-link underline too. */
.site-navbar .nav-item:not(.dropdown) > .nav-link.nav-link-operator::after,
.site-navbar .nav-item:not(.dropdown) > .nav-link.nav-link-admin::after {
    content: none;
}

/* Partner/organiser band — scrolls with content so it costs no fixed viewport */
.partner-band {
    background-color: var(--card-bg);
    border-bottom: 1px solid var(--border);
    padding: 1rem 0;
}

.partner-band .partner-list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    gap: 1rem 2.5rem;
}

.partner-band .partner-item {
    display: flex;
    align-items: center;
    gap: 0.75rem;
}

/* Height-based sizing with width:auto is deliberate: partner marks range from
   square (IGCAR, JSME) to ~2.4:1 wordmarks (IIM). Any width-based rule breaks
   the moment a wordmark is added. */
.partner-band .partner-logo {
    height: clamp(38px, 10vw, 52px);
    width: auto;
    flex-shrink: 0;
}

.partner-band .partner-caption {
    font-size: 0.72rem;
    line-height: 1.35;
    color: var(--text-muted);
}

.partner-band .partner-caption strong {
    color: var(--text);
    font-weight: 600;
}

/* Updates ticker */
.site-ticker {
    position: fixed;
    top: var(--nav-h, 68px);
    left: 0;
    right: 0;
    z-index: 1020;
    height: var(--ticker-h, 36px);
    background-color: var(--bg-alt);
    border-bottom: 1px solid rgba(12, 110, 166, 0.14);
    display: flex;
    align-items: center;
    overflow: hidden;
}

.site-ticker .ticker-label {
    flex-shrink: 0;
    background-color: var(--accent);
    color: var(--on-color);
    font-size: 0.62rem;
    font-weight: 700;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    padding: 0 1rem;
    height: 100%;
    display: flex;
    align-items: center;
}

.site-ticker .ticker-label-home {
    text-decoration: none;
    cursor: pointer;
}

.site-ticker .ticker-label-home:hover,
.site-ticker .ticker-label-home:focus-visible {
    background-color: var(--accent-dark, var(--accent));
    color: var(--on-color);
}

.site-ticker .ticker-track {
    flex: 1;
    overflow: hidden;
}

.site-ticker .ticker-inner {
    display: inline-flex;
    white-space: nowrap;
}

/* Duration is tiered off the total text length (set in header.php) so the strip
   scrolls at roughly one speed no matter how much it is carrying.

   Not gated behind prefers-reduced-motion: some browsers/OS configs
   (battery saver, certain enterprise policies) report reduce by default
   with no motion sensitivity behind it, which left the strip stuck and
   only draggable by hand on a number of visitor systems. The hover/focus
   pause below is the actual accessibility control for moving text, so the
   animation now always runs. */
.site-ticker .ticker-inner {
    animation: ticker-marquee 32s linear infinite;
}

.site-ticker .ticker-speed-short  { animation-duration: 22s; }
.site-ticker .ticker-speed-medium { animation-duration: 32s; }
.site-ticker .ticker-speed-long   { animation-duration: 46s; }

/* Hover pauses for a mouse; focus-within does the same for a keyboard, so the
   text can be stopped and read without a pointer. */
.site-ticker .ticker-inner:hover,
.site-ticker .ticker-inner:focus-within {
    animation-play-state: paused;
}

.site-ticker .ticker-inner span {
    /* Was a flat 0.78rem with 2.25rem of padding either side plus a 2.25rem
       margin on the diamond — about 4.5rem between items, which on a phone left
       long stretches of empty strip between fragments. */
    font-size: clamp(0.72rem, 2.2vw, 0.8rem);
    color: #4a7d9e;
    padding: 0 clamp(0.9rem, 3vw, 2.25rem);
    position: relative;
}

.site-ticker .ticker-inner span::after {
    content: "\25C6";
    margin-left: clamp(0.9rem, 3vw, 2.25rem);
    font-size: 0.4rem;
    color: var(--accent);
    opacity: 0.6;
}

@keyframes ticker-marquee {
    from { transform: translateX(0); }
    to   { transform: translateX(-50%); }
}

/* Hero carousel */
#heroCarousel .carousel-item {
    min-height: 75vh;
}

#heroCarousel.carousel-fade .carousel-item {
    transition: opacity var(--motion-slow) var(--ease-standard);
}

/* Bootstrap's default control is a 15%-of-viewport-wide, full-height
   invisible click band — at mid-range widths its inner edge lands inside
   the text column (.slide-content's 620px max-width) and overlaps the
   title. Shrinking it to a small fixed-width button anchored to the edge
   keeps it clear of the text at every width, and reads as an actual
   control instead of an invisible hit zone. */
#heroCarousel .carousel-control-prev,
#heroCarousel .carousel-control-next {
    width: 4rem;
    opacity: 1;
}

#heroCarousel .carousel-control-prev-icon,
#heroCarousel .carousel-control-next-icon {
    background-color: rgba(255, 255, 255, 0.15);
    border-radius: 50%;
    transition: background-color var(--motion-fast) var(--ease-standard);
}

#heroCarousel .carousel-control-prev:hover .carousel-control-prev-icon,
#heroCarousel .carousel-control-next:hover .carousel-control-next-icon {
    background-color: rgba(255, 255, 255, 0.28);
}

@media (max-width: 767px) {
    #heroCarousel .carousel-control-prev,
    #heroCarousel .carousel-control-next {
        width: 2.75rem;
    }
}

.carousel-slide-inner {
    min-height: 75vh;
    display: flex;
    align-items: center;
    padding: 3rem 4rem;
    position: relative;
    overflow: hidden;
}

.carousel-slide-inner::after {
    content: '';
    position: absolute;
    top: -80px;
    right: -80px;
    width: 420px;
    height: 420px;
    border-radius: 50%;
    background: rgba(255, 255, 255, 0.06);
    border: 1px solid rgba(255, 255, 255, 0.14);
}

.carousel-slide-inner > * {
    position: relative;
    z-index: 1;
}

.carousel-slide-inner.slide-1 { background: linear-gradient(135deg, #0c4a78 0%, #1872b5 45%, #1f8cd3 100%); }
.carousel-slide-inner.slide-2 { background: linear-gradient(110deg, #09395a 0%, #1460a0 55%, #1880c2 100%); }
.carousel-slide-inner.slide-3 { background: linear-gradient(150deg, #0b5785 0%, #1374b0 50%, #1890cb 100%); }

.slide-accent-bar {
    width: 4px;
    height: 90px;
    background-color: var(--accent);
    border-radius: 2px;
    flex-shrink: 0;
    margin-right: 2.25rem;
}

.slide-content {
    max-width: 1200px;
}

.carousel-slide-inner .slide-eyebrow {
    font-size: clamp(0.8rem, 2.6vw, 1.25rem);
    font-weight: 600;
    /* 0.22em tracking at 1.25rem pushed this to ~470px of inline text, which
       wrapped to two lines inside a ~342px phone slide. */
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--accent);
    margin-bottom: 1rem;
}

.carousel-slide-inner h1 {
    color: var(--on-color);
    /* Tuned against the two actual heading phrases' measured widths (Inter,
       weight 800, -0.03em tracking): ~0.9rem is the smallest this can go at
       a 390px phone (this file's own established narrow-phone reference,
       see .slide-eyebrow below) without the long phrase overflowing; 3.4rem
       is unchanged from before and only applies once the viewport is wide
       enough to give the long phrase's ~1135px natural width room to fit
       on one line. */
    font-size: clamp(0.9rem, calc(3.7vw + 0.07rem), 3.4rem);
    font-weight: 800;
    line-height: 1.1;
    letter-spacing: -0.03em;
    max-width: 1200px;
}

.carousel-slide-inner .hero-name-line {
    display: block;
    /* Each line is a deliberate, complete phrase (see index.php) — nowrap
       is what actually keeps it to exactly two lines; the font-size clamp
       above is what keeps nowrap from overflowing at narrow widths. */
    white-space: nowrap;
}

.carousel-slide-inner .slide-sub {
    color: rgba(255, 255, 255, 0.78);
    font-size: clamp(0.95rem, 2.8vw, 1.25rem);
    font-weight: 300;
    max-width: 520px;
    line-height: 1.75;
    margin-top: 1rem;
    margin-bottom: 2rem;
}

.carousel-indicators {
    margin-left: 4rem;
    justify-content: flex-start;
}

/* The transparent top/bottom borders keep the visible bar 3px tall while giving
   the control a ~23px touch target. Bootstrap ships them for exactly this
   reason; a plain `border: none` here left a 3px-tall tap target. */
.carousel-indicators [data-bs-target] {
    box-sizing: content-box;
    width: 24px;
    height: 3px;
    border-radius: 2px;
    border: 0;
    border-top: 10px solid transparent;
    border-bottom: 10px solid transparent;
    background-color: rgba(255, 255, 255, 0.3);
    background-clip: padding-box;
    opacity: 1;
    transition: background-color var(--motion-slow) var(--ease-standard),
                width var(--motion-slow) var(--ease-standard);
}

.carousel-indicators .active {
    background-color: var(--accent);
    width: 40px;
}

/* Info strip */
.info-strip {
    background-color: var(--bg-alt);
    border-bottom: 1px solid rgba(12, 110, 166, 0.12);
}

.info-item {
    display: flex;
    align-items: center;
    gap: 1rem;
    padding: 1.5rem 2rem;
}

.info-item + .info-item {
    border-left: 1px solid rgba(12, 110, 166, 0.12);
}

.info-icon {
    font-size: 1.75rem;
    color: var(--primary);
    flex-shrink: 0;
}

.info-label {
    font-size: 0.65rem;
    font-weight: 700;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--text-muted);
    margin-bottom: 0.2rem;
}

.info-value {
    font-size: 0.92rem;
    font-weight: 600;
    color: var(--text);
}

/* Welcome section */
.section-welcome {
    background-color: var(--bg);
    padding: 4rem 0;
}

.section-welcome h2 {
    color: var(--primary);
    font-weight: 700;
}

.section-welcome p {
    color: var(--text-muted);
}

/* Body copy is ragged-right at every width: justifying a 720px measure with
   tokens this long ("creep-fatigue interaction") opens uneven word gaps, and
   the auto-hyphenation that used to compensate was breaking words mid-line.
   The explicit left is load-bearing — the parent container is .text-center,
   which long-form body copy must not inherit. */
.section-welcome .welcome-intro {
    max-width: 720px;
    margin-inline: auto;
    text-align: left;
    line-height: 1.75;
}

.section-welcome .welcome-intro p:last-child {
    margin-bottom: 0;
}

/* bi-dot draws a ~6px dot inside a ~24px glyph advance, which read as a broken
   indent. A small filled circle aligned to the first text line is honest. */
.topic-bullet {
    font-size: 0.4rem;
    line-height: 1.5;
    margin-top: 0.5rem;
}

/* Bootstrap's gap-2 (0.5rem) sat on top of the ~1em glyph advance the icon font
   already reserves, leaving roughly 10px of air beside a 5px dot. Setting the
   gap directly measures from the glyph box, so the marker reads as attached to
   its line. Matched by .fee-inclusions li. */
.topic-item {
    gap: 0.35rem;
}

/* Venue map: 1:1 suits the narrow desktop sidebar, but at full mobile width that
   same square eats ~43% of the viewport, so widen the ratio on small screens. */
.venue-map {
    --bs-aspect-ratio: 75%;
}

@media (min-width: 992px) {
    .venue-map {
        --bs-aspect-ratio: 100%;
    }
}

/* Meta cards (venue/dates/organiser style callouts) */
.meta-card {
    background-color: var(--card-bg);
    border: 1px solid var(--border);
    border-top: 3px solid var(--accent);
    border-radius: 0.5rem;
    padding: 1.25rem 1.5rem;
    box-shadow: 0 1px 4px rgba(0, 0, 0, 0.04);
    transition: box-shadow var(--motion-normal) var(--ease-standard),
                transform var(--motion-normal) var(--ease-standard);
}

.meta-card:hover {
    box-shadow: 0 6px 20px rgba(0, 0, 0, 0.08);
    transform: translateY(-2px);
}

.meta-card + .meta-card {
    margin-top: 1rem;
}

.meta-label {
    font-size: 0.62rem;
    font-weight: 700;
    letter-spacing: 0.15em;
    text-transform: uppercase;
    color: var(--accent);
    margin-bottom: 0.4rem;
}

.meta-value {
    font-size: 0.9rem;
    color: var(--text);
    line-height: 1.55;
}

/* Single centered highlight strip (home page), not the stacked sidebar list
   .meta-card is elsewhere — constrained so it reads as a callout, not a
   full-width bar. */
.conference-dates-card {
    max-width: 420px;
}

/* Feature cards */
.feature-card {
    border: 1px solid var(--border);
    border-radius: 0.5rem;
    background-color: var(--card-bg);
    transition: box-shadow var(--motion-normal) var(--ease-standard),
                transform var(--motion-normal) var(--ease-standard);
    height: 100%;
}

.feature-card:hover {
    box-shadow: 0 6px 24px rgba(0, 0, 0, 0.09);
    transform: translateY(-3px);
}

.feature-card .card-icon {
    color: var(--accent);
    font-size: 2.25rem;
    margin-bottom: 1rem;
    display: block;
}

.feature-card .card-title {
    color: var(--primary);
    font-weight: 700;
}

.feature-card .card-text {
    color: var(--text-muted);
}

.btn-primary-cf {
    background-color: var(--primary);
    color: var(--on-color);
    border: none;
    border-radius: 0.375rem;
    transition: background-color var(--motion-fast) var(--ease-standard),
                transform var(--motion-fast) var(--ease-standard),
                box-shadow var(--motion-fast) var(--ease-standard);
    text-decoration: none;
    display: inline-block;
    padding: 0.5rem 1rem;
}

.btn-primary-cf:hover {
    background-color: var(--primary-dark);
    color: var(--on-color);
    transform: translateY(-1px);
    box-shadow: 0 4px 12px rgba(12, 110, 166, 0.25);
}

/* Same shape as .btn-primary-cf, soft green instead of the brand blue —
   makes the Excel export instantly distinguishable from CSV at a glance. */
.btn-excel-cf {
    background-color: var(--excel-green);
    color: var(--on-color);
    border: none;
    border-radius: 0.375rem;
    transition: background-color var(--motion-fast) var(--ease-standard),
                transform var(--motion-fast) var(--ease-standard),
                box-shadow var(--motion-fast) var(--ease-standard);
    text-decoration: none;
    display: inline-block;
    padding: 0.5rem 1rem;
}

.btn-excel-cf:hover {
    background-color: var(--excel-green-dark);
    color: var(--on-color);
    transform: translateY(-1px);
    box-shadow: 0 4px 12px rgba(92, 171, 111, 0.3);
}

.btn-outline-cf {
    background-color: transparent;
    color: var(--primary);
    border: 1.5px solid var(--primary);
    border-radius: 0.375rem;
    transition: background-color var(--motion-fast) var(--ease-standard),
                color var(--motion-fast) var(--ease-standard),
                transform var(--motion-fast) var(--ease-standard),
                box-shadow var(--motion-fast) var(--ease-standard);
    text-decoration: none;
    display: inline-block;
    padding: 0.5rem 1rem;
}

.btn-outline-cf:hover {
    background-color: var(--primary);
    color: var(--on-color);
    transform: translateY(-1px);
    box-shadow: 0 4px 12px rgba(12, 110, 166, 0.2);
}

/* Accent variant — reserved for the one or two CTAs on a page that need to
   outrank the primary-blue buttons already everywhere else (e.g. the
   circular download on the homepage), not a general-purpose swap-in. */
.btn-accent-cf {
    background-color: var(--accent);
    color: var(--on-color);
    border: none;
    border-radius: 0.375rem;
    transition: background-color var(--motion-fast) var(--ease-standard),
                transform var(--motion-fast) var(--ease-standard),
                box-shadow var(--motion-fast) var(--ease-standard);
    text-decoration: none;
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.75rem 1.5rem;
    font-weight: 600;
}

.btn-accent-cf:hover {
    background-color: var(--accent-dark);
    color: var(--on-color);
    transform: translateY(-1px);
    box-shadow: 0 4px 12px rgba(230, 126, 34, 0.3);
}

/* A real "pressed" state, not grey — grey reads as disabled everywhere
   else on this site (see .badge.bg-secondary for "Coming Soon"), and this
   button works, so it shouldn't look broken the moment it's clicked. */
.btn-accent-cf:active {
    background-color: var(--accent-dark);
    transform: translateY(0);
    box-shadow: 0 2px 6px rgba(230, 126, 34, 0.25);
}

/* No browser default is dim enough on its own to avoid reading as a
   filled-in value at a glance — every form on the site gets this fix at
   once since it was never scoped per-page. */
.form-control::placeholder,
.form-select::placeholder {
    color: var(--placeholder);
    opacity: 1; /* Firefox applies its own default dimming otherwise, compounding with the color above */
}

/* Groups a long form into labeled sections without splitting it into
   separate cards — no other form on the site uses multiple cards, so this
   keeps one continuous card while still breaking up a flat wall of fields
   (e.g. contactinformation-edit.php). */
.form-section-label {
    font-size: 0.72rem;
    font-weight: 700;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--accent);
    margin-bottom: 1rem;
    padding-top: 1.5rem;
    border-top: 1px solid var(--border);
}

.form-section-label:first-child {
    padding-top: 0;
    border-top: none;
}

/* Inner page chrome */
.page-header-band {
    background: linear-gradient(135deg, var(--primary-dark) 0%, var(--primary) 100%);
    padding: 2.5rem 0;
}

.page-header-band h1 {
    color: var(--on-color);
    margin: 0;
    font-size: clamp(1.4rem, 3vw, 2rem);
    font-weight: 700;
}

.page-content {
    padding: 3rem 0;
}

/* Long-form body copy lifted from the announcement document. Ragged-right and
   loosely leaded for the same reason as .welcome-intro: this text is dense with
   long technical compounds that justification would space badly. */
.scope-intro {
    line-height: 1.75;
    margin-bottom: 2rem;
}

.scope-intro p:last-child {
    margin-bottom: 0;
}

/* Reads as a caveat rather than body copy: the accent rule carries the emphasis
   so the note can stay small without being missed. */
.fee-note {
    border-left: 3px solid var(--accent);
    background-color: var(--bg-alt);
    padding: 0.75rem 1rem;
    margin-bottom: 2.5rem;
    font-size: 0.9rem;
    color: var(--text-muted);
}

.fee-inclusions {
    background-color: var(--card-bg);
    padding: 1.5rem;
}

/* Flex so a wrapping item indents under its own text rather than back under the
   tick, matching how .footer-contact handles the same problem. */
.fee-inclusions li {
    display: flex;
    align-items: flex-start;
    /* Wider than .topic-item's 0.35rem because the tick is a full-size glyph,
       not a 5px dot — same optical gap, different marker. */
    gap: 0.45rem;
    margin-bottom: 0.5rem;
}

.fee-inclusions li:last-child {
    margin-bottom: 0;
}

.fee-inclusions li > .bi {
    flex-shrink: 0;
    line-height: 1.5;
    font-weight: 700;
}

/* Sponsor marks arrive at whatever size the sponsor supplies; bound both axes so
   a tall or a wide logo both settle into the same row without distortion. */
.sponsor-logo {
    max-height: 80px;
    max-width: 200px;
}

.inner-table th {
    background-color: var(--primary);
    color: var(--on-color);
}

.inner-table td {
    color: var(--text);
    border-color: var(--border);
}

/* Footer */
.site-footer {
    background-color: var(--footer-bg);
    color: var(--footer-text);
    padding: 3rem 0 0;
    /* Pushes the footer (and the sub-footer after it) to the bottom of the
       flex-column body when the page content is shorter than the viewport. */
    margin-top: auto;
}

.site-footer h5 {
    color: var(--accent);
    font-size: 0.65rem;
    font-weight: 700;
    letter-spacing: 0.15em;
    text-transform: uppercase;
    margin-bottom: 1rem;
}

.site-footer p,
.site-footer li {
    color: var(--footer-text);
    font-size: 0.85rem;
}

.site-footer a {
    color: rgba(255, 255, 255, 0.65);
    text-decoration: none;
    transition: color var(--motion-fast) var(--ease-standard);
}

.site-footer a:hover {
    color: var(--on-color);
}

/* Bootstrap's <hr> defaults to currentColor + opacity, which renders as a
   pale bar against the dark teal footer. Set the rule explicitly instead. */
.footer-divider {
    border: 0;
    border-top: 1px solid rgba(255, 255, 255, 0.1);
    opacity: 1;
    margin: 1.5rem 0;
}

.footer-venue {
    color: rgba(255, 255, 255, 0.55);
}

/* Flex rather than inline icons so the 111-char address indents under its own
   text on wrap, instead of continuation lines running back under the icon. */
.footer-contact li {
    display: flex;
    align-items: flex-start;
    gap: 0.5rem;
    margin-bottom: 0.4rem;
}

.footer-contact li > .bi {
    flex-shrink: 0;
    line-height: 1.5;
}

.sub-footer {
    background-color: var(--footer-bg);
    border-top: 1px solid rgba(255, 255, 255, 0.1);
    padding: 1rem 0;
    text-align: center;
    /* Was 0.72rem at 40% white: under the readable floor on a phone and well
       below 4.5:1 contrast, and this is where the developer credit lives. */
    font-size: 0.8rem;
    color: rgba(255, 255, 255, 0.66);
}

/* Back-to-top */
.back-to-top {
    position: fixed;
    bottom: 1.75rem;
    right: 1.75rem;
    background-color: var(--primary);
    color: var(--on-color);
    border: none;
    border-radius: 50%;
    width: 2.75rem;
    height: 2.75rem;
    font-size: 1.25rem;
    line-height: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    z-index: 1050;
    opacity: 0;
    transform: translateY(12px);
    pointer-events: none;
    transition: opacity var(--motion-normal) var(--ease-standard),
                transform var(--motion-normal) var(--ease-standard),
                background-color var(--motion-fast) var(--ease-standard);
}

.back-to-top.visible {
    opacity: 1;
    transform: translateY(0);
    pointer-events: auto;
}

.back-to-top:hover {
    background-color: var(--primary-dark);
}

/* Quick links floating panel */
.quick-links-panel {
    position: fixed;
    right: 0;
    top: 50%;
    transform: translateY(-50%);
    z-index: 900;
    display: flex;
    align-items: stretch;
}

.quick-links-body {
    background-color: var(--card-bg);
    border: 1px solid var(--border);
    border-right: none;
    border-radius: 0.5rem 0 0 0.5rem;
    overflow: hidden;
    max-width: 0;
    transition: max-width var(--motion-normal) var(--ease-standard);
    white-space: nowrap;
    box-shadow: -2px 2px 16px rgba(0, 0, 0, 0.08);
}

.quick-links-body.open {
    max-width: 220px;
}

.quick-links-header {
    background-color: var(--primary);
    color: var(--on-color);
    font-size: 0.62rem;
    font-weight: 700;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    padding: 0.6rem 1rem;
}

.quick-link-item {
    display: block;
    padding: 0.5rem 1rem;
    color: var(--text-muted);
    text-decoration: none;
    font-size: 0.8rem;
    font-weight: 500;
    border-bottom: 1px solid var(--border);
    transition: color var(--motion-fast) var(--ease-standard),
                background-color var(--motion-fast) var(--ease-standard);
}

.quick-link-item:last-child {
    border-bottom: none;
}

.quick-link-item:hover {
    color: var(--primary);
    background-color: var(--bg-alt);
}

.quick-links-tab {
    writing-mode: vertical-lr;
    transform: rotate(180deg);
    background-color: var(--accent);
    color: var(--on-color);
    border: none;
    border-radius: 0 0 0.375rem 0.375rem;
    padding: 1.1rem 0.55rem;
    font-size: 0.6rem;
    font-weight: 700;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    cursor: pointer;
    flex-shrink: 0;
    transition: background-color var(--motion-fast) var(--ease-standard);
}

.quick-links-tab:hover {
    background-color: var(--accent-dark);
}

/* Scroll-reveal */
@media (prefers-reduced-motion: no-preference) {
    .reveal-on-scroll {
        opacity: 0;
        transform: translateY(24px);
        transition: opacity var(--motion-slow) var(--ease-standard),
                    transform var(--motion-slow) var(--ease-standard);
    }

    .reveal-on-scroll.in-view {
        opacity: 1;
        transform: translateY(0);
    }
}

/* Admin */
.admin-subnav {
    display: flex;
    flex-wrap: wrap;
    gap: 0.25rem;
    border-bottom: 1px solid var(--border);
    padding-bottom: 0.5rem;
}

.admin-subnav-item {
    color: var(--text-muted);
    text-decoration: none;
    font-size: 0.85rem;
    font-weight: 500;
    padding: 0.35rem 0.75rem;
    border-radius: 0.375rem;
    transition: color var(--motion-fast) var(--ease-standard),
                background-color var(--motion-fast) var(--ease-standard);
}

.admin-subnav-item:hover,
.admin-subnav-item:focus-visible {
    color: var(--primary);
    background-color: var(--bg-alt);
}

.admin-subnav-item.active {
    color: var(--on-color);
    background-color: var(--primary);
}

.admin-toolbar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.75rem;
    margin-bottom: 1rem;
}

/* Pushes the export actions to the trailing edge, whatever precedes them. */
.admin-toolbar .export-actions { margin-left: auto; }

/* Groups CSV + Excel export together, closer and smaller than a full-size
   standalone button — these are secondary actions on the page, not the
   primary thing someone's here to do. .btn-primary-cf/.btn-excel-cf are
   custom-styled (not Bootstrap's .btn), so this is a small bespoke
   grouping rather than Bootstrap's .btn-group (which only collapses
   borders/sizing for elements carrying its own .btn class). */
.export-actions {
    display: flex;
    gap: 0.4rem;
}

.export-actions .btn-primary-cf,
.export-actions .btn-excel-cf {
    padding: 0.35rem 0.75rem;
    font-size: 0.85rem;
}

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

/* Search-first, not browse-first — with thousands of registrants, paging
   through the full list to find one person doesn't scale the way a direct
   search does. */
.admin-search {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
}

.admin-search input[type="search"] {
    flex: 1 1 260px;
}

.admin-stat {
    display: block;
    background-color: var(--card-bg);
    border: 1px solid var(--border);
    border-top: 3px solid var(--accent);
    border-radius: 0.5rem;
    padding: 1.25rem;
    text-decoration: none;
    height: 100%;
    transition: box-shadow var(--motion-normal) var(--ease-standard),
                transform var(--motion-normal) var(--ease-standard);
}

.admin-stat:hover,
.admin-stat:focus-visible {
    box-shadow: 0 6px 20px rgba(0, 0, 0, 0.08);
    transform: translateY(-2px);
}

/* Matches .feature-card .card-icon's existing visual language (homepage)
   rather than inventing a new icon treatment for this one section. */
.admin-stat-icon {
    display: block;
    color: var(--accent);
    font-size: 1.5rem;
    margin-bottom: 0.5rem;
}

.admin-stat-value {
    display: block;
    font-size: 1.75rem;
    font-weight: 700;
    color: var(--primary);
    line-height: 1.1;
    font-variant-numeric: tabular-nums;
}

.admin-stat-label {
    display: block;
    margin-top: 0.25rem;
    font-size: 0.7rem;
    font-weight: 700;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--text-muted);
}

.admin-review-form {
    display: flex;
    flex-direction: column;
    gap: 0.4rem;
    min-width: 12rem;
}

.admin-review-actions {
    display: flex;
    gap: 0.35rem;
}

/* Themed confirmation modals — used for anything that grants/revokes
   access or fires an irreversible side effect (email, lockout). Stock
   Bootstrap otherwise looks visually unrelated to the rest of the site. */
.modal-content {
    border: 1px solid var(--border);
    border-radius: 0.75rem;
}

.modal-header {
    border-bottom: 1px solid var(--border);
}

.modal-title {
    color: var(--primary);
    font-weight: 700;
}

/* Utilities */
.form-footer-link { font-size: 0.9rem; }
.text-nums        { font-variant-numeric: tabular-nums; }
.text-primary-cf  { color: var(--primary); }
.text-accent-cf   { color: var(--accent); }
.text-muted-cf    { color: var(--text-muted); }
.bg-alt-cf        { background-color: var(--bg-alt); }
.section-pad      { padding: 3rem 0; }
.border-cf        { border-color: var(--border) !important; }

@media (max-width: 991px) {
    .site-navbar .navbar-collapse {
        background-color: rgba(255, 255, 255, 0.97);
        border-top: 1px solid var(--border);
        padding: 1rem 1.25rem;
        margin-top: 0.5rem;
        border-radius: 0 0 0.5rem 0.5rem;
        box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
    }
    .carousel-indicators { margin-left: 1.5rem; }
    .carousel-slide-inner { padding: 2rem 1.5rem; }

    .navbar-nav.ms-auto {
        align-items: flex-start;
        gap: 0.75rem;
    }
    .navbar-nav.ms-auto .nav-item.dropdown {
        width: 100%;
    }
}

@media (max-width: 767px) {
    .quick-links-panel { display: none; }
    .info-item + .info-item { border-left: none; border-top: 1px solid rgba(12, 110, 166, 0.1); }
    .slide-accent-bar { display: none; }

    /* Admin tables → stacked cards instead of horizontal scroll. Label
       above value handles any cell content uniformly (plain text, a
       badge, a whole form with buttons) without per-column special-
       casing, unlike a label-left/value-right row layout. */
    .admin-table thead {
        display: none;
    }

    .admin-table, .admin-table tbody, .admin-table tr, .admin-table td {
        display: block;
        width: 100%;
    }

    .admin-table {
        border: none;
    }

    .admin-table tr {
        margin-bottom: 1rem;
        border: 1px solid var(--border);
        border-radius: 0.5rem;
        padding: 0.75rem 1rem;
        background-color: var(--card-bg);
    }

    .admin-table td {
        padding: 0.5rem 0;
        border: none !important;
        text-align: left !important; /* Bootstrap's .text-end/.text-nums utilities are !important too — must match to win here */
    }

    .admin-table td:not(:last-child) {
        border-bottom: 1px solid var(--border) !important;
        padding-bottom: 0.75rem;
        margin-bottom: 0.25rem;
    }

    .admin-table td::before {
        content: attr(data-label);
        display: block;
        font-size: 0.68rem;
        font-weight: 700;
        text-transform: uppercase;
        letter-spacing: 0.05em;
        color: var(--text-muted);
        margin-bottom: 0.25rem;
    }

    /* Toolbar/subnav/search rows already wrap; this just gives full-width
       children breathing room instead of everything crowding together at
       the same cramped gap used at desktop width. */
    .admin-toolbar,
    .admin-search {
        gap: 0.6rem;
    }

    .admin-toolbar > * {
        width: 100%;
    }

    .admin-toolbar .export-actions {
        margin-left: 0;
    }

    .admin-subnav {
        gap: 0.4rem;
    }

    .admin-review-form {
        width: 100%;
    }
}
