/* ============================================================
   Det här är prototypens stilmall (prototype/style.css), kopierad
   till produktionskoden av M1-4 · del skal. Två avsiktliga avsteg
   från prototypen: sökvägarna i @font-face nedan — fonterna ligger
   i ../fonts/ här, inte i fonts/ som i prototypen — och de två
   extra deklarationerna i .view-head h1 (min-width, overflow-wrap),
   se kommentaren vid regeln. Ändras inte fristående; se
   prototype/style.css för originalet och FrontendAssetTests för
   kopians tokenlikhetskontroll.
   ============================================================ */

/* ============================================================
   SalesPortal — prototyp
   Implementerar prototype/DESIGNSPEC.md. Mörkt är enda temat.
   Tokenuppsättningen i :root är spec §4 rakt av.
   ============================================================ */

@font-face {
  font-family: "Inter";
  src: url("../fonts/inter-400.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Inter";
  src: url("../fonts/inter-500.woff2") format("woff2");
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Inter";
  src: url("../fonts/inter-600.woff2") format("woff2");
  font-weight: 600;
  font-style: normal;
  font-display: swap;
}

:root {
  /* Ytor — mörkt är enda temat */
  --bg:            #0e1116;
  --bg-elev:       #161b22;
  --bg-elev-2:     #1c232c;
  --border:        #262d38;
  --border-strong: #333c49;

  /* Text — faint höjd från #6b7885 (3,8:1) till #8090a0 så den klarar AA
     även mot --bg-elev-2, som är den svåraste ytan (hovrad rad, fält). */
  --text:       #e6edf3;
  --text-muted: #9aa7b5;
  --text-faint: #8090a0;   /* 5,28:1 mot --bg-elev · 4,84:1 mot --bg-elev-2 */

  /* Accent — interaktion, aldrig rörelse.
     --accent bär fokusringar och pulser; knappytan är mörkare så att vit
     text klarar AA (5,5:1) även i hovertillstånd, och --accent-ink är den
     ljusare tonen som graf- och sparklinebläck behöver för 3:1 som grafik. */
  --accent:          #6366f1;
  --accent-hover:    #7c7ff5;
  --accent-btn:      #5457e0;   /* vit text 5,50:1 */
  --accent-btn-hover:#4a4dd4;   /* vit text 6,35:1 — hover går mörkare, inte ljusare */
  --accent-ink:      #7c7ff5;   /* 5,12:1 mot --bg-elev */
  --accent-dim:      rgba(99, 102, 241, 0.15);

  /* Signal — rörelse, aldrig interaktion.
     --down ljusad från #f85149 (4,4:1 i vila, 4,0:1 på hovrad rad). */
  --up:        #3fb950;
  --up-dim:    rgba(63, 185, 80, 0.14);
  --down:      #ff7b73;
  --down-dim:  rgba(255, 123, 115, 0.13);
  --flat:      #9aa7b5;    /* "oförändrad" visas som 0 i muted, inte som streck */

  /* Typsnitt */
  --font: "Inter", "Segoe UI", system-ui, -apple-system, sans-serif;
  --mono: ui-monospace, "SF Mono", "Cascadia Mono", "Consolas", monospace;

  --fs-xs:   11px;
  --fs-sm:   13px;
  --fs-base: 14px;
  --fs-md:   16px;
  --fs-lg:   20px;
  --fs-pos:  24px;   /* höjd från 22 — spec §3.2 */
  --fs-xl:   36px;   /* höjd från 28 — spec §3.1, endast domännamnet */

  --fw-normal: 400;
  --fw-medium: 500;
  --fw-bold:   600;

  /* Mellanrum (4 px-bas), form, rörelse */
  --s1: 4px;  --s2: 8px;   --s3: 12px;  --s4: 16px;
  --s5: 24px; --s6: 32px;  --s7: 48px;  --s8: 64px;

  --r-sm: 6px;
  --r-md: 10px;
  --r-lg: 14px;

  --row-h: 48px;

  --dur-fast: 120ms;
  --dur:      200ms;
  --dur-slow: 300ms;
  --ease:     cubic-bezier(0.2, 0, 0, 1);

  /* Topplistens totalhöjd — tabellernas rubrikrader fäster här under */
  --topbar-h: 57px;

  /* Skugga används bara för svävande lager (meny) — se spec §8.2 */
  --shadow-float: 0 8px 24px rgba(0, 0, 0, 0.45);
}

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

/* Bara vikterna 400/500/600 finns laddade. Utan detta reset ärver rubriker
   webbläsarens 700 och får syntetisk fetstil som inte matchar resten. */
h1, h2, h3, h4, h5, h6 { font-size: inherit; font-weight: var(--fw-bold); }

[hidden] { display: none !important; }

html { color-scheme: dark; background: var(--bg); }

body {
  background: var(--bg);
  color: var(--text);
  font-family: var(--font);
  font-size: var(--fs-base);
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}

.num { font-variant-numeric: tabular-nums; }
.mono { font-family: var(--mono); }

/* Kvotsiffror är en av exakt tre mono-platser (spec §5) — samma form i
   tabell, underrad, hjälptext och dialog. */
.qnum {
  font-family: var(--mono);
  font-size: 13px;
  color: var(--text-muted);
}
.qnum strong { color: var(--text); font-weight: var(--fw-bold); }

a { color: inherit; text-decoration: none; }

button, input, textarea, select {
  font: inherit;
  color: inherit;
}

/* Ingen border-radius här: fokusmarkeringen är outline + offset, och radien
   vann över komponenternas egna värden så att hörnen hoppade från 10 px till
   6 px i samma ögonblick som kontrollen fick fokus. */
:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* Nedtonad TLD — sista punktsegmentet i ett domännamn (spec §5) */
.tld { color: var(--text-faint); font-weight: var(--fw-medium); }

/* ============================================================
   Topplist
   ============================================================ */

.topbar {
  position: sticky;
  top: 0;
  z-index: 30;
  background: var(--bg);
  border-bottom: 1px solid var(--border);
  /* Pulsen sveper till translateX(250%) och nådde 140 % av viewportbredden:
     dokumentets scrollWidth växte cykliskt och en horisontell rullningslist
     tändes och släcktes var 1,6:e sekund under hela mätningen. Spåret klipps
     i sidled; clip (inte hidden) låter pulsens 1 px utanför underkanten stå
     kvar och gör inte topplisten till en scrollport. */
  overflow-x: clip;
}
.topbar-inner {
  max-width: 1120px;
  margin: 0 auto;
  padding: 0 var(--s6);
  height: 56px;
  display: flex;
  align-items: center;
  gap: var(--s6);
}

/* Pulsspåret är alltid närvarande (2 px) så layouten aldrig hoppar. */
.topbar .pulse {
  position: absolute;
  left: 0;
  bottom: -1px;
  height: 2px;
  width: 40%;
  background: linear-gradient(90deg, transparent, var(--accent), var(--accent-hover), var(--accent), transparent);
  opacity: 0;
  pointer-events: none;
}
body.measuring-live .topbar .pulse {
  opacity: 1;
  animation: pulse-sweep 1.6s linear infinite;
}
@keyframes pulse-sweep {
  from { transform: translateX(-100%); }
  to   { transform: translateX(250%); }
}

.wordmark {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 15px;
  font-weight: var(--fw-bold);
  letter-spacing: -0.01em;
  white-space: nowrap;
}
.wordmark .mark {
  width: 22px;
  height: 22px;
  border-radius: 7px;
  background: var(--accent);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
}
.wordmark .mark svg { display: block; }

.topnav {
  display: flex;
  gap: var(--s2);
  flex: 1;
}
.topnav a {
  font-size: var(--fs-sm);
  font-weight: var(--fw-medium);
  color: var(--text-muted);
  padding: 6px 12px;
  border-radius: var(--r-sm);
  transition: color var(--dur-fast) var(--ease), background var(--dur-fast) var(--ease);
}
.topnav a:hover { color: var(--text); background: var(--bg-elev-2); }
.topnav a[aria-current="page"] { color: var(--text); background: var(--bg-elev-2); }

/* Användarchipet är en meny (enda posten "Logga ut"), inte en länk —
   som länk till inloggningen loggade ett klick ut en mitt i demon. */
.userchip {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: var(--fs-sm);
  color: var(--text-muted);
  white-space: nowrap;
  background: none;
  border: 1px solid transparent;
  border-radius: var(--r-md);
  padding: 3px 8px 3px 3px;
  cursor: pointer;
  transition: background var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease),
              color var(--dur-fast) var(--ease);
}
.userchip:hover { color: var(--text); background: var(--bg-elev-2); }
.userchip[aria-expanded="true"] { color: var(--text); background: var(--bg-elev-2); border-color: var(--border-strong); }
/* M2-8: enda nya CSS-regeln i den här delen. Prototypens .topnav { flex: 1 } skjuter annars
   chipet åt höger, men .topnav byggs inte förrän M3-5/M7-4 - utan den här regeln skulle chipet
   ligga fastklistrat direkt efter ordmärket. */
