* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

html {
    width: 100%;
    height: 100%;
    min-height: 100vh;
    min-height: 100dvh;
    overflow: hidden;
}

body {
    font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
    width: 100%;
    height: 100%;
    min-height: 100vh;
    min-height: 100dvh;
    overflow: hidden;
    margin: 0;
    padding: 0;
    position: relative;
    background: #eef2f7;
}

#map {
    width: 100%;
    height: 100vh;
    height: 100dvh;
    background: white;
}

/* Covers the empty map container until the floor plan is drawn. Without it
   the first moment of a visit is a blank white screen, which reads as broken
   rather than as loading, and a fair hall's wifi is where that moment is
   longest. */
#map-loading {
    position: fixed;
    inset: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 14px;
    background: white;
    color: #64748b;
    font-size: 14px;
    /* Above the map, below the header controls, so the search bar is never
       covered by it. */
    z-index: 500;
    transition: opacity 0.25s ease;
}

#map-loading p {
    margin: 0;
}

#map-loading.is-done {
    opacity: 0;
    pointer-events: none;
}

.map-loading-spinner {
    width: 28px;
    height: 28px;
    border-radius: 50%;
    border: 3px solid #e2e8f0;
    border-top-color: #1042cc;
    animation: map-loading-spin 0.8s linear infinite;
}

@keyframes map-loading-spin {
    to { transform: rotate(360deg); }
}

/* Someone who has asked their system not to animate gets a resting ring
   rather than a spinning one; the message below it is what carries the
   meaning anyway. */
@media (prefers-reduced-motion: reduce) {
    .map-loading-spinner {
        animation: none;
    }
}

/* The id rule below sets display:flex, which would otherwise beat the
   browser's own [hidden] rule and leave the button on screen. */
#filter-toggle[hidden],
#companies-toggle[hidden] {
    display: none !important;
}

#app-toast {
    position: fixed;
    left: 50%;
    /* Clears the bottom bar rather than landing on top of it. footer.js
       measures the bar and publishes --footer-height; it is 0 on a fair that
       has no bar, so this is the old position in that case. Seen on a phone:
       "Booth 101, not on the floor plan" covered the Facebook link. */
    bottom: calc(env(safe-area-inset-bottom, 0px) + var(--footer-height, 0px) + 24px);
    transform: translate(-50%, 16px);
    z-index: 1400;
    max-width: min(420px, calc(100vw - 32px));
    padding: 12px 18px;
    border-radius: 14px;
    font-size: 14px;
    line-height: 1.4;
    color: #fff;
    background: #b91c1c;
    box-shadow: 0 12px 28px rgba(15, 23, 42, 0.25);
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.2s ease, transform 0.2s ease;
}

#app-toast.visible {
    opacity: 1;
    transform: translate(-50%, 0);
}

#app-toast.is-info {
    background: #1e40af;
}

#app-header {
    position: absolute;
    top: 10px;
    left: 10px;
    right: 10px;
    z-index: 1001;
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.control-surface {
    background: rgba(255, 255, 255, 0.94);
    backdrop-filter: blur(10px);
    border: 1px solid rgba(226, 232, 240, 0.95);
    box-shadow: 0 10px 24px rgba(15, 23, 42, 0.12);
}

#top-controls {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 6px;
    border-radius: 18px;
    position: relative;
    z-index: 2;
}

#company-search {
    position: relative;
    flex: 1 1 auto;
}

.search-icon {
    position: absolute;
    left: 14px;
    top: 50%;
    transform: translateY(-50%);
    width: 18px;
    height: 18px;
    color: #64748b;
    pointer-events: none;
}

.search-icon svg {
    width: 100%;
    height: 100%;
    display: block;
    fill: currentColor;
}

#company-search-input {
    width: 100%;
    min-height: 46px;
    padding: 11px 14px 11px 42px;
    border: 1px solid #d7dce5;
    border-radius: 14px;
    font-size: 15px;
    font-weight: 500;
    color: #0f172a;
    background: #f8fafc;
    transition: border-color 0.2s ease, background-color 0.2s ease, box-shadow 0.2s ease;
}

