/* VisionLAN - Components: reusable UI pieces */

/* ══════════════════════════════════════════
   BUTTONS
   ══════════════════════════════════════════ */

.btn-xs {
    padding: 0.15rem 0.4rem;
    font-size: 0.7rem;
    line-height: 1.4;
    border-radius: 0.2rem;
}

/* ══════════════════════════════════════════
   USER CARDS
   ══════════════════════════════════════════ */

.user-card {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.75rem;
    background: var(--vl-bg-card);
    border: 1px solid var(--vl-glass-border);
    border-radius: var(--vl-radius-sm);
    transition: all 0.15s ease;
}

.user-card:hover {
    border-color: var(--vl-border);
    background: var(--vl-bg-elevated);
}

.user-card-main {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    flex: 1;
    min-width: 0;
    text-decoration: none;
    color: var(--vl-text);
}

.user-card-main:hover {
    color: var(--vl-text);
}

.user-card-avatar {
    width: 44px;
    height: 44px;
    border-radius: 50%;
    object-fit: cover;
    flex-shrink: 0;
}

.user-card-info {
    flex: 1;
    min-width: 0;
}

.user-card-name {
    font-weight: 600;
    font-size: 0.9rem;
    display: block;
}

.user-card-action {
    display: flex;
    align-items: center;
    gap: 0.25rem;
    flex-shrink: 0;
}

/* ══════════════════════════════════════════
   NAV CARD (reusable link block with icon)
   ══════════════════════════════════════════ */

.nav-card {
    display: flex;
    align-items: center;
    gap: 1rem;
    background: var(--vl-bg-card);
    border: 1px solid var(--vl-glass-border);
    border-radius: var(--vl-radius-sm);
    padding: 1.1rem 1.25rem;
    color: var(--vl-text);
    text-decoration: none;
    transition: border-color 0.2s, transform 0.15s;
}

.nav-card:hover {
    border-color: var(--vl-border);
    transform: translateY(-2px);
    color: var(--vl-text);
}

.nav-card-icon {
    width: 44px;
    height: 44px;
    border-radius: var(--vl-radius-sm);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 1.15rem;
    flex-shrink: 0;
}

.nav-card-body {
    flex: 1;
    min-width: 0;
}

.nav-card-body h5 {
    font-size: 0.95rem;
    font-weight: 600;
    margin-bottom: 0.15rem;
}

.nav-card-body p {
    font-size: 0.8rem;
    color: var(--vl-text-muted);
    margin: 0;
}

.nav-card-chevron {
    color: var(--vl-text-muted);
    font-size: 0.8rem;
    flex-shrink: 0;
}

/* ── Audit log ── */

/* `.audit-item` med farget venstrekant er FJERNET.
   Nivaaet baeres av `.status-pill` i raden, som resten av systemet — en kant i
   kanten er den AI-signaturen design/komponenter.md forbyr, og den sa dessuten
   det samme som pilla ved siden av. Se `.revisjon-rad` under. */

/* ══════════════════════════════════════════
   EMPTY STATE
   ══════════════════════════════════════════ */

.empty-state {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    padding: 3rem 1.5rem;
    text-align: center;
}

.empty-state-img {
    width: 100%;
    max-width: 220px;
    height: auto;
    margin-bottom: 1.5rem;
    opacity: 0.85;
    filter: drop-shadow(0 4px 24px rgba(108, 92, 231, 0.15));
}

.empty-state-btn { margin-top: 0.35rem; }

.empty-state-text {
    font-size: 1.05rem;
    color: var(--vl-text-muted);
    max-width: 360px;
    line-height: 1.6;
}

/* ══════════════════════════════════════════
   EVENT CARDS
   ══════════════════════════════════════════ */

.featured-event-card {
    display: block;
    background: var(--vl-bg-card);
    border: 1px solid var(--vl-glass-border);
    border-radius: var(--vl-radius);
    margin-bottom: 1rem;
    text-decoration: none;
    color: var(--vl-text);
    transition: transform 0.2s ease, box-shadow 0.2s ease, border-color 0.2s ease;
    overflow: hidden;
}

.featured-event-card:hover {
    transform: translateY(-2px);
    box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
    border-color: var(--vl-primary);
    color: var(--vl-text);
}

.featured-event-cover {
    height: 140px;
    background-size: cover;
    background-position: center;
    position: relative;
}

.featured-event-body {
    padding: 1.25rem;
}

.featured-event-card h3 {
    font-size: 1.3rem;
    font-weight: 700;
}