.userchip { margin-left: auto; }
.avatar {
  width: 28px;
  height: 28px;
  border-radius: 50%;
  background: var(--bg-elev-2);
  border: 1px solid var(--border-strong);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: var(--fs-xs);
  font-weight: var(--fw-bold);
  color: var(--text-muted);
  letter-spacing: 0.02em;
  flex: none;
}

/* ============================================================
   Sidlayout
   ============================================================ */

.page {
  max-width: 1120px;
  margin: 0 auto;
  padding: var(--s6) var(--s6) var(--s8);
}

/* ============================================================
   Knappar
   ============================================================ */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  height: 44px;
  padding: 0 18px;
  border: none;
  border-radius: var(--r-md);
  font-size: var(--fs-base);
  font-weight: var(--fw-medium);
  cursor: pointer;
  white-space: nowrap;
  transition: background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease),
              border-color var(--dur-fast) var(--ease);
}
.btn-primary { background: var(--accent-btn); color: #ffffff; }
.btn-primary:hover { background: var(--accent-btn-hover); }
/* Spärrad primärknapp ska ligga UNDER ghost-knappen visuellt, inte över:
   i överlåtelsedialogen står "Avbryt" bredvid en blockerad "Överlåt projektet"
   och de två får inte läsa som lika starka (spec §8.2). */
.btn-primary:disabled {
  background: var(--bg-elev-2);
  border: 1px solid var(--border);
  color: var(--text-faint);
  cursor: default;
}
.btn-ghost {
  background: transparent;
  color: var(--text-muted);
  border: 1px solid var(--border);
}
.btn-ghost:hover { color: var(--text); border-color: var(--text-faint); }
/* Dämpad ghost — används för "Avbryt" när dialogen har två verkliga val */
.btn-quiet {
  background: transparent;
  color: var(--text-muted);
  border: none;
  height: 34px;
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-color: var(--border-strong);
}
.btn-quiet:hover { color: var(--text); text-decoration-color: var(--text-faint); }
.btn-sm { height: 34px; padding: 0 13px; font-size: var(--fs-sm); border-radius: var(--r-sm); }

/* ============================================================
   Chip (förbehåll, roll, status) — alltid neutralt
   ============================================================ */

.chip {
  display: inline-block;
  font-size: var(--fs-xs);
  font-weight: var(--fw-medium);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--text-muted);          /* spec §3.5 — faint klarar inte AA i 11 px */
  background: var(--bg-elev);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  padding: 3px 9px;
  white-space: nowrap;
}
.chip-solid { background: var(--bg-elev-2); border-color: var(--border-strong); color: var(--text); }

/* ============================================================
   Vyhuvuden
   ============================================================ */

.backlink {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: var(--fs-sm);
  color: var(--text-muted);
  transition: color var(--dur-fast) var(--ease);
}
.backlink:hover { color: var(--text); }

.view-head {
  display: flex;
  align-items: baseline;
  gap: var(--s4);
  flex-wrap: wrap;
  margin-top: var(--s4);
}
/* min-width och overflow-wrap är ett avsteg mot prototypen (se filens huvudkommentar) - de saknas i
   prototype/style.css. Huvudet är flex (.view-head), och utan min-width: 0 kan ett flexbarn aldrig
   krympa under sin innehållsbredd - en lång domän utan bindestreck sprängde annars sidbredden vid
   380 px i stället för att radbrytas. */
.view-head h1 {
  font-size: var(--fs-xl);
  font-weight: var(--fw-bold);
  letter-spacing: -0.02em;
  line-height: 1.1;
  min-width: 0;
  overflow-wrap: anywhere;
}
.view-head .chip { position: relative; top: -6px; }

.view-meta {
  margin-top: var(--s2);
  font-size: var(--fs-sm);
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
}
.view-meta .sep { color: var(--text-faint); margin: 0 6px; }
/* Mätningschipet bär sin egen gräns via pulsprickan — en middot direkt före
   prickan läser som ett skrivfel, två runda tecken intill varandra. */
/* Pulsprickan är samma komponent här som i projektlistan — samma storlek,
   samma neutrala färg. Pågående mätning är ett tillstånd, och accent betyder
   uteslutande interaktion (spec §6.1); livesignalen bärs av pulslinjen. */
.view-meta .measure { color: var(--text-muted); margin-left: 14px; }

/* Rubrik för listvyerna — 28 px, 36 px är reserverat för domännamnet */
.list-head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--s4);
  flex-wrap: wrap;
}
.list-head h1 {
  font-size: 28px;
  font-weight: var(--fw-bold);
  letter-spacing: -0.015em;
  line-height: 1.2;
}
.list-head .sub {
  margin-top: var(--s2);
  font-size: var(--fs-sm);
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
}
.list-head .sub .sep { color: var(--text-faint); margin: 0 6px; }

/* Pulserande prick — pågående mätning i listtext */
.dot-pulse {
  display: inline-block;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--text-muted);
  margin-right: 6px;
  vertical-align: 1px;
  animation: measurepulse 1.6s ease-in-out infinite;
}
@keyframes measurepulse {
  0%, 100% { opacity: 0.25; }
  50%      { opacity: 1; }
}

/* ============================================================
   Inmatningsfält + kvot
   ============================================================ */

.addbar {
  display: flex;
  align-items: flex-start;
  gap: var(--s3);
  margin-top: var(--s5);
}
/* Fältet och raden under det är en kolumn, inte två syskon över hela
   sidbredden: flerradshinten högerställdes tidigare mot sidans kant, hamnade
   under kvotindikatorn och lästes som en del av kvoten i stället för som en
   instruktion för fältet den beskriver. */
.addcol { flex: 1; min-width: 0; }
.addfield { position: relative; }
.addfield textarea {
  display: block;
  width: 100%;
  resize: none;
  /* Auto: fältet växer med innehållet till taket och scrollar därefter.
     Med overflow:hidden gick rader 9+ inte att nå vid stor inklistring. */
  overflow-y: auto;
  max-height: 200px;
  background: var(--bg-elev-2);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  padding: 11px 14px;
  min-height: 44px;
  line-height: 20px;
  color: var(--text);
  scrollbar-width: thin;
  scrollbar-color: var(--border-strong) transparent;
  transition: border-color var(--dur-fast) var(--ease), box-shadow var(--dur-fast) var(--ease);
}
.addfield textarea::placeholder { color: var(--text-faint); }
.addfield textarea:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-dim);
}
.addfield textarea:disabled { color: var(--text-faint); cursor: not-allowed; }
/* M4-12: kvoten nådd av ett AVVISAT svar spärrar fältet med readOnly, inte disabled - texten ska
   förbli valbar och kopierbar (se lockQuotaField i salesportal.js). Samma dämpade läsning som det
   spärrade läget ovan, så de två spärrformerna ser identiska ut trots olika DOM-tillstånd. */
.addfield textarea:read-only { color: var(--text-faint); cursor: not-allowed; }
.addfield.multiline textarea { line-height: 22px; }

/* Når innehållet taket tonas underkanten ut så att avklippet läses
   som "det finns mer" i stället för som en trasig rad. */