#company-search-input::placeholder {
    color: #7b8797;
}

#company-search-input:focus {
    outline: none;
    border-color: #1042cc;
    background: #fff;
    box-shadow: 0 0 0 4px rgba(107, 124, 240, 0.14);
}

#company-search-results {
    display: none;
    position: absolute;
    top: calc(100% + 8px);
    left: 0;
    right: 0;
    background: #fff;
    border: 1px solid #e2e8f0;
    border-radius: 16px;
    box-shadow: 0 16px 32px rgba(15, 23, 42, 0.18);
    max-height: 320px;
    overflow-y: auto;
    padding: 6px;
    z-index: 10;
}

.search-result-item {
    width: 100%;
    text-align: left;
    border: none;
    border-radius: 12px;
    padding: 10px 12px;
    background: #fff;
    cursor: pointer;
    display: flex;
    flex-direction: column;
    gap: 3px;
}

.search-result-item:hover {
    background: #eef2ff;
}

.search-result-name {
    font-size: 14px;
    font-weight: 600;
    color: #222;
}

.search-result-meta {
    font-size: 12px;
    color: #666;
}

.search-result-empty {
    padding: 10px 12px;
    color: #666;
    font-size: 13px;
}

#filter-toggle {
    width: 46px;
    min-width: 46px;
    height: 46px;
    border: 1px solid #d7dce5;
    border-radius: 14px;
    background: #f8fafc;
    color: #334155;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    transition: background-color 0.2s ease, border-color 0.2s ease, color 0.2s ease, box-shadow 0.2s ease;
}

#filter-toggle svg {
    width: 20px;
    height: 20px;
    display: block;
    fill: currentColor;
}

#filter-toggle:hover,
#filter-toggle.is-open,
#filter-toggle.is-active {
    background: #eef2ff;
    border-color: #1042cc;
    color: #1042cc;
}

#filter-toggle:focus {
    outline: none;
    box-shadow: 0 0 0 4px rgba(107, 124, 240, 0.14);
}

#companies-toggle {
    min-height: 46px;
    padding: 0 14px;
    border: 1px solid #d7dce5;
    border-radius: 14px;
    background: #f8fafc;
    color: #334155;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    cursor: pointer;
    font-size: 14px;
    font-weight: 700;
    transition: background-color 0.2s ease, border-color 0.2s ease, color 0.2s ease, box-shadow 0.2s ease;
}

#companies-toggle svg {
    width: 18px;
    height: 18px;
    display: block;
    fill: currentColor;
}

#companies-toggle:hover,
#companies-toggle.is-open {
    background: #eef2ff;
    border-color: #1042cc;
    color: #1042cc;
}

#companies-toggle:focus {
    outline: none;
    box-shadow: 0 0 0 4px rgba(107, 124, 240, 0.14);
}

#venue-switcher {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: 4px;
    padding: 4px;
    border-radius: 18px;
}

.venue-btn {
    min-height: 44px;
    padding: 10px 12px;
    font-size: 14px;
    font-weight: 700;
    border: none;
    border-radius: 14px;
    background: transparent;
    color: #475569;
    cursor: pointer;
    transition: background-color 0.2s ease, color 0.2s ease, box-shadow 0.2s ease;
    outline: none;
}

.venue-btn:hover {
    background: #eef2ff;
    color: #1042cc;
}

.venue-btn.active {
    background: #1042cc;
    color: white;
    box-shadow: 0 6px 14px rgba(107, 124, 240, 0.35);
}

#filter-panel {
    position: absolute;
    top: 126px;
    left: 10px;
    right: 10px;
    z-index: 1002;
    opacity: 0;
    transform: translateY(-10px);
    pointer-events: none;
    transition: opacity 0.18s ease, transform 0.18s ease;
}