.featured-event-desc {
    font-size: 0.9rem;
    line-height: 1.5;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.past-event-card {
    display: block;
    background: var(--vl-bg-card);
    border: 1px solid var(--vl-glass-border);
    border-radius: var(--vl-radius-sm);
    text-decoration: none;
    color: var(--vl-text);
    transition: transform 0.2s ease, box-shadow 0.2s ease;
    height: 100%;
    opacity: 0.8;
    overflow: hidden;
}

.past-event-card:hover {
    transform: translateY(-1px);
    box-shadow: 0 4px 16px rgba(0, 0, 0, 0.2);
    opacity: 1;
    color: var(--vl-text);
}

.past-event-cover {
    height: 80px;
    background-size: cover;
    background-position: center;
}

.past-event-body {
    padding: 0.75rem 1rem;
    position: relative;
}

.past-event-body .profile-img-sm {
    position: absolute;
    top: -18px;
    left: 0.75rem;
}

/* ══════════════════════════════════════════
   DETAIL PAGE (reusable profile-style pages)
   ══════════════════════════════════════════ */

.detail-cover {
    height: 320px;
    border-radius: var(--vl-radius);
    background-size: cover;
    background-position: center;
    position: relative;
    z-index: 1;
    margin-bottom: 1rem;
    display: flex;
    flex-direction: column;
    justify-content: flex-end;
}

.detail-cover--tall { height: 380px; }
.detail-cover--short { height: 260px; }

.detail-cover-overlay {
    position: absolute;
    inset: 0;
    background: linear-gradient(to top, rgba(0,0,0,0.75) 0%, rgba(0,0,0,0.25) 40%, transparent 70%);
    border-radius: var(--vl-radius);
}

.detail-cover-edit {
    position: absolute;
    top: 0.75rem;
    right: 0.75rem;
    padding: 0.4rem 0.75rem;
    border: none;
    border-radius: var(--vl-radius-sm);
    background: rgba(0, 0, 0, 0.5);
    color: #fff;
    display: flex;
    align-items: center;
    gap: 0.4rem;
    cursor: pointer;
    transition: background 0.2s, opacity 0.2s;
    font-size: 0.8rem;
    opacity: 0;
    z-index: 3;
}

/* Samme redigeringsknapp paa begge coverflatene. `.detail-cover` er
   ressurssider (arrangement, spill, turnering), `.profile-cover-display` er
   identitetssider (bruker, lag) — men knappen skal se lik ut og oppfoere seg
   likt begge steder. */
.detail-cover:hover .detail-cover-edit,
.profile-cover-display:hover .detail-cover-edit,
.profile-cover-display:focus-within .detail-cover-edit {
    opacity: 1;
}

/* Flere kontroller i hjornet. Absolutt plasserte knapper uten holder klipper
   mot hoyrekanten naar teksten er lang nok — og `btn-outline-light` oppaa et
   lyst cover er praktisk talt usynlig. Holderen gir dem flyt og luft, og
   .detail-cover-edit gir dem hver sin morke bakgrunn. */
.detail-cover-actions {
    position: absolute;
    top: 0.75rem;
    right: 0.75rem;
    z-index: 3;
    display: flex;
    gap: 0.4rem;
    flex-wrap: wrap;
    justify-content: flex-end;
    max-width: calc(100% - 1.5rem);
}

.detail-cover-actions .detail-cover-edit {
    position: static;
    white-space: nowrap;
}

.detail-cover-edit:hover {
    background: rgba(0, 0, 0, 0.7);
}

.detail-cover-content {
    position: relative;
    z-index: 2;
    padding: 1.25rem 1.5rem;
    display: flex;
    align-items: flex-end;
    gap: 1rem;
}

.detail-cover-content--centered {
    max-width: 800px;
    margin: 0 auto;
    width: 100%;
    align-items: center;
}

.detail-cover-icon {
    flex-shrink: 0;
}

.detail-cover-icon img {
    width: 80px;
    height: 80px;
    object-fit: cover;
    /* Logoer kan ha gjennomsiktig luft rundt seg etter innramming. Uten en
       bakgrunn ville cover-bildet skint gjennom inne i sirkelen. */
    background: var(--vl-bg-tertiary);
    border-radius: 50%;
    border: 3px solid rgba(255,255,255,0.2);
    box-shadow: 0 2px 12px rgba(0,0,0,0.3);
}

.detail-cover-icon--placeholder {
    width: 80px;
    height: 80px;
    border-radius: 50%;
    background: var(--vl-bg-tertiary);
    display: flex;
    align-items: center;
    justify-content: center;
    border: 3px solid rgba(255,255,255,0.2);
    box-shadow: 0 2px 12px rgba(0,0,0,0.3);
}

.detail-cover-icon--placeholder i {
    font-size: 2rem;
    color: var(--vl-primary);
}

/* Redigerbart ikon — samme regel som ellers: bildet er knappen.
   Coveret hadde lenge sin egen .detail-cover-edit, mens logoen ved siden av
   ikke kunne trykkes i det hele tatt. Ingen visuell forskjell forklarte
   hvorfor. */
.detail-cover-icon--editable {
    position: relative;
    cursor: pointer;
    border-radius: 50%;
    /* Uten dette gir bildets linjehoyde en pikselstripe under det, og
       overlegget blir en ellipse i stedet for en sirkel. */
    line-height: 0;
}

.detail-cover-icon-overlay {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 50%;
    background: rgba(0, 0, 0, 0.55);
    color: #fff;
    font-size: 1.1rem;
    line-height: 1;
    opacity: 0;
    transition: opacity 0.15s;
    pointer-events: none;
}

.detail-cover-icon--editable:hover .detail-cover-icon-overlay,
.detail-cover-icon--editable:focus-visible .detail-cover-icon-overlay {
    opacity: 1;
}

.detail-cover-icon[role="button"] {
    cursor: pointer;
    transition: transform 0.15s ease, border-color 0.15s ease;
}
.detail-cover-icon[role="button"]:hover {
    transform: scale(1.08);
    border-color: var(--vl-primary);
}
.detail-cover-icon[role="button"]:hover img {
    border-color: var(--vl-primary);
}

.detail-cover-info {
    flex: 1;
    min-width: 0;
}

.detail-cover-info h2 {
    color: #fff;
    text-shadow: 0 1px 4px rgba(0,0,0,0.4);
    margin-bottom: 0.25rem;
}

.detail-title-row {
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    flex-wrap: wrap;
    gap: 0.5rem;
}

.detail-meta {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    flex-wrap: wrap;
    color: rgba(255,255,255,0.7);
    font-size: 0.85rem;
    margin-top: 0.25rem;
}

.detail-actions {
    display: flex;
    gap: 0.5rem;
    flex-shrink: 0;
}

/* Info item — glass pill with icon + label/value (sidebars, detail pages) */
.info-item {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.5rem;
    border-radius: var(--bs-border-radius, 0.375rem);
    background: var(--vl-glass);
    overflow: hidden;
}
.info-item-icon {
    width: 20px;
    flex-shrink: 0;
    text-align: center;
    color: var(--vl-primary);
    font-size: 0.9rem;
}
.info-item-content {
    min-width: 0;
}
.info-item-label {
    display: block;
    font-size: 0.7rem;
    line-height: 1;
    color: var(--vl-text-muted, rgba(255,255,255,0.5));
}
.info-item-value {
    font-size: 0.85rem;
}
.info-item-value.text-truncate {
    display: block;
}

/* Circular profile images (reusable) */
.profile-img-sm,
.profile-img-md,
.profile-img-lg {
    border-radius: 50%;
    border: 2px solid var(--vl-bg-card-solid);
    background: var(--vl-bg-elevated);
    flex-shrink: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    overflow: hidden;
}

.profile-img-sm { width: 36px; height: 36px; }
.profile-img-md { width: 60px; height: 60px; }
.profile-img-lg { width: 80px; height: 80px; border-width: 4px; filter: drop-shadow(0 2px 8px rgba(0,0,0,0.3)); }

.profile-img-sm img,
.profile-img-md img,
.profile-img-lg img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.event-meta {
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
}

.event-meta-item {
    display: flex;
    align-items: flex-start;
    gap: 0.75rem;
    color: var(--vl-text-muted);
}

.event-meta-item i {
    width: 18px;
    text-align: center;
    margin-top: 3px;
    color: var(--vl-primary);
}

.event-description {
    line-height: 1.7;
    color: var(--vl-text-muted);
}

.event-description p {
    margin-bottom: 0.75rem;
}

@media (max-width: 767.98px) {
    .detail-cover { height: 220px; }
    .detail-cover--tall { height: 260px; }
    .detail-cover--short { height: 200px; }
    .detail-cover-icon img { width: 56px; height: 56px; }
    .detail-cover-icon--placeholder { width: 56px; height: 56px; }
    .detail-cover-icon--placeholder i { font-size: 1.5rem; }
    .detail-cover-content { padding: 1rem; gap: 0.75rem; }
    .detail-cover-info h2 { font-size: 1.1rem; }
    .featured-event-cover { height: 100px; }
}

/* ══════════════════════════════════════════
   LIST ITEMS (reusable)
   ══════════════════════════════════════════ */

/* Raden man kom fra.
   Aapner du bestillingen fra én av tre like billetter, er «hvilken var min»
   det foerste oyet leter etter. Markeringen er kantfargen og et hakk lysere
   flate — IKKE en farget venstrekant: den staar i design/farger.md som et
   trekk vi ikke bruker, og den ville dessuten konkurrert med statusmerket i
   samme rad. `.aktiv` er navnet ny kode bruker (se merknaden ved
   `.period-chip.aktiv`). */
.list-item.aktiv {
    border-color: var(--vl-accent);
    /* Bokstavelig rgba og ikke `var(--vl-accent)` med alfa: variabelen er en
       hex uten kanal, og `--vl-bg-card-hover` — det naerliggende valget —
       er aldri definert noe sted. En fallback som stille gir samme flate som
       naboraden er ingen markering. */
    background: rgba(0, 206, 201, 0.07);
}

.list-item {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    background: var(--vl-bg-card);
    border: 1px solid var(--vl-glass-border);
    border-radius: var(--vl-radius-sm);
    padding: 0.7rem 1rem;
    transition: border-color 0.15s;
}

.list-item:hover {
    border-color: var(--vl-border);
}

.list-item-main {
    flex: 1;
    min-width: 0;
}

.list-item-actions {
    display: flex;
    gap: 0.25rem;
    flex-shrink: 0;
}

@media (max-width: 575.98px) {
    .list-item {
        flex-direction: column;
        align-items: flex-start;
    }
    .list-item-actions {
        align-self: flex-end;
    }
}

/* ── Column list (reusable base for tabular .list-item layouts) ── */

.col-list-row {
    justify-content: flex-start !important;
    gap: 0.75rem !important;
    align-items: center;
    font-size: 0.85rem;
}

.col-list-header {
    display: flex;
    justify-content: flex-start;
    gap: 0.75rem;
    align-items: center;
    padding: 0 1rem;
    font-size: 0.7rem;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--vl-text-muted, #6c757d);
}

/* Klikkbar kolonneoverskrift — se components/kolonnesort.js.

   Knappen skal LESES som overskriften ved siden av, ikke som en knapp i en
   rad med knapper: ingen flate, ingen ramme, arver `font` og `color` fra
   `.col-list-header`. Det er samme regel som `.metric--klikkbar` foelger, og
   av samme grunn — et tall og en overskrift som blir knapper skal fortsatt
   se ut som et tall og en overskrift.

   Pila er `visibility` og ikke `display`: plassen er tatt hele tiden, saa
   overskriften ikke flytter seg naar man holder over den. */
.kol-sort {
    display: flex;
    align-items: center;
    gap: 0.3rem;
    padding: 0;
    border: 0;
    background: none;
    font: inherit;
    letter-spacing: inherit;
    text-transform: inherit;
    text-align: left;
    color: inherit;
    cursor: pointer;
}

.kol-sort > i {
    visibility: hidden;
    font-size: 0.8em;
}

.kol-sort:hover { color: var(--vl-text); }
.kol-sort:hover > i { visibility: visible; opacity: 0.45; }

.kol-sort.aktiv { color: var(--vl-text); }
.kol-sort.aktiv > i { visibility: visible; opacity: 1; color: var(--vl-primary); }

@media (max-width: 575.98px) {
    .col-list-header { display: none !important; }
    .list-item.col-list-row {
        /* `.list-item` setter `flex-direction: column` paa telefon, og denne
           regelen overstyrte den ikke — saa den 2-linjers mobilvisningen
           lister.md beskriver har aldri virket. Hver kolonne fikk sin egen
           linje, og `order`-reglene per kolonnegruppe (`.bru-col-*`,
           `.tk-col-*`, `.crw-col-*` …) sorterte en loddrett stabel i stedet
           for aa brekke en rad. `flex: 1 1 0` paa en kolonne ble i tillegg en
           HOYDE, saa radene ble unaturlig hoye.

           Maalt 30.09.2026: 17 sider bruker `.col-list-row`, og seks
           kolonnegrupper har mobilregler som forutsetter en rad. Feilen laa
           altsaa i basen, ikke paa sidene. */
        flex-direction: row;
        align-items: center;
        flex-wrap: wrap;
        gap: 0.15rem 0.5rem !important;
    }
}

/* ── Past tickets columns ── */

.past-ticket-col-name   { flex: 2 1 200px; min-width: 0; }
.past-ticket-col-date   { flex: 1 1 100px; min-width: 0; }
.past-ticket-col-type   { flex: 1 1 120px; min-width: 0; }
/* Bred nok til det LENGSTE merket, «Venter på betaling».
   Sto paa 90px, men `.status-pill` har `white-space: nowrap`, og en flex-item
   nekter aa krympe under innholdet sitt (`min-width: auto`). Merket sprengte
   derfor boksen og skjoev dato og type ut av kolonnene sine — men bare paa de
   radene som hadde den lange statusen, saa lista sto og hoppet. */
.past-ticket-col-status { flex: 0 0 150px; }

@media (max-width: 575.98px) {
    .past-ticket-col-name   { flex: 1 1 0; order: 1; }
    .past-ticket-col-status { flex: 0 0 auto; order: 2; }
    .past-ticket-col-date   { flex: 0 0 auto; order: 3; font-size: 0.75rem; }
    .past-ticket-col-type   { flex: 1 1 0; order: 4; font-size: 0.75rem; }
}

/* ── Past events columns ── */

.past-event-col-name   { flex: 2 1 200px; min-width: 0; }
.past-event-col-date   { flex: 1 1 130px; min-width: 0; }
.past-event-col-venue  { flex: 1 1 120px; min-width: 0; }
.past-event-col-count  { flex: 0 0 120px; }

@media (max-width: 575.98px) {
    .past-event-col-name   { flex: 1 1 0; order: 1; }
    .past-event-col-count  { flex: 0 0 auto; order: 2; }
    .past-event-col-date   { flex: 0 0 auto; order: 3; font-size: 0.75rem; }
    .past-event-col-venue  { flex: 1 1 0; order: 4; font-size: 0.75rem; }
}

/* ── Past tournaments columns ── */

.past-tourn-col-name   { flex: 2 1 200px; min-width: 0; }
.past-tourn-col-game   { flex: 1 1 120px; min-width: 0; }
.past-tourn-col-event  { flex: 1 1 130px; min-width: 0; }
.past-tourn-col-count  { flex: 0 0 70px; }

@media (max-width: 575.98px) {
    .past-tourn-col-name   { flex: 1 1 0; order: 1; }
    .past-tourn-col-count  { flex: 0 0 auto; order: 2; }
    .past-tourn-col-game   { flex: 0 0 auto; order: 3; font-size: 0.75rem; }
    .past-tourn-col-event  { flex: 1 1 0; order: 4; font-size: 0.75rem; }
}

/* Game chips (profile) */
.game-chip {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    padding: 0.3rem 0.6rem;
    border-radius: var(--vl-radius-sm);
    background: var(--vl-glass);
    color: var(--vl-text);
    font-size: 0.85rem;
    transition: background 0.15s;
}
.game-chip:hover {
    background: var(--vl-border);
    color: var(--vl-text);
}
.game-chip-img {
    width: 20px;
    height: 20px;
    border-radius: 3px;
    object-fit: cover;
}
.game-chip-icon {
    width: 20px;
    text-align: center;
    font-size: 0.8rem;
    color: var(--vl-text-muted);
}

/* Game toggle cards (profile edit) */
.game-toggle {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.4rem;
    padding: 0.6rem;
    border-radius: var(--vl-radius-sm);
    border: 2px solid transparent;
    background: var(--vl-glass);
    cursor: pointer;
    transition: border-color 0.15s, background 0.15s;
    text-align: center;
    width: 100px;
}
.game-toggle:hover {
    background: var(--vl-border);
}
.game-toggle.active {
    border-color: var(--vl-primary);
    background: rgba(108, 92, 231, 0.15);
}
.game-toggle img {
    width: 48px;
    height: 48px;
    border-radius: 6px;
    object-fit: cover;
}
.game-toggle .game-toggle-name {
    font-size: 0.75rem;
    line-height: 1.2;
    max-height: 2.4em;
    overflow: hidden;
}
.game-toggle .game-toggle-check {
    position: absolute;
    top: 4px;
    right: 4px;
    font-size: 0.7rem;
    color: var(--vl-primary);
}

/* Option cards (tournament editor type/format selection) */
.option-card {
    display: flex;
    align-items: center;
    gap: 1rem;
    padding: 1rem 1.25rem;
    border-radius: var(--vl-radius);
    border: 2px solid var(--vl-border);
    background: var(--vl-glass);
    cursor: pointer;
    transition: border-color 0.15s, background 0.15s, box-shadow 0.15s;
    position: relative;
    flex: 1 1 200px;
    min-width: 200px;
}
.option-card:hover {
    border-color: var(--vl-text-muted);
    background: rgba(255, 255, 255, 0.03);
}
.option-card.active {
    border-color: var(--vl-primary);
    background: rgba(108, 92, 231, 0.1);
    box-shadow: 0 0 0 1px rgba(108, 92, 231, 0.3);
}
.option-card-icon {
    flex-shrink: 0;
    width: 40px;
    height: 40px;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: var(--vl-radius-sm);
    background: var(--vl-bg-tertiary);
    font-size: 1.1rem;
    color: var(--vl-text-muted);
}
.option-card.active .option-card-icon {
    background: rgba(108, 92, 231, 0.2);
    color: var(--vl-primary);
}
.option-card-body {
    flex: 1;
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
    min-width: 0;
}
.option-card-body strong {
    font-size: 0.95rem;
}
.option-card-desc {
    font-size: 0.8rem;
    color: var(--vl-text-muted);
    line-height: 1.35;
}
.option-card-check {
    position: absolute;
    top: 0.6rem;
    right: 0.6rem;
    font-size: 0.85rem;
    color: var(--vl-primary);
    opacity: 0;
    transition: opacity 0.15s;
}
.option-card.active .option-card-check {
    opacity: 1;
}
.option-card-wide {
    flex: 1 1 100%;
}

/* ── Brukerlista  ·  /admin/users ─────────────────────────────
   Kolonnebasert liste, se design/lister.md. Base-layouten kommer fra
   `.col-list-row` og `.col-list-header`; her defineres BARE kolonnene.

   Erstattet `.admin-user-col-*`, som var bygget for en rad med egen
   `gap`-overstyring i stedet for `.col-list-row`. */
.bru-col-navn       { flex: 2 1 200px; min-width: 0; }
.bru-col-navn > span { min-width: 0; }
.bru-col-epost      { flex: 2 1 190px; min-width: 0; }
.bru-col-alder      { flex: 0 0 62px; }
.bru-col-registrert { flex: 0 0 110px; }
/* Fast bredde, aldri `auto`: merkene varierer i antall, og en variabel
   bredde her ville forskjovet alle radene i forhold til hverandre. */
.bru-col-merker     { flex: 0 0 190px; display: flex; flex-wrap: wrap; gap: 0.25rem; }

/* ── Arrangementstabellen  ·  /admin/brukerstatistikk ─────────
   Stolpen viser STOERRELSEN paa arrangementet, og den lysere delen inni
   hvor mye av det som var nye deltakere. To tall i én figur — den
   interessante utviklingen er at den lyse delen krymper aar for aar. */
.ustat-col-navn      { flex: 2 1 150px; min-width: 0; }
.ustat-col-tall      { flex: 0 0 78px; text-align: right; font-variant-numeric: tabular-nums; }
.ustat-col-fordeling { flex: 1 1 120px; min-width: 60px; display: flex; align-items: center; }

.ustat-stolpe {
    display: block;
    height: 8px;
    border-radius: 999px;
    background: var(--vl-primary);
    opacity: 0.55;
    min-width: 3px;
}
/* Nye deltakere ligger INNI stolpen, ikke ved siden av: to stolper ville
   krevd at oyet sammenligner lengder som starter ulike steder. */
.ustat-stolpe-ny {
    display: block;
    height: 100%;
    border-radius: 999px;
    background: var(--vl-accent);
}

@media (max-width: 767.98px) {
    /* Fem talkolonner faar ikke plass. Deltakere og snittalder er de to
       som baerer raden; resten staar i tittelteksten paa stolpen. */
    .ustat-col-fordeling { display: none; }
    .ustat-col-tall:nth-of-type(3),
    .ustat-col-tall:nth-of-type(4),
    .ustat-col-tall:nth-of-type(5) { display: none; }
}

@media (max-width: 575.98px) {
    /* Navn + merker paa foerste linje, e-post paa andre. Alder og
       registreringsdato faller bort — de er sortering, ikke identifikasjon. */
    .bru-col-navn       { flex: 1 1 0; order: 1; }
    .bru-col-merker     { flex: 0 0 auto; order: 2; }
    .bru-col-epost      { flex: 1 1 100%; order: 3; font-size: 0.78rem; }
    .bru-col-alder      { display: none; }
    .bru-col-registrert { display: none; }
}

/* Admin game-player list columns */
.game-player-col-name  { flex: 2 1 160px; min-width: 0; }
.game-player-col-email { flex: 1 1 140px; min-width: 0; }
.game-player-col-info  { flex: 0 0 120px; }

@media (max-width: 575.98px) {
    .list-item.col-list-row > .game-player-col-name  { flex: 1 1 0; order: 1; }
    .list-item.col-list-row > .game-player-col-info  { flex: 0 0 auto; order: 2; }
    .list-item.col-list-row > .game-player-col-email { display: none; }
}

/* Admin game-tournament list columns */
.game-tourney-col-name   { flex: 2 1 160px; min-width: 0; }
.game-tourney-col-event  { flex: 1 1 120px; min-width: 0; }
.game-tourney-col-info   { flex: 0 0 100px; }
.game-tourney-col-status { flex: 0 0 80px; }

@media (max-width: 575.98px) {
    .list-item.col-list-row > .game-tourney-col-name   { flex: 1 1 0; order: 1; }
    .list-item.col-list-row > .game-tourney-col-status { flex: 0 0 auto; order: 2; }
    .list-item.col-list-row > .game-tourney-col-event  { display: none; }
    .list-item.col-list-row > .game-tourney-col-info   { flex: 0 0 auto; order: 3; font-size: 0.75rem; }
}

/* App game-player list columns */
.app-player-col-name { flex: 2 1 140px; min-width: 0; }
.app-player-col-ign  { flex: 1 1 120px; min-width: 0; }
.app-player-col-info { flex: 0 0 120px; }

@media (max-width: 575.98px) {
    .list-item.col-list-row > .app-player-col-name { flex: 1 1 0; order: 1; }
    .list-item.col-list-row > .app-player-col-info { flex: 0 0 auto; order: 2; }
    .list-item.col-list-row > .app-player-col-ign  { display: none; }
}

/* Admin order list columns — desktop */
.admin-order-row {
    gap: 0.75rem !important;
    align-items: center;
}
/* Statuskolonnen er bred nok til det LENGSTE merket, «Venter paa betaling».
   Sto paa 130px, men `.status-pill` har `white-space: nowrap` og en flex-item
   krymper ikke under innholdet sitt — merket sprengte boksen og skjoev resten
   av raden, men bare paa de radene som hadde den lange statusen. Lista sto og
   hoppet. Samme feil som `.past-ticket-col-status` hadde. */
.admin-order-col-avatar { flex: 0 0 28px; }
/* Vekstfaktorene fordeler den ledige plassen 2:2:1. Med `.content-xl` (1400 px)
   og bare to voksende kolonner ble navn og arrangement over 400 px hver, mens
   «1 billett / Bankoverfoering» sto klemt paa 130 — mye luft der det ikke
   trengtes, og avkorting der det gjorde. */
.admin-order-col-user   { flex: 2 1 180px; min-width: 0; }
/* Kolonnen bar «Arrangement» da raden var en ordre. Naa er den BILLETTYPEN,
   og «Deltager» er kortere enn «VisionLAN 2026» — derfor halv vekstfaktor.
   Klassenavnet staar igjen; aa doepe om fire klasser i to filer for aa vinne
   et ord er ikke verdt risikoen midt i et salg. */
.admin-order-col-event  { flex: 1 1 140px; min-width: 0; }
.admin-order-col-info   { flex: 1 1 120px; min-width: 0; font-size: 0.85rem; color: var(--vl-text-muted); }
.admin-order-col-amount { flex: 0 0 80px; text-align: right; font-weight: 600; font-size: 0.85rem; font-variant-numeric: tabular-nums; }

/* «3 i best.» — at billetten har soesken. Det er en fotnote til raden, ikke
   et tall man sammenligner nedover, saa den er dempet og uten tabularsiffer. */
.admin-order-soesken {
    font-size: 0.72rem;
    font-weight: 500;
    color: var(--vl-text-muted);
    white-space: nowrap;
}
.admin-order-col-status { flex: 0 0 160px; display: flex; justify-content: flex-end; }
.admin-order-col-act    { flex: 0 0 32px; display: flex; justify-content: flex-end; }

/* Bestilt-linja under navnet. Baerer ogsaa alderen naar bestillingen venter
   paa betaling — se `bestiltNaar()`. */
.admin-order-nar {
    display: block;
    font-size: 0.78rem;
    color: var(--vl-text-muted);
}

.admin-order-sent { color: #e8907a; font-weight: 600; }

/* ══════════════════════════════════════════
   Revisjonsloggen (/admin/audit-log)
   ══════════════════════════════════════════ */

/* Tett rad med fem kolonner. Tida staar FOERST og hoyrejustert, fordi loggen
   leses kronologisk: oyet foelger én kolonne nedover, og da maa den ligge i
   kanten. Klokkeslettet er stoerst — datoen gjentar seg, klokka gjor ikke. */
.revisjon-rad {
    gap: 0.85rem !important;
    align-items: flex-start;
    cursor: pointer;
}

.revisjon-tid {
    flex: 0 0 74px;
    text-align: right;
    font-variant-numeric: tabular-nums;
    line-height: 1.25;
}
.revisjon-klokke { font-size: 0.85rem; font-weight: 600; }
.revisjon-dato   { font-size: 0.74rem; color: var(--vl-text-muted); }

.revisjon-hoved { flex: 3 1 240px; min-width: 0; }

.revisjon-topp {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    flex-wrap: wrap;
    margin-bottom: 0.2rem;
}

/* Handlingsnavnet er en noekkel man skanner etter, ikke prosa. */
.revisjon-handling {
    font-size: 0.78rem;
    color: var(--vl-text-muted);
    background: var(--vl-glass);
    border: 1px solid var(--vl-glass-border);
    border-radius: 4px;
    padding: 0.05rem 0.35rem;
}

.revisjon-melding {
    font-size: 0.88rem;
    overflow-wrap: anywhere;
}

/* `min-width: 0` paa begge: uten den krymper ikke en flex-item under
   innholdet sitt, og et langt navn eller en lang entitet skyver raden ut av
   kolonneoppstillingen. Samme fella som `.admin-order-col-status` hadde. */
.revisjon-hvem    { flex: 1 1 150px; min-width: 0; font-size: 0.85rem; }
.revisjon-gjelder { flex: 1 1 130px; min-width: 0; font-size: 0.85rem; }
.revisjon-mer     { flex: 0 0 16px; display: flex; justify-content: flex-end; align-self: center; font-size: 0.8rem; }

/* Sporlenke: ser ut som en lenke, er en knapp. Den navigerer ikke — den bytter
   visning paa sida — og da skal den ikke vaere en <a> med falsk href. */
.revisjon-lenke {
    background: none;
    border: 0;
    padding: 0;
    color: var(--vl-accent);
    font: inherit;
    text-align: left;
    cursor: pointer;
    overflow-wrap: anywhere;
}
.revisjon-lenke:hover { text-decoration: underline; }
.revisjon-lenke:focus-visible { outline: 2px solid var(--vl-primary); outline-offset: 2px; border-radius: 3px; }

.revisjon-sporhode .card-body { padding-top: 1rem; padding-bottom: 1rem; }

/* Definisjonslista i detaljmodalen. To kolonner paa bred skjerm, stablet paa
   smal — etiketten over verdien er lettere aa lese enn to smale kolonner. */
.revisjon-defliste {
    display: grid;
    grid-template-columns: minmax(7rem, 10rem) 1fr;
    gap: 0.55rem 1rem;
    margin: 0;
}
.revisjon-def { display: contents; }
.revisjon-def dt {
    font-size: 0.78rem;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    color: var(--vl-text-muted);
    font-weight: 500;
}
.revisjon-def dd { margin: 0; overflow-wrap: anywhere; }

.revisjon-json {
    background: var(--vl-glass);
    border: 1px solid var(--vl-glass-border);
    border-radius: 6px;
    padding: 0.85rem;
    font-size: 0.78rem;
    max-height: 320px;
    overflow: auto;
    margin: 0;
}

@media (max-width: 767.98px) {
    .list-item.revisjon-rad {
        flex-wrap: wrap;
        gap: 0.4rem 0.75rem !important;
    }
    .list-item.revisjon-rad > .revisjon-tid     { flex: 0 0 auto; order: 1; text-align: left; }
    .list-item.revisjon-rad > .revisjon-tid     { display: flex; gap: 0.4rem; align-items: baseline; }
    .list-item.revisjon-rad > .revisjon-mer     { flex: 1 1 auto; order: 2; }
    .list-item.revisjon-rad > .revisjon-hoved   { flex: 1 1 100%; order: 3; }
    .list-item.revisjon-rad > .revisjon-hvem    { flex: 1 1 auto; order: 4; }
    .list-item.revisjon-rad > .revisjon-gjelder { flex: 0 0 auto; order: 5; }

    .revisjon-defliste { grid-template-columns: 1fr; gap: 0.15rem; }
    .revisjon-def + .revisjon-def dt { margin-top: 0.6rem; }
}

/* Referansen er crews soekeord, ikke radens hovedsak. Den sto som `<code>` og
   tok farge fra kodestilen — en roed streng midt i lista, som trakk blikket
   bort fra navn og status. */
.admin-order-ref {
    display: block;
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: 0.72rem;
    color: var(--vl-text-muted);
    opacity: 0.75;
}

.admin-order-metode { font-size: 0.78rem; opacity: 0.85; }

.admin-order-header { display: flex; }

/* Mobile: hide header, wrap rows into compact 2-line layout */
@media (max-width: 767.98px) {
    .admin-order-header { display: none !important; }

    .list-item.admin-order-row {
        flex-wrap: wrap;
        align-items: flex-start;
        gap: 0.15rem 0.5rem !important;
    }
    /* Line 1: avatar + name + status */
    .list-item.admin-order-row > .admin-order-col-avatar { flex: 0 0 28px; order: 1; }
    .list-item.admin-order-row > .admin-order-col-user   { flex: 1 1 0; min-width: 0; order: 2; }
    .list-item.admin-order-row > .admin-order-col-status { flex: 0 0 auto; order: 3; }

    /* Linje 2: billettype + plass + soeskenmerket */
    .list-item.admin-order-row > .admin-order-col-event  {
        flex: 0 1 auto; order: 4; min-width: 0;
        padding-left: 36px;
    }
    /* Plassen staar OGSAA paa telefon.
       Kolonnen var `display: none` her da den bar «1 billett / Vipps» — en
       opplysning man kunne slaa opp. Naa baerer den seteplasseringen, og det
       er nettopp det man staar og leter etter med telefonen i haanda naar
       noen spoer hvor de sitter. */
    .list-item.admin-order-row > .admin-order-col-info {
        flex: 1 1 auto; order: 5; min-width: 0;
    }
    .list-item.admin-order-row > .admin-order-col-amount {
        flex: 0 0 auto; order: 6;
    }

    /* Handlingsmenyen sist — den er ikke pynt, den er eneste vei til
       «Godkjenn betaling» paa telefon. */
    .list-item.admin-order-row > .admin-order-col-act {
        flex: 0 0 auto; order: 7;
    }

    /* «Bestilt»-linja BLIR staaende. Den ble skjult for aa holde radene korte,
       men baerer naa alderen paa en ubetalt bestilling — og det er nettopp den
       opplysningen man er ute etter naar man rydder i koen fra telefonen. */
    .list-item.admin-order-row .admin-order-nar { font-size: 0.72rem; }
}

/* Admin ticket type columns */
.admin-tt-col-name    { flex: 2 1 200px; min-width: 0; }
.admin-tt-col-price   { flex: 0 0 80px; }
.admin-tt-col-qty     { flex: 0 0 90px; }
.admin-tt-col-zone    { flex: 0 0 90px; }
.admin-tt-col-actions { flex: 0 0 30px; text-align: right; }

@media (max-width: 575.98px) {
    .list-item.col-list-row > .admin-tt-col-name    { flex: 1 1 0; order: 1; }
    .list-item.col-list-row > .admin-tt-col-price   { flex: 0 0 auto; order: 2; font-weight: 600; }
    .list-item.col-list-row > .admin-tt-col-actions  { flex: 0 0 auto; order: 3; }
    .list-item.col-list-row > .admin-tt-col-qty     { flex: 0 0 auto; order: 4; font-size: 0.75rem; }
    .list-item.col-list-row > .admin-tt-col-zone    { flex: 0 0 auto; order: 5; font-size: 0.75rem; }
}

/* ── Bemanningslista  ·  /admin/crew ──────────────────────────────────
   Kolonnene, og bare kolonnene: base-layouten ligger i `.col-list-row` og
   `.col-list-header`.

   Erstattet `.admin-crew-*`, som var en egen rad-grid med sin egen
   `gap`-overstyring og sitt eget mobilbrekk paa 768 px — altsaa en kopi av
   base-klassene med andre tall. Avataren laa i en EGEN kolonne der, og det
   ga en overskriftscelle uten overskrift; den ligger naa inne i
   navnekolonnen, som i `/admin/users`. */
.crw-col-navn        { flex: 2 1 190px; min-width: 0; }
.crw-col-navn > span { min-width: 0; }
.crw-col-epost       { flex: 2 1 180px; min-width: 0; }
/* Alderen staar her for vaktlistenes skyld — en femtenaaring skal ikke settes
   paa nattevakt. Fast og smal: «15 aar» og «—» er like brede uansett rad. */
.crw-col-alder       { flex: 0 0 58px; }
/* Fast bredde, aldri `auto`: rollenavnet varierer i lengde («Admin» mot
   «Spill-ansvarlig»), og en variabel bredde her forskyver radene i forhold
   til hverandre. Samme grunn som `.past-ticket-col-status`.

   `min-width: 0` + `ellipsis` er det som faktisk HOLDER bredden: en flex-item
   nekter aa krympe under innholdet sitt (`min-width: auto`), saa uten den
   sprenger et langt rollenavn boksen og skyver resten av raden — noeyaktig
   feilen `.past-ticket-col-status` fikk. Navnet staar ogsaa i `title`. */
.crw-col-rolle {
    flex: 0 0 150px;
    min-width: 0;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.crw-col-handling    { flex: 0 0 40px; justify-content: flex-end; }

@media (max-width: 575.98px) {
    .list-item.col-list-row > .crw-col-navn     { flex: 1 1 0; order: 1; }
    /* `0 1 auto` og ikke `0 0 auto`: et langt rollenavn skal krympe med
       ellipsis, ikke skyve navnet ut av linja. */
    .list-item.col-list-row > .crw-col-rolle    { flex: 0 1 auto; order: 2; }
    .list-item.col-list-row > .crw-col-handling { flex: 0 0 auto; order: 3; }

    /* Linje to er e-post OG alder.
       `70%` er det som FAKTISK bryter linja: flex bryter paa
       flex-basis, saa med `0` (foerste forsoek) fant e-posten plass paa
       linje én, og da ble navnet klippet til «Ro…». Med 70 % er den for
       bred for resten av linja og faller ned — mens alderen paa ~40 px
       fortsatt faar plass ved siden av, saa raden blir to linjer og ikke
       tre. Se `lister.md`: maks to linjer. */
    .list-item.col-list-row > .crw-col-epost {
        flex: 1 1 70%; order: 4; min-width: 0; font-size: 0.75rem;
    }
    .list-item.col-list-row > .crw-col-alder {
        flex: 0 0 auto; order: 5; font-size: 0.75rem;
    }
}

/* Admin crew roles columns — desktop */
.admin-crewrole-row {
    gap: 0.75rem !important;
    align-items: center;
}
.admin-crewrole-col-color   { flex: 0 0 20px; }
.admin-crewrole-col-name    { flex: 1 1 140px; min-width: 0; }
.admin-crewrole-col-desc    { flex: 1 1 180px; min-width: 0; }
.admin-crewrole-col-perms   { flex: 0 0 110px; }
.admin-crewrole-col-actions { flex: 0 0 70px; text-align: right; }

.admin-crewrole-header { display: flex; }

@media (max-width: 767.98px) {
    .admin-crewrole-header { display: none !important; }

    .list-item.admin-crewrole-row {
        flex-wrap: wrap;
        gap: 0.15rem 0.5rem !important;
    }
    /* Line 1: color + name + perms badge */
    .list-item.admin-crewrole-row > .admin-crewrole-col-color { flex: 0 0 16px; order: 1; }
    .list-item.admin-crewrole-row > .admin-crewrole-col-name  { flex: 1 1 0; min-width: 0; order: 2; }
    .list-item.admin-crewrole-row > .admin-crewrole-col-perms { flex: 0 0 auto; order: 3; }

    /* Line 2: description (hidden on mobile — already in name col) */
    .list-item.admin-crewrole-row > .admin-crewrole-col-desc  { display: none !important; }
    .list-item.admin-crewrole-row > .admin-crewrole-col-actions { flex: 0 0 auto; order: 4; }
}

/* ══════════════════════════════════════════
   STAT CARDS
   ══════════════════════════════════════════ */

.stat-card {
    position: relative;
    overflow: hidden;
    border-radius: var(--vl-radius);
    background: var(--vl-bg-card);
    border: 1px solid var(--vl-glass-border);
    padding: 1.1rem 1rem;
    text-align: center;
}

.stat-card-icon {
    position: absolute;
    top: -8px;
    right: -8px;
    font-size: 3.5rem;
    opacity: 0.07;
    pointer-events: none;
}

.stat-card-value {
    font-size: 1.6rem;
    font-weight: 700;
    line-height: 1.2;
}

.stat-card-value small {
    font-size: 0.75rem;
    font-weight: 400;
    opacity: 0.5;
}

.stat-card-label {
    font-size: 0.75rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    opacity: 0.6;
    margin-top: 0.15rem;
}

.stat-card.stat-primary   { border-left: 3px solid var(--vl-primary); }
.stat-card.stat-success   { border-left: 3px solid #00b894; }
.stat-card.stat-warning   { border-left: 3px solid #fdcb6e; }
.stat-card.stat-danger    { border-left: 3px solid #e17055; }
.stat-card.stat-info      { border-left: 3px solid var(--vl-accent); }

.stat-card.stat-primary .stat-card-icon  { color: var(--vl-primary); }
.stat-card.stat-success .stat-card-icon  { color: #00b894; }
.stat-card.stat-warning .stat-card-icon  { color: #fdcb6e; }
.stat-card.stat-danger .stat-card-icon   { color: #e17055; }
.stat-card.stat-info .stat-card-icon     { color: var(--vl-accent); }

.stat-card.stat-primary .stat-card-value { color: var(--vl-primary); }
.stat-card.stat-success .stat-card-value { color: #00b894; }
.stat-card.stat-warning .stat-card-value { color: #fdcb6e; }
.stat-card.stat-danger .stat-card-value  { color: #e17055; }
.stat-card.stat-info .stat-card-value    { color: var(--vl-accent); }

/* Inline stat card – compact row layout for toolbars */
.stat-card.stat-card-inline {
    display: flex;
    flex-direction: column;
    padding: 0.5rem 0.75rem;
}
.stat-card.stat-card-inline .stat-card-value { font-size: 1rem; }
.stat-card.stat-card-inline .stat-card-label { font-size: 0.65rem; }

/* ══════════════════════════════════════════
   TOAST NOTIFICATIONS
   ══════════════════════════════════════════ */

/* ══════════════════════════════════════════
   MELD FEIL ELLER FORSLAG

   Flytende knapp nederst til hoyre, paa alle flater unntatt apparatene.
   Se `components/report-widget.js` for hvorfor.
   ══════════════════════════════════════════ */

.report-fab {
    position: fixed;
    bottom: 1.5rem;
    right: 1.5rem;
    z-index: 1040;
    height: 46px;
    padding: 0 14px;
    display: inline-flex;
    align-items: center;
    gap: 0;
    border: 1px solid var(--vl-glass-border);
    border-radius: 999px;
    background: var(--vl-bg-elevated);
    color: var(--vl-text-muted);
    font-size: 0.86rem;
    font-weight: 600;
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.45);
    cursor: pointer;
    /* `width` er ikke animerbar fra `auto`. `max-width` er det, og gir samme
       utfoldelse uten aa maatte maale teksten. */
    max-width: 46px;
    overflow: hidden;
    white-space: nowrap;
    transition: max-width 0.25s ease, color 0.15s, border-color 0.15s, background 0.15s;
}
.report-fab i { min-width: 18px; text-align: center; font-size: 1rem; }

.report-fab-tekst {
    opacity: 0;
    margin-left: 10px;
    transition: opacity 0.2s ease;
}

.report-fab:hover,
.report-fab:focus-visible {
    max-width: 260px;
    color: var(--vl-text);
    border-color: var(--vl-accent);
    background: var(--vl-bg-card-solid);
}
.report-fab:hover .report-fab-tekst,
.report-fab:focus-visible .report-fab-tekst { opacity: 1; }

/* Toastene skyves opp naar knappen er der. */
body.has-report-fab .toast-container { bottom: 5.2rem; }

/* ── Naar en chat-komponist ligger i veien ──

   Knappen er fast nederst til hoyre, og det er ogsaa send-knappen i
   `.chat-input-area` (/crew/support, /app/messages). De laa oppaa hverandre.

   Knappen SKJULES ikke: den skal vaere tilgjengelig paa alle flater
   (beslutning 269). I stedet flyttes den opp over komponisten — samme grep som
   toastene over, og av samme grunn: flytt det som kolliderer, ikke det som
   skal vaere der.

   `:has()` gjor at ingen sidefil trenger aa vite om knappen. Nettlesere uten
   stotte faar den gamle overlappingen, ikke en odelagt side. */
body.has-report-fab:has(.chat-input-area) .report-fab {
    bottom: 5.4rem;
}

/* Komponisten faar litt luft til hoyre, saa knappen ikke lander rett oppaa
   send-knappen naar den folder seg ut ved hover. */
body.has-report-fab .chat-input-area {
    padding-right: 1.25rem;
}

/* Paa telefon er det ikke plass til at knappen folder seg ut, og en hover
   finnes uansett ikke. Da er den bare ikonet. */
@media (max-width: 575.98px) {
    .report-fab { bottom: 1rem; right: 1rem; }
    body.has-report-fab:has(.chat-input-area) .report-fab { bottom: 4.6rem; }
    .report-fab:hover, .report-fab:focus-visible { max-width: 46px; }
    .report-fab-tekst { display: none; }
    body.has-report-fab .toast-container { bottom: 4.4rem; }
}

@media (prefers-reduced-motion: reduce) {
    .report-fab, .report-fab-tekst { transition: none; }
}

/* ── Skjemaet ── */

.report-type { display: flex; gap: 0.6rem; margin-bottom: 1.1rem; flex-wrap: wrap; }
.report-type-valg { flex: 1 1 160px; cursor: pointer; }
.report-type-valg input { position: absolute; opacity: 0; pointer-events: none; }
.report-type-valg span {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    padding: 0.65rem 0.8rem;
    border: 1px solid var(--vl-glass-border);
    border-radius: var(--vl-radius-sm);
    color: var(--vl-text-muted);
    font-size: 0.88rem;
    transition: all 0.15s;
}
.report-type-valg:hover span { border-color: rgba(255, 255, 255, 0.25); color: var(--vl-text); }
.report-type-valg input:checked + span {
    border-color: var(--vl-primary);
    background: rgba(108, 92, 231, 0.14);
    color: var(--vl-text);
}
/* Tastaturbrukeren maa se hvor fokus staar — avkrysningen selv er skjult. */
.report-type-valg input:focus-visible + span { outline: 2px solid var(--vl-accent); outline-offset: 2px; }

.report-forhandsvis {
    margin-top: 0.7rem;
    display: flex;
    align-items: flex-start;
    gap: 0.7rem;
}
.report-forhandsvis img {
    max-width: 180px;
    max-height: 120px;
    border-radius: var(--vl-radius-xs);
    border: 1px solid var(--vl-glass-border);
}

.toast-container {
    position: fixed;
    /* Innmeldingsknappen bor i samme hjornet. Uten dette ville toastene lagt
       seg oppa den — to faste elementer i samme hjorne maa bli enige.
       `.has-report-fab` settes av `report-widget.js` og er borte paa
       apparatflatene, der knappen ikke vises. */
    bottom: 1.5rem;
    right: 1.5rem;
    z-index: 9999;
    display: flex;
    flex-direction: column-reverse;
    gap: 0.5rem;
    pointer-events: none;
}

.vl-toast {
    background: var(--vl-bg-elevated);
    border: 1px solid var(--vl-glass-border);
    border-radius: var(--vl-radius-sm);
    padding: 0.75rem 1rem;
    font-size: 0.875rem;
    color: var(--vl-text);
    backdrop-filter: blur(20px);
    pointer-events: auto;
    cursor: pointer;
    opacity: 0;
    transform: translateY(10px);
    transition: opacity 0.2s, transform 0.2s;
    max-width: 360px;
    display: flex;
    align-items: center;
}

.vl-toast.show { opacity: 1; transform: translateY(0); }
.vl-toast-success { border-left: 3px solid #28a745; }
.vl-toast-danger { border-left: 3px solid #dc3545; }
.vl-toast-warning { border-left: 3px solid #ffc107; }
.vl-toast-info { border-left: 3px solid var(--vl-primary); }

.vl-toast-success i { color: #28a745; }
.vl-toast-danger i { color: #dc3545; }
.vl-toast-warning i { color: #ffc107; }
.vl-toast-info i { color: var(--vl-primary); }

/* ══════════════════════════════════════════
   VARSELLINJE — vedvarende varsel med én handling
   ══════════════════════════════════════════

   For det som IKKE er et resultat av en handling, og som derfor ikke kan
   forsvinne av seg selv. Toast er feil komponent til det: den staar i fire
   sekunder og er for «lagret», «slettet», «sendt» (interaksjon.md).

   Nede til VENSTRE med vilje. Bunnen til hoyre har toast-beholderen,
   innmeldingsknappen og `.chat-input-area`, og tre regler lenger opp i denne
   fila flytter dem rundt hverandre. Et fjerde element der ville krevd en
   fjerde regel. */

.varsellinje {
    position: fixed;
    bottom: 1.25rem;
    left: 1.25rem;
    z-index: 9997;   /* under toast (9999) og confirm (9998) */
    display: flex;
    align-items: center;
    gap: 0.6rem;
    max-width: calc(100vw - 2.5rem);
    padding: 0.6rem 0.7rem 0.6rem 0.9rem;
    font-size: 0.875rem;
    color: var(--vl-text);
    background: var(--vl-bg-elevated);
    border: 1px solid var(--vl-glass-border);
    border-radius: var(--vl-radius-sm);
    backdrop-filter: blur(20px);
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.35);
}

.varsellinje > i { color: var(--vl-primary); }

.varsellinje span { min-width: 0; }

.varsellinje-lukk {
    display: flex;
    align-items: center;
    padding: 0.25rem 0.35rem;
    color: var(--vl-text-muted);
    background: none;
    border: 0;
    cursor: pointer;
    font-size: 0.8rem;
}

.varsellinje-lukk:hover,
.varsellinje-lukk:focus-visible { color: var(--vl-text); }

/* Paa telefon faar linja hele bredden framfor aa bli en smal stripe i
   hjornet. Innmeldingsknappen staar nede til hoyre paa 1rem, saa linja
   stopper foer den. */
@media (max-width: 575.98px) {
    .varsellinje {
        left: 1rem;
        right: 4.2rem;
        bottom: 1rem;
        max-width: none;
    }
}

/* ══════════════════════════════════════════
   CONFIRM DIALOG
   ══════════════════════════════════════════ */

.vl-confirm-backdrop {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.5);
    z-index: 9998;
    display: flex;
    align-items: center;
    justify-content: center;
    opacity: 0;
    transition: opacity 0.15s;
}

.vl-confirm-backdrop.show { opacity: 1; }

.vl-confirm-dialog {
    background: var(--vl-bg-card-solid);
    border: 1px solid var(--vl-glass-border);
    border-radius: var(--vl-radius);
    padding: 1.5rem;
    max-width: 400px;
    width: 90%;
}

/* ══════════════════════════════════════════
   MODAL (dark theme overrides for Bootstrap)
   ══════════════════════════════════════════ */

/* Backdrop — blurred overlay behind modals */
.modal-backdrop-custom {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.6);
    backdrop-filter: blur(4px);
    z-index: 1050;
}

/* Dark theme: content, header, footer, close button */
.modal-content {
    background: var(--vl-bg-card-solid);
    border: 1px solid var(--vl-glass-border);
    border-radius: var(--vl-radius);
    color: var(--vl-text);
}

.modal-header {
    border-bottom: none;
    padding: 1rem 1.25rem;
}

.modal-footer {
    border-top: none;
    padding: 0.75rem 1.25rem;
}

.modal-body {
    padding: 1.25rem;
}

.modal .btn-close {
    filter: invert(1) grayscale(100%) brightness(200%);
}

/* ── Image Picker modal ── */

/* Inline search */
.imgpicker-search-wrap {
    position: relative;
    display: flex;
    align-items: center;
}

.imgpicker-search-wrap i {
    position: absolute;
    left: 10px;
    font-size: 0.75rem;
    color: var(--vl-text-muted);
    pointer-events: none;
}

.imgpicker-search-wrap input {
    background: var(--vl-bg-secondary);
    border: 1px solid var(--vl-glass-border);
    border-radius: var(--vl-radius-sm);
    color: var(--vl-text);
    font-size: 0.8rem;
    padding: 0.3rem 0.6rem 0.3rem 1.8rem;
    width: 180px;
    outline: none;
    transition: border-color 0.15s;
}

.imgpicker-search-wrap input:focus {
    border-color: var(--vl-primary);
}

/* Folder overview grid */
.imgpicker-folder-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
    gap: 0.75rem;
}

.imgpicker-folder-card {
    border-radius: var(--vl-radius-sm);
    overflow: hidden;
    cursor: pointer;
    border: 1px solid var(--vl-glass-border);
    transition: border-color 0.15s, transform 0.15s;
    background: var(--vl-bg-secondary);
}

.imgpicker-folder-card:hover {
    border-color: var(--vl-primary);
    transform: translateY(-2px);
}

.imgpicker-folder-thumb {
    aspect-ratio: 16/9;
    overflow: hidden;
}

.imgpicker-folder-thumb img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.imgpicker-folder-info {
    padding: 0.5rem 0.65rem;
    display: flex;
    align-items: center;
    gap: 0.25rem;
    font-size: 0.8rem;
}

.imgpicker-folder-info i {
    color: var(--vl-text-muted);
    font-size: 0.7rem;
}

.imgpicker-folder-name {
    flex: 1;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.imgpicker-folder-count {
    color: var(--vl-text-muted);
    font-size: 0.7rem;
}

/* Back button */
.imgpicker-back {
    display: inline-flex;
    align-items: center;
    background: none;
    border: none;
    color: var(--vl-text-muted);
    font-size: 0.8rem;
    cursor: pointer;
    padding: 0.25rem 0;
    margin-bottom: 0.75rem;
    transition: color 0.15s;
}

.imgpicker-back:hover {
    color: var(--vl-text);
}

/* Image grid */
.imgpicker-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(130px, 1fr));
    gap: 0.5rem;
    max-height: 340px;
    overflow-y: auto;
}

.imgpicker-thumb {
    position: relative;
    aspect-ratio: 16/9;
    border-radius: var(--vl-radius-sm);
    overflow: hidden;
    cursor: pointer;
    border: 2px solid transparent;
    transition: border-color 0.15s, transform 0.15s;
}

.imgpicker-thumb:hover {
    border-color: var(--vl-primary);
    transform: scale(1.03);
}

.imgpicker-thumb--active {
    border-color: var(--vl-primary);
    box-shadow: 0 0 0 2px rgba(108, 92, 231, 0.4);
}

.imgpicker-thumb--current::after {
    content: 'N\00e5v\00e6rende';
    position: absolute;
    top: 4px;
    left: 4px;
    font-size: 0.6rem;
    padding: 1px 5px;
    border-radius: 3px;
    background: var(--vl-primary);
    color: #fff;
}

.imgpicker-thumb img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.imgpicker-thumb-label {
    position: absolute;
    bottom: 0;
    left: 0;
    right: 0;
    font-size: 0.6rem;
    padding: 2px 6px;
    background: rgba(0, 0, 0, 0.6);
    color: rgba(255, 255, 255, 0.7);
    text-align: center;
}

/* Upload zone */
.imgpicker-upload-zone {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    padding: 2rem;
    border: 2px dashed var(--vl-glass-border);
    border-radius: var(--vl-radius);
    cursor: pointer;
    transition: border-color 0.2s, background 0.2s;
    text-align: center;
}

.imgpicker-upload-zone:hover,
.imgpicker-upload-zone--hover {
    border-color: var(--vl-primary);
    background: rgba(108, 92, 231, 0.05);
}

.imgpicker-size-hint {
    margin-top: 1.25rem;
    text-align: center;
}

.imgpicker-size-hint-diagram {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    max-width: 280px;
    width: 100%;
    border: 1px dashed rgba(255, 255, 255, 0.2);
    border-radius: var(--vl-radius-sm);
    background: rgba(255, 255, 255, 0.03);
    color: rgba(255, 255, 255, 0.4);
    font-size: 0.75rem;
    padding: 0.5rem;
}

@media (max-width: 575.98px) {
    .imgpicker-grid {
        grid-template-columns: repeat(auto-fill, minmax(100px, 1fr));
        max-height: 280px;
    }
    .imgpicker-folder-grid {
        grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
    }
    .imgpicker-search-wrap input {
        width: 140px;
    }
}

/* ========================================
   User search result item
   Reusable component for user search across the app.
   Used in: ticket assign, crew add, team invite, messages.
   ======================================== */

.user-search-item {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.5rem;
    border-radius: var(--vl-radius-sm, 0.375rem);
    cursor: pointer;
    transition: background 0.15s;
}

.user-search-item:hover {
    background: var(--vl-glass);
}

.user-search-avatar {
    width: 32px;
    height: 32px;
    border-radius: 50%;
    object-fit: cover;
    flex-shrink: 0;
}

.user-search-info {
    flex: 1;
    min-width: 0;
}

.user-search-name {
    font-weight: 600;
    font-size: 0.9rem;
    line-height: 1.3;
}

.user-search-detail {
    color: var(--vl-text-muted, #6c757d);
    font-size: 0.75rem;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.user-search-action {
    flex-shrink: 0;
    margin-left: auto;
}

/* ══════════════════════════════════════════
   SHOUTBOX (public chat widget)
   ══════════════════════════════════════════ */

.shoutbox {
    display: flex;
    flex-direction: column;
    background: var(--vl-bg-card-solid, #1a1a2e);
    border: 1px solid var(--vl-glass, rgba(255,255,255,0.06));
    border-radius: var(--vl-radius, 0.75rem);
    overflow: hidden;
}

.shoutbox-header {
    display: flex;
    align-items: center;
    padding: 0.6rem 0.85rem;
    font-size: 0.85rem;
    font-weight: 600;
    border-bottom: 1px solid var(--vl-glass, rgba(255,255,255,0.06));
    color: var(--vl-text, #eee);
}

.shoutbox-status {
    font-size: 0.7rem;
    font-weight: 400;
}

.shoutbox-messages {
    flex: 1;
    overflow-y: auto;
    padding: 0.5rem;
    min-height: 200px;
    max-height: 400px;
    scroll-behavior: smooth;
}

.shoutbox-msg {
    display: flex;
    gap: 0.5rem;
    padding: 0.25rem 0.35rem;
    border-radius: 0.35rem;
    transition: background 0.15s;
}
.shoutbox-msg:hover {
    background: var(--vl-glass, rgba(255,255,255,0.03));
}

.shoutbox-avatar {
    width: 28px;
    height: 28px;
    border-radius: 50%;
    object-fit: cover;
    flex-shrink: 0;
    margin-top: 2px;
}

.shoutbox-msg-body {
    min-width: 0;
    flex: 1;
}

.shoutbox-msg-header {
    display: flex;
    align-items: baseline;
    gap: 0.4rem;
    line-height: 1.2;
}

.shoutbox-msg-name {
    font-size: 0.78rem;
    font-weight: 600;
    color: var(--vl-primary, #6c5ce7);
    text-decoration: none;
    white-space: nowrap;
}
.shoutbox-msg-name:hover {
    text-decoration: underline;
}

.shoutbox-msg-time {
    font-size: 0.65rem;
    color: var(--vl-text-muted, #888);
    white-space: nowrap;
}

.shoutbox-msg-delete {
    background: none;
    border: none;
    color: var(--vl-text-muted, #888);
    font-size: 0.6rem;
    padding: 0;
    margin-left: auto;
    cursor: pointer;
    opacity: 0;
    transition: opacity 0.15s;
}
.shoutbox-msg:hover .shoutbox-msg-delete {
    opacity: 0.6;
}
.shoutbox-msg-delete:hover {
    opacity: 1 !important;
    color: var(--bs-danger, #e74c3c);
}

.shoutbox-msg-text {
    font-size: 0.8rem;
    line-height: 1.4;
    color: var(--vl-text, #ddd);
    word-break: break-word;
}

.shoutbox-input {
    display: flex;
    gap: 0.35rem;
    padding: 0.5rem;
    border-top: 1px solid var(--vl-glass, rgba(255,255,255,0.06));
}
.shoutbox-input .form-control {
    font-size: 0.8rem;
}
.shoutbox-input .btn {
    flex-shrink: 0;
}

/* ══════════════════════════════════════════
   ROUND ICON BUTTON
   ══════════════════════════════════════════ */

.btn-icon-round {
    width: 36px;
    height: 36px;
    padding: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: 50%;
    font-size: 0.85rem;
    line-height: 1;
    flex-shrink: 0;
}
.btn-icon-round.btn-sm {
    width: 32px;
    height: 32px;
    font-size: 0.8rem;
}

/* ══════════════════════════════════════════
   POLL WIDGET
   ══════════════════════════════════════════ */

.poll-option-card {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    padding: 0.6rem 0.85rem;
    border-radius: var(--vl-radius, 8px);
    border: 1px solid var(--vl-glass-border, rgba(255,255,255,0.08));
    background: var(--vl-bg-elevated, rgba(255,255,255,0.03));
    cursor: pointer;
    transition: border-color 0.15s, background 0.15s;
    margin: 0;
}
.poll-option-card:hover {
    border-color: var(--vl-primary);
    background: rgba(108, 92, 231, 0.06);
}
.poll-option-card.active,
.poll-option-card:has(input:checked) {
    border-color: var(--vl-primary);
    background: rgba(108, 92, 231, 0.1);
}
.poll-option-indicator {
    font-size: 1.1rem;
    color: var(--vl-text-muted, #888);
    flex-shrink: 0;
    width: 1.2rem;
    text-align: center;
}
.poll-option-indicator .fas { display: none; color: var(--vl-primary); }
.poll-option-indicator .far { display: inline; }
.poll-option-card:has(input:checked) .poll-option-indicator .fas { display: inline; }
.poll-option-card:has(input:checked) .poll-option-indicator .far { display: none; }
.poll-option-text {
    font-size: 0.9rem;
}
/* Ett spørsmål i en undersøkelse. Luft og en hårstrek mellom dem — med
   bare `mb-3` leste fjorten spørsmål som én lang liste med kort, og man så
   ikke hvor det ene sluttet. Se docs/moduler/avstemninger.md. */
.poll-question { margin-bottom: 1.75rem; }
/* Første spørsmål løst fra arrangementslinja over skjemaet. */
.poll-vote-form > .poll-question:first-child { margin-top: 1.25rem; }
.poll-question + .poll-question {
    padding-top: 1.5rem;
    border-top: 1px solid var(--vl-border-light, rgba(255,255,255,0.06));
}
.poll-question-label {
    font-weight: 600;
    font-size: 0.95rem;
    margin-bottom: 0.75rem;
}

/* Skala 1–5 (`poll_questions.type = scale`): fem like knapper på rad, også
   på mobil — fem kolonner à ~55 px får plass i 320 px. */
.poll-skala {
    display: grid;
    grid-template-columns: repeat(5, 1fr);
    gap: 0.5rem;
}
/* `position: relative` holder den usynlige radioknappen (`.visually-hidden`
   er absolutt) INNE i knappen. Uten den ble den plassert mot hele dokumentet,
   langt under appen, og et klikk ga den fokus — nettleseren rullet da hele
   dokumentet ned, og halve vinduet ble tomt (Robert 05.10.2026). */
.poll-skala-knapp,
.poll-skala-na { position: relative; }
.poll-skala-knapp {
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 3rem;
    margin: 0;
    border-radius: var(--vl-radius, 8px);
    border: 1px solid var(--vl-glass-border, rgba(255,255,255,0.08));
    background: var(--vl-bg-elevated, rgba(255,255,255,0.03));
    color: var(--vl-text-muted, #888);
    cursor: pointer;
    transition: border-color 0.15s, background 0.15s, color 0.15s;
}
.poll-skala-knapp:hover { border-color: var(--vl-primary); color: var(--vl-text); }
.poll-skala-knapp:has(input:checked) {
    border-color: var(--vl-primary);
    background: rgba(108, 92, 231, 0.18);
    color: var(--vl-text);
}
.poll-skala-knapp:has(input:focus-visible) { outline: 2px solid var(--vl-primary); outline-offset: 2px; }
.poll-skala-tall { font-size: 1.1rem; font-weight: 600; }
/* Fjesene er ekte emoji (Robert 05.10.2026: ikonene leste som ikoner, ikke
   som fjes). Hver knapp har likevel sin farge, fra rødt til grønt, i kanten
   og tonen bak når den er valgt — emojiene er gule alle sammen. Uvalgt er
   fjeset dempet, så det valgte skiller seg ut. */
.poll-skala--smil .poll-skala-knapp { font-size: 1.7rem; }
.poll-skala--smil .poll-skala-knapp:nth-child(1) { --fjes: #ff7675; }
.poll-skala--smil .poll-skala-knapp:nth-child(2) { --fjes: #fdab3d; }
.poll-skala--smil .poll-skala-knapp:nth-child(3) { --fjes: #fdcb6e; }
.poll-skala--smil .poll-skala-knapp:nth-child(4) { --fjes: #a3e07a; }
.poll-skala--smil .poll-skala-knapp:nth-child(5) { --fjes: #2ecc8f; }
.poll-skala-fjes {
    font-family: 'Apple Color Emoji', 'Segoe UI Emoji', 'Noto Color Emoji', sans-serif;
    line-height: 1;
    opacity: 0.6;
    transition: opacity 0.15s, transform 0.15s;
}
.poll-skala--smil .poll-skala-knapp:hover { border-color: var(--fjes); }
.poll-skala--smil .poll-skala-knapp:hover .poll-skala-fjes { opacity: 1; }
.poll-skala--smil .poll-skala-knapp:has(input:checked) {
    border-color: var(--fjes);
    background: color-mix(in srgb, var(--fjes) 18%, transparent);
}
.poll-skala--smil .poll-skala-knapp:has(input:checked) .poll-skala-fjes { opacity: 1; transform: scale(1.15); }
/* Unntaket og kommentarlenka er noe man trykker på, og skal ikke se ut som
   endepunktsteksten rett over (design/komponenter.md: informasjon og
   handling skal ikke ha samme form). Unntaket har kanten et valg har;
   lenka har aksentfargen. */
.poll-skala-na {
    display: inline-block;
    margin: 0;
    padding: 0.3rem 0.9rem;
    border-radius: 999px;
    border: 1px solid var(--vl-glass-border, rgba(255,255,255,0.12));
    background: var(--vl-bg-elevated, rgba(255,255,255,0.03));
    font-size: 0.8rem;
    color: var(--vl-text, #e6edf3);
    cursor: pointer;
}
.poll-skala-na:hover { border-color: var(--vl-primary); }
.poll-skala-na:has(input:checked) {
    border-color: var(--vl-primary);
    background: rgba(108, 92, 231, 0.18);
    color: var(--vl-text);
}
.poll-skala-na:has(input:focus-visible) { outline: 2px solid var(--vl-primary); outline-offset: 2px; }
/* «Legg til kommentar» under et spørsmål (`allow_comment`). Lukket som
   standard: et åpent felt under hvert spørsmål dobler lengden for alle. */
.poll-kommentar { margin-top: 0.6rem; }
.poll-kommentar > summary {
    display: inline-block;
    font-size: 0.8rem;
    color: var(--vl-accent, #00cec9);
    cursor: pointer;
    list-style: none;
}
.poll-kommentar > summary::-webkit-details-marker { display: none; }
/* ── Undersøkelseslista · /crew/polls ─────────────────────────────
   Bare kolonnene; base-layouten er `.col-list-row`/`.col-list-header`.
   Faste kolonner har fast bredde, aldri `auto` (design/lister.md). */
.pol-col-tittel   { flex: 2 1 240px; min-width: 0; }
.pol-under        { font-size: 0.78rem; }
.pol-col-hvem     { flex: 0 0 100px; }
.pol-col-anonym   { flex: 0 0 90px; }
.pol-col-svar     { flex: 0 0 70px; }
.pol-col-frist    { flex: 0 0 70px; }
.pol-col-status   { flex: 0 0 100px; }
.pol-col-handling { flex: 0 0 32px; justify-content: flex-end; }
@media (max-width: 575.98px) {
    /* Linje én: tittelen og menyen. Linje to: status, hvem, svar, frist.
       Basisen er det som bryter linja: med `0` fant de små plass på linje
       én og klemte tittelen til «[DEV-…». Statusen står på linje to fordi
       pilla varierer i bredde («Aktiv»/«Avsluttet») — menyen gjør ikke det,
       så tittelen kan ta resten av linja uten å gjette. */
    .list-item.col-list-row > .pol-col-tittel   { flex: 1 1 calc(100% - 3rem); order: 1; }
    .list-item.col-list-row > .pol-col-handling { flex: 0 0 auto; order: 2; }
    .list-item.col-list-row > .pol-col-status   { flex: 0 0 auto; order: 3; }
    .list-item.col-list-row > .pol-col-hvem,
    .list-item.col-list-row > .pol-col-svar,
    .list-item.col-list-row > .pol-col-frist    { flex: 0 0 auto; order: 4; font-size: 0.75rem; }
    .list-item.col-list-row > .pol-col-anonym   { display: none; }
}

/* ── Svarene · /crew/polls/{id}/svar ──────────────────────────────
   Fritekst, «Annet» og kommentarer står i en svak flate, med linjeskiftene
   som ble skrevet. Enkeltsvaret er spørsmål for spørsmål med en hårstrek
   mellom, som skjemaet den som svarte så. */
.svar-tekst {
    padding: 0.5rem 0.65rem;
    border-radius: var(--vl-radius, 8px);
    background: var(--vl-glass, rgba(255,255,255,0.03));
    font-size: 0.875rem;
    white-space: pre-line;
}
.svar-rad { padding: 0.75rem 0; border-bottom: 1px solid var(--vl-glass-border, rgba(255,255,255,0.08)); }
.svar-rad:first-child { padding-top: 0; }
.svar-rad:last-child { border-bottom: 0; padding-bottom: 0; }
.svar-fjes { font-size: 1.25rem; vertical-align: -0.15em; }

/* ── Dra og slipp — components/dra-sortering.js ──────────────────
   Hanken er greie-ikonet, ikke raden: drar du fra teksten mister du
   muligheten til å markere den. Raden som dras dempes framfor å
   forsvinne, og en strek viser hvor den lander. */
.dra-hank { cursor: grab; color: var(--vl-text-muted, #888); padding: 0.25rem; }
.dra-hank:active { cursor: grabbing; }
.dra-aktiv { opacity: 0.4; }
.dra-over-for { box-shadow: 0 -2px 0 0 var(--vl-primary); }
.dra-over-etter { box-shadow: 0 2px 0 0 var(--vl-primary); }

/* Spørsmålskortet i /crew/polls/{id}: toppen er alltid synlig og åpner
   kortet; kroppen står bare når det er åpent. */
.sp-kort-topp {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    padding: 0.7rem 0.9rem;
    cursor: pointer;
}
.sp-kort-nr {
    flex: 0 0 auto;
    min-width: 1.6rem;
    text-align: center;
    font-size: 0.8rem;
    font-weight: 600;
    color: var(--vl-text-muted, #888);
}
.sp-kort-tekst { flex: 1 1 auto; min-width: 0; }
.sp-kort-tittel { font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sp-kort-meta { font-size: 0.75rem; color: var(--vl-text-muted, #888); }
.sp-kort--apen .sp-kort-tittel { white-space: normal; }
/* `.card` har backdrop-filter og blir en egen stablingskontekst: uten
   dette legger menyen seg bak kortet under (design/interaksjon.md). */
.sp-kort:has(.dropdown-menu.show) { position: relative; z-index: 5; }

/* `anonymity = optional`: valget om å svare med navn, ved «Send svar». */
.poll-med-navn {
    display: flex;
    align-items: center;
    margin: 0;
    font-size: 0.8rem;
    color: var(--vl-text, #e6edf3);
    cursor: pointer;
}
.poll-med-navn .form-check-input { flex-shrink: 0; margin-top: 0; }
.poll-med-navn-hint { margin: 0.15rem 0 0 1.6rem; font-size: 0.75rem; color: var(--vl-text-muted, #888); }
/* Tekstfelt som vokser med teksten — utils/auto-voks.js. Over taket ruller
   det; `resize` lar den som vil, dra det større selv. */
.auto-voks { resize: vertical; max-height: 24rem; overflow-y: auto; }
.poll-kommentar > summary:hover { text-decoration: underline; }

.poll-skala-ender {
    display: flex;
    justify-content: space-between;
    gap: 1rem;
    margin-top: 0.4rem;
    font-size: 0.75rem;
    color: var(--vl-text-muted, #888);
}

/* Poll in CMS content (articles/pages): glass background since there's no .card wrapper */
.poll-embed > .poll-widget {
    background: var(--vl-glass);
    border: 1px solid var(--vl-glass-border);
    border-radius: var(--vl-radius, 8px);
    padding: 1rem;
}

/* ══════════════════════════════════════════
   METADATA ROWS (label + value pairs)
   ══════════════════════════════════════════ */

.meta-row {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding-bottom: 0.5rem;
    margin-bottom: 0.5rem;
    font-size: 0.85rem;
    border-bottom: 1px solid var(--vl-glass-border, rgba(255,255,255,0.08));
}
.meta-row:last-child {
    border-bottom: none;
    margin-bottom: 0;
    padding-bottom: 0;
}
.meta-row-label {
    color: var(--vl-text-muted, #888);
    min-width: 80px;
    flex-shrink: 0;
}

/* Admin interest list columns — desktop */
.admin-interest-row {
    gap: 0.75rem !important;
    align-items: center;
}
.admin-interest-col-name    { flex: 2 1 160px; min-width: 0; }
.admin-interest-col-nick    { flex: 1 1 110px; min-width: 0; }
.admin-interest-col-email   { flex: 2 1 180px; min-width: 0; }
.admin-interest-col-place   { flex: 1 1 110px; min-width: 0; }
.admin-interest-col-games   { flex: 2 1 180px; min-width: 0; }
.admin-interest-col-status  { flex: 0 0 110px; text-align: right; }
.admin-interest-col-date    { flex: 0 0 92px; text-align: right; }
.admin-interest-col-actions { flex: 0 0 34px; text-align: right; }

.admin-interest-header { display: flex; }

/* Mobil: skjul header, brett radene til kompakt 2-linjers layout */
@media (max-width: 767.98px) {
    .admin-interest-header { display: none !important; }

    .list-item.admin-interest-row {
        flex-wrap: wrap;
        align-items: flex-start;
        gap: 0.15rem 0.5rem !important;
    }
    /* Linje 1: navn + status */
    .list-item.admin-interest-row > .admin-interest-col-name   { flex: 1 1 0; min-width: 0; order: 1; }
    .list-item.admin-interest-row > .admin-interest-col-status { flex: 0 0 auto; order: 2; }
    .list-item.admin-interest-row > .admin-interest-col-actions { flex: 0 0 auto; order: 3; }

    /* Linje 2: kallenavn + e-post */
    .list-item.admin-interest-row > .admin-interest-col-nick   { flex: 0 0 auto; order: 4; font-size: 0.75rem; }
    .list-item.admin-interest-row > .admin-interest-col-email  { flex: 1 1 0; min-width: 0; order: 5; font-size: 0.75rem; }

    /* Sekundaert paa mobil — kommune, spill og dato tas bort for aa holde
       radene paa maks to linjer, jf. docs/design/lister.md */
    .list-item.admin-interest-row > .admin-interest-col-place { display: none !important; }
    .list-item.admin-interest-row > .admin-interest-col-games { display: none !important; }
    .list-item.admin-interest-row > .admin-interest-col-date  { display: none !important; }
}

/* ══════════════════════════════════════════
   BILDEFELT (standard for alle bildevalg)

   Ett moenster overalt: bildet ER knappen. Et kamera-overlay legger seg over
   ved hover, i stedet for en knapp ved siden. Knapper paa toppen av et cover
   ga uleselig tekst mot lyse bilder — overlayet har sin egen skygge og er
   lesbart uansett hva som ligger under.

   To varianter, etter hva bildet ER:
     .image-field--surface  flate (cover, banner, hero, avatar) — fyller
     .image-field--mark     merke (logo, ikon) — fyller ogsaa, men beskjaeres
                            av brukeren selv i cropperen foer opplasting
     .image-field--logo     sponsorlogo — VISES HEL, aldri beskaaret
   ══════════════════════════════════════════ */

.image-field {
    position: relative;
    display: block;
    overflow: hidden;
    border-radius: var(--vl-radius);
    background: var(--vl-bg-tertiary);
    border: 1px solid var(--vl-glass-border);
    cursor: pointer;
    padding: 0;
    width: 100%;
}

.image-field--round {
    border-radius: 50%;
}

.image-field img {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
}

/*
 * En sponsorlogo beskjaeres ikke ved opplasting (beslutning 301), saa den kan
 * heller ikke beskjaeres i forhaandsvisningen — da viser ruta noe annet enn
 * det som faktisk er lagret. `cover` gjorde nettopp det: en bred logo ble
 * zoomet inn til midtpartiet, og «Fosen IKT» stod som «sen».
 *
 * Padding og en lys flate fordi mange logoer er hvite med gjennomsiktig
 * bakgrunn — uten den forsvinner de i det morke feltet.
 */
.image-field--logo img {
    object-fit: contain;
    padding: 0.6rem;
}
.image-field--logo { background: #ffffff0a; }

/* Tom tilstand — ikon i midten, samme flate som naar det er bilde. */
.image-field-empty {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    height: 100%;
    color: var(--vl-text-muted);
    font-size: 1.5rem;
}

/* Overlayet. Alltid synlig paa touch (der finnes ingen hover), ellers
   ved hover og tastaturfokus. */
.image-field-overlay {
    position: absolute;
    inset: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0.35rem;
    background: rgba(0, 0, 0, 0.55);
    color: #fff;
    opacity: 0;
    transition: opacity 0.15s;
    font-size: 0.8rem;
    text-align: center;
    padding: 0.5rem;
}

.image-field:hover .image-field-overlay,
.image-field:focus-visible .image-field-overlay {
    opacity: 1;
}

.image-field-overlay i {
    font-size: 1.25rem;
}

@media (hover: none) {
    .image-field-overlay {
        opacity: 1;
        background: linear-gradient(to top, rgba(0, 0, 0, 0.7), transparent 60%);
        justify-content: flex-end;
    }
    .image-field-overlay span { display: none; }
}

/* Liten variant (logo/ikon ved siden av tekst) — bare kameraet, ingen tekst. */
.image-field--sm .image-field-overlay span { display: none; }
.image-field--sm .image-field-overlay i { font-size: 1rem; }

/* Fjern-knapp. Ligger utenfor selve flaten, saa et klikk paa bildet alltid
   betyr «bytt» og aldri «slett». */
.image-field-clear {
    position: absolute;
    top: 0.4rem;
    right: 0.4rem;
    z-index: 2;
    width: 26px;
    height: 26px;
    border-radius: 50%;
    border: none;
    background: rgba(0, 0, 0, 0.6);
    color: #fff;
    font-size: 0.75rem;
    display: none;
    align-items: center;
    justify-content: center;
}

.image-field:hover .image-field-clear { display: flex; }
.image-field-clear:hover { background: var(--bs-danger, #dc3545); }

/* ── Beskjaerer ── */

.cropper-frame {
    position: relative;
    overflow: hidden;
    margin: 0 auto;
    background: var(--vl-bg-tertiary);
    border: 1px solid var(--vl-glass-border);
    border-radius: var(--vl-radius);
    touch-action: none;
}

.cropper-frame--round {
    border-radius: 50%;
}

.cropper-image {
    position: absolute;
    top: 0;
    left: 0;
    transform-origin: 0 0;
    cursor: grab;
    user-select: none;
    max-width: none;
}

.cropper-image:active {
    cursor: grabbing;
}

/* ══════════════════════════════════════════
   MASTER–DETALJ  (skinne + innhold, én side)
   ══════════════════════════════════════════

   Navigasjon INNENFOR én seksjon — ikke panelnavigasjon. Panelene har ingen
   sidebar; hub-en er veien mellom seksjoner. Dette er veien mellom rader av
   samme type inne i én av dem, og sparer et hopp ut til en liste og inn igjen.

   Forutsetter en KORT liste (arrangementer: fem, +1 i aaret). Skinna viser alt
   uten scroll, og blir en chip-rad paa mobil i stedet for aa kollapse til to
   visninger. Er lista lang, er dette feil moenster — bruk en egen listeside.
   ══════════════════════════════════════════ */

.master-detail {
    display: grid;
    grid-template-columns: 260px minmax(0, 1fr);
    gap: 1.25rem;
}

/* INGEN sticky her — det var proevd, og det var feil.
 *
 * Skinna festet seg mens man scrollet, men innholdsruta bytter hoeyde naar man
 * bytter fane (1 spiller vs 5 turneringer). Da klemmes scroll-posisjonen,
 * skinna loesner fra festet og faller tilbake til naturlig plass — den hopper
 * opp og ned av et klikk som ikke gjaldt den.
 *
 * Hoeyden paa innholdet kan ikke stabiliseres uten aa vite hva den hoeyeste
 * fanen er, saa valget staar mellom «skinna kan hoppe» og «skinna ligger
 * stille og scroller med sida». Det siste er forutsigbart, og med 5–10 rader
 * oeverst paa sida er det lite aa vinne paa det foerste. */
.md-rail-inner {
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
}

.md-rail-search {
    position: relative;
    margin-bottom: 0.35rem;
}

.md-rail-search i {
    position: absolute;
    left: 0.7rem;
    top: 50%;
    transform: translateY(-50%);
    font-size: 0.75rem;
    color: var(--vl-text-muted);
    opacity: 0.7;
    pointer-events: none;
}

.md-rail-search input {
    width: 100%;
    padding: 0.5rem 0.7rem 0.5rem 2rem;
    border-radius: 9px;
    border: 1px solid var(--vl-border);
    background: var(--vl-glass);
    color: var(--vl-text);
    font-size: 0.85rem;
}

.md-rail-search input:focus {
    outline: none;
    border-color: var(--vl-primary);
}

.md-rail-empty {
    padding: 0.6rem 0.7rem;
    font-size: 0.85rem;
    margin: 0;
}

.md-rail-group {
    padding: 0.6rem 0.7rem 0.25rem;
    font-size: 0.7rem;
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--vl-text-muted);
    opacity: 0.7;
}

.md-rail-group:first-child { padding-top: 0; }

.md-rail-item {
    display: flex;
    align-items: center;
    gap: 0.65rem;
    padding: 0.6rem 0.7rem;
    border-radius: 10px;
    text-decoration: none;
    color: var(--vl-text-muted);
    border: 1px solid transparent;
    transition: background 0.15s, color 0.15s, border-color 0.15s;
}

.md-rail-item:hover {
    background: var(--vl-glass);
    color: var(--vl-text);
}

.md-rail-item.is-active {
    background: var(--vl-glass);
    border-color: var(--vl-border);
    color: var(--vl-text);
}

.md-rail-img {
    width: 30px;
    height: 30px;
    border-radius: 7px;
    object-fit: cover;
    flex: 0 0 30px;
}

/* Rader uten bilde (lokaler) faar et ikon i samme flate som bildet, saa
   skinna staar i samme rutenett uansett hva den lister. */
.md-rail-icon {
    width: 30px;
    height: 30px;
    border-radius: 7px;
    flex: 0 0 30px;
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--vl-glass);
    color: var(--vl-primary);
    font-size: 0.85rem;
}

.md-rail-text {
    display: flex;
    flex-direction: column;
    min-width: 0;
    flex: 1 1 auto;
}

.md-rail-name {
    font-weight: 600;
    font-size: 0.9rem;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* `nowrap` UTEN klipping er ikke en halv losning, det er verre enn ingen:
   teksten bryter ikke, men den stopper heller ikke — den renner ut av den 260
   px brede skinna og maler seg tvers over innholdsruta ved siden av. Det slo
   ut foerst i /crew/faq, der undertittelen er artikkelsammendraget og altsaa
   flere hundre tegn; i skinnene som lister arrangementer og lokaler er den et
   par ord, og da synes det ikke.

   `.md-rail-name` har hatt de tre linjene hele tiden. Denne manglet dem. */
.md-rail-sub {
    font-size: 0.75rem;
    opacity: 0.7;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Statusprikk framfor merkelapp: skinna skal leses paa ett blikk, og en rad
   merkelapper ville konkurrert med navnet den staar ved siden av. */
.md-rail-dot {
    width: 7px;
    height: 7px;
    border-radius: 50%;
    flex: 0 0 7px;
    background: var(--vl-text-muted);
}

.md-rail-dot.status-published,
.md-rail-dot.status-active    { background: var(--vl-accent); }
.md-rail-dot.status-draft     { background: #8b949e; }
.md-rail-dot.status-completed { background: #2ea043; }
.md-rail-dot.status-cancelled { background: #d1495b; }
/* Oppsettet er i veien for seg selv — se Tournament::setupIssues(). Gul og
   ikke roed: raden er ikke avlyst, den er feilstilt. */
.md-rail-dot.status-warning   { background: #e0a458; }

/* Kan vaere <a> (arrangementer, som har en egen /new-side) eller <button>
   (lokaler, som aapner en modal). Uten nullstillingen under arver knappen
   nettleserens egen bakgrunn, font og midtstilling, og de to blir ulike. */
.md-rail-new {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    width: 100%;
    margin-top: 0.35rem;
    padding: 0.6rem 0.7rem;
    border-radius: 10px;
    border: 1px dashed var(--vl-border);
    background: none;
    -webkit-appearance: none;
    appearance: none;
    color: var(--vl-text-muted);
    text-decoration: none;
    text-align: left;
    font: inherit;
    font-size: 0.85rem;
    cursor: pointer;
    transition: color 0.15s, border-color 0.15s;
}

.md-rail-new:hover {
    color: var(--vl-text);
    border-color: var(--vl-text-muted);
}

.md-pane {
    min-width: 0;   /* uten denne sprenger brede tabeller og cover-bildet rutenettet */
}

/* Knappen finnes bare paa mobil. Paa desktop ER kolonnen synlig hele tiden,
   og en knapp som sier det samme ville vaert stoy. */
.md-rail-trigger { display: none; }

/* ── Mobil: skinna blir en dropdown ──────────────────────────────────
   Foerste utgave var en vannrett rad man dro sideveis. Den er lettere aa
   bygge, men verre aa bruke: du ser bare noen av valgene, maa dra for aa
   finne resten, og ingenting sier at det ER mer der. En dropdown viser hele
   lista naar du aapner den, og sier i lukket tilstand hva du staar i — som er
   spoersmaalet man faktisk har paa en liten skjerm.

   Samme markup i begge former. Bare CSS skiller dem, saa den aktive
   markeringen ikke kan bli uenig med seg selv. */
@media (max-width: 991.98px) {
    .master-detail {
        grid-template-columns: minmax(0, 1fr);
        gap: 0.85rem;
    }

    .md-rail {
        position: relative;
        z-index: 5;
    }

    .md-rail-trigger {
        display: flex;
        align-items: center;
        gap: 0.75rem;
        width: 100%;
        padding: 0.8rem 0.9rem;
        border-radius: 12px;
        border: 1px solid var(--vl-border);
        background: var(--vl-glass);
        -webkit-appearance: none;
        appearance: none;
        color: var(--vl-text);
        text-align: left;
        font: inherit;
        cursor: pointer;
        transition: border-color 0.15s;
    }

    .md-rail-trigger:hover { border-color: var(--vl-text-muted); }

    .md-rail-chevron {
        margin-left: auto;
        font-size: 0.75rem;
        opacity: 0.6;
        transition: transform 0.18s ease;
    }

    .md-rail.is-open .md-rail-chevron { transform: rotate(180deg); }

    /* Panelet ligger OVER innholdet, ikke i flyten. Skjot det inn, og
       innholdet under ville hoppet ned hver gang lista aapnes. */
    .md-rail-inner {
        position: absolute;
        top: calc(100% + 0.4rem);
        left: 0;
        right: 0;
        z-index: 10;
        display: none;
        gap: 0.15rem;
        padding: 0.4rem;
        border-radius: 12px;
        border: 1px solid var(--vl-border);
        background: var(--vl-bg-card-solid);
        box-shadow: 0 12px 32px rgba(0, 0, 0, 0.45);
        max-height: min(60vh, 26rem);
        overflow-y: auto;
    }

    .md-rail.is-open .md-rail-inner { display: flex; }

    /* Luftigere rader enn i kolonnen: dette er trykkflater paa en liten
       skjerm, ikke en tett sidemeny. */
    .md-rail-item { padding: 0.75rem 0.7rem; }

    .md-rail-new {
        margin-top: 0.25rem;
        padding: 0.75rem 0.7rem;
    }
}

/* ══════════════════════════════════════════
   AVATAR
   ══════════════════════════════════════════

   Sirkel, bakgrunn og kant — paa selve <img>, uten wrapper.

   `.profile-img-sm/md/lg` gjor det samme, men er WRAPPER-klasser som krever
   en <div> rundt bildet. Den friksjonen er grunnen til at 13 steder i stedet
   skrev `class="rounded-circle" style="width:36px;height:36px"` for haand —
   og ingen av dem fikk bakgrunn. Et gjennomsiktig avatarbilde lot da coveret
   under skinne gjennom.

   Bakgrunnen er ikke pynt: standardavatarene og laglogoene er PNG/SVG med
   gjennomsiktighet.
   ══════════════════════════════════════════ */

.avatar {
    border-radius: 50%;
    object-fit: cover;
    background: var(--vl-bg-elevated);
    border: 1px solid var(--vl-glass-border);
    flex-shrink: 0;
}

.avatar-xs { width: 18px; height: 18px; }
.avatar-sm { width: 28px; height: 28px; }
.avatar-md { width: 36px; height: 36px; }
.avatar-lg { width: 44px; height: 44px; }
.avatar-xl { width: 96px; height: 96px; border-width: 3px; }

/* ── Merket ────────────────────────────────────────────────────────
   Soesterklassen til `.avatar`, med samme stoerrelsesskala: begge svarer paa
   «hvem/hva ER dette», men `.avatar` for en PERSON og `.mark` for en TING —
   et arrangement, et spill, en sponsor.

   Forskjellen som betyr noe er `object-fit`. En avatar er et foto og skal
   FYLLE flata si. Et merke er ofte en gjennomsiktig PNG/SVG med tekst langs
   kanten, og `cover` ville kuttet bort nettopp det som gjor det gjenkjennelig
   — derfor `contain`, med bakgrunn og litt luft saa merket ikke ligger klint
   mot kanten.

   Naar bruker du den? Naar flata er for liten til aa vise coveret. Et cover er
   1200x260, og krympet til 44px er det en stripe uten motiv. Se
   design/cover-bilder.md, «Cover eller merke». */
.mark {
    border-radius: var(--vl-radius-sm);
    object-fit: contain;
    background: var(--vl-bg-elevated);
    border: 1px solid var(--vl-glass-border);
    padding: 3px;
    flex-shrink: 0;
}

.mark-xs { width: 18px; height: 18px; padding: 2px; }
.mark-sm { width: 28px; height: 28px; }
.mark-md { width: 36px; height: 36px; }
.mark-lg { width: 44px; height: 44px; padding: 5px; }

/* ══ Billett — boarding pass ═══════════════════════════════════════
   Billetten er delt i en stamme og en avrivningsdel, med perforering og
   utstansing imellom. Formen er hele poenget: den skal leses som en billett
   paa en halv sekunds blikk, ogsaa naar den ligger i en liste med andre.

   Merk at dette IKKE er `.card`. `.card` har `backdrop-filter`, som klipper
   alt som stikker utenfor — og her stikker utstansingen med vilje utenfor.
   ────────────────────────────────────────────────────────────────── */
.ticket {
    position: relative;
    display: flex;
    background: var(--vl-bg-card-solid);
    border: 1px solid var(--vl-glass-border);
    border-radius: var(--vl-radius);
    overflow: hidden;
}

.ticket::before {
    content: "";
    position: absolute;
    inset: 0 0 auto 0;
    height: 3px;
    background: var(--vl-gradient-accent);
}

.ticket-main {
    flex: 1;
    min-width: 0;
    position: relative;
    padding: 1.25rem 1.4rem;
}

/* Coveret er BEVISST ikke med. Foerste utgave la det som svakt bakteppe bak
   teksten — det saa bra ut mot et rolig foto, men de ekte coverne er
   logoer og folkemengder, og da blir stammen rotete uansett hvor mye man
   demper. Fargebaandet i toppen gir billetten identitet nok. */

.ticket-in { position: relative; }

.ticket-head {
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    gap: 0.75rem;
}

.ticket-event {
    font-size: 1.14rem;
    font-weight: 700;
    letter-spacing: -0.01em;
    color: var(--vl-text);
    text-decoration: none;
    display: block;
}
.ticket-event:hover { color: var(--vl-accent); }

.ticket-when { font-size: 0.78rem; color: var(--vl-text-muted); }

.ticket-fields {
    display: flex;
    flex-wrap: wrap;
    gap: 0.6rem 1.9rem;
    margin-top: 1rem;
}

.ticket-k {
    font-size: 0.63rem;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    font-weight: 700;
    color: var(--vl-text-muted);
    margin-bottom: 2px;
}

.ticket-v { font-size: 0.94rem; font-weight: 600; }
.ticket-v--muted { color: var(--vl-text-muted); font-weight: 500; }

.ticket-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    margin-top: 1rem;
}

/* Skillet mellom egne billetter og dem man har gitt bort. Marginen er stor
   med vilje: gruppene skal ikke kunne forveksles naar man scroller forbi i
   doera. `.section-heading` er feil her — den har 5rem topp og hoerer til
   frittstaaende seksjoner nedover en side (se beslutning 142). */
.ticket-group-heading {
    display: flex;
    align-items: center;
    gap: 0.45rem;
    margin: 3rem 0 1rem;
    font-size: 0.7rem;
    font-weight: 700;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--vl-text-muted);
}

/* Er alt man har bortgitt, staar overskriften oeverst i lista og skal ikke
   dytte seg selv ned fra sidetittelen. */
.ticket-group-heading:first-child { margin-top: 0; }

/* ── Perforering ── */
.ticket-perf {
    position: relative;
    flex: 0 0 auto;
    width: 0;
    border-left: 2px dashed var(--vl-glass-border);
    margin: 18px 0;
}

/* Sirkelen ligger midt paa kanten og klippes av `overflow: hidden` paa
   `.ticket`, saa det som vises er en halvsirkel — biten som er stanset ut.

   Foerste utgave fylte hullet med `--vl-gradient` + `background-attachment:
   fixed`, for aa treffe noeyaktig de pikslene som ligger bak billetten
   uansett rulleposisjon. Mekanismen VIRKET, men resultatet var usynlig:
   gradienten er `#111827` der hullene ligger, og kortet er `#161b22`. To
   farger som er tre trinn fra hverandre gir ikke noe hull — brukeren saa
   ingen utstansing i det hele tatt.

   Naa `--vl-bg-dark` (`#0a0e17`), som er merkbart moerkere enn kortet, pluss
   en 1px kantring. Ringen er det som faktisk faar det til aa LESES som et
   hull: en ekte utstansing har en synlig snittkant, og den baerer formen selv
   naar fyllet ligger naer bakgrunnen. Fargen bommer noen trinn paa den ekte
   bakgrunnen bak, og det er en billigere pris enn en usynlig effekt. */
.ticket-notch {
    position: absolute;
    width: 22px;
    height: 22px;
    border-radius: 50%;
    background: var(--vl-bg-dark);
    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.13);
    left: -10px;
    /* Hullet er stanset gjennom ALT, ogsaa fargebaandet i toppen. Uten dette
       maler baandet over hullet og streken gaar ubrutt tvers over det — og
       da ser billetten ut som den er trykt, ikke stanset. */
    z-index: 1;
}
.ticket-notch--a { top: -29px; }
.ticket-notch--b { bottom: -29px; }

/* ── Avrivningsdelen ── */
.ticket-stub {
    flex: 0 0 186px;
    padding: 1.1rem 1rem;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0.6rem;
    text-align: center;
}

/* Plassen settes av foer bildet kommer, slik at kortet ikke hopper naar
   QR-en lander. 132 + 2 x 8 px polstring = 148. */
.ticket-qr-slot {
    width: 148px;
    height: 148px;
    display: flex;
    align-items: center;
    justify-content: center;
}

.ticket-qr {
    background: #fff;
    border: 0;
    border-radius: 10px;
    padding: 8px;
    line-height: 0;
    cursor: pointer;
    display: block;
}
.ticket-qr img { display: block; width: 132px; height: 132px; }
.ticket-qr:focus-visible { outline: 2px solid var(--vl-accent); outline-offset: 3px; }

.ticket-code {
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: 0.6rem;
    letter-spacing: 0.04em;
    line-height: 1.35;
    color: var(--vl-text-muted);
    word-break: break-all;
}

.ticket-stub-note {
    font-size: 0.72rem;
    color: var(--vl-text-muted);
    line-height: 1.35;
}
.ticket-stub-icon { font-size: 1.5rem; color: var(--vl-text-muted); opacity: 0.35; }

/* ── Gule og lyse merker maa ha MOERK tekst ──
   Bootstrap gir `.badge` hvit tekst uansett bakgrunn. Paa `bg-warning`
   (#ffc107) og `bg-info` (#0dcaf0) gir det hvitt paa lyst, som i praksis er
   uleselig — maalt paa en vanlig skjerm er kontrasten under 2:1.
   Kallstedene skrev derfor `bg-warning text-dark` for haand, 35 steder. Det
   virker helt til merket bygges DYNAMISK: `bg-${st.color}` kan ikke baere
   `text-dark`, og da faller det tilbake til hvitt. Det var slik statusen paa
   /app/orders/{id} ble staaende uleselig.
   Regelen hoerer i CSS-en, ikke i hvert kallsted. `text-dark` ved siden av
   blir bare overfloedig, ikke feil. */
.badge.bg-warning,
.badge.bg-info,
.badge.bg-light {
    color: #1a1d27;
}

/* ── Statusmerke (`.status-pill`) ──
   Dempet pille: tonet bakgrunn, tynn kant, farget tekst. Bootstraps
   `.badge bg-success` er en solid fargeklump, og ved siden av fargebaandet
   paa en billett tar den mer oppmerksomhet enn statusen fortjener.

   `.badge bg-*` er fortsatt standarden i lister og tabeller, der merket ER
   kolonnen og skal kunne skummes nedover. `.status-pill` er for merket som
   staar inne i et innholdsrikt kort og bare skal bekrefte en tilstand. */
.status-pill {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    padding: 0.2rem 0.6rem;
    border-radius: 999px;
    border: 1px solid;
    font-size: 0.72rem;
    font-weight: 600;
    letter-spacing: 0.02em;
    white-space: nowrap;
}

.status-pill--ok     { background: rgba(0, 206, 201, 0.14);  color: #00cec9; border-color: rgba(0, 206, 201, 0.32); }
.status-pill--wait   { background: rgba(255, 193, 7, 0.13);  color: #ffc107; border-color: rgba(255, 193, 7, 0.32); }
.status-pill--info   { background: rgba(108, 92, 231, 0.18); color: #a99bff; border-color: rgba(108, 92, 231, 0.38); }
.status-pill--danger { background: rgba(225, 112, 85, 0.14); color: #e17055; border-color: rgba(225, 112, 85, 0.32); }
.status-pill--off    { background: var(--vl-glass); color: var(--vl-text-muted); border-color: var(--vl-glass-border); }

/* ── QR i full skjerm ──
   Ved inngangen staar man i koe med telefonen i én haand. Da er en modal med
   ramme, tittel og lukkeknapp i veien: hvit flate fra kant til kant gir
   skanneren mest mulig kontrast, og koden i klartekst under er reserven naar
   skanningen ikke vil. */
.ticket-qr-full {
    position: fixed;
    inset: 0;
    z-index: 2000;
    background: #fff;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 1.25rem;
    padding: 1.5rem;
}

/* PNG-en blaases opp godt over sin egen stoerrelse. Uten `pixelated` glatter
   nettleseren modulkantene, og en uskarp QR er merkbart tyngre aa lese for en
   skanner enn en hard en. */
.ticket-qr-full img {
    width: min(78vw, 58vh);
    height: auto;
    image-rendering: pixelated;
}

.ticket-qr-full-code {
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: 0.8rem;
    letter-spacing: 0.08em;
    color: #000;
    text-align: center;
    word-break: break-all;
    max-width: 20rem;
}

.ticket-qr-full-meta {
    font-size: 0.85rem;
    color: #555;
    text-align: center;
}

.ticket-qr-full-close {
    position: absolute;
    top: 1rem;
    right: 1rem;
    width: 40px;
    height: 40px;
    border-radius: 50%;
    border: 1px solid #ddd;
    background: #fff;
    color: #333;
    font-size: 1.1rem;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
}

/* ── Mobil: perforeringen legger seg ned ──
   Avrivningsdelen flyttes under stammen, og utstansingen bytter kant. Paa en
   telefon er QR-en det eneste man skal frem til, saa den faar hele bredden. */
@media (max-width: 599px) {
    .ticket { flex-direction: column; }

    .ticket-main { padding: 1.1rem; }

    .ticket-fields { gap: 0.6rem 1.4rem; }

    .ticket-perf {
        width: auto;
        height: 0;
        border-left: 0;
        border-top: 2px dashed var(--vl-glass-border);
        margin: 0 18px;
    }

    .ticket-notch { left: auto; right: auto; top: -11px; bottom: auto; }
    .ticket-notch--a { left: -29px; }
    .ticket-notch--b { right: -29px; }

    .ticket-stub {
        flex: 1 1 auto;
        padding: 1.3rem 1.1rem 1.1rem;
    }
    /* QR-en er det eneste man skal frem til her, saa den faar bredden.
       Taket paa 340px er for at den ikke skal bli absurd paa en liten
       nettbrett-bredde som fortsatt treffer dette bruddpunktet. */
    .ticket-qr {
        width: 100%;
        max-width: 340px;
        padding: 10px;
    }
    .ticket-qr img { width: 100%; height: auto; }
    .ticket-qr-slot {
        width: 100%;
        max-width: 340px;
        height: auto;
        aspect-ratio: 1;
    }
    .ticket-code { font-size: 0.68rem; }
}

/* ── Grafer ──────────────────────────────────────────────────────────────
   Beholderen har fast hoyde og `position: relative` fordi Chart.js maaler mot
   naermeste posisjonerte forelder. Hoyden inkluderer aksebaandet under plottet:
   uten den plassen faar kortet en liten egen rullefelt, og x-etikettene blir
   klippet. */
.chart-box {
    position: relative;
    height: 260px;
    margin-top: 0.5rem;
}

.chart-table {
    max-height: 320px;
    overflow: auto;
    border-top: 1px solid var(--vl-border-light);
    margin-top: 0.5rem;
}

/* Tall i kolonner skal ligge under hverandre. Store enkelttall (stat-kort)
   skal IKKE ha dette — der gjor like brede sifre at «121» ser lost ut. */
.chart-table table {
    margin-bottom: 0;
    font-variant-numeric: tabular-nums;
}

.chart-table thead th {
    position: sticky;
    top: 0;
    background: var(--vl-bg-card-solid);
    font-size: 0.75rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--vl-text-muted);
}

/* ══════════════════════════════════════════════════════════════════════
   Nøkkeltall, rangerte lister, periodevelger, varmekart
   ──────────────────────────────────────────────────────────────────────
   Delte komponenter, ikke sidestil. Hver tile er sin egen app, og bygger
   hver av dem sitt eget design, ender vi der `.stat-card` allerede endte:
   fem kopier med ulike signaturer. Se components/metrics.js.
   ══════════════════════════════════════════════════════════════════════ */

/* ── Nøkkeltall som stripe ────────────────────────────────────────────
   Erstatter raden med stat-kort. Fire kort tar en tredjedel av skjermen
   for fire tall som ikke trenger ramme — samme avveining budsjettet tok
   da `.bx-sum` erstattet sine tre. */
.metric-strip {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: 1rem 2.4rem;
    margin-bottom: 1.5rem;
}

.metric { display: flex; flex-direction: column; gap: 0.1rem; }

/* Proporsjonale sifre, ikke tabular: like brede sifre gjør at «121» ser
   løst ut i displaystørrelse. tabular-nums hører i kolonner. */
.metric-value {
    font-size: 2rem;
    font-weight: 800;
    letter-spacing: -0.035em;
    line-height: 1;
}

.metric-suffix {
    font-size: 0.85rem;
    font-weight: 500;
    color: var(--vl-text-muted);
    margin-left: 0.25rem;
}

.metric-label {
    font-size: 0.7rem;
    letter-spacing: 0.13em;
    text-transform: uppercase;
    color: var(--vl-text-muted);
    font-weight: 600;
}

/* Pil OG fortegn, ikke bare farge: en rød prosent alene er fargekodet
   informasjon, og pila bærer samme beskjed for den som ikke ser fargen. */
.metric-delta {
    display: inline-flex;
    align-items: center;
    gap: 0.25rem;
    font-size: 0.77rem;
    font-weight: 600;
    margin-top: 0.15rem;
}

.metric-delta.is-up { color: #00b894; }
.metric-delta.is-down { color: #e8907a; }
.metric-delta--flat { color: var(--vl-text-muted); font-weight: 500; }

.metric--spark { margin-left: auto; align-items: flex-end; }

/* Klikkbart noekkeltall.
   Ingen knappedrakt — tallet SKAL fortsatt lese som et tall, ikke som en
   knapp i en rad med knapper. Det eneste som skiller er markoeren, en
   understrek paa etiketten ved hover, og en tydelig aktiv tilstand. */
.metric--klikkbar {
    background: none;
    border: 0;
    padding: 0;
    font: inherit;
    text-align: left;
    cursor: pointer;
    border-radius: var(--vl-radius);
}
.metric--klikkbar .metric-label { text-decoration: underline dotted transparent; }
.metric--klikkbar:hover .metric-label { text-decoration-color: var(--vl-text-muted); }
.metric--klikkbar:focus-visible { outline: 2px solid var(--vl-primary); outline-offset: 3px; }
.metric--klikkbar[aria-pressed="true"] .metric-value { color: var(--vl-primary); }
.metric--klikkbar[aria-pressed="true"] .metric-label {
    color: var(--vl-text);
    text-decoration: underline solid var(--vl-primary);
}
.sparkline { display: block; }

/* ── Rangert liste ────────────────────────────────────────────────────
   Stolpen ligger BAK raden, ikke ved siden av: et eget stolpeelement
   ville tatt plass fra navnet, som er det man leser etter. */
.rank-list { display: flex; flex-direction: column; gap: 0.4rem; }

.rank-row {
    position: relative;
    overflow: hidden;
    display: flex;
    align-items: center;
    gap: 0.75rem;
    padding: 0.55rem 0.85rem;
    border-radius: var(--vl-radius-xs);
    background: var(--vl-glass);
    border: 1px solid var(--vl-glass-border);
}

.rank-bar {
    position: absolute;
    inset: 0 auto 0 0;
    background: var(--vl-data-1);
    opacity: 0.16;
    pointer-events: none;
}

.rank-no {
    position: relative;
    flex: 0 0 auto;
    font-size: 0.72rem;
    color: var(--vl-text-muted);
    font-variant-numeric: tabular-nums;
    min-width: 1.4rem;
}

.rank-main { position: relative; flex: 1; min-width: 0; }

.rank-title {
    display: flex;
    align-items: center;
    gap: 0.45rem;
    flex-wrap: wrap;
}

.rank-title i { color: var(--vl-text-muted); font-size: 0.85rem; }
.rank-name { font-weight: 600; font-size: 0.92rem; overflow-wrap: anywhere; }

.rank-badge {
    font-size: 0.63rem;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--vl-text-muted);
    border: 1px solid var(--vl-glass-border);
    border-radius: 4px;
    padding: 0 0.32rem;
}

.rank-meta {
    font-size: 0.78rem;
    color: var(--vl-text-muted);
    overflow-wrap: anywhere;
    margin-top: 0.1rem;
}

.rank-value {
    position: relative;
    flex: 0 0 auto;
    text-align: right;
    font-variant-numeric: tabular-nums;
}

.rank-value strong { display: block; font-size: 1rem; line-height: 1.2; }

.rank-value span {
    font-size: 0.65rem;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--vl-text-muted);
}

/* ── Periodevelger ────────────────────────────────────────────────────
   ÉN rad over alt den styrer. Filtre inne i hvert kort ville latt to
   grafer vise ulike perioder samtidig. */
.period-bar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.75rem 1.3rem;
    padding-bottom: 1rem;
    border-bottom: 1px solid var(--vl-border);
    margin-bottom: 1.5rem;
}

.period-nav { display: flex; align-items: center; gap: 0.5rem; }

.period-label {
    font-size: 1.35rem;
    font-weight: 700;
    letter-spacing: -0.02em;
    margin: 0;
    min-width: 10rem;
}

.period-step {
    appearance: none;
    background: none;
    border: 1px solid var(--vl-glass-border);
    color: var(--vl-text-muted);
    width: 28px;
    height: 28px;
    border-radius: var(--vl-radius-xs);
    cursor: pointer;
    font: inherit;
    line-height: 1;
    flex: 0 0 auto;
}

.period-step:hover:not(:disabled) { color: var(--vl-text); border-color: var(--vl-border); }
.period-step:disabled { opacity: 0.3; cursor: default; }

.period-chips { display: flex; gap: 0.3rem; flex-wrap: wrap; }
.period-bar > .period-chips:nth-of-type(1) { margin-left: auto; }

.period-chip {
    appearance: none;
    border: 1px solid var(--vl-glass-border);
    background: transparent;
    color: var(--vl-text-muted);
    font: inherit;
    font-size: 0.82rem;
    padding: 0.22rem 0.7rem;
    border-radius: 999px;
    cursor: pointer;
}

.period-chip:hover { color: var(--vl-text); border-color: var(--vl-border); }

/* Antall i en chip — «Kiosk 4». Merket er det samme som i en fane, og staar
   dokumentert som gjenbrukbart i komponenter.md; her trengs bare luften
   mellom teksten og tallet. */
.period-chip > .tall-merke,
.period-chip > .varsel-merke { margin-left: 0.35rem; }

/* `.aktiv` OG `.is-active`.

   Kodebasen har begge fra for: `.is-active` i master-rail, periodevelgeren og
   spilldetaljene; `.aktiv` i `.seg` og `.faner`. Ett navn ville vaert bedre,
   men et bytte over ni filer der ordet «aktiv» ogsaa staar inni «aktivitet»
   er ikke noe man gjor uten aa kunne se resultatet.

   NY KODE bruker `.aktiv`. `.is-active` staar for det som alt bruker den. */
.period-chip.aktiv,
.period-chip.is-active {
    background: var(--vl-primary);
    border-color: var(--vl-primary);
    color: #fff;
    font-weight: 600;
}

/* ── Varmekart ────────────────────────────────────────────────────────
   ÉN farge, lys til mørk. Verdien er en STØRRELSE, og en regnbue ville
   fått leseren til å lete etter kategorier som ikke finnes. Seks trinn:
   over sju klasser blir naboene umulige å skille, og da lyver kartet om
   presisjonen sin. */
.heatmap {
    --heat-tint: var(--vl-data-1);
    /* Den tomme ruta skal nesten forsvinne inn i kortet. Paa 0.04 tegnet
       168 tomme ruter et synlig rutenett — figuren leste som millimeterpapir
       framfor som et felt, og i en stille periode er nesten alle rutene tomme. */
    --heat-0: rgba(255, 255, 255, 0.022);
    margin-top: 0.6rem;
}

.heat-row {
    display: grid;
    grid-template-columns: 2.4rem 1fr;
    align-items: center;
    gap: 0.5rem;
}

.heat-row + .heat-row { margin-top: 2px; }
.heat-row--head { margin-bottom: 0.3rem; }

.heat-rowlabel {
    font-size: 0.75rem;
    color: var(--vl-text-muted);
    text-align: right;
}

.heat-cells {
    display: grid;
    grid-template-columns: repeat(var(--cols, 24), 1fr);
    gap: 2px;
}

.heat-collabel {
    font-size: 0.65rem;
    color: var(--vl-text-muted);
    text-align: center;
    font-variant-numeric: tabular-nums;
}

.heat-cell {
    display: block;
    height: 24px;
    border-radius: 3px;
}

/* Trinnene bygges av tinten med color-mix, så hele rampa følger én
   variabel — et bytte av seriefarge krever ikke seks nye hex-verdier. */
.heat-0 { background: var(--heat-0); }
.heat-1 { background: color-mix(in srgb, var(--heat-tint) 22%, transparent); }
.heat-2 { background: color-mix(in srgb, var(--heat-tint) 40%, transparent); }
.heat-3 { background: color-mix(in srgb, var(--heat-tint) 58%, transparent); }
.heat-4 { background: color-mix(in srgb, var(--heat-tint) 78%, transparent); }
.heat-5 { background: var(--heat-tint); }

.heat-legend {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 0.5rem;
    margin-top: 0.85rem;
    font-size: 0.74rem;
    color: var(--vl-text-muted);
}

.heat-steps { display: flex; gap: 2px; }
.heat-steps i { width: 17px; height: 10px; border-radius: 2px; display: block; }

/* Tegnforklaring til grafer — swatch + navn, aldri farge alene. */
.chart-legend {
    display: flex;
    flex-wrap: wrap;
    gap: 1rem;
    font-size: 0.8rem;
    color: var(--vl-text-muted);
    margin-bottom: 0.3rem;
}

.chart-legend i {
    width: 9px;
    height: 9px;
    border-radius: 50%;
    display: inline-block;
    margin-right: 0.4rem;
}

@media (max-width: 575.98px) {
    .metric-strip { gap: 1rem 1.6rem; }
    .metric-value { font-size: 1.6rem; }
    .metric--spark { display: none; }
    .period-nav { width: 100%; justify-content: space-between; }
    .period-label { min-width: 0; font-size: 1.15rem; }
    .period-bar > .period-chips:nth-of-type(1) { margin-left: 0; }
    .heat-cell { height: 18px; }
    .heat-row { grid-template-columns: 2rem 1fr; }
}

/* ══════════════════════════════════════════════════════════════════════
   Galleri
   ══════════════════════════════════════════════════════════════════════

   Rutenettet som vises på /galleri/{slug}, i en `gallery-embed`-blokk og i
   CMS-ets forhåndsvisning. ÉN definisjon — tre kopier ville gitt tre ulike
   rutestørrelser første gang noen justerte den ene.

   `auto-fill` og ikke faste kolonner: et album skal se likt ut i en artikkel
   på 800px og på en gallerisides fulle bredde, uten to sett med regler. */

.gallery-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
    gap: 0.5rem;
}

.gallery-tile {
    position: relative;
    aspect-ratio: 1;
    border: none;
    padding: 0;
    /* `display` og `width` maa staa her, ikke overlates til konteksten.
       Flisa er som regel en <button>, altsaa `inline-block` med bredde etter
       innhold — og innholdet er tomt. I `.gallery-grid` ble den likevel
       strukket av rutenettet, saa mangelen syntes ikke foer noen brukte flisa
       ALENE: da ble den null piksler bred, og bildet forsvant uten en feil. */
    display: block;
    width: 100%;
    border-radius: var(--vl-radius-sm);
    background-color: var(--vl-bg-elevated);
    background-size: cover;
    background-position: center;
    cursor: zoom-in;
    overflow: hidden;
    transition: transform 0.15s ease, box-shadow 0.15s ease;
}

/* Kvadratiske ruter, ikke bildets eget forhold. Et album fra et LAN er
   stående telefonbilder og liggende kamerabilder om hverandre, og et
   murstensoppsett gjør rader med ulik høyde som er vanskeligere å skumme
   enn å se på. Utsnittet er sentrert; hele bildet vises i lyskassa. */

.gallery-tile:hover,
.gallery-tile:focus-visible {
    transform: translateY(-2px);
    box-shadow: 0 6px 18px rgba(0, 0, 0, 0.45);
    outline: none;
}

.gallery-tile--blank {
    background: var(--vl-glass);
    border: 1px dashed var(--vl-glass-border);
}

/* Avspillingsmerket. Bare video har det, og det er det ENESTE som skiller en
   video fra et bilde i rutenettet — ruta er et stillbilde uansett. */
.gallery-play {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    color: #fff;
    font-size: 1.5rem;
    text-shadow: 0 2px 12px rgba(0, 0, 0, 0.7);
    pointer-events: none;
}

.gallery-dur {
    position: absolute;
    right: 6px;
    bottom: 6px;
    padding: 1px 6px;
    border-radius: 4px;
    background: rgba(0, 0, 0, 0.72);
    color: #fff;
    font-size: 0.7rem;
    font-variant-numeric: tabular-nums;
    pointer-events: none;
}

/* Bildeteksten ligger PÅ ruta, ikke under den. Under ville radene fått ulik
   høyde etter hvor lang teksten er, og rutenettet ville hakket. */
.gallery-cap {
    position: absolute;
    inset: auto 0 0 0;
    padding: 1.4rem 0.5rem 0.4rem;
    background: linear-gradient(transparent, rgba(0, 0, 0, 0.8));
    color: #fff;
    font-size: 0.72rem;
    line-height: 1.25;
    text-align: left;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
    pointer-events: none;
}

/* «+38» på siste synlige rute i et avkortet rutenett. Trykker man på den,
   åpner lyskassa med HELE lista — avkortingen er en forkortelse, ikke en vegg. */
.gallery-more {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    background: rgba(0, 0, 0, 0.62);
    color: #fff;
    font-size: 1.15rem;
    font-weight: 700;
    pointer-events: none;
}

.gallery-title {
    font-size: 1.1rem;
    margin-bottom: 0.75rem;
}

.gallery-link {
    display: inline-block;
    margin-top: 0.85rem;
    font-size: 0.85rem;
    color: var(--vl-primary);
    text-decoration: none;
}

.gallery-link:hover { color: var(--vl-primary-hover); }

.gallery-empty,
.gallery-loading {
    color: var(--vl-text-muted);
    font-size: 0.9rem;
    padding: 1rem 0;
}

/* Innsatt i rik tekst. Litt luft over og under, som en figur. */
.cms-content .gallery-embed {
    margin: 1.75rem 0;
}

@media (max-width: 575.98px) {
    .gallery-grid {
        grid-template-columns: repeat(auto-fill, minmax(104px, 1fr));
        gap: 0.35rem;
    }
}

/* ══════════════════════════════════════════
   SEGMENTERT VELGER  ·  .seg
   TONET KNAPP        ·  .knapp-tone

   ── Hvorfor de ligger her og ikke paa en side ──

   Begge ble skrevet paa /crew/bemanning og hadde `bm-`-prefiks. Da
   /crew/schedule trengte det samme, ble de doept `sk-`. Ved tredje side
   ville de blitt doept om igjen. De hoerer i components.css.

   ── .seg: velg ÉN av flere VISNINGER ──

   Sammensveiset pillegruppe. Bruk den naar valgene er ulike blikk paa det
   SAMME (Bemanning | Program). Er de filtre som SNEVRER en liste, bruk
   `.period-chip` — separate piller med luft mellom.

   ── Ikke Bootstrap ──

   `btn-outline-light` med `.active` gir HVIT flate. Fem slike paa rad over en
   moerk flate lyser mer enn innholdet de styrer; en verktoylinje skal vaere
   leselig, ikke det foerste oyet finner. `btn-outline-primary` er verre: den
   er BLAA, og paa en side som kjorer `.palett-amber` staar den og slaass med
   paletten.

   Se `docs/design/komponenter.md`.
   ══════════════════════════════════════════ */

.seg {
    display: inline-flex;
    border: 1px solid var(--vl-glass-border);
    border-radius: 999px;
    overflow: hidden;
}
.seg button,
.seg a {
    background: transparent;
    border: 0;
    color: var(--vl-text-muted);
    font: inherit;
    font-size: 0.82rem;
    padding: 0.3rem 0.8rem;
    cursor: pointer;
    text-decoration: none;
    line-height: 1.45;
    white-space: nowrap;
}
.seg button.aktiv,
.seg a.aktiv { background: var(--vl-primary); color: #fff; }
.seg button:not(.aktiv):hover,
.seg a:not(.aktiv):hover { background: var(--vl-glass); color: var(--vl-text); }

.knapp-tone {
    background: transparent;
    border: 1px solid var(--vl-glass-border);
    color: var(--vl-text-muted);
    border-radius: 999px;
    padding: 0.3rem 0.85rem;
    font-size: 0.82rem;
    line-height: 1.45;
    cursor: pointer;
    white-space: nowrap;
    /* Klassen brukes ogsaa paa <a> — en «Rediger»-lenke som ser ut som en
       knapp skal ikke ha understrek. `inline-flex` gir samme hoyde som en
       <button> med ikon, som ellers blir en piksel hoyere. */
    display: inline-flex;
    align-items: center;
    text-decoration: none;
}
.knapp-tone:hover { text-decoration: none; }
.knapp-tone:hover { border-color: rgba(255, 255, 255, 0.24); color: var(--vl-text); }

/* Deaktivert: dempet, og hover slaar ikke inn.

   Uten denne saa en avslaatt pille noeyaktig ut som en paaslaatt, og
   lyste dessuten opp ved hover — den lovet et klikk som ikke skjedde.
   Funnet paa /admin/interest, der «Send e-post» skal vaere av naar det
   ikke er noen i lista aa sende til. */
.knapp-tone:disabled,
.knapp-tone[disabled] {
    opacity: 0.45;
    cursor: not-allowed;
}
.knapp-tone:disabled:hover,
.knapp-tone[disabled]:hover {
    border-color: var(--vl-glass-border);
    color: var(--vl-text-muted);
}

/* Redigering PAA skal ses uten aa rope. En tonet ramme og farget tekst holder;
   en fylt gul knapp ville konkurrert med selve tavla. */
.knapp-tone--paa {
    border-color: rgba(253, 203, 110, 0.55);
    color: #fdcb6e;
    background: rgba(253, 203, 110, 0.10);
}
.knapp-tone--primaer {
    border-color: rgba(108, 92, 231, 0.6);
    color: #c9c0ff;
    background: rgba(108, 92, 231, 0.14);
}
.knapp-tone--primaer:hover { border-color: var(--vl-primary); color: #ded8ff; background: rgba(108, 92, 231, 0.22); }

.knapp-tone--ikon { padding: 0.3rem 0.6rem; }

/* Destruktivt. Rodt bare paa KANTEN og teksten, ikke som fyll: en «Slett»
   som lyser rodt hele tiden roper om oppmerksomhet den ikke fortjener foer
   noen faktisk vurderer aa trykke. Se interaksjon.md — rodt er for det
   ugjenkallelige, og det er fortsatt sant naar knappen er en pille. */
.knapp-tone--fare {
    border-color: rgba(225, 112, 85, 0.45);
    color: #e17055;
}
.knapp-tone--fare:hover {
    border-color: #e17055;
    color: #ff8a6d;
    background: rgba(225, 112, 85, 0.14);
}

/* Full bredde. `.seg` er `inline-flex` fordi den vanligvis staar i en
   verktoylinje ved siden av annet; i en sidebar skal den fylle kolonnen. */
.seg--full { display: flex; width: 100%; }
.seg--full button, .seg--full a { flex: 1; text-align: center; }

/* ══════════════════════════════════════════
   VERKTOYLINJE  ·  .verktoylinje  +  .sok-felt

   Raden over en liste: en `.seg` og gjerne et sokefelt.

   ── Hvorfor et eget sokefelt ──

   `form-control-sm` er FIRKANTET og hoyere enn `.seg`. Staar de ved siden av
   hverandre, moter en pille en kasse — to hoyder og to hjorneradier i samme
   rad, og raden ser ut som to ting som tilfeldigvis havnet sammen.

   `.sok-felt` har samme hoyde, samme radius og samme skriftstoerrelse som en
   `.seg`-knapp.

   ── Men ikke samme FYLL ──

   Sokefeltet har `--vl-glass` som bakgrunn; knappene er gjennomsiktige. Samme
   form saa raden linjer opp, ulikt fyll saa man ser hva man kan SKRIVE i og
   hva man kan TRYKKE paa. Var de identiske, ville feltet lest som en fjerde
   knapp.

   Husk `autocomplete="off"` — se avsnittet om sokefelt i komponenter.md.
   ══════════════════════════════════════════ */

.verktoylinje {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem;
    margin-bottom: 1.1rem;
}

/* Skyv resten til hoyre. Paa en rad som wrapper faller den til neste linje,
   og da er `margin-left: auto` uskadelig. */
.verktoylinje-hoyre { margin-left: auto; }

.sok-felt {
    appearance: none;
    background: var(--vl-glass);
    border: 1px solid var(--vl-glass-border);
    border-radius: 999px;
    color: var(--vl-text);
    font: inherit;
    font-size: 0.82rem;
    line-height: 1.45;
    padding: 0.3rem 0.9rem;
    min-width: 0;
    width: 100%;
    max-width: 16rem;
}
.sok-felt::placeholder { color: var(--vl-text-muted); }
.sok-felt:focus {
    outline: none;
    border-color: rgba(108, 92, 231, 0.6);
    background: rgba(255, 255, 255, 0.055);
}

/* Nettleserens egen tommekryss i `type="search"` er firkantet og lys. */
.sok-felt::-webkit-search-cancel-button {
    appearance: none;
    width: 12px; height: 12px;
    background: var(--vl-text-muted);
    cursor: pointer;
    mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath d='M2 2l8 8M10 2l-8 8' stroke='%23000' stroke-width='2' fill='none'/%3E%3C/svg%3E") center/contain no-repeat;
}

/* ══════════════════════════════════════════
   FANER  ·  .faner

   Understreksfaner: bytt mellom SEKSJONER av samme skjerm.

   ── Ikke det samme som `.seg` ──

   `.seg` er en pillegruppe med fylt flate paa aktiv, og den FILTRERER eller
   bytter visning av samme liste. En fane bytter hva skjermen VISER — den har
   ingen flate, bare en strek under den valgte.

   ── Tre kopier, én komponent ──

   Denne erstattet `.imgpicker-tab` (bildevelgerens modal), `.bx-tab`
   (budsjettet) og `.modal-tab` (meldinger). Alle tre var understreksfaner med
   `background: none` og `border-bottom-color` paa aktiv; forskjellene var
   kosmetiske — 0.85 mot 0.9 i skriftstoerrelse, og to av dem var uenige om
   fargen (`--vl-primary` mot `--vl-accent`).

   Aktiv-klassen er `.aktiv`, samme som `.seg`. Ett navn paa tvers av
   designsystemet: `.active` er Bootstraps, og to navn for samme tilstand er
   nettopp hvordan man glemmer den ene.

   Varianter:
     .faner--fyll   fanene deler bredden likt (til en modal)
     .faner--rull   ruller sidelengs naar de ikke faar plass
   ══════════════════════════════════════════ */

.faner {
    display: flex;
    gap: 0.25rem;
    border-bottom: 1px solid var(--vl-glass-border);
}

.faner button,
.faner a {
    display: inline-flex;
    align-items: center;
    gap: 0.45rem;
    padding: 0.45rem 0.9rem;
    background: none;
    border: 0;
    border-bottom: 2px solid transparent;
    color: var(--vl-text-muted);
    font: inherit;
    font-size: 0.86rem;
    white-space: nowrap;
    cursor: pointer;
    text-decoration: none;
    transition: color 0.15s, border-color 0.15s;
}
.faner button:hover,
.faner a:hover { color: var(--vl-text); }

.faner button.aktiv,
.faner a.aktiv {
    color: var(--vl-primary);
    border-bottom-color: var(--vl-primary);
}

.faner--fyll button, .faner--fyll a { flex: 1; justify-content: center; }
.faner--rull { overflow-x: auto; }

/* Tall og varsler i en kontroll — en fane ELLER en chip. Derfor ikke
   `fane-`-prefiks: merket er det samme uansett hva det staar i.

   `.tall-merke` er noytralt («12 poster»), `.varsel-merke` krever handling
   («3 uleste») — samme skille som badge-regelen i paneler.md. */
.tall-merke,
.varsel-merke {
    min-width: 1.25rem;
    padding: 0 0.3rem;
    border-radius: 999px;
    font-size: 0.7rem;
    line-height: 1.25rem;
    text-align: center;
}
.tall-merke { background: var(--vl-glass); color: var(--vl-text-muted); }
.varsel-merke { background: #e17055; color: #fff; }

/* ── Nedtrekk i en verktoylinje  ·  .velg-felt ───────────────

   Samme hoyde, radius og fyll som `.sok-felt`. Begge er felter man endrer en
   verdi i, til forskjell fra knappene rundt \u2014 og de skal se ut som samme
   slags ting.

   `appearance: none` fjerner nettleserens egen pil, saa den maa tegnes. En
   inline-SVG framfor et FontAwesome-ikon: pila hoerer til FELTET og ikke til
   innholdet, og et ikon-element inni en `<select>` er ikke lovlig markup. */
.velg-felt {
    appearance: none;
    background-color: var(--vl-glass);
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 6'%3E%3Cpath d='M1 1l4 4 4-4' stroke='%238b949e' stroke-width='1.6' fill='none' stroke-linecap='round'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right 0.75rem center;
    background-size: 10px 6px;
    border: 1px solid var(--vl-glass-border);
    border-radius: 999px;
    color: var(--vl-text);
    font: inherit;
    font-size: 0.82rem;
    line-height: 1.45;
    padding: 0.3rem 2.1rem 0.3rem 0.9rem;
    cursor: pointer;
    max-width: 100%;
}
.velg-felt:focus {
    outline: none;
    border-color: rgba(108, 92, 231, 0.6);
    background-color: rgba(255, 255, 255, 0.055);
}

/* Nedtrekkslista tegnes av operativsystemet og arver ikke flata over. Uten
   dette blir den hvit paa Windows. */
.velg-felt option { background: var(--vl-bg-card-solid); color: var(--vl-text); }

/* Datofelt i verktoylinja — `.dato-felt`
   ---------------------------------------
   Samme familie som `.sok-felt` og `.velg-felt`: samme hoyde, radius og fyll,
   saa raden linjer opp.

   Den fantes ikke da revisjonsloggen trengte et tidsrom, og foerste utgave
   brukte derfor `form-control-sm` — firkantet og hoyere enn pillene rundt.
   Da moeter en kasse en pille i samme rad, som er noeyaktig det
   `.sok-felt`-avsnittet advarer mot.

   Kalenderikonet er nettleserens eget. Det kan ikke erstattes uten aa miste
   velgeren, saa det inverteres i stedet: uten `filter` tegnes det moerkt paa
   moerkt og forsvinner. */
.dato-felt {
    appearance: none;
    background: var(--vl-glass);
    border: 1px solid var(--vl-glass-border);
    border-radius: 999px;
    color: var(--vl-text);
    font: inherit;
    font-size: 0.82rem;
    line-height: 1.45;
    padding: 0.3rem 0.9rem;
    min-width: 0;
    cursor: text;
}
.dato-felt:focus {
    outline: none;
    border-color: rgba(108, 92, 231, 0.6);
    background: rgba(255, 255, 255, 0.055);
}
.dato-felt::-webkit-calendar-picker-indicator {
    filter: invert(0.65);
    cursor: pointer;
}
/* Tomt felt: nettleseren viser aaaa-mm-dd i full tekstfarge, og da ser et tomt
   filter ut som et satt filter. */
.dato-felt:not(:valid)::-webkit-datetime-edit { color: var(--vl-text-muted); }

/* Skilletegnet mellom to felter som hoerer sammen (fra–til). */
/* Foretaksopplysningene i bunnteksten — krav fra Vipps for ePayment-noekler.
   Egen linje over copyright-raden, dempet: den skal vaere FINNBAR, ikke
   fremtredende. Wrapper paa smal skjerm framfor aa presse raden ut. */
.public-footer-org {
    margin-bottom: 0.5rem;
    line-height: 1.6;
}
.public-footer-org a { color: inherit; text-decoration: underline; }
.public-footer-org a:hover { color: var(--vl-accent); }

.verktoylinje-skille {
    color: var(--vl-text-muted);
    font-size: 0.82rem;
    padding: 0 0.1rem;
}

/* ── Infoskjerm-launcheren  ·  /crew/infoskjerm ──────────────────────
   Lista over embed-visninger. Radene er `.list-item` som ellers; dette er
   bare de tre bitene som er egne for denne lista.

   HVER rad har de samme to kontrollene — play og ellipsis — og en visning
   som ikke er bygget faar dem GRAAET UT, ikke fjernet. Foerste utkast skjulte
   dem, og da hoppet hoyrekanten inn og ut nedover lista. */

.embed-ikon {
    width: 40px;
    height: 40px;
    border-radius: var(--vl-radius-sm);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 1.1rem;
    flex-shrink: 0;
}

/* Play-knappen er kvadratisk saa den ikke skifter bredde med ikonet. */
.embed-play {
    width: 2rem;
    height: 2rem;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    flex-shrink: 0;
}

/* En rad som ikke kan startes skal SES som det, ikke bare oppfoere seg slik.
   Samme regel som `.knapp-tone:disabled` og den avslaatte menyraden.

   Dempingen er mild med vilje: gjor man hele raden blass, forsvinner ogsaa
   forskjellen mellom play-knappene, og det var nettopp den forskjellen som
   ikke var synlig i foerste utkast. Kontrasten baeres av knappen — fylt naar
   den virker, tom ramme naar den ikke gjor det. */
.embed-rad--planlagt { opacity: 0.72; }
.embed-rad--planlagt:hover { background: var(--vl-glass); }

/* Uten dette ser en avslaatt play-knapp ut som en trykkbar. Bootstrap setter
   `opacity: .65` paa `:disabled`, og paa en rad som alt er dempet holder ikke
   det. Samme fallgruve som `.dropdown-item:disabled` hadde. */
.embed-play:disabled {
    opacity: 0.4;
    cursor: not-allowed;
}

/* Adressen i konfigurasjonsmodalen. Monospace fordi den skal LESES tegn for
   tegn naar noen skriver den av paa en TV-fjernkontroll. */
.embed-url {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.5rem 0.75rem;
    border-radius: var(--vl-radius-sm);
    background: var(--vl-bg-elevated);
    font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
    font-size: 0.75rem;
    word-break: break-all;
}
.embed-url > span { flex: 1 1 auto; min-width: 0; }
/* ── Helpdesk  ·  /crew/saker ────────────────────────────────────────
   To spalter: koen til venstre, saken til hoyre. Outlook-modellen, ikke
   chat-bobler — en saksbehandler LESER en tidslinje.

   Hvorfor ikke `master-rail`: skinna er dokumentert for KORTE lister
   («Er lista lang eller uforutsigbar, hoerer den paa sin egen listeside»).
   En sakskoe er nettopp uforutsigbar, saa den trenger rulling og filter. */

.sak-delt {
    display: grid;
    grid-template-columns: 320px 1fr;
    gap: 1rem;
    /* Hoeyden er laast til skjermen saa BEGGE spaltene ruller hver for seg.
       Uten den ruller hele sida, og koen forsvinner opp naar man leser en lang
       sak — nettopp naar man trenger den for aa hoppe videre. */
    height: calc(100vh - 190px);
    min-height: 420px;
}

.sak-ko {
    overflow-y: auto;
    border: 1px solid var(--vl-glass-border);
    border-radius: var(--vl-radius);
    background: var(--vl-bg-card);
}

.sak-rad {
    display: block;
    width: 100%;
    text-align: left;
    background: none;
    border: 0;
    border-bottom: 1px solid var(--vl-glass-border);
    padding: 0.7rem 0.9rem;
    cursor: pointer;
    color: var(--vl-text);
}
.sak-rad:hover { background: var(--vl-glass); }

/* Den valgte raden maa vaere tydelig OGSAA naar musa staar et annet sted —
   ellers mister man hvilken sak man leser hver gang man ser paa hoyre side.

   Foerste utgave brukte `box-shadow: inset 3px 0 0`: en farget venstrekant,
   tegnet med skygge i stedet for `border-left`. Regelen i komponenter.md
   gjelder uansett hvordan stripa er tegnet — det er utseendet den forbyr.

   SAMME TONE SOM `.list-item.aktiv`. Den markeringen finnes allerede, og
   kommentaren der avviser venstrekanten av nøyaktig samme grunn. To ulike
   farger for «raden du ser paa» ville vaert to konvensjoner for én ting.
   Litt sterkere alfa her, fordi radene ikke har en egen kant som kan baere
   aksenten slik `.list-item` har — og fordi den maa skilles fra `:hover`. */
.sak-rad.aktiv { background: rgba(0, 206, 201, 0.10); }
.sak-rad.aktiv .sak-rad-emne { color: var(--vl-accent); }

/* Nummer og emne paa samme linje, med prikken presset helt ut til hoyre. */
.sak-rad-linje { display: flex; align-items: flex-start; gap: 0.5rem; }
.sak-nr { color: var(--vl-text-muted); font-variant-numeric: tabular-nums; font-weight: 400; }
.sak-rad-emne {
    flex: 1; min-width: 0;
    font-size: 0.9rem; font-weight: 600; line-height: 1.35;
    display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}

/* Statusen som PRIKK, ikke pille.
   En pille per rad ropte hoeyere enn emnet — og emnet er det man skanner
   etter. Ordet ligger i `title`, saa det kan leses ved tvil. */
.sak-prikk {
    display: block;
    width: 0.5rem; height: 0.5rem; border-radius: 50%;
    flex-shrink: 0; margin-top: 0.35rem;
    background: var(--vl-text-muted);
}
.sak-prikk--ny     { background: #ecab35; box-shadow: 0 0 0 3px rgba(236, 171, 53, 0.18); }
.sak-prikk--pagar  { background: #3fe3ff; }
/* «Venter» ligger hos innsenderen og krever ingenting av oss naa. Den skal
   derfor vaere den roligste — en tom ring, ikke en fylt prikk. */
.sak-prikk--venter { background: transparent; box-shadow: inset 0 0 0 1.5px var(--vl-text-muted); }
.sak-prikk--lost   { background: #2c9c63; }
.sak-prikk--avvist { background: #b83b52; }

.sak-rad-meta {
    font-size: 0.75rem; color: var(--vl-text-muted); margin-top: 0.25rem;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

/* ── Saksflata ── */
.sak-flate {
    display: flex;
    flex-direction: column;
    min-height: 0;
    border: 1px solid var(--vl-glass-border);
    border-radius: var(--vl-radius);
    background: var(--vl-bg-card);
    overflow: hidden;
}

.sak-hode { padding: 1rem 1.25rem; border-bottom: 1px solid var(--vl-glass-border); flex-shrink: 0; }
.sak-hode-tittel { display: flex; align-items: baseline; gap: 0.6rem; }
.sak-hode-tittel h2 { font-size: 1.25rem; margin: 0; }
.sak-nr-stor { color: var(--vl-text-muted); font-variant-numeric: tabular-nums; }
.sak-hode-merker { display: flex; flex-wrap: wrap; gap: 0.4rem; margin: 0.5rem 0; align-items: center; }
.sak-kilde { font-size: 0.75rem; color: var(--vl-text-muted); }
.sak-hode-valg { display: flex; flex-wrap: wrap; gap: 0.5rem; align-items: center; margin-top: 0.75rem; }

/* Eier-nedtrekket erstattet en `.sak-eier`-etikett som bare KUNNE leses.
   «Send videre» er ett valg, ikke en melding til noen om aa gaa inn og ta
   saken selv. */
#sak-eier { max-width: 14rem; }

/* -- Ny melding lagt til uten at flata ble bygget om --
   Uten et blink er det ikke sikkert at man ser at noe skjedde: teksten
   forsvinner fra feltet, og svaret dukker opp nederst i en tidslinje som
   kanskje allerede var rullet dit. Animasjonen kjoerer én gang og lar
   deretter meldinga vaere som de andre. */
@keyframes sak-melding-inn {
    from { opacity: 0; transform: translateY(0.4rem); }
    to   { opacity: 1; transform: none; }
}
.sak-melding--ny { animation: sak-melding-inn 0.22s ease-out; }

@media (prefers-reduced-motion: reduce) {
    .sak-melding--ny { animation: none; }
}

/* -- Brukersoek i «Ny sak» --
   Crew skrev av navn og e-post de allerede hadde i registeret, med
   skrivefeilene det gir. Trefflista er kort med vilje: ti rader, og et
   soek som ikke traff peker videre til «Skriv inn». */
.sak-treff:not(:empty) {
    margin-top: 0.4rem;
    max-height: 12rem;
    overflow-y: auto;
    border: 1px solid var(--vl-glass-border);
    border-radius: var(--vl-radius);
    background: var(--vl-bg-card);
}
.sak-treff-rad {
    display: flex;
    /* `center`, ikke `baseline`: raden har en avatar, og et bilde har ingen
       tekstlinje aa stille seg paa. Med to tekstspenn var forskjellen usynlig. */
    justify-content: space-between;
    align-items: center;
    gap: 1rem;
    width: 100%;
    padding: 0.5rem 0.7rem;
    text-align: left;
    background: none;
    border: 0;
    border-bottom: 1px solid var(--vl-glass-border);
    color: var(--vl-text);
    cursor: pointer;
}
.sak-treff-rad:last-child { border-bottom: 0; }
.sak-treff-rad:hover { background: var(--vl-glass); }

/* ══════════════════════════════════════════
   SAKEN SETT FRA INNSENDEREN  —  /sak/{token} og /app/saker/{id}
   ══════════════════════════════════════════

   Samme tidslinje som crew ser, men uten koen ved siden av. Sida er smal med
   vilje: det eneste man gjor her er aa lese en historie og svare paa den.

   `/sak/{token}` er FULLSKJERM (se `fullscreenPages` i app.js), saa den maa
   ha sin egen ramme og sin egen vei hjem — det finnes ingen navbar rundt. */
.sak-side {
    min-height: 100vh;
    padding: 2rem 1rem 4rem;
    background: var(--vl-bg);
}
.sak-side-inner { max-width: 720px; margin: 0 auto; }

.sak-side-hjem {
    display: inline-flex;
    align-items: center;
    margin-bottom: 1.5rem;
    font-size: 0.85rem;
    color: var(--vl-text-muted);
    text-decoration: none;
}
.sak-side-hjem:hover { color: var(--vl-text); }

.sak-side-hode { margin-bottom: 1.5rem; }
.sak-side-hode h1 { font-size: 1.4rem; line-height: 1.3; margin-bottom: 0.6rem; }
.sak-side-merker { display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem; }
.sak-side-meldt { margin: 0.6rem 0 0; font-size: 0.8rem; color: var(--vl-text-muted); }

.sak-side-tidslinje { display: flex; flex-direction: column; gap: 0.75rem; }

.sak-side-svar { margin-top: 1.5rem; }
.sak-side-svar-bunn {
    display: flex;
    align-items: center;
    gap: 1rem;
    margin-top: 0.6rem;
}
/* Primaerhandlingen i hoyre hjoerne — samme regel som verktoylinja, se
   komponenter.md. `:last-child` og ikke `.btn`, saa den taaler at det kommer
   en knapp til. */
.sak-side-svar-bunn > :last-child { margin-left: auto; }

/* En avsluttet sak er ikke en blindvei. «Jeg har mer aa legge til» aapner
   svarboksen igjen — serveren setter status tilbake naar svaret kommer. */
.sak-side-avsluttet {
    margin-top: 1.5rem;
    padding: 1rem 1.1rem;
    border: 1px solid var(--vl-glass-border);
    border-radius: var(--vl-radius);
    background: var(--vl-glass);
    font-size: 0.9rem;
}

.sak-side-tomt { text-align: center; padding: 4rem 1rem; }
/* `margin: 0 auto` — FontAwesome gir ikonet fast bredde, så en blokk uten
   auto-marger står til venstre. Se design/komponenter.md. */
.sak-side-tomt i { font-size: 2.5rem; color: var(--vl-text-muted); margin: 0 auto 1rem; display: block; }
.sak-side-tomt h1 { font-size: 1.3rem; margin-bottom: 0.75rem; }
.sak-side-tomt p { color: var(--vl-text-muted); max-width: 38ch; margin: 0 auto 1.5rem; }

/* ══════════════════════════════════════════
   STEMMER PAA BIDRAG  —  /app/tournaments/{id}
   ══════════════════════════════════════════

   Se migrasjon 217. Tallet er skjult som standard: ser man stillingen mens
   man stemmer, stemmer man paa det som alt leder. */

.bidrag-stemmemerke {
    position: absolute;
    right: 0.5rem;
    bottom: 0.5rem;
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    padding: 0.2rem 0.55rem;
    border-radius: 20px;
    font-size: 0.8rem;
    font-weight: 600;
    /* Moerk plate under, fordi merket ligger paa et bilde vi ikke kjenner
       fargen paa. Uten den forsvinner tallet paa en lys himmel. */
    background: rgba(0, 0, 0, 0.62);
    color: #fff;
    backdrop-filter: blur(2px);
    pointer-events: none;
}

.bidrag-stemmemerke--min {
    background: rgba(232, 67, 147, 0.85);
}

.gallery-tile {
    position: relative;
}

.bidrag-modal-bilde {
    max-width: 100%;
    max-height: 62vh;
    border-radius: var(--vl-radius-xs);
}

/* Teksten til venstre, handlinga til hoeyre — knappen i et skjema staar
   hoeyrestilt, se docs/design/skjema.md. */
.bidrag-modal-bunn {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    flex-wrap: wrap;
}

@media (max-width: 576px) {
    .bidrag-modal-bilde { max-height: 52vh; }
    .bidrag-stemmemerke { font-size: 0.72rem; padding: 0.15rem 0.45rem; }
}

/* ══════════════════════════════════════════
   FAQ  —  /app/faq
   ══════════════════════════════════════════

   Svaret aapner seg der spoersmaalet staar. Medianartikkelen er 177 tegn,
   og en sidelasting for to linjer er feil pris. Se `pages/app/faq.js`. */

.faq-gruppe + .faq-gruppe {
    margin-top: 3.25rem;
}

/* Hvit og stor. Gruppa er det oeyet navigerer etter naar man leter — sto den
   i samme stoerrelse og farge som spoersmaalene, var den bare enda en linje. */
.faq-gruppe-tittel {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    margin: 0 0 1rem;
    font-size: 1.4rem;
    font-weight: 700;
    color: var(--vl-text);
}

.faq-gruppe-tittel i {
    color: var(--vl-primary);
    font-size: 1.15rem;
}

.faq-gruppe-antall {
    font-size: 0.8rem;
    font-weight: 600;
    color: var(--vl-text-muted);
    background: var(--vl-glass);
    border-radius: 20px;
    padding: 0.1rem 0.55rem;
}

.faq-gruppe-intro {
    margin: -0.5rem 0 1rem;
    font-size: 0.9rem;
    color: var(--vl-text-muted);
}

.faq-liste {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
}

.faq-post {
    background: var(--vl-bg-card);
    border: 1px solid var(--vl-border-light);
    border-radius: var(--vl-radius-xs);
    overflow: hidden;
}

.faq-spm {
    display: flex;
    align-items: center;
    gap: 1rem;
    width: 100%;
    padding: 0.9rem 1.1rem;
    background: none;
    border: 0;
    text-align: left;
    color: inherit;
    cursor: pointer;
}

.faq-spm:hover {
    background: var(--vl-bg-hover, rgba(255, 255, 255, 0.04));
}

.faq-spm-tekst {
    display: flex;
    flex-direction: column;
    gap: 0.2rem;
    min-width: 0;
    flex: 1;
}

.faq-tittel {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    flex-wrap: wrap;
    font-weight: 600;
    color: var(--vl-text);
}

.faq-utdrag {
    font-size: 0.85rem;
    color: var(--vl-text-muted);
}

/* Utdraget er et LOEFTE om svaret, og i praksis er det ofte foerste setning i
   det. Naar svaret staar rett under, leste man det samme to ganger. */
.faq-spm[aria-expanded="true"] .faq-utdrag {
    display: none;
}

.faq-crew-merke {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    font-size: 0.7rem;
    font-weight: 600;
    padding: 0.1rem 0.45rem;
    border-radius: 20px;
    background: rgba(108, 92, 231, 0.2);
    color: #a694f5;
    border: 1px solid rgba(108, 92, 231, 0.3);
}

/* Pila peker ned naar den er lukket og opp naar den er aapen. Den snur seg
   fordi `aria-expanded` snur — ett sted aa endre tilstand, ikke to. */
.faq-pil {
    flex-shrink: 0;
    font-size: 0.8rem;
    color: var(--vl-text-muted);
    transition: transform 0.18s ease;
}

.faq-spm[aria-expanded="true"] .faq-pil {
    transform: rotate(180deg);
}

.faq-svar {
    padding: 0 1.1rem 1.1rem;
}

.faq-svar .cms-content > :first-child {
    margin-top: 0;
}

.faq-laster {
    padding: 0.5rem 0;
}

.faq-nyttig {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    flex-wrap: wrap;
    margin-top: 1rem;
    padding-top: 0.85rem;
    border-top: 1px solid var(--vl-border-light);
}

.faq-nyttig-tekst {
    font-size: 0.85rem;
    color: var(--vl-text-muted);
}

.faq-nyttig-knapper {
    flex: 1;
    min-width: 0;
}

@media (max-width: 576px) {
    .faq-gruppe + .faq-gruppe { margin-top: 2.5rem; }
    .faq-gruppe-tittel { font-size: 1.2rem; }
    .faq-spm { padding: 0.8rem 0.9rem; }
    .faq-svar { padding: 0 0.9rem 0.9rem; }
}

/* ══════════════════════════════════════════
   KONTAKTSKJEMAET  —  /kontakt
   ══════════════════════════════════════════

   Skjemaet er hovedsaken; spalta ved siden av er de andre veiene inn. Under
   860px legger de seg under hverandre — skjemaet foerst, fordi det er det man
   kom for. */
.kontakt-grid {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 15rem;
    gap: 2rem;
    align-items: start;
}
.kontakt-side h2 { margin-bottom: 0.75rem; color: var(--vl-text-muted); }
.kontakt-side p { color: var(--vl-text-muted); }

.kontakt-bunn {
    display: flex;
    align-items: center;
    gap: 1rem;
    margin-top: 1.25rem;
}
.kontakt-bunn > :last-child { margin-left: auto; }

.kontakt-kvittering { text-align: center; padding: 1.5rem 0; }
.kontakt-kvittering > i {
    display: block;
    font-size: 2.5rem;
    color: var(--vl-accent);
    /* Auto-marger: se `.sak-side-tomt i`. */
    margin: 0 auto 1rem;
}
.kontakt-kvittering-valg {
    display: flex;
    justify-content: center;
    flex-wrap: wrap;
    gap: 0.5rem;
}

@media (max-width: 860px) {
    .kontakt-grid { grid-template-columns: minmax(0, 1fr); }
    .kontakt-side {
        border-top: 1px solid var(--vl-glass-border);
        padding-top: 1.5rem;
    }
}

/* Innsenderen i saksoverskriften er en KNAPP, ikke en etikett.
   Den saa ut som de andre feltene i `.meta-row` og gjor det fortsatt — men
   den kan trykkes, og blyanten sier det. Aa bytte hvem saken gjelder hoerer
   hjemme der navnet staar; ligger det i en ellipsis, finner ingen det. */
/* Innsenderen i sakshodet.

   Var ÉN knapp som aapnet «bytt innsender», saa den eneste veien fra navnet
   til personen gikk gjennom aa redigere saken. Naa er navnet en lenke til
   personen, og pennen en egen knapp ved siden av: identitet og redigering er
   to ting, og de skal ikke dele treffflate. */
.sak-innsender {
    display: inline-flex;
    align-items: center;
    gap: 0.1rem;
}

.sak-innsender-navn {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    padding: 0.1rem 0.4rem;
    margin: -0.1rem -0.4rem;
    color: inherit;
    text-decoration: none;
    border-radius: var(--vl-radius-sm, 0.35rem);
}
a.sak-innsender-navn { cursor: pointer; }
a.sak-innsender-navn:hover { background: var(--vl-glass); color: var(--vl-text); }

.sak-innsender-bytt {
    padding: 0.1rem 0.35rem;
    font: inherit;
    font-size: 0.8em;
    color: inherit;
    background: none;
    border: 0;
    border-radius: var(--vl-radius-sm, 0.35rem);
    cursor: pointer;
    opacity: 0;
}
.sak-innsender:hover .sak-innsender-bytt,
.sak-innsender-bytt:focus-visible { opacity: 0.7; }
.sak-innsender-bytt:hover { opacity: 1; background: var(--vl-glass); color: var(--vl-text); }

/* En handling som bare finnes paa hover er utilgjengelig der det ikke finnes
   en peker — se komponenter.md. Paa beroeringsskjerm staar pennen framme. */
@media (hover: none) {
    .sak-innsender-bytt { opacity: 0.7; }
}

.sak-valgt-bruker {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 1rem;
    margin-top: 0.5rem;
    padding: 0.55rem 0.7rem;
    border: 1px solid var(--vl-accent);
    border-radius: var(--vl-radius);
    background: rgba(0, 206, 201, 0.07);
}

/* ── Tidslinja ──
   Svar og interne notater staar i SAMME kronologi. Skillet baeres av
   utseendet, ikke av plasseringen: en fane til ville betydd at halve
   historien ligger et sted man maa huske aa se. */
.sak-tidslinje {
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    padding: 1rem 1.25rem;
    display: flex;
    flex-direction: column;
    gap: 0.85rem;
}

.sak-melding {
    border: 1px solid var(--vl-glass-border);
    border-radius: var(--vl-radius-sm);
    padding: 0.7rem 0.9rem;
    background: var(--vl-glass);
}
.sak-melding--oss { background: rgba(108, 92, 231, 0.10); border-color: rgba(108, 92, 231, 0.28); }
/* Et internt notat maa ses UMIDDELBART. Skriver noen et notat i den tro at det
   er et svar, har vi fortalt innsenderen ingenting — motsatt vei har vi sendt
   dem noe som ikke var ment for dem. */
.sak-melding--intern {
    background: rgba(236, 171, 53, 0.08);
    border-color: rgba(236, 171, 53, 0.3);
    border-style: dashed;
}

.sak-melding-hode {
    display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap;
    font-size: 0.8rem; margin-bottom: 0.35rem;
}
.sak-melding-tid { color: var(--vl-text-muted); margin-left: auto; }
.sak-intern-merke { color: #ecab35; display: inline-flex; align-items: center; gap: 0.3rem; }
.sak-sendt { color: #2c9c63; display: inline-flex; align-items: center; gap: 0.3rem; }
.sak-usendt { color: #e07070; display: inline-flex; align-items: center; gap: 0.3rem; }
/* Underveis: dempet, ikke roedt — ingenting har feilet ennaa. Se `sendtMerke()`. */
.sak-sender { color: var(--vl-text-muted); display: inline-flex; align-items: center; gap: 0.3rem; }
.sak-melding-tekst { white-space: pre-wrap; font-size: 0.9rem; line-height: 1.5; }

/* ── Svarboksen ── */
.sak-svar { padding: 0.85rem 1.25rem 1rem; border-top: 1px solid var(--vl-glass-border); flex-shrink: 0; }

/* Formatlinja over svarboksen. To knapper, ikke en verktoykasse: en WYSIWYG
   her ville betydd HTML skrevet av crew rett inn i en e-post. `**fet**` og
   `*kursiv*` er den samme delmengden `fritekst()` og `bodyToHtml()` kjenner,
   saa flata og e-posten viser det samme. */
.sak-format { display: flex; align-items: center; gap: 0.35rem; margin-bottom: 0.4rem; }
.sak-format-hint { font-size: 0.72rem; color: var(--vl-text-muted); margin-left: 0.25rem; }
.sak-melding-tekst strong { font-weight: 700; color: var(--vl-text); }
.sak-melding-tekst em { font-style: italic; }
.sak-svar-bunn { display: flex; align-items: center; gap: 1rem; margin-top: 0.6rem; }

/* SISTE BARN, ikke `.btn`.
   Da send-knappen ble en delt knapp, havnet `margin-left: auto` paa den
   foerste `.btn` INNE i `.btn-group` — altsaa mellom knappen og pila, ikke
   foran gruppa. Gruppa ble staaende inntil «Internt notat» med hele raden tom
   til hoyre. Primaerhandlingen skal ligge i hoyre hjoerne; se
   `komponenter.md`. */
.sak-svar-bunn > :last-child { margin-left: auto; }
.sak-svar-hint { font-size: 0.78rem; color: var(--vl-text-muted); margin: 0.5rem 0 0; }

/* Under 992px faar koen og saken hver sin hoeyde i stedet for hver sin
   spalte. En sakskoe paa mobil er sjelden, men crew staar med telefon i
   hallen — og da er en 320px-spalte ved siden av teksten ubrukelig. */
@media (max-width: 991.98px) {
    .sak-delt { grid-template-columns: 1fr; height: auto; }
    .sak-ko { max-height: 40vh; }
    .sak-tidslinje { max-height: 50vh; }
}

/* ── Turneringskort: naar og meta ─────────────────────────────────────────
   Ligger i components.css og ikke i public.css eller landing.css, fordi de
   samme to linjene brukes av begge formspraakene: `.public-card` i appen og
   paa den offentlige lista, `.lp-card` paa forsiden. To kopier ville betydd
   to steder aa rette naar stoerrelsen skal justeres.

   Kortet hadde fem opplysninger med hvert sitt ikon fordelt paa to rader.
   Paa `col-lg-4` brot de i tre, og ikonet havnet over teksten sin. Ikonene
   er borte: tre ord skilt med `·` leses raskere enn tre ikoner man maa tyde,
   og de bryter pent naar plassen er knapp. */
.turn-naar {
    font-size: 0.85rem;
    font-weight: 600;
    margin-bottom: 0.15rem;
}

.turn-meta {
    font-size: 0.85rem;
    opacity: 0.72;
}

/* `.lp-card` gir sine `<p>` en egen farge og marg. Naar-linja skal skille
   seg ut der ogsaa, saa den arver ikke den dempede tonen. */
.lp-card .turn-naar {
    color: var(--lp-ink);
    margin: 0 0 0.15rem;
}

.lp-card .turn-meta { margin: 0; }

/* ── Turneringssida ──────────────────────────────────────────────────────
   Sida hadde fem faner, en rad statuskort, et kort rundt vinneren og en
   strek under hver overskrift. For en konkurranse med tre avsnitt tekst var
   det mer ramme enn innhold — og fanene skjulte nettopp det man kom for.
   Naa: én hero, én rull, og overskrifter som ser ut som overskrifter. */

/* ── Turneringsheroen er `.hub-hero` med et bilde under ──
   Komponenten ligger i `pages.css` og brukes av /app. Det eneste som er
   annerledes her er coveret, og det er en modifikator — ikke en ny familie.
   Scrimet er det samme som hub-en har, lagt OVER bildet saa teksten kan
   leses mot hva som helst. */
/* Dobbel klasse: `.hub-hero` staar i `pages.css`, som lastes ETTER
   `components.css`. Med én klasse hver vinner den som kommer sist, og
   coveret ble aldri tegnet. */
/* Coveret er BAKGRUNN, ikke bilde. Hoyre stopp var 0.55, og det holdt saa
   lenge det bare sto tekst til venstre — men heroen har innhold paa hoyre
   side ogsaa: fristen og nedtellingen, og paa /crew i tillegg knapperada.
   Over et moerkt cover gikk det bra; over Counter-Strikes oransje ble
   «Paamelding aapner om» hvit tekst paa lyst. Lesbarheten kan ikke avhenge
   av hvilket bilde noen tilfeldigvis lastet opp. */
.hub-hero.hub-hero--bilde {
    background:
        linear-gradient(100deg, rgba(10, 14, 23, 0.96) 28%, rgba(10, 14, 23, 0.82) 100%),
        var(--turn-cover) center / cover no-repeat,
        linear-gradient(135deg, #2a1f5e 0%, #123f52 60%, #0a0e17 100%);
}

/* Teksten over nedtellingen. `.hub-island` gir selve flata. */
.turn-frist-tekst {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    line-height: 1.25;
    margin-bottom: 0.45rem;
}

.turn-frist-naar { font-weight: 600; font-size: 0.85rem; }
.turn-frist-dato { font-size: 0.75rem; color: var(--vl-text-muted); }

/* Seksjonene. Ingen kort, ingen streker — luft er skillet, og overskrifta
   er stoerre enn broedteksten. Foer var «Regler» samme stoerrelse som
   avsnittet under, med en `<hr>` imellom. */
/* Heroen har 1.75rem luft inn til teksten sin. Uten det samme innrykket
   under starter broedteksten lenger ute enn overskrifta i heroen, og da
   LESES heroen som smalere enn sida — selv om kantene er like. */
/* Alt paa sidenivaa deler ytterkant: heroen, varslene, fanerada og kortet.
   Ingen egen innrykkklasse — den fantes en stund, satte `padding: 0`, og
   overkjorte da varselets EGEN padding saa ikonet laa klint i kanten.
   Teksten flukter uansett: baade heroen og kortet har innvendig luft. */

/* ── Rik tekst fra editoren ──
   Crew skriver regler og premier i TinyMCE og setter `<h1>` fordi det er det
   oeverste valget der — ikke fordi de vet hvilket nivaa sida bruker. Uten
   dette rendres de paa 2em, altsaa stoerre enn sidas egne
   seksjonsoverskrifter, og hierarkiet staar paa hodet.

   Alt forfattet innhold legges derfor UNDER `.turn-seksjon-tittel` (1.15rem),
   uansett hvilken tag som ble valgt. */
.rich-content h1,
.rich-content h2,
.rich-content h3,
.rich-content h4,
.rich-content h5,
.rich-content h6 {
    font-weight: 700;
    line-height: 1.3;
    margin: 1.25rem 0 0.5rem;
}

.rich-content h1 { font-size: 1.02rem; }
.rich-content h2 { font-size: 0.98rem; }
.rich-content h3,
.rich-content h4,
.rich-content h5,
.rich-content h6 { font-size: 0.94rem; color: var(--vl-text-muted); }

.rich-content > :first-child { margin-top: 0; }
.rich-content p { margin-bottom: 0.7rem; }
.rich-content ul,
.rich-content ol { margin-bottom: 0.7rem; padding-left: 1.3rem; }
.rich-content li { margin-bottom: 0.25rem; }

/* ══════════════════════════════════════════════════════════════════════
   Turneringssida — `/app/tournaments/{id}` (1003-1909)
   ══════════════════════════════════════════════════════════════════════

   Ingen faner. Ovenfra: heroen, KORTET (det du skal gjøre nå), STIGEN (hvor
   du er), og så hovedflata + høyrekolonnen. Se kommentaren over
   `renderDetail()`. Fanene, «Din deltakelse»-boksen og sammenklappene som
   sto her før, er borte sammen med markupen sin. */

/* ── Kortet ──
   Det ene på sida som får være en boks: det er handlingen. Alt annet flyter
   med skillelinjer (sidelayout.md, «ingen bokser i bokser»). */
.turn-kort {
    position: relative;
    margin-top: 1.25rem;
    padding-top: 1.25rem;
    border-top: 1px solid var(--vl-glass-border);
}
.turn-kort-merke {
    font-size: 0.72rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.1em;
    color: var(--vl-accent);
}
/* To sider med «MOT» i midten — eller én side og en handling (`--en`) */
.turn-kort-rad {
    display: grid;
    grid-template-columns: 1fr auto 1fr;
    align-items: center;
    gap: 1.25rem;
    margin-top: 1rem;
}
.turn-kort-rad--en { grid-template-columns: 1fr auto; }
.turn-kort-rad > .turn-side:last-child:not(:first-child) { flex-direction: row-reverse; text-align: right; }
.turn-kort-bidrag { margin-top: 1rem; }
.turn-vs {
    font: 700 0.95rem 'Space Grotesk', sans-serif;
    letter-spacing: 0.1em;
    color: var(--vl-text-muted);
}
.turn-side { display: flex; align-items: center; gap: 0.9rem; min-width: 0; }
.turn-side-navn { font: 700 1.35rem/1.15 'Space Grotesk', sans-serif; overflow-wrap: anywhere; }
.turn-side-under { color: var(--vl-text-muted); font-size: 0.85rem; margin-top: 0.2rem; }
.turn-merke {
    width: 56px; height: 56px; flex-shrink: 0;
    border-radius: 14px; overflow: hidden;
    display: inline-flex; align-items: center; justify-content: center;
    background: var(--vl-bg-tertiary);
    border: 1px solid var(--vl-glass-border);
    color: var(--vl-text-muted);
}
.turn-merke img { width: 100%; height: 100%; object-fit: cover; }
.turn-merke--ukjent { border-style: dashed; }
.turn-kort-fot {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem 1.25rem;
    margin-top: 1.25rem;
    padding-top: 1rem;
    border-top: 1px solid var(--vl-glass-border);
    font-size: 0.88rem;
}
.turn-kort-fot .turn-lag-medlemmer { flex-basis: 100%; order: 3; }
.turn-kort-fot-hoyre { margin-left: auto; }
@media (max-width: 767.98px) {
    .turn-kort-rad, .turn-kort-rad--en { grid-template-columns: 1fr; gap: 0.75rem; }
    .turn-kort-rad > .turn-side:last-child:not(:first-child) { flex-direction: row; text-align: left; }
    .turn-side-navn { font-size: 1.15rem; }
    .turn-merke { width: 44px; height: 44px; border-radius: 11px; }
}

/* «Meld av» bruker `.signup-btn signup-btn--cancel` fra pages.css — nøytral
   i hvile, rød på hover. Ingen parallell klasse (interaksjon.md). */

/* Lagnavnet lenker til lagsida — primærfargen sier at det kan trykkes på. */
.turn-lag-lenke {
    color: var(--vl-primary);
    text-decoration: none;
}
.turn-lag-lenke:hover { text-decoration: underline; }
.turn-lag-lenke i { font-size: 0.6rem; }

/* Lagkameratene. Crew setter sammen lagene, så «med hvem?» er det
   deltakeren lurer på — navnet på laget svarer ikke på det. */
.turn-lag-medlemmer {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem 1rem;
}
.turn-lag-medlem {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    color: var(--vl-text);
    text-decoration: none;
    font-size: 0.85rem;
}
.turn-lag-medlem:hover span { text-decoration: underline; }
.turn-lag-medlem i { font-size: 0.7rem; }

/* ── Stigen ──
   Kampene du har spilt og veien til finalen, eller fasene i en innsending. */
.turn-vei { display: flex; align-items: flex-start; margin: 1.5rem 0 0; overflow-x: auto; padding-bottom: 0.25rem; }
.turn-steg { flex: 1; min-width: 110px; position: relative; text-align: center; }
.turn-steg::before {
    content: ''; position: absolute; top: 15px; left: -50%; right: 50%;
    height: 2px; background: var(--vl-glass-border);
}
.turn-steg:first-child::before { display: none; }
.turn-steg--ferdig::before, .turn-steg--naa::before, .turn-steg--tap::before { background: var(--vl-accent); }
.turn-prikk {
    position: relative; width: 32px; height: 32px; margin: 0 auto 0.45rem;
    border-radius: 50%; display: flex; align-items: center; justify-content: center;
    font-size: 0.8rem; color: var(--vl-text-muted);
    background: var(--vl-bg-tertiary); border: 2px solid var(--vl-glass-border);
}
.turn-steg--ferdig .turn-prikk { background: var(--vl-accent); border-color: var(--vl-accent); color: #062b2a; }
.turn-steg--tap .turn-prikk { border-color: rgba(255, 118, 117, 0.6); color: #ff7675; }
.turn-steg--naa .turn-prikk { border-color: var(--vl-accent); color: var(--vl-accent); box-shadow: 0 0 0 5px rgba(0, 206, 201, 0.15); }
.turn-steg-t { font-weight: 600; font-size: 0.85rem; }
.turn-steg-u { font-size: 0.75rem; color: var(--vl-text-muted); }

/* Det ingen forstår før de spør: hva skjer om vi taper? */
/* En fotnote under kampen, inne i heroen — ingen egen flate */
.turn-merknad {
    display: flex; gap: 0.5rem; align-items: baseline;
    margin-top: 0.85rem;
    font-size: 0.85rem; color: var(--vl-text-muted);
}
.turn-merknad i { color: var(--vl-accent); margin-top: 0.2rem; }
.turn-merknad b { color: var(--vl-text); }

/* ── Hovedflata og høyrekolonnen ── */
.turn-grid {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 320px;
    gap: 2rem;
    margin-top: 2rem;
}
/* `min-width: 0`: bracket-SVG-en tegnes i full bredde før den måles, og
   blåser ellers opp kolonnen den så måler (samme felle som 1003-1641). */
.turn-grid > * { min-width: 0; }
@media (max-width: 1099.98px) { .turn-grid { grid-template-columns: 1fr; } }

.turn-tittel {
    font-size: 0.72rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--vl-text-muted);
    margin: 0 0 0.75rem;
}
.turn-seksjon { display: flex; align-items: center; justify-content: space-between; gap: 1rem; margin-bottom: 0.75rem; }
.turn-seksjon .turn-tittel { margin: 0; }

.turn-hoyre > section { padding-bottom: 1.25rem; margin-bottom: 1.25rem; border-bottom: 1px solid var(--vl-glass-border); }
.turn-hoyre > section:last-child { border-bottom: 0; }
.turn-hoyre-tekst { font-size: 0.88rem; }

/* ── Pallen — premier() i tournament-detail.js (utkast B) ──
   Tre plasser, 2 – 1 – 3, vinneren høyest i midten. Premien står OVER
   trinnet, og trinnene har FASTE høyder: en lang premietekst gjør
   kolonnen høyere oppover, aldri trinnet. Med teksten inni søylen og bare
   `min-height` ble 3. plass nesten like høy som 1. (Robert 03.10.2026).
   Rekkefølgen settes med `order`, så markupen står i plassrekkefølge for
   skjermlesere. Gull er en tone i trinnet, ikke en farget kant. */
.turn-pall {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    align-items: end;
    gap: 0.4rem;
    text-align: center;
}
.turn-pall--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.turn-pall-plass { display: flex; flex-direction: column; justify-content: flex-end; min-width: 0; }
.turn-pall-premie { padding: 0 0.15rem 0.45rem; }
.turn-pall-premie b { display: block; font-size: 0.88rem; line-height: 1.2; overflow-wrap: anywhere; }
.turn-pall-premie small { display: block; font-size: 0.7rem; line-height: 1.25; color: var(--vl-text-muted); margin-top: 0.15rem; }
.turn-pall-trinn {
    display: flex; align-items: center; justify-content: center;
    border-radius: 8px 8px 0 0;
    background: var(--vl-glass);
    border: 1px solid var(--vl-glass-border);
    border-bottom: 0;
    font: 700 1.15rem 'Space Grotesk', sans-serif;
    color: var(--vl-text-muted);
}
.turn-pall-plass--1 { order: 2; }
.turn-pall-plass--2 { order: 1; }
.turn-pall-plass--3 { order: 3; }
.turn-pall-plass--1 .turn-pall-trinn { height: 64px; color: #fdcb6e; background: rgba(253, 203, 110, 0.10); border-color: rgba(253, 203, 110, 0.28); }
.turn-pall-plass--2 .turn-pall-trinn { height: 46px; }
.turn-pall-plass--3 .turn-pall-trinn { height: 32px; }
.turn-pall--2 .turn-pall-plass--1 { order: 1; }
.turn-pall--2 .turn-pall-plass--2 { order: 2; }
/* Lister i crew-skrevet HTML har <p> i hvert punkt — det dobler luften */
.turn-hoyre-tekst li > p { margin: 0; }

/* Ingen høyde her. Høyden og taket eies av `fitToContainer()` i
   svg-bracket.js (1003-1641). `hidden`, ikke `auto`: visningen har egen
   panorering og zoom, og en scrollbar oppå gir to måter å flytte det samme på. */
.turn-bracket {
    overflow: hidden;
}

/* Oppsettet står HER, ikke som `d-flex flex-column gap-2` på elementet.
   Bootstrap gir `.d-flex` et `!important`, og det slår `[hidden]` — skjemaet
   skal skjules når man allerede har levert. */
.turn-bidrag-form {
    width: 100%;
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
}
.turn-bidrag-form[hidden] { display: none; }
.turn-bidrag-form > div { max-width: none; }

.turn-laast {
    margin: 0.75rem 0 0;
    font-size: 0.8rem;
    color: var(--vl-text-muted);
}

.turn-vinner { font-size: 0.95rem; }
.turn-vinner i { color: var(--vl-amber); margin-right: 0.4rem; }

@media (max-width: 48rem) {
    .turn-frist-tekst { align-items: flex-start; }
    .hub-island .hub-countdown { justify-content: flex-start; }
}

/* ── Regelverket som oppslag — `components/regelverk.js` ──
   Innholdsfortegnelse til venstre, teksten til høyre, søk i toppen. */
.regelverk .modal-dialog { max-width: 1000px; }
.regelverk .modal-header { gap: 1rem; }
.regelverk .modal-header .sok-felt { flex: 1; max-width: 26rem; }
.regelverk .modal-body { padding: 0; display: grid; grid-template-columns: 250px minmax(0, 1fr); min-height: 0; }
.regelverk-toc {
    border-right: 1px solid var(--vl-glass-border);
    overflow-y: auto;
    padding: 0.75rem 0.5rem;
}
.regelverk-toc a {
    display: block;
    padding: 0.3rem 0.6rem;
    border-radius: var(--vl-radius-xs);
    font-size: 0.82rem;
    color: var(--vl-text-muted);
    text-decoration: none;
}
.regelverk-toc a:hover { background: var(--vl-glass); color: var(--vl-text); }
.regelverk-toc a[hidden] { display: none; }
.regelverk-tekst { position: relative; overflow-y: auto; padding: 1.25rem 1.5rem; font-size: 0.9rem; }
.regelverk-tekst section { scroll-margin-top: 1rem; }
.regelverk-tekst section[hidden] { display: none; }
.regelverk-tekst hr { display: none; }
.regelverk-tekst mark { background: rgba(253, 203, 110, 0.35); color: inherit; padding: 0 1px; border-radius: 2px; }
/* Korte regler (ett kapittel): bare teksten — ingen fortegnelse, intet søk */
.regelverk--kort .modal-dialog { max-width: 640px; }
.regelverk--kort .modal-body { grid-template-columns: 1fr; }
.regelverk--kort .regelverk-toc,
.regelverk--kort .sok-felt,
.regelverk--kort [data-status] { display: none; }
@media (max-width: 767.98px) {
    .regelverk .modal-body { grid-template-columns: 1fr; }
    .regelverk-toc { display: none; }
    .regelverk .modal-header { flex-wrap: wrap; }
    .regelverk .modal-header .sok-felt { order: 3; flex-basis: 100%; max-width: none; }
}

/* ══════════════════════════════════════════════════════════════════════
   Slippsone — `.slippsone`
   ══════════════════════════════════════════════════════════════════════

   Dra en fil hit, eller klikk for å velge. ÉN definisjon; oppførselen ligger
   i `components/slippsone.js`.

   Mønstret fantes fra før på fem steder — galleriredigereren, kiosken,
   bildevelgeren, bunntekst- og menyredigereren — men som fem kopier, med
   stilene i `cms.css` under `.gal-drop-*`. En slippsone kan man ikke søke
   etter på utseende, så den sjette som trengte en skrev en sjette. De fem
   kan flyttes hit når noen likevel er inne i dem.

   Den nakne `<input type="file">` er grunnen til at den finnes: nettleserens
   egen «Choose File / No file chosen» er det ene feltet i appen som ikke lar
   seg style, og den ser ut som et fremmedelement overalt den står. */

.slippsone {
    position: relative;
    display: block;
    width: 100%;
    border: 1px dashed var(--vl-glass-border);
    border-radius: var(--vl-radius);
    background: var(--vl-glass);
    padding: 2rem 1rem;
    text-align: center;
    cursor: pointer;
    transition: border-color 0.15s, background 0.15s;
}

.slippsone:hover,
.slippsone:focus-visible {
    border-color: var(--vl-primary);
    outline: none;
}

/* Under en aktiv dra-operasjon. Fyllet er svakt med vilje: sona skal si «slipp
   her», ikke overdøve innholdet bak. */
.slippsone--over {
    border-color: var(--vl-primary);
    border-style: solid;
    background: color-mix(in srgb, var(--vl-primary) 10%, transparent);
}

/* Feltet er der for tastatur, skjermlesere og vanlig skjema-innsending —
   `display: none` ville tatt det ut av alle tre. */
.slippsone-felt {
    position: absolute;
    width: 1px; height: 1px;
    opacity: 0;
    pointer-events: none;
}

/* FontAwesome setter selv `display: inline-block` paa `.fas`. Uten `width`
   og `margin: auto` blir ikonet staaende der linjeboksen begynner, mens
   teksten under sentreres — to akser i samme kolonne. */
.slippsone-inn i {
    font-size: 2rem;
    color: var(--vl-primary);
    display: block;
    width: 100%;
    text-align: center;
    margin-bottom: 0.6rem;
}

.slippsone-inn p { margin-bottom: 0.25rem; }

.slippsone-inn small {
    color: var(--vl-text-muted);
    font-size: 0.8rem;
}

/* Navnet på det som er valgt. Uten dette ser sona uendret ut etter et
   vellykket drop, og folk slipper fila en gang til. */
/* Én av de to setningene vises. `hover: none` er det naermeste svaret paa
   «finnes det en peker her» — «Dra en fil hit» er en instruks man ikke kan
   foelge paa en telefon, og det meste som lastes opp under et LAN kommer fra
   en telefon. */
.slippsone-trykk { display: none; }

@media (hover: none) {
    .slippsone-dra { display: none; }
    .slippsone-trykk { display: inline; }
}

.slippsone-valgt {
    margin-top: 0.75rem;
    font-size: 0.875rem;
    color: var(--vl-text);
    word-break: break-all;
}

/* ══════════════════════════════════════════════════════════════════════
   Bidragsflis — `.bidrag-flis`
   ══════════════════════════════════════════════════════════════════════

   Ett innsendt bidrag. Ligger i `.gallery-grid`, og brukes BEGGE steder
   bidrag vises: deltakeren ser sine egne under «Ditt bidrag», crew ser alle
   i moderering. Markupen bygges av `components/bidrag-flis.js` — ikke skriv
   den for haand, da blir det to utseender igjen.

   ── Bildet ER kortet ──

   Første utgave la navn, status og knapper som rader UNDER bildet. Det ga to
   problemer på én gang: kortene ble ulikt høye (et bidrag uten tittel er
   lavere enn et med), og knapperaden så påklistret ut — en firkant med tre
   knapper limt på undersiden.

   Nå er kortet en kvadratisk flis. Navnet ligger i en gradient nederst,
   statusen øverst, og handlingene kommer fram OVER bildet når man peker på
   det. Alle fliser er like høye fordi de er kvadrater, og raden linjer opp av
   seg selv — ingen `margin-top: auto` som må holde orden.

   ── Handlingene må være der uten mus ──

   `:hover` alene ville gjort kortet ubrukelig på nettbrett og med tastatur.
   `:focus-within` dekker tastaturet, og `@media (hover: none)` viser dem
   permanent der det ikke finnes en peker. */

.bidrag-flis {
    position: relative;
    aspect-ratio: 1;
    border-radius: var(--vl-radius-sm);
    overflow: hidden;
    background: var(--vl-bg-elevated);
}

.bidrag-flis-bilde {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    border: none;
    padding: 0;
    background-size: cover;
    background-position: center;
    cursor: zoom-in;
}

/* Statusen oeverst. Bakgrunnen er egen, ikke `.status-pill` sin, fordi den
   staar paa et bilde og maa vaere lesbar uansett hva som er under. */
.bidrag-flis-topp {
    position: absolute;
    top: 0.5rem;
    left: 0.5rem;
    right: 0.5rem;
    display: flex;
    align-items: center;
    gap: 0.35rem;
    pointer-events: none;
    z-index: 2;
}

.bidrag-flis-status {
    font-size: 0.7rem;
    font-weight: 600;
    padding: 0.15rem 0.5rem;
    border-radius: 999px;
    backdrop-filter: blur(6px);
    background: rgba(12, 16, 22, 0.72);
}
.bidrag-flis-status--ok { color: #55efc4; }
.bidrag-flis-status--wait { color: #ffeaa7; }
.bidrag-flis-status--avvist { color: #e17055; }

.bidrag-flis-merke {
    margin-left: auto;
    font-size: 0.7rem;
    color: rgba(255, 255, 255, 0.75);
    background: rgba(12, 16, 22, 0.72);
    backdrop-filter: blur(6px);
    border-radius: 999px;
    padding: 0.15rem 0.4rem;
}

/* Navnet, i en gradient som gjoer teksten lesbar uten aa dekke bildet. */
.bidrag-flis-bunn {
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    padding: 1.8rem 0.6rem 0.55rem;
    background: linear-gradient(to top, rgba(8, 11, 16, 0.92) 25%, transparent);
    pointer-events: none;
    transition: opacity 0.15s ease;
    z-index: 2;
}

.bidrag-flis-navn {
    font-size: 0.85rem;
    font-weight: 600;
    color: #fff;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.bidrag-flis-tittel {
    font-size: 0.75rem;
    color: rgba(255, 255, 255, 0.72);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Handlingene ligger over navnet og kommer fram paa hover eller fokus. */
.bidrag-flis-handling {
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    display: flex;
    gap: 0.35rem;
    padding: 0.55rem;
    background: linear-gradient(to top, rgba(8, 11, 16, 0.96) 55%, transparent);
    opacity: 0;
    transform: translateY(0.4rem);
    transition: opacity 0.15s ease, transform 0.15s ease;
    z-index: 3;
}

.bidrag-flis:hover .bidrag-flis-handling,
.bidrag-flis:focus-within .bidrag-flis-handling {
    opacity: 1;
    transform: none;
}
.bidrag-flis:hover .bidrag-flis-bunn,
.bidrag-flis:focus-within .bidrag-flis-bunn { opacity: 0; }

.bidrag-flis-handling .knapp-tone {
    flex: 1;
    justify-content: center;
    background: rgba(255, 255, 255, 0.08);
}
.bidrag-flis-handling .knapp-tone--ikon { flex: 0 0 auto; }

/* ── «Legg til nytt bidrag» ──
   Staar SOM en flis i samme rutenett, like stor som bildene ved siden av.
   Foer laa hele opplastingsskjemaet permanent under bildet: tittelfelt,
   slippsone og knapp, framme ogsaa etter at man var ferdig. Naa er skjemaet
   skjult til man ber om det, og det man ber med er en tom plass i rekka —
   stiplet, fordi det er der noe KAN komme, ikke noe som er der. */
.bidrag-flis-ny {
    aspect-ratio: 1;
    border: 1px dashed var(--vl-glass-border);
    border-radius: var(--vl-radius-sm);
    background: none;
    color: var(--vl-text-muted);
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0.45rem;
    padding: 0.75rem;
    text-align: center;
    font-size: 0.8rem;
    line-height: 1.3;
    cursor: pointer;
    transition: border-color 0.15s ease, color 0.15s ease, background 0.15s ease;
}

.bidrag-flis-ny i { font-size: 1.35rem; }

.bidrag-flis-ny:hover,
.bidrag-flis-ny:focus-visible {
    border-color: var(--vl-accent);
    color: var(--vl-text);
    background: rgba(255, 255, 255, 0.03);
}

/* Uten peker finnes ingen hover. Da staar handlingene permanent, og navnet
   flytter opp over dem i stedet for aa ligge under. */
@media (hover: none) {
    .bidrag-flis-handling { opacity: 1; transform: none; }
    .bidrag-flis-bunn { bottom: 2.6rem; padding-bottom: 0.3rem; background: none; }
    .bidrag-flis-navn,
    .bidrag-flis-tittel { text-shadow: 0 1px 3px rgba(0, 0, 0, 0.9); }
}

/* ══════════════════════════════════════════
   DELTAKERMERKER — `.dm`
   Smaa ikoner i en billettliste: trenger personen foreldresamtykke, og har
   vi moett hen. De staar BARE naar de betyr noe — se components/deltakermerker.js.
   ══════════════════════════════════════════ */

.dm { white-space: nowrap; }

.dm-merke {
    margin-left: 0.45rem;
    font-size: 0.8rem;
    vertical-align: baseline;
    cursor: help;
}

/* Dempet groent. Merket skal bekrefte, ikke feire — det er det roede som skal
   fange oeyet i en liste man skanner. */
.dm-ok { color: rgba(85, 239, 196, 0.65); }
.dm-varsel { color: #f0b429; }
.dm-fare { color: #ff6b5b; }

/* ══════════════════════════════════════════
   OPPGAVETAVLE — `.opg-`
   Tavla paa /crew/oppgaver: opprigg, nedrigg og alt crew skal huske.

   ── ÉN grid, tre grupperinger ──

   Kolonnene er ikke en kanban med faste spalter. `auto-fit` gjor at det ER
   en kanban naar man grupperer paa status (tre grupper), en Planner-tavle
   naar man grupperer paa person (femten som brekker over flere rader), og
   én kolonne paa telefon. Ett oppsett, ingen spesialtilfeller, og ingen
   vannrett rulling — som er nettopp der Planka og MS Planner blir uleselige
   paa en laptop i en hall.

   ── Gruppa er IKKE en boks ──

   `sidelayout.md` § «Ingen bokser i bokser»: kortene er `.list-item` og har
   alt sin egen bakgrunn og ramme. Gruppa har derfor bare en overskrift med
   en strek under — ingen flate, ingen kant.
   ══════════════════════════════════════════ */

.opg-brett {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(270px, 1fr));
    gap: 1.5rem 1.25rem;
    align-items: start;
}

.opg-gruppe { min-width: 0; }

.opg-gruppe-topp {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin-bottom: 0.6rem;
    padding-bottom: 0.4rem;
    border-bottom: 1px solid var(--vl-glass-border);
}

.opg-gruppe-navn {
    font-weight: 600;
    font-size: 0.95rem;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.opg-gruppe-tall {
    margin-left: auto;
    color: var(--vl-text-muted);
    font-size: 0.78rem;
    font-variant-numeric: tabular-nums;
}

/* ── Kortene flyter, de stables ikke ──
   Griden over fordeler GRUPPENE. Med bare én gruppe — tavlevelgeren staar
   paa «Rigging» — ble den ene kolonnen 1340 px bred, og hvert kort en
   nesten tom stripe med tjue tegn tekst. Arrangoeren: «vi faar svaert mye
   whitespace».

   Lista er derfor selv en grid. Er gruppa bred, tiler kortene i flere
   spalter; er den smal (mange grupper ved siden av hverandre), blir det én.
   Ett oppsett, begge tilfellene. */
.opg-liste {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
    gap: 0.5rem;
    align-content: start;
}

/* ── «Ny oppgave» nederst i kolonnen ──
   Samme plass som «Add another card» i Planka og Trello: under kortene, i
   kolonnen den hoerer til. Dempet i hviletilstand — én knapp per kolonne som
   roper like hoeyt som kortene gjoer brettet uroligere enn det er. */
.opg-komponer { margin-top: 0.5rem; }

.opg-komponer-knapp {
    display: flex;
    align-items: center;
    gap: 0.45rem;
    width: 100%;
    padding: 0.4rem 0.6rem;
    border: 1px dashed var(--vl-glass-border);
    border-radius: 0.5rem;
    background: transparent;
    color: var(--vl-text-muted);
    font-size: 0.82rem;
    text-align: left;
    transition: background 0.15s, color 0.15s, border-color 0.15s;
}

.opg-komponer-knapp:hover {
    background: var(--vl-glass-bg);
    border-color: var(--vl-primary);
    color: var(--vl-text);
}

/* Feltet er skjult til knappen trykkes, og knappen forsvinner naar det er
   framme. To kontroller for det samme, samtidig, ville vaert to maater aa
   gjoere én ting paa. */
.opg-komponer-felt { display: none; }
.opg-komponer.er-aapen .opg-komponer-knapp { display: none; }
.opg-komponer.er-aapen .opg-komponer-felt { display: block; }

.opg-komponer-felt textarea {
    font-size: 0.85rem;
    resize: none;
}

.opg-komponer-handling {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    margin-top: 0.4rem;
}

/* Kortet. `.list-item` er en rad med `space-between`; i en smal kolonne skal
   innholdet stables fra toppen i stedet. */
.opg-kort {
    align-items: flex-start;
    gap: 0.5rem;
    /* Tett. Trettini kort skal faa plass paa en skjerm, ikke ni. */
    padding: 0.45rem 0.6rem;
    cursor: pointer;
}

/* En ferdig oppgave skal fortsatt kunne LESES — den er kvitteringen for at
   noe ble gjort. Dempet, ikke skjult. */
.opg-kort--ferdig { opacity: 0.5; }
.opg-kort--ferdig .opg-tittel { text-decoration: line-through; }

/* ── Haken ──
   Den ene synlige kontrollen paa kortet. En rund avkrysningsboks er den
   universelle sjekkliste-affordansen: alle vet hva den gjor, og den er
   reversibel med samme trykk. */
.opg-hake {
    flex: 0 0 auto;
    width: 16px;
    height: 16px;
    margin-top: 0.12rem;
    padding: 0;
    border: 2px solid var(--vl-glass-border);
    border-radius: 50%;
    background: transparent;
    color: transparent;
    font-size: 0.6rem;
    line-height: 1;
    cursor: pointer;
    transition: border-color 0.12s, background 0.12s, color 0.12s;
}

.opg-hake:hover { border-color: #55efc4; }

.opg-hake[aria-pressed="true"] {
    border-color: #55efc4;
    background: #55efc4;
    color: #10241c;
}

.opg-kropp { flex: 1 1 auto; min-width: 0; }

.opg-tittel {
    font-weight: 600;
    font-size: 0.85rem;
    line-height: 1.25;
    overflow-wrap: anywhere;
}

.opg-meta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.15rem 0.5rem;
    margin-top: 0.2rem;
    color: var(--vl-text-muted);
    font-size: 0.72rem;
}

/* Metalinja skal ikke gjore kortet hoeyere enn tittelen gjor. Er det for
   mye i den, faller det siste bort framfor aa brekke til en tredje linje. */
.opg-meta > * { white-space: nowrap; }

/* Trenger fire, har to. Tallet er en ADVARSEL naar det mangler folk, og
   noeytralt naar det ikke gjor det — fargen sier hvilken av de to. */
.opg-behov--mangler { color: #f0b429; }

/* Prioritet. `normal` har ingen klasse med vilje — et merke paa
   normaltilstanden er stoey. */
.opg-pri--hoy { color: #ff7a6b; font-weight: 600; }
.opg-pri--middels { color: #f0b429; }

/* Ansiktet i gruppeoverskrifta naar man grupperer paa person. Raskere aa
   finne enn navnet naar man leter etter sin egen kolonne blant ti. */
.opg-gruppe-avatar { flex: 0 0 auto; }

.opg-folk {
    display: flex;
    align-items: center;
    flex: 0 0 auto;
}

.opg-folk .avatar {
    margin-left: -6px;
    border: 2px solid var(--vl-bg-card-solid);
}

.opg-folk .avatar:first-child { margin-left: 0; }

/* `.list-item` stabler paa telefon. Det er riktig for en bred rad med
   handlinger til hoeyre, og feil her: haken havner alene paa foerste linje og
   ellipsisen alene paa siste, saa et kort med to ord tar 140 px hoeyde.
   Kortet er allerede bygget som en smal kolonne — det trenger ingen stabling. */
@media (max-width: 575.98px) {
    .opg-kort {
        flex-direction: row;
        align-items: flex-start;
    }
    .opg-kort .list-item-actions { align-self: flex-start; }
}

/* Sjekklista inne i kortet: bare telleren, ikke punktene. Kortet skal kunne
   leses paa et halvt sekund; punktene staar i modalen. */
.opg-sjekk { font-variant-numeric: tabular-nums; }
.opg-sjekk--full { color: #55efc4; }

/* Punktene i modalen */
.opg-punkt {
    display: flex;
    align-items: flex-start;
    gap: 0.55rem;
    padding: 0.35rem 0;
    border-bottom: 1px solid var(--vl-glass-border);
}

.opg-punkt:last-of-type { border-bottom: 0; }
.opg-punkt-tekst {
    flex: 1 1 auto;
    min-width: 0;
    font-size: 0.88rem;
    overflow-wrap: anywhere;
    /* Teksten ER redigeringsknappen. Tekstmarkoeren sier det uten aa legge
       til en blyant per rad. */
    cursor: text;
    border-radius: 0.25rem;
    padding: 0 0.2rem;
    margin: 0 -0.2rem;
}

.opg-punkt-tekst:hover,
.opg-punkt-tekst:focus-visible { background: var(--vl-glass-bg); }

/* ── Skrivefeltet ER teksten ──
   Maalt foer: med Bootstraps `.form-control` vokste raden fra 34 til 56 px i
   det man klikket, og teksten flyttet seg 3 px til hoeyre. Feltet arver
   derfor boksen til `.opg-punkt-tekst` helt ut — samme skriftstoerrelse,
   samme linjehoeyde, samme padding, ingen ramme — og hoyden settes av
   `voksPunkt()`. Da staar raden helt stille. */
.opg-punkt-felt {
    flex: 1 1 auto;
    min-width: 0;
    display: block;
    font-family: inherit;
    font-size: 0.88rem;
    line-height: 1.5;
    padding: 0 0.2rem;
    margin: 0 -0.2rem;
    border: 0;
    border-radius: 0.25rem;
    background: var(--vl-glass-bg);
    color: var(--vl-text);
    overflow: hidden;
    overflow-wrap: anywhere;
    resize: none;
}

/* Ring i stedet for ramme: en ramme ville lagt 2 px paa hoyden. */
.opg-punkt-felt:focus {
    outline: none;
    box-shadow: 0 0 0 1px var(--vl-primary);
}
.opg-punkt--gjort .opg-punkt-tekst { opacity: 0.55; text-decoration: line-through; }

/* Grepet. Dempet i hvile og tydelig naar man er over raden: det skal vaere
   mulig aa finne uten aa rope i en liste paa seks linjer. */
.opg-punkt-grep {
    flex: 0 0 auto;
    padding-top: 0.15rem;
    color: var(--vl-text-muted);
    font-size: 0.78rem;
    cursor: grab;
    opacity: 0.3;
    transition: opacity 0.12s;
}

.opg-punkt:hover .opg-punkt-grep { opacity: 1; }
.opg-punkt.er-dratt { opacity: 0.4; }

/* Strek i toppen av raden man er over — punktet legger seg DER. En ramme
   rundt hele raden ville sagt «bytt med denne», som ikke er det som skjer. */
.opg-punkt.er-maal { box-shadow: inset 0 2px 0 0 var(--vl-primary); }

/* HTML5-dra finnes ikke paa beroeringsskjerm. Et grep som ikke kan gripes
   er verre enn ingen: paa telefon skriver man punktene i rekkefoelge. */
@media (hover: none) and (pointer: coarse) {
    .opg-punkt-grep { display: none; }
}

.opg-punkt-slett {
    flex: 0 0 auto;
    padding: 0.1rem 0.35rem;
    border: 0;
    background: none;
    color: #e07070;
    font-size: 0.78rem;
    cursor: pointer;
}

/* Hvem laget oppgaven, og hvem roerte den sist. Dempet og sist i kortet:
   det er en fotnote man leter etter, ikke noe man leser hver gang. */
.opgm-spor {
    margin-top: 1.25rem;
    padding-top: 0.6rem;
    border-top: 1px solid var(--vl-glass-border);
    color: var(--vl-text-muted);
    font-size: 0.75rem;
}

/* Navnene i klartekst og punktene under kortet er BARE for papir. Paa skjerm
   er avatarene tettere, og punktene staar i modalen. */
.opg-navn-print,
.opg-punkt-print,
.opg-utskriftstopp { display: none; }

/* ══════════════════════════════════════════
   UTSKRIFT — oppgavetavla paa papir

   Hallen mister nettet. Tavla skal kunne henge paa veggen, og den skal kunne
   krysses av med penn — derfor en ekte firkant per linje og per punkt, ikke
   en gjengivelse av skjermen.

   ── Hvorfor `:has()` og ikke en klasse paa `body` ──

   Ruteren har ingen cleanup-hook. En klasse sida setter paa `body` maa noen
   fjerne igjen, og den som glemmer det gjor at NESTE side printer som en
   oppgaveliste. `body:has(.opg-brett)` er sann noeyaktig saa lenge tavla er
   montert, og faller bort av seg selv naar `#app-content` byttes ut.

   Faller `:has()` bort paa en gammel nettleser, kommer topbaren med paa
   utskriften. Det er en darligere utskrift, ikke en odelagt side. Regelen om
   Chrome 81 gjelder `infoskjerm.css`, ikke denne fila.

   Resten av appen printer som foer.
   ══════════════════════════════════════════ */

@media print {
    body:has(.opg-brett),
    body:has(.opg-brett) .app-shell,
    body:has(.opg-brett) .app-main,
    body:has(.opg-brett) .app-content,
    body:has(.opg-brett) .app-content > * {
        display: block !important;
        max-width: none !important;
        width: auto !important;
        margin: 0 !important;
        padding: 0 !important;
        background: #fff !important;
        color: #000 !important;

        /* ── Uten disse to blir utskriften ÉN side ──
           `.app-shell` er 100vh og `.app-content` ruller INNVENDIG
           (`overflow-y: auto`, se router.js). En rullende boks KLIPPER i
           utskrift: alt under foerste arkhoeyde finnes ikke, og det
           paginerer ikke — det forsvinner. Maalt mot en ekte PDF 30.09.2026:
           trettini oppgaver ble til én side som sluttet midt i en tittel. */
        height: auto !important;
        min-height: 0 !important;
        max-height: none !important;
        overflow: visible !important;
    }

    /* ── ÉN spalte, ikke to ──
       Foerste utgave brukte `column-count: 2`. Det ble tettere paa arket og
       KLIPPET innholdet: Chromium paginerer flerspaltet innhold daarlig, og
       lista sluttet midt i en oppgave nederst paa side 1 uten at noe fortsatte
       paa side 2. Maalt med en ekte PDF-utskrift 30.09.2026.

       En riggeliste som mangler de siste tolv punktene er verre enn en som
       bruker tre ark. */
    body:has(.opg-brett) .opg-brett {
        display: block;
        column-count: auto;
    }

    /* Toppteksten finnes BARE paa papir. Arket havner paa en vegg og blir
       liggende; uten dato og arrangement er det umulig aa vite om det er
       denne helgas liste eller fjoraarets. */
    body:has(.opg-brett) .opg-utskriftstopp {
        display: block !important;
        margin-bottom: 5mm;
        padding-bottom: 2mm;
        border-bottom: 0.5mm solid #000;
        color: #000 !important;
    }

    body:has(.opg-brett) .opg-utskriftstopp h2 {
        margin: 0;
        font-size: 14pt;
        font-weight: 700;
    }

    body:has(.opg-brett) .opg-utskriftstopp p {
        margin: 1mm 0 0;
        font-size: 8.5pt;
        color: #444;
    }

    /* ── Gruppa maa KUNNE brekke ──
       Foerste utgave hadde `break-inside: avoid` her. En tavle med fjorten
       oppgaver er hoeyere enn et A4-ark, saa regelen skjoev hele gruppa til
       neste side — der den fortsatt ikke fikk plass. Resultatet var en helt
       blank foerste side. Maalt mot en ekte PDF 30.09.2026.

       Det som faktisk skal holdes sammen er det ENKELTE kortet, og
       overskrifta med den foerste linja under seg. */
    body:has(.opg-brett) .opg-gruppe {
        break-inside: auto;
        page-break-inside: auto;
        margin-bottom: 6mm;
    }

    body:has(.opg-brett) .opg-gruppe-topp {
        border-bottom: 1px solid #000;
        color: #000;
        break-after: avoid;
        page-break-after: avoid;
    }

    body:has(.opg-brett) .opg-gruppe-navn { font-size: 11pt; }
    body:has(.opg-brett) .opg-gruppe-tall { color: #444; }

    body:has(.opg-brett) .opg-liste { display: block; }
    /* Et skrivefelt paa papir er bare en tom boks. */
    body:has(.opg-brett) .opg-komponer { display: none; }
    body:has(.opg-brett) .opg-meta > * { white-space: normal; }
    /* «!» foran de viktige — papir har ingen farge aa bruke. */
    body:has(.opg-brett) .opg-pri--hoy::before { content: '! '; font-weight: 700; }
    body:has(.opg-brett) .opg-pri--middels::before { content: ' b7 '; }
    body:has(.opg-brett) .opg-gruppe-avatar { display: none; }

    /* Firkanten man krysser av med penn. `.list-item`-flata bort — papir har
       ingen bruk for en bakgrunn. */
    body:has(.opg-brett) .opg-kort {
        display: block;
        break-inside: avoid;
        page-break-inside: avoid;
        margin: 0 0 1.5mm;
        padding: 0 0 0 6mm;
        border: 0 !important;
        border-radius: 0;
        background: none !important;
        color: #000 !important;
        opacity: 1 !important;
        position: relative;
    }

    body:has(.opg-brett) .opg-kort::before {
        content: "";
        position: absolute;
        left: 0;
        top: 1mm;
        width: 3.2mm;
        height: 3.2mm;
        border: 0.4mm solid #000;
    }

    /* En ferdig oppgave faar krysset satt for seg. Strek over tittelen ville
       gjort den uleselig paa papir. */
    body:has(.opg-brett) .opg-kort--ferdig::before { background: #000; }
    body:has(.opg-brett) .opg-kort--ferdig .opg-tittel { text-decoration: none; color: #555; }

    body:has(.opg-brett) .opg-tittel { font-size: 9.5pt; font-weight: 600; }
    body:has(.opg-brett) .opg-meta { color: #444; font-size: 7.5pt; margin-top: 0.3mm; }
    body:has(.opg-brett) .opg-folk { display: none; }

    /* Papiret har plass til navnene i klartekst — avatarene har det ikke. */
    body:has(.opg-brett) .opg-navn-print { display: inline !important; }

    body:has(.opg-brett) .opg-punkt-print {
        display: block;
        padding-left: 5mm;
        font-size: 8pt;
        color: #222;
        position: relative;
    }

    body:has(.opg-brett) .opg-punkt-print::before {
        content: "";
        position: absolute;
        left: 0;
        top: 0.9mm;
        width: 2.2mm;
        height: 2.2mm;
        border: 0.3mm solid #666;
    }

    body:has(.opg-brett) .opg-punkt-print--gjort::before { background: #666; }

    body:has(.opg-brett) .status-pill {
        border-color: #999 !important;
        background: none !important;
        color: #333 !important;
    }

    /* Metaen er farget paa skjerm — bla tavlenavn, gul bemanningsvarsel. Paa
       papir er alt graatt, og barna maa tvinges: fargen staar paa dem, ikke
       paa raden. */
    body:has(.opg-brett) .opg-meta,
    body:has(.opg-brett) .opg-meta * { color: #444 !important; }

    /* ── SIST i blokka, og det er ikke tilfeldig ──
       `display: none` og `display: block` over har SAMME spesifisitet og
       begge `!important`; da vinner den siste. Laa denne foerst, ble
       verktoylinja — en direkte barn av `.app-content` — satt tilbake til
       block av reset-regelen, og hele filterraden kom med paa utskriften. */
    body:has(.opg-brett) #app-sidebar,
    body:has(.opg-brett) #app-topbar,
    body:has(.opg-brett) .verktoylinje,
    body:has(.opg-brett) #opg-tall,
    body:has(.opg-brett) .metric-strip,
    body:has(.opg-brett) .opg-hake,
    body:has(.opg-brett) .opg-tom,
    body:has(.opg-brett) .list-item-actions { display: none !important; }
}

/* ══════════════════════════════════════════
   OPPGAVEKORTET — `.opgm-`
   Modalen bak et kort på /crew/oppgaver, bygget som et Trello-/Planka-kort.

   ── Hvorfor den ble bygget om ──

   Foerste utgave var et SKJEMA: tittel, tavle, status, beskrivelse, sted,
   trenger, fra, til, folk og sjekkliste — alle synlige, alltid, med etikett
   over hvert felt. Det ga 1100 px hoeyde for en oppgave som het «Sett ut
   soeppelboetter» og ikke hadde noe annet utfylt. Arrangoeren meldte det slik:
   «modalen blir veldig oppblaast, med plass til svaert lite».

   Trello, Planka og Planner loeser det samme paa samme maate, og det er ikke
   pynt: **kortet viser bare det som har innhold.** Resten legger du til fra en
   sidekolonne, og da vokser kortet med bruken i stedet for aa starte fullt.

   Det er dessuten regelen som alt staar i `interaksjon.md`:
   «Aapneren forsvinner naar skjemaet kommer», og «fokus foelger med».

   ── Den lagrer selv ──

   Ingen fot, ingen «Lagre». Hvert felt skriver ved `blur`/`change`, slik
   sjekklistepunktene alt gjorde. En modal man maa huske aa lagre er en modal
   folk mister arbeid i naar de lukker den med hendene fulle av kabel.
   ══════════════════════════════════════════ */

.opgm {
    display: grid;
    grid-template-columns: 1fr 190px;
    gap: 1.5rem;
    align-items: start;
}

.opgm-hoved { min-width: 0; }

/* Tittel og «Lagret» paa SAMME linje.
   «Lagret» laa som en naken inline-span rett etter et blokk-input, altsaa
   paa sin egen linje — og den tomme linja var avstanden ned til chipsene
   som saa unaturlig ut. */
.opgm-tittelrad {
    display: flex;
    align-items: center;
    gap: 0.25rem;
    min-width: 0;
}

/* ── Tittelen ──
   Et `<input>`, ikke contenteditable: `interaksjon.md` reserverer den siste
   for compose-layout, og en modal er ikke det. Rammen er borte til man peker
   paa den, saa den leses som en overskrift til man vil endre den. */
.opgm-tittel {
    width: 100%;
    padding: 0.35rem 0.5rem;
    border: 1px solid transparent;
    border-radius: var(--vl-radius-sm);
    background: transparent;
    color: var(--vl-text);
    font-size: 1.15rem;
    font-weight: 700;
    line-height: 1.3;
}

.opgm-tittel:hover { border-color: var(--vl-glass-border); }

.opgm-tittel:focus {
    outline: none;
    border-color: var(--vl-primary);
    background: var(--vl-glass);
}

/* Statusen rett under tittelen: det som endres oftest, og det eneste som
   alltid staar framme ved siden av beskrivelsen. */
.opgm-status { margin: 0.35rem 0 0 0.5rem; }

/* ── Seksjonene ──
   `[hidden]` maa ha en egen regel her: `.opgm-seksjon` setter `display`, og
   en layoutregel slaar attributtet. Samme felle som `.d-flex hidden` i
   `interaksjon.md`. */
.opgm-seksjon {
    display: block;
    margin-top: 1rem;
}

.opgm-seksjon[hidden] { display: none; }

.opgm-seksjon-topp {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin-bottom: 0.4rem;
    color: var(--vl-text-muted);
    font-size: 0.78rem;
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
}

.opgm-seksjon-tall {
    margin-left: auto;
    font-variant-numeric: tabular-nums;
    text-transform: none;
    letter-spacing: 0;
}

/* ── Beskrivelsen ──
   Hoeyden settes av `voks()` i `oppgave-modal.js`, som maaler innholdet.
   `resize: none` fordi et manuelt dratt felt likevel blir overstyrt ved
   neste tastetrykk — et haandtak som ikke holder er verre enn ingen.

   Mindre skrift enn resten av skjemaet: dette er loepende tekst og kan vaere
   en halv side, ikke et navn paa én linje. */
.opgm-beskrivelse {
    min-height: 4rem;
    max-height: 65vh;
    padding: 0.5rem 0.65rem;
    font-size: 0.86rem;
    line-height: 1.5;
    resize: none;
    overflow-y: auto;
}

/* Folkevelgeren: pillene er de samme som foer, men de ligger naa i en
   seksjon man selv har bedt om. */
.opgm-folk {
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem;
}

.opgm-folk label {
    display: flex;
    align-items: center;
    gap: 0.45rem;
    padding: 0.25rem 0.6rem;
    border: 1px solid transparent;
    border-radius: 999px;
    background: var(--vl-glass);
    font-size: 0.82rem;
    cursor: pointer;
}

.opgm-folk label:hover { border-color: var(--vl-glass-border); }

/* ── Sidekolonnen ── */

.opgm-side { min-width: 0; }

.opgm-side-tittel {
    margin: 1rem 0 0.4rem;
    color: var(--vl-text-muted);
    font-size: 0.7rem;
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
}

.opgm-side-tittel:first-child { margin-top: 0; }

/* Knappene i sidekolonnen er en EGEN form: flate, fullbreddes rader med ikon.
   De er verken `.knapp-tone` (verktoylinjas pille) eller `btn btn-*` — de er
   en meny, og en meny som ser ut som fem knapper ved siden av hverandre
   leses som fem konkurrerende handlinger. */
.opgm-side-knapp {
    display: flex;
    align-items: center;
    gap: 0.55rem;
    width: 100%;
    margin-bottom: 0.3rem;
    padding: 0.42rem 0.65rem;
    border: 0;
    border-radius: var(--vl-radius-sm);
    background: var(--vl-glass);
    color: var(--vl-text);
    font-size: 0.85rem;
    text-align: left;
    cursor: pointer;
    transition: background 0.12s;
}

.opgm-side-knapp:hover { background: rgba(255, 255, 255, 0.09); }

.opgm-side-knapp i {
    width: 1rem;
    flex: 0 0 auto;
    text-align: center;
    color: var(--vl-text-muted);
}

/* Paa-tilstand for «Ta den» / «Meld meg av». Handlingen er reversibel, saa
   den er noeytral i hvile — se `interaksjon.md` § Roedt er reservert. */
.opgm-side-knapp.er-paa {
    background: rgba(85, 239, 196, 0.14);
    color: #7fe0ab;
}

.opgm-side-knapp.er-paa i { color: #7fe0ab; }

/* Slett er det eneste ugjenkallelige i kortet, og det eneste roede. */
.opgm-side-knapp.er-fare { color: #e07070; }
.opgm-side-knapp.er-fare i { color: #e07070; }
.opgm-side-knapp.er-fare:hover { background: rgba(224, 112, 112, 0.14); }

/* «Lagret» — den eneste kvitteringen et kort uten Lagre-knapp gir. Den
   dukker opp ved tittelen og forsvinner igjen; en toast per felt ville vaert
   stoey, og ingen kvittering ville latt folk lure paa om det tok. */
.opgm-lagret {
    flex: 0 0 auto;
    margin-left: 0.25rem;
    color: #7fe0ab;
    font-size: 0.75rem;
    font-weight: 500;
    opacity: 0;
    transition: opacity 0.2s;
}

.opgm-lagret.er-synlig { opacity: 1; }

/* ── Telefon ──
   Sidekolonnen legger seg under innholdet som en rad av knapper. Over
   innholdet ville den dyttet det man kom for under brettet. */
@media (max-width: 575.98px) {
    .opgm {
        grid-template-columns: 1fr;
        gap: 1rem;
    }

    .opgm-side {
        display: flex;
        flex-wrap: wrap;
        gap: 0.3rem;
        padding-top: 0.75rem;
        border-top: 1px solid var(--vl-glass-border);
    }

    /* Overskriftene i sidekolonnen gir ingen mening i en knapperad. */
    .opgm-side-tittel { display: none; }

    .opgm-side-knapp {
        width: auto;
        margin-bottom: 0;
    }
}

/* ── Metalinja: chips og avatarer, ikke seksjoner ──
   Foerste utgave la hvert felt ut som en egen seksjon med etikett. Med ti i
   crewet ble folkevelgeren fire rader avkryssingsbokser, og sjekklista ble
   dyttet under brettet — altsaa den samme oppblaastheten, bare flyttet.

   Trello, Planka og Planner gjor det motsatte: VERDIEN staar som en chip
   eller en avatar, og redigeringen skjer i en popover. Fire seksjoner blir
   én rad paa tretti piksler. */

.opgm-meta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.4rem;
    /* Tett paa tittelen. Venstremargen matcher tittelens egen padding, saa
       chipsene staar rett under teksten og ikke under inputrammen. */
    margin: 0.45rem 0 0 0.5rem;
}

.opgm-avatarer { display: flex; align-items: center; }

.opgm-avatarer .avatar {
    margin-left: -7px;
    border: 2px solid var(--vl-bg-card-solid);
}

.opgm-avatarer .avatar:first-child { margin-left: 0; }

/* Stiplet sirkel: «her kan det staa en til». Samme form som avatarene den
   staar ved siden av, saa den leses som en plass og ikke som en knapp. */
.opgm-avatar-ny {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    margin-left: 4px;
    padding: 0;
    border: 1px dashed var(--vl-glass-border);
    border-radius: 50%;
    background: var(--vl-glass);
    color: var(--vl-text-muted);
    font-size: 0.7rem;
    cursor: pointer;
}

.opgm-avatar-ny:hover { border-color: var(--vl-primary); color: var(--vl-text); }

.opgm-chip {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    padding: 0.25rem 0.65rem;
    border: 1px solid var(--vl-glass-border);
    border-radius: 999px;
    background: var(--vl-glass);
    color: var(--vl-text);
    font-size: 0.8rem;
    cursor: pointer;
}

.opgm-chip:hover { border-color: var(--vl-primary); }
.opgm-chip i { color: var(--vl-text-muted); }

/* Gult naar noen staar paa oppgaven og de er for faa — samme regel som paa
   kortet ute paa tavla. */
.opgm-chip--mangler,
.opgm-chip--mangler i { color: #f0b429; }

/* Prioritet. `lav` er standarden og har ingen chip i det hele tatt. */
.opgm-chip--hoy,
.opgm-chip--hoy i {
    color: #ff7a6b;
}
.opgm-chip--hoy {
    border-color: rgba(255, 122, 107, 0.45);
    background: rgba(255, 122, 107, 0.12);
    font-weight: 600;
}

.opgm-chip--middels,
.opgm-chip--middels i { color: #f0b429; }
.opgm-chip--middels {
    border-color: rgba(240, 180, 41, 0.4);
    background: rgba(240, 180, 41, 0.1);
}

/* ── Popoveren ──
   Montert paa `<body>`, ikke i modalen: en `modal-dialog-scrollable` har
   `overflow: auto`, og et lag inne i den blir klippet. Samme grunn som
   `createAutocomplete` — se `design/interaksjon.md`. Etasjen er 1080, over
   modalen (1055). */
.opgm-pop {
    position: fixed;
    z-index: 1080;
    display: flex;
    flex-direction: column;
    width: 290px;
    max-height: min(60vh, 380px);
    padding: 0.75rem;
    border: 1px solid var(--vl-glass-border);
    border-radius: var(--vl-radius);
    background: var(--vl-bg-card-solid);
    box-shadow: 0 12px 34px rgba(0, 0, 0, 0.5);
}

.opgm-pop-topp {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin-bottom: 0.6rem;
    color: var(--vl-text-muted);
    font-size: 0.75rem;
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
}

.opgm-pop-lukk {
    margin-left: auto;
    padding: 0 0.2rem;
    border: 0;
    background: none;
    color: var(--vl-text-muted);
    cursor: pointer;
}

.opgm-pop-liste {
    min-height: 0;
    margin-top: 0.5rem;
    overflow-y: auto;
}

.opgm-pop-rad {
    display: flex;
    align-items: center;
    gap: 0.55rem;
    width: 100%;
    padding: 0.35rem 0.4rem;
    border: 0;
    border-radius: var(--vl-radius-sm);
    background: none;
    color: var(--vl-text);
    font-size: 0.85rem;
    text-align: left;
    cursor: pointer;
}

.opgm-pop-rad:hover { background: var(--vl-glass); }
.opgm-pop-rad .opgm-pop-hake { margin-left: auto; color: #55efc4; }
.opgm-pop-tom { padding: 0.5rem 0.4rem; color: var(--vl-text-muted); font-size: 0.82rem; }

/* Fremdriftsstripa i sjekklista. Tallet «7/9» sier det samme, men en stripe
   leses uten aa telle — og den er det Planka og Trello har. */
.opgm-fremdrift {
    height: 4px;
    margin: 0 0 0.5rem;
    border-radius: 999px;
    background: var(--vl-glass);
    overflow: hidden;
}

.opgm-fremdrift i {
    display: block;
    height: 100%;
    background: #55efc4;
    transition: width 0.2s;
}

.opgm-fremdrift:empty { display: none; }

/* ── .hover-tips — verktoeytips som kommer med en gang ────────────────────
   components/hover-tips.js. Et `title`-tips kommer foerst etter et par
   sekunder, og det kan ikke endres; paa bemanningstavla og i setekartet
   skummer man over mange smaa ting, og da er det ubrukelig.
   Samme utseende som setekartets tips hadde inline foer det ble delt.
   z-index over modal og toast: det foelger pekeren, og skal aldri skjules. */
.hover-tips {
    position: fixed;
    z-index: 10000;
    pointer-events: none;
    max-width: 280px;
    background: rgba(0, 0, 0, 0.9);
    color: #fff;
    padding: 6px 10px;
    border-radius: 6px;
    font-size: 0.75rem;
    line-height: 1.4;
}
.hover-tips .hover-tips-svak { opacity: 0.7; }