.addfield::after {
  content: "";
  position: absolute;
  left: 1px;
  right: 1px;
  bottom: 1px;
  height: 26px;
  border-radius: 0 0 var(--r-md) var(--r-md);
  background: linear-gradient(to bottom, rgba(28, 35, 44, 0), var(--bg-elev-2));
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--dur-fast) var(--ease);
}
.addfield.scrolling::after { opacity: 1; }

/* Raden under fältet: kvittens till vänster, flerradshint till höger.
   Hinten låg tidigare inne i textarean och täckte sista raden. */
.addfoot {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--s4);
  margin-top: var(--s2);
  min-height: 20px;
}
/* Kvittensen är faint enligt spec §8.3: en överhoppad dubblett är ett neutralt
   utfall och får inte bli den ljusaste texten på ytan. `quotanote` nedan bär
   det stående kvotbeskedet, som inte är övergående. */
.addnote {
  font-size: var(--fs-sm);
  color: var(--text-faint);
}
/* DESIGNSPEC §8.3 väger tyngre än prototypens .notice för det stående
   kvotbeskedet - det är inte övergående och ska därför inte dela nyans
   med kvittensen. */
.addnote.quotanote {
  color: var(--text-muted);
}
.multihint {
  font-size: var(--fs-xs);
  color: var(--text-muted);
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
  opacity: 0;
  transition: opacity var(--dur) var(--ease);
}
.addfoot.multiline .multihint { opacity: 1; }

.quota {
  min-width: 136px;
  padding-top: 3px;
  text-align: right;
}
.quota .label {
  font-size: var(--fs-sm);
  color: var(--text-muted);
}
.quota .bar {
  margin-top: 7px;
  margin-left: auto;
  width: 112px;
  height: 4px;
  border-radius: 2px;
  background: var(--border);
  overflow: hidden;
}
/* Kvotstapeln är tillstånd, inte interaktion — därför neutral, aldrig accent
   (spec §3.4). Fyllnaden är --text-faint: --border-strong gav bara 1,2:1 mot
   spåret och stapeln lästes som ett enfärgat streck. */
.quota .bar i {
  display: block;
  height: 100%;
  border-radius: 2px;
  background: var(--text-faint);
  transition: width var(--dur-slow) var(--ease), background var(--dur) var(--ease);
}
.quota.near .bar i { background: var(--text-muted); }
.quota.full .bar i { background: var(--text); }

/* ============================================================
   Positionskartan — signaturen (spec §8.7)
   ============================================================ */

/* Sidopadding 24 px = tabellradernas padding, så att axelns nollpunkt ligger i
   exakt samma x som kolumnen Sökord. Två identiskt breda kort med olika gutter
   underminerar kartans egen motivering: nya streck ska landa rakt ovanför
   raderna som glider in. */
.pmapcard {
  margin-top: var(--s4);
  background: var(--bg-elev);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  padding: 12px var(--s5);
}
.pmaphead {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--s4);
  margin-bottom: 2px;
}
.pmaphead .lbl {
  font-size: var(--fs-xs);
  font-weight: var(--fw-medium);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--text-muted);
}
/* Hint-texten är kartans enda förklaring och dubbleras ingenstans — muted, inte faint */
.pmaphead .hint { font-size: var(--fs-xs); color: var(--text-muted); }

.pmap svg { display: block; width: 100%; }
/* Axel och avgränsare bar tidigare --border (1,2:1) och försvann på projektor.
   --text-faint vid 0,7 opacitet ger ~3,3:1 — kravet för gränssnittsgrafik. */
.pmap .axis      { stroke: var(--text-faint); stroke-opacity: 0.7; stroke-width: 1; }
.pmap .divider   { stroke: var(--text-faint); stroke-opacity: 0.7; stroke-width: 1; stroke-dasharray: 2 3; }
/* Zonen ska ha en egen yta. --bg-elev-2 mot kortet gav 1,09:1 och försvann
   helt vid skärmdelning; --border-strong ger ~1,5:1 — synlig som en plats,
   fortfarande tyst nog att strecken i den läser som data. */
.pmap .zone      { fill: var(--border-strong); fill-opacity: 0.7; }
.pmap .axislabel { font-family: var(--mono); font-size: 10px; fill: var(--text-muted); }
.pmap .tick      { fill: var(--text); fill-opacity: 0.85; }
.pmap .tick-over { fill: var(--text-faint); fill-opacity: 1; }
/* Bortfiltrerat sökord: strecket blir kvar för helhetsbilden men dämpas.
   0,22 gav 1,9:1 — under 3:1 för grafik som bär information, och strecken är
   fortfarande klickbara kontroller som ska gå att hitta. 0,38 ≈ 3:1. */
.pmap .hit.off .tick { fill-opacity: 0.38; }
.pmap .hit       { cursor: pointer; }
.pmap .hit .hitarea { fill: transparent; }
.pmap .hit:hover .tick,
.pmap .hit:focus .tick { fill-opacity: 1; }
.pmap .hit:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.pmap .tick-enter { animation: tickin var(--dur-slow) var(--ease) both; }
@keyframes tickin { from { opacity: 0; } to { opacity: 1; } }
.pmapsvg:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; border-radius: var(--r-sm); }

/* Miniversion i projektlistan — ren grafik, ingen interaktion */
.pmap-mini svg { width: 180px; height: 32px; }
.pmap-mini .axis, .pmap-mini .divider { stroke-opacity: 0.7; }
.pmap-mini .bin { fill: var(--text); fill-opacity: 0.7; }
.pmap-mini .bin.tick-over { fill: var(--text-faint); fill-opacity: 1; }

/* ============================================================
   Tabellkort (sökord och användare delar form)
   ============================================================ */

.tablecard {
  margin-top: var(--s3);
  background: var(--bg-elev);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
}
/* Utan positionskarta ovanför (tomt projekt) tar tabellkortet dess luft */
#pmapcard[hidden] + .tablecard,
.admtable { margin-top: var(--s5); }

.tabletools {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s4);
  padding: var(--s4) var(--s5);
}
.tabletools .count {
  font-size: var(--fs-sm);
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
}
.tabletools .filter { position: relative; }
.tabletools .filter input {
  width: 220px;
  height: 32px;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  padding: 0 10px 0 30px;
  font-size: var(--fs-sm);
  color: var(--text);
  transition: border-color var(--dur-fast) var(--ease);
}
.tabletools .filter input::placeholder { color: var(--text-faint); }
.tabletools .filter input:focus { outline: none; border-color: var(--accent); }
.tabletools .filter > svg {
  position: absolute;
  left: 9px;
  top: 50%;
  transform: translateY(-50%);
  color: var(--text-faint);
  pointer-events: none;
}

/* Krysset som slutar filtrera. Ligger inne i fältet och tar plats först när
   det finns något att rensa — söktypens inbyggda kryss ser olika ut i olika
   webbläsare och döljs helt i vissa, så vi ritar ett eget. */
.tabletools .filter input { padding-right: 28px; }
.tabletools .filter input::-webkit-search-cancel-button { display: none; }
.filterclear {
  position: absolute;
  right: 5px;
  top: 50%;
  transform: translateY(-50%);
  width: 22px;
  height: 22px;
  display: grid;
  place-items: center;
  border: 0;
  padding: 0;
  border-radius: var(--r-sm);
  background: transparent;
  color: var(--text-faint);
  cursor: pointer;
  transition: color var(--dur-fast) var(--ease), background var(--dur-fast) var(--ease);
}
.filterclear:hover { color: var(--text); background: var(--bg-elev-2); }
.filterclear:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }

/* Notis om att nyss tillagda sökord visas trots filtret. */
.exemptnote {
  font-size: var(--fs-xs);
  color: var(--text-muted);
  white-space: nowrap;
}

/* Ett undantaget sökord markeras diskret i vänsterkanten så att det går att se
   varför raden ligger kvar när filtret säger något annat. */
.row.exempt, tr.exempt, .exempt > .row { box-shadow: inset 2px 0 0 var(--accent); }

/* M5-4b, avvägning 1: en sjunde spårbredd (36px) för åtgärdscellen läggs sist i ALLA fyra
   --cols-deklarationer (den här och de tre i @media-blocken nedan) - åtgärdskolumnen får INTE
   försvinna under samma brytpunkt som döljer url/trend-kolumnerna, F30 måste gå att nå även på en
   smal skärm. */