#filter-panel.open {
    opacity: 1;
    transform: translateY(0);
    /* Pointer-events stays off on this wrapper even when open. left/right:10px
       makes it span the map's full width so the visible card can sit near
       either edge, but that means the wrapper's own box reaches far past the
       card, over booths the card never covers. With auto here, that empty
       stretch silently ate every click, including on booths, which is why
       closing the panel only ever worked by clicking the toggle a second
       time: nothing else the panel drew over could receive a click at all. */
}

/* Scoped to .open, not the card unconditionally: the card keeps its layout
   position (just translated 10px and faded) while closed, so an unconditional
   pointer-events: auto here would leave that same dead patch blocking clicks
   even when the panel looks fully gone. A child can re-enable pointer-events
   inside a none parent, which is what lets everywhere else in the wrapper's
   box fall through to the map underneath while this stays clickable. */
#filter-panel.open #filter-panel-card {
    pointer-events: auto;
}

#filter-panel-card {
    border-radius: 18px;
    padding: 14px;
}

/* The panel can list every study field plus opportunities, locations and
   languages, so it scrolls inside itself rather than growing off screen. */
#filter-panel-card {
    max-height: min(70vh, 560px);
    overflow-y: auto;
    width: min(340px, calc(100vw - 20px));
}

.filter-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    padding-bottom: 10px;
    margin-bottom: 4px;
    border-bottom: 1px solid #e6eaf1;
    position: sticky;
    top: -14px;
    background: rgba(255, 255, 255, 0.97);
}

#filter-summary {
    font-weight: 700;
    font-size: 13px;
    color: #334155;
}

#filter-clear {
    border: 1px solid #d7dce5;
    background: #fff;
    color: #334155;
    border-radius: 10px;
    padding: 5px 10px;
    font-size: 12px;
    font-family: inherit;
    cursor: pointer;
}

#filter-clear:hover:not(:disabled) {
    background: #f1f5f9;
}

#filter-clear:disabled {
    opacity: 0.45;
    cursor: default;
}

.filter-group {
    padding: 10px 0 2px;
}

.filter-group-title {
    font-weight: 700;
    font-size: 12px;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: #64748b;
    margin-bottom: 6px;
}

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

.filter-option {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 13px;
    color: #0f172a;
    padding: 5px 6px;
    border-radius: 8px;
    cursor: pointer;
}

.filter-option:hover {
    background: #f1f5f9;
}

.filter-option input {
    width: 16px;
    height: 16px;
    accent-color: #1042cc;
    flex: none;
    cursor: pointer;
}

/* The name inside its own colour, shaped like the same tag on a booth's popup
   and in Pejling. Sized to the text rather than the row, so the tags keep the
   ragged right edge they have everywhere else instead of becoming a block of
   colour bars. The text colour is set per tag in filters.js, since half this
   palette is too pale to carry white. */
.filter-tag {
    padding: 3px 9px;
    border-radius: 6px;
    font-size: 12px;
    font-weight: 600;
    line-height: 1.5;
}

#company-drawer-overlay {
    position: fixed;
    inset: 0;
    z-index: 1300;
    background: rgba(15, 23, 42, 0.2);
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.2s ease;
}

#company-drawer-overlay.open {
    opacity: 1;
    pointer-events: auto;
}

#company-drawer {
    position: absolute;
    top: 0;
    right: 0;
    height: 100%;
    width: min(420px, 92vw);
    border-radius: 0;
    border: none;
    box-shadow: -10px 0 28px rgba(15, 23, 42, 0.22);
    background: rgba(255, 255, 255, 0.98);
    backdrop-filter: blur(8px);
    display: flex;
    flex-direction: column;
    transform: translateX(100%);
    transition: transform 0.22s ease;
}

#company-drawer-overlay.open #company-drawer {
    transform: translateX(0);
}

.company-drawer-header {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 10px;
    padding: max(16px, env(safe-area-inset-top, 0px)) 16px 10px;
    border-bottom: 1px solid #e2e8f0;
}

.company-drawer-header h2 {
    margin: 0;
    font-size: 19px;
    color: #0f172a;
}

#company-drawer-count {
    margin-top: 3px;
    font-size: 13px;
    color: #64748b;
}

