@import "status-palette-QYhs4CM.css";

:root, [data-theme="light"] {
    --bg: #f4f5f7;
    --surface: #ffffff;
    --surface-alt: #f0f1f4;
    --border: #e2e4e9;
    --text: #1a1d27;
    --text-muted: #6b7084;
    --accent: #DA3628;
    /* Text on an --accent fill, such as the notification count. The same in
       both themes, because the accent does not change either. */
    --on-accent: #ffffff;
    /* Status colours derive from the shared status-palette (single source). */
    --green: var(--status-green);
    --yellow: var(--status-yellow);
    --orange: var(--status-orange);
    --red: var(--status-red);
    --marker-blue: #2563eb;
    /* Open kiosk without a selected signal: a blank marker rather than a
       coloured one. Deliberately NOT --text-muted, which is the "gesloten"
       grey - the two used to be indistinguishable on the map. */
    --marker-no-signal: #ffffff;
    --marker-no-signal-ring: #4b5162;
    --tooltip-shadow: rgba(0,0,0,.12);
    /* Floor-plan tiles stay light in both themes: the drawings themselves have
       a white background baked in, so a dark tile would show as a white slab. */
    --plan-surface: #ffffff;
    --plan-caption-surface: #f0f1f4;
    --plan-caption-text: #6b7084;
}

[data-theme="dark"] {
    --bg: #0f1117;
    --surface: #1a1d27;
    --surface-alt: #222633;
    --border: #2a2e3b;
    --text: #e4e6ed;
    --text-muted: #8b8fa3;
    /* --green/--orange/--red follow the shared status-palette dark override. */
    --marker-blue: #3b82f6;
    --marker-no-signal: #10131a;
    --marker-no-signal-ring: #9aa0b4;
    --tooltip-shadow: rgba(0,0,0,.4);
    /* Deliberately NOT flipped to a dark surface - see the light block above.
       The caption is dimmed instead so the tile does not glare in dark mode. */
    --plan-caption-surface: #d8dae1;
    --plan-caption-text: #4a4f60;
}

body {
    font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Inter, sans-serif;
    background: var(--bg);
    color: var(--text);
    min-height: 100vh;
}

/* Since the 2026-08 rebuild there is no left sidebar (scope decision):
   logo, view switcher and Admin/log-out live in the top bar. */
.topbar-logo {
    display: flex; align-items: center;
    flex-shrink: 0;
    text-decoration: none;
}
.topbar-logo-img {
    display: block;
    height: 34px;
    width: auto;
    /* White chip behind the logo: the source is dark-on-transparent and
       would disappear in the dark theme. */
    background: #fff;
    padding: 5px 9px;
    border-radius: 8px;
    box-sizing: border-box;
    /* In light mode the chip is invisible (white on white); compensate
       the inner padding so the logo glyphs optically align with "Weergave:"
       and the filter selects on the 20px gutter below. In dark mode the chip
       is visible and its edge should sit on the gutter instead. */
    margin-left: -9px;
}
[data-theme="dark"] .topbar-logo-img { margin-left: 0; }

/* View switcher: segmented buttons (single view today, plugs back in). */
.view-switcher {
    display: flex;
    gap: 4px;
    padding: 3px;
    border-radius: 10px;
    background: var(--surface-alt);
    border: 1px solid var(--border);
    flex-shrink: 0;
}
.view-tab {
    display: flex; align-items: center; gap: 7px;
    padding: 6px 12px;
    border-radius: 8px;
    cursor: pointer;
    color: var(--text-muted);
    background: none;
    border: none;
    font-family: inherit;
    font-size: 12px;
    font-weight: 600;
    white-space: nowrap;
    transition: all .15s;
}
.view-tab svg { flex-shrink: 0; stroke: currentColor; }
.view-tab:hover { color: var(--text); background: var(--border); }
.view-tab.active {
    color: #fff;
    background: var(--accent);
}
.view-tab.active svg { stroke: #fff; }
.topbar-logout-form { margin: 0; padding: 0; display: flex; }

.main {
    display: flex;
    flex-direction: column;
    height: 100vh;
}

.topbar {
    padding: 12px 20px;
    border-bottom: 1px solid var(--border);
    display: flex;
    align-items: center;
    gap: 16px;
    flex-shrink: 0;
    background: var(--surface);
    /* Boven de Leaflet-panes; blijft onder de mobiele drawer (950). */
    position: relative;
    z-index: 930;
}
/* Counters of the filtered map view; they live on the view-selection row
   (.category-bar), right-aligned next to the category buttons. */
.stat-pills {
    display: flex; gap: 6px;
    margin-left: auto;
    flex-wrap: wrap;
}
.pill {
    display: inline-flex; align-items: baseline; gap: 6px;
    padding: 6px 12px;
    border-radius: 8px;
    font-size: 12px;
    background: var(--surface-alt);
    border: 1px solid var(--border);
    color: var(--text);
    font-family: inherit;
}
button.pill {
    cursor: pointer;
    transition: background .15s, border-color .15s, color .15s;
}
button.pill:hover {
    background: var(--border);
    border-color: var(--text-muted);
}
button.pill.active {
    background: var(--accent);
    color: #fff;
    border-color: var(--accent);
}
button.pill.active .dot { box-shadow: 0 0 0 1px rgba(255,255,255,.4); }
.pill .num {
    font-weight: 800;
    font-size: 14px;
    font-variant-numeric: tabular-nums;
    line-height: 1;
}
.pill .dot {
    width: 7px; height: 7px; border-radius: 50%;
    align-self: center;
}
.dot-green { background: var(--green); }
.dot-orange { background: var(--orange); }
.dot-red { background: var(--red); }

/* Colour-blind safety: shape per band via CSS mask-image. Square for green
   (stable/OK), triangle for orange (warning/attention), X for red
   (stop/wrong). Shapes don't collide with the HACCP trend chart's
   circle/diamond glyphs (which encode source, not band). */
.pill .dot[data-band],
.legal-docs-pill .dot[data-band] {
    border-radius: 0;
    -webkit-mask-repeat: no-repeat;
            mask-repeat: no-repeat;
    -webkit-mask-position: center;
            mask-position: center;
    -webkit-mask-size: contain;
            mask-size: contain;
}
.pill .dot[data-band="green"],
.legal-docs-pill .dot[data-band="green"] {
    -webkit-mask-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 10'><rect width='10' height='10' fill='black'/></svg>");
            mask-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 10'><rect width='10' height='10' fill='black'/></svg>");
}
.pill .dot[data-band="orange"],
.legal-docs-pill .dot[data-band="orange"] {
    -webkit-mask-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 10'><polygon points='5,0 10,10 0,10' fill='black'/></svg>");
            mask-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 10'><polygon points='5,0 10,10 0,10' fill='black'/></svg>");
}
.pill .dot[data-band="red"],
.legal-docs-pill .dot[data-band="red"] {
    -webkit-mask-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 10'><path d='M1,1 L9,9 M9,1 L1,9' stroke='black' stroke-width='2.5' stroke-linecap='round'/></svg>");
            mask-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 10'><path d='M1,1 L9,9 M9,1 L1,9' stroke='black' stroke-width='2.5' stroke-linecap='round'/></svg>");
}

/* The existing `button.pill.active .dot { box-shadow: 0 0 0 1px rgba(255,255,255,.4); }`
   draws a ring around the element's BORDER-BOX, not the masked silhouette. With
   triangle/X masks that ring would render as a phantom square outside the shape.
   Drop the box-shadow for masked dots, and invert their colour to white when the
   parent pill is active (its red background swallows same-band shapes otherwise).

   The .legal-docs-pill .dot[data-band] half of the comma-separated rules
   above is the only consumer of [data-band] now; pills themselves use
   [data-tone]. */

.topbar-right { margin-left: auto; display: flex; align-items: center; gap: 8px; }
.search-box {
    display: flex; align-items: center; gap: 6px;
    background: var(--surface-alt); border: 1px solid var(--border);
    border-radius: 8px; padding: 6px 12px;
}
.search-box svg { stroke: var(--text-muted); flex-shrink: 0; }
.search-box input {
    background: none; border: none; color: var(--text);
    font-size: 13px; outline: none; width: 240px; font-family: inherit;
}
.search-box input::placeholder { color: var(--text-muted); }
.search-box:focus-within {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
}

.search-kbd {
    font-family: ui-monospace, 'SF Mono', Menlo, Consolas, monospace;
    font-size: 11px;
    padding: 2px 6px;
    border-radius: 4px;
    border: 1px solid var(--border);
    /* --surface is lighter than search-box's --surface-alt in light theme,
       and darker in dark theme — both give the keycap visual prominence
       against its parent. Re-evaluate if dark-theme contrast feels weak. */
    background: var(--surface);
    color: var(--text-muted);
    line-height: 1;
    font-weight: 600;
    user-select: none;
}
.search-box:focus-within .search-kbd { display: none; }
@media (hover: none) { .search-kbd { display: none; } }

/* View tabs (.view-tab) live in the top-bar view switcher (.view-switcher) */

.filter-bar {
    padding: 8px 20px;
    border-bottom: 1px solid var(--border);
    display: flex; gap: 8px; align-items: center;
    background: var(--surface);
    flex-shrink: 0;
    min-height: 40px;
}
.filter-select.tab-hidden { display: none; }
.filter-bar-notice {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    margin: 0;
    padding: 0 10px 0 8px;
    height: 26px;
    border-radius: 6px;
    font-size: 12px;
    font-weight: 500;
    color: var(--text-muted);
    background: color-mix(in srgb, var(--orange) 8%, transparent);
    border-left: 2px solid var(--orange);
}
.filter-bar-notice svg {
    stroke: var(--orange);
    flex-shrink: 0;
}
.filter-bar-notice[hidden] { display: none; }

.filter-reset {
    /* Sits inline with the filter selects via the filter-bar's own gap. */
    margin-left: 8px;
    padding: 5px 12px;
    border-radius: 6px;
    font-size: 12px;
    font-family: inherit;
    color: var(--text-muted);
    background: transparent;
    border: 1px solid var(--border);
    cursor: pointer;
    transition: background .15s, color .15s, border-color .15s;
    animation: filter-reset-in .2s ease-out;
}
.filter-reset:hover {
    background: var(--surface-alt);
    color: var(--text);
    border-color: var(--text-muted);
}
.filter-reset:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
}
.filter-reset[hidden] { display: none; }