.kwtable { --cols: minmax(220px, 1.5fr) 96px 100px 88px 88px minmax(190px, 1fr) 36px; }

.thead {
  display: grid;
  grid-template-columns: var(--cols);
  gap: var(--s4);
  align-items: center;
  padding: 0 var(--s5);
  height: 36px;
  border-top: 1px solid var(--border);
  border-bottom: 1px solid var(--border);
  position: sticky;
  top: var(--topbar-h);
  background: var(--bg-elev);
  z-index: 4;
}
.thead > * {
  font-size: var(--fs-xs);
  font-weight: var(--fw-medium);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--text-muted);
  white-space: nowrap;
  /* Ingen rubrik får spilla ut ur kortet: utan detta sköt "7 DAGAR ↕" ut över
     kortkanten på smala skärmar och sorteringsglyfen kapades av kantlinjen.
     `clip` med 4 px marginal och inte `hidden`: cellen ska inte bli en
     scrollport, och fokusringen (2 px med 2 px offset) måste få plats. */
  min-width: 0;
  overflow: clip;
  overflow-clip-margin: 4px;
}
/* Kort rubrikform för smala skärmar — bara en av de två är i DOM-flödet, så
   skärmläsaren läser alltid exakt en etikett. */
.lbl-short { display: none; }
.thead .sortable {
  background: none;
  border: none;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 0;
  text-transform: inherit;
  letter-spacing: inherit;
  font-size: inherit;
  font-weight: inherit;
  color: inherit;
  transition: color var(--dur-fast) var(--ease);
}
.thead .sortable:hover { color: var(--text); }
/* Sorteringsglyfen är ↑/↓ — ▲/▼ betyder positionsrörelse i samma tabell och
   får inte betyda två saker. Pilen visas alltid, så sorterbara rubriker går
   att skilja från icke-sorterbara. */
.thead .sortable .arrow {
  font-size: 10px;
  color: var(--text-faint);
  transition: color var(--dur-fast) var(--ease);
}
.thead .sortable[data-dir] { color: var(--text); }
.thead .sortable[data-dir] .arrow { color: var(--text); }
.th-right { text-align: right; }
.th-right .sortable { justify-content: flex-end; width: 100%; }

/* Ligger rubrikraden överst i kortet bär kortets egen kant linjen */
.tablecard > .grid:first-child > .thead:first-child {
  border-top: none;
  border-radius: var(--r-lg) var(--r-lg) 0 0;
}

/* Text som bara finns för skärmläsare */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
}

.kw + .kw .row { border-top: 1px solid var(--border); }

.row {
  display: grid;
  grid-template-columns: var(--cols);
  gap: var(--s4);
  align-items: center;
  min-height: var(--row-h);
  padding: 5px var(--s5);
  cursor: pointer;
  transition: background var(--dur-fast) var(--ease);
}
.row:hover { background: var(--bg-elev-2); }
.row:focus-visible { outline: none; box-shadow: inset 0 0 0 2px var(--accent); }
.kw.open .row { background: var(--bg-elev-2); }
.kw:last-child .row { border-radius: 0 0 var(--r-lg) var(--r-lg); }
.kw:last-child.open .row { border-radius: 0; }

/* Engångspuls när ett streck i positionskartan klickas. Den startar först när
   scrollningen är klar (se revealRow) och varar 1,8 s, så att markeringen
   fortfarande syns när ögat hinner följa efter från kartan till raden. */
.kw.mappulse .row { animation: rowpulse 1800ms ease-out; }
@keyframes rowpulse {
  from { background-color: var(--accent-dim); }
  to   { background-color: transparent; }
}