#company-drawer-close {
    width: 36px;
    min-width: 36px;
    height: 36px;
    border: 1px solid #d7dce5;
    border-radius: 10px;
    background: #f8fafc;
    color: #334155;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
}

#company-drawer-close svg {
    width: 18px;
    height: 18px;
    fill: currentColor;
}

#company-drawer-close:hover {
    background: #eef2ff;
    border-color: #004f8f;
    color: #006fcc;
}

.company-drawer-mode {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 6px;
    margin: 12px 16px 10px;
    padding: 4px;
    border-radius: 12px;
    background: #eef2f7;
}

/* Same trap as #filter-toggle above: the display rule beats the browser's
   own [hidden] rule, so hiding this on a one-area fair needs saying twice. */
.company-drawer-mode[hidden] {
    display: none !important;
}

.company-mode-btn {
    min-height: 36px;
    border: none;
    border-radius: 9px;
    background: transparent;
    color: #475569;
    font-size: 13px;
    font-weight: 700;
    cursor: pointer;
}

.company-mode-btn.active {
    background: white;
    color: #334155;
    box-shadow: 0 1px 3px rgba(15, 23, 42, 0.12);
}

#company-drawer-list {
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    padding: 0 10px max(16px, env(safe-area-inset-bottom, 0px));
}

.company-drawer-row {
    width: 100%;
    border: none;
    border-radius: 12px;
    background: transparent;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    text-align: left;
    padding: 11px 10px;
    cursor: pointer;
}

.company-drawer-row:hover {
    background: #f1f5ff;
}

.company-drawer-name {
    color: #0f172a;
    font-size: 14px;
    font-weight: 600;
    line-height: 1.3;
}

.company-drawer-meta {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 8px;
}

.company-drawer-booth {
    font-size: 12px;
    font-weight: 700;
    color: #334155;
    border-radius: 999px;
    border: 1px solid #d7dce5;
    background: #f8fafc;
    padding: 3px 8px;
    white-space: nowrap;
}

.company-drawer-area {
    font-size: 11px;
    color: #64748b;
    border-radius: 999px;
    background: #edf2f7;
    padding: 3px 7px;
    white-space: nowrap;
}

/*
 * Language toggle. It lives in the company drawer's header rather than the
 * top bar, because that bar already carries search plus three buttons and is
 * tight at 375px. Most visitors never need it: the map opens in Danish on a
 * Danish phone and in English otherwise.
 */
/* Sized and coloured as #filter-toggle rather than as its own thing: it sits
   in the same row, and a control that is nearly but not quite the same as
   its neighbours reads as a mistake. Two letters wide instead of square,
   because that is what it holds. */
#language-toggle {
    flex: none;
    min-width: 46px;
    height: 46px;
    padding: 0 12px;
    border: 1px solid #d7dce5;
    border-radius: 14px;
    background: #f8fafc;
    color: #334155;
    font-size: 13px;
    font-weight: 700;
    letter-spacing: 0.03em;
    cursor: pointer;
    transition: background-color 0.2s ease, border-color 0.2s ease, color 0.2s ease;
}

#language-toggle:hover {
    background: #eef2ff;
    border-color: #1042cc;
    color: #1042cc;
}

/* --- Favourites -------------------------------------------------------
 *
 * Amber throughout, so a saved booth reads the same in the popup, in the
 * company list and on the floor plan itself. Blue is already what every
 * booth is, which is exactly why saved ones are not blue.
 */

#favourites-toggle {
    width: auto;
    min-width: 46px;
    height: 46px;
    padding: 0 12px;
    border: 1px solid #d7dce5;
    border-radius: 14px;
    background: #f8fafc;
    color: #334155;
    display: inline-flex;
    align-items: center;
    gap: 5px;
    font-size: 14px;
    font-weight: 700;
    cursor: pointer;
    transition: background-color 0.2s ease, border-color 0.2s ease, color 0.2s ease;
}

/* Beaten by the display: inline-flex above without this, the same way the
   filter button needed it. */
#favourites-toggle[hidden] {
    display: none !important;
}