@keyframes filter-reset-in {
    from { opacity: 0; }
    to   { opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
    .filter-reset { animation: none; }
}

/* On mobile the filter-bar wraps; an auto-margin pushes the button up or
   left unexpectedly. Reset here so it stays after the notice/selects. */
@media (max-width: 800px) {
    .filter-reset { margin-left: 0; }
}

.filter-select {
    padding: 5px 10px; border-radius: 6px; font-size: 12px;
    border: 1px solid var(--border); background: var(--surface-alt);
    color: var(--text); font-family: inherit; cursor: pointer;
}
.filter-select:focus { outline: 2px solid var(--accent); outline-offset: -1px; }

.topbar-freshness {
    font-size: 11px;
    color: var(--text-muted);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
    user-select: none;
}
.topbar-freshness[hidden] { display: none; }
.topbar-freshness time { font-weight: 600; }

.topbar-btn {
    width: 34px; height: 34px;
    border-radius: 8px;
    border: 1px solid var(--border);
    background: var(--surface-alt);
    color: var(--text-muted);
    cursor: pointer;
    display: flex; align-items: center; justify-content: center;
    transition: all .15s;
}
.topbar-btn:hover { color: var(--text); background: var(--border); }
.topbar-btn svg { width: 16px; height: 16px; }

/* Notification bell (SUSHI-73). The count sits on the button's top-right
   corner, ringed in the bar's own surface so it reads as a separate mark. */
.topbar-bell { position: relative; }
.topbar-bell .notification-bell-count {
    position: absolute;
    top: -6px;
    right: -6px;
    min-width: 18px;
    height: 18px;
    padding: 0 4px;
    border-radius: 9px;
    border: 2px solid var(--surface);
    background: var(--accent);
    color: var(--on-accent);
    font-size: 10px;
    font-weight: 700;
    line-height: 14px;
    text-align: center;
}

.content {
    flex: 1;
    display: grid;
    grid-template-columns: 1fr 380px;
    overflow: hidden;
}

.map-wrap {
    position: relative;
    background: var(--surface-alt);
}

#map { width: 100%; height: 100%; }

.side-panel {
    border-left: 1px solid var(--border);
    background: var(--surface);
    overflow-y: auto;
    display: flex;
    flex-direction: column;
}
.panel-header {
    padding: 18px 20px;
    border-bottom: 1px solid var(--border);
}
.panel-header h2 { font-size: 18px; font-weight: 700; }
.panel-header .muted { font-size: 12px; color: var(--text-muted); margin-top: 4px; }
.panel-body {
    padding: 16px 20px;
    display: flex;
    flex-direction: column;
    gap: 12px;
}
.empty-state { color: var(--text-muted); font-size: 13px; }

/* Top/Bottom-5 ranking widget op de Omzet-tab. Staat tussen panel-header en
   panel-body, alleen zichtbaar wanneer tab=omzet. Compact zodat de kiosk-lijst
   eronder zichtbaar blijft zonder scroll bij gemiddelde scherm-grootte. */
.rankings-card {
    display: flex;
    flex-direction: column;
    gap: 14px;
    padding: 14px 20px;
    border-bottom: 1px solid var(--border);
    background: var(--surface-2, var(--surface));
}
.rankings-section { display: flex; flex-direction: column; gap: 6px; }
.rankings-title {
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.05em;
    text-transform: uppercase;
    color: var(--text-muted);
}
.rankings-list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 4px;
    counter-reset: rankings;
}
.rankings-list li {
    counter-increment: rankings;
    display: block;
}
.rankings-row {
    display: grid;
    grid-template-columns: 18px 1fr auto auto;
    gap: 8px;
    align-items: center;
    width: 100%;
    padding: 6px 8px;
    background: transparent;
    border: 1px solid transparent;
    border-radius: 6px;
    color: inherit;
    text-align: left;
    cursor: pointer;
    font-size: 12px;
    transition: background-color 0.12s ease, border-color 0.12s ease;
}
.rankings-row::before {
    content: counter(rankings) ".";
    color: var(--text-muted);
    font-variant-numeric: tabular-nums;
    font-size: 11px;
}
.rankings-row:hover,
.rankings-row:focus-visible {
    background: var(--hover, rgba(0, 0, 0, 0.04));
    border-color: var(--border);
    outline: none;
}
.rankings-name {
    font-weight: 500;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    min-width: 0;
}
.rankings-formula {
    color: var(--text-muted);
    font-size: 10px;
    text-transform: uppercase;
    letter-spacing: 0.04em;
}
.rankings-delta {
    font-weight: 700;
    font-variant-numeric: tabular-nums;
}
.rankings-row--above .rankings-delta { color: var(--green); }
.rankings-row--below .rankings-delta { color: var(--red); }