.cell-kw {
  font-weight: var(--fw-medium);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.cell-kw .newtag {
  margin-left: 8px;
  font-size: var(--fs-xs);
  font-weight: var(--fw-medium);
  color: var(--text-faint);
  letter-spacing: 0.04em;
}

.cell-pos {
  text-align: right;
  font-size: var(--fs-pos);
  font-weight: var(--fw-bold);
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.015em;
  line-height: 1;
}
.cell-pos .poswrap { position: relative; display: inline-block; padding: 2px 4px; }
.cell-pos .over50 { color: var(--text-faint); font-weight: var(--fw-medium); }
.cell-pos .failed {
  color: var(--text-faint);
  font-weight: var(--fw-normal);
  cursor: help;
}
/* Dagens mätning uteblev men det rapporterade medelvärdet står kvar — den
   uteblivna dagen markeras med en liten ihålig ring FÖRE talet. I upphöjt läge
   till höger lästes raden som "34°", alltså som en enhet eller ett tryckfel,
   och positionssiffran är den enda siffran som vänds mot prospektet. */
.cell-pos .gapmark {
  display: inline-block;
  width: 6px;
  height: 6px;
  margin-right: 7px;
  border-radius: 50%;
  border: 1px solid var(--text-faint);
  vertical-align: 0.3em;
  cursor: help;
}

/* Skimrande platshållare — exakt siffrans höjd så raden inte hoppar.
   Basen är --border, inte --bg-elev-2: annars smälter plattan in i den
   hovrade eller utfällda radens egen bakgrund och tappar sin form. */
.shimmer {
  display: inline-block;
  width: 42px;
  height: 24px;
  border-radius: var(--r-sm);
  background: linear-gradient(100deg, var(--border) 35%, var(--border-strong) 50%, var(--border) 65%);
  background-size: 220% 100%;
  animation: shimmer 1.4s linear infinite;
  vertical-align: middle;
}
@keyframes shimmer {
  from { background-position: 120% 0; }
  to   { background-position: -100% 0; }
}

.pos-land { animation: posland var(--dur-slow) var(--ease); }
@keyframes posland {
  from { opacity: 0; transform: scale(1.08); }
  to   { opacity: 1; transform: scale(1); }
}
.pos-pulse {
  position: absolute;
  inset: -3px -7px;
  border-radius: var(--r-sm);
  background: var(--accent-dim);
  animation: pospulse 700ms ease-out forwards;
  pointer-events: none;
}
@keyframes pospulse {
  from { opacity: 1; }
  to   { opacity: 0; }
}

/* Förändringspill — riktningen bärs av tecken OCH färg */
.pill {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 12px;
  font-weight: var(--fw-medium);
  font-variant-numeric: tabular-nums;
  padding: 2px 8px;
  border-radius: var(--r-sm);
  line-height: 18px;
}
/* Tecknet är den andra informationsbäraren vid färgblindhet och måste
   kunna läsas tvärs över ett mötesbord — 8 px räckte inte. */
.pill .tri { font-size: 10px; font-weight: var(--fw-bold); line-height: 1; transform: translateY(-0.5px); }
.pill-up   { color: var(--up);   background: var(--up-dim); }
.pill-down { color: var(--down); background: var(--down-dim); }
/* "Vi mätte, inget hände" visas som 0 i muted; "vi har inget att jämföra
   med" som streck i faint. Tidigare såg de fem tillstånden likadana ut. */
.pill-flat { color: var(--flat); background: none; padding-left: 2px; cursor: help; }
.pill-none { color: var(--text-faint); background: none; padding-left: 2px; cursor: help; }
/* En ändpunkt utanför topp 50: riktningen är känd, magnituden är det inte.
   Pillen bär därför bara tecknet — ett tal här vore räknat på sentinelvärdet
   51 och kunde lika gärna vara 4 som 400 (Designgrund princip 6). */
.pill-edge { padding: 2px 7px; cursor: help; }
.pill-edge .tri { font-size: 12px; }

.cell-fade { animation: fadein var(--dur-slow) var(--ease); }
@keyframes fadein { from { opacity: 0; } to { opacity: 1; } }

/* Sparkline — bläcket är --accent-ink i full opacitet. --accent vid 0,65
   gav 2,4:1 mot kortytan, under 3:1-kravet för informationsbärande grafik. */
.cell-trend svg { display: block; }
.cell-trend .spark-line   { stroke: var(--accent-ink); }
.cell-trend .spark-dot    { fill: var(--accent-ink); }
.cell-trend .spark-hollow { stroke: var(--text-faint); fill: none; }
.cell-trend .spark-capped { stroke: var(--text-faint); }
.cell-trend .nodata { font-size: var(--fs-xs); color: var(--text-faint); }

/* Rankande URL — mono, domänen dämpad så ögat landar på sidan */
.cell-url {
  font-family: var(--mono);
  font-size: 12px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* Värddelen skrivs bara ut när den avviker från projektets egen domän.
   Annars äter den bredden och trunkerar bort sökvägen, som är det ögat
   ska landa på (spec §8.8). Fullständig URL ligger i title. */
.cell-url .host { color: var(--text-faint); }
.cell-url .path { color: var(--text-muted); }
.cell-url.ownhost .path { color: var(--text); }
.cell-url.none {
  font-family: var(--font);
  font-size: var(--fs-sm);
  color: var(--text-faint);
  cursor: help;
}

.kw.measuring .cell-url,
.kw.measuring .cell-trend { color: var(--text-faint); }

/* M5-4b, avvägning 1: den sjunde cellen, husets enda radåtgärd (F30). Proportionerna och
   färgtrappan speglar .kebab (§9.5) - men utlöser direkt i stället för att öppna en meny, eftersom
   det bara finns en åtgärd. */
.th-act { text-align: right; }
.cell-act { display: flex; justify-content: flex-end; }
.rowact {
  width: 34px;
  height: 34px;
  display: grid;
  place-items: center;
  padding: 0;
  border-radius: var(--r-sm);
  background: transparent;
  border: 1px solid transparent;
  color: var(--text-faint);
  cursor: pointer;
  /* Dämpad till osynlig tills raden hovras eller knappen får fokus (avvägning 13) - 500 alltid
     synliga glyfer bryter mot Designgrundens lugna yta. Ett osynligt men fokuserbart element är
     annars en tillgänglighetsfälla - :focus-visible/:focus-within nedan, plus @media (hover: none),
     garanterar att den ändå går att se. opacity ingår MEDVETET inte i transition: ett tangentbords-
     tabb till knappen ska göra den synlig i samma ögonblick den får fokus, inte efter en
     övertoningsfördröjning - bara färg/kant/bakgrund (det diskreta hover-svaret) toningsanimeras. */
  opacity: 0;
  transition: color var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease),
              background var(--dur-fast) var(--ease);
}
.row:hover .rowact,
.row:focus-within .rowact,
.rowact:focus-visible {
  opacity: 1;
}
.rowact:hover { color: var(--text); border-color: var(--border); background: var(--bg-elev-2); }
.rowact:focus-visible { outline: none; box-shadow: 0 0 0 2px var(--accent); }
/* En spärrad knapp (begäran i luften efter ett klick, avvägning 3) ska stå kvar synlig - annars
   tappar :hover/:focus-within sitt grepp när elementet blir disabled (webbläsare slutar route:a
   pekar-/fokushändelser dit) och knappen skulle osynliggöras mitt i sin egen återkoppling. */
.rowact:disabled { cursor: default; opacity: 1; }
/* Ikonen: två lodräta stänger, ren CSS (inte SVG - se buildDeactivateIcon i salesportal.js för
   varför). Aldrig röd/accent (§6.1) - ärver knappens color, som redan går text-faint → text. */
.rowicon { display: inline-flex; gap: 3px; width: 8px; height: 12px; }
.rowicon .bar { flex: 1; background: currentColor; border-radius: 1px; }
/* Pekskärm saknar hover helt - en knapp som bara syns vid hover vore i praktiken permanent osynlig
   där, inte bara diskret. */
@media (hover: none) {
  .rowact { opacity: 1; }
}

.kw.enter .row { animation: rowin 260ms var(--ease) both; }
@keyframes rowin {
  from { opacity: 0; transform: translateY(-7px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* ============================================================
   Utfälld trendgraf
   ============================================================ */

.detail {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows var(--dur-slow) var(--ease);
}
.kw.open .detail { grid-template-rows: 1fr; }
.detail-inner {
  overflow: hidden;
  min-height: 0;
  background: var(--bg-elev-2);
}
.detail-pad {
  padding: var(--s3) var(--s5) var(--s5);
  opacity: 0;
  transition: opacity var(--dur-slow) var(--ease);
}
.kw.open .detail-pad { opacity: 1; }

.detail-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--s4);
  flex-wrap: wrap;
  padding-bottom: var(--s3);
}
.detail-head .glabel {
  font-size: var(--fs-xs);
  font-weight: var(--fw-medium);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--text-muted);
}
.detail-head .stats {
  font-size: var(--fs-sm);
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
}
.detail-head .stats strong { color: var(--text); font-weight: var(--fw-medium); }
.detail-head .stats .sep { color: var(--text-faint); margin: 0 6px; }

.graph-wrap { position: relative; }
.graph-wrap svg { display: block; width: 100%; }
/* Hjälplinjer i --border gav 1,14:1 och försvann helt vid skärmdelning.
   --text-faint vid 0,7 ger ~3,1:1 mot den utfällda radens --bg-elev-2. */
.graph-grid line  { stroke: var(--text-faint); stroke-opacity: 0.7; }
.graph-cap line   { stroke: var(--text-faint); stroke-dasharray: 3 4; stroke-opacity: 0.85; }
.graph-miss line  { stroke: var(--text-faint); stroke-dasharray: 2 4; stroke-opacity: 0.45; }
.graph-line       { stroke: var(--accent-ink); stroke-width: 2; fill: none; }
.graph-dot        { fill: var(--accent-ink); }
.graph-dot-capped { fill: var(--bg-elev-2); stroke: var(--text-faint); }
.graph-label      { font-family: var(--mono); font-size: 10px; fill: var(--text-muted); }
/* Markör vid den punkt tooltipen gäller — utan den går det inte att se
   vilken av flera intilliggande punkter talet avser. */
.graph-cursor line   { stroke: var(--border-strong); stroke-width: 1; }
.graph-cursor circle { fill: none; stroke: var(--accent-ink); stroke-width: 2; }
.graph-note {
  font-size: var(--fs-sm);
  color: var(--text-muted);
  margin-top: 10px;
}
/* När serien består av en enda punkt, eller aldrig legat inom topp 50, är
   texten huvudsaken och grafen noteringen — inte tvärtom. */
.graph-note.lead {
  margin: 2px 0 12px;
  font-size: var(--fs-base);
  color: var(--text);
  max-width: 64ch;
}
.graph-status {
  font-size: var(--fs-sm);
  color: var(--text-muted);
  padding: 10px 0 4px;
}

.graph-tip {
  position: absolute;
  pointer-events: none;
  background: #0b0e13;
  border: 1px solid var(--border-strong);
  border-radius: var(--r-sm);
  padding: 7px 10px;
  line-height: 1.45;
  white-space: nowrap;
  z-index: 10;
  opacity: 0;
  transition: opacity var(--dur-fast) var(--ease);
}
.graph-tip.visible { opacity: 1; }
.graph-tip .d { color: var(--text-muted); font-size: var(--fs-xs); }
.graph-tip .p { font-weight: var(--fw-bold); font-size: var(--fs-sm); font-variant-numeric: tabular-nums; }
.graph-tip .u {
  color: var(--text-faint);
  font-family: var(--mono);
  font-size: 10.5px;
  max-width: 240px;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* ============================================================
   Tomtillstånd — egen komponent, aldrig en tom tabell
   ============================================================ */

.empty {
  padding: var(--s8) var(--s5);
  text-align: center;
}
.empty h2 {
  font-size: var(--fs-lg);
  font-weight: var(--fw-bold);
  letter-spacing: -0.01em;
}
.empty p {
  margin-top: var(--s2);
  color: var(--text-muted);
}
.empty .btn { margin-top: var(--s5); }

/* ============================================================
   Projektlista
   ============================================================ */

.projlist {
  margin-top: var(--s5);
  background: var(--bg-elev);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
}
.prow {
  display: grid;
  grid-template-columns: minmax(200px, 1.4fr) 180px 110px 150px 130px 20px;
  gap: var(--s4);
  align-items: center;
  min-height: 56px;
  padding: 8px var(--s5);
  cursor: pointer;
  transition: background var(--dur-fast) var(--ease);
}
/* Kolumnrubriker över projektlistan. Samma rutnät som .prow så att varje
   etikett står exakt över sin kolumn. */
.plisthead {
  display: grid;
  grid-template-columns: minmax(200px, 1.4fr) 180px 110px 150px 130px 20px;
  gap: var(--s4);
  align-items: end;
  padding: 0 var(--s5) 8px;
  font-size: var(--fs-xs);
  font-weight: var(--fw-medium);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--text-muted);
}
/* Skalan under rubriken talar om vad staplarnas x-led betyder: bäst position
   till vänster, allt utanför topp 50 längst till höger. */
.plisthead .maplbl { display: flex; flex-direction: column; gap: 3px; }
.plisthead .scale {
  display: flex;
  justify-content: space-between;
  width: 180px;
  text-transform: none;
  letter-spacing: 0;
  color: var(--text-faint);
  font-variant-numeric: tabular-nums;
}
.plisthead .scale span:last-child { color: var(--text-faint); }

.prowitem + .prowitem .prow { border-top: 1px solid var(--border); }
.prow:hover { background: var(--bg-elev-2); }
.prow:focus-visible { outline: none; box-shadow: inset 0 0 0 2px var(--accent); }
.prowitem:first-child .prow { border-radius: var(--r-lg) var(--r-lg) 0 0; }
.prowitem:last-child .prow  { border-radius: 0 0 var(--r-lg) var(--r-lg); }

.prow .domain {
  font-size: var(--fs-md);
  font-weight: var(--fw-medium);
  letter-spacing: -0.005em;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.prow .kwcount {
  font-size: var(--fs-sm);
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
  text-align: right;
}
/* Listans rörelse räknar SÖKORD, tabellens pill räknar PLACERINGAR. Samma
   pillform för båda gjorde "▲8" tvetydig utan någon synlig enhet — här är det
   en räkning i text, och pillformen förblir reserverad för positionsändring. */
.prow .moves {
  display: flex;
  align-items: baseline;
  font-size: var(--fs-sm);
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
/* Signalfärgen sitter på glyfen, inte på hela strängen (spec §9.2). Med
   "▲4 upp" helt i grönt bar projektlistan produktens starkaste färg i 13 px
   över sex rader, medan samma information i tabellen är 12 px på en tonad
   platta — dubbelkodningen bärs av glyf + ord, inte av en färgyta. */
.prow .moves .mv { display: inline-flex; align-items: baseline; gap: 3px; color: var(--text-muted); }
.prow .moves .mv.up .tri   { color: var(--up); }
.prow .moves .mv.down .tri { color: var(--down); }
.prow .moves .tri { font-size: 9px; font-weight: var(--fw-bold); }
.prow .moves .sep { color: var(--text-faint); margin: 0 6px; }
.prow .moves .moveflat { color: var(--text-muted); cursor: help; }
.prow .moves .movenone { color: var(--text-faint); cursor: help; }

/* Tomt projekt: notisen spänner över karta-, antals- och rörelsekolumnerna och
   börjar där minikartan börjar — en vänsterställd text i den högerställda
   antalskolumnen fick raden att se trasig ut i stället för tom. */
.prow .emptycells {
  grid-column: 2 / -2;
  font-size: var(--fs-sm);
  color: var(--text-faint);
}
.prow .measure {
  display: inline-flex;
  align-items: center;
  font-size: var(--fs-sm);
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
}
.prow .chev { color: var(--text-faint); font-size: var(--fs-md); text-align: right; }
.prow .emptynote { font-size: var(--fs-sm); color: var(--text-faint); }

/* ============================================================
   Adminvy
   ============================================================ */

.admtable {
  /* Kostnadskolumnerna bär sina egna rubriker: "SENASTE HELMÅNAD · JULI ↕"
     mäter 185 px och sköt tidigare ut över grannkolumnen. Statuskolumnen
     ("AKTIV" / "SPÄRRAD") lämnar ifrån sig bredden. */
  --acols: minmax(230px, 1.7fr) 92px 148px 188px 148px 44px;
}

.admtable .thead { grid-template-columns: var(--acols); }

/* Radhöjden är 56 px enligt spec §9.5. Varken "Administratör"-chipet eller
   "Kvot nådd" får växa raden — därför fast höjd på chipet och en absolut
   placerad kvotnotis. */
.urow {
  display: grid;
  grid-template-columns: var(--acols);
  gap: var(--s4);
  align-items: center;
  min-height: 56px;
  height: 56px;
  padding: 0 var(--s5);
}
.user + .user .urow { border-top: 1px solid var(--border); }
.urow:hover { background: var(--bg-elev-2); }
.user:last-child .urow { border-radius: 0 0 var(--r-lg) var(--r-lg); }
.user:last-child.open .urow { border-radius: 0; }

.ident { min-width: 0; }
.ident .name {
  font-size: var(--fs-base);
  font-weight: var(--fw-medium);
  line-height: 20px;
  display: flex;
  align-items: center;
  gap: var(--s2);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.ident .name .chip {
  line-height: 14px;
  padding: 1px 7px;
  flex: none;
}
.ident .mail {
  font-size: var(--fs-sm);
  color: var(--text-muted);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.user.blocked .ident .name,
.user.blocked .ident .mail { color: var(--text-muted); }

.ustatus { font-size: var(--fs-sm); color: var(--text-muted); }
.ustatus .invited { color: var(--text-faint); cursor: help; }

.uquota { position: relative; }
.uquota .bar {
  margin-top: 6px;
  width: 64px;
  height: 4px;
  border-radius: 2px;
  background: var(--border);
  overflow: hidden;
}
.uquota .bar i { display: block; height: 100%; border-radius: 2px; background: var(--text-faint); }
.uquota.near .bar i { background: var(--text-muted); }
.uquota.full .bar i { background: var(--text); }
/* Absolut placerad UNDER stapeln så att "Kvot nådd" inte gör raden 6 px högre
   än de andra. Till höger om stapeln hängde etiketten fritt mellan två
   kolumner och såg bortglömd ut (spec §9.5). */
.uquota .capnote {
  position: absolute;
  left: 0;
  top: calc(100% + 3px);
  font-size: var(--fs-xs);
  line-height: 14px;
  color: var(--text-muted);
  white-space: nowrap;
}
.uquota .none { font-size: var(--fs-sm); color: var(--text-muted); }

.ucost {
  text-align: right;
  font-variant-numeric: tabular-nums;
  font-size: var(--fs-base);
}
.ucost.na { color: var(--text-faint); cursor: help; }

.uactions { text-align: right; }
.kebab {
  width: 34px;
  height: 34px;
  padding: 0;
  border-radius: var(--r-sm);
  background: transparent;
  border: 1px solid transparent;
  color: var(--text-muted);
  cursor: pointer;
  font-size: 16px;
  line-height: 1;
  transition: background var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease),
              color var(--dur-fast) var(--ease);
}
.kebab:hover { color: var(--text); border-color: var(--border); background: var(--bg-elev-2); }
.kebab[aria-expanded="true"] { color: var(--text); border-color: var(--border-strong); background: var(--bg-elev-2); }

/* Menyn är ett svävande lager och behöver egen yta plus skugga — med samma
   färg som kortet under lästes den som text ovanpå tabellraderna. */
.menu {
  position: absolute;
  z-index: 50;
  min-width: 216px;
  max-width: 316px;   /* rymmer "Ta bort administratörsrollen" + orsak på en rad */
  background: var(--bg-elev-2);
  border: 1px solid var(--border-strong);
  border-radius: var(--r-md);
  padding: var(--s1);
  box-shadow: var(--shadow-float);
}
.menu button {
  display: block;
  width: 100%;
  text-align: left;
  background: none;
  border: none;
  border-radius: var(--r-sm);
  padding: 8px 10px;
  font-size: var(--fs-sm);
  color: var(--text-muted);
  cursor: pointer;
  transition: background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}
.menu button:hover { background: var(--bg-elev); color: var(--text); }
/* Låst läge bärs inte av grå ton allena — skillnaden mot aktiva poster var
   ~1,3:1 och menyn såg ut som sex likvärdiga val. Hänglåset och den korta
   orsaken är den andra och tredje bäraren. */
.menu button:disabled {
  color: var(--text-faint);
  cursor: default;
  background: none;
  display: flex;
  align-items: center;
  gap: 7px;
}
.menu button .lock { display: inline-flex; flex: none; color: var(--text-faint); }
.menu button .why {
  margin-left: auto;
  padding-left: var(--s2);
  font-size: var(--fs-xs);
  color: var(--text-faint);
  white-space: nowrap;
}
.menu hr { border: none; border-top: 1px solid var(--border-strong); margin: var(--s1) 0; }
.menu .note {
  padding: 4px 10px 6px;
  font-size: var(--fs-xs);
  line-height: 1.4;
  color: var(--text-muted);
}

/* Utfällt projektblock under en användarrad */
.uprojects {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows var(--dur-slow) var(--ease);
}
.user.open .uprojects { grid-template-rows: 1fr; }
.uprojects-inner { overflow: hidden; min-height: 0; background: var(--bg-elev-2); }
/* Blocket ligger 24 px indraget med en kant som visuell klammer. Med samma
   vänsterkant som föräldrarraderna — och --bg-elev-2 mot --bg-elev på 1,09:1 —
   lästes användarens projekt som sex nya toppnivåanvändare. */
.uprojects-pad {
  padding: var(--s3) var(--s5) var(--s4);
  margin-left: var(--s5);
  border-left: 2px solid var(--border-strong);
}
.uprojects h3 {
  font-size: var(--fs-xs);
  font-weight: var(--fw-medium);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--text-muted);
  margin-bottom: var(--s2);
}
/* Samma kolumnraster som adminraderna ovanför. Bara den flexibla första
   kolumnen krymper av indraget, så antal och "Överlåt…" landar på exakt samma
   x som tabellens egna kolumner i stället för att rimma med ingenting. */
.uproj {
  display: grid;
  grid-template-columns: var(--acols);
  gap: var(--s4);
  align-items: center;
  padding: 7px 0;
  font-size: var(--fs-sm);
}
.uproj + .uproj { border-top: 1px solid var(--border); }
.uproj .d { grid-column: 1; font-size: var(--fs-base); font-weight: var(--fw-medium); }
.uproj .n { grid-column: 3; color: var(--text-muted); font-variant-numeric: tabular-nums; }
.uproj .a { grid-column: 5 / span 2; text-align: right; }
.uproj .arch { color: var(--text-faint); font-size: var(--fs-sm); }
.uprojects .noproj { font-size: var(--fs-sm); color: var(--text-faint); }

/* Åtkomstspärr — visas om en icke-administratör når adminvyn (F56, F71).
   Använder tomtillståndets komponent (.empty) så att portalen inte har två
   typsystem för samma sorts yta; kortet är det enda som är eget. */
.denied {
  margin-top: var(--s5);
  background: var(--bg-elev);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
}

/* Kvittensrad efter en genomförd åtgärd i adminvyn */
.adminflash {
  margin-top: var(--s4);
  font-size: var(--fs-sm);
  color: var(--text-muted);
}
.adminflash:empty { display: none; }

/* ============================================================
   Dialoger
   ============================================================ */

dialog {
  margin: auto;
  background: var(--bg-elev);
  color: var(--text);
  border: 1px solid var(--border-strong);
  border-radius: var(--r-lg);
  padding: var(--s5);
  width: min(440px, calc(100vw - 48px));
}
dialog::backdrop { background: rgba(5, 7, 10, 0.65); }
dialog h2 {
  font-size: var(--fs-lg);
  font-weight: var(--fw-bold);
  letter-spacing: -0.015em;
}
dialog .hint {
  margin-top: var(--s2);
  font-size: var(--fs-sm);
  color: var(--text-muted);
}
dialog label {
  display: block;
  margin-top: var(--s4);
  font-size: var(--fs-xs);
  font-weight: var(--fw-medium);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--text-muted);
  margin-bottom: var(--s2);
}
dialog input[type="text"],
dialog input[type="email"],
dialog input[type="number"],
dialog select {
  display: block;
  width: 100%;
  background: var(--bg-elev-2);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  height: 44px;
  padding: 0 14px;
  color: var(--text);
  font-variant-numeric: tabular-nums;
}
/* Selecterna hade webbläsarens egen chevron och OS-lista — det enda ostylade
   systemwidgetet i ett genomdesignat mörkt gränssnitt, med risk för en ljus
   popup vid skärmdelning. Chevronen är inbäddad SVG, ingen extern fil. */
dialog select {
  appearance: none;
  padding-right: 40px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8' fill='none'%3E%3Cpath d='M1.5 1.75 6 6.25l4.5-4.5' stroke='%239aa7b5' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 14px center;
  cursor: pointer;
}
dialog select option { background: var(--bg-elev-2); color: var(--text); }
/* Talfältets native spinner är samma sorts ostylade systemwidget som selecten
   var — och dess pilar är ▲/▼, glyfer som betyder positionsrörelse i den här
   produkten (spec §3.14). Stegningen sker med piltangenter som förut. */
dialog input[type="number"] { appearance: textfield; -moz-appearance: textfield; }
dialog input[type="number"]::-webkit-outer-spin-button,
dialog input[type="number"]::-webkit-inner-spin-button {
  -webkit-appearance: none;
  margin: 0;
}
dialog input::placeholder { color: var(--text-faint); }
dialog input:focus, dialog select:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-dim);
}
dialog .normalized {
  margin-top: var(--s2);
  font-family: var(--mono);
  font-size: 12px;
  color: var(--text-faint);
  min-height: 18px;
}
dialog .normalized strong { color: var(--text-muted); font-weight: var(--fw-bold); }
/* Ett hinder ska läsas, inte anas. Full textstyrka och en neutral markör —
   ingen varningsfärg, eftersom rött är reserverat för nedåtgående rörelse. */