#favourites-toggle svg {
    width: 20px;
    height: 20px;
    fill: #f59e0b;
}

#favourites-toggle.active {
    background: #fef3c7;
    border-color: #f59e0b;
    color: #92722a;
}

.popup-actions {
    display: flex;
    gap: 6px;
    margin-top: 2px;
}

.popup-favourite,
.popup-route {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 5px 12px;
    border-radius: 999px;
    border: 1px solid rgba(255, 255, 255, 0.55);
    background: rgba(255, 255, 255, 0.14);
    color: #fff;
    font-size: 0.78em;
    font-weight: 700;
    cursor: pointer;
}

.popup-favourite svg,
.popup-route svg {
    width: 15px;
    height: 15px;
    fill: none;
    stroke: currentColor;
    stroke-width: 1.8;
}

.popup-favourite.is-active {
    background: #f59e0b;
    border-color: #f59e0b;
    color: #3d2f08;
}

.popup-favourite.is-active svg {
    fill: currentColor;
    stroke: none;
}

/* Green to match the entrance marker and the route line itself, so the
   button that turns it on reads as the same thing as what appears. */
.popup-route.is-active {
    background: #16a34a;
    border-color: #16a34a;
    color: #fff;
}

.popup-route.is-active svg {
    fill: currentColor;
    stroke: none;
}

.company-drawer-item {
    display: flex;
    align-items: center;
    gap: 2px;
}

.company-drawer-item .company-drawer-row {
    flex: 1;
    min-width: 0;
}

.company-drawer-star {
    flex: none;
    /* 44px is the smallest reliable touch target, and this list is used
       one-handed while walking through a hall. */
    width: 44px;
    height: 44px;
    border: none;
    border-radius: 12px;
    background: transparent;
    color: #94a3b8;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
}

.company-drawer-star svg {
    width: 20px;
    height: 20px;
    fill: none;
    stroke: currentColor;
    stroke-width: 1.7;
}

.company-drawer-star:hover {
    background: #f1f5ff;
    color: #64748b;
}

.company-drawer-star.is-active {
    color: #f59e0b;
}

.company-drawer-star.is-active svg {
    fill: currentColor;
    stroke: none;
}

/*
 * A company shown despite an active filter because we hold no data on it
 * along that dimension. Set back rather than hidden: excluding it would make
 * a quarter of Aalborg's exhibitors disappear over a gap in our own records.
 */
.company-drawer-row.is-unknown-for-filters .company-drawer-name {
    color: #64748b;
    font-weight: 500;
}

.company-drawer-unknown-tag {
    font-size: 11px;
    color: #92722a;
    border-radius: 999px;
    background: #fdf3d7;
    padding: 3px 7px;
    white-space: nowrap;
}

.company-drawer-unknown-title {
    margin: 12px 8px 6px;
    font-size: 12px;
    font-weight: 700;
    color: #64748b;
    text-transform: uppercase;
    letter-spacing: 0.04em;
}

.company-drawer-empty {
    padding: 12px 10px;
    color: #64748b;
    font-size: 13px;
}

/* Custom popup styles */
.leaflet-popup-content-wrapper {
    border-radius: 8px;
    padding: 0;
    overflow: hidden;
}

.leaflet-popup-content {
    margin: 0;
    width: 300px !important;
    max-height: min(70vh, 520px);
    overflow-y: auto;
}

/* Everything sits in normal flow. The booth number used to be absolutely
   positioned in the top left corner, which meant any company name long
   enough to reach that corner ran underneath it. */