/* Per-categorie ticket-samenvatting op de Tickets-tab. Zelfde plek als de
   Omzet-rankings (tussen panel-header en panel-body), alleen zichtbaar wanneer
   tab=tickets. Rijen linken door naar de admin ticket-lijst per categorie. */
.category-summary-card {
    padding: 14px 20px;
    border-bottom: 1px solid var(--border);
    background: var(--surface-2, var(--surface));
}
.category-summary-title {
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.05em;
    text-transform: uppercase;
    color: var(--text-muted);
    margin-bottom: 8px;
}
.category-summary-table {
    width: 100%;
    border-collapse: collapse;
    font-size: 12px;
}
.category-summary-table th {
    text-align: left;
    font-weight: 600;
    color: var(--text-muted);
    padding: 4px 6px;
    border-bottom: 1px solid var(--border);
}
.category-summary-table th:not(:first-child),
.category-summary-table td.cat-sum-num {
    text-align: right;
    font-variant-numeric: tabular-nums;
    width: 56px;
}
.category-summary-table td {
    padding: 5px 6px;
    border-bottom: 1px solid var(--border);
}
.category-summary-table tr:last-child td { border-bottom: none; }
.cat-sum-name { color: var(--text); }
.cat-sum-link { color: inherit; text-decoration: none; }
.cat-sum-link:hover,
.cat-sum-link:focus-visible { text-decoration: underline; outline: none; }
.cat-sum-overdue { color: var(--red); font-weight: 700; }
.cat-sum-empty { color: var(--text-muted); text-align: left; }

.kiosk-list-empty {
    display: flex;
    flex-direction: column;
    gap: 10px;
    align-items: flex-start;
    padding: 8px 4px;
}
.kiosk-list-empty p { margin: 0; }
.kiosk-list-empty-reset {
    padding: 5px 12px;
    border-radius: 6px;
    font-size: 12px;
    font-family: inherit;
    color: var(--accent);
    background: transparent;
    border: 1px solid var(--accent);
    cursor: pointer;
    transition: background .15s, color .15s;
}
.kiosk-list-empty-reset:hover {
    background: var(--accent);
    color: #fff;
}
.kiosk-list-empty-reset:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
}
.muted { color: var(--text-muted); }