dialog .normalized.problem {
  color: var(--text);
  display: flex;
  align-items: flex-start;
  gap: 7px;
}
dialog .normalized.problem::before {
  content: "!";
  flex: none;
  width: 16px;
  height: 16px;
  margin-top: 1px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  background: var(--bg-elev-2);
  border: 1px solid var(--border-strong);
  color: var(--text-muted);
  font-size: 11px;
  font-weight: var(--fw-bold);
  line-height: 1;
}
/* Blockerande fel — neutral platta, aldrig röd (spec §6.1) */
dialog .blockmsg {
  margin-top: var(--s4);
  background: var(--bg-elev-2);
  border: 1px solid var(--border-strong);
  border-radius: var(--r-md);
  padding: var(--s3) var(--s4);
  font-size: var(--fs-sm);
  color: var(--text-muted);
}
dialog .actions {
  margin-top: var(--s5);
  display: flex;
  justify-content: flex-end;
  gap: var(--s3);
  flex-wrap: wrap;
}
/* Två likvärdiga vägar staplas i full bredd; "Avbryt" är en utväg och ligger
   som diskret textknapp under dem — inte som ett tredje likvärdigt val. */
dialog .actions.stack { flex-direction: column; align-items: stretch; gap: var(--s2); }
dialog .actions.stack .btn { width: 100%; }
dialog .actions.stack .btn-quiet { margin-top: var(--s1); }