.popup-header {
    background: linear-gradient(0deg, #1042cc 0%, #2d56c9 100%);
    color: white;
    padding: 12px 12px 10px;
    text-align: center;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 6px;
}

.popup-header img {
    display: block;
    margin: 0;
    border-radius: 4px;
    background: white;
    padding: 4px;
}

.popup-header h3 {
    margin: 0;
    font-size: 1.2em;
    line-height: 1.25;
    overflow-wrap: anywhere;
}

.popup-header .booth-number {
    font-size: 0.8em;
    font-weight: 600;
    padding: 3px 10px;
    border-radius: 999px;
    background: rgba(0, 0, 0, 0.2);
}

.popup-body {
    padding: 10px 12px;
}

.popup-body p {
    margin: 0 0 6px 0;
    line-height: 1.6;
    color: #333;
}

.popup-body .category {
    display: inline-block;
    background: #f0f0f0;
    padding: 4px 8px;
    border-radius: 12px;
    font-size: 0.75em;
    color: #667eea;
    font-weight: 600;
    text-transform: capitalize;
}

.field-tag {
    display: inline-block;
    padding: 6px 10px;
    border-radius: 4px;
    font-size: 0.8em;
    font-weight: 600;
    white-space: nowrap;
}

.popup-footer {
    padding: 10px 15px;
    background: #f9f9f9;
    border-top: 1px solid #eee;
}

/* While a route is shown, the popup keeps only its header (name and
   buttons): the body and footer sit right above the target booth, which is
   exactly where an entrance-to-booth line has to pass. */
.custom-popup.route-open .popup-body,
.custom-popup.route-open .popup-footer {
    display: none;
}

.popup-footer a {
    color: #667eea;
    text-decoration: none;
    font-weight: 600;
}

.popup-footer a:hover {
    text-decoration: underline;
}

/* Zoom controls styling */
.leaflet-control-zoom {
    border: none !important;
    box-shadow: 0 6px 16px rgba(15,23,42,0.18) !important;
}

.leaflet-control-zoom a {
    border-radius: 10px !important;
    color: #667eea !important;
}

/* SVG booth hover effects */
.booth-group {
    transition: opacity 0.3s ease;
}

.booth-group:hover {
    opacity: 0.9;
}

.booth-group:hover .booth-rect {
    filter: brightness(1.1);
}

.booth-number-text {
    pointer-events: none;
    text-shadow: 1px 1px 2px rgba(0,0,0,0.3);
}

/* Mobile responsive */
@media (max-width: 768px) {
    #app-header {
        top: calc(env(safe-area-inset-top, 0px) + 8px);
        gap: 6px;
    }

    #top-controls {
        padding: 5px;
        border-radius: 16px;
    }

    #company-search-input,
    #filter-toggle,
    #companies-toggle,
    .venue-btn {
        min-height: 44px;
    }

    /* The same 44px floor as the controls above, for the two things that were
       sized to their content instead: a 36px close button and a row of link
       pills about 27px tall. Both are fine to hit with a mouse and fiddly with
       a thumb, which is the only way either is ever used at a fair. The rules
       that size them sit earlier in this file, so these win by order. */
    #company-drawer-close {
        width: 44px;
        min-width: 44px;
        height: 44px;
    }

    .site-footer-links a {
        min-height: 44px;
    }

    .filter-option {
        padding: 9px 6px;
    }

    #company-search-input {
        font-size: 14px;
        padding-left: 40px;
    }

    #venue-switcher {
        border-radius: 16px;
    }

    .venue-btn {
        font-size: 13px;
        border-radius: 12px;
        padding: 8px 10px;
    }

    #filter-panel {
        top: calc(env(safe-area-inset-top, 0px) + 112px);
    }

    #filter-panel-card {
        padding: 12px;
        border-radius: 16px;
    }

    #company-search-results {
        max-height: min(240px, 35vh);
    }

    #companies-toggle {
        min-width: 44px;
        padding: 0 10px;
        font-size: 13px;
        gap: 6px;
        white-space: nowrap;
    }

    #companies-toggle svg {
        width: 20px;
        height: 20px;
    }

    #company-drawer {
        top: auto;
        left: 0;
        right: 0;
        bottom: 0;
        width: 100%;
        height: min(82vh, 680px);
        border-radius: 16px 16px 0 0;
        transform: translateY(100%);
    }

    #company-drawer-overlay.open #company-drawer {
        transform: translateY(0);
    }

    .company-drawer-header {
        padding: 12px 12px 8px;
    }

    .company-drawer-mode {
        margin: 10px 12px 8px;
    }

    #company-drawer-list {
        padding: 0 8px max(18px, env(safe-area-inset-bottom, 0px));
    }

    .leaflet-popup-content {
        width: min(240px, calc(100vw - 48px)) !important;
        max-height: min(48vh, 360px);
    }

    .leaflet-popup-content-wrapper {
        border-radius: 10px;
    }

    .popup-header {
        padding: 10px 8px 8px;
    }

    .popup-header h3 {
        font-size: 1.05em;
    }

    .popup-header .booth-number {
        font-size: 0.76em;
        padding: 2px 8px;
    }

    .popup-header img {
        max-width: 48px;
        max-height: 48px;
        margin: 0;
        padding: 3px;
    }

    .popup-body {
        padding: 8px 10px;
    }

    .popup-body p {
        font-size: 13px;
        line-height: 1.45;
    }

    .field-tag {
        padding: 5px 8px;
        font-size: 0.72em;
    }

    .popup-footer {
        padding: 8px 12px;
    }

    .leaflet-control-zoom {
        margin-bottom: calc(env(safe-area-inset-bottom, 0px) + 12px) !important;
    }

    /* Leaflet ships these at 30px. They are the most-pressed controls on the
       map and the ones a thumb reaches for while walking, so they get the
       same 44px floor as everything else rather than keeping a default that
       was drawn for a mouse. !important because Leaflet's own rule is what
       is being overridden, and line-height carries the glyph with the box. */
    .leaflet-control-zoom a {
        width: 44px !important;
        height: 44px !important;
        line-height: 44px !important;
    }

    /* The bar's own row: full width already, but 34px tall on its padding
       alone. It is what a visitor taps to fold DSE's links away, and it sits
       at the very bottom edge where a thumb is least precise. */
    #site-footer-toggle {
        min-height: 44px;
    }
}