/* -- Kiosk list -- */
.kiosk-list { display: flex; flex-direction: column; gap: 2px; }
.kiosk-list-item {
    display: flex; align-items: center; gap: 10px;
    padding: 10px 12px; border-radius: 8px;
    background: transparent; border: none; cursor: pointer;
    text-align: left; font: inherit; color: var(--text);
    transition: background .12s;
    width: 100%;
}
.kiosk-list-item:hover { background: var(--surface-alt); }
.kli-score {
    width: 36px; height: 36px; border-radius: 8px;
    display: flex; align-items: center; justify-content: center;
    font-size: 13px; font-weight: 800; color: #fff; flex-shrink: 0;
}
.kli-score[data-band="green"] { background: var(--green); }
.kli-score[data-band="orange"] {
    /* Diagonal stripes on the orange fill — extra CVD cue. */
    background:
        repeating-linear-gradient(
            45deg,
            rgba(255,255,255,0) 0,
            rgba(255,255,255,0) 4px,
            rgba(255,255,255,0.12) 4px,
            rgba(255,255,255,0.12) 6px
        ),
        var(--orange);
}
.kli-score[data-band="red"] {
    /* Cross-hatch on the red fill — denser than orange, also legible in greyscale. */
    background:
        repeating-linear-gradient(
            45deg,
            rgba(255,255,255,0) 0,
            rgba(255,255,255,0) 3px,
            rgba(255,255,255,0.14) 3px,
            rgba(255,255,255,0.14) 5px
        ),
        repeating-linear-gradient(
            -45deg,
            rgba(255,255,255,0) 0,
            rgba(255,255,255,0) 3px,
            rgba(255,255,255,0.14) 3px,
            rgba(255,255,255,0.14) 5px
        ),
        var(--red);
}
.kli-score[data-band="none"] { background: var(--border); color: var(--text-muted); }
.kli-info { flex: 1; min-width: 0; }
.kli-name { font-size: 13px; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.kli-meta { font-size: 11px; color: var(--text-muted); }
.kli-formula {
    font-size: 11px; color: var(--text-muted); flex-shrink: 0;
}
.kli-noloc {
    color: var(--orange); font-size: 11px; cursor: help; margin-left: 4px;
}

/* -- Open ticket named on the row --
   One line: the subject, who it is with, and how many others are open. The
   subject truncates rather than wrapping, so a long one cannot push a row to
   twice the height of its neighbours and break the scan down the list. */
.kli-ticket {
    font-size: 11px;
    margin-top: 3px;
    min-width: 0;
}
.kli-ticket-subject {
    align-items: baseline;
    display: flex;
    gap: 4px;
    min-width: 0;
}
/* Overdue is spelled out, not only coloured: this line is scanned, and colour
   on its own would carry the most important state on it. */
.kli-ticket-late {
    color: var(--red);
    flex-shrink: 0;
    font-weight: 700;
    text-transform: uppercase;
}
.kli-ticket-title {
    color: var(--text);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
/* Who it is with, plus how many others are open. Muted and unbadged on
   purpose: it is a footnote to the subject, and a second colour on this row
   would compete with the band chip on the left. */
.kli-ticket-who {
    color: var(--text-muted);
    display: block;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* -- Back to list -- */
.back-to-list {
    color: var(--text-muted); text-decoration: none;
    font-size: 16px; margin-right: 6px;
}
.back-to-list:hover { color: var(--accent); }

/* -- Visit type widgets (3 laatste-datums per type) -- */
.visit-type-row {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 8px;
    margin-bottom: 12px;
}
.visit-type-cell {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 8px;
    padding: 10px 12px;
    text-align: center;
}
.visit-type-label {
    font-size: 10px;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--text-muted);
    font-weight: 700;
    margin-bottom: 4px;
}
.visit-type-date {
    font-size: 13px;
    font-weight: 700;
    color: var(--text);
}
.visit-type-date.is-empty { color: var(--text-muted); font-weight: 400; }

.visit-latest {
    margin-top: 8px;
    padding-top: 8px;
    border-top: 1px solid var(--border);
    font-size: 12px;
    color: var(--text-muted);
}

/* Quick-note CTA: vanaf het kiosk-detail panel direct een bezoek vastleggen.
   Alleen zichtbaar voor users met VisitVoter::EDIT (winkelondersteuning,
   HACCP-manager) - server-side gegated in KioskSerializer. */
.btn-quick-visit {
    display: inline-flex; align-items: center; gap: 6px;
    margin-top: 12px;
    padding: 8px 14px;
    background: var(--accent);
    color: #fff !important;
    border-radius: 8px;
    font-size: 13px;
    font-weight: 600;
    text-decoration: none;
    transition: filter 0.15s ease;
}
.btn-quick-visit:hover,
.btn-quick-visit:focus {
    filter: brightness(0.92);
    text-decoration: none;
}
.btn-quick-visit svg { flex-shrink: 0; }

/* -- Revenue card -- */
.revenue-row { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; }
.revenue-big {
    font-size: 30px; font-weight: 800; line-height: 1;
    color: var(--text);
}
.revenue-delta {
    font-size: 12px;
    font-weight: 600;
    padding: 3px 8px;
    border-radius: 999px;
}
.revenue-delta.rev-up {
    background: color-mix(in srgb, var(--green) 12%, transparent);
    color: var(--green);
}
.revenue-delta.rev-down {
    background: color-mix(in srgb, var(--red) 12%, transparent);
    color: var(--red);
}
.revenue-benchmarks {
    display: flex;
    gap: 6px;
    margin-top: 8px;
    flex-wrap: wrap;
}
.revenue-benchmark-chip {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    font-size: 11px;
    font-weight: 600;
    padding: 3px 8px;
    border-radius: 999px;
    background: color-mix(in srgb, var(--text-muted) 8%, transparent);
    color: var(--text);
    line-height: 1.4;
}
.revenue-benchmark-chip .chip-label {
    font-weight: 500;
    color: var(--text-muted);
}
.revenue-benchmark-chip.rev-up {
    background: color-mix(in srgb, var(--green) 10%, transparent);
}
.revenue-benchmark-chip.rev-down {
    background: color-mix(in srgb, var(--red) 10%, transparent);
}
.card {
    background: var(--surface-alt);
    border: 1px solid var(--border);
    border-radius: 10px;
    padding: 14px;
    font-size: 13px;
    line-height: 1.5;
}
.card-label {
    font-size: 11px;
    font-weight: 700;
    text-transform: uppercase;
    color: var(--text-muted);
    letter-spacing: .04em;
    margin-bottom: 8px;
}
.card hr { border: none; border-top: 1px solid var(--border); margin: 8px 0; }

/* Secondary contacts on the kiosk panel: quieter than .card-label so the primary
   contacts above stay the focus, with the type acting as a group heading. */
.card-sublabel {
    font-size: 11px;
    font-weight: 700;
    text-transform: uppercase;
    color: var(--text-muted);
    letter-spacing: .04em;
    margin-bottom: 6px;
}
.contact-group { margin-bottom: 8px; }
.contact-group:last-child { margin-bottom: 0; }
.contact-group > strong { display: block; font-size: 12px; }
.contact-person + .contact-person { margin-top: 6px; }
/* Long addresses must not force the panel to scroll sideways. */
.contact-reach { font-size: 12px; overflow-wrap: anywhere; }
.score-row { display: flex; align-items: center; gap: 16px; }
.score-big {
    position: relative;
    font-size: 36px;
    font-weight: 800;
    line-height: 1;
    padding: 8px 12px;
    border-radius: 10px;
    color: #fff;
}
.score-big[data-band="green"] { background: var(--green); }
.score-big[data-band="orange"] { background: var(--orange); }
.score-big[data-band="red"] { background: var(--red); }

/* Corner glyph mirrors the pill shape language: square (green) / triangle
   (orange) / X (red). White on the band-coloured background. Empty-state
   badges have no `data-band` so no glyph renders. Top-right placement
   avoids overlapping the score digits (which sit bottom-heavy in the 36px
   font box). */
.score-big[data-band]::after {
    content: '';
    position: absolute;
    top: 4px;
    right: 4px;
    width: 10px;
    height: 10px;
    background-color: rgba(255, 255, 255, 0.85);
    -webkit-mask-repeat: no-repeat;
            mask-repeat: no-repeat;
    -webkit-mask-position: center;
            mask-position: center;
    -webkit-mask-size: contain;
            mask-size: contain;
    pointer-events: none;
}
.score-big[data-band="green"]::after {
    -webkit-mask-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 10'><rect width='10' height='10' fill='black'/></svg>");
            mask-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 10'><rect width='10' height='10' fill='black'/></svg>");
}
.score-big[data-band="orange"]::after {
    -webkit-mask-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 10'><polygon points='5,0 10,10 0,10' fill='black'/></svg>");
            mask-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 10'><polygon points='5,0 10,10 0,10' fill='black'/></svg>");
}
.score-big[data-band="red"]::after {
    /* viewBox 12 + stroke 3 matches the pill X's effective stroke ratio (~25% of
       rendered size). Pill is 7×7 with viewBox 10 stroke 2.5 ≈ 1.75px effective;
       corner is 12×12 with viewBox 12 stroke 3 ≈ 3px effective — consistent ratio. */
    -webkit-mask-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'><path d='M1.5,1.5 L10.5,10.5 M10.5,1.5 L1.5,10.5' stroke='black' stroke-width='3' stroke-linecap='round'/></svg>");
            mask-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'><path d='M1.5,1.5 L10.5,10.5 M10.5,1.5 L1.5,10.5' stroke='black' stroke-width='3' stroke-linecap='round'/></svg>");
}

.score-big.is-empty {
    background: transparent;
    color: var(--text-muted);
    border: 1.5px dashed var(--border);
    padding: 6px 12px;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
}
.score-meta { font-size: 12px; line-height: 1.6; }

/* ─── HACCP split cards: internal (Sushi Lin) vs external (Bureau de Wit etc.) ─── */
.haccp-card {
    position: relative;
    padding-block: 16px;
    overflow: hidden;
}
.haccp-card + .haccp-card {
    margin-top: 10px;
}
.haccp-card .score-row {
    align-items: flex-start;
    gap: 14px;
}
.haccp-eyebrow {
    display: flex;
    align-items: baseline;
    gap: 8px;
    margin-bottom: 12px;
}
.haccp-eyebrow-tag {
    font-size: 10px;
    font-weight: 800;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    padding: 2px 7px;
    border-radius: 3px;
    line-height: 1.4;
}
.haccp-eyebrow-sub {
    font-size: 12px;
    color: var(--text-muted);
    letter-spacing: 0.01em;
}
.haccp-meta {
    font-size: 13px;
    color: var(--text);
    line-height: 1.4;
}
.haccp-when {
    font-weight: 600;
    color: var(--text);
}
.haccp-meta-sub {
    font-size: 11px;
    color: var(--text-muted);
    margin-top: 2px;
    font-variant-numeric: tabular-nums;
}
.haccp-meta-next {
    font-size: 12px;
    color: var(--text-muted);
    margin-top: 8px;
    padding-top: 8px;
    border-top: 1px dashed var(--border);
}
.haccp-meta-empty {
    color: var(--text-muted);
    font-style: italic;
    font-size: 12px;
}

/* Internal card: subtle red-accent left edge — owns operational rhythm. */
.haccp-card--internal {
    border-left: 3px solid var(--accent);
}
.haccp-card--internal .haccp-eyebrow-tag {
    background: rgba(218, 54, 40, 0.10);
    color: var(--accent);
}

/* External card: cooler steel-blue accent — formal/institutional tone. */
.haccp-card--external {
    border-left: 3px solid #5b6b85;
}
.haccp-card--external .haccp-eyebrow-tag {
    background: rgba(91, 107, 133, 0.14);
    color: #5b6b85;
}
[data-theme="dark"] .haccp-card--external {
    border-left-color: #7a8aa6;
}
[data-theme="dark"] .haccp-card--external .haccp-eyebrow-tag {
    background: rgba(122, 138, 166, 0.18);
    color: #a4b2cb;
}

.haccp-card.is-empty {
    background: transparent;
}
.haccp-card.is-empty .haccp-eyebrow-tag {
    opacity: 0.65;
}

.haccp-trend-card {
    margin-top: 10px;
}

.haccp-trend-card .card-header-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    margin-bottom: 10px;
}

.haccp-trend-legend {
    display: inline-flex;
    gap: 4px;
}

.haccp-trend-chip {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 3px 9px;
    font-size: 11px;
    font-weight: 600;
    line-height: 1.4;
    color: var(--text-muted);
    background: transparent;
    border: 1px solid var(--border);
    border-radius: 999px;
    cursor: pointer;
    font-family: inherit;
    transition: color 0.12s, border-color 0.12s, background 0.12s;
}

.haccp-trend-chip:hover {
    color: var(--text);
    border-color: var(--text-muted);
}

.haccp-trend-chip[aria-pressed="false"] {
    color: var(--text-muted);
    opacity: 0.55;
    background: transparent;
}

.haccp-trend-chip[aria-pressed="true"] {
    color: var(--text);
    background: var(--surface);
}

.haccp-trend-chip[aria-disabled="true"] {
    opacity: 0.3;
    cursor: not-allowed;
    pointer-events: none;
}

.haccp-trend-chip-glyph {
    width: 10px;
    height: 10px;
    background: currentColor;
    flex-shrink: 0;
}

.haccp-trend-chip-glyph--circle {
    border-radius: 50%;
}

.haccp-trend-chip-glyph--diamond {
    transform: rotate(45deg);
}
.visit-notes {
    margin-top: 8px;
    color: var(--text);
    font-size: 12px;
    background: var(--surface);
    border-radius: 6px;
    padding: 8px 10px;
    border: 1px solid var(--border);
}

.trend-wrap {
    margin-top: 14px;
    height: 140px;
    position: relative;
}
.trend-wrap canvas { max-width: 100%; }

/* -- Locate me button -- */
#locate-me.locating { animation: spin .8s linear infinite; }
@keyframes spin { 100% { transform: rotate(360deg); } }

/* -- Proximity banner -- */
#proximity-banner {
    position: absolute; bottom: 20px; left: 50%; transform: translateX(-50%);
    z-index: 150; display: none;
}
.proximity-inner {
    display: flex; align-items: center; gap: 8px;
    background: var(--surface); border: 1px solid var(--border);
    border-radius: 10px; padding: 10px 16px;
    box-shadow: 0 4px 16px var(--tooltip-shadow);
    font-size: 13px; white-space: nowrap;
}
.proximity-inner svg { stroke: #2563eb; flex-shrink: 0; }
.proximity-close {
    background: none; border: none; font-size: 18px; cursor: pointer;
    color: var(--text-muted); padding: 0 0 0 8px; line-height: 1;
}
.proximity-close:hover { color: var(--text); }

/* -- User location marker -- */
.user-loc-marker { filter: drop-shadow(0 0 6px rgba(37,99,235,.5)); }

/* -- Status badges -- */
.badge { display: inline-block; padding: 1px 7px; border-radius: 4px; font-size: 10px; font-weight: 700; line-height: 1.6; letter-spacing: .02em; white-space: nowrap; }
.badge-operatie { background: rgba(232,93,58,.15); color: var(--accent); }
.badge-warning { background: rgba(217,119,6,.18); color: #b45309; }

/* -- Checklist rows, shared by the legal-documents and tickets cards -- */
.opening-checklist { display: flex; flex-direction: column; gap: 6px; }
.checklist-item { display: flex; align-items: center; gap: 8px; font-size: 12px; line-height: 1.5; }
.checklist-icon { width: 18px; height: 18px; border-radius: 50%; display: flex; align-items: center; justify-content: center; flex-shrink: 0; font-size: 10px; }
.checklist-icon.done { background: var(--green); color: #fff; }
.checklist-icon.pending { background: var(--border); color: var(--text-muted); }
.checklist-label { flex: 1; color: var(--text); }
.checklist-item.is-done .checklist-label { text-decoration: line-through; color: var(--text-muted); }

/* Deeplink-rij naar admin (legal docs). Onderscheidt zich subtiel van een
   info-only rij via hover; padding + tap target zodat hij op mobiel ook
   duidelijk klikbaar is. */
a.checklist-item.is-deeplink {
    text-decoration: none;
    color: inherit;
    padding: 4px 6px;
    margin: -4px -6px;
    border-radius: 6px;
    transition: background-color .15s;
    cursor: pointer;
}
a.checklist-item.is-deeplink:hover {
    background: color-mix(in srgb, var(--accent) 8%, transparent);
}
a.checklist-item.is-deeplink:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 1px;
}
a.checklist-item.is-deeplink .checklist-label {
    cursor: pointer;
}

/* -- Legal documents card -- */
.card-header-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: 8px;
    gap: 8px;
}
.card-header-row .card-label { margin-bottom: 0; }
.legal-docs-pill {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 2px 8px;
    border-radius: 999px;
    background: var(--surface);
    border: 1px solid var(--border);
    font-size: 11px;
    font-weight: 700;
    color: var(--text-muted);
    white-space: nowrap;
}
.legal-docs-pill .dot {
    width: 7px;
    height: 7px;
    border-radius: 50%;
    flex-shrink: 0;
}
.legal-franchisee-name {
    font-size: 12px;
    font-weight: 700;
    color: var(--text);
    margin: 6px 0 4px;
}
.legal-inline-checks {
    font-size: 14px;
    color: var(--green);
    letter-spacing: 4px;
    line-height: 1.2;
}
.legal-empty {
    color: var(--text-muted);
    font-size: 12px;
    font-style: italic;
}
/* A document row keeps its status, file name and approve button beside the
   title while they fit. A pending upload carries all three, which is wider
   than the card, so then the group drops below the title as one unit and the
   file name gives way first, rather than the button running out of the card. */
.legal-doc-row { flex-wrap: wrap; row-gap: 4px; }
.legal-doc-row .checklist-label { flex: 1 1 0; }
.legal-doc-meta {
    display: flex;
    align-items: center;
    gap: 6px;
    margin-left: auto;
    min-width: 0;
    max-width: 100%;
}
.legal-doc-link {
    flex: 0 1 auto;
    min-width: 2.5rem;
    font-size: 11px;
    color: var(--accent);
    text-decoration: none;
    max-width: 140px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.legal-doc-link:hover { text-decoration: underline; }

.legal-doc-approve-cta {
    font-size: 11px;
    font-weight: 600;
    color: #fff;
    background: var(--green);
    padding: 2px 8px;
    border-radius: 4px;
    text-decoration: none;
    white-space: nowrap;
}
.legal-doc-approve-cta:hover { background: color-mix(in srgb, var(--green) 85%, black); }

/* -- Tickets card --
   Rows reuse .checklist-item.is-deeplink but stack the title above a wrapping
   meta line (priority/status/deadline/assignee), so a long title never squeezes
   the badges. */
.ticket-list .ticket-row {
    flex-direction: column;
    align-items: stretch;
    gap: 4px;
}
.ticket-title { font-weight: 600; }
.ticket-meta {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 6px;
    font-size: 11px;
    color: var(--text-muted);
}
.ticket-priority { font-weight: 700; }
.ticket-priority--critical { background: color-mix(in srgb, var(--red) 15%, transparent); color: var(--red); }
.ticket-priority--high     { background: color-mix(in srgb, var(--orange) 18%, transparent); color: var(--orange); }
/* medium + low share the quiet treatment — no visual distinction by design. */
.ticket-priority--medium,
.ticket-priority--low      { background: var(--surface-alt); color: var(--text-muted); }
/* Status is a state light rather than a chip like priority beside it: the dot
   carries the colour and the label stays plain. The .dot sizing rules elsewhere
   in this file are scoped to .pill / .legal-docs-pill, so it needs its own. */
.ticket-status {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    white-space: nowrap;
}
.ticket-status .dot {
    width: 7px;
    height: 7px;
    border-radius: 50%;
    flex-shrink: 0;
}
.ticket-deadline { white-space: nowrap; }
.ticket-deadline.is-overdue { color: var(--red); font-weight: 700; }
.ticket-assignee { white-space: nowrap; }
.ticket-assignee.is-empty { font-style: italic; }
/* Category reads as context, not as a status: muted, and it wraps rather than
   pushing the deadline and assignee off the row on a narrow panel. */
.ticket-category { color: var(--text-muted); }

.leaflet-tooltip {
    background: var(--surface);
    border: 1px solid var(--border);
    box-shadow: 0 2px 12px var(--tooltip-shadow);
    color: var(--text);
    font-size: 12px;
    padding: 8px 10px;
}
.leaflet-tooltip:before { display: none; }

/* -- Keyboard focus indicators (WCAG 2.4.7) -- */
.view-tab:focus-visible,
.kiosk-list-item:focus-visible,
.topbar-btn:focus-visible,
.proximity-close:focus-visible,
button.pill:focus-visible,
.filter-select:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
}
/* Suppress the browser's default focus outline only when focus came from
   mouse/touch (`:not(:focus-visible)`). Keyboard focus still gets the
   accessible outline defined in the `:focus-visible` block above. */
.view-tab:focus:not(:focus-visible),
.kiosk-list-item:focus:not(:focus-visible),
.topbar-btn:focus:not(:focus-visible),
.proximity-close:focus:not(:focus-visible),
button.pill:focus:not(:focus-visible) {
    outline: none;
}

/* -- Mobile breakpoint: the top bar wraps (no drawer since the sidebar is
      gone), filter bar compacts (3 cols), map+panel stack vertically. -- */
@media (max-width: 800px) {
    .main { height: auto; min-height: 100vh; }

    .topbar { flex-wrap: wrap; gap: 8px; padding: 10px 12px; align-items: center; }
    .topbar-logo-img { height: 30px; padding: 4px 7px; }
    .view-switcher { order: 2; }
    .view-tab { padding: 6px 10px; font-size: 11px; }

    /* Pills wrap below the category buttons on the view-selection row. */
    .stat-pills {
        margin-left: 0;
        flex: 1 1 100%;
        gap: 4px;
    }
    .pill { padding: 4px 9px; font-size: 11px; }
    .pill .num { font-size: 12px; }

    .topbar-right {
        width: 100%;
        justify-content: flex-start;
        flex-wrap: wrap;
        gap: 8px;
    }
    /* 44px touch target (WCAG 2.5.5) now the buttons stay in the top bar
       on mobile. */
    .topbar-btn { width: 44px; height: 44px; }
    .search-box {
        flex: 1 1 100%;
        min-width: 0;
    }
    .search-box input {
        width: 100%;
        min-width: 0;
    }
    .topbar-freshness { flex: 0 0 auto; font-size: 10px; }

    /* Filter-bar: 3 selects op 1 rij via grid; notice/wis vullen aparte rijen. */
    .filter-bar {
        display: grid;
        grid-template-columns: repeat(3, minmax(0, 1fr));
        gap: 6px;
        padding: 8px 12px;
        align-items: stretch;
        min-height: 0;
    }
    .filter-bar-notice {
        grid-column: 1 / -1;
        height: auto;
        font-size: 11px;
        padding: 4px 8px;
    }
    .filter-select {
        width: 100%;
        min-width: 0;
        padding: 7px 8px;
        font-size: 11px;
    }
    .filter-reset {
        grid-column: 1 / -1;
        margin-left: 0;
        padding: 7px 12px;
        font-size: 12px;
    }

    .content {
        grid-template-columns: 1fr;
        grid-template-rows: 50vh auto;
    }
    .side-panel {
        border-left: none;
        border-top: 1px solid var(--border);
    }
}

/* -- Respect reduced-motion preference -- */
@media (prefers-reduced-motion: reduce) {
    .view-tab,
    .category-toggle,
    button.pill,
    .topbar-btn,
    .kiosk-list-item {
        transition: none;
    }
    #locate-me.locating {
        animation: none;
    }
}

