/* Flightrax — modern glass UI over a full-screen dark map. */

:root {
  /* C1 type scale — seven sizes, three weights (650/700/800; .strike's
     400 is the ONE exception: struck old time stays light against the bold
     new one, that contrast IS the Flighty pattern). Display sizes
     (36/46/58/72) live outside the scale on purpose. */
  --fs-micro: 10px;
  --fs-caption: 11.5px;
  --fs-body: 13px;
  --fs-lead: 15px;
  --fs-title: 17px;
  --fs-big: 21px;
  --fs-hero: 26px;
  /* SVART, ikke marineblatt. Brage 7/8: «Jeg liker det svarte, for det ser
     ut som del av 2 ulike apper» — den native detaljflaten sto pa Apples
     systemGroupedBackground (ren #000) mens webflatene sto pa Flightrax-
     navy, og da er det to apper. Verdiene under ER Apples dark mode, ikke
     en tilnaerming: bakgrunn #000, gruppeplate #1C1C1E, nestet #2C2C2E,
     etiketter nøytralt hvite (235,235,245) — ikke blatonet. */
  --bg: #000000;
  /* RGB triplets back every tinted rgba() below — a theme block re-tints the
     whole UI by overriding tokens alone, no per-component rules. */
  --bg-rgb: 0, 0, 0;
  /* Arket over kartet: samme svarte familie, fortsatt gjennomskinnelig sa
     verden under leses. */
  --glass: rgba(12, 12, 14, 0.78);
  --glass-strong: rgba(12, 12, 14, 0.94);
  --line: rgba(var(--muted-rgb), 0.16);
  /* Den lyse alfa-KANTEN (border/inset-rim) på kort, chips og felt. Egen
     token fordi hvit-alfa forsvinner på en hvit plate: lyst tema snur den
     til mørk-alfa. Default = nøyaktig den gamle verdien (mørk uendret). */
  --rim: rgba(255, 255, 255, .14);
  /* Gruppeplaten er en EGEN token, ikke en hvit-alfa pa flaks: den ma
     treffe #1C1C1E over svart, og temaene skal kunne tone den. */
  --plate: #1c1c1e;
  --plate-2: #2c2c2e;
  --fg: #ffffff;
  --muted: #8e8e93;
  --muted-rgb: 235, 235, 245;
  --accent: #5b9dff;
  --accent-rgb: 91, 157, 255;
  /* Teksten OPPÅ aksenten (CTA-knapper, egne chatbobler, aktive chips).
     Hvit på champagne/gull/mint var 1,6–1,9:1 (16/9) — hvert tema eier
     sin egen verdi, og ingen regel skriver #fff på aksent lenger. */
  --on-accent: #fff;
  /* Logo gradient's second stop: COLD cyan, never violet — «mindre lilla»
     (Brage 6/8). Pro themes keep their own duos. */
  --accent2: #46d4ff;
  --good: #4ade80;
  --warn: #fbbf24;
  --bad: #f87171;
  /* Two trackings only: caps for inline uppercase data, kicker for section
     labels. Every uppercase rule uses one of them — no ad-hoc px values. */
  --track-caps: .08em;
  --track-kicker: .14em;
  /* One radius scale. Floating surfaces --r-lg, cards/inputs/rows --r-md,
     small nested things --r-sm; chips/pills/dots are 999px/50%. Nested
     surfaces step DOWN (card in sheet: sheet lg, card md) — same radius
     inside same radius looks stamped, not built. */
  --r-lg: 22px;
  --r-md: 14px;
  --r-sm: 10px;
  --sat: env(safe-area-inset-top, 0px);
  --sab: env(safe-area-inset-bottom, 0px);
  /* Bevegelse (design-uplift 5/9): ÉN utgangskurve og ÉN fjær for hele
     flaten, så faneskift, toast og innlogging deler samme håndlag. */
  --ease-out: cubic-bezier(.2, .8, .2, 1);
  --ease-spring: cubic-bezier(.32, 1.5, .48, 1);
  /* ---- Liquid-glass material ---- */
  --glass-blur: blur(30px) saturate(1.7) brightness(1.02);
  --glass-blur-strong: blur(34px) saturate(1.9) brightness(1.03);
  /* The layered EDGE is what reads as a real glass slab instead of a flat
     frosted panel: a bright specular top rim, faint side rims that catch
     light, a dark bottom that gives the glass thickness, and a soft inner
     body glow. Compose it with an outer float shadow per-surface. */
  --glass-edge:
    inset 0 1.5px 0 rgba(255, 255, 255, .55),
    inset 1px 0 0 rgba(255, 255, 255, .10),
    inset -1px 0 0 rgba(255, 255, 255, .06),
    inset 0 -1.5px 1px rgba(0, 0, 0, .38),
    inset 0 0 26px rgba(255, 255, 255, .045);
}

/* ---------- Pro themes ----------
   Token-only skins: each block swaps the palette, nothing else. Status
   colours (--good/--warn/--bad) keep their meaning in every theme — only
   stealth's chrome goes mono, never its semantics. Kartet tones per tema i
   app.js (tintBasemap) — på basiskartets EGNE lag, aldri på lerretet, for
   lerretet inneholder også flyene og liveryen deres er betydning. */

/* Nordlys — aurora over dark fjord: blue-green base, cold green-cyan accent.
   --good stays the CTA green; the accent is clearly cyan so they never blur. */
:root[data-theme="nordlys"] {
  --bg: #000000;
  --bg-rgb: 0, 0, 0;
  --glass: rgba(9, 20, 17, 0.76);
  --glass-strong: rgba(9, 20, 17, 0.93);
  --plate: #131e1a;
  --plate-2: #1e2c27;
  --fg: #f2fbf7;
  --muted: #8ba79b;
  --muted-rgb: 200, 232, 220;
  --accent: #3ddcc0;
  --accent-rgb: 61, 220, 192;
  --on-accent: #04211b;
  --accent2: #9c7bff; /* logo runs teal → violet */
}


/* Midnattssol — warm arctic night: deep plum base, low-sun gold accent,
   rose-tinted hairlines (--line derives from the warmed --muted-rgb). */
:root[data-theme="midnattssol"] {
  --bg: #000000;
  --bg-rgb: 0, 0, 0;
  --glass: rgba(24, 14, 20, 0.76);
  --glass-strong: rgba(24, 14, 20, 0.93);
  --line: rgba(232, 173, 160, 0.18);
  --plate: #1f1519;
  --plate-2: #2e2226;
  --fg: #fdf6f0;
  --muted: #a79088;
  --muted-rgb: 240, 214, 205;
  --accent: #f0b35c;
  --accent-rgb: 240, 179, 92;
  --on-accent: #2a1608;
  --accent2: #ee7d96; /* logo runs gold → rose */
}


/* Stealth — graphite mono: near-black neutral base, cool steel accent.
   Chrome is desaturated on purpose; the status colours stay saturated so
   green/amber/red still carry meaning against the grayscale. */
:root[data-theme="stealth"] {
  --bg: #000000;
  --bg-rgb: 0, 0, 0;
  --glass: rgba(14, 15, 17, 0.76);
  --glass-strong: rgba(14, 15, 17, 0.93);
  --line: rgba(190, 198, 210, 0.14);
  /* MÅLT 7/8: #1a1b1d lå ΔE 0,8 fra Flightrax-platen — under terskelen
     for hva øyet i det hele tatt kan se. Stealth er et PRO-tema; det kan
     ikke være pikselidentisk med gratistemaet på hver eneste flate.
     #141416 gir ΔE 4,0 og er dessuten riktig i innhold: stealth SKAL
     ligge lavere, nærmere svart, med mindre kontrast — den er dempet, ikke
     bare avfarget. Flightrax-platen står urørt på Apples #1C1C1E, for den
     native SwiftUI-lista bruker nøyaktig den verdien. */
  --plate: #141416;
  --plate-2: #232326;
  --fg: #f4f5f7;
  --muted: #8d949e;
  --muted-rgb: 216, 220, 226;
  --accent: #9aa7b8;
  --accent-rgb: 154, 167, 184;
  --on-accent: #0e1116;
  --accent2: #67717e; /* logo runs steel → gunmetal */
}

:root[data-theme="founder"] {
  /* Founder (16/9) — de 100 første som kjøpte Pro. «Black card»: onyx,
     champagne og platina. Inspirasjonen (luksus-paletter 2026) sier det
     samme som øyet: luksus i mørk UI er KONTROLLERT KONTRAST, gull på
     5–15 % av flaten — ikke mer gull. Midnattssol eier alt rav→rose på
     plomme; founder er kjøligere, hvitere gull på VARM sort, og skiller
     seg på platen (brun-sort, ikke plomme) og aksenten (champagne #e6c886,
     ikke rav #f0b35c). Logoen løper champagne → platina. */
  --bg: #000000;
  --bg-rgb: 0, 0, 0;
  --glass: rgba(18, 15, 11, 0.76);
  --glass-strong: rgba(18, 15, 11, 0.93);
  --line: rgba(230, 200, 134, 0.16);
  --plate: #171410;
  --plate-2: #241f18;
  --fg: #f7f1e6;
  --muted: #a8997f;
  --muted-rgb: 236, 224, 200;
  --accent: #e6c886;
  --accent-rgb: 230, 200, 134;
  --on-accent: #1a1408;
  --accent2: #f3ead6; /* logo runs champagne → platinum */
}

/* Founder-pillen ved navnet (vennelista/topplista, 16/9): champagne på
   mørkt, liten og tett — et merke, ikke et banner. */
.pill-founder {
  display: inline-block; margin-left: 6px; padding: 1px 7px;
  border-radius: 999px; font-size: 10px; font-weight: 800; letter-spacing: .02em;
  color: #e6c886; background: rgba(230, 200, 134, 0.16);
  border: 1px solid rgba(230, 200, 134, 0.35); vertical-align: 1px;
}

/* Lys — Apples light mode. GRATIS (tilgjengelighet, Brage 1/9): for de som
   ikke liker mørk modus — ikke et Pro-skin. Her snus HELE polariteten, så
   blokka overstyrer MER enn Pro-temaene: bakgrunn, tekst, plate — OG
   --muted-rgb (hårstrekene --line må bli MØRKE på lyst; med den lyse
   tripletten var de hvite-på-hvitt), --rim (de hvite alfa-kantene som
   forsvinner på hvitt) og --glass-edge (den mørke er bygget for mørkt glass:
   spekulær hvit topp + mørk bunn ser feil ut på lys plate). Kartet bytter
   til en LYS basisstil i app.js (pickStyle, ved last) — toning gjør ikke et
   mørkt kart lyst. Statusfargene beholder betydningen, justert for kontrast
   på hvitt (Apples light-verdier). */
:root[data-theme="lys"] {
  --bg: #f2f2f7;
  --bg-rgb: 242, 242, 247;
  --glass: rgba(255, 255, 255, 0.72);
  --glass-strong: rgba(255, 255, 255, 0.92);
  --plate: #ffffff;
  --plate-2: #f2f2f7;
  --fg: #1c1c1e;
  --muted: #6c6c70;
  --muted-rgb: 60, 60, 67;
  --line: rgba(60, 60, 67, 0.18);
  --rim: rgba(0, 0, 0, 0.10);
  --accent: #0a84ff;
  --accent-rgb: 10, 132, 255;
  --accent2: #32ade6;
  --good: #34c759;
  --warn: #ff9500;
  --bad: #ff3b30;
  --glass-edge:
    inset 0 1.5px 0 rgba(255, 255, 255, .70),
    inset 1px 0 0 rgba(0, 0, 0, .04),
    inset -1px 0 0 rgba(0, 0, 0, .04),
    inset 0 -1.5px 1px rgba(0, 0, 0, .08),
    inset 0 0 26px rgba(0, 0, 0, .015);
}
/* De to flatene som bar en HARDKODET mørk marineblå gradient (ikke token):
   dokken og foto-plassholderen. På lyst ble de mørke klatter. */
:root[data-theme="lys"] nav.tabs {
  background: linear-gradient(180deg, rgba(255, 255, 255, .78), rgba(242, 242, 247, .86));
}
:root[data-theme="lys"] .pop-photo.placeholder {
  background: linear-gradient(155deg, rgba(226, 232, 244, .9), rgba(206, 214, 230, .95));
}


/* A slow specular highlight that drifts across the glass — the "living glass"
   motion, distinct from the tap ripple. Applied to floating chrome via ::before. */
@keyframes glass-sheen {
  0%, 100% { background-position: 130% 0; }
  50%      { background-position: -30% 0; }
}
.glass-sheen::before {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  border-radius: inherit; z-index: 0; mix-blend-mode: screen;
  background: linear-gradient(115deg,
    transparent 22%, rgba(255, 255, 255, .09) 42%, rgba(255, 255, 255, .17) 50%,
    rgba(255, 255, 255, .09) 58%, transparent 78%);
  background-size: 260% 100%;
  animation: glass-sheen 7.5s ease-in-out infinite;
}
/* A specular highlight that slowly ORBITS the glass rim — the signature
   "living glass" edge, light travelling around the bezel. Masked to a hairline
   ring so only the border lights up. */
@property --rim-a { syntax: "<angle>"; initial-value: 0deg; inherits: false; }
@keyframes rim-orbit { to { --rim-a: 360deg; } }
/* Guarded: without mask-composite the ring can't be cut out, so skip the rim
   entirely rather than washing the panel with a conic fill. */
@supports ((-webkit-mask-composite: xor) or (mask-composite: exclude)) {
  .glass-sheen::after {
    content: ""; position: absolute; inset: 0; pointer-events: none;
    border-radius: inherit; z-index: 2; padding: 1.5px;
    background: conic-gradient(from var(--rim-a),
      transparent 0%, rgba(255, 255, 255, .55) 10%, transparent 26%,
      transparent 54%, rgba(150, 190, 255, .45) 68%, transparent 86%, transparent 100%);
    -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
    -webkit-mask-composite: xor; mask-composite: exclude;
    animation: rim-orbit 7s linear infinite;
  }
}
@media (prefers-reduced-motion: reduce) {
  .glass-sheen::before, .glass-sheen::after { animation: none; }
}

* { box-sizing: border-box; -webkit-tap-highlight-color: transparent; }
html, body { height: 100%; }
body {
  margin: 0;
  font: 14px/1.45 -apple-system, BlinkMacSystemFont, "SF Pro Text", "Segoe UI", Inter, Roboto, sans-serif;
  background: var(--bg);
  color: var(--fg);
  overflow: hidden;
  overscroll-behavior: none;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

/* Type scale — the whole UI hangs on these six steps.
   Numbers are the heroes (big + heavy + tight); labels step far down
   (small + wide caps + muted) so hierarchy reads at a glance. */
.t-display { font-size: 46px; font-weight: 800; letter-spacing: -.03em; line-height: 1; font-variant-numeric: tabular-nums; }
.t-big     { font-size: var(--fs-hero); font-weight: 800; letter-spacing: -.02em; line-height: 1.1; font-variant-numeric: tabular-nums; }
.t-label   { font-size: var(--fs-micro); font-weight: 650; letter-spacing: var(--track-kicker); text-transform: uppercase; color: var(--muted); }

#map { position: fixed; inset: 0; background: var(--bg); }
#map canvas { outline: none; }

.hidden { display: none !important; }
.muted { color: var(--muted); }

/* ---------- header ---------- */
header.appbar {
  position: fixed; top: 0; left: 0; right: 0; z-index: 30;
  padding: calc(10px + var(--sat)) 16px 10px;
  display: flex; align-items: center; gap: 10px;
  background: linear-gradient(to bottom, rgba(var(--bg-rgb),.85), rgba(var(--bg-rgb),0));
  pointer-events: none;
}
header.appbar > * { pointer-events: auto; }
.logo {
  font-weight: 800; font-size: var(--fs-title); letter-spacing: 1.5px;
  background: linear-gradient(120deg, var(--accent), var(--accent2), var(--accent));
  background-size: 220% 100%;
  -webkit-background-clip: text; background-clip: text; color: transparent;
  display: flex; align-items: center; gap: 7px;
  animation: logo-flow 1.8s ease-out 1;
}
@keyframes logo-flow { 0%, 100% { background-position: 0% 0; } 50% { background-position: 100% 0; } }
/* The wordmark's glyph is the sprite plane — sized in em so the login card's
   bigger logo scales it along. Explicit colour: the wordmark's own text
   colour is transparent (gradient clip), which a stroke must not inherit. */
.logo .glyph { display: flex; color: var(--accent); }
.logo .glyph svg { width: 1.05em; height: 1.05em; }
/* Connection state is a quiet dot, not a counter — the flight/radar counts
   it used to print were internals (board-row totals) that read as noise. */
#connState {
  width: 8px; height: 8px; border-radius: 50%; flex: none;
  background: var(--muted); opacity: .5;
}
#connState.live {
  background: var(--good); opacity: 1;
  animation: live-pulse 2.4s ease-in-out infinite;
}
@keyframes live-pulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(74, 222, 128, .0); }
  50%      { box-shadow: 0 0 0 4px rgba(74, 222, 128, .12), 0 0 12px rgba(74, 222, 128, .18); }
}
@media (prefers-reduced-motion: reduce) {
  .logo, #connState.live { animation: none; }
}
.spacer { flex: 1; }
.chip {
  font: inherit; font-size: var(--fs-caption); font-weight: 700; padding: 3px 10px;
  border-radius: 999px; border: 1px solid var(--rim); color: var(--muted);
  background: var(--glass); backdrop-filter: var(--glass-blur); -webkit-backdrop-filter: var(--glass-blur);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .28), 0 4px 14px rgba(0, 0, 0, .28);
  cursor: pointer; transition: all .15s;
}
.chip svg { width: 15px; height: 15px; display: block; margin: 2px 0; }
.chip.active { color: var(--accent); border-color: rgba(var(--accent-rgb),.45); }
/* The pill is 24 px tall because that is the size it should LOOK; a thumb
   needs 44. An invisible strip centred on it takes the taps without moving
   a pixel of the design. Vertical only, so neighbours are never covered. */
.chip { position: relative; }
.chip::after {
  content: ""; position: absolute; left: 0; right: 0; top: 50%;
  height: 44px; transform: translateY(-50%);
}

/* ---------- panel / sheet ---------- */
.sheet {
  position: fixed; z-index: 20; left: 0; right: 0; bottom: 0;
  height: 46vh; display: flex; flex-direction: column;
  background: var(--glass);
  backdrop-filter: var(--glass-blur-strong);
  -webkit-backdrop-filter: var(--glass-blur-strong);
  border-top: 1px solid var(--rim);
  border-radius: var(--r-lg) var(--r-lg) 0 0;
  transition: height .28s cubic-bezier(.4, 0, .2, 1);
  box-shadow: 0 -20px 60px rgba(0, 0, 0, .5), var(--glass-edge);
}
/* A crisp specular arc along the sheet's rounded top lip — light pooling on
   the leading glass edge. Kept to the very top so it never washes out the
   dense content below. */
.sheet::before {
  content: ""; position: absolute; left: 0; right: 0; top: 0; height: 46px;
  border-radius: var(--r-lg) var(--r-lg) 0 0; pointer-events: none;
  background: linear-gradient(180deg, rgba(255, 255, 255, .12), rgba(255, 255, 255, 0));
}
/* three-mode switch where the drag handle used to live */
.sheet-modes { display: flex; gap: 8px; justify-content: center; margin: 7px auto 4px; flex: none; }
.sheet-modes button {
  position: relative;
  display: flex; align-items: flex-end; justify-content: center;
  width: 44px; height: 26px; padding: 0 0 5px;
  background: rgba(var(--muted-rgb),.10); border: 1px solid var(--line);
  border-radius: 999px; cursor: pointer; color: rgba(var(--muted-rgb),.55);
}
/* Same invisible thumb-sized strip as the header chips (see .chip::after). */
.sheet-modes button::after {
  content: ""; position: absolute; left: 0; right: 0; top: 50%;
  height: 44px; transform: translateY(-50%);
}
.sheet-modes button i { display: block; width: 16px; background: currentColor; border-radius: 2px; }
.sheet-modes button:nth-child(1) i { height: 3px; }
.sheet-modes button:nth-child(2) i { height: 8px; }
.sheet-modes button:nth-child(3) i { height: 13px; }
.sheet-modes button.active {
  color: var(--accent); background: rgba(var(--accent-rgb),.16); border-color: rgba(var(--accent-rgb),.45);
}
/* Selected-plane info: its own glass block floating ABOVE the sheet, with a
   gap between them, equal insets left and right (its bottom is anchored to
   the sheet's current top by JS). */
.plane-panel.squeezed { opacity: 0; pointer-events: none; }
.plane-panel {
  /* 16px side inset — the same rail as the dock and the sheet's content, so
     the floating chrome and the cards below sit on ONE line. */
  position: fixed; z-index: 21; left: 16px; right: 16px;
  display: flex; align-items: center; gap: 9px;
  padding: 8px 30px 8px 12px;
  /* Panelet GLIR med rullegardinens snap (samme kurve som sheeten);
     under selve draget nulles transition inline saa det foelger haanden. */
  transition: bottom .28s cubic-bezier(.4, 0, .2, 1), opacity .2s ease;
  background: var(--glass-strong);
  backdrop-filter: var(--glass-blur-strong);
  -webkit-backdrop-filter: var(--glass-blur-strong);
  border: 1px solid var(--rim); border-radius: var(--r-lg);
  overflow: hidden;
  box-shadow: 0 16px 40px rgba(0, 0, 0, .48), var(--glass-edge);
  animation: panel-in .26s cubic-bezier(.34, 1.4, .5, 1);
  /* Same curve/duration as the sheet's height transition, so the panel rides
     up and down attached to the sheet's top when you switch min/medium/full. */
  transition: bottom .28s cubic-bezier(.4, 0, .2, 1), opacity .2s ease;
}
@keyframes panel-in { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }
/* The panel's close is the same .icon-x component as every other close —
   this class only pins it to the corner. */
.icon-x.plane-panel-x { position: absolute; top: 7px; right: 7px; margin: 0; }
/* Content rides above the drifting sheen (::before, z:0). */
.plane-panel-body, .plane-panel-x, .plane-spinner, #planePanelPhoto { position: relative; z-index: 1; }
.plane-panel-body { flex: 1; min-width: 0; }
/* fr24-style aircraft photo: thumbnail on the left, photographer credit in the
   corner (planespotters requires attribution). Its own element next to the
   text so live route/ETA updates never wipe it. */
.pop-photo {
  flex: none; width: 116px; height: 74px; border-radius: var(--r-sm); overflow: hidden;
  display: block; text-decoration: none;
  box-shadow: 0 3px 12px rgba(0, 0, 0, .4), inset 0 0 0 1px rgba(255, 255, 255, .12);
  animation: photo-in .3s ease both;
}
.pop-photo img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* Fallback when the aircraft has no photo: a muted type silhouette so the box
   stays consistent whether or not planespotters has an image. */