/* --- DSE's bottom bar ---------------------------------------------------
 *
 * Anchored to the bottom of the viewport rather than sitting inside #map, so
 * Leaflet never counts it as part of the drawing surface. The strip itself
 * is transparent to the pointer and only its card takes clicks: a bar across
 * the full width would otherwise eat every drag that started near the bottom
 * edge, which on a phone is most of them.
 *
 * Collapsed it is one line. Opening it grows the card upwards, because there
 * is nothing below the bottom of the screen to grow into.
 */

#site-footer {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 1200;
    display: flex;
    flex-direction: column-reverse;
    align-items: stretch;
    gap: 0;
    padding: 0 10px max(8px, env(safe-area-inset-bottom, 0px));
    pointer-events: none;
}

#site-footer[hidden] {
    display: none;
}

#site-footer-toggle,
.site-footer-panel {
    pointer-events: auto;
    background: rgba(255, 255, 255, 0.94);
    backdrop-filter: blur(10px);
    border: 1px solid rgba(226, 232, 240, 0.95);
    box-shadow: 0 10px 24px rgba(15, 23, 42, 0.12);
}

#site-footer-toggle {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    width: 100%;
    padding: 8px 14px;
    border-radius: 12px;
    font: inherit;
    font-size: 0.82em;
    color: #334155;
    text-align: left;
    cursor: pointer;
}

#site-footer.is-open #site-footer-toggle {
    border-radius: 0 0 12px 12px;
    border-top: none;
}

.site-footer-summary {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.site-footer-chevron {
    flex: none;
    width: 8px;
    height: 8px;
    border-right: 2px solid #64748b;
    border-bottom: 2px solid #64748b;
    /* Points up while closed: the card opens upwards. */
    transform: rotate(-135deg) translate(-2px, -2px);
    transition: transform 0.15s ease;
}

#site-footer.is-open .site-footer-chevron {
    transform: rotate(45deg) translate(-1px, -1px);
}

.site-footer-panel {
    padding: 12px 14px;
    border-radius: 12px 12px 0 0;
    border-bottom: none;
}

.site-footer-panel[hidden] {
    display: none;
}