/* ============================================================
   Legend glyph class
   ============================================================
   Plain coloured discs that match the map's circleMarker rendering.
   Background colour comes from the inline `style` attribute set in legend.js.
   The chip-shape mask-image rules in .pill .dot[data-band] /
   .score-big[data-band] apply to chips, not to map markers, which are
   circles today (the divIcon migration is deferred).
*/

.glyph {
    display: inline-block;
    width: 12px;
    height: 12px;
    flex-shrink: 0;
    border-radius: 50%;
}

/* ============================================================
   Map legend control (bottom-right)
   ============================================================ */

.map-legend {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 8px;
    padding: 10px 12px;
    box-shadow: 0 2px 6px rgba(0, 0, 0, 0.08);
    font-size: 12px;
    min-width: 140px;
}

.map-legend-title {
    font-weight: 700;
    color: var(--text);
    margin-bottom: 6px;
    font-size: 12px;
    letter-spacing: 0.02em;
    text-transform: uppercase;
}

.map-legend-row {
    display: flex;
    align-items: center;
    gap: 8px;
    line-height: 1.5;
    color: var(--text);
}

.map-legend-label {
    flex: 1;
}

.map-legend-toggle {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 8px;
    padding: 6px 10px;
    font-size: 12px;
    font-weight: 600;
    cursor: pointer;
    color: var(--text);
}