/* ============================================================
   Inloggning
   ============================================================ */

.loginpage { min-height: 100vh; display: grid; place-items: center; padding: var(--s6) var(--s5); }
.login { width: 100%; max-width: 380px; }
.login .wordmark { font-size: var(--fs-lg); gap: 12px; }
.login .wordmark .mark { width: 32px; height: 32px; border-radius: 10px; }

.login-map { margin-top: var(--s7); }
.login-map svg { display: block; width: 100%; height: auto; }

.login h1 {
  margin-top: var(--s6);
  font-size: 28px;
  font-weight: var(--fw-bold);
  letter-spacing: -0.02em;
  line-height: 1.15;
}
.login-sub {
  margin-top: var(--s3);
  font-size: var(--fs-base);
  color: var(--text-muted);
}
/* M2-6, §9.1: feltillståndet (?fel=...) renderas i --down på ren --bg - inget kort, ingen
   platta - ovanför knapparna, och ersätter inget annat i layouten. */
.login-error {
  margin-top: var(--s5);
  font-size: var(--fs-base);
  color: var(--down);
}
.login-btns {
  margin-top: var(--s6);
  display: flex;
  flex-direction: column;
  gap: var(--s3);
}
.idbtn {
  display: flex;
  align-items: center;
  gap: var(--s3);
  height: 44px;
  padding: 0 var(--s4);
  background: var(--bg-elev-2);
  border: 1px solid var(--border-strong);
  border-radius: var(--r-md);
  color: var(--text);
  font-size: var(--fs-base);
  font-weight: var(--fw-medium);
  cursor: pointer;
  transition: background var(--dur-fast) var(--ease);
}
.idbtn:hover { background: var(--bg-elev); }
.idbtn svg { display: block; flex: none; }
/* Fotnoten bär ett krav (F08) och sätts därför i --text-muted i stället för --text-faint som
   DESIGNSPEC §9.1 punkt 5 föreskriver - båda tokens klarar AA, så avvikelsen är ett medvetet val
   för extra marginal, inte ett fel. */