.site-footer-text {
    margin: 0 0 10px;
    font-size: 0.82em;
    line-height: 1.45;
    color: #475569;
}

.site-footer-links {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}

.site-footer-links a {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 6px 12px;
    border: 1px solid #e2e8f0;
    border-radius: 999px;
    background: #f8fafc;
    font-size: 0.8em;
    color: #1e293b;
    text-decoration: none;
}

.site-footer-links a:hover {
    background: #eef2f7;
}

/* Sized in em so the mark tracks the label beside it rather than needing its
   own breakpoint, and filled from the link's colour so both stay one piece. */
.site-footer-links a svg {
    width: 1.25em;
    height: 1.25em;
    flex-shrink: 0;
    fill: currentColor;
}

/* Leaflet's zoom buttons sit in the same bottom right corner (see map.js).
   Lift them clear so the bar never covers the one control a visitor uses
   most. --footer-height is the bar's real height, republished by footer.js
   whenever it changes, because open or closed it is a different number and
   so is each language. The fallback covers the moment before the first
   measurement and is the collapsed row's height on a phone. */
body.has-footer .leaflet-control-zoom {
    margin-bottom: calc(env(safe-area-inset-bottom, 0px) + var(--footer-height, 44px) + 10px) !important;
}

/* The booth popup's company logo. Was an inline style attribute on the <img>
   until a Content-Security-Policy made inline styles worth removing. */
.popup-logo {
    max-width: 110px;
    max-height: 70px;
    margin-bottom: 8px;
}

/* --- Legal pages -------------------------------------------------------
 *
 * privatlivspolitik.html and kolofon.html. Ordinary scrolling documents
 * rather than part of the map, so they undo the full-bleed, no-scroll layout
 * the rest of this file sets up on body.
 */
/* Baade html og body. body alene var ikke nok: html har height: 100% og
   overflow: hidden foroven i denne fil, fordi kortet fylder skaermen og ikke
   maa kunne rulles. Det klippede ogsaa de juridiske sider, saa de 20.845 px
   tekst i privatlivspolitikken stoppede ved foerste skaermbillede og resten
   var ikke til at naa. Klassen saettes derfor paa <html> i de to filer. */
html.legal-page,
body.legal-page {
    height: auto;
    min-height: 100%;
    overflow: visible;
}

body.legal-page {
    background: #f8fafc;
}

.legal {
    max-width: 44rem;
    margin: 0 auto;
    padding: 2rem 1.25rem 4rem;
    color: #1e293b;
    line-height: 1.6;
    font-size: 1rem;
}

.legal h1 {
    font-size: 1.9rem;
    margin: 0 0 0.25rem;
}

.legal h2 {
    font-size: 1.15rem;
    margin: 2rem 0 0.5rem;
}

.legal ul {
    padding-left: 1.25rem;
}

.legal li {
    margin-bottom: 0.4rem;
}

.legal a {
    color: #3b4fd8;
}

.legal hr {
    border: 0;
    border-top: 1px solid #e2e8f0;
    margin: 2.5rem 0;
}

.legal-updated {
    color: #64748b;
    font-size: 0.9rem;
    margin-top: 0;
}

.legal-back {
    margin: 0 0 1.5rem;
}

.legal-back a {
    color: #475569;
    text-decoration: none;
}

.legal-back a:hover,
.legal-back a:focus-visible {
    text-decoration: underline;
}

/* The privacy and imprint links, set apart from the fair's own social links:
   they are an obligation rather than something the fair chose to say. */
.site-footer-legal {
    display: flex;
    gap: 1rem;
    margin-top: 0.75rem;
    padding-top: 0.6rem;
    border-top: 1px solid rgba(100, 116, 139, 0.2);
}

.site-footer-legal a {
    color: #475569;
    font-size: 0.8rem;
    text-decoration: underline;
}

@media (max-width: 768px) {
    /* 44px targets like the rest of the bar on a phone, see PR #7. */
    .site-footer-legal a {
        display: flex;
        align-items: center;
        min-height: 44px;
    }
}