.map-legend-toggle:hover {
    background: var(--bg);
}

/* Mobile: collapse card behind a button. */
@media (max-width: 800px) {
    .map-legend.is-collapsed {
        background: transparent;
        border: none;
        box-shadow: none;
        padding: 0;
    }
}

/* Reduced motion: no transitions ever on the legend control. */
@media (prefers-reduced-motion: reduce) {
    .map-legend,
    .map-legend-toggle,
    .map-legend-card {
        transition: none !important;
        animation: none !important;
    }
}

/* ============================================================
   Side-panel summary header
   ============================================================ */

.panel-summary {
    display: block;
    font-size: 12px;
    font-weight: 600;
    color: var(--text);
    margin-top: 2px;
}

.panel-summary-sub {
    display: block;
    font-size: 11px;
    margin-top: 2px;
}

/* ============================================================
   Slashed-fraction chip variant (Jumbo contracten tab)
   ============================================================ */

.kli-score--fraction {
    /* Inherits 36x36 from .kli-score; three glyphs need to fit. */
    gap: 0;
    font-size: 11px;
    font-weight: 800;
    letter-spacing: -0.02em;
}

.kli-score-divider {
    display: inline-block;
    transform: rotate(-15deg) translateY(-0.5px);
    opacity: 0.85;
    margin: 0 1px;
}

/* ============================================================
   Weekomzet empty-state map overlay
   ============================================================
   Mirrors #proximity-banner chrome; positioned top-centre of the map area
   to avoid collision with the bottom-centred proximity banner.
   No transition by default -> no reduced-motion concern.
*/

.map-banner {
    position: absolute;
    top: 80px;
    left: 50%;
    transform: translateX(-50%);
    z-index: 500;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 10px;
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
    padding: 10px 14px;
    display: flex;
    align-items: center;
    gap: 10px;
    font-size: 13px;
    color: var(--text-muted);
    max-width: 360px;
}

.map-banner[hidden] {
    display: none;
}

.map-banner svg {
    flex-shrink: 0;
    color: var(--text-muted);
}

/* ============================================================
   Descriptor-driven pill tones
   ============================================================
   Decouples shape from band so non-HACCP tabs get correct CVD shapes via
   tone semantics rather than colour names. Shape rules keyed on data-band
   apply to HACCP chips; the data-tone axis here is used by pills.js.
   Five tones: ok (square/green), warn (triangle/orange), critical (cross/red),
   muted (circle/grey, for "n.v.t." and "gesloten"), info (circle/blue, for
   "open"). */