.pop-photo.placeholder {
  display: flex; align-items: center; justify-content: center;
  background: linear-gradient(155deg, rgba(40, 54, 82, .55), rgba(18, 26, 42, .65));
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .08);
}
.pop-photo.placeholder svg { width: 48px; height: 48px; fill: rgba(var(--muted-rgb),.42); margin-bottom: 6px; }
.pop-photo.placeholder .ph-type {
  position: absolute; left: 0; right: 0; bottom: 5px; text-align: center;
  font-size: var(--fs-micro); font-weight: 800; letter-spacing: var(--track-caps); text-transform: uppercase;
  color: rgba(var(--muted-rgb),.72);
}
.pop-photo .pop-cred {
  position: absolute; left: 0; right: 0; bottom: 0; padding: 1px 5px;
  font-size: var(--fs-micro); line-height: 1.5; letter-spacing: .02em; text-align: right;
  color: rgba(255, 255, 255, .9); background: linear-gradient(to top, rgba(0, 0, 0, .62), transparent);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
@keyframes photo-in { from { opacity: 0; transform: scale(.9); } }
/* Water ripple on press — the glass behaves like liquid where you touch it.
   (Positioning is set per-element in JS so it never clobbers an absolutely
   positioned control like the panel's close ✕.) */
.ripple {
  position: absolute; border-radius: 50%; pointer-events: none;
  background: radial-gradient(circle,
    rgba(160, 200, 255, .5) 0%, rgba(160, 200, 255, .22) 38%, rgba(160, 200, 255, 0) 68%);
  transform: scale(0); opacity: .9; mix-blend-mode: screen;
  animation: ripple .62s cubic-bezier(.22, .7, .3, 1) forwards;
}
@keyframes ripple {
  0% { transform: scale(0); opacity: .9; }
  55% { opacity: .55; }
  100% { transform: scale(1); opacity: 0; }
}

/* Lasteindikatoren ER ✕-knappens egen ramme. Brage 7/8: «om rammen rundt
   kryss-knappen kunne vært loading-spinneren, og ikke en egen spinner?
   Det ser mye renere ut.» Han har rett — to runde ting side om side i et
   hjørne som allerede er trangt er én for mye, og den ekstra sirkelen
   betydde ikke noe utover «vent». Nå snurrer rammen som allerede er der:
   én ring, to tilstander.

   `border-top-color` alene ville forsvunnet i den grå rammen, så den
   løftes til aksenten og resten dempes — ellers leser den som et hjul med
   fire like eiker, som ikke ser ut til å snurre i det hele tatt. */
.icon-x.is-loading {
  border-color: rgba(var(--muted-rgb), .22);
  border-top-color: var(--accent);
  border-width: 2px;
  animation: plane-spin .7s linear infinite;
}
/* ✕-tegnet ville snurret med ringen. Det skjules mens den laster — knappen
   er fortsatt der og fortsatt trykkbar (44px-flaten er uendret).
   `color: transparent`, ikke `> * { visibility:hidden }`: ✕ er en TEKST-
   node i knappen, ikke et element, så barneselektoren traff den aldri
   (målt). Fargen treffer den. */
.icon-x.is-loading { color: transparent; }
.icon-x.is-loading:active { transform: scale(.9); }
/* Den frittstående spinneren er borte fra panelet; regelen står igjen for
   andre flater som fortsatt bruker den. */
.plane-spinner {
  position: absolute; right: 34px; top: 9px; width: 15px; height: 15px;
  border: 2px solid rgba(var(--muted-rgb),.28); border-top-color: var(--accent);
  border-radius: 50%; animation: plane-spin .7s linear infinite;
}
@keyframes plane-spin { to { transform: rotate(360deg); } }

/* 16px side padding IS the sheet's rail: search-wrap, section titles, card
   edges, board rows and empty states all align on it (children carry no
   horizontal margins of their own). */
.sheet-content { flex: 1; overflow-y: auto; padding: 4px 16px calc(92px + var(--sab)); -webkit-overflow-scrolling: touch; scrollbar-width: none;
  /* C2: soft exit — content dissolves at the bottom edge instead of being
     guillotined by the dock/tab-bar overlap. */
  -webkit-mask-image: linear-gradient(180deg, #000 0, #000 calc(100% - 26px), transparent);
  mask-image: linear-gradient(180deg, #000 0, #000 calc(100% - 26px), transparent);
}
/* C4: empty-state art — one 40px currentColor glyph at 30 %, never a color. */
.empty-art { width: 40px; height: 40px; opacity: .3; display: block; margin: 0 auto 12px; }
/* C3: the follow-chip and a toast both live at the top edge — stack, don't
   overprint. Sibling order in index.html: followChip before toast. */
#followChip:not(.hidden) ~ #toast { top: calc(114px + var(--sat)); }
.sheet-content::-webkit-scrollbar { display: none; }

@media (min-width: 900px) {
  .sheet {
    left: auto; right: 16px; top: calc(74px + var(--sat)); bottom: 16px;
    width: 430px; height: auto !important; border-radius: var(--r-lg);
    border: 1px solid var(--line);
  }
  .sheet-modes { display: none; }
  .sheet-content { padding-bottom: 76px; }
}

/* ---------- tab bar: floating dock ---------- */
/* Liquid-glass capsule dock: translucent enough that sheet content visibly
   slides behind it, heavy blur+saturation, specular top edge. */
nav.tabs {
  /* `10px + --sab` stacked our own margin on top of the whole safe area —
     44 px of dead space under the dock on any home-indicator phone, which is
     what made it read as floating high up the screen.
     Padding stays EVEN: buying clearance with extra bottom padding left the
     labels riding high in the capsule with a dead band of glass beneath
     them, which looks exactly as wrong as it sounds. The clearance comes
     from where the capsule SITS instead. What must be avoided is the home
     indicator's own strip (~20 px), not the full 34 px inset — the inset is
     a margin hint, and treating it as forbidden space is what pushed the
     dock up the screen in the first place. */
  /* Gulvet er 14, ikke 12 (målt 12/9): knappene sitter 7 px inne i
     kapselen, så et 12 px gulv ga dem bare 19 px over hjem-indikatorens
     egen 20 px-stripe på Pixel 7 (sone 24) og iPad mini (sone 20) —
     layoutcheck var rød på HEAD. Garantien hører til KNAPPENE, ikke
     glasset: 14 + 7 = 21. iPhone (sone 34) styres fortsatt av sonen. */
  position: absolute; bottom: max(14px, calc(var(--sab) - 12px));
  left: 16px; right: 16px; z-index: 25;
  display: flex; gap: 4px; padding: 7px;
  background: linear-gradient(180deg, rgba(var(--muted-rgb),.16), rgba(30, 42, 66, .26) 40%, rgba(12, 18, 30, .34));
  border: 1px solid var(--rim);
  border-radius: 999px;
  backdrop-filter: var(--glass-blur-strong);
  -webkit-backdrop-filter: var(--glass-blur-strong);
  box-shadow: 0 18px 46px rgba(0, 0, 0, .55), var(--glass-edge);
}
nav.tabs button {
  position: relative; z-index: 1;
  flex: 1; border: 0; background: transparent; color: var(--muted);
  font: inherit; font-size: var(--fs-caption); font-weight: 700; cursor: pointer;
  display: flex; flex-direction: column; align-items: center; gap: 2px;
  padding: 7px 0 6px; border-radius: 999px; transition: all .18s;
  /* The tap ripple uses mix-blend-mode inside a backdrop-filter parent — a
     combination WebKit composites OUTSIDE the overflow clip, so droplets
     leaked past the capsule edge. isolation pins the blend to the button
     and clip-path clips in the compositor where overflow:hidden can't. */
  isolation: isolate;
  clip-path: inset(0 round 999px);
}
/* Stroke glyphs inherit currentColor: muted at rest, accent on the active
   tab — the only colour a resting dock carries. */
nav.tabs button .ico { width: 22px; height: 22px; display: block; }
nav.tabs button.active .ico { color: var(--accent); }
nav.tabs button.active {
  color: var(--fg);
  background: rgba(255, 255, 255, .10);
  box-shadow: inset 0 0 0 1px var(--rim),
              inset 0 1px 0 rgba(255, 255, 255, .20);
}

/* ---------- native-app embed (?embed=app) ---------- */
/* The iOS shell brings its own Liquid Glass tab bar — ONE dock on screen. */
html.embed nav.tabs { display: none; }
/* The three mode buttons give way to the draggable grabber (rullegardin). */
html.embed .sheet-modes { display: none; }
.sheet-grabber {
  flex: 0 0 auto; height: 26px; position: relative; cursor: grab;
  /* The drag owns vertical gestures on this strip — without this iOS
     scrolls the page instead of delivering pointermove. */
  touch-action: none;
}
.sheet-grabber::after {
  content: ""; position: absolute; left: 50%; top: 9px;
  width: 44px; height: 5px; margin-left: -22px;
  border-radius: 999px; background: rgba(var(--muted-rgb), .38);
}
/* At minimum the sheet reads as a docked search bar: the teaser is the
   visible «search lives here»-affordance. Hidden from half height up — the
   real search field takes over there. */
.sheet-search-teaser { display: none; }
html.embed .sheet.min .sheet-search-teaser {
  /* gap 8, ikke 11: målt 3 px tekst-drift mot den ekte radens input. */
  display: flex; align-items: center; gap: 8px;
  margin: 4px 16px 0; padding: 0 18px; height: 50px; flex: 0 0 auto;
  border-radius: 999px;
  /* Facelift 6/8: the whole search row wears the date-chip's dark INSET
     glass — a light white pill next to a dark chip read as two different
     materials («mer dark mode»). */
  background: rgba(0, 0, 0, .22);
  border: 1px solid var(--rim);
  box-shadow: inset 0 1.5px 3px rgba(0, 0, 0, .30);
  color: var(--muted); font-size: var(--fs-lead); font-weight: 650;
  cursor: pointer;
}
.sheet-search-teaser .ico { width: 20px; height: 20px; flex: 0 0 auto; }
/* The REAL search field wears the same clothes in-app as the teaser pill —
   otherwise the drag from minimum reads as swapping between two different
   search bars instead of one continuous element. */
/* Strimlen og den EKTE søkeraden må stå på nøyaktig samme sted, ellers
   hopper baren i det du rører gardinen: `pointerdown` fjerner `.min`, og
   da byttes `.sheet-search-teaser` (margin-top 4px) mot `.search-wrap`
   (margin-top 12px). Åtte piksler — «marginalt ned», Brage 7/8. Begge er
   50px høye i embed, så det var kun toppmargen som skilte dem — og margen
   skal være NULL, ikke 4px: `.sheet-content` har allerede 4px topp-padding
   som strimlen (et direkte barn av arket) ikke får. Målt til 0,0 px hopp. */
html.embed .search-wrap { margin-top: 0; margin-bottom: 0; }

html.embed .search-box {
  border-radius: 999px;
  background: rgba(0, 0, 0, .22);
  border-color: var(--rim);
  box-shadow: inset 0 1.5px 3px rgba(0, 0, 0, .30);
  min-height: 50px; padding: 0 18px;
}
html.embed .search-box .search-ico svg { width: 20px; height: 20px; }
html.embed .search-box input { font-size: var(--fs-lead); }
/* Teksten er den SAMME i min (teaser-span) og halv/fokus (placeholder) —
   tegn for tegn OG klær for klær. Målt 10/8 19:31 (Brage: «marginalt
   forskjellig … det liker jeg ikke»): placeholderen arvet globalens
   rgba(--muted-rgb,.78) på vekt 400 mot teaserens solide --muted på 650,
   og lupen lå på fg×.55 mot teaserens muted×1. Chip og geometri var alt
   identiske (1.95.2). Samme klær, én kilde: */
html.embed .search-box input::placeholder {
  color: var(--muted); opacity: 1; font-weight: 650;
}
html.embed .search-box .search-ico { opacity: 1; color: var(--muted); }
html.embed .date-chip { border-radius: 999px; }
/* In-app the NATIVE profile owns sign-out and delete — the native session
   (URLSession cookies + APNs device token) must be cleared with it, and the
   web buttons would only kill the webview's copy and desync the two. */
html.embed .logout-btn { display: none; }
/* The board STAYS in the app's map sheet: «Mine flyvninger» is the sheet's
   default content, and its Kart action is the radar join (locate my plane).
   Hiding all of #boardDefault (1.31.1) left an empty void and read as data
   loss. Only the stats line goes: it exists to open the Pass WEB tab via
   the nav — which is hidden in embed, so the click dead-ends inside the
   sheet. In-app the native Fly tab's stats strip is that doorway. */
html.embed #myStats { display: none; }
/* Themes are web-only skins; the native tabs can't follow them (yet). An
   in-app switch would leave a half-aurora, half-navy app — hide the picker
   until FxColor is theme-aware. The boot also ignores any stored choice in
   embed (app.js). */
html.embed #themeSection { display: none; }
/* Varsler er WEB PUSH — mekanismen for nettleseren og PWA-en på
   hjemskjermen. Inne i appen finnes ikke PushManager i WKWebView i det
   hele tatt, så raden kunne aldri bli noe annet enn «Ikke støttet her»,
   og hjelpeteksten ba deg legge appen på hjemskjermen mens du STO i
   appen (Brage 7/8, IMG_7222: «Den der varsel greia er jo feil? Det er
   fra det var en webapp?»). Han har rett: i appen går varsler over APNs,
   som den native siden eier — PushManager + PermissionNag. Seksjonen blir
   stående for ekte webbrukere, der den er den ENESTE veien til varsler. */
html.embed #pushSection { display: none; }
/* Native eier varselvalgene og slettingen inne i appen — webben viste et
   annet sett brytere med et tredje Pro-kort, og to «Slett kontoen min» (16/9). */
html.embed #notifyPrefsSection, html.embed .delete-btn { display: none; }
/* …men adminflaten skal fungere i appen: den pinnede profilen har en egen
   inngang, og fanen selv må kunne vises når den åpnes derfra. */
html.embed-pin #tab-admin:not(.hidden) { display: block; }
/* …men er ADMIN selv den pinnede fanen, eier fanelinja navigasjonen og
   «‹ Profil» ville sendt deg til en flate som ikke er der. */
html[data-pin="admin"] .nav-back-row { display: none; }

/* iOS-vane: tilbake er en pil med navnet på stedet du kom fra, oppe til
   venstre — ikke en knapp i knappefarge. Den skal lese som navigasjon. */
.nav-back-row { padding: 2px 0 6px; }
.nav-back {
  display: inline-flex; align-items: center; gap: 3px;
  background: none; border: 0; padding: 6px 6px 6px 0;
  font: inherit; font-size: 16px; font-weight: 600;
  color: var(--accent); cursor: pointer; margin-left: -4px;
}
.nav-back svg { width: 18px; height: 18px; }
.nav-back:active { opacity: .55; }
/* Pinned tab (native Venner/Pass): no appbar, no sheet modes — the sheet IS
   the whole view, near full height under the status bar. */
html.embed-pin .appbar { display: none; }
html.embed-pin .sheet-modes { display: none; }
html.embed-pin .sheet {
  top: calc(8px + var(--sat));
  height: auto !important;
  border-radius: var(--r-lg) var(--r-lg) 0 0;
}
/* En innstillingsflate har ikke et kart bak seg. Brage 7/8: «Jeg liker det
   svarte … det ser ut som del av 2 ulike apper.» Den blåaktige tonen i
   Venner/Pass/Profil var IKKE en farge — det var basiskartet som skinte
   gjennom det gjennomskinnelige arket. I en pinnet fane er arket hele
   flaten, så glasset blir ugjennomsiktig svart og kartet slås av: samme
   svart som den native detaljflaten, og én GPU-tegnet kartflate mindre å
   holde i live på en fane som aldri viser den. */
html.embed-pin .sheet {
  background: var(--bg);
  backdrop-filter: none; -webkit-backdrop-filter: none;
  box-shadow: none;
}
html.embed-pin .sheet::before { display: none; }
html.embed-pin #map { display: none; }

/* ---------- cards ---------- */
/* RESTING surface: cards sit IN the sheet's glass, not on it — flat fill,
   one hairline, no blur, no outer shadow. Only floating chrome gets glass. */
.card {
  /* Plate, ikke glass-med-ramme. Rammen var web-vanen som skilte
     webflatene fra de native (Brage IMG_7219: «ser ikke ut som samme
     app») — iOS definerer en gruppe med FLATE, ikke med kontur. */
  background: var(--plate);
  border: 0;
  border-radius: var(--r-md);
  padding: 14px 16px;
  margin: 10px 0;
  animation: rise .25s ease both;
}
@keyframes rise { from { opacity: 0; transform: translateY(8px); } }
.card .row1 { display: flex; align-items: center; gap: 9px; }
.card .fno { font-size: var(--fs-lead); font-weight: 700; letter-spacing: -.01em; cursor: pointer; font-variant-numeric: tabular-nums; }
.card .route {
  color: var(--muted); font-weight: 650; font-size: var(--fs-caption);
  letter-spacing: var(--track-caps); text-transform: uppercase;
}
.card .row2 { display: flex; align-items: center; gap: 8px; margin-top: 10px; flex-wrap: wrap; }
.card .times { font-variant-numeric: tabular-nums; font-weight: 800; font-size: var(--fs-big); letter-spacing: -.02em; }
.card .strike { text-decoration: line-through; color: var(--muted); font-weight: 400; font-size: var(--fs-body); margin-right: 6px; letter-spacing: 0; }

/* One card per tracked flight (0.28.0): identity, headline route, live rows,
   actions. The old layout wrapped a card inside a card and printed the flight
   number and route twice — two boxes of the same thing is not information. */
.fcard { padding: 16px 16px 12px; }
.fcard .fc-head { display: flex; align-items: center; gap: 8px; }
.fcard .fno { font-size: var(--fs-lead); font-weight: 700; }
.fc-sub {
  color: var(--muted); font-size: var(--fs-caption); font-weight: 650;
  letter-spacing: var(--track-caps); text-transform: uppercase; white-space: nowrap;
}
/* THE close component — every ✕ in the app (card, plane-panel, modal, live
   view) is this one control; siblings only position it. */
.icon-x {
  position: relative;
  /* 28, ikke 27 (Brage 17/9: «krysset og plussen er ikke helt sentrert»):
     et oddetall legger sentrum på en halv piksel, og ringen (1 px kant) og
     glyfen snapper hver sin vei. Målt ved 3x: ringen sto 1,8/2,5 device-px
     opp-venstre for glyfen. Partall + eget lag (will-change) gjør at både
     ring og glyf tegnes på hele device-piksler uansett hvor panelet står. */
  width: 28px; height: 28px; flex: none; margin-left: 4px; padding: 0;
  border-radius: 999px; border: 1px solid var(--line);
  background: rgba(var(--muted-rgb), .06); color: var(--muted);
  font: inherit; font-size: var(--fs-caption); line-height: 1; display: grid; place-items: center;
  cursor: pointer; will-change: transform;
  transition: transform .12s ease, color .12s ease, border-color .12s ease;
}
.icon-x svg { width: 14px; height: 14px; display: block; }
.icon-x:hover { color: var(--bad); border-color: rgba(248, 113, 113, .45); }
.icon-x.is-loading:hover { color: transparent; border-top-color: var(--accent); }
.icon-x:active { transform: scale(.9); }
/* Finger-sized (44px) invisible strip centred on the 27px control. */
.icon-x::after {
  content: ""; position: absolute; left: 50%; top: 50%;
  width: 44px; height: 44px; transform: translate(-50%, -50%);
}
.icon-x.modal-x { float: right; }
.icon-x.live-x { position: absolute; right: 0; top: 0; margin: 0; }
/* One hero per card: the time pair. The route steps down to a subhead. */
.fc-route {
  display: flex; align-items: center; gap: 8px; margin: 12px 0 2px;
  font-size: var(--fs-title); font-weight: 650; letter-spacing: -.025em; line-height: 1.1;
}
.fc-route .arw { color: var(--muted); font-size: var(--fs-lead); font-weight: 650; }
.fcard .times { font-size: var(--fs-hero); font-variant-numeric: tabular-nums; letter-spacing: -.025em; }
/* Ankomsten ved siden av avgangen — dempet, destinasjonens klokke. */
.fcard .fc-arr {
  font-size: var(--fs-lead); font-weight: 700; color: var(--muted);
  font-variant-numeric: tabular-nums; margin-left: 8px; align-self: baseline;
}
.fcard .fc-line { align-items: baseline; }
.fc-line { display: flex; align-items: baseline; gap: 8px; margin-top: 3px; }
/* "Flyet ditt" — where the airframe operating this departure is right now.
   Grayscale on purpose: it's information, not a call to action. */
.fc-line.rot {
  align-items: center; gap: 8px; margin-top: 8px; padding: 6px 9px;
  border: 1px solid var(--line); border-radius: var(--r-sm);
  font-size: var(--fs-body); color: var(--muted);
}
.fc-line.rot.tappable { cursor: pointer; }
.fc-line.rot.tappable:active { transform: scale(.985); }
.fc-line.rot .rot-ico { font-size: var(--fs-body); opacity: .8; }
.fc-line.rot .rot-txt { flex: 1; min-width: 0; }
/* The one blue in the row: "Se på kart ›" is the tap affordance, the rest is data. */
.fc-line.rot .rot-go { font-weight: 700; font-size: var(--fs-caption); white-space: nowrap; color: var(--accent); }
/* Badge under the plane panel: this aircraft flies YOUR flight next. */
.rot-note {
  margin-top: 6px; padding-top: 5px; border-top: 1px solid var(--line);
  font-size: var(--fs-caption); color: var(--muted);
}
.fc-chips { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin-top: 8px; }
.fc-chips:empty { display: none; }
/* ONE chip: every pill-shaped token shares this geometry; the variants below
   change colour only. Uppercase + tracking is reserved for the status pill. */
.pill, .boardchip, .chipbtn, .delaychip, .pp-chip {
  display: inline-flex; align-items: center; height: 24px; padding: 0 10px;
  border-radius: 999px; font-size: var(--fs-caption); font-weight: 700; white-space: nowrap;
  border: 1px solid var(--line); background: rgba(var(--muted-rgb), .05); color: var(--muted);
}
.chipbtn { transition: transform .12s ease; cursor: pointer; }
.chipbtn:active { transform: scale(.94); }
/* The aircraft type opens the cabin layout — hint it without shouting. */
.cabin-link {
  color: var(--fg); border-bottom: 1px dotted rgba(var(--muted-rgb),.55);
  cursor: pointer; padding-bottom: 1px;
}
.cabin-link:active { opacity: .6; }
.fc-actions {
  display: flex; gap: 8px; margin-top: 10px; padding-top: 10px;
  border-top: 1px solid var(--line);
}
.fc-act {
  flex: 1; min-height: 38px; border-radius: var(--r-sm);
  border: 1px solid var(--line); background: rgba(var(--muted-rgb), .06);
  color: var(--fg); font-size: var(--fs-body); font-weight: 700; letter-spacing: .05em;
  display: flex; align-items: center; justify-content: center; gap: 7px;
  transition: transform .12s ease, background .18s ease;
}
.fc-act:active { transform: scale(.97); }
.fc-act.live {
  color: var(--accent); border-color: rgba(var(--accent-rgb),.4);
  background: rgba(var(--accent-rgb),.10);
}
.fc-act .dot {
  width: 6px; height: 6px; border-radius: 50%; background: var(--accent);
  animation: fc-dot 2.4s ease-in-out infinite;
}
@keyframes fc-dot {
  0%, 100% { box-shadow: 0 0 0 2px rgba(var(--accent-rgb),.10); }
  50%      { box-shadow: 0 0 0 5px rgba(var(--accent-rgb),.20), 0 0 10px rgba(var(--accent-rgb),.35); }
}
@media (prefers-reduced-motion: reduce) { .fc-act .dot { animation: none; } }
.fcard .journey:not(:empty) { margin-top: 12px; }
/* The meta line is ONE sentence, not flex items — as a flex container every
   text fragment around a <b> became its own item and inherited the 14px gap,
   which is why "Gate  E28  · Term  A" read so airy. */
.fcard .meta { display: block; margin-top: 8px; line-height: 1.5; }
.fcard .meta b { color: var(--fg); font-weight: 700; margin-left: 2px; }
.pill {
  font-size: var(--fs-micro); font-weight: 800;
  letter-spacing: var(--track-caps); text-transform: uppercase;
}
.pill.s-expected, .pill.s-boarding, .pill.s-gate_closing, .pill.s-go_to_gate, .pill.s-gate_closed { color: var(--warn); border-color: rgba(251,191,36,.30); background: none; }
.pill.s-cancelled, .pill.s-diverted { color: var(--bad); border-color: rgba(248,113,113,.32); background: none; }
.pill.s-landed, .pill.s-departed, .pill.s-en_route, .pill.s-baggage, .pill.s-baggage_delivered { color: var(--good); border-color: rgba(74,222,128,.30); background: none; }
.pill.track { color: var(--accent); border-color: rgba(var(--accent-rgb),.4); background: rgba(var(--accent-rgb),.08); }
.pill.ghost { opacity: .6; }
.delaychip {
  color: var(--warn); font-weight: 800; font-variant-numeric: tabular-nums;
  border-color: rgba(251, 191, 36, .35); background: rgba(251, 191, 36, .08);
}
/* Grayscale base: a countdown is data, not an affordance. Colour arrives
   only with meaning (.late/.off/.good). */
.countdown { font-size: var(--fs-body); font-weight: 800; color: var(--fg);
  white-space: nowrap; font-variant-numeric: tabular-nums; }
.countdown.late { color: var(--warn); }
.countdown.off { color: var(--bad); }
.countdown.good { color: var(--good); }
.lv-good { color: var(--good); font-weight: 700; }
.lv-late { color: var(--warn); font-weight: 700; }

/* history + stats */
.section-title.collapsible { cursor: pointer; user-select: none; }
.section-title .chev { opacity: .6; }
.past-card { padding: 10px 14px; opacity: .8; }
.fno-plain { font-weight: 800; font-size: var(--fs-lead); }
.times.muted, .muted { color: var(--muted); }
.btn.ghosted { opacity: .55; padding: 2px 8px; }
/* One-line muted teaser under "Mine flyvninger" — taps through to Pass. */
.stats-line {
  margin: 0 0 10px; font-size: var(--fs-caption); font-weight: 650; color: var(--muted);
  cursor: pointer; font-variant-numeric: tabular-nums;
}
.lb-row { display: flex; align-items: center; gap: 10px; padding: 8px 0; border-bottom: 1px solid var(--line); }
.lb-row:last-child { border-bottom: 0; }
.lb-rank { width: 26px; text-align: center; font-weight: 800; color: var(--muted); }
/* "Me" is emphasis, not interaction — weight + a whisper of surface, no blue. */
.lb-row.me { background: rgba(var(--muted-rgb), .07); }
.lb-row.me .lb-rank, .lb-row.me .lb-name { color: var(--fg); font-weight: 800; }
.lb-name { font-weight: 700; flex: 1; }
.lb-count { font-weight: 800; }
.lb-sub { font-size: var(--fs-caption); color: var(--muted); }
.hist-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
.hist-grid input { width: 100%; }

/* passport */
.pp-head { display: flex; align-items: center; justify-content: space-between; margin: 20px 0 10px; }
.pp-head /* Fanens NAVN. I appen er hver webfane pinnet som sin egen skjerm, og en
   skjerm apner med stor tittel — det er vanen de native fanene (Fly,
   Venner) alltid har hatt. Brage 7/8: «ha harmoni i appen. Nå er det jo
   ulikt ulike steder.» Utenfor den pinnede fanen finnes docken, som
   allerede sier hvor du er, og tittelen blir en vanlig seksjon. */
/* …men IKKE i appen: der ligger hver pinnet fane under en ekte native
   navigasjonslinje som allerede tegner tittelen (`.navigationBarTitle-
   DisplayMode(.large)`). To titler oppa hverandre er ikke harmoni. La
   systemet eie den — da kollapser den ved scroll slik iOS gjor, og en
   web-etterligning kan aldri det. */
html.embed-pin .tab-title { display: none; }

.section-title { margin: 0; }
.pp-years { display: flex; gap: 6px; }
.pp-chip { background: rgba(var(--muted-rgb),.10); cursor: pointer; }
.pp-chip.active { color: var(--accent); background: rgba(var(--accent-rgb),.16); border-color: rgba(var(--accent-rgb),.45); }
.pp-card { border-radius: var(--r-md); padding: 18px 16px; margin-bottom: 10px; }
/* Helten og forsinkelseskortet er farga PLATER: teksten er hvit i ALLE
   temaer. Målt 5/9: i Lys arvet tallene --fg (#1c1c1e) og sto svarte på
   mørkeblått — uleselig. Etikettene er hvit-alfa, aldri --muted. */
.pp-hero, .pp-delay { color: #fff; }
.pp-hero .pp-lab, .pp-delay .pp-lab { color: rgba(255, 255, 255, .72); }
.pp-hero .pp-kicker, .pp-delay .pp-kicker { opacity: .78; }
.pp-kicker { font-size: var(--fs-micro); font-weight: 700; letter-spacing: var(--track-kicker); text-transform: uppercase; opacity: .65; margin-bottom: 14px; }
.pp-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 18px 12px; }
.pp-num { font-size: 36px; font-weight: 800; letter-spacing: -.03em; line-height: 1; font-variant-numeric: tabular-nums; }
.pp-num.xl { font-size: 58px; }
.pp-unit { font-size: var(--fs-title); font-weight: 700; opacity: .75; letter-spacing: 0; }
.pp-lab { font-size: var(--fs-micro); color: var(--muted); margin-top: 5px; text-transform: uppercase; letter-spacing: var(--track-caps); font-weight: 650; }
.pp-sub { font-size: var(--fs-body); margin-top: 8px; opacity: .8; }
/* Empty passport: the SAME hero, waiting to be filled. Dimmed rather than
   absent, so a new user sees the shape of what they are collecting instead
   of one grey sentence in an empty pane. */
.pp-blank { filter: saturate(.55); }
.pp-blank .pp-num { opacity: .38; }
.pp-blank .pp-lab { opacity: .5; }
.pp-onboard { padding: 4px 2px 0; }
.ppo-title { font-size: var(--fs-lead); font-weight: 800; margin: 16px 0 12px; }
.ppo-steps { list-style: none; display: flex; flex-direction: column; gap: 11px; margin: 0 0 16px; padding: 0; }
.ppo-steps li { display: flex; align-items: flex-start; gap: 11px; font-size: var(--fs-body); line-height: 1.45; color: var(--muted); }
/* --text has never existed; the palette token is --fg. An invalid var() on an
   inherited property falls back to inherit, so these <b>s picked up --muted from
   the parent li — bleaching exactly the two words that point a first-time user at
   the "Fly" tab and the "+" button. */
.ppo-steps b { color: var(--fg); font-weight: 700; }
/* Tabular step number: a filled accent disc, same 22 px rhythm as the rows. */
.ppo-n {
  flex: none; width: 22px; height: 22px; border-radius: 999px;
  display: grid; place-items: center; margin-top: 1px;
  background: rgba(var(--accent-rgb),.16); color: var(--accent);
  border: 1px solid rgba(var(--accent-rgb),.42);
  font-size: var(--fs-caption); font-weight: 800; font-variant-numeric: tabular-nums;
}
.pp-onboard .btn { width: 100%; }
.ppo-note { font-size: var(--fs-caption); color: var(--muted); margin-top: 12px; line-height: 1.45; }
.pp-lab.dark, .pp-sub.dark { color: #37456b; opacity: 1; }
.pp-light .pp-topname { color: #101a35; }
.pp-topline { display: flex; align-items: center; gap: 10px; margin-top: 8px; }
.pp-topname { font-size: var(--fs-big); font-weight: 800; }
.pp-topcount { margin-left: auto; font-weight: 800; color: #37456b; }
.pp-row { display: flex; align-items: center; gap: 10px; padding: 9px 0; border-bottom: 1px solid var(--line); font-size: var(--fs-lead); }
.pp-row:last-child { border-bottom: 0; }
.pp-fno { font-weight: 800; min-width: 62px; }
.pp-route { color: var(--muted); flex: 1; }
.pp-date { color: var(--muted); font-size: var(--fs-body); }
.al-badge {
  position: relative; overflow: hidden;
  display: inline-flex; align-items: center; justify-content: center;
  width: 30px; height: 30px; border-radius: 50%; flex: none;
  font-size: var(--fs-caption); font-weight: 800; border: 1.5px solid; letter-spacing: .02em;
}
/* Real logo over the lettered fallback. Brand tiles come edge-to-edge, so
   cover + inherit the badge's radius; a hairline ring keeps a white tile from
   glaring against the dark card. */
.al-logo {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: contain; border-radius: inherit; padding: 3px;
  /* Every mark sits on a light tile: brand tiles cover it, and logos that
     ship transparent (dark ink meant for a white page) stay legible instead
     of disappearing into the card. */
  background: #f2f6fb;
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .10);
  animation: logo-in .22s ease both;
}
@keyframes logo-in { from { opacity: 0; } }
@media (prefers-reduced-motion: reduce) { .al-logo { animation: none; } }

/* live "you are here" dot */
.me-dot {
  width: 14px; height: 14px; border-radius: 50%;
  background: var(--accent); border: 2.5px solid #fff;
  box-shadow: 0 0 0 0 rgba(var(--accent-rgb),.55);
  animation: me-pulse 2.4s ease-out infinite;
}
@keyframes me-pulse {
  0% { box-shadow: 0 0 0 0 rgba(var(--accent-rgb),.55); }
  70% { box-shadow: 0 0 0 16px rgba(var(--accent-rgb),0); }
  100% { box-shadow: 0 0 0 0 rgba(var(--accent-rgb),0); }
}
/* Neutral by default: only a real call to action (go to gate / boarding)
   earns colour. The security-queue and info chips are grey. */
.boardchip { background: none; }
.boardchip.go { background: rgba(74,222,128,.10); color: var(--good); border-color: rgba(74,222,128,.38); }
.boardchip.warn { background: none; color: var(--warn); border-color: rgba(251,191,36,.34); }

.meta { display: flex; gap: 14px; margin-top: 9px; font-size: var(--fs-caption); color: var(--muted); flex-wrap: wrap; font-weight: 650; }
.meta b { color: var(--fg); font-weight: 700; font-variant-numeric: tabular-nums; }

/* Brage 7/8 (IMG_7219): den native detaljflaten «ser veldig iphone aktig
   ut», webflatene «ser ikke ut som samme app». Fasiten er Apples inset-
   grouped liste — og der ROPER ikke gruppeoverskriftene. De er rolige,
   grå og i vanlig setningsform («Avgang BGO · avinor»), ikke sperret
   versal. Teksten i markupen er allerede setningsform; det var kun
   text-transform som skrek. */
.section-title {
  font-size: 15px; font-weight: 600; letter-spacing: 0;
  color: var(--muted); margin: 22px 0 7px;
}
/* «Avansert» (Task 7): en disclosure i kicker-drakt — summary BÆRER
   .section-title (én regel, ett hjem), nettleserens trekant byttes med
   husets chevron. Lukket i appen, åpen i nettleseren (app.js). */
details.adv > summary { list-style: none; cursor: pointer; user-select: none; display: flex; align-items: center; gap: 6px; }
details.adv > summary::-webkit-details-marker { display: none; }
details.adv > summary::after { content: ""; width: 7px; height: 7px; border-right: 1.8px solid currentColor; border-bottom: 1.8px solid currentColor; transform: rotate(-45deg); transition: transform .18s; opacity: .7; }
details.adv[open] > summary::after { transform: rotate(45deg); }
/* Section title → first card is ALWAYS 6px (kill the card's own 10px top
   margin so block-margin collapse can't stretch the gap). #myFlights is
   listed separately: the hidden stats teaser sits between it and the title,
   and a display:none sibling still defeats the adjacent-sibling selector. */
.section-title + .card, .section-title + div > .card:first-child,
#myFlights > .card:first-child { margin-top: 0; }
.empty { text-align: center; color: var(--muted); padding: 26px 10px; font-size: var(--fs-body); }
/* Et tomt rom som står FOR en liste skal lese som listas eneste rad —
   samme plate og samme radius som radene den erstatter. Venner-fanen
   viste hvorfor: «Toppliste» lå på plate (den er et .card), mens
   «Venner» og «Venners flyvninger» hang som løs tekst i svart. Tre
   seksjoner, tre ulike svar på samme tilstand.
   Ligger den alt INNE i et kort, arver den kortets flate — da ingen ny. */
:not(.card) > .empty:not(.tall) {
  background: var(--plate); border-radius: var(--r-md); margin: 10px 0;
}
/* Empty states that own a whole view get room to breathe.
   MÅLT 21/8: `min-height: 42vh` sentrerte teksten i en boks som var
   HØYERE enn plassen som faktisk var synlig — på 932 px lå den 7 px inn
   under den flytende docken, på 700 px hele 75 px. Et tomt rom som
   klipper sin egen forklaring er verre enn ingen forklaring. Blokka er
   nå toppforankret med luft rundt: samme ro på høye skjermer, lesbar på
   lave. */
.empty.tall { padding: 42px 10px 48px; display: grid; place-items: center; }
/* Lave skjermer har ikke luften å gi bort — MÅLT: 42 px topp-padding la
   teksten 14 px inn under docken på en 700 px høy flate. */
@media (max-height: 780px) { .empty.tall { padding: 20px 10px 26px; } }

/* ---------- inputs & buttons ---------- */
/* INSET wells: fields are sunk INTO the surface — darker fill + a top inset
   shadow, never a raised or glassed box. */
input, select {
  /* Et felt inne i en gruppe stepper OPP (--plate-2), ikke ned i en mørk
     brønn. Den innfelte skyggen var en gravert-i-metall-effekt fra da
     bakgrunnen var lys nok til å kaste den; på ren svart lager den bare
     et hull. Apple bruker ett hakk lysere fyll og ingen skygge. */
  background: var(--plate-2); border: 1px solid transparent; color: var(--fg);
  border-radius: var(--r-md); padding: 11px 13px; font: inherit; width: 100%;
  outline: none; transition: border-color .15s, box-shadow .15s;
}
/* Fokus er en mykt lysende ring, ikke bare en streksfarge — feltet du
   skriver i skal FØLES aktivt (design-uplift 5/9). */
input:focus { border-color: var(--accent); box-shadow: 0 0 0 3px rgba(var(--accent-rgb), .18); }
/* A well inside a resting card steps the radius down one notch. */
.card input, .card select { border-radius: var(--r-sm); }
input::placeholder { color: rgba(var(--muted-rgb),.78); }
/* The default .btn is the view's ONE true submit — green, nothing else.
   Everything that merely navigates or assists is .secondary glass. */
.btn {
  /* Husregel A2: ÉN ekte CTA per flate, og den er grønn. Alt annet er
     stille glass — før 1.57.0 var HVER knapp grønn (Lagre, «Ikke støttet
     her», feeder-nøkkel …), og da betyr fargen ingenting. */
  border: 1px solid var(--line); border-radius: var(--r-md);
  padding: 11px 16px; font: inherit; font-weight: 700;
  cursor: pointer; color: var(--fg);
  background: rgba(var(--muted-rgb), .09);
  transition: transform .12s, opacity .15s, background .15s;
}
.btn:active { transform: scale(.97); }
/* CTA-en bærer AKSENTEN, ikke grønt. Brage 7/8: «de grønne knappene …
   matcher ikke tema». Han hadde rett på et dypere plan enn fargesmak:
   grønn betyr «i rute» overalt ellers i appen (status, kort, brett). Når
   den SAMME grønnfargen også betyr «trykk her», slutter den å bety noe
   av delene — og på innloggingsskjermen sto en knallgrønn knapp under en
   blå logo. Aksenten følger dessuten temaet, så CTA-en blir riktig i
   Nordlys og Midnattssol også; det gjorde aldri grønn. */
.btn.cta { background: var(--accent); color: var(--on-accent); border-color: transparent; }
.btn[disabled], .btn.is-off {
  opacity: .5; cursor: default; background: rgba(var(--muted-rgb), .06);
}
.btn.secondary { background: rgba(var(--muted-rgb),.14); color: var(--fg); border: 1px solid var(--line); }
.btn.danger { background: rgba(248,113,113,.15); color: var(--bad); border: 1px solid rgba(248,113,113,.35); }
.btn.small { padding: 7px 14px; font-size: var(--fs-body); }
/* Rhythm values live here, not as inline styles in the markup. */
.card > .btn { margin-top: 10px; }
#feederSetup .btn { margin-top: 10px; }
.add-hist { margin: 10px 0 2px; }
/* Logg ut: rød tekst på en rolig plate (iOS-vanen); sletting: stille
   tekstlenke under — det irreversible skal ikke være det mest synlige. */
.logout-btn { margin: 16px 0 4px; width: 100%; background: var(--plate); border: 0; color: var(--bad); }
.delete-btn { width: 100%; margin: 0 0 6px; background: none; border: 0; color: var(--bad); opacity: .7; font-weight: 600; font-size: var(--fs-body); }
.delete-btn:active { opacity: 1; }
.lead-input { max-width: 110px; }
.hint.below { margin: 0 0 8px; }
.hint.sep { margin-top: 12px; }
:is(button, a, [role="button"]):focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.inline-form { display: flex; gap: 8px; margin: 10px 0; }
.inline-form input { flex: 1; }
/* ---------- gruppert liste (iOS Settings-vanen) ----------
   Brage 7/8: «liker at det ser litt mer iphone app aktig ut». Et stablet
   web-skjema (etikett OVER felt, ramme rundt hvert felt) leser som en
   nettside. iOS grupperer i stedet: ett kort, én hårstrek mellom radene,
   etikett venstre og verdi høyre — og fotnoten UTENFOR kortet. */
.card.list {
  padding: 0 0 0 16px; overflow: hidden;
  /* Ingen ramme: iOS-gruppa er en plate ett hakk lysere enn bakgrunnen.
     Rammen rundt glass er web-vane og er nettopp det som gjorde at de to
     flatene ikke leste som samme app. */
  border: 0; background: var(--plate);
}
.lrow {
  display: flex; align-items: center; gap: 12px;
  min-height: 46px; padding: 8px 16px 8px 0; width: 100%;
  /* border: 0 FØRST — <button>-radene arver ellers UA-rammen sin, som
     tegner en loddrett strek i venstrekanten av gruppa. */
  border: 0; border-top: 1px solid var(--line);
  background: none; font: inherit; color: var(--fg); text-align: left;
}
.lrow:first-child { border-top: 0; }
.lrow.head { padding-top: 14px; padding-bottom: 14px; }
.lrow-l { flex: 0 0 auto; font-weight: 400; color: var(--muted); }
/* Verdien er høyrestilt og dempet til du redigerer den — samme signal som
   iOS: teksten til høyre er DIN, etiketten til venstre er appens. */
.lrow-v {
  flex: 1 1 auto; min-width: 0; text-align: right;
  background: none; border: 0; padding: 0; font: inherit;
  color: var(--fg); font-weight: 700; border-radius: 0;
}
.lrow-v:focus { outline: 0; }
.lrow-v::placeholder { color: var(--muted); font-weight: 400; }
.lrow-x { margin-left: auto; color: var(--muted); font-variant-numeric: tabular-nums; }
/* Hårstreken starter der teksten starter (venstre-innrykk), som i iOS. */
.card.list .lrow + .lrow, .card.list .feeder-row + .feeder-row { border-top-color: var(--line); }
.lrow.nav, .lrow.act { cursor: pointer; }
/* Grå er for ETIKETTEN i en verdirad. En navigasjonsrad har ingen verdi
   til venstre — den har en TITTEL, og den er hvit (iOS Settings). Grå
   tittel leser som deaktivert. */
.lrow.nav .lrow-l { color: var(--fg); }
.lrow.nav:active, .lrow.act:active { background: rgba(var(--muted-rgb), .08); }
.lrow.act { color: var(--accent); font-weight: 400; }
.lrow.act .lr-ico { width: 20px; height: 20px; flex: 0 0 auto; }
.chev { width: 17px; height: 17px; color: var(--muted); opacity: .7; flex: 0 0 auto; }
/* Avskrudd er en TILSTAND, ikke en handling — den mister aksentfargen. */
.lrow.act[disabled] { color: var(--muted); cursor: default; }
.lrow.act[disabled]:active { background: none; }
/* Rader som JS fyller inn (mottakere, oppsett) arver samme geometri. */
.card.list .feeder-row { margin: 0; padding: 10px 16px 10px 0; border-top: 1px solid var(--line); }
.card.list .feeder-row:first-child { border-top: 0; }
.card.list #feederSetup:not(.hidden) { padding: 12px 16px 12px 0; border-top: 1px solid var(--line); }
/* Tom statusboks er ikke en rad: uten dette tegner knappen en løs strek
   i toppen av gruppa når ingen mottaker finnes. */
.card.list #feederStatus:empty + .lrow { border-top: 0; }
.lrow.nav .lrow-x + .chev { margin-left: 6px; }
/* Fotnoten hører til GRUPPA, ikke til en rad — derfor utenfor kortet. */
.card-note {
  font-size: var(--fs-caption); color: var(--muted);
  line-height: 1.45; margin: -2px 4px 14px; padding: 0 12px;
}

.field { margin: 12px 0; }
.field label { display: block; font-size: var(--fs-caption); font-weight: 700; color: var(--muted); margin: 0 2px 5px; }
.hint { font-size: var(--fs-caption); color: var(--muted); margin-top: 5px; line-height: 1.5; }

/* ---------- login ---------- */
#loginView {
  position: fixed; inset: 0; z-index: 40; display: flex; align-items: center; justify-content: center;
  /* Ingen farget gløde i hjørnet. Et blått radial-skjær bak et mørkt kort
     er selve standardlooken Brage kalte «generisk ai kode» — og på ren
     svart leser det som en flekk, ikke som atmosfære. Apple lar svart
     være svart og lar innholdet bære skjermen. */
  background: var(--bg);
  padding: 20px;
}
.login-card {
  width: 100%; max-width: 380px; padding: 30px 26px;
  /* Samme plate som alle andre grupper — ikke glass med kontur. Det er
     ingenting bak den å se gjennom her. */
  background: var(--plate); border: 0; border-radius: var(--r-lg);
}
.login-art { display: block; width: 96px; height: 96px; margin: 0 auto 14px; border-radius: 22px;
  box-shadow: 0 14px 34px rgba(0, 0, 0, .45), inset 0 0 0 1px rgba(255, 255, 255, .06); }
.login-card .logo { font-size: var(--fs-hero); justify-content: center; margin-bottom: 4px; }
.login-card .tag { text-align: center; color: var(--muted); font-size: var(--fs-body); margin-bottom: 20px; text-wrap: balance; }
/* Kortet ANKOMMER (design-uplift 5/9): en rolig rise+fade, ingen glød og
   ingen «generisk» radial bak — svart er svart, bevegelsen bærer det. */
.login-card { animation: login-in .5s var(--ease-out) both; }
@keyframes login-in { from { opacity: 0; transform: translateY(14px) scale(.985); } }
@media (prefers-reduced-motion: reduce) { .login-card { animation: none; } }
.login-card .btn { width: 100%; margin-top: 6px; }
.google-btn {
  width: 100%; margin-top: 10px; display: flex; align-items: center; justify-content: center; gap: 9px;
  background: #fff; color: #1f2937; border-radius: var(--r-md); padding: 11px; font-weight: 700;
  text-decoration: none; font-size: var(--fs-lead);
}
.login-alt { text-align: center; margin-top: 15px; font-size: var(--fs-body); color: var(--muted); }
.login-alt a { color: var(--accent); cursor: pointer; text-decoration: none; font-weight: 700; }
.form-error { color: var(--bad); font-size: var(--fs-body); margin-top: 9px; text-align: center; min-height: 17px; }

/* ---------- friends ---------- */
/* Sections are flex items so the "Finn venner" block can move to the top
   while the user has no friends yet — DOM order untouched. */
#tab-friends { display: flex; flex-direction: column; }
#tab-friends.friendless .fsec-find { order: -1; }
.friend-row { display: flex; align-items: center; gap: 11px; }
.avatar {
  width: 40px; height: 40px; border-radius: 50%; flex: none;
  position: relative;
  display: flex; align-items: center; justify-content: center;
  font-weight: 800; font-size: var(--fs-lead); color: #061224;
  background: var(--accent);
}
.avatar.sm { width: 30px; height: 30px; font-size: var(--fs-body); }

/* ---------- prestige frames (game badge art) + level ----------
   The frame is EARNED (airlines flown — the 18-step ladder in
   avatarRing(), mirrored in native FxPrestige). PNG art from
   scripts/gen_prestige.py; geometry contract: avatar disc = 54% of the
   frame, number plate baked at (0.5, 0.815) of it. */
.avatar .av-frame {
  position: absolute; left: 50%; top: 50%;
  width: 185.2%; height: 185.2%;
  transform: translate(-50%, -50%);
  max-width: none; pointer-events: none; z-index: 1;
}
.av-lv {
  position: absolute; right: -6px; bottom: -4px; z-index: 2;
  min-width: 17px; height: 17px; padding: 0 4px; border-radius: 999px;
  display: flex; align-items: center; justify-content: center;
  font-size: 10px; font-weight: 800; font-variant-numeric: tabular-nums;
  color: var(--fg); background: var(--bg);
  border: 1px solid rgba(var(--muted-rgb), .35);
}
.avatar.sm .av-lv { right: -7px; bottom: -5px; }
/* On a framed avatar the number sits ON the baked plate: plate centre is
   (0.815-0.5)·frame = 58.3% of the avatar below its centre. */
.avatar.framed .av-lv {
  right: auto; bottom: auto; left: 50%; top: 108.3%;
  transform: translate(-50%, -50%);
  background: transparent; border: 0; padding: 0; min-width: 0; height: auto;
  font-size: 11px; line-height: 1;
}
.avatar.sm.framed .av-lv { font-size: 8.5px; }
/* Frames overhang the row — give them air instead of clipping. */
.friend-row .avatar.framed, .lb-row .avatar.framed { margin: 8px 6px; }

.friend-row .who { flex: 1; min-width: 0; }
.friend-row .who .dn { font-weight: 700; }
.friend-row .who .un { font-size: var(--fs-caption); color: var(--muted); }

/* Follow: the ✕'s corner-sibling — same .icon-x chrome, opposite corner.
   Green is the meaning (THE CTA on this surface); followed = quiet check. */
.icon-x.pp-follow {
  position: absolute; right: 6px; bottom: 6px; margin: 0; z-index: 1;
  width: 26px; height: 26px;
  color: var(--good); border-color: rgba(74, 222, 128, .45);
  font-size: 15px; font-weight: 800; line-height: 0;
}
.icon-x.pp-follow svg { width: 12px; height: 12px; display: block; }
.icon-x.pp-follow:hover { color: var(--good); border-color: var(--good); }
.icon-x.pp-follow.on {
  background: rgba(74, 222, 128, .14); color: var(--good);
  border-color: rgba(74, 222, 128, .30); cursor: default;
}
.icon-x.pp-follow:disabled { opacity: .55; cursor: default; }
/* Room so the meta text never runs under the corner button. */
.plane-panel-body { padding-bottom: 2px; }
/* Only when the follow-+ is actually showing does the body reserve the
   corner — an always-on pad wasted a text line for unresolved planes. */
.plane-panel:has(.pp-follow:not(.hidden)) .plane-panel-body { padding-bottom: 20px; }

/* ---------- journey (cross-referenced sources) ---------- */
.journey:not(:empty) { margin-top: 10px; border-top: 1px solid var(--line); padding-top: 8px; }
.jrow { display: flex; gap: 10px; padding: 5px 0; font-size: var(--fs-body); align-items: baseline; }
/* Labels whisper, values speak. */
.jrow .jlab {
  flex: none; width: 96px; font-size: var(--fs-caption); font-weight: 650;
  text-transform: uppercase; letter-spacing: var(--track-kicker); color: var(--muted);
}
.jrow .jlab + span { font-size: var(--fs-lead); font-weight: 700; color: var(--fg); }
.jrow .jsrc { display: block; font-size: var(--fs-micro); font-weight: 650; color: var(--muted); text-transform: uppercase; letter-spacing: var(--track-caps); }
.jcheck { font-size: var(--fs-body); padding: 7px 10px; border-radius: var(--r-sm); margin-top: 6px; }
.jcheck.warn { background: rgba(251,191,36,.1); border: 1px solid rgba(251,191,36,.3); color: var(--warn); }
.jcheck.ok { background: rgba(74,222,128,.08); border: 1px solid rgba(74,222,128,.25); color: var(--good); }
.jcheck.info { background: rgba(var(--muted-rgb),.08); border: 1px solid var(--line); color: var(--muted); }

/* ---------- feed ---------- */
.feed-item { font-size: var(--fs-body); padding: 7px 0; border-bottom: 1px dashed var(--line); color: var(--muted); }
.feed-item b { color: var(--fg); }

/* ---------- seat map modal ---------- */
.overlay {
  position: fixed; inset: 0; z-index: 50; display: none;
  align-items: flex-end; justify-content: center;
  background: rgba(4, 7, 12, .6); backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px);
}
@media (min-width: 700px) { .overlay { align-items: center; } }
.overlay.open { display: flex; }
.modal {
  background: var(--glass-strong); border: 1px solid var(--line);
  border-radius: var(--r-lg) var(--r-lg) 0 0; width: 100%; max-width: 560px;
  max-height: 88vh; overflow-y: auto; padding: 18px 18px calc(18px + var(--sab));
  backdrop-filter: blur(24px); -webkit-backdrop-filter: blur(24px);
  animation: slideup .28s cubic-bezier(.4,0,.2,1) both;
}
@media (min-width: 700px) { .modal { border-radius: var(--r-lg); } }
@keyframes slideup { from { transform: translateY(40px); opacity: 0; } }
.modal h2 { margin: 0 0 2px; font-size: var(--fs-title); }
.modal .sub { color: var(--muted); font-size: var(--fs-body); margin-bottom: 10px; }
.modal .approx { color: var(--warn); font-size: var(--fs-caption); }
.seat-input { display: flex; gap: 8px; margin: 10px 0; }
.seat-input input { width: 90px; flex: none; text-transform: uppercase; }
.cabin-section { margin: 12px 0; }
.cabin-label { font-size: var(--fs-caption); text-transform: uppercase; letter-spacing: var(--track-caps); color: var(--muted); margin-bottom: 5px; font-weight: 800; }
.seat-row { display: flex; align-items: center; gap: 4px; margin: 2.5px 0; }
.seat-row .rownum { width: 24px; text-align: right; color: var(--muted); font-size: var(--fs-caption); flex: none; }
.seat {
  width: 24px; height: 24px; border-radius: 6px 6px 4px 4px; border: 1px solid var(--line);
  display: flex; align-items: center; justify-content: center; font-size: var(--fs-micro); font-weight: 700;
  color: var(--muted); background: var(--plate-2); cursor: pointer; transition: transform .1s;
}
.seat:active { transform: scale(.9); }
.seat.aisle-gap { background: transparent; border: 0; cursor: default; }
.seat.business, .legend .k-business { background: rgba(251, 191, 36, .18); border-color: rgba(251, 191, 36, .45); }
.seat.premium, .legend .k-premium { background: rgba(var(--accent-rgb), .16); border-color: rgba(var(--accent-rgb), .45); }
.legend .k-exit { background: var(--plate-2); box-shadow: inset 0 0 0 1.5px var(--good); }
.legend .k-mine { background: var(--accent); }
.seat.exit { box-shadow: inset 0 0 0 1.5px var(--good); }
.seat.mine { background: var(--accent); color: #061224; border-color: transparent; }
.legend { display: flex; gap: 13px; flex-wrap: wrap; font-size: var(--fs-caption); color: var(--muted); margin-top: 10px; }
.legend span { display: inline-flex; align-items: center; gap: 5px; }
.legend i { width: 13px; height: 13px; border-radius: 4px; display: inline-block; }

/* ---------- map markers ---------- */
/* Sprite plane (points north; JS rotates it to the true track). */
.plane-marker { width: 26px; height: 26px; color: var(--accent); cursor: pointer;
  filter: drop-shadow(0 0 6px rgba(var(--accent-rgb),.9)); will-change: transform; }
.plane-marker svg { width: 100%; height: 100%; display: block; }
/* Muted "last seen here"-marker for a plane that is no longer transmitting. */
.plane-marker { width: 26px; height: 26px; color: var(--accent);
  filter: drop-shadow(0 1px 3px rgba(0,0,0,.6)); }
.plane-marker svg { width: 100%; height: 100%; display: block; }
.lastseen-dot { width: 22px; height: 22px; color: var(--muted); opacity: .85; }
.lastseen-dot svg { width: 100%; height: 100%; display: block; }
.maplibregl-ctrl-attrib { background: rgba(var(--bg-rgb),.55) !important; }
/* Sammenslått er attribusjonen en BRIKKE som resten av kartchromen —
   ikke MapLibres hvite skive med svart ⓘ, som var det klareste elementet
   på hele kartet. Åpen står innholdet som før. */
.maplibregl-ctrl-attrib.maplibregl-compact:not(.maplibregl-compact-show) {
  background: rgba(var(--bg-rgb), .55) !important;
  border-radius: 999px; backdrop-filter: blur(12px) saturate(1.4);
  -webkit-backdrop-filter: blur(12px) saturate(1.4);
  box-shadow: inset 0 0 0 1px var(--line);
}
.maplibregl-ctrl-attrib-button {
  background-color: transparent !important;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%238e8e93' stroke-width='2' stroke-linecap='round'%3E%3Ccircle cx='12' cy='12' r='9'/%3E%3Cpath d='M12 11v5'/%3E%3Cpath d='M12 7.6v.1'/%3E%3C/svg%3E") !important;
  background-size: 15px 15px !important;
  background-position: center !important;
  background-repeat: no-repeat !important;
  opacity: .85;
}
/* MapLibre farger bare LENKENE; ren tekst arver bibliotekets svarte —
   «Data from» sto usynlig i svart på svart når panelet åpnes. */
.maplibregl-ctrl-attrib,
.maplibregl-ctrl-attrib-inner { color: var(--muted) !important; }
.maplibregl-ctrl-attrib a { color: var(--muted) !important; }
.maplibregl-ctrl-attrib-button:focus-visible {
  outline: 2px solid rgba(var(--accent-rgb), .6); outline-offset: 1px;
}
/* OSM attribution must stay readable — lift it clear of the floating dock. */
/* The sheet has THREE snap heights and covers the whole bottom — no bottom
   placement survives them all (the ⓘ peeked half-hidden from behind the
   sheet corner). Park the attribution top-right, under the header chips. */
.maplibregl-ctrl-bottom-left, .maplibregl-ctrl-bottom-right {
  top: calc(var(--sat) + 54px); bottom: auto;
}
.maplibregl-ctrl-bottom-right { right: 6px; }

/* ---------- live flight view ---------- */
#liveView {
  position: fixed; inset: 0; z-index: 45; display: flex; flex-direction: column;
  padding: calc(20px + var(--sat)) 22px calc(24px + var(--sab));
  background: radial-gradient(130% 80% at 50% -10%, rgba(var(--accent-rgb),.14), transparent 62%),
              rgba(var(--bg-rgb),.93);
  backdrop-filter: blur(20px); -webkit-backdrop-filter: blur(20px);
  animation: livein .3s cubic-bezier(.4,0,.2,1) both;
}
@keyframes livein { from { opacity: 0; transform: scale(1.04); } }
.live-top { text-align: center; position: relative; }
.live-fno {
  font-size: 36px; font-weight: 800; letter-spacing: -.03em; margin-top: 16px;
  color: var(--fg); font-variant-numeric: tabular-nums;
}
.live-route { color: var(--muted); font-weight: 650; font-size: var(--fs-lead); margin-top: 3px; letter-spacing: .01em; }
.live-status { margin-top: 10px; }
.live-status .pill { font-size: var(--fs-body); height: 28px; padding: 0 14px; }
.live-top .map-btn { margin-top: 12px; }

/* follow-cam chip — floats over the map while the camera rides a flight */
#followChip {
  position: fixed; top: calc(66px + var(--sat)); left: 50%; transform: translateX(-50%);
  z-index: 55; background: var(--glass-strong); border: 1px solid rgba(var(--accent-rgb),.45);
  color: var(--accent); padding: 8px 16px; border-radius: 999px;
  font-size: var(--fs-body); font-weight: 800; letter-spacing: .2px;
  display: inline-flex; align-items: center; gap: 7px;
  backdrop-filter: blur(18px); -webkit-backdrop-filter: blur(18px);
  box-shadow: 0 4px 18px rgba(0,0,0,.35); cursor: pointer;
}
#followChip svg { width: 15px; height: 15px; flex: none; }
.live-count { text-align: center; margin: auto 0; }
.live-count-label { color: var(--muted); font-size: var(--fs-caption); font-weight: 650; text-transform: uppercase; letter-spacing: var(--track-kicker); }
.live-count-num {
  font-size: 72px; font-weight: 800; font-variant-numeric: tabular-nums;
  letter-spacing: -.03em; margin: 8px 0 4px; line-height: 1;
  text-shadow: 0 0 40px rgba(var(--accent-rgb),.26);
}
/* A recorded landing time is a fact, not a live countdown — no hero size. */
.live-count-num.t-big { font-size: var(--fs-hero); text-shadow: none; }
.live-eta { color: var(--muted); font-size: var(--fs-body); font-weight: 650; line-height: 1.6; }
/* Frosne tall skal SI at de er frosne — banneret eies av refreshLive alene
   (tikkeren skriver aldri hit) og forsvinner når det er tomt. */
.live-stale { color: var(--warn, #e6a23c); font-size: var(--fs-caption); font-weight: 650; margin-top: 10px; }
.live-stale:empty { display: none; }
.live-progress { display: flex; align-items: center; gap: 12px; margin: 26px 0 8px; }
.live-ap { font-weight: 800; font-size: var(--fs-lead); flex: none; }
.live-bar { position: relative; flex: 1; height: 5px; border-radius: 999px; background: rgba(var(--muted-rgb),.18); }
.live-bar-fill {
  height: 100%; border-radius: 999px; width: 0%;
  background: var(--accent);
  box-shadow: 0 0 14px rgba(var(--accent-rgb),.7); transition: width 1s linear;
}
/* Sprite plane points north; quarter-turn sends it along the bar. */
.live-bar-plane {
  position: absolute; top: 50%; left: 0%; transform: translate(-50%, -50%) rotate(90deg);
  transition: left 1s linear; filter: drop-shadow(0 0 8px rgba(var(--accent-rgb),.9));
}
.live-bar-plane svg { width: 20px; height: 20px; display: block; }
.live-stats { display: flex; justify-content: center; gap: 26px; margin-top: 18px; flex-wrap: wrap; }
.live-stats .st { text-align: center; }
.live-stats .st .v { font-size: var(--fs-title); font-weight: 800; font-variant-numeric: tabular-nums; }
.live-stats .st .k { font-size: var(--fs-caption); color: var(--muted); text-transform: uppercase; letter-spacing: var(--track-caps); font-weight: 700; }
.live-checks { margin-top: 16px; }
.live-checks .jcheck { text-align: center; }
/* ---- the whole round, for a flight number that flies several hops ---- */
.live-stops { margin-top: 22px; }
.live-stops .lr-h {
  font-size: var(--fs-caption); color: var(--muted); text-transform: uppercase;
  letter-spacing: var(--track-caps); font-weight: 700; margin-bottom: 10px;
}
.live-stops ol { list-style: none; margin: 0; padding: 0; }
.live-stops li {
  position: relative; display: flex; align-items: baseline; gap: 10px;
  padding: 0 0 14px 20px; font-size: var(--fs-lead);
}
.live-stops li:last-child { padding-bottom: 0; }
/* The dot, and the line joining it to the next stop. */
.live-stops li::before {
  content: ""; position: absolute; left: 0; top: 6px;
  width: 9px; height: 9px; border-radius: 50%;
  border: 2px solid var(--muted); background: var(--bg);
}
.live-stops li:not(:last-child)::after {
  content: ""; position: absolute; left: 4px; top: 17px; bottom: 1px;
  width: 1px; background: var(--line);
}
/* Flown already: filled dot, dimmed text. */
.live-stops li.done::before { background: var(--muted); }
.live-stops li.done .lr-ap, .live-stops li.done .lr-t { opacity: .55; }
/* The stop the user boards at — the one fact we actually know about them. */
.live-stops li.mine::before {
  border-color: var(--accent); background: var(--accent);
  box-shadow: 0 0 10px rgba(var(--accent-rgb),.7);
}
.live-stops li.mine .lr-ap { color: var(--accent); }
.live-stops .lr-ap { font-weight: 800; flex: none; }
.live-stops .lr-name { color: var(--muted); font-size: var(--fs-body); flex: 1; min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.live-stops .lr-t { font-variant-numeric: tabular-nums; color: var(--muted);
  font-size: var(--fs-body); flex: none; }
.live-stops .lr-t b { color: var(--fg); font-weight: 700; }
.live-stops .lr-you { font-size: var(--fs-caption); font-weight: 700; color: var(--accent);
  letter-spacing: var(--track-caps); text-transform: uppercase; flex: none; }
.delay-banner {
  margin-top: 10px; text-align: center; padding: 9px 14px; border-radius: var(--r-md);
  background: rgba(251,191,36,.12); border: 1px solid rgba(251,191,36,.35);
  color: var(--warn); font-weight: 800; font-size: var(--fs-lead);
}

.rebook-banner {
  margin-top: 10px; padding: 9px 12px; border-radius: var(--r-md);
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  background: rgba(248,113,113,.10); border: 1px solid rgba(248,113,113,.35);
  color: var(--bad); font-weight: 800; font-size: var(--fs-lead);
}
.rebook-banner .btn { flex: none; }

/* ---------- search / add flight (Flighty-style) ---------- */
.search-wrap { display: flex; gap: 8px; margin: 12px 0 4px; align-items: stretch; }
.search-box {
  flex: 1; display: flex; align-items: center; gap: 8px; min-width: 0;
  background: rgba(0, 0, 0, .18); border: 1px solid var(--line); border-radius: var(--r-md); padding: 0 12px;
  box-shadow: inset 0 1.5px 3px rgba(0, 0, 0, .30);
  transition: border-color .15s;
}
.search-box:focus-within { border-color: var(--accent); }
.search-box .search-ico { opacity: .55; flex: none; display: flex; }
.search-box .search-ico svg { width: 16px; height: 16px; }
.search-box input { border: 0; background: transparent; box-shadow: none; padding: 12px 0; border-radius: 0; text-transform: uppercase; }
.search-box input::placeholder { text-transform: none; }
.search-box input:focus { border: 0; }
.search-clear {
  position: relative; border: 0; background: transparent; color: var(--muted);
  font-size: var(--fs-lead); cursor: pointer; padding: 4px 2px; flex: none;
}
/* Same invisible thumb-strip as the header chips — vertical only, so it
   never covers taps meant for the input beside it. */
.search-clear::after {
  content: ""; position: absolute; left: 0; right: 0; top: 50%;
  height: 44px; transform: translateY(-50%);
}
.date-chip {
  flex: none; border: 1px solid var(--line); background: rgba(0, 0, 0, .18); color: var(--fg);
  border-radius: var(--r-md); padding: 0 14px; font: inherit; font-weight: 700; font-size: var(--fs-body);
  box-shadow: inset 0 1.5px 3px rgba(0, 0, 0, .30);
  cursor: pointer; white-space: nowrap; transition: transform .12s, border-color .15s;
}
.date-chip:active { transform: scale(.96); }
.date-chip.custom { border-color: rgba(var(--accent-rgb),.5); color: var(--accent); }
/* The native date input sits invisibly ON TOP of the chip so a real tap
   lands on it directly and iOS opens the picker natively — showPicker()/
   click() on a 1px hidden input silently failed on iOS. */
.date-wrap { position: relative; display: flex; }
#dateInput {
  /* PARKED at 0×0, never overlaying the chip: iOS composites the date
     input's own white UA chrome above an opacity-0 overlay — that was the
     mystery white «I dag» pill (computed styles said dark all along).
     The chip opens the picker with showPicker() instead. */
  position: absolute; width: 0; height: 0; opacity: 0;
  margin: 0; padding: 0; border: 0; pointer-events: none;
  -webkit-appearance: none; appearance: none;
}

.results-head { display: flex; align-items: baseline; gap: 8px; margin: 12px 0 2px; }
.results-head .rh-route { font-size: var(--fs-lead); font-weight: 800; }
.results-head .rh-date { color: var(--muted); font-size: var(--fs-body); font-weight: 700; }

.fresult {
  display: flex; gap: 13px; padding: 13px 0; border-bottom: 1px solid var(--line);
  cursor: pointer; align-items: center; transition: background .12s; border-radius: var(--r-md);
  touch-action: manipulation;
}
.fresult:active { background: rgba(var(--accent-rgb),.09); }
.fresult .fr-when { flex: none; width: 66px; }
.fresult .fr-when b { display: block; font-size: var(--fs-big); font-weight: 800; line-height: 1.05; letter-spacing: -.5px; font-variant-numeric: tabular-nums; }
.fresult .fr-when span { font-size: var(--fs-micro); color: var(--muted); text-transform: uppercase; letter-spacing: var(--track-caps); font-weight: 700; }
.fresult .fr-main { flex: 1; min-width: 0; }
.fr-top { display: flex; align-items: center; gap: 8px; }
.fr-no { font-size: var(--fs-body); font-weight: 800; letter-spacing: .3px; color: var(--muted); }
.fr-status { margin-left: auto; font-size: var(--fs-caption); font-weight: 700; color: var(--muted); white-space: nowrap; }
.fr-status.ontime { color: var(--good); }
.fr-status.delay { color: var(--warn); }
.fr-status.bad { color: var(--bad); }
.fr-cities { font-size: var(--fs-lead); font-weight: 800; margin: 3px 0 5px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.fr-cities .arrow { color: var(--muted); margin: 0 5px; font-weight: 650; }
/* Route search: the header already names the route, so the flight number +
   airline is the row's primary line and the times step up. */
.fr-flight { font-size: var(--fs-lead); font-weight: 800; letter-spacing: -.01em; }
.fresult.route .fr-times { font-size: var(--fs-lead); margin-top: 4px; }
.fr-times { display: flex; gap: 16px; font-size: var(--fs-body); }
.fr-leg { display: flex; align-items: center; gap: 6px; }
.fr-dot { width: 17px; height: 17px; border-radius: 50%; display: inline-flex; align-items: center; justify-content: center; font-size: var(--fs-micro); font-weight: 800; flex: none; }
/* The ↗/↘ glyphs already encode direction — times are data, not status.
   Green in a row belongs to .fr-status.ontime alone. */
.fr-dot.dep, .fr-dot.arr { background: rgba(var(--muted-rgb),.14); color: var(--muted); }
.fr-leg .fr-code { color: var(--muted); font-weight: 700; }
.fr-leg b { color: var(--fg); font-variant-numeric: tabular-nums; font-weight: 800; }
.fresult.added { opacity: .48; }
/* Finger-sized (44px HIG) tap target; negative margins eat the row padding
   so the visual + stays where it was. */
.fresult .fr-add {
  flex: none; color: var(--accent); font-weight: 800; font-size: var(--fs-big);
  width: 44px; align-self: stretch; margin: -13px -12px -13px -6px;
  display: flex; align-items: center; justify-content: center;
}
.fresult.added .fr-add { color: var(--good); }

.show-gone {
  display: block; width: 100%; margin: 12px 0 4px; padding: 12px;
  background: none; border: 1px dashed var(--line); border-radius: var(--r-md);
  color: var(--muted); font-size: var(--fs-body); font-weight: 700; letter-spacing: .2px;
  cursor: pointer; touch-action: manipulation;
}
.show-gone:active { background: rgba(var(--accent-rgb),.07); }

/* ---- airport search results + board ---- */
.apresult {
  display: flex; align-items: center; gap: 12px; padding: 12px 0;
  border-bottom: 1px solid var(--line); cursor: pointer; border-radius: var(--r-md);
  transition: background .12s; touch-action: manipulation;
}
.apresult:active { background: rgba(var(--accent-rgb),.09); }
.apresult .ap-pin { flex: none; width: 24px; display: flex; justify-content: center; color: var(--muted); }
.apresult .ap-pin svg { width: 18px; height: 18px; }
.apresult .ap-main { flex: 1; min-width: 0; }
.apresult .ap-name { font-size: var(--fs-lead); font-weight: 700; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.apresult .ap-code { font-size: var(--fs-caption); font-weight: 800; color: var(--muted); letter-spacing: .6px; margin-top: 1px; }
.apresult .ap-time { flex: none; font-size: var(--fs-body); font-weight: 700; color: var(--muted); font-variant-numeric: tabular-nums; }

.apboard-head { position: relative; margin: 10px 0 2px; }
/* Back sits on the LEFT — where "back" lives everywhere else on the phone. */
.apboard-back {
  position: absolute; left: 0; top: 0; background: none; border: 0;
  color: var(--accent); font-weight: 700; font-size: var(--fs-body); padding: 2px 2px 2px 0; cursor: pointer;
  touch-action: manipulation;
}
.apb-title { font-size: var(--fs-title); font-weight: 800; letter-spacing: -.3px; padding-left: 58px; }
.apb-title .apb-code { font-size: var(--fs-body); font-weight: 800; color: var(--muted); letter-spacing: .6px; margin-left: 7px; }
.apb-sub { font-size: var(--fs-caption); color: var(--muted); font-weight: 650; margin-top: 2px; }
/* Pulsen («OSL nå: …»): tom slot fra første tegning så linja aldri
   dytter brettet når svaret lander. */
.apb-pulse { font-size: var(--fs-caption); color: var(--muted); margin-top: 3px; min-height: 0; }
.apb-pulse:empty { display: none; }
.apboard-tabs { display: flex; gap: 7px; margin: 11px 0 2px; }
.apboard-tabs button {
  flex: 1; background: rgba(var(--muted-rgb),.06); border: 1px solid var(--line);
  color: var(--muted); border-radius: 999px; padding: 6px 12px; font-weight: 700; font-size: var(--fs-body);
  cursor: pointer; touch-action: manipulation;
}
.apboard-tabs button.active { background: rgba(var(--accent-rgb),.15); color: var(--accent); border-color: rgba(var(--accent-rgb),.5); }
.apbrow .fr-cities { font-size: var(--fs-lead); margin: 2px 0 0; }
.apbrow .fr-cities .fr-code { color: var(--muted); font-weight: 800; font-size: var(--fs-caption); margin-left: 7px; }
.apbrow .fr-when b { font-size: var(--fs-title); font-weight: 800; font-variant-numeric: tabular-nums; }
/* Radar contact, not a bookable flight: the identifier is a broadcast callsign
   that the aircraft re-files on its next rotation, so there is nothing to save.
   Sits where the "+" would be, so the row still lines up. */
.fresult .fr-radar {
  flex: none; align-self: center; font-size: var(--fs-micro); font-weight: 800;
  letter-spacing: var(--track-caps); text-transform: uppercase;
  color: var(--muted); opacity: .7; border: 1px solid var(--line);
  border-radius: 999px; padding: 3px 6px; white-space: nowrap;
}
/* A time borrowed from the OTHER end of the leg, in the OTHER airport's clock.
   It is the only number we have for an outstation we don't poll, so it stays —
   but it must not read as this airport's departure. Muted, lighter, and
   labelled with the direction and airport it actually belongs to. */
.apbrow .fr-when b.borrowed { color: var(--muted); font-weight: 700; }
.apbrow .fr-when .fr-borrowed {
  display: block; font-size: var(--fs-micro); color: var(--muted); font-weight: 700;
  text-transform: uppercase; letter-spacing: var(--track-caps); opacity: .85;
  white-space: nowrap; margin-top: 1px;
}
.apbrow .apb-meta { font-size: var(--fs-caption); color: var(--muted); font-weight: 650; margin-top: 3px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.apbrow .apb-meta .apb-gate { color: var(--fg); font-weight: 800; }
/* Billettnumrene raden slukte. Dempet med vilje: det er en fotnote for
   den som leter etter SITT nummer, ikke informasjon brettet roper. */
.apbrow .apb-meta .apb-cs { opacity: .72; cursor: help;
  border-bottom: 1px dotted currentColor; }

.pp-row .pp-del {
  background: none; border: none; color: var(--muted); opacity: .55;
  font-size: var(--fs-lead); padding: 6px 2px 6px 10px; cursor: pointer; flex: none;
  touch-action: manipulation;
}
.pp-row .pp-del:active { opacity: 1; color: var(--bad); }

.sheet.min .sheet-content { visibility: hidden; }

.countdown .cd-arr { color: var(--muted); font-weight: 700; }

/* The version lives in Profil, not the header — chrome carries no internals. */
.ver-note { margin: 8px 2px 0; text-align: center; font-size: var(--fs-caption); color: var(--muted); }

/* ---------- restyled map popup ---------- */
.maplibregl-popup { max-width: 250px !important; }
.maplibregl-popup-content {
  background: var(--glass-strong) !important; color: var(--fg) !important;
  border: 1px solid var(--line); border-radius: var(--r-md) !important; padding: 11px 14px !important;
  font: inherit; font-size: var(--fs-body); line-height: 1.5;
  backdrop-filter: blur(18px); -webkit-backdrop-filter: blur(18px);
  box-shadow: 0 12px 40px rgba(0, 0, 0, .55) !important;
}
.maplibregl-popup-content b { color: var(--fg); }
.maplibregl-popup-close-button { color: var(--muted) !important; font-size: var(--fs-title) !important; padding: 2px 8px !important; right: 2px !important; }
.maplibregl-popup-anchor-top .maplibregl-popup-tip,
.maplibregl-popup-anchor-top-left .maplibregl-popup-tip,
.maplibregl-popup-anchor-top-right .maplibregl-popup-tip { border-bottom-color: var(--glass-strong) !important; }
.maplibregl-popup-anchor-bottom .maplibregl-popup-tip,
.maplibregl-popup-anchor-bottom-left .maplibregl-popup-tip,
.maplibregl-popup-anchor-bottom-right .maplibregl-popup-tip { border-top-color: var(--glass-strong) !important; }
.maplibregl-popup-anchor-left .maplibregl-popup-tip { border-right-color: var(--glass-strong) !important; }
.maplibregl-popup-anchor-right .maplibregl-popup-tip { border-left-color: var(--glass-strong) !important; }
/* Compact & inline: callsign · route · ETA on one row, meta on the next.
   ÉN hode-klasse: `.pop-top` var tvillingen som manglet ETA-slot, ✕-plass
   og brytning — den er borte (12/9). */
/* Redesignet panelhode (6/8): identitet venstre, ETA som chip HØYRE på
   SAMME linje — aldri en foreldreløs linje to. Rom for ✕ i hjørnet. */
.pop .pop-head {
  display: flex; align-items: baseline; gap: 7px; flex-wrap: nowrap;
  padding-right: 30px; min-width: 0;   /* plass til ✕ i hjørnet */
}
.pop .pop-head .pop-no { font-size: var(--fs-body); font-weight: 800; flex: none; }
.pop .pop-head .pop-route {
  /* Ruta kuttes ALDRI — den er panelets viktigste fakta. Full bredde,
     ingen ellipse; ETA-chipen viker til hoyre. */
  color: var(--fg); font-weight: 700; font-size: var(--fs-caption);
  white-space: nowrap; flex: 0 0 auto;
}
.pop .pop-head .pop-eta {
  flex: none; margin-left: auto;
  font-size: var(--fs-micro); font-weight: 800; font-variant-numeric: tabular-nums;
  color: var(--accent);
  padding: 2px 8px; border-radius: 999px;
  background: rgba(var(--accent-rgb), .12);
}
.pop .pop-head .pop-eta:empty { display: none; }
/* Én dempet identitetslinje: selskap · type · reg. */
.pop .pop-ident {
  color: var(--muted); font-size: var(--fs-micro); margin-top: 1px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
/* Tallene som grid — etikett hvisker, verdi snakker. Tre kolonner. */
.pop .pop-grid {
  /* auto-fit: 2 kolonner paa mobil (smalt ved foto), 4-6 paa brede flater. */
  /* To skarpe kolonner — trenden bor i setningslinja under, ikke i cella
     (den presset gridet til aa stable seg, maalt i 390px). */
  display: grid; grid-template-columns: repeat(auto-fit, minmax(78px, 1fr));
  gap: 3px 10px; margin-top: 4px;
}
.pop .pg { min-width: 0; }
.pop .pg-l {
  display: block; font-size: 9px; font-weight: 650;
  letter-spacing: .1em; text-transform: uppercase;
  color: var(--muted); margin-bottom: 0;
}
.pop .pg-v {
  display: block; font-size: var(--fs-lead); font-weight: 700;
  font-variant-numeric: tabular-nums; line-height: 1.25; white-space: nowrap;
}
.pop .pg-s {
  display: block; font-size: var(--fs-micro); font-weight: 650;
  color: var(--muted); font-variant-numeric: tabular-nums;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.pop .pg-s:empty { display: none; }
.pop .pop-no { font-size: var(--fs-lead); font-weight: 800; }
.pop .pop-route { color: var(--fg); font-weight: 700; }
.pop .pop-eta { color: var(--fg); font-weight: 700; font-size: var(--fs-body); margin-left: auto; }
.pop .pop-meta { color: var(--muted); font-size: var(--fs-caption); margin-top: 4px; }

/* ---------- feeder program ---------- */
.pro-badge { display: inline-block; margin-left: 6px; padding: 1px 7px; border-radius: 999px;
  font-size: var(--fs-micro); font-weight: 800; letter-spacing: var(--track-caps); color: var(--good);
  border: 1px solid rgba(74, 222, 128, .30); background: rgba(74, 222, 128, .08); vertical-align: middle; }
.feeder-row { display: flex; align-items: center; gap: 7px; margin-top: 8px; font-size: var(--fs-body); }
.fx-dot { width: 8px; height: 8px; border-radius: 50%; flex: none; }
.fx-dot.on { background: var(--good); box-shadow: 0 0 8px var(--good); }
.fx-dot.off { background: var(--muted); opacity: .5; }
.feeder-del { margin-left: auto; flex: none; border: none; background: transparent;
  color: var(--muted); font-size: var(--fs-body); line-height: 1; padding: 4px 8px;
  border-radius: var(--r-sm); cursor: pointer; -webkit-tap-highlight-color: transparent; }
.feeder-del:hover { color: var(--fg); background: rgba(var(--muted-rgb), .10); }
.feeder-del.armed { color: var(--bad); background: rgba(248,113,113,.14); font-size: var(--fs-caption); font-weight: 700; }
.feeder-key { font-family: ui-monospace, Menlo, monospace; font-size: var(--fs-body); word-break: break-all;
  background: rgba(0,0,0,.18); box-shadow: inset 0 1.5px 3px rgba(0,0,0,.30);
  border: 1px solid var(--line); border-radius: var(--r-sm); padding: 9px 11px; margin-top: 5px; }
.feeder-cmd { font-family: ui-monospace, Menlo, monospace; font-size: var(--fs-caption); word-break: break-all;
  background: rgba(0,0,0,.18); box-shadow: inset 0 1.5px 3px rgba(0,0,0,.30);
  border: 1px solid var(--line); border-radius: var(--r-sm); padding: 9px 11px; margin-top: 5px; color: var(--fg); }

/* ---------- theme picker (Profil → Tema) ---------- */
/* Each chip is a miniature of its theme, painted by inline --sw-* vars:
   the swatch is the theme's bg, the stripe its accent→accent2 duo. The
   active one wears a ring in the CURRENT theme's accent. */
/* minmax(0,1fr): «Midnattssol» skal ikke få gjøre sin kolonne bredere enn
   de andre (1fr = minmax(auto,1fr) lot min-content vinne, målt 5/9). */
.theme-grid { display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 8px; }
.theme-chip {
  position: relative; border: 0; background: none; padding: 0; margin: 0;
  display: flex; flex-direction: column; align-items: center; gap: 7px;
  font: inherit; color: var(--muted); cursor: pointer;
  transition: transform .12s ease;
}
.theme-chip:active { transform: scale(.95); }
.theme-chip .sw {
  position: relative; width: 100%; aspect-ratio: 5 / 4;
  border-radius: var(--r-sm); border: 1px solid var(--line);
  background: var(--sw-bg); overflow: hidden;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .07);
  transition: box-shadow .15s ease, border-color .15s ease;
}
/* The theme's own accent glow, same corner as the login card's radial. */
.theme-chip .sw::before {
  content: ""; position: absolute; inset: 0;
  background: radial-gradient(130% 110% at 22% -8%, var(--sw-glow), transparent 58%);
}
/* Accent → accent2 duo stripe: the swatch's "logo gradient" signature. */
.theme-chip .sw::after {
  content: ""; position: absolute; left: 9px; right: 9px; bottom: 8px; height: 5px;
  border-radius: 999px; background: linear-gradient(90deg, var(--sw-a), var(--sw-b));
}
.theme-chip .nm { font-size: 10px; font-weight: 700; letter-spacing: 0; white-space: nowrap; }
.theme-chip.active { color: var(--fg); }
.theme-chip.active .sw {
  border-color: transparent;
  box-shadow: 0 0 0 2px var(--bg), 0 0 0 3.5px var(--accent);
}
/* Pro-locked: dimmed swatch + a small lock; the tap toasts instead of applying. */
.theme-chip .lock {
  display: none; position: absolute; top: 6px; right: 6px;
  width: 13px; height: 13px; color: rgba(255, 255, 255, .75);
  filter: drop-shadow(0 1px 2px rgba(0, 0, 0, .6));
}
.theme-chip.locked .sw { opacity: .5; }
.theme-chip.locked .nm { opacity: .55; }
.theme-chip.locked .lock { display: block; }

/* ---------- sheet drag ---------- */
.sheet.dragging { transition: none !important; }

/* toast */
#toast {
  position: fixed; top: calc(66px + var(--sat)); left: 50%; transform: translateX(-50%) translateY(-8px);
  /* Plate-2 + rim + fall-skygge, ikke det svarte glasset: MÅLT 5/9 i riggen
     — glass-strong (12,12,14 @ .94) over svart kart ga luminans 30 mot 24
     ved siden av. En toast som knapt skiller seg fra bakgrunnen leses
     ikke; den skal LØFTE seg fra flaten. */
  z-index: 60; background: var(--plate-2); border: 1px solid var(--rim);
  box-shadow: 0 12px 32px rgba(0, 0, 0, .45), inset 0 1px 0 rgba(255, 255, 255, .10);
  padding: 10px 18px; border-radius: var(--r-md); font-size: var(--fs-body); font-weight: 650;
  opacity: 0; pointer-events: none;
  transition: opacity .2s ease, transform .34s var(--ease-spring);
  backdrop-filter: blur(18px); -webkit-backdrop-filter: blur(18px); max-width: 88vw;
  text-align: center; text-wrap: balance;
}
#toast.show { opacity: 1; transform: translateX(-50%) translateY(0); }
@media (prefers-reduced-motion: reduce) { #toast { transition: opacity .2s ease; } }

/* Broadcast flight data under the panel's meta line: vertical rate, the level
   the autopilot is flying to, Mach, OAT, wind. Dimmer than the meta row — it
   is detail, not identity. */
.pop .pop-live {
  color: var(--muted); font-size: var(--fs-micro); margin-top: 3px; opacity: .85;
  /* Setningen faar bryte til to linjer — den er panelets forklaring. */
  line-height: 1.35;
}
/* 7500/7600/7700. Rare, and the one thing on this panel worth interrupting for. */
.pop .pop-alert {
  margin-top: 5px; padding: 3px 8px; border-radius: 6px; font-size: var(--fs-caption);
  font-weight: 700; color: #fff; background: rgba(225, 29, 72, .92);
  display: inline-block;
}
/* Why the flown line starts out at sea: a statement of fact about coverage,
   not a warning — muted, one line, never competing with the emergency badge. */
.pop .pop-gap { margin-top: 4px; font-size: var(--fs-caption); color: var(--muted); line-height: 1.35; }

/* Panelfoto krymper paa smale flater saa gridet faar puste. */
@media (max-width: 430px) {
  .pop-photo { width: 96px; height: 46px; }
}

/* ---------- admin ---------- */
/* Adminraden bruker kortets eget språk; ingen ny visuell dialekt. */
/* Den ENE destruktive handlingen i adminlista bærer bad-fargen — den er
   ikke en handling blant likemenn. */
.fc-act.danger { color: var(--bad); }
.fc-act.danger[data-armed="1"] { background: rgba(248, 113, 113, .16); }
.adm-row .fc-actions { margin-top: 10px; padding-top: 10px; }
.adm-row .fc-act { font-size: var(--fs-caption); letter-spacing: 0; }
.adm-row .who .dn { display: flex; align-items: center; gap: 7px; }
.adm-row .pill { flex: none; }
#admSummary { margin: 2px 0 10px; }

/* «Tallene er X min gamle» — gult betyr avvik i dette huset, og en flate
   som står med gamle data er nettopp et avvik. Ikke rødt: ingenting er
   ødelagt, vi vet bare ikke om det stemmer lenger. */
.stale-note {
  margin: 0 0 8px; padding: 8px 12px; border-radius: 10px;
  background: rgba(255, 209, 102, .12);
  color: var(--warn); font-size: 13px; font-weight: 600;
}

/* ---------- admin: rene rader + liquid-glass-alert ---------- */
/* Raden er BARE identitet (Brage 8/8): avatar, navn, status-piller, meta —
   handlingene bor i popupen. Hele raden er tappbar. Lista er iOS-gruppert
   plate; ALERTEN er husets liquid-glass — kontrasten er hierarkiet. */
.adm-row { cursor: pointer;
  transition: background .12s, transform .12s;
  /* backwards, ikke both: en ferdig fylt animasjon eier transform og
     ville slukt pressefysikken under. */
  animation: rise .3s ease backwards;
}
.adm-row:active { background: var(--plate-2); transform: scale(.985); }
.adm-row .friend-row { padding: 2px 0; }
.adm-row .chev { margin-left: auto; flex: none; color: var(--muted);
  opacity: .5; padding-left: 8px; }
.adm-row .chev svg { width: 8px; height: 14px; display: block; }
.adm-row .un { font-variant-numeric: tabular-nums; }
#admSummary { text-transform: uppercase; font-size: var(--fs-micro);
  font-weight: 800; letter-spacing: var(--track-kicker);
  color: var(--muted); font-variant-numeric: tabular-nums; }

/* Monogram-gradienter som iOS Kontakter: duo per bruker (hash av navnet),
   lysere topp mot dypere bunn, hvit glyf. Identiteten følger fra rad til
   popup — samme duo begge steder. */
.avatar.mono { color: #fff;
  text-shadow: 0 1px 2px rgba(0, 0, 0, .18);
  box-shadow: inset 0 -8px 14px rgba(0, 0, 0, .16),
              inset 0 1px 0 rgba(255, 255, 255, .35); }
.avatar.mono-0 { background: linear-gradient(180deg, #6ab2ff, #3d7bf5); }
.avatar.mono-1 { background: linear-gradient(180deg, #fc8a7a, #f0503f); }
.avatar.mono-2 { background: linear-gradient(180deg, #ffb06b, #f0813a); }
.avatar.mono-3 { background: linear-gradient(180deg, #7fdc8b, #38b757); }
.avatar.mono-4 { background: linear-gradient(180deg, #6fd7dc, #2fa9c0); }
.avatar.mono-5 { background: linear-gradient(180deg, #8f9bff, #5d60e6); }
.avatar.mono-6 { background: linear-gradient(180deg, #c78fff, #9450ea); }
.avatar.mono-7 { background: linear-gradient(180deg, #ff8fb1, #ef4f88); }

.adm-modal {
  position: fixed; inset: 0; z-index: 60;
  display: flex; align-items: center; justify-content: center;
  background: rgba(4, 6, 10, .48);
  backdrop-filter: blur(14px) saturate(1.3);
  -webkit-backdrop-filter: blur(14px) saturate(1.3);
  animation: admfade .2s ease-out both;
}
@keyframes admfade { from { opacity: 0; } }
.adm-modal-card {
  width: min(320px, 86vw);
  display: flex; flex-direction: column; gap: 8px;
  animation: admpop .32s cubic-bezier(.32, 1.5, .48, 1) both;
}
/* Glasset er EKTE: husets materiale + den lagdelte kanten. Hodet+handlingene
   er ÉN flate, Avbryt en EGEN under — action-sheet-rytmen letter slabben. */
/* .adm-glass: DØD klasse (16/9) — ingen markup eller JS bruker den lenger.
   Regelen sto igjen fra en tidligere alert-flate og ble slettet, ikke
   pyntet: en regel uten flate er en felle for neste leser. */
@keyframes admpop {
  from { opacity: 0; transform: scale(.86) translateY(14px); } }
/* Lukking er også en bevegelse — alerter som bare forsvinner føles som
   crash. closeAdmModal setter .closing og venter animasjonen ut. */
.adm-modal.closing { animation: admfade .15s ease-in reverse both; }
.adm-modal.closing .adm-modal-card { animation: admout .15s ease-in both; }
@keyframes admout { to { opacity: 0; transform: scale(.94); } }
.adm-modal-head { text-align: center; padding: 22px 16px 14px; }
.adm-modal-head .avatar { margin: 0 auto 10px;
  width: 56px; height: 56px; font-size: 24px; }
/* Duo-farget aura under det store monogrammet — identiteten LYSER svakt. */
.adm-modal-head .avatar.mono-0 { box-shadow: 0 10px 32px -6px rgba(61, 123, 245, .55); }
.adm-modal-head .avatar.mono-1 { box-shadow: 0 10px 32px -6px rgba(240, 80, 63, .5); }
.adm-modal-head .avatar.mono-2 { box-shadow: 0 10px 32px -6px rgba(240, 129, 58, .5); }
.adm-modal-head .avatar.mono-3 { box-shadow: 0 10px 32px -6px rgba(56, 183, 87, .5); }
.adm-modal-head .avatar.mono-4 { box-shadow: 0 10px 32px -6px rgba(47, 169, 192, .55); }
.adm-modal-head .avatar.mono-5 { box-shadow: 0 10px 32px -6px rgba(93, 96, 230, .55); }
.adm-modal-head .avatar.mono-6 { box-shadow: 0 10px 32px -6px rgba(148, 80, 234, .55); }
.adm-modal-head .avatar.mono-7 { box-shadow: 0 10px 32px -6px rgba(239, 79, 136, .5); }
.adm-modal-name { font-size: var(--fs-title); font-weight: 800;
  letter-spacing: -.01em; color: var(--fg); }
.adm-modal-pills { margin-top: 6px; display: flex; gap: 6px;
  justify-content: center; flex-wrap: wrap; }
.adm-modal-meta { color: var(--muted); font-size: var(--fs-caption);
  margin-top: 7px; line-height: 1.6; font-variant-numeric: tabular-nums; }
/* Handlingsrader som UIAlertController: 17pt, hårstrek over, aksent for
   handling, rød for destruktivt, halvfet Avbryt. */
.adm-act {
  display: block; width: 100%; text-align: center;
  min-height: 44px; padding: 11px 14px;
  font-size: var(--fs-title); font-weight: 650;
  color: var(--accent); background: none; border: 0;
  border-top: 1px solid var(--line); cursor: pointer;
  transition: background .1s;
}
.adm-act:active { background: rgba(var(--muted-rgb), .10); }

.adm-act.danger { color: #ff6b5e; position: relative; }
/* Armert sletting: rød fylling + en nedtellingslinje som RENNER UT i takt
   med de-arm-timeren (4 s i openAdmUser) — brukeren SER vinduet lukke seg. */
.adm-act.danger[data-armed="1"] { background: rgba(248, 113, 113, .13);
  font-weight: 700; }
.adm-act.danger[data-armed="1"]::after {
  content: ""; position: absolute; left: 0; bottom: 0; height: 2px;
  width: 100%; background: var(--bad); transform-origin: left;
  animation: admdisarm 4s linear forwards;
}
@keyframes admdisarm { to { transform: scaleX(0); } }
.adm-act.cancel { font-weight: 750; color: var(--fg); border-top: 0; }
.adm-act[disabled] { opacity: .45; }

/* Folden (10/8): fremtidige flyvninger som kompakte rader. Samme kort-
   plate, mindre luft; chevronen hinter «det finnes mer». */
.fcard.mini { padding: 11px 16px; cursor: pointer; }
.fcard.mini .fc-head { gap: 8px; }
.fcard.mini:active { background: var(--plate-2); }
.mini-chev { flex: none; color: var(--muted); opacity: .55; padding-left: 2px; }
.mini-chev svg { width: 12px; height: 7px; display: block; }
.fc-head.foldable { cursor: pointer; }
.mini-chev.up { padding-left: 6px; }

/* Teaserens chip-spøkelse: SAMME mål som den ekte .date-chip i embed, så
   min→halv bytter element for element uten at noe flytter seg. Ikke
   interaktiv — hele teaseren åpner søket. */
.sheet-search-teaser .teaser-chip {
  /* MÅLT mot den ekte raden (min vs halv skal være 0 px drift):
     -18px kansellerer teaserens indre padding så spøkelsets høyrekant
     treffer der #dateChip faktisk står; stretch gir samme høyde. */
  margin: 0 -18px 0 auto; flex: none;
  align-self: stretch; display: flex; align-items: center;
  border: 1px solid var(--line); border-radius: 999px;
  padding: 0 14px; font-weight: 700; font-size: var(--fs-body);
  color: var(--fg); background: rgba(0, 0, 0, .18);
  box-shadow: inset 0 1.5px 3px rgba(0, 0, 0, .30);
}

/* App-krom er ikke dokument: ordmerke, faner, chips og etiketter skal ikke
   kunne tekst-markeres — de blå håndtakene + loupen over FLIGHTRAX leste
   som en bug (IMG_7258). Ekte inndatafelt beholder seleksjon. */
body {
  -webkit-user-select: none; user-select: none;
  -webkit-touch-callout: none;
}
input, textarea, [contenteditable] {
  -webkit-user-select: text; user-select: text;
}


/* Skjelett-plassholder (23/8): startmarkupen PÅSTO ting («Legg til
   venner…») som var feil for brukere med venner, synlig til første svar
   landet — målt som førstegangs-flash i flimmerriggen. Rolige striper
   til dataen kommer; påstandstekster settes kun av et LASTET svar. */
.empty.skel { display: grid; gap: 8px; padding: 14px 12px; }
.empty.skel i {
  display: block; height: 12px; border-radius: 6px;
  background: linear-gradient(90deg,
    rgba(var(--muted-rgb), 0.10) 25%,
    rgba(var(--muted-rgb), 0.22) 50%,
    rgba(var(--muted-rgb), 0.10) 75%);
  background-size: 200% 100%;
  animation: fx-skel 1.3s ease-in-out infinite;
}
.empty.skel i:nth-child(2) { width: 72%; animation-delay: 0.12s; }
.empty.skel i:nth-child(3) { width: 45%; animation-delay: 0.24s; }
@keyframes fx-skel { 0% { background-position: 180% 0; } 100% { background-position: -20% 0; } }
@media (prefers-reduced-motion: reduce) {
  .empty.skel i { animation: none; background: rgba(var(--muted-rgb), 0.14); }
}


/* Bryter-rad i grupperte lister (varselvalg, 24/8). Samme høyde og
   hårstrek som .lrow ellers; selve boksen er skjult og <i> tegner
   sporet + knotten, så treffområdet er hele raden. */
.lrow.sw { display: flex; align-items: center; justify-content: space-between;
           gap: 12px; cursor: pointer; }
.lrow.sw input { position: absolute; opacity: 0; pointer-events: none; }
.lrow.sw i {
  flex: none; width: 46px; height: 28px; border-radius: 999px;
  background: rgba(var(--muted-rgb), 0.20); position: relative;
  transition: background .18s ease;
}
.lrow.sw i::after {
  content: ""; position: absolute; top: 3px; left: 3px;
  width: 22px; height: 22px; border-radius: 50%; background: #fff;
  box-shadow: 0 1px 3px rgba(0, 0, 0, .35);
  transition: transform .18s ease;
}
.lrow.sw input:checked + i { background: var(--accent); }
.lrow.sw input:checked + i::after { transform: translateX(18px); }
.lrow.sw input:focus-visible + i { outline: 2px solid var(--accent); outline-offset: 2px; }
@media (prefers-reduced-motion: reduce) {
  .lrow.sw i, .lrow.sw i::after { transition: none; }
}


/* Været i begge ender (24/8). Egen rad over statistikken, stille i
   uttrykket: dette er kontekst, ikke en av flyvningens fakta. */
.live-weather { display: flex; gap: 14px; justify-content: center;
                flex-wrap: wrap; margin: 2px 0 10px; }
.live-weather:empty { display: none; }
.live-weather .wx { font-size: var(--fs-caption); color: var(--muted);
                    letter-spacing: .01em; }
.live-weather .wx b { color: var(--fg); font-weight: 600; margin-right: 2px; }

/* Året på kart (24/8): delbar parade i passet. Canvasen er 1080×1350
   (Instagram-story-forhold) og skaleres ned i visning — bildet som
   deles skal være skarpt, ikke skjermoppløsning. */
.pp-review { display: grid; gap: 10px; justify-items: center; }
.pp-review.hidden { display: none; }
.pp-review canvas {
  width: 100%; max-width: 420px; height: auto; border-radius: 14px;
  background: var(--bg); box-shadow: 0 6px 22px rgba(0, 0, 0, .35);
}

/* ---------- Pro-låser (docs/PRO-SPLIT.md) ----------
   Ett kort per låst flate: hva Pro gir, og én knapp. I appen åpner
   knappen den native paywallen (fxPaywall), i nettleseren Pro-arket. */
/* .card har border: 0 — kanten må være en inset-skygge for å finnes. */
.pro-lock { box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--accent) 38%, transparent); }
.pro-lock-title { font-weight: 800; font-size: var(--fs-lead); margin-bottom: 4px; display: flex; align-items: center; gap: 8px; }
.pl-ico { width: 18px; height: 18px; color: var(--accent); flex: none; }
.src-ico { width: 13px; height: 13px; vertical-align: -2px; margin-left: 1px; opacity: .8; }
.pro-lock-why { color: var(--muted); font-size: var(--fs-body); margin-bottom: 10px; }
.pro-perks { margin: 0 0 12px; padding-left: 18px; font-size: var(--fs-body); }
.pro-perks li { margin: 3px 0; }
.pro-lock .btn { width: 100%; display: block; text-align: center; box-sizing: border-box; text-decoration: none; }
.pro-sheet .card-note { margin: 8px 0 0; }
.pro-sheet .card { padding: 16px; }
#tab-friends.pro-locked .fsec { display: none; }
.pro-locked .card.list, .pro-locked .card-note { opacity: .45; pointer-events: none; }
.pro-row { display: flex; align-items: center; gap: 12px; padding: 14px 16px; margin-bottom: 14px; }
.pro-row.cta { background: var(--accent); color: var(--on-accent); border-color: transparent; cursor: pointer; }
.pro-row .pr-ico { display: flex; flex: none; }
.pro-row .pr-ico svg { width: 22px; height: 22px; }
.pro-row .pr-ico.good { color: var(--good); }
.pro-row .pr-t { font-weight: 800; font-size: var(--fs-body); }
.pro-row .pr-s { font-size: var(--fs-caption); opacity: .85; }
html.embed #proRow { display: none; }

/* ---------- design-uplift 5/9: faneskift, lys-felt, tekstbryting ----------
   Brage: «font, harmoni, flickering, loading — high end». Hver regel her er
   målt mot et skjermbilde i riggen FØR og ETTER; ingen «pussing». */
/* Et faneskift toner den nye flaten inn (6 px rise). Klassen settes av
   fane-handleren KUN ved ekte bytte, aldri ved re-render — ingen flimmer. */
.tab-in { animation: tab-in .24s var(--ease-out) both; }
@keyframes tab-in { from { opacity: 0; transform: translateY(6px); } }
@media (prefers-reduced-motion: reduce) { .tab-in { animation: none; } }
/* Lys: søkefeltet, datochipen og teaseren var mørke, tunge brønner
   (rgba(0,0,0,.18–.22) + innfelt skygge) på hvit plate. På lyst er
   brønnen Apples systemGray6: nesten ingenting, ingen skygge. */
:root[data-theme="lys"] .search-box,
:root[data-theme="lys"] .date-chip,
:root[data-theme="lys"] .sheet-search-teaser,
:root[data-theme="lys"] .sheet-search-teaser .teaser-chip,
:root[data-theme="lys"] .feeder-key,
:root[data-theme="lys"] .feeder-cmd {
  background: rgba(0, 0, 0, .045);
  box-shadow: inset 0 1px 1.5px rgba(0, 0, 0, .05);
}
:root[data-theme="lys"] nav.tabs button.active {
  background: rgba(0, 0, 0, .06);
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .06);
}
/* Tekst som skal leses som ÉN tanke brekkes balansert; fotnoter unngår
   enslige ord på siste linje. Ignoreres av eldre motorer. */
.empty, .ppo-title, .pro-lock-why, .pro-row .pr-s { text-wrap: balance; }
.card-note, .hint, .ppo-note, .pro-lock-why { text-wrap: pretty; }
/* Glyfen i et tomt rom: samme 40 px currentColor-regel (C4) — nå BRUKT. */
.empty .empty-art { margin-bottom: 10px; }
.empty.tall .empty-art { margin: 0 auto 12px; }
/* Lukk/fjern-kryssene er strekglyfer nå (i-close) — samme størrelse
   overalt, currentColor, så .is-loading (color: transparent) skjuler dem
   nøyaktig som tekst-krysset før. */
.search-clear svg, .pp-del svg, .feeder-del svg { width: 12px; height: 12px; display: block; }
.search-clear svg { width: 14px; height: 14px; }
#followChip .fc-x { width: 12px; height: 12px; margin-left: 2px; }
/* Selskapets merke i brett- og søkeradene (design-uplift r3): Flightys rad
   har alltid identiteten først. Liten variant, samme logo/monogram-regel. */
.al-badge.sm { width: 22px; height: 22px; font-size: 8.5px; border-width: 1px; letter-spacing: 0; }
.al-badge.sm .al-logo { padding: 2px; }
/* Lys: dimmingen bak alerter/ark er lettere — iOS dimmer lyst svakt. */
:root[data-theme="lys"] .adm-modal { background: rgba(60, 60, 67, .28); }
:root[data-theme="lys"] .overlay { background: rgba(60, 60, 67, .32); }
.legend i { border: 1px solid var(--line); }

/* Trakten i admin (vekst 6/9): seks tall i tre kolonner, samme plate og
   hårstrek som resten av gruppene — tåler embed-bredden. */
.funnel { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; margin: 0 0 12px; }
.funnel .fn { background: var(--plate); border-radius: var(--r-md); padding: 10px 10px 8px;
  box-shadow: inset 0 0 0 1px var(--line); min-width: 0; }
.funnel .fn b { display: block; font-size: var(--fs-big); font-weight: 800; letter-spacing: -.01em;
  font-variant-numeric: tabular-nums; line-height: 1.1; }
.funnel .fn span { display: block; font-size: var(--fs-caption); color: var(--fg); font-weight: 650; margin-top: 2px; }
.funnel .fn i { display: block; font-style: normal; font-size: var(--fs-micro); color: var(--muted); margin-top: 2px; }

/* Del-knappen (vekst 6/9) er et ikon, ikke et ord: fem ord i handlingsraden
   brakk «Vis mindre» over to linjer. Samme høyde og hårstrek som naboene. */
.fc-act.ico { flex: 0 0 auto; padding: 0 12px; }
.fc-act.ico svg { width: 17px; height: 17px; display: block; }
.fc-act.ico svg[viewBox="0 0 12 7"] { width: 14px; height: 8px; }

/* Kilde-overvåking i admin (9/9): veksler + per-flyplass live-prikk +
   ærlige dekningschips. Token-styrt, holder i Lys og mørkt. */
.adm-seg { display: flex; gap: 6px; margin: 0 0 12px; }
.adm-seg button { flex: 1; padding: 8px 0; border-radius: var(--r-md); border: 1px solid var(--line);
  background: var(--plate); color: var(--muted); font: inherit; font-weight: 700; font-size: var(--fs-body);
  cursor: pointer; -webkit-tap-highlight-color: transparent; }
.adm-seg button.seg-on { color: var(--fg); background: rgba(var(--accent-rgb), .14); border-color: transparent; }
.src-row { padding: 12px 14px; margin-bottom: 8px; }
.src-head { display: flex; align-items: center; gap: 8px; }
.src-head b { font-variant-numeric: tabular-nums; letter-spacing: .02em; }
.src-name { color: var(--muted); font-size: var(--fs-body); flex: 1; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.src-age { color: var(--muted); font-size: var(--fs-caption); flex: none; }
.fx-dot.warn { background: var(--warn); box-shadow: 0 0 8px var(--warn); opacity: 1; }
.src-meta { color: var(--muted); font-size: var(--fs-caption); margin: 6px 0 8px; }
.src-cov { display: flex; flex-wrap: wrap; gap: 6px; }
.cov { font-size: var(--fs-micro); font-weight: 700; padding: 3px 8px; border-radius: 999px;
  background: rgba(var(--muted-rgb), .10); color: var(--muted); }
.cov.ok { background: color-mix(in srgb, var(--good) 18%, transparent); color: var(--good); }
.cov.lo { background: color-mix(in srgb, var(--warn) 20%, transparent); color: var(--warn); }
.cov.zero { background: color-mix(in srgb, var(--bad) 18%, transparent); color: var(--bad); }
.cov.na { opacity: .6; }

/* Kilder: løgn-chips (rader som ikke kan være sanne) og filterchips (9/9). */
.cov.lie { color: #fff; background: var(--bad, #c0392b); border-color: transparent; }
.src-filters { margin: 6px 0 8px; flex-wrap: wrap; }

/* =====================================================================
   LUFTROM + MENYER (Brage 11/9: «pop up menyer … mer i Apple-stil og mer
   moderne» og «mellomrom er noen ganger litt tight … likt mellom knapper»).
   Én rytme for hele appen: 8 mellom søsken i en gruppe, 12 mellom
   kontroller, 16 mellom grupper, 24 mellom seksjoner. Kontroller er 44 høye
   (Apples minimum). Menyene er iOS-kontekstmenyer: glass, ikon + etikett
   venstrestilt, hårstrek mellom rader, tykk skille mellom grupper, rødt for
   det destruktive, ingen «Avbryt» — du trykker utenfor.
   ===================================================================== */
:root {
  --sp-1: 4px; --sp-2: 8px; --sp-3: 12px; --sp-4: 16px; --sp-5: 20px; --sp-6: 24px; --sp-8: 32px;
  --control-h: 44px;
  --veil-rgb: 0, 0, 0;
}
:root[data-theme="lys"] { --veil-rgb: 60, 60, 67; }

/* --- rytme ---------------------------------------------------------- */
.section-title { margin: var(--sp-6) 0 var(--sp-2); }
.card { padding: var(--sp-4); margin: var(--sp-2) 0; }
.card.list { padding: 0 0 0 var(--sp-4); }
.card-note { margin: var(--sp-1) 4px var(--sp-5); padding: 0 var(--sp-3); }
.card > .btn, #feederSetup .btn { margin-top: var(--sp-3); }
.btn { min-height: var(--control-h); padding: 0 var(--sp-4); display: inline-flex; align-items: center; justify-content: center; }
.btn.small { min-height: 34px; padding: 0 14px; }
.logout-btn { margin: var(--sp-6) 0 var(--sp-1); }
.lrow { min-height: 48px; padding: var(--sp-2) var(--sp-4) var(--sp-2) 0; }
.search-wrap { margin: 0 0 var(--sp-3); }
.search-box { min-height: var(--control-h); }
.adm-seg { gap: var(--sp-2); margin: 0 0 var(--sp-3); }
.adm-seg button { min-height: var(--control-h); padding: 0 var(--sp-3); }
.adm-seg.src-filters button { min-height: 36px; }
.funnel { gap: var(--sp-2); margin: 0 0 var(--sp-4); }
.funnel .fn { padding: var(--sp-3) var(--sp-3) 10px; }
.stats-line { margin: 0 0 var(--sp-2); }
.adm-row.card { margin: 0 0 var(--sp-2); }
.src-row { margin-bottom: var(--sp-2); }
.theme-grid { gap: var(--sp-2); }
.apboard-tabs { gap: var(--sp-2); margin: var(--sp-3) 0 var(--sp-1); }
.pp-years { gap: var(--sp-2); }
.pp-card { margin-bottom: var(--sp-2); }
.lang-seg button { min-height: var(--control-h); }
/* Innbygd i appen ligger den native docken OVER webinnholdet: den siste
   raden gled under den (Brages skjermbilde 11/9 19:22). Reservér plass. */
html.embed #tab-admin, html.embed #tab-profile, html.embed #tab-friends,
html.embed #tab-passport, html.embed #tab-feedback { padding-bottom: calc(104px + var(--sab)); }

/* --- iOS-kontekstmeny — ÉN regel, ett hjem (16/9) ------------------------
   Før lå seks generasjoner overstyringer oppå hverandre (18→20→24→26 px
   radius, blur 34→52, fire --glass-lens-definisjoner, rader 46→34 px).
   Det Brage så på telefonen — «usnud og cramped», tykke hvite kanter i lys
   modus, grå utvisket bakgrunn — var SUMMEN av dem, ikke et design.
   Målene er Apples (iOS 26-kontekstmeny): rader 44 pt, 17 pt vekt 500,
   ikon 20 pt, ÉN tynn lysende kant, et slør som lar innholdet skimtes.
   Forankret meny er like bred som raden den vokser ut av (Brage 12/9):
   to bredder i samme stabel leses som to elementer, ikke ÉN meny. */
:root { --glass-lens: rgba(72, 74, 84, .52); --glass-modal: rgba(44, 46, 54, .80);
        --lens-hi: rgba(255, 255, 255, .55); --lens-lo: rgba(255, 255, 255, .12); --lens-shadow: rgba(0, 0, 0, .28); }
:root[data-theme="nordlys"] { --glass-lens: rgba(56, 84, 78, .50); --glass-modal: rgba(30, 52, 46, .80); }
:root[data-theme="midnattssol"] { --glass-lens: rgba(92, 64, 76, .50); --glass-modal: rgba(58, 38, 48, .80); }
:root[data-theme="stealth"] { --glass-lens: rgba(70, 72, 78, .52); --glass-modal: rgba(42, 44, 50, .80); }
:root[data-theme="lys"] { --glass-lens: rgba(255, 255, 255, .66); --glass-modal: rgba(255, 255, 255, .84);
        --lens-hi: rgba(255, 255, 255, .95); --lens-lo: rgba(60, 60, 67, .12); --lens-shadow: rgba(60, 60, 67, .14); }

/* Sløret: innholdet bak skal SKIMTES, som i iOS — ikke viskes ut til grått. */
.fx-veil {
  position: fixed; inset: 0; z-index: 70;
  display: flex; align-items: center; justify-content: center;
  padding: var(--sp-6);
  background: rgba(var(--veil-rgb), .20);
  backdrop-filter: blur(18px) saturate(1.25);
  -webkit-backdrop-filter: blur(18px) saturate(1.25);
  animation: fxveil .2s ease-out both;
  -webkit-tap-highlight-color: transparent;
}
:root[data-theme="lys"] .fx-veil {
  background: rgba(var(--veil-rgb), .14);
  backdrop-filter: blur(16px); -webkit-backdrop-filter: blur(16px);
}
.fx-veil.closing { animation: fxveil .16s ease-in reverse both; }
.fx-veil.closing .fx-stack { animation: fxpop .16s ease-in reverse both; }
.fx-stack {
  width: min(300px, 100%);
  display: flex; flex-direction: column; gap: 10px;
  animation: fxpop .36s cubic-bezier(.3, 1.45, .5, 1) both;
  transform-origin: 50% 40%;
}

/* Materialet: gjennomskinnelig linse, dempet topp-glans, myk dobbel skygge. */
.fx-preview, .fx-menu {
  position: relative; isolation: isolate; overflow: hidden;
  border-radius: 22px;
  background: linear-gradient(180deg, rgba(255, 255, 255, .10), rgba(255, 255, 255, 0) 42%), var(--glass-lens);
  backdrop-filter: blur(40px) saturate(1.8);
  -webkit-backdrop-filter: blur(40px) saturate(1.8);
  box-shadow: 0 24px 64px rgba(0, 0, 0, .42), 0 2px 8px rgba(0, 0, 0, .20),
              inset 0 1px 0 rgba(255, 255, 255, .28), inset 0 -1px 0 var(--lens-shadow);
}
:root[data-theme="lys"] .fx-preview, :root[data-theme="lys"] .fx-menu {
  background: linear-gradient(180deg, rgba(255, 255, 255, .42), rgba(255, 255, 255, 0) 48%), var(--glass-lens);
  box-shadow: 0 20px 56px rgba(40, 40, 60, .20), 0 2px 8px rgba(40, 40, 60, .10),
              inset 0 1px 0 rgba(255, 255, 255, .95), inset 0 -1px 0 var(--lens-shadow);
}
/* Kanten: ÉN 1 px-ring med lyset oppe til venstre. (Den 5 px lysnende
   innerringen og 2 px-gradienten fra før er borte — de var «tykke kanter».) */
.fx-preview::before, .fx-menu::before {
  content: ""; position: absolute; inset: 0; border-radius: inherit; pointer-events: none; z-index: 2;
  padding: 1px;
  background: linear-gradient(135deg, var(--lens-hi) 0%, var(--lens-lo) 42%, var(--lens-lo) 58%, var(--lens-hi) 100%);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor; mask-composite: exclude;
}
/* Lysglimtet som sveiper over glasset i det menyen åpner — beholdt. */
.fx-glint {
  position: absolute; inset: -40% -60%; pointer-events: none; z-index: 3; border-radius: inherit;
  background: linear-gradient(115deg, rgba(255, 255, 255, 0) 38%, rgba(255, 255, 255, .22) 47%, rgba(255, 255, 255, .42) 50%, rgba(255, 255, 255, .22) 53%, rgba(255, 255, 255, 0) 62%);
  transform: translateX(-70%); opacity: 0;
  animation: fxglint 1.1s .12s cubic-bezier(.2, .7, .2, 1) both;
}
@keyframes fxglint { 0% { transform: translateX(-70%); opacity: 0; } 12% { opacity: 1; } 100% { transform: translateX(70%); opacity: 0; } }

/* Forhåndsvisningen (raden du trykket på, løftet opp i glasset). */
.fx-preview { display: flex; align-items: center; gap: var(--sp-3); padding: 10px 14px; }
.fx-preview .avatar { width: 42px; height: 42px; font-size: 17px; }
.fx-preview-t { min-width: 0; flex: 1; }
.fx-preview-name { font-size: 16px; font-weight: 600; letter-spacing: -.01em; color: #fff;
  display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.fx-preview-meta { color: rgba(255, 255, 255, .72); font-size: var(--fs-caption); margin-top: 2px; line-height: 1.45;
  font-variant-numeric: tabular-nums; overflow: hidden; text-overflow: ellipsis; }
:root[data-theme="lys"] .fx-preview-name { color: #111114; }
:root[data-theme="lys"] .fx-preview-meta { color: rgba(30, 30, 40, .62); }

/* Radene: 44 pt, hårstrek trukket inn fra ikonkolonnen som på iOS. */
.fx-title { position: relative; z-index: 1; padding: 10px 16px 8px; color: rgba(255, 255, 255, .78);
  font-size: var(--fs-body); line-height: 1.4; text-align: left; }
.fx-title b { display: block; color: #fff; font-size: 15px; font-weight: 700; margin-bottom: 2px; }
:root[data-theme="lys"] .fx-title { color: rgba(30, 30, 40, .7); }
:root[data-theme="lys"] .fx-title b { color: #111114; }
.fx-mi {
  position: relative; z-index: 1;
  display: flex; align-items: center; gap: 12px; width: 100%;
  min-height: 44px; padding: 0 16px 0 14px;
  background: none; border: 0;
  font: inherit; font-size: 17px; font-weight: 500; letter-spacing: -.01em; line-height: 1.2;
  color: #fff; text-align: left; cursor: pointer;
  transition: background .08s;
  -webkit-tap-highlight-color: transparent;
}
.fx-mi + .fx-mi::before { content: ""; position: absolute; left: 46px; right: 0; top: 0; height: .5px; background: rgba(255, 255, 255, .16); }
.fx-mi:active { background: rgba(255, 255, 255, .14); }
.fx-mi .fx-mi-l { flex: 1; min-width: 0; }
.fx-mi .fx-mi-ico { width: 20px; height: 20px; flex: none; display: block; color: inherit; opacity: .8; }
.fx-mi .fx-mi-ico svg { width: 20px; height: 20px; display: block; }
.fx-mi.danger { color: #ff6b62; }
.fx-mi.armed { background: rgba(255, 69, 58, .20); }
.fx-mi.armed:active { background: rgba(255, 69, 58, .30); }
.fx-mi.accent { color: var(--accent); }
:root[data-theme="lys"] .fx-mi { color: #111114; }
:root[data-theme="lys"] .fx-mi + .fx-mi::before { background: rgba(60, 60, 67, .18); }
:root[data-theme="lys"] .fx-mi:active { background: rgba(0, 0, 0, .06); }
:root[data-theme="lys"] .fx-mi.danger { color: #e0342c; }
:root[data-theme="lys"] .fx-mi.armed { background: rgba(255, 59, 48, .14); }
.fx-msep { position: relative; z-index: 1; height: 6px; background: rgba(0, 0, 0, .14); }
:root[data-theme="lys"] .fx-msep { background: rgba(60, 60, 67, .08); }
.fx-menu { width: min(232px, 100%); }
@keyframes fxveil { from { opacity: 0; } to { opacity: 1; } }
@keyframes fxpop { from { opacity: 0; transform: scale(.86); } to { opacity: 1; transform: scale(1); } }
@media (prefers-reduced-motion: reduce) { .fx-veil, .fx-stack, .fx-glint { animation: none !important; } }

/* --- Forankret meny: vokser ut av raden du trykket på -------------------- */
.fx-veil.anchored { display: block; padding: 0; }
.fx-veil.anchored .fx-stack {
  position: absolute; width: auto; align-items: flex-start;
  animation: fxgrow .42s cubic-bezier(.26, 1.55, .5, 1) both;
}
.fx-veil.anchored .fx-stack.above { flex-direction: column-reverse; }
.fx-veil.anchored .fx-preview { width: 100%; }
.fx-veil.anchored .fx-menu { width: 100%; }
.fx-veil.closing .fx-stack.anchored { animation: fxgrow .16s ease-in reverse both; }
@keyframes fxgrow { from { opacity: 0; transform: scale(.72); } to { opacity: 1; transform: scale(1); } }


/* Skjemaene (tilbakemelding/Pro) arver menyens radius og rytme. */
.adm-act { min-height: 46px; padding: 0 var(--sp-4); font-weight: 600; }
.adm-modal-head { padding: var(--sp-5) var(--sp-4) var(--sp-3); }
/* Segmentkontroll som iOS: ÉN pille med et flyttbart lyst segment, ikke
   to løse knapper med hver sin ramme (admin «Brukere/Kilder», språk,
   kildefiltre). */
.adm-seg {
  gap: 0; padding: 3px; border-radius: 12px;
  background: rgba(var(--muted-rgb), .10);
}
.adm-seg button {
  min-height: 38px; padding: 0 var(--sp-2); border: 0; border-radius: 9px;
  background: transparent; color: var(--muted); font-weight: 600;
  transition: background .15s, color .15s, box-shadow .15s;
}
.adm-seg button.seg-on {
  color: var(--fg); background: var(--plate-2);
  box-shadow: 0 1px 3px rgba(0, 0, 0, .35), inset 0 0 0 .5px rgba(255, 255, 255, .06);
}
:root[data-theme="lys"] .adm-seg { background: rgba(60, 60, 67, .12); }
:root[data-theme="lys"] .adm-seg button.seg-on { background: #fff; box-shadow: 0 1px 4px rgba(0, 0, 0, .12); }
.adm-seg.src-filters button { font-size: var(--fs-caption); padding: 0 4px; min-height: 34px; }
.lang-seg { flex-wrap: wrap; }
.lang-seg button { flex: 1 1 30%; min-height: 38px; }

/* =====================================================================
   LIQUID GLASS — DESIGNSPRÅKET (Brage 12/9: «stilen, boblene, kantene,
   temafargene — alt» / «full uplift»). Ett lag over hele appen, sist i
   fila så det vinner på lik spesifisitet. Prinsippene (iOS 26):
   1. LYS OVENFRA: hver flate har en lys topplinje, mørkere bunn, og en
      tynn lysende rand. Glasset lyser selv — aldri en svart plate.
   2. BOBLER: alle kontroller er kapsler (999px). Flater er runde (20/28).
   3. STØRRE TYPE: 15/17/20/28/34 — iOS-skalaen, ikke 13.
   4. FARGER: Apples systemfarger for status (grønn/oransje/rød), tonete
      kapsler i stedet for rammer, merkeblått som aksent med glans.
   5. DYBDE OG FYSIKK: skygge under, glød over, trykk = 0.97 skala.
   ===================================================================== */
:root {
  /* TYPESKALA OG RADIER: Brage 12/9, med skjermbilde av kartet — «mye mer
     zoomet inn og ser ikke bra ut. Dette vil jeg ha som det var før.» Den
     store iOS-skalaen (11/13/15/17/20/28/34 og radier 14/20/28) blåste opp
     HELE appen, ikke bare listene den var tenkt for: kartets panel, søkefelt,
     dock og kort ble 15-30 % større. MATERIALET (glass, lys ovenfra, kapsler,
     Apples statusfarger, glansende CTA) er beholdt — bare målene er tilbake. */
  --fs-micro: 10px; --fs-caption: 11.5px; --fs-body: 13px; --fs-lead: 15px;
  --fs-title: 17px; --fs-big: 21px; --fs-hero: 26px;
  --r-sm: 10px; --r-md: 14px; --r-lg: 22px;
  --good: #30d158; --warn: #ff9f0a; --bad: #ff453a;
  --good-rgb: 48, 209, 88; --warn-rgb: 255, 159, 10; --bad-rgb: 255, 69, 58;
  /* Glassplaten: lys på svart, ikke grå plate. */
  --plate: rgba(255, 255, 255, .07);
  --plate-2: rgba(255, 255, 255, .12);
  --plate-hi: rgba(255, 255, 255, .30);      /* topplinja */
  --plate-rim: rgba(255, 255, 255, .10);     /* randen rundt */
  --plate-lo: rgba(0, 0, 0, .28);            /* bunnen */
  --glass: rgba(16, 18, 24, .62);
  --glass-strong: rgba(28, 30, 38, .80);
  --glass-blur: blur(36px) saturate(1.9) brightness(1.04);
  --glass-blur-strong: blur(46px) saturate(2.1) brightness(1.06);
  --line: rgba(255, 255, 255, .10);
  --rim: rgba(255, 255, 255, .18);
  --bg: #05070c;
  --shadow-lift: 0 18px 44px rgba(0, 0, 0, .42), 0 2px 6px rgba(0, 0, 0, .22);
}
:root[data-theme="nordlys"] { --plate: rgba(120, 220, 200, .07); --plate-2: rgba(120, 220, 200, .12); --glass: rgba(10, 24, 20, .62); --glass-strong: rgba(18, 36, 30, .80); --bg: #04100c; }
:root[data-theme="midnattssol"] { --plate: rgba(255, 190, 150, .07); --plate-2: rgba(255, 190, 150, .12); --glass: rgba(26, 14, 20, .62); --glass-strong: rgba(40, 24, 30, .80); --bg: #0d0509; }
:root[data-theme="stealth"] { --plate: rgba(200, 210, 224, .07); --plate-2: rgba(200, 210, 224, .12); --glass: rgba(14, 15, 18, .64); --glass-strong: rgba(26, 28, 32, .82); --bg: #060708; }
:root[data-theme="lys"] {
  --plate: rgba(255, 255, 255, .78); --plate-2: rgba(255, 255, 255, .95);
  --plate-hi: rgba(255, 255, 255, 1); --plate-rim: rgba(60, 60, 67, .12); --plate-lo: rgba(60, 60, 80, .10);
  --glass: rgba(246, 246, 250, .66); --glass-strong: rgba(255, 255, 255, .82);
  --line: rgba(60, 60, 67, .14); --rim: rgba(60, 60, 67, .16);
  --good: #34c759; --warn: #ff9500; --bad: #ff3b30; --good-rgb: 52, 199, 89; --warn-rgb: 255, 149, 0; --bad-rgb: 255, 59, 48;
  --bg: #eef0f6; --shadow-lift: 0 18px 44px rgba(40, 40, 70, .14), 0 2px 6px rgba(40, 40, 70, .08);
}
html, body { background: var(--bg); }
body { -webkit-font-smoothing: antialiased; }

/* --- typografi: store titler som iOS ------------------------------------ */
.tab-title { font-size: var(--fs-hero); font-weight: 800; letter-spacing: -.03em; color: var(--fg); margin: var(--sp-4) 0 var(--sp-3); line-height: 1.1; }
.section-title { font-weight: 600; letter-spacing: -.005em; }
.nav-back { font-size: 16px; }

/* --- flater: glassplater med lys ovenfra ---------------------------------- */
.card, .card.list, .funnel .fn, .src-row, .pro-row, .adm-row.card, .pp-card, .past-card {
  background: linear-gradient(180deg, rgba(255, 255, 255, .06), rgba(255, 255, 255, 0) 60%), var(--plate);
  border: 0; border-radius: var(--r-md);
  box-shadow: inset 0 1px 0 var(--plate-hi), 0 0 0 .5px var(--plate-rim), inset 0 -1px 0 var(--plate-lo), 0 10px 30px rgba(0, 0, 0, .18);
}
:root[data-theme="lys"] .card, :root[data-theme="lys"] .card.list, :root[data-theme="lys"] .funnel .fn, :root[data-theme="lys"] .src-row,
:root[data-theme="lys"] .pro-row, :root[data-theme="lys"] .adm-row.card, :root[data-theme="lys"] .pp-card, :root[data-theme="lys"] .past-card {
  background: linear-gradient(180deg, rgba(255, 255, 255, .9), rgba(255, 255, 255, .5) 60%), var(--plate);
  box-shadow: inset 0 1px 0 var(--plate-hi), 0 0 0 .5px var(--plate-rim), 0 10px 30px rgba(40, 40, 70, .10);
}
.card.list { padding-left: var(--sp-4); }
.lrow { border-top: 1px solid var(--line); }
.adm-row:active, .card.press:active { transform: scale(.985); }

/* --- bobler: kapsler for alle kontroller ----------------------------------- */
.btn, .chip, .date-chip, .pill, .apboard-tabs button, .pp-chip, .fc-act, .search-box, .adm-seg, .cov, .delaychip, .toast {
  border-radius: 999px;
}
.btn {
  min-height: var(--control-h); padding: 0 var(--sp-4); font-size: var(--fs-body); font-weight: 700; letter-spacing: -.01em;
  background: linear-gradient(180deg, rgba(255, 255, 255, .12), rgba(255, 255, 255, .04)), var(--plate);
  border: 0; color: var(--fg);
  box-shadow: inset 0 1px 0 var(--plate-hi), 0 0 0 .5px var(--plate-rim), 0 6px 18px rgba(0, 0, 0, .18);
  transition: transform .14s var(--ease-out), box-shadow .14s, filter .14s;
}
.btn:active { transform: scale(.97); filter: brightness(1.08); }
.btn.cta {
  color: var(--on-accent);
  background: linear-gradient(180deg, rgba(255, 255, 255, .28), rgba(255, 255, 255, 0) 55%), linear-gradient(135deg, var(--accent), var(--accent2));
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .55), inset 0 -1px 0 rgba(0, 0, 0, .18), 0 10px 26px rgba(var(--accent-rgb), .38);
  text-shadow: 0 1px 1px rgba(0, 0, 0, .18);
}
.btn.danger { color: var(--bad); background: linear-gradient(180deg, rgba(255, 255, 255, .06), rgba(255, 255, 255, 0)), rgba(var(--bad-rgb), .14); box-shadow: inset 0 1px 0 rgba(255, 255, 255, .18), 0 0 0 .5px rgba(var(--bad-rgb), .35); }
.btn.secondary { background: linear-gradient(180deg, rgba(255, 255, 255, .10), rgba(255, 255, 255, 0)), var(--plate-2); }
.btn.small { min-height: 34px; padding: 0 14px; font-size: var(--fs-body); }
.logout-btn { background: var(--plate); color: var(--bad); box-shadow: inset 0 1px 0 var(--plate-hi), 0 0 0 .5px var(--plate-rim); }
.chip {
  padding: 5px 11px; font-size: var(--fs-micro); font-weight: 700; color: var(--fg);
  background: var(--glass); border: 0;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .35), 0 0 0 .5px var(--rim), 0 6px 16px rgba(0, 0, 0, .25);
}
.date-chip {
  min-height: var(--control-h); padding: 0 14px; font-size: var(--fs-body); font-weight: 700; border: 0;
  background: linear-gradient(180deg, rgba(255, 255, 255, .10), rgba(255, 255, 255, 0)), var(--plate);
  box-shadow: inset 0 1px 0 var(--plate-hi), 0 0 0 .5px var(--plate-rim);
}
.search-box {
  min-height: var(--control-h); padding: 0 12px; border: 0;
  background: linear-gradient(180deg, rgba(255, 255, 255, .08), rgba(255, 255, 255, 0)), var(--plate);
  box-shadow: inset 0 1px 0 var(--plate-hi), 0 0 0 .5px var(--plate-rim);
}
.search-box input { font-size: var(--fs-body); }
.search-box:focus-within { box-shadow: inset 0 1px 0 var(--plate-hi), 0 0 0 1.5px rgba(var(--accent-rgb), .6), 0 0 0 6px rgba(var(--accent-rgb), .14); }
.apboard-tabs button, .pp-chip { padding: 7px 13px; font-size: var(--fs-caption); font-weight: 700; border: 0; background: var(--plate); box-shadow: inset 0 1px 0 var(--plate-hi), 0 0 0 .5px var(--plate-rim); color: var(--muted); }
.apboard-tabs button.active, .pp-chip.active { color: var(--on-accent); background: linear-gradient(180deg, rgba(255, 255, 255, .25), rgba(255, 255, 255, 0) 55%), var(--accent); box-shadow: inset 0 1px 0 rgba(255, 255, 255, .5), 0 6px 16px rgba(var(--accent-rgb), .35); }
.adm-seg { padding: 4px; background: var(--plate); box-shadow: inset 0 1px 0 var(--plate-hi), 0 0 0 .5px var(--plate-rim); }
.adm-seg button { border-radius: 999px; min-height: 36px; font-size: var(--fs-body); }
.adm-seg button.seg-on { background: linear-gradient(180deg, rgba(255, 255, 255, .22), rgba(255, 255, 255, .04)), var(--plate-2); box-shadow: inset 0 1px 0 rgba(255, 255, 255, .45), 0 4px 12px rgba(0, 0, 0, .28); color: var(--fg); }
:root[data-theme="lys"] .adm-seg button.seg-on { background: #fff; box-shadow: 0 2px 8px rgba(40, 40, 70, .18), inset 0 1px 0 #fff; }
.fc-act { min-height: 38px; border: 0; background: linear-gradient(180deg, rgba(255, 255, 255, .10), rgba(255, 255, 255, 0)), var(--plate); box-shadow: inset 0 1px 0 var(--plate-hi), 0 0 0 .5px var(--plate-rim); font-size: var(--fs-body); letter-spacing: .02em; }
.fc-act:active { transform: scale(.96); }
/* Statuskapsler: tonet fyll med Apples farger, ikke tynne rammer. */
.pill { padding: 4px 9px; font-weight: 800; letter-spacing: var(--track-caps); border: 0; box-shadow: inset 0 1px 0 rgba(255, 255, 255, .18); background: rgba(255, 255, 255, .10); color: var(--fg); }
.pill.s-expected, .pill.s-boarding, .pill.s-gate_closing, .pill.s-go_to_gate, .pill.s-gate_closed, .delaychip { color: var(--warn); background: rgba(var(--warn-rgb), .18); }
.pill.s-cancelled, .pill.s-diverted { color: var(--bad); background: rgba(var(--bad-rgb), .18); }
.pill.s-landed, .pill.s-departed, .pill.s-en_route, .pill.s-baggage, .pill.s-baggage_delivered { color: var(--good); background: rgba(var(--good-rgb), .18); }
.pill.track { color: var(--accent); background: rgba(var(--accent-rgb), .18); }
:root[data-theme="lys"] .pill { background: rgba(60, 60, 67, .08); }

/* --- glasskrom: arket, docken, panelet, toasten ----------------------------- */
.sheet { border-radius: var(--r-lg) var(--r-lg) 0 0; box-shadow: 0 -24px 70px rgba(0, 0, 0, .55), var(--glass-edge); }
nav.tabs { padding: 6px; background: linear-gradient(180deg, rgba(255, 255, 255, .14), rgba(255, 255, 255, .04) 45%, rgba(0, 0, 0, .08)), var(--glass); box-shadow: 0 20px 50px rgba(0, 0, 0, .5), inset 0 1px 0 rgba(255, 255, 255, .45), inset 0 -1px 0 rgba(0, 0, 0, .25), 0 0 0 .5px rgba(255, 255, 255, .16); }
nav.tabs button { font-size: var(--fs-caption); font-weight: 700; padding: 7px 0 6px; }
.plane-panel, .maplibregl-popup-content { border-radius: var(--r-lg) !important; box-shadow: var(--shadow-lift), inset 0 1px 0 var(--plate-hi), 0 0 0 .5px var(--plate-rim) !important; }
.sheet-modes button { border: 0; background: var(--plate); box-shadow: inset 0 1px 0 var(--plate-hi), 0 0 0 .5px var(--plate-rim); }

/* --- avatarer og ikoner: glans ------------------------------------------- */
.avatar { box-shadow: inset 0 1px 0 rgba(255, 255, 255, .45), inset 0 -8px 14px rgba(0, 0, 0, .18), 0 4px 12px rgba(0, 0, 0, .25); }
.theme-chip .sw { box-shadow: inset 0 1px 0 rgba(255, 255, 255, .35), 0 6px 16px rgba(0, 0, 0, .3); }

/* --- innloggingen: glasskort, kapsler, glansende CTA ------------------------- */
.login-card, #loginView .card { border-radius: var(--r-lg); }
#loginView input { border-radius: 999px; min-height: 46px; padding: 0 18px; font-size: var(--fs-body); border: 0; background: var(--plate); box-shadow: inset 0 1px 0 var(--plate-hi), 0 0 0 .5px var(--plate-rim); color: var(--fg); }
#loginView .btn { min-height: 46px; }

/* --- rader i flykortet: større tall, luft --------------------------------- */
.fc-sub { font-size: var(--fs-caption); letter-spacing: .06em; }
.fc-actions { gap: var(--sp-2); margin-top: var(--sp-3); padding-top: var(--sp-3); }
.funnel .fn b { font-size: var(--fs-big); }
.funnel .fn span { font-size: var(--fs-body); }
.funnel .fn i { font-size: var(--fs-caption); }
.stats-line { font-size: var(--fs-caption); }
.card-note { font-size: var(--fs-caption); }
.empty { font-size: var(--fs-body); }
/* Store titler må vinne over .section-title-regelen (to klasser). */
.section-title.tab-title { font-size: var(--fs-hero); font-weight: 800; letter-spacing: -.03em; color: var(--fg); margin: var(--sp-3) 0 var(--sp-3); line-height: 1.1; }
.search-box input { font-size: var(--fs-body); text-overflow: ellipsis; }
.search-box input::placeholder { color: var(--muted); }
/* Innbygd i appen (Brages skjermbilde 12/9 09:00): den gamle embed-regelen
   nullet søkefeltets bunnmarg, så kapselen sto inntil flisene. Samme luft
   som i nettleseren (12). Og den native flaten har alt en stor tittel —
   webens egen tittel under den var en dublett. */
html.embed .search-wrap { margin-bottom: var(--sp-3); }
html.embed .section-title.tab-title { display: none; }
html.embed .nav-back-row { display: none; }


/* =====================================================================
   SUPPORT-CHAT (Brage 12/9: «tilbakemelding gjøres om til en chat … moderne
   og elegant»). ÉN flate for begge roller: Meldinger-bobler i husets glass.
   Mine bobler bærer aksenten med glans, deres er glassplater med lys ovenfra;
   dagskiller som kapsler; komponisten er en glasslinje med kapselfelt og
   rund send-knapp. Fullskjerm over alt (z 66: over arket og alertene, under
   fxMenu-sløret på 70).
   ===================================================================== */
.chat { position: fixed; inset: 0; z-index: 66; display: flex; flex-direction: column;
  /* Bunnen følger tastaturet (--kb settes av dockChatToKeyboard) — som iMessage. */
  bottom: var(--kb, 0px);
  background: var(--bg); color: var(--fg); animation: chat-in .32s var(--ease-out) both; }
/* Rommet bak boblene lever: en kald glød i toppen og en varmere i bunnen
   (der komposisjonen din sitter) — samme grep som appens fullskjermflater.
   Nok til at svart ikke er dødt, lite nok til at det aldri leses som farge. */
.chat::before { content: ""; position: absolute; inset: 0; pointer-events: none;
  background:
    radial-gradient(130% 46% at 50% -6%, rgba(var(--accent-rgb), .20), transparent 64%),
    radial-gradient(120% 40% at 50% 104%, rgba(var(--accent-rgb), .10), transparent 62%); }
.chat.hidden { display: none; }
.chat.closing { animation: chat-out .2s ease-in both; }
@keyframes chat-in { from { opacity: 0; transform: translateY(28px); } }
@keyframes chat-out { to { opacity: 0; transform: translateY(28px); } }
.chat-head { position: relative; z-index: 2; flex: none; display: flex; align-items: center; gap: 10px;
  padding: calc(8px + var(--sat)) 12px 8px;
  background: linear-gradient(180deg, rgba(255, 255, 255, .10), rgba(255, 255, 255, 0) 60%), var(--glass);
  backdrop-filter: var(--glass-blur); -webkit-backdrop-filter: var(--glass-blur);
  box-shadow: inset 0 -1px 0 var(--line), 0 8px 24px rgba(0, 0, 0, .18); }
.chat-back { width: 40px; height: 40px; border-radius: 999px; border: 0; flex: none; display: grid; place-items: center;
  color: var(--accent); background: var(--plate); cursor: pointer; padding: 0;
  box-shadow: inset 0 1px 0 var(--plate-hi), 0 0 0 .5px var(--plate-rim); transition: transform .14s var(--ease-out); }
.chat-back svg { width: 22px; height: 22px; display: block; }
.chat-back:active { transform: scale(.92); }
.chat-who { flex: 1; min-width: 0; display: flex; align-items: center; gap: 10px; }
.chat-titles { min-width: 0; }
.chat-who .avatar { width: 38px; height: 38px; font-size: var(--fs-lead); }
.avatar.brand { background: linear-gradient(135deg, var(--accent), var(--accent2)); color: #fff; }
.avatar.brand svg { width: 20px; height: 20px; }
.chat-name { font-size: var(--fs-lead); font-weight: 700; letter-spacing: -.01em; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.chat-sub { font-size: var(--fs-caption); color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.chat-act { flex: none; min-height: 36px; padding: 0 14px; border: 0; border-radius: 999px; font: inherit;
  font-size: var(--fs-body); font-weight: 700; color: var(--accent); background: rgba(var(--accent-rgb), .16);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .18); cursor: pointer; transition: transform .14s var(--ease-out); }
.chat-act.done { color: var(--good); background: rgba(var(--good-rgb), .16); }
.chat-act:active { transform: scale(.95); }
.chat-scroll { position: relative; z-index: 1; flex: 1; min-height: 0; overflow-y: auto; -webkit-overflow-scrolling: touch;
  overscroll-behavior: contain; padding: 14px 14px 10px; }
.chat-log { display: flex; flex-direction: column; gap: 3px; min-height: 100%; justify-content: flex-end; }
.chat-day, .chat-time { align-self: center; color: var(--muted); font-size: var(--fs-micro); font-weight: 700;
  letter-spacing: .04em; margin: 12px 0 6px; }
.chat-day { padding: 4px 11px; border-radius: 999px; background: var(--plate); letter-spacing: 0; font-size: var(--fs-caption); font-weight: 600;
  box-shadow: inset 0 1px 0 var(--plate-hi), 0 0 0 .5px var(--plate-rim); }
.chat-tag { display: flex; margin: 4px 0 4px; }
.chat-tag.mine { justify-content: flex-end; }
/* Inne i samtalen HVISKER typechipen (den er en etikett, ikke en feil) —
   i innboksen roper den, for der er den et sorteringssignal. .chat-prefikset
   må til: .sup-kind.k-bug har samme spesifisitet og står senere i fila. */
.chat .chat-tag .sup-kind { background: rgba(var(--muted-rgb), .12); color: var(--muted); }
.msg { position: relative; max-width: 78%; padding: 9px 14px; font-size: var(--fs-lead); line-height: 1.32;
  border-radius: 20px; white-space: pre-wrap; overflow-wrap: anywhere; }
.msg.new { animation: msg-in .28s var(--ease-spring) both; }
@keyframes msg-in { from { opacity: 0; transform: translateY(10px) scale(.96); } }
.msg.theirs { align-self: flex-start;
  background: linear-gradient(180deg, rgba(255, 255, 255, .10), rgba(255, 255, 255, 0) 60%), var(--plate-2);
  box-shadow: inset 0 1px 0 var(--plate-hi), 0 0 0 .5px var(--plate-rim), 0 6px 18px rgba(0, 0, 0, .16); }
.msg.theirs.last { border-bottom-left-radius: 6px; }
.msg.mine { align-self: flex-end; color: var(--on-accent);
  background: linear-gradient(180deg, rgba(255, 255, 255, .24), rgba(255, 255, 255, 0) 55%), linear-gradient(135deg, var(--accent), var(--accent2));
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .5), inset 0 -1px 0 rgba(0, 0, 0, .14), 0 8px 22px rgba(var(--accent-rgb), .30);
  text-shadow: 0 1px 1px rgba(0, 0, 0, .12); }
.msg.mine.last { border-bottom-right-radius: 6px; }
.msg.pending { opacity: .6; }
.msg.welcome { max-width: 86%; }
.chat-status { align-self: flex-end; margin: 2px 6px 0; color: var(--muted); font-size: var(--fs-micro); font-weight: 600; }
/* Tomrommet: merke, hilsen, én linje om hva du kan skrive — sentrert i
   flaten, ikke en foreldreløs boble i bunnen. */
.chat-hero { flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 6px; text-align: center; padding: 24px 18px 32px; animation: msg-in .4s var(--ease-out) both; }
.chat-hero-mark { width: 72px; height: 72px; border-radius: 999px; display: grid; place-items: center; color: #fff; margin-bottom: 8px;
  background: linear-gradient(180deg, rgba(255, 255, 255, .30), rgba(255, 255, 255, 0) 55%), linear-gradient(135deg, var(--accent), var(--accent2));
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .55), 0 16px 40px rgba(var(--accent-rgb), .42); }
.chat-hero-mark svg { width: 34px; height: 34px; }
.chat-hero-t { font-size: var(--fs-title); font-weight: 800; letter-spacing: -.02em; }
.chat-hero-s { font-size: var(--fs-body); color: var(--muted); line-height: 1.45; max-width: 30ch; text-wrap: balance; }
.chat-compose { position: relative; z-index: 2; flex: none; padding: 8px 12px calc(10px + var(--sab));
  background: linear-gradient(180deg, rgba(255, 255, 255, .08), rgba(255, 255, 255, 0) 50%), var(--glass);
  backdrop-filter: var(--glass-blur); -webkit-backdrop-filter: var(--glass-blur);
  box-shadow: inset 0 1px 0 var(--line), 0 -10px 30px rgba(0, 0, 0, .18); }
.chat-kinds { display: flex; gap: 8px; margin: 2px 0 10px; overflow-x: auto; scrollbar-width: none; }
.chat-kinds::-webkit-scrollbar { display: none; }
.chat-kinds button { flex: none; min-height: 34px; padding: 0 14px; border: 0; border-radius: 999px; font: inherit;
  font-size: var(--fs-body); font-weight: 600; color: var(--muted); background: var(--plate); cursor: pointer;
  box-shadow: inset 0 1px 0 var(--plate-hi), 0 0 0 .5px var(--plate-rim); }
.chat-kinds button.active { color: var(--on-accent);
  background: linear-gradient(180deg, rgba(255, 255, 255, .25), rgba(255, 255, 255, 0) 55%), var(--accent);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .5), 0 6px 16px rgba(var(--accent-rgb), .35); }
.chat-bar { display: flex; align-items: flex-end; gap: 8px; }
.chat-bar textarea { flex: 1; min-width: 0; min-height: 42px; max-height: 140px; padding: 10px 16px; margin: 0; border: 0;
  border-radius: 21px; resize: none; font: inherit; font-size: var(--fs-lead); line-height: 1.3; color: var(--fg); outline: 0;
  background: var(--plate); box-shadow: inset 0 1px 0 var(--plate-hi), 0 0 0 .5px var(--plate-rim); box-sizing: border-box; }
.chat-bar textarea::placeholder { color: var(--muted); }
.chat-bar textarea:focus { box-shadow: inset 0 1px 0 var(--plate-hi), 0 0 0 1.5px rgba(var(--accent-rgb), .6), 0 0 0 6px rgba(var(--accent-rgb), .14); }
.chat-send { flex: none; width: 42px; height: 42px; border: 0; border-radius: 999px; display: grid; place-items: center;
  color: #fff; cursor: pointer; padding: 0;
  background: linear-gradient(180deg, rgba(255, 255, 255, .28), rgba(255, 255, 255, 0) 55%), linear-gradient(135deg, var(--accent), var(--accent2));
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .55), 0 8px 20px rgba(var(--accent-rgb), .38);
  transition: transform .14s var(--ease-out), opacity .14s, filter .14s, box-shadow .14s; }
.chat-send svg { width: 20px; height: 20px; display: block; }
.chat-send:active { transform: scale(.9); }
.chat-send[disabled] { opacity: .35; filter: saturate(.3); cursor: default; box-shadow: none; }
.chat.pinned .chat-head { display: none; }        /* native nav eier tittel og tilbake */
:root[data-theme="lys"] .msg.theirs { background: #fff; box-shadow: inset 0 1px 0 #fff, 0 0 0 .5px var(--plate-rim), 0 6px 18px rgba(40, 40, 70, .10); }
:root[data-theme="lys"] .chat-day { background: #fff; }
:root[data-theme="lys"] .chat-head, :root[data-theme="lys"] .chat-compose { box-shadow: inset 0 -1px 0 var(--line), 0 8px 24px rgba(40, 40, 70, .08); }

/* --- merker: uleste som telle-kapsel (aksent, som Meldinger) og en prikk
       på docken/segmentet (rød, som appmerker) ------------------------------ */
.badge { display: inline-grid; place-items: center; min-width: 22px; height: 22px; padding: 0 7px; border-radius: 999px;
  font-size: 12px; font-weight: 700; color: #fff; letter-spacing: 0; font-variant-numeric: tabular-nums; flex: none;
  background: linear-gradient(180deg, rgba(255, 255, 255, .25), rgba(255, 255, 255, 0) 55%), var(--accent);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .4), 0 4px 12px rgba(var(--accent-rgb), .35); }
.badge.hidden { display: none; }
.lrow .badge { margin-left: auto; }
.lrow .badge + .chev { margin-left: 6px; }
.lrow.nav .lr-ico { width: 22px; height: 22px; flex: none; color: var(--accent); }
nav.tabs button.has-dot::after, .adm-seg button.has-dot::after { content: ""; position: absolute; width: 8px; height: 8px;
  border-radius: 50%; background: var(--bad); box-shadow: 0 0 0 2px var(--bg), 0 0 8px rgba(var(--bad-rgb), .8); }
nav.tabs button.has-dot::after { top: 6px; right: calc(50% - 17px); }
.adm-seg button.has-dot { position: relative; }
.adm-seg button.has-dot::after { top: 9px; right: 10px; width: 7px; height: 7px; box-shadow: 0 0 6px rgba(var(--bad-rgb), .7); }

/* --- innboksen: Meldinger-rytme — prikk, navn, forhåndsvisning, tid ------- */
.sup-dot { flex: none; width: 8px; height: 8px; border-radius: 50%; background: transparent; margin-right: -3px; }
.sup-row.unread .sup-dot { background: var(--accent); box-shadow: 0 0 8px rgba(var(--accent-rgb), .8); }
.sup-row .who .dn { gap: 8px; font-weight: 600; }
.sup-row.unread .who .dn { font-weight: 800; }
.sup-name { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.sup-when { margin-left: auto; color: var(--muted); font-size: var(--fs-caption); font-weight: 500; white-space: nowrap; }
.sup-preview { color: var(--muted); font-size: var(--fs-body); line-height: 1.35; margin: 2px 0;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.sup-row.unread .sup-preview { color: var(--fg); }
.sup-you { color: var(--muted); font-weight: 600; }
.sup-row.done { opacity: .7; }
.sup-kind { display: inline-block; flex: none; padding: 2px 8px; border-radius: 999px; font-size: var(--fs-micro); font-weight: 700;
  letter-spacing: .04em; text-transform: uppercase; background: rgba(var(--muted-rgb), .12); color: var(--muted); }
.sup-kind.k-bug { background: rgba(var(--bad-rgb), .16); color: var(--bad); }
.sup-kind.k-idea { background: rgba(var(--accent-rgb), .16); color: var(--accent); }
.sup-kind.k-praise { background: rgba(var(--good-rgb), .16); color: var(--good); }

/* =====================================================================
   LIQUID GLASS — RUNDE 2 (12/9, HANDOFF pkt. 1: «resten av flatene»).
   Samme prinsipper som blokka over: lys ovenfra, kapsler, iOS-skalaen,
   Apples statusfarger, dybde. Flatene: flypanelet + .pg-cellene, kart-
   popupen, Pro-arket, setekartet, admin → Kilder, varselbryterne.
   ===================================================================== */
/* --- flypanelet og kartpopupen: RØRT SÅ LITE SOM MULIG ------------------
   Brage 12/9: «tror du skal være forsiktig med å redesigne popupen som
   kommer når man klikker på et fly. Den er veldig perfeksjonert. Ideen der
   og hvor den er plassert skal vi la være.»

   Runde 2 hadde gitt den større type, mer luft og en ny ✕ — ALT er tatt ut
   igjen, og hodet er ikke rørt: samme nowrap, samme mål, samme rytme.

   Jeg hadde også latt hodet BRYTE, fordi ETA-kapselen kan renne ut av
   panelet når et bredt flyfoto spiser plassen (målt 27 px inn i ✕-en). Den
   endret hvordan den vanlige flaten ser ut — kapselen falt ned på linje to —
   så den er tatt bort igjen. Overflyten er dermed tilbake som før; sier
   Brage fra at han ser den, finnes det en løsning som ikke rører linje én.

   Det eneste som står igjen her er fokusringen: MapLibre gir lukkeknappen
   fokus når popupen åpnes, og nettleserens blå ring tegnet seg rundt ✕-en
   ved hvert trykk. Egen ring, og bare for tastatur. */
.maplibregl-popup-close-button:focus { outline: none; }
.maplibregl-popup-close-button:focus-visible {
  outline: none; box-shadow: 0 0 0 2px rgba(var(--accent-rgb), .75);
}

/* --- Pro-arket: ikon i glansende kapsel, stor tittel, fordelene som
       glassrader med hake (ikke kulepunkter), glansende CTA ------------------ */
.pro-sheet .card.pro-lock { padding: 24px 18px 18px; text-align: center; box-shadow: inset 0 1px 0 var(--plate-hi), 0 0 0 .5px var(--plate-rim), var(--shadow-lift); }
/* Hero-utgaven (sentrert, stort ikon) hører til ARKET. Låsekortene inne
   på Pass/Venner/Varsler beholder base-geometrien over (venstrestilt, 18 px
   ikon) — samme kort som den native ProLockCard ett fanetrykk unna (16/9). */
.pro-sheet .pro-lock-title { flex-direction: column; justify-content: center; gap: 14px; font-size: var(--fs-big); font-weight: 800; letter-spacing: -.02em; margin-bottom: 8px; }
.pro-sheet .pro-lock .pl-ico { width: 56px; height: 56px; padding: 14px; box-sizing: border-box; border-radius: 999px; color: var(--on-accent);
  background: linear-gradient(180deg, rgba(255, 255, 255, .32), rgba(255, 255, 255, 0) 55%), linear-gradient(135deg, var(--accent), var(--accent2));
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .55), 0 12px 30px rgba(var(--accent-rgb), .40); }
.pro-sheet .pro-lock-why { font-size: var(--fs-lead); line-height: 1.4; }
.pro-price { margin: 4px 0 12px; font-weight: 700; font-size: var(--fs-lead); color: var(--fg); }
.founder-card { display: block; margin: 0 0 12px; padding: 13px 14px; border-radius: var(--r-md); text-align: left; text-decoration: none;
  color: #e6c886; background: linear-gradient(135deg, #1c1710, #2a2216); box-shadow: inset 0 0 0 1px rgba(230, 200, 134, .38); font-size: var(--fs-body); line-height: 1.4; }
.founder-card b { display: block; font-size: var(--fs-lead); margin-bottom: 2px; color: #f3dfae; }
.founder-card code { font-weight: 800; letter-spacing: .06em; }
.pro-perks { list-style: none; padding: 0; margin: 16px 0; text-align: left; border-radius: var(--r-md); background: var(--plate);
  box-shadow: inset 0 1px 0 var(--plate-hi), 0 0 0 .5px var(--plate-rim); }
.pro-perks li { display: flex; align-items: center; gap: 12px; margin: 0; padding: 11px 14px; font-size: var(--fs-body); font-weight: 500;
  border-top: 1px solid var(--line); }
.pro-perks li:first-child { border-top: 0; }
.pro-perks li::before { content: ""; flex: none; width: 24px; height: 24px; border-radius: 999px; background-color: rgba(var(--good-rgb), .18);
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Ccircle cx='12' cy='12' r='12'/%3E%3C/svg%3E") center/100% no-repeat;
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Ccircle cx='12' cy='12' r='12'/%3E%3C/svg%3E") center/100% no-repeat;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%2330d158' stroke-width='2.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m7.5 12.3 3 3 6-6.4'/%3E%3C/svg%3E");
  background-size: 15px; background-position: center; background-repeat: no-repeat; }
.pro-sheet .btn.secondary { min-height: 50px; }

/* --- setekartet: glassark med gripehåndtak, runde seter, kapsel-legende --- */
.modal { border: 0; padding: 12px 18px calc(18px + var(--sab));
  background: linear-gradient(180deg, rgba(255, 255, 255, .08), rgba(255, 255, 255, 0) 40%), var(--glass-strong);
  backdrop-filter: var(--glass-blur-strong); -webkit-backdrop-filter: var(--glass-blur-strong);
  box-shadow: 0 -24px 70px rgba(0, 0, 0, .55), inset 0 1px 0 var(--plate-hi), 0 0 0 .5px var(--plate-rim); }
.modal::before { content: ""; display: block; width: 36px; height: 5px; margin: 0 auto 14px; border-radius: 999px; background: rgba(var(--muted-rgb), .35); }
.modal h2 { font-size: var(--fs-big); font-weight: 800; letter-spacing: -.02em; }
.modal .sub { font-size: var(--fs-body); }
.icon-x.modal-x { margin-top: 2px; }
.seat-input { gap: 8px; margin: 12px 0 14px; }
.seat-input input { width: 96px; min-height: 44px; padding: 0 16px; border: 0; border-radius: 999px; text-align: center; font-size: var(--fs-lead); font-weight: 700;
  color: var(--fg); background: var(--plate); box-shadow: inset 0 1px 0 var(--plate-hi), 0 0 0 .5px var(--plate-rim); }
.seat-input input:focus { outline: 0; box-shadow: inset 0 1px 0 var(--plate-hi), 0 0 0 1.5px rgba(var(--accent-rgb), .6); }
.seat-input .btn.small { min-height: 44px; }
.cabin-label { font-size: var(--fs-caption); font-weight: 700; letter-spacing: .08em; margin-bottom: 8px; }
.seat-row { gap: 5px; margin: 3px 0; }
.seat-row .rownum { width: 26px; font-size: var(--fs-caption); }
.seat { width: 28px; height: 28px; border: 0; border-radius: 9px 9px 6px 6px; font-size: var(--fs-caption); color: var(--fg);
  background: linear-gradient(180deg, rgba(255, 255, 255, .10), rgba(255, 255, 255, 0) 60%), var(--plate-2);
  box-shadow: inset 0 1px 0 var(--plate-hi), 0 0 0 .5px var(--plate-rim); }
.seat.aisle-gap { background: transparent; box-shadow: none; }
.seat.business { background: rgba(var(--warn-rgb), .22); color: var(--warn); }
.seat.premium { background: rgba(var(--accent-rgb), .22); color: var(--accent); }
.seat.exit { box-shadow: inset 0 0 0 1.5px var(--good), inset 0 1px 0 var(--plate-hi); }
.seat.mine { color: var(--on-accent); background: linear-gradient(180deg, rgba(255, 255, 255, .3), rgba(255, 255, 255, 0) 55%), var(--accent);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .5), 0 6px 14px rgba(var(--accent-rgb), .45); }
.legend { gap: 8px; margin-top: 16px; }
.legend span { display: inline-flex; align-items: center; gap: 7px; padding: 6px 11px; border-radius: 999px; font-size: var(--fs-caption); font-weight: 600;
  color: var(--fg); background: var(--plate); box-shadow: inset 0 1px 0 var(--plate-hi), 0 0 0 .5px var(--plate-rim); }
.legend i { width: 12px; height: 12px; border-radius: 4px; display: inline-block; border: 0; }
.legend .k-business { background: rgba(var(--warn-rgb), .5); }
.legend .k-premium { background: rgba(var(--accent-rgb), .5); }

/* --- admin → Kilder: rullbar chip-rad (fem chips på 390 uten klem), større IATA --- */
.adm-seg.src-filters { padding: 4px; gap: 4px; flex-wrap: nowrap; overflow-x: auto; scrollbar-width: none; }
.adm-seg.src-filters::-webkit-scrollbar { display: none; }
.adm-seg.src-filters button { flex: 1 0 auto; min-height: 34px; padding: 0 13px; font-size: var(--fs-caption); }
.src-row { padding: 14px 16px; }
.src-head { gap: 9px; }
.src-head b { font-size: var(--fs-lead); }
.src-name { font-size: var(--fs-body); }
.src-age { font-size: var(--fs-caption); }
.src-meta { font-size: var(--fs-caption); margin: 4px 0 10px; }
.src-cov { gap: 6px; }
.cov { padding: 4px 10px; box-shadow: inset 0 1px 0 rgba(255, 255, 255, .12); }

/* --- varselbryterne: iOS-mål (51×31), knott med skygge, fjærende --------- */
.lrow.sw i { width: 51px; height: 31px; background: rgba(120, 120, 128, .32); box-shadow: inset 0 1px 2px rgba(0, 0, 0, .25); transition: background .2s ease; }
.lrow.sw i::after { width: 27px; height: 27px; top: 2px; left: 2px; box-shadow: 0 3px 8px rgba(0, 0, 0, .15), 0 3px 1px rgba(0, 0, 0, .06);
  transition: transform .24s var(--ease-spring); }
.lrow.sw input:checked + i::after { transform: translateX(20px); }
.lrow.sw input:checked + i { box-shadow: inset 0 1px 2px rgba(0, 0, 0, .12), 0 0 12px rgba(var(--accent-rgb), .35); }
/* Lys: bare SPORET er lysere. Uten :not(:checked) slo denne regelen
   (0,3,2) også `.lrow.sw input:checked + i` (0,3,1) — og alle bryterne så
   AV ut på Lys-temaet selv om de sto på (målt i riggen 12/9). */
:root[data-theme="lys"] .lrow.sw input:not(:checked) + i { background: rgba(120, 120, 128, .16); }


/* =====================================================================
   ÉN KANT, OG TETTHET SOM TÅLER DATA (Brage 12/9, skjermbilde fra
   admin-fanen: «dobbel kanter her i admin fanen? Og litt vel zoomet inn?»)

   1. ÉN KANT PER FLATE. En beholder som selv har rand, skal ikke ha barn
      med samme rand — to konsentriske ringer 4 px fra hverandre leses som
      en feil, ikke som dybde. Apples segmentkontroll er et TRAU (fylt, uten
      ring) med en HEIS (fylt, med skygge, uten ring). Randen bæres av ÉN
      av dem, aldri begge.
   2. TETTHETEN AVGJØR SKALAEN. iOS-skalaen er riktig for lister og
      innstillinger, men admin er en TABELL: på 390 px brakk trakt-flisene
      undertekstene over to linjer («+3 siste 7 d ·» / «+3 siste 30 d») og
      radene ble dobbelt så høye. Tallet får være stort — etiketten under
      skal stå på ÉN linje.
   ===================================================================== */
/* --- segmentkontrollen: trau + heis, ingen dobbeltring ------------------- */
.adm-seg {
  padding: 3px; background: rgba(var(--muted-rgb), .12);
  box-shadow: none;
}
.adm-seg button { min-height: 38px; box-shadow: none; }
.adm-seg button.seg-on {
  background: linear-gradient(180deg, rgba(255, 255, 255, .16), rgba(255, 255, 255, .03)), var(--plate-2);
  box-shadow: 0 3px 10px rgba(0, 0, 0, .34);
}
:root[data-theme="lys"] .adm-seg { background: rgba(60, 60, 67, .10); }
:root[data-theme="lys"] .adm-seg button.seg-on { background: #fff; box-shadow: 0 2px 8px rgba(40, 40, 70, .18); }
/* Filterchipene er samme trau — og de RULLER, så de skal ikke ha hver sin ring. */
.adm-seg.src-filters { padding: 3px; }
.adm-seg.src-filters button { min-height: 32px; padding: 0 12px; }

/* --- trakten: stort tall, én linje etikett, én linje undertekst ---------- */
.funnel .fn { padding: 12px 11px 10px; }
.funnel .fn b { font-size: var(--fs-big); letter-spacing: -.02em; line-height: 1.1; }
.funnel .fn span { font-size: var(--fs-caption); font-weight: 650; line-height: 1.25; display: block; margin-top: 2px; }
.funnel .fn i { font-size: var(--fs-micro); line-height: 1.3; display: block; margin-top: 3px; }
.stats-line { font-size: var(--fs-micro); letter-spacing: .08em; }

/* --- radene: identiteten er stor, metadata hvisker på ÉN linje ----------- */
.adm-row .who .dn { font-size: var(--fs-body); }
.adm-row .un, .sup-row .un {
  font-size: var(--fs-caption); white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.sup-row .un { margin-top: 1px; }
.adm-row.card { padding: 12px 14px; }
/* Innbyggede flater (native admin/venner/pass) har ingen dock å konkurrere
   med, men samme tetthet — søkefeltet og segmentet er allerede 44/38. */
html.embed .funnel .fn { padding: 11px 10px 9px; }


/* --- ÉN LINJE, IKKE TO (Brage 12/9: «dobbel kanter») --------------------
   Liquid Glass-laget ga hver flate BÅDE en lys innerlinje øverst
   (inset 0 1px 0 --plate-hi) OG en rand rundt (0 0 0 .5px --plate-rim).
   På en telefon ligger de 1 px fra hverandre og leses som to kanter, ikke
   som materiale. Apples glass har ÉN kant som er lysere øverst.
   Her bæres lyset ovenfra av FYLLET (gradienten som alt ligger der), og
   kanten er den ene randen. Det store krommet (arket, docken, menyene,
   alerten) beholder begge — der ligger linjene langt nok fra hverandre til
   å lese som tykkelse, og de flatene har ingen naboer å konkurrere med. */
.card, .card.list, .funnel .fn, .src-row, .pro-row, .adm-row.card, .pp-card, .past-card,
.sup-row, .msg.theirs, .chat-day, .chat-kinds button, .btn, .date-chip, .search-box,
.apboard-tabs button, .pp-chip, .fc-act, .seat, .legend span, .chat-back, .chat-bar textarea {
  --edge: 0 0 0 .5px var(--plate-rim);
}
.card, .card.list, .funnel .fn, .src-row, .pro-row, .adm-row.card, .pp-card, .past-card, .sup-row {
  background: linear-gradient(180deg, rgba(255, 255, 255, .11), rgba(255, 255, 255, .02) 52%), var(--plate);
  box-shadow: var(--edge), 0 10px 30px rgba(0, 0, 0, .18);
}
:root[data-theme="lys"] .card, :root[data-theme="lys"] .card.list, :root[data-theme="lys"] .funnel .fn,
:root[data-theme="lys"] .src-row, :root[data-theme="lys"] .pro-row, :root[data-theme="lys"] .adm-row.card,
:root[data-theme="lys"] .pp-card, :root[data-theme="lys"] .past-card, :root[data-theme="lys"] .sup-row {
  background: linear-gradient(180deg, #fff, rgba(255, 255, 255, .82) 60%), var(--plate);
  box-shadow: var(--edge), 0 10px 30px rgba(40, 40, 70, .10);
}

/* --- passet: kortene som maler seg selv ------------------------------------
   ⚠️ DENNE BLOKKA MÅ LIGGE ETTER PLATE-REGLENE OVER. Flytter du den opp,
   blir kortene blanke igjen — og `tests/test_pass_paint.py` blir rød.

   `.pp-hero`, `.pp-delay` og `.pp-light` er farga PLATER med LÅST
   tekstfarge (hvit på de to første, #101a35/#37456b på den siste, i alle
   temaer — se ~886 og ~921). De er også `.pp-card`, så de ble feid med i
   de generiske plate-listene over, som både står senere i fila og er mer
   spesifikke: `:root[data-theme="lys"] .pp-card` er (0,3,0) mot `.pp-hero`
   (0,1,0). Fargen tapte, tekstfargen ble liggende.

   Målt 16/9-2026 på bygg 87, og feilen er SPEILVENDT per tema:
     Lys  — hero og forsinkelseskortet ble hvite: hvit tekst på hvitt.
     Mørk — «Mest fløyet» ble kullgrått: marineblå tekst på kull.
   Det var «noen blanke felt» Brage så — to av dem i Lys, en tredje som
   bare viser seg i Mørk, og som ingen hadde meldt.

   Skyggen fulgte samme vei: glans-regelen lå FØR plata og var død, så
   alle tre sto med den generiske flate-skyggen. Den er med her nå.

   Paletten hadde tre hjem (flat gradient ~884, glans ~2661, `.pp-light`
   ~892). Nå har den ett. Nytt farga pass-kort? Legg det HER — aldri i
   plate-listene over. */
:root .pp-card.pp-hero, :root .pp-card.pp-delay {
  border-radius: var(--r-lg);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .45), inset 0 -2px 4px rgba(0, 0, 0, .22),
              0 0 0 .5px rgba(255, 255, 255, .18), var(--shadow-lift);
}
:root .pp-card.pp-hero {
  background: radial-gradient(120% 90% at 10% -10%, rgba(255, 255, 255, .28), rgba(255, 255, 255, 0) 45%),
              linear-gradient(135deg, #1e3fa8 0%, #2a5bd6 50%, #142063 100%);
}
:root .pp-card.pp-delay {
  background: radial-gradient(120% 90% at 10% -10%, rgba(255, 255, 255, .22), rgba(255, 255, 255, 0) 45%),
              linear-gradient(135deg, #8a1d2c 0%, #4a1220 100%);
}
/* Blek plate i ALLE temaer — teksten inni er hardkodet mørk. Beholder den
   generiske kant-/løft-skyggen; det er bare fargen som var borte. */
:root .pp-card.pp-light {
  background: linear-gradient(135deg, #d9e3f8 0%, #eef3fd 100%);
}
.btn { box-shadow: var(--edge), 0 6px 18px rgba(0, 0, 0, .18); }
.btn.secondary { background: linear-gradient(180deg, rgba(255, 255, 255, .14), rgba(255, 255, 255, .03)), var(--plate-2); }
.date-chip, .search-box, .apboard-tabs button, .pp-chip, .fc-act, .chat-kinds button, .chat-back {
  box-shadow: var(--edge);
}
.search-box:focus-within { box-shadow: 0 0 0 1.5px rgba(var(--accent-rgb), .6), 0 0 0 6px rgba(var(--accent-rgb), .14); }
.chat-bar textarea { box-shadow: var(--edge); }
.chat-bar textarea:focus { box-shadow: 0 0 0 1.5px rgba(var(--accent-rgb), .6), 0 0 0 6px rgba(var(--accent-rgb), .14); }
.msg.theirs { box-shadow: var(--edge), 0 6px 18px rgba(0, 0, 0, .16); }
.chat-day, .legend span { box-shadow: var(--edge); }
.seat { box-shadow: var(--edge); }
.seat.exit { box-shadow: inset 0 0 0 1.5px var(--good); }
.seat.mine { box-shadow: 0 6px 14px rgba(var(--accent-rgb), .45); }
.pro-perks { box-shadow: var(--edge); }
.lrow.sw i { box-shadow: inset 0 1px 2px rgba(0, 0, 0, .25); }
/* CTA-en beholder glansen: den ER ett trykkbart objekt, ikke en flate blant
   naboer, og glansen er det som gjør den til hovedhandlingen. */




/* --- FELTER MAN SKRIVER I FÅR EN TYDELIGERE KANT (Brage 12/9) -------------
   «Burde det ikke være en svak kant rundt der man søker og skriver? For at
   det ser mer elegant og glossy ut.» Han har rett: ett-kant-regelen er riktig
   for KORT som ligger side om side (der ble to linjer til en dobbel kant),
   men et inntastingsfelt er ett enkelt objekt uten naboer å konkurrere med —
   der er nettopp den lysende randen pluss et glimt på overkanten det som
   gjør at glasset leser som glass. Litt sterkere rand (.16 mot .10) og en
   hårfin topplinje, bare på flatene du skriver i. */
.search-box, .chat-bar textarea, #loginView input, .seat-input input,
html.embed .search-box, html.embed .chat-bar textarea {
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .14),
              0 0 0 .5px rgba(255, 255, 255, .16),
              inset 0 -1px 0 rgba(0, 0, 0, .18);
}
:root[data-theme="lys"] .search-box, :root[data-theme="lys"] .chat-bar textarea,
:root[data-theme="lys"] #loginView input, :root[data-theme="lys"] .seat-input input {
  box-shadow: inset 0 1px 0 #fff, 0 0 0 .5px rgba(60, 60, 67, .22),
              inset 0 -1px 0 rgba(60, 60, 80, .06);
}
/* `html.embed .search-box` (0,2,1) slo den vanlige `.search-box` (0,1,0), så
   kanten fantes bare i NETTLESEREN — inne i appen sto den gamle mørke brønnen
   igjen (Brage 12/9: «ser fortsatt ikke den runde kanten rundt søk?»).
   Lærdom: en regel som bare skrives for grunnflaten treffer ikke embed. */
.search-box:focus-within, .chat-bar textarea:focus, #loginView input:focus, .seat-input input:focus,
html.embed .search-box:focus-within {
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .14),
              0 0 0 1.5px rgba(var(--accent-rgb), .6),
              0 0 0 6px rgba(var(--accent-rgb), .14);
}


/* =====================================================================
   CHATTEN SOM EN MODERNE MELDINGSAPP (Brage 12/9, skjermbilde fra appen:
   «synes kantene til chatten ikke passer helt. F.eks. der nede? Og det
   oppe? Må være helt lik moderne messenger. Ikke se ut som en gammel
   iPhone»).

   Tre ting gjorde den gammeldags:
   1. BOBLENE GLØDET. En blå glorie rundt hver boble (0 8px 22px accent)
      pluss tekstskygge — det er 2013-skeuomorfisme. Moderne bobler er
      FLATE: rent fyll, ingen kastet skygge, ingen tekstskygge.
   2. TO KANTEDE BÅND. Hodet og komposisjonen var fullbredde plater med
      gradient og hårstrek — to vannrette streker som delte skjermen i
      tre. Moderne: krommet er uskarpt glass UTEN kant, og hårstreken
      dukker bare opp NÅR innhold ligger under den.
   3. GRADIENT FRA BLÅ TIL CYAN. Fint på en CTA, men en samtale skal ha
      ÉN farge. Nå er det aksenten, med et hint lysere øverst.
   ===================================================================== */
/* --- boblene: flate, én farge, ingen glorie -------------------------- */
.msg { padding: 8px 13px; border-radius: 19px; }
.msg.mine {
  background: linear-gradient(180deg,
    color-mix(in srgb, var(--accent) 92%, #fff), var(--accent));
  box-shadow: none; text-shadow: none;
}
.msg.theirs {
  background: var(--plate-2);
  box-shadow: none;
}
:root[data-theme="lys"] .msg.theirs { background: #e9e9eb; color: #1c1c1e; box-shadow: none; }
.msg.mine.last { border-bottom-right-radius: 7px; }
.msg.theirs.last { border-bottom-left-radius: 7px; }

/* --- krommet: glass uten kant; hårstreken kommer når noe ligger under -- */
.chat-head, .chat-compose {
  background: color-mix(in srgb, var(--bg) 72%, transparent);
  backdrop-filter: blur(24px) saturate(1.7);
  -webkit-backdrop-filter: blur(24px) saturate(1.7);
  box-shadow: none;
  transition: box-shadow .18s ease;
}
.chat-head.scrolled { box-shadow: 0 .5px 0 var(--line); }
.chat-compose.lifted { box-shadow: 0 -.5px 0 var(--line); }
:root[data-theme="lys"] .chat-head, :root[data-theme="lys"] .chat-compose {
  background: color-mix(in srgb, #fff 78%, transparent);
}

/* --- komposisjonen: feltet er hovedsaken, knappen er liten ------------ */
.chat-bar { align-items: flex-end; gap: 7px; }
.chat-bar textarea { min-height: 38px; padding: 9px 15px; border-radius: 19px; }
.chat-send { width: 34px; height: 34px; margin-bottom: 2px; box-shadow: none; background: var(--accent); }
.chat-send svg { width: 17px; height: 17px; }
.chat-send[disabled] { background: rgba(var(--muted-rgb), .18); color: var(--muted); opacity: 1; filter: none; }
.chat-back { width: 36px; height: 36px; background: none; box-shadow: none; }
.chat-back svg { width: 24px; height: 24px; }
.chat-head { padding: calc(6px + var(--sat)) 10px 6px; gap: 8px; }
.chat-act { min-height: 32px; padding: 0 13px; font-size: var(--fs-body); }

/* --- dagskilleren: ren tekst, ikke en kapsel ------------------------- */
.chat-day, :root[data-theme="lys"] .chat-day {
  background: none; box-shadow: none; padding: 0; color: var(--muted);
  font-size: var(--fs-caption); font-weight: 600; letter-spacing: .01em;
}


/* =====================================================================
   BEVEGELSEN (Brage 12/9: «kan animasjonen når meldingssiden laster etc
   være litt smoother og mer elegant? Litt mer i Apple-stil?»).

   Å åpne en samtale fra en liste er en NAVIGASJONS-PUSH i iOS, ikke et
   ark som toner opp: flaten kommer inn fra HØYRE, og den du forlot glir
   litt til venstre. Kurven er Apples egen push-kurve
   cubic-bezier(.32,.72,0,1) — treg start, lang utrulling, ingen sprett.
   Boblene fjærer inn fra sitt EGET hjørne (nede høyre for mine, nede
   venstre for deres), slik iMessage gjør, i stedet for å gli rett opp.
   ===================================================================== */
:root { --ios-push: cubic-bezier(.32, .72, 0, 1); }

.chat { animation: chat-push .36s var(--ios-push) both; }
.chat.closing { animation: chat-pop .28s var(--ios-push) both; }
@keyframes chat-push { from { transform: translateX(100%); } }
@keyframes chat-pop { to { transform: translateX(100%); } }
/* Flaten bak glir litt til venstre mens samtalen kommer inn — parallaksen
   som gjør en iOS-push til en push og ikke en overlapping. */
html.chat-open #appView { transform: translateX(-22px); filter: brightness(.82); }
/* Tastaturet oppe: hjem-indikatoren er skjult bak det — ingen luft under feltet (iMessage). */
html.kb-up .chat-compose { padding-bottom: 8px; }
#appView { transition: transform .36s var(--ios-push), filter .36s var(--ios-push); }

/* Boblene: fjærer opp fra sitt eget hjørne, ikke rett opp. */
.msg.new { animation: bubble-in .34s cubic-bezier(.2, .9, .25, 1.06) both; }
.msg.mine.new { transform-origin: 100% 100%; }
.msg.theirs.new { transform-origin: 0 100%; }
@keyframes bubble-in {
  from { opacity: 0; transform: scale(.72) translateY(6px); }
  to { opacity: 1; transform: none; }
}
/* Kvitteringen hvisker seg inn etterpå — den skal aldri sprette. */
.chat-status { animation: fade-in .3s ease-out both; }
@keyframes fade-in { from { opacity: 0; } }
/* Tomrommet toner opp uten å flytte seg: en hilsen som spretter er ikke rolig. */
.chat-hero { animation: fade-in .45s ease-out both; }
/* Dagskilleren kommer stille, sammen med den første bobla. */
.chat-day, .chat-time, .chat-tag { animation: fade-in .3s ease-out both; }

@media (prefers-reduced-motion: reduce) {
  .chat, .chat.closing, .msg.new, .chat-status, .chat-hero,
  .chat-day, .chat-time, .chat-tag { animation: none; }
  #appView { transition: none; }
  html.chat-open #appView { transform: none; filter: none; }
}


/* =====================================================================
   KANT TIL KANT (Brage 12/9: «alt skal gå helt til top! Så det ser moderne
   ut. Overalt.»)

   Den native navigasjonslinja lå OVER webviewet og etterlot en svart stripe
   under statuslinja — flaten begynte ikke på skjermens topp. Med
   `?chrome=none` (bygg 87) skjuler appen linja si, og da må webflaten
   overta to jobber linja gjorde: reservere plass til statuslinja, og tegne
   tittelen. Uten flagget er ingenting endret — dagens App Store-bygg ser
   akkurat som før.
   ===================================================================== */
/* ⚠️ ÉN eier statuslinja, ikke fire. Panelene (`#tab-admin` m.fl.) ligger
   ALLE inni `.sheet-content` (målt), så sto de i samme liste ble insetet
   lagt til to ganger — 59 px på wrapperen og 59 til på panelet. */
html.embed-nochrome .sheet-content { padding-top: var(--sat); }
/* ⚠️ …OG DA MÅ ARKET SLUTTE Å GJØRE DET SAMME. `html.embed-pin .sheet`
   setter `top: calc(8px + var(--sat))` — riktig den gangen den NATIVE
   linja lå over webviewet og arket måtte begynne under statuslinja. Med
   `chrome=none` reserverer panelet over plassen selv, og da ble
   statuslinja talt TO ganger.

   Målt 16/9 på bygg 87 (Brage: «Ting kan flyttes mer opp? Om vi bruker
   hele skjermen gir det mening at alt starter litt mer opp»): med
   `--sat: 59px` havnet «Admin»-tittelen på **198 px** — 67 fra arket,
   59 fra panelet, 12 i margin. Nettleseren kunne ikke vise det, for der
   er `--sat: 0` og dobbelttellingen usynlig.

   Arket starter derfor på de samme 8 pikslene som ellers; panelet eier
   statuslinja alene. */
html.embed-nochrome .sheet { top: 8px; }
/* Tittelen kommer tilbake: den native er borte, og en flate uten navn er
   ikke moderne — den er bare naken. */
html.embed-nochrome .section-title.tab-title { display: block; }
/* Chatten eier hele skjermen: hodet er webbens, og det bærer statuslinja. */
html.embed-nochrome .chat.pinned .chat-head { display: flex; }
html.embed-nochrome .chat-head { padding-top: calc(6px + var(--sat)); }