.login-foot {
  margin-top: var(--s5);
  font-size: var(--fs-sm);
  color: var(--text-muted);
}

/* ============================================================
   Rörelse av
   ============================================================ */

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
  /* Stillastående platta måste ändå skilja sig från både radens vanliga yta
     och dess hover-yta — annars syns platshållaren knappt alls. */
  .shimmer { animation: none; background: var(--border); box-shadow: inset 0 0 0 1px var(--border-strong); }
  .kw.enter .row { animation: none; }
  .dot-pulse { animation: none; opacity: 0.7; }
  /* Pulsspåret blir en stillastående accentlinje så länge mätning pågår.
     --accent-dim gav ~1,1:1 mot --bg och gick inte att skilja från topplistens
     vanliga kant — livesignalen var i praktiken osläckt. Opak --accent-ink ger
     5,0:1, och 3 px läser som ett tillstånd i stället för som en kant. */
  body.measuring-live .topbar .pulse {
    animation: none;
    width: 100%;
    height: 3px;
    background: var(--accent-ink);
  }
}

/* ============================================================
   Responsivt
   ============================================================ */

/* Inget flexbarn i topplisten får tvinga fram sidbredd: userchipet stack ut
   över högerkanten vid 380 px och gav hela dokumentet horisontell scroll. */
.topbar-inner > * { min-width: 0; }
.wordmark { overflow: hidden; }

@media (max-width: 990px) {
  .kwtable { --cols: minmax(150px, 1.4fr) 84px 84px 76px 76px minmax(120px, 1fr) 36px; }
  .admtable { --acols: minmax(180px, 1.5fr) 100px 132px 120px 120px 40px; }
  /* Kostnadsrubrikerna får inte breda ut sig över grannkolumnen */
  .th-cost .lbl-long { display: none; }
  .th-cost .lbl-short { display: inline; }
  .page { padding: var(--s5) var(--s4) var(--s7); }
  .topbar-inner { padding: 0 var(--s4); }
  .prow { grid-template-columns: minmax(180px, 1.4fr) 110px 150px 130px 20px; }
  .prow .pmap-mini { display: none; }
  .plisthead { display: none; }
  .pmaphead .hint { display: none; }
  /* Under 900 px ryms inte domän + sökväg. Domänen är identisk på varje rad,
     så den faller bort först — sökvägen är kolumnens hela informationsvärde. */
  .cell-url .host { display: none; }
}
@media (max-width: 815px) {
  .page { padding: var(--s4) var(--s3) var(--s7); }
  .topbar-inner { padding: 0 var(--s3); gap: var(--s4); }
  .userchip .uname { display: none; }

  /* Domännamnet får inte spilla över kanten på små skärmar */
  .view-head { gap: var(--s2); }
  .view-head h1 { font-size: 28px; }
  .view-head .chip { top: 0; }

  .addbar { flex-wrap: wrap; }
  .addcol { flex: 1 0 100%; }
  .quota { min-width: 0; flex: 1; }

  /* Kartkortets gutter följer radernas padding hela vägen ned */
  .pmapcard { padding: 10px var(--s4); }

  /* Kolumnerna faller bort i värdeordning: först URL, sedan Trend.
     "Igår" är ett uttryckligt krav (PRD F67) och stannar kvar; sparklinen
     är den enda cell som har en större motsvarighet en klickning bort. */
  .kwtable { --cols: minmax(120px, 1.4fr) 62px 58px 58px 36px; }
  .th-url, .cell-url, .th-trend, .cell-trend { display: none; }
  /* "7 DAGAR ↕" och "POSITION ↕" ryms inte i sina kolumner här och sköt ut
     över kortkanten, där sorteringsglyfen kapades av kantlinjen. De korta
     formerna säger samma sak. */
  .th-d7 .lbl-long, .th-pos .lbl-long { display: none; }
  .th-d7 .lbl-short, .th-pos .lbl-short { display: inline; }
  .row, .thead { padding-left: var(--s4); padding-right: var(--s4); gap: var(--s3); }
  .detail-pad { padding: var(--s3) var(--s4) var(--s4); }
  .tabletools {
    padding: var(--s3) var(--s4);
    flex-direction: column;
    align-items: stretch;
    gap: var(--s2);
  }
  .tabletools .filter input { width: 100%; }

  .prow {
    grid-template-columns: 1fr 90px 20px;
    padding-left: var(--s4);
    padding-right: var(--s4);
  }
  /* Notisen får en egen kolumnbredd på smala skärmar — i 90 px-kolumnen bröts
     "Inga sökord ännu" till två rader mitt i en annars enradig lista. */
  .prow-empty { grid-template-columns: 1fr auto 20px; }
  .prow-empty .emptycells { white-space: nowrap; }
  .prow .moves, .prow .measure, .prow .pmap-mini { display: none; }

  .admtable { --acols: minmax(110px, 1.2fr) 78px 96px 36px; }
  .th-cost, .ucost { display: none; }
  /* "SÖKORD / KVOT ↕" ryms inte i 96 px — kolumnen visar kvoten, rubriken med. */
  .th-quota .lbl-long { display: none; }
  .th-quota .lbl-short { display: inline; }
  .urow { padding-left: var(--s4); padding-right: var(--s4); gap: var(--s3); }
  .uprojects-pad { padding-left: var(--s4); padding-right: var(--s4); margin-left: var(--s4); }
  /* Fyra kolumner kvar: antalet flyttar in i statuskolumnen och knappen tar
     de två sista, så att blocket fortsätter rimma med raderna ovanför. */
  .uproj .n { grid-column: 2; }
  .uproj .a { grid-column: 3 / span 2; }
}

/* Under 480 px är sökfrasen radens identitet och ska offras sist — den bryts
   till två rader i stället för att tre rader i följd läser "badrumsrenove…". */
@media (max-width: 480px) {
  .kwtable { --cols: minmax(0, 1fr) 60px 52px 52px 36px; }
  .row, .thead { padding-left: var(--s3); padding-right: var(--s3); gap: 10px; }
  .thead { height: 34px; }
  .cell-kw {
    white-space: normal;
    overflow: hidden;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    line-height: 1.35;
  }
  .cell-kw .newtag { margin-left: 6px; }
  .row { padding-top: 7px; padding-bottom: 7px; }
  .detail-pad { padding: var(--s3) var(--s3) var(--s4); }
  .prow { padding-left: var(--s3); padding-right: var(--s3); }
  .topbar-inner { gap: var(--s3); }
  .topnav a { padding: 6px 8px; }
  .pmapcard { padding: 10px var(--s3); }

  /* Adminlistan tvingade fram 385 px sidbredd vid 380 px viewport: identiteten
     får krympa fritt och raderna följer tabellens smalare gutter. */
  .admtable { --acols: minmax(0, 1fr) 72px 92px 36px; }
  .urow { padding-left: var(--s3); padding-right: var(--s3); }
  .uprojects-pad { padding-left: var(--s3); padding-right: var(--s3); margin-left: var(--s3); }
}