.pill .dot[data-tone] {
    border-radius: 0;
    -webkit-mask-repeat: no-repeat;
            mask-repeat: no-repeat;
    -webkit-mask-position: center;
            mask-position: center;
    -webkit-mask-size: contain;
            mask-size: contain;
}
.pill .dot[data-tone="ok"] {
    background: var(--green);
    -webkit-mask-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 10'><rect width='10' height='10' fill='black'/></svg>");
            mask-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 10'><rect width='10' height='10' fill='black'/></svg>");
}
.pill .dot[data-tone="warn"] {
    background: var(--orange);
    -webkit-mask-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 10'><polygon points='5,0 10,10 0,10' fill='black'/></svg>");
            mask-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 10'><polygon points='5,0 10,10 0,10' fill='black'/></svg>");
}
.pill .dot[data-tone="critical"] {
    background: var(--red);
    -webkit-mask-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 10'><path d='M1,1 L9,9 M9,1 L1,9' stroke='black' stroke-width='2.5' stroke-linecap='round'/></svg>");
            mask-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 10'><path d='M1,1 L9,9 M9,1 L1,9' stroke='black' stroke-width='2.5' stroke-linecap='round'/></svg>");
}
.pill .dot[data-tone="muted"] {
    background: var(--text-muted);
    border-radius: 50%;
    -webkit-mask-image: none;
            mask-image: none;
}
.pill .dot[data-tone="info"] {
    background: var(--marker-blue);
    border-radius: 50%;
    -webkit-mask-image: none;
            mask-image: none;
}
.pill .dot[data-tone] { box-shadow: none; }
button.pill.active .dot[data-tone] { background-color: #fff; }

/* Kiosk marker halos. Stroked SVG rings on overlayPane — see
   selection.js for the rationale on why we stroke instead of fill+shadow.
   Two intensities: hover is a transient cue while the cursor is over a list
   row; selected stays until cleared. Both use a brighter red (#FF4D3D) than
   brand #DA3628 to keep the halo distinguishable against HACCP-red markers. */
.kiosk-marker-halo-hover {
    filter: drop-shadow(0 0 4px rgba(255, 77, 61, 0.5));
    pointer-events: none;
}
.kiosk-marker-halo-selected {
    filter: drop-shadow(0 0 8px rgba(255, 77, 61, 0.75));
    pointer-events: none;
    animation: haloIn 180ms ease-out;
    transform-origin: center;
}
@keyframes haloIn {
    from { opacity: 0; }
    to   { opacity: 1; }
}
@media (prefers-reduced-motion: reduce) {
    .kiosk-marker-halo-selected { animation: none; }
}

/* -- Clickable card affordance (e.g. revenue card -> detail modal) -- */
.card.card-clickable {
    cursor: pointer;
    transition: border-color 120ms ease, background-color 120ms ease, transform 120ms ease;
}
.card.card-clickable:hover,
.card.card-clickable:focus-visible {
    border-color: var(--accent);
    background: color-mix(in srgb, var(--accent) 4%, var(--surface-alt));
}
.card.card-clickable:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
}
.card.card-clickable:active { transform: scale(0.997); }
.card.card-clickable .card-label {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 8px;
}
.card-action-hint {
    font-size: 11px;
    font-weight: 600;
    color: var(--accent);
    text-transform: none;
    letter-spacing: 0;
    opacity: 0.85;
}
.card.card-clickable:hover .card-action-hint,
.card.card-clickable:focus-visible .card-action-hint { opacity: 1; }

/* -- Revenue detail modal -- */
body.rev-modal-open { overflow: hidden; }
.rev-modal-backdrop {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.55);
    display: flex;
    align-items: center;
    justify-content: center;
    z-index: 1000;
    padding: 24px;
    animation: revModalFadeIn 140ms ease-out;
}
.rev-modal {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 14px;
    width: min(880px, 100%);
    max-height: calc(100vh - 48px);
    display: flex;
    flex-direction: column;
    box-shadow: 0 20px 60px rgba(0, 0, 0, 0.35);
    animation: revModalSlideIn 180ms ease-out;
}
.rev-modal-header {
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    gap: 12px;
    padding: 18px 22px 14px;
    border-bottom: 1px solid var(--border);
}
.rev-modal-eyebrow {
    font-size: 11px;
    font-weight: 700;
    color: var(--text-muted);
    text-transform: uppercase;
    letter-spacing: .04em;
    margin-bottom: 4px;
}
.rev-modal-header h2 {
    margin: 0;
    font-size: 20px;
    font-weight: 700;
    color: var(--text);
}
.rev-modal-close {
    background: transparent;
    border: 1px solid transparent;
    color: var(--text-muted);
    border-radius: 8px;
    padding: 4px;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    transition: background 120ms ease, color 120ms ease, border-color 120ms ease;
}
.rev-modal-close:hover,
.rev-modal-close:focus-visible {
    color: var(--text);
    background: var(--surface-alt);
    border-color: var(--border);
}
.rev-modal-close:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
}
.rev-modal-body {
    padding: 18px 22px 22px;
    overflow-y: auto;
    display: flex;
    flex-direction: column;
    gap: 14px;
}
.rev-modal-kpis {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 12px;
}
.rev-kpi {
    background: var(--surface-alt);
    border: 1px solid var(--border);
    border-radius: 10px;
    padding: 12px 14px;
}
.rev-kpi-label {
    font-size: 11px;
    font-weight: 600;
    color: var(--text-muted);
    text-transform: uppercase;
    letter-spacing: .04em;
    margin-bottom: 6px;
}
.rev-kpi-value {
    font-size: 22px;
    font-weight: 800;
    color: var(--text);
    line-height: 1.1;
}
.rev-modal-chart-card .rev-modal-chart {
    position: relative;
    height: 260px;
    margin-top: 4px;
}
.rev-modal-bench .rev-bench-row {
    display: flex;
    justify-content: space-between;
    gap: 12px;
    padding: 6px 0;
    font-size: 13px;
}
.rev-modal-bench .rev-bench-row + .rev-bench-row { border-top: 1px dashed var(--border); }
.rev-bench-label { color: var(--text-muted); }
.rev-bench-value { font-weight: 600; color: var(--text); }
.rev-bench-outlier {
    margin: 8px 0 0;
    font-size: 12px;
    color: var(--text-muted);
    font-style: italic;
}
.rev-modal-table-wrap { overflow-x: auto; }
.rev-modal-table {
    width: 100%;
    border-collapse: collapse;
    font-size: 13px;
}
.rev-modal-table th,
.rev-modal-table td {
    padding: 8px 10px;
    border-bottom: 1px solid var(--border);
    text-align: left;
}
.rev-modal-table th {
    font-size: 11px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .04em;
    color: var(--text-muted);
}
.rev-modal-table td.rev-num,
.rev-modal-table th.rev-num { text-align: right; font-variant-numeric: tabular-nums; }
.rev-modal-table tbody tr:hover { background: var(--surface-alt); }
.rev-modal-table .rev-up { color: var(--green); font-weight: 600; }
.rev-modal-table .rev-down { color: var(--red); font-weight: 600; }
.rev-modal-table .rev-detail-link {
    color: var(--brand-red);
    font-weight: 600;
    text-decoration: none;
    white-space: nowrap;
}
.rev-modal-table .rev-detail-link:hover,
.rev-modal-table .rev-detail-link:focus-visible { text-decoration: underline; }

/* Revenue drilldown tables: highlight the whole row and the whole column
   when hovering a cell. Row uses a subtle surface tint, column uses a brand
   overlay so the intersection remains visibly stronger. */
