/* 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 {
    cursor: pointer;
}

.audit-item.audit-error {
    border-left: 3px solid var(--bs-danger);
}

.audit-item.audit-warning {
    border-left: 3px solid var(--bs-warning);
}

/* ══════════════════════════════════════════
   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-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)
   ══════════════════════════════════════════ */

.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);
}

@media (max-width: 575.98px) {
    .col-list-header { display: none !important; }
    .list-item.col-list-row {
        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; }
.past-ticket-col-status { flex: 0 0 90px; }

@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%;
}

/* Admin user list columns */
.admin-user-row {
    gap: 0.75rem !important;
}
.admin-user-col-name  { flex: 1 1 160px; min-width: 0; }
.admin-user-col-email { flex: 1 1 180px; min-width: 0; }
.admin-user-col-meta  { flex: 0 0 50px; }
.admin-user-col-role  { flex: 0 0 80px; }

@media (max-width: 767.98px) {
    .admin-user-col-name { flex: 1 1 auto; }
}

/* 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;
}
.admin-order-col-avatar { flex: 0 0 28px; }
.admin-order-col-user   { flex: 1 1 140px; min-width: 0; }
.admin-order-col-event  { flex: 1 1 140px; min-width: 0; }
.admin-order-col-info   { flex: 0 0 140px; }
.admin-order-col-amount { flex: 0 0 70px; text-align: right; }
.admin-order-col-status { flex: 0 0 130px; text-align: right; }
.admin-order-col-chevron { flex: 0 0 20px; text-align: right; }

.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; }

    /* Line 2: event name + amount on same row */
    .list-item.admin-order-row > .admin-order-col-event  {
        flex: 1 1 0; order: 4; min-width: 0;
        padding-left: 36px;
    }
    .list-item.admin-order-row > .admin-order-col-amount {
        flex: 0 0 auto; order: 5;
    }

    /* Hide on mobile */
    .list-item.admin-order-row > .admin-order-col-info    { display: none !important; }
    .list-item.admin-order-row > .admin-order-col-chevron { display: none !important; }

    /* Hide date sub-text on mobile to keep rows compact */
    .list-item.admin-order-row .admin-order-col-user > span:last-child { display: none !important; }
}

/* 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; }
}

/* Admin crew list columns — desktop */
.admin-crew-row {
    gap: 0.75rem !important;
    align-items: center;
}
.admin-crew-col-avatar  { flex: 0 0 36px; }
.admin-crew-col-name    { flex: 1 1 160px; min-width: 0; }
.admin-crew-col-email   { flex: 1 1 160px; min-width: 0; }
.admin-crew-col-role    { flex: 0 0 140px; }
.admin-crew-col-actions { flex: 0 0 60px; text-align: right; }

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

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

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

    /* Line 2: email */
    .list-item.admin-crew-row > .admin-crew-col-email   {
        flex: 1 1 0; order: 4; min-width: 0;
        padding-left: 36px;
    }
    .list-item.admin-crew-row > .admin-crew-col-actions { flex: 0 0 auto; order: 5; }
}

/* 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); }

/* ══════════════════════════════════════════
   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 ── */

/* Tab navigation */
.imgpicker-tabs {
    display: flex;
    gap: 0;
    border-bottom: 1px solid var(--vl-glass-border);
}

.imgpicker-tab {
    padding: 0.4rem 1rem;
    background: none;
    border: none;
    border-bottom: 2px solid transparent;
    color: var(--vl-text-muted);
    font-size: 0.85rem;
    cursor: pointer;
    transition: color 0.15s, border-color 0.15s;
    white-space: nowrap;
}

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

.imgpicker-tab--active {
    color: var(--vl-primary);
    border-bottom-color: var(--vl-primary);
}

/* 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;
}
/* 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;
}

/* ══════════════════════════════════════════
   EMBED SCHEDULE TIMELINE (resource grid)
   ══════════════════════════════════════════ */

.sched-embed {
    width: 100vw;
    height: 100vh;
    overflow: hidden;
    background: var(--vl-bg, #0f0f23);
}
.sched-embed-grid {
    display: grid;
    width: 100%;
    overflow: hidden;
}
/* Header cells */
.sched-embed-corner {
    background: var(--vl-bg-elevated, rgba(255,255,255,0.03));
    border-bottom: 1px solid var(--vl-glass-border, rgba(255,255,255,0.08));
    border-right: 1px solid var(--vl-glass-border, rgba(255,255,255,0.08));
}
.sched-embed-day {
    font-weight: 700;
    font-size: max(0.6rem, 0.85vw);
    text-align: center;
    padding: 0.3vh 0;
    background: var(--vl-bg-elevated, rgba(255,255,255,0.03));
    border-bottom: 1px solid var(--vl-glass-border, rgba(255,255,255,0.08));
    color: var(--vl-text, #e0e0e0);
}
.sched-embed-hour {
    font-size: max(0.5rem, 0.65vw);
    text-align: center;
    color: var(--vl-text-muted, #888);
    border-bottom: 1px solid var(--vl-glass-border, rgba(255,255,255,0.08));
    border-left: 1px solid rgba(255,255,255,0.04);
    display: flex;
    align-items: center;
    justify-content: center;
}
/* Resource label */
.sched-embed-resource {
    display: flex;
    align-items: center;
    padding: 0 0.4vw;
    border-bottom: 1px solid rgba(255,255,255,0.04);
    border-right: 1px solid var(--vl-glass-border, rgba(255,255,255,0.08));
    overflow: hidden;
}
.sched-embed-resource--separator {
    border-top: 2px solid rgba(255,255,255,0.15);
}
.sched-embed-resource-text {
    font-size: max(0.55rem, 0.75vw);
    font-weight: 600;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    color: var(--vl-text, #e0e0e0);
}
/* Row (time cells area) */
.sched-embed-row {
    border-bottom: 1px solid rgba(255,255,255,0.04);
}
.sched-embed-gridline {
    position: absolute;
    top: 0;
    height: 100%;
    border-left: 1px solid rgba(255,255,255,0.04);
}
/* Items */
.sched-embed-item {
    position: absolute;
    top: 8%;
    height: 84%;
    border-radius: 3px;
    display: flex;
    align-items: center;
    padding: 0 0.3vw;
    overflow: hidden;
    z-index: 2;
}
.sched-embed-item--past { opacity: 0.3; }
.sched-embed-item--current {
    box-shadow: 0 0 0 2px #fff, 0 0 6px rgba(108,92,231,0.5);
    z-index: 3;
}
.sched-embed-item-text {
    font-size: max(0.5rem, 0.7vw);
    font-weight: 600;
    color: #fff;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
/* Now indicator */
.sched-embed-now {
    position: absolute;
    top: 0;
    height: 100%;
    width: 2px;
    background: #e74c3c;
    z-index: 10;
}
.sched-embed-now::after {
    content: '';
    position: absolute;
    top: -3px;
    left: -4px;
    width: 10px;
    height: 10px;
    background: #e74c3c;
    border-radius: 50%;
}

/* 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-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; }

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

/* 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;
}

.md-rail-sub {
    font-size: 0.75rem;
    opacity: 0.7;
    white-space: nowrap;
}

/* 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; }

/* ── 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; }
.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); }

.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;
    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;
    }
}