.revenue-table-hover td.revenue-table-row-hover,
.revenue-table-hover th.revenue-table-row-hover {
    background: color-mix(in srgb, var(--surface-alt) 92%, var(--surface));
}
.revenue-table-hover td.revenue-table-col-hover,
.revenue-table-hover th.revenue-table-col-hover {
    box-shadow: inset 0 0 0 9999px color-mix(in srgb, var(--accent) 7%, transparent);
}
.revenue-table-hover td.revenue-table-cell-hover,
.revenue-table-hover th.revenue-table-cell-hover {
    background: color-mix(in srgb, var(--accent) 9%, var(--surface-alt));
    box-shadow: inset 0 0 0 9999px color-mix(in srgb, var(--accent) 14%, transparent);
}

@keyframes revModalFadeIn {
    from { opacity: 0; }
    to   { opacity: 1; }
}
@keyframes revModalSlideIn {
    from { opacity: 0; transform: translateY(8px); }
    to   { opacity: 1; transform: translateY(0); }
}
@media (prefers-reduced-motion: reduce) {
    .rev-modal-backdrop,
    .rev-modal { animation: none; }
}
@media (max-width: 640px) {
    .rev-modal-backdrop { padding: 0; }
    .rev-modal {
        width: 100%;
        max-height: 100vh;
        border-radius: 0;
        border: none;
    }
    .rev-modal-kpis { grid-template-columns: 1fr; }
    .rev-modal-chart-card .rev-modal-chart { height: 220px; }
}

/* ============================================================
   2026-08 rebuild: category selection bar, yellow band, tooltips
   ============================================================ */

/* View selection (T-50). Sits between the topbar and the filter bar;
   checkboxes choose which signals feed the aggregated traffic light. */
.category-bar {
    padding: 8px 20px;
    border-bottom: 1px solid var(--border);
    display: flex; gap: 14px; align-items: center; flex-wrap: wrap;
    background: var(--surface);
    flex-shrink: 0;
    min-height: 40px;
}
.category-bar[hidden] { display: none; }
.category-bar-label {
    font-size: 12px;
    font-weight: 700;
    color: var(--text-muted);
    text-transform: uppercase;
    letter-spacing: .04em;
}
/* Shown only when no category is selected: explains why the markers carry no
   colour. Sits between the switcher and the pills and wraps on narrow screens
   rather than pushing the pills off the bar. */
.category-bar-hint {
    margin: 0;
    font-size: 12px;
    color: var(--text-muted);
}
.category-bar-hint[hidden] { display: none; }
/* Segmented button bar, same form language as .view-switcher: a rounded
   container with buttons; checked = filled button in the accent colour. */
.category-switcher {
    display: flex;
    gap: 4px;
    padding: 3px;
    border-radius: 10px;
    background: var(--surface-alt);
    border: 1px solid var(--border);
    flex-wrap: wrap;
}
.category-toggle {
    position: relative;
    display: inline-flex; align-items: center; gap: 7px;
    padding: 6px 12px;
    border-radius: 8px;
    font-size: 12px; font-weight: 600;
    color: var(--text-muted);
    cursor: pointer;
    user-select: none;
    transition: all .15s;
}
.category-toggle:hover { color: var(--text); background: var(--border); }
/* Native checkbox visually hidden but focusable: multi-select semantics
   and keyboard interaction keep coming from the real element. */
.category-toggle input[type="checkbox"] {
    position: absolute;
    width: 1px; height: 1px;
    opacity: 0;
    pointer-events: none;
}
.category-toggle:has(input:checked) {
    color: #fff;
    background: var(--accent);
}
.category-toggle:has(input:focus-visible) {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
}
/* Counter: number of stores with an issue in this category. Hidden at 0
   (categories.js sets hidden), red so it reads as a signal; inverted to
   white on the filled (checked) button for contrast. */
.category-toggle-count {
    min-width: 18px; height: 18px;
    padding: 0 5px;
    border-radius: 9px;
    background: var(--red);
    color: #fff;
    font-size: 11px; font-weight: 800;
    display: inline-flex; align-items: center; justify-content: center;
    font-variant-numeric: tabular-nums;
}
.category-toggle:has(input:checked) .category-toggle-count {
    background: #fff;
    color: var(--accent);
}
.category-toggle-count[hidden] { display: none; }

/* Yellow band - fourth traffic-light step (one category not OK). Shape
   language: diamond, between the green square and the orange triangle. */
.dot-yellow { background: var(--yellow); }
.pill .dot[data-band="yellow"],
.legal-docs-pill .dot[data-band="yellow"] {
    -webkit-mask-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 10'><polygon points='5,0 10,5 5,10 0,5' fill='black'/></svg>");
            mask-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 10'><polygon points='5,0 10,5 5,10 0,5' fill='black'/></svg>");
}
.pill .dot[data-tone="warning"] {
    background: var(--yellow);
    -webkit-mask-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 10'><polygon points='5,0 10,5 5,10 0,5' fill='black'/></svg>");
            mask-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 10'><polygon points='5,0 10,5 5,10 0,5' fill='black'/></svg>");
}
/* Dark text on yellow: white does not meet the contrast bar. */
.kli-score[data-band="yellow"] {
    background: var(--yellow);
    color: #422006;
}
.score-big[data-band="yellow"] { background: var(--yellow); color: #422006; }
.score-big[data-band="yellow"]::after {
    background-color: rgba(66, 32, 6, 0.75);
    -webkit-mask-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 10'><polygon points='5,0 10,5 5,10 0,5' fill='black'/></svg>");
            mask-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 10'><polygon points='5,0 10,5 5,10 0,5' fill='black'/></svg>");
}

/* Marker tooltip (T-52): one line per category with a coloured dot. */
.tooltip-categories {
    margin-top: 6px;
    padding-top: 6px;
    border-top: 1px solid rgba(127, 127, 127, 0.25);
    line-height: 1.7;
}
.tooltip-dot {
    display: inline-block;
    width: 8px; height: 8px;
    border-radius: 50%;
    margin-right: 6px;
    vertical-align: baseline;
}

/* Main photo in the side panel (T-66). Fixed height + object-fit so a
   portrait photo does not take over the panel; click opens the original. */
.kiosk-photo {
    display: block;
    border-radius: 12px;
    overflow: hidden;
    margin-bottom: 12px;
    border: 1px solid var(--border);
}
.kiosk-photo img {
    display: block;
    width: 100%;
    height: 170px;
    object-fit: cover;
}

/* Floor plans in the side panel. Unlike the photo these use `contain` on a
   light backdrop: a layout drawing cropped to a fixed frame loses exactly the
   edges you opened it for. Several plans per kiosk sit two to a row so a store
   with four drawings does not push the contact details off screen; a single
   plan gets the full width. Click opens the full-size image. */
.kiosk-floorplan-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 8px;
}
.kiosk-floorplan-grid.is-single {
    grid-template-columns: 1fr;
}
.kiosk-floorplan {
    display: block;
    border-radius: 10px;
    overflow: hidden;
    border: 1px solid var(--border);
    /* Line drawings carry their own white background, so the tile stays light
       in both themes - hence a dedicated token rather than var(--surface).
       The caption below pairs with it so the two do not clash in dark mode. */
    background: var(--plan-surface);
}
.kiosk-floorplan img {
    display: block;
    width: 100%;
    height: 110px;
    object-fit: contain;
}
.kiosk-floorplan-grid.is-single .kiosk-floorplan img {
    height: 180px;
}
.kiosk-floorplan-title {
    display: block;
    padding: 6px 10px;
    font-size: 12px;
    color: var(--plan-caption-text);
    background: var(--plan-caption-surface);
    border-top: 1px solid var(--border);
}
