:root{
  --ink:#1f2933; --muted:#5b6672; --line:#dfe3e8; --bg:#f4f6f8;
  --panel:#ffffff; --accent:#0b5563; --accent-soft:#e6f0f1;
  --ok:#2f7d4f; --warn:#b5701c; --danger:#a02020; --radius:8px;
}
*{margin:0;padding:0;box-sizing:border-box}
body{font-family:-apple-system,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
  color:var(--ink);background:var(--bg);line-height:1.55;font-size:15px}
/* STEP 2: hævet max-width (1100 -> 1560) så midtersektionen kan blive bredere. */
.app{max-width:1560px;margin:0 auto;padding:24px 20px 60px}
.topbar{background:var(--panel);border:1px solid var(--line);border-radius:var(--radius);
  padding:20px 24px;margin-bottom:18px}
.topbar h1{font-size:20px;font-weight:600;letter-spacing:.2px}
.topbar .sub{color:var(--muted);font-size:13px;margin-top:2px}
.progress{height:6px;background:var(--line);border-radius:99px;margin-top:14px;overflow:hidden}
.progress > i{display:block;height:100%;width:0;background:var(--accent);transition:width .3s}
.progress-text{font-size:12px;color:var(--muted);margin-top:6px}
/* STEP 2: midterkolonne ~fordoblet (1560-loft + 1fr); AI-kolonne 360->340. */
.layout{display:grid;grid-template-columns:230px 1fr 340px;gap:18px;align-items:start}
/* Step rail */
.rail{background:var(--panel);border:1px solid var(--line);border-radius:var(--radius);
  padding:10px;position:sticky;top:16px}
.rail button{display:flex;gap:10px;align-items:center;width:100%;text-align:left;
  border:none;background:transparent;padding:9px 10px;border-radius:6px;cursor:pointer;
  color:var(--muted);font-size:13.5px;font-family:inherit}
.rail button:hover{background:var(--bg);color:var(--ink)}
.rail button.active{background:var(--accent-soft);color:var(--accent);font-weight:600}
.rail .num{display:inline-flex;justify-content:center;align-items:center;width:22px;height:22px;
  border-radius:50%;border:1px solid var(--line);font-size:12px;flex-shrink:0;background:#fff}
.rail button.active .num{border-color:var(--accent);color:var(--accent)}
.rail button.done .num{background:var(--ok);border-color:var(--ok);color:#fff}
/* Panel */
.panel{background:var(--panel);border:1px solid var(--line);border-radius:var(--radius);
  padding:30px 34px;min-height:520px}
.step{display:none}
.step.active{display:block;animation:fade .25s ease}
@keyframes fade{from{opacity:0;transform:translateY(6px)}to{opacity:1;transform:none}}
.step h2{font-size:19px;font-weight:600;color:var(--accent)}
.step .lead{color:var(--muted);font-size:13.5px;margin:6px 0 18px;max-width:64ch}
h3.block{font-size:14px;font-weight:600;margin:24px 0 12px;padding-bottom:6px;
  border-bottom:1px solid var(--line)}
/* Guidance accordion */
details.vejledning{border:1px solid var(--line);border-left:3px solid var(--accent);
  border-radius:6px;background:#fbfdfd;margin:0 0 20px;padding:0}
details.vejledning > summary{cursor:pointer;padding:11px 14px;font-size:13px;font-weight:600;
  color:var(--accent);list-style:none;display:flex;align-items:center;gap:8px;user-select:none}
details.vejledning > summary::-webkit-details-marker{display:none}
details.vejledning > summary::before{content:"▸";font-size:11px;transition:transform .2s}
details.vejledning[open] > summary::before{transform:rotate(90deg)}
details.vejledning .vej-body{padding:0 16px 14px 32px;font-size:13px;color:var(--muted)}
details.vejledning .vej-body p{margin:6px 0}
details.vejledning .vej-body ul{margin:6px 0 6px 18px}
.src{font-size:11px;color:#9aa5af;font-style:italic}
.btn-insert{margin-top:10px;background:var(--accent-soft);color:var(--accent);
  border:none;border-radius:6px;padding:7px 13px;font-size:12.5px;font-weight:600;
  cursor:pointer;font-family:inherit}
.btn-insert:hover{background:#d7e7e8}
/* Forms */
.field{margin-bottom:18px}
label{display:block;font-weight:600;font-size:13.5px;margin-bottom:6px}
input[type=text],input[type=tel],input[type=email],input[type=date],textarea,select{
  width:100%;padding:10px 12px;border:1px solid var(--line);border-radius:6px;
  font-family:inherit;font-size:14px;color:var(--ink);background:#fff}
input:focus,textarea:focus,select:focus{outline:none;border-color:var(--accent);
  box-shadow:0 0 0 3px var(--accent-soft)}
textarea{resize:vertical;min-height:88px}
.two{display:grid;grid-template-columns:1fr 1fr;gap:14px}
/* Unified hazard / add-remove list */
.hz-row{display:flex;align-items:center;gap:10px;padding:8px 10px;border:1px solid var(--line);
  border-radius:6px;margin-bottom:8px;font-size:14px;background:#fff}
.hz-row:hover{background:var(--bg)}
.hz-row input[type=checkbox]{width:16px;height:16px;accent-color:var(--accent);flex-shrink:0}
.hz-row input[type=text]{border:none;background:transparent;padding:2px 0;flex:1}
.hz-row input[type=text]:focus{box-shadow:none}
.hz-row .tag{font-size:11px;color:#9aa5af;border:1px solid var(--line);border-radius:99px;padding:1px 8px}
.hz-row .x{background:none;border:none;color:var(--danger);cursor:pointer;font-size:15px;padding:0 4px}
.addrow{display:flex;gap:8px;margin:4px 0 6px}
.addrow input{flex:1}
.addrow button{white-space:nowrap}
/* Repeatable cards */
.card{border:1px solid var(--line);border-radius:6px;padding:16px;margin-bottom:14px;background:#fcfdfd}
.card-head{display:flex;justify-content:space-between;align-items:center;margin-bottom:12px}
.card-head h4{font-size:14px;color:var(--accent)}
.card .origin{font-size:11px;color:#9aa5af}
/* Map card */
.mapcard{border:1px solid var(--line);border-radius:8px;overflow:hidden;margin-bottom:14px}
.mapcard .maphead{display:flex;justify-content:space-between;align-items:center;
  padding:10px 14px;background:var(--bg);font-size:13px;font-weight:600}
.mapcard iframe{width:100%;height:320px;border:0;display:block;background:#eef1f3}
.mapcard .mapfoot{padding:8px 14px;font-size:12px}
/* Buttons */
.btn{font-family:inherit;font-size:13.5px;font-weight:600;border-radius:6px;
  padding:9px 16px;cursor:pointer;border:1px solid transparent}
.btn-primary{background:var(--accent);color:#fff}
.btn-primary:hover{background:#0a4750}
.btn-ghost{background:#fff;border-color:var(--line);color:var(--ink)}
.btn-ghost:hover{background:var(--bg)}
.btn-add{background:var(--accent-soft);color:var(--accent);border-color:transparent}
.btn-add:hover{background:#d7e7e8}
.btn-del{background:#fff;border-color:var(--line);color:var(--danger);padding:6px 12px;font-size:12.5px}
.btn-del:hover{background:#fbeaea}
/* Table */
table.grid{width:100%;border-collapse:collapse;margin-bottom:8px}
table.grid th,table.grid td{border:1px solid var(--line);padding:10px;text-align:left;vertical-align:top}
table.grid th{background:var(--bg);font-size:13px;font-weight:600;width:210px}
table.grid textarea{min-height:60px;font-size:13px}
/* Footer nav */
.foot{display:flex;justify-content:space-between;gap:12px;margin-top:26px;
  padding-top:18px;border-top:1px solid var(--line)}
.badge{padding:12px 14px;border-radius:6px;font-size:13.5px;font-weight:600;margin-top:14px}

/* ============================================================
   §5 HANDLINGSPLANER – NYE ELEMENTER
   ============================================================ */
.indexcard{border:1px solid var(--line);border-left:3px solid var(--accent);
  border-radius:6px;background:#fbfdfd;padding:12px 16px;margin:0 0 16px}
.indexcard .idx-ttl{font-weight:600;color:var(--accent);margin-bottom:8px;font-size:13px}
.idx-links{display:flex;flex-wrap:wrap;gap:8px}
.idx-link{display:inline-flex;align-items:center;gap:7px;text-decoration:none;
  background:var(--accent-soft);color:var(--accent);border:1px solid var(--line);
  border-radius:16px;padding:4px 12px 4px 5px;font-size:12.5px;transition:.15s}
.idx-link:hover{background:var(--accent);color:#fff;border-color:var(--accent)}
.idx-link:hover .idx-num{background:#fff;color:var(--accent)}
.idx-num{display:inline-flex;align-items:center;justify-content:center;min-width:22px;
  height:22px;border-radius:11px;background:var(--accent);color:#fff;font-size:12px;font-weight:700}
.idx-done{font-size:13px}
.idx-done.ok{color:var(--ok)}
.idx-done.no{color:#c9c9c9}
.haz-badge{display:inline-flex;align-items:center;justify-content:center;min-width:24px;
  height:24px;padding:0 7px;border-radius:12px;background:var(--accent);color:#fff;
  font-size:12.5px;font-weight:700;flex-shrink:0}
.card-head .titlewrap{display:flex;align-items:center;gap:9px}
.card{scroll-margin-top:16px}
.field.handling label{color:var(--accent)}
.field.handling textarea{border-left:3px solid var(--accent)}
.field .hint{font-weight:400;color:#9aa5af}
.xref{font-size:12.5px;color:var(--accent);background:var(--accent-soft);
  border-radius:6px;padding:7px 10px;margin-top:12px}
.xref b{color:var(--ink)}
.attach{margin-top:14px;border-top:1px dashed var(--line);padding-top:12px}
.attach-list{display:flex;flex-wrap:wrap;gap:12px}
.attach-list:not(:empty){margin-bottom:12px}
.attach-head{display:flex;align-items:center;gap:10px;flex-wrap:wrap}
.attach-lbl{font-size:13px;font-weight:600;color:var(--muted)}
.att-item{border:1px solid var(--line);border-radius:8px;padding:8px;max-width:100%;background:#fff}
.att-item img{display:block;width:420px;max-width:100%;height:auto;border-radius:5px;cursor:zoom-in}
.att-pdf{display:flex;align-items:center;gap:10px;width:420px;max-width:100%;cursor:pointer}
.att-pdf .pdf-ico{width:38px;height:46px;flex:0 0 38px;background:var(--danger);color:#fff;
  border-radius:5px;display:flex;align-items:center;justify-content:center;font-size:11px;font-weight:700}
.att-pdf .pdf-name{font-size:13px;color:var(--accent);word-break:break-all}
.att-cap{width:100%;margin-top:8px}
.att-cap input{font-size:12.5px;padding:6px 8px}
.att-row{display:flex;align-items:center;justify-content:space-between;gap:8px;margin-bottom:6px}
.att-remove{border:1px solid var(--line);background:#fff;color:var(--danger);border-radius:5px;
  padding:4px 9px;cursor:pointer;font-size:12px}
.att-remove:hover{background:#fbeaea}
.btn-attach{background:var(--accent-soft);color:var(--accent);border-color:transparent;
  font-size:12.5px;padding:7px 12px}
.btn-attach:hover{background:#d7e7e8}
.backtop{display:inline-block;margin-top:12px;font-size:12px;color:var(--accent);text-decoration:none}
.backtop:hover{text-decoration:underline}
/* Modal / lightbox */
.modal-bg{position:fixed;inset:0;background:rgba(0,0,0,.72);display:none;
  align-items:center;justify-content:center;z-index:100;padding:24px}
.modal-bg.open{display:flex}
.modal-box{background:#fff;border-radius:10px;max-width:92vw;max-height:92vh;
  overflow:auto;position:relative;padding:14px}
.modal-box img{display:block;max-width:86vw;max-height:80vh;height:auto}
.modal-box iframe{width:80vw;height:80vh;border:none}
.modal-close{position:absolute;top:8px;right:8px;background:var(--danger);color:#fff;
  border:none;border-radius:50%;width:32px;height:32px;font-size:18px;cursor:pointer;line-height:1}

@media print{.rail,.foot,.topbar .progress,.topbar .progress-text{display:none}
  .layout{display:block}.step{display:block!important;page-break-inside:avoid}
  details.vejledning{display:none}
  .indexcard,.attach-head,.att-remove,.backtop,.btn-attach,.modal-bg{display:none}
  [data-action="exportJson"],[data-action="importJson"],#importFile{display:none}}
/* STEP 2: breakpoints rebalanceret til bredere footprint (1040 -> 1240). */
@media(max-width:1240px){.layout{grid-template-columns:230px 1fr}.ai-panel{display:none}}
@media(max-width:820px){.layout{grid-template-columns:1fr}.rail{position:static}}
/* ============================================================
   AI-ASSISTENT PANEL  (app.ai.js)
   ============================================================ */
.ai-panel{background:var(--panel);border:1px solid var(--line);
  border-radius:var(--radius);position:sticky;top:16px;
  display:flex;flex-direction:column;overflow:hidden;
  max-height:calc(100vh - 32px)}
.ai-panel[hidden]{display:none}
.ai-head{display:flex;align-items:center;gap:9px;padding:12px 14px;
  background:var(--accent);color:#fff}
.ai-head h3{font-size:14px;font-weight:600;flex:1;margin:0}
.ai-head .model{font-size:11px;opacity:.85}
.ai-dot{width:9px;height:9px;border-radius:50%;background:#c9c9c9;flex-shrink:0;
  box-shadow:0 0 0 3px rgba(255,255,255,.2)}
.ai-dot.ok{background:#8fe6a9}
.ai-dot.warn{background:#ffd27a}
.ai-dot.off{background:#f0a3a3}
.ai-ctx{font-size:11px;background:var(--accent-soft);color:var(--accent);
  padding:7px 14px;border-bottom:1px solid var(--line)}
.ai-ctx b{font-weight:700}
.ai-badge-ai{display:inline-block;font-size:9px;font-weight:700;letter-spacing:.4px;
  text-transform:uppercase;background:var(--accent);color:#fff;
  border-radius:4px;padding:1px 6px;margin-left:6px}
.ai-tone{display:flex;align-items:center;gap:7px;padding:7px 14px;
  border-bottom:1px solid var(--line);font-size:11px;color:var(--muted)}
.ai-seg{display:flex;border:1px solid var(--line);border-radius:6px;overflow:hidden}
.ai-seg button{border:none;background:#fff;font-size:11px;padding:3px 9px;
  cursor:pointer;color:var(--muted);font-family:inherit}
.ai-seg button.on{background:var(--accent);color:#fff}
.ai-group{padding:9px 14px;border-bottom:1px solid var(--line)}
.ai-group .lbl{font-size:10px;text-transform:uppercase;letter-spacing:.6px;
  color:var(--muted);margin-bottom:6px;font-weight:700}
.ai-group .row{display:flex;flex-wrap:wrap;gap:6px}
.ai-pbtn{font-size:12px;border:1px solid var(--line);background:#fff;
  border-radius:6px;padding:6px 10px;cursor:pointer;color:var(--ink);
  font-weight:600;font-family:inherit}
.ai-pbtn:hover{border-color:var(--accent);color:var(--accent)}
.ai-empty{font-size:12px;color:var(--muted)}
.ai-body{flex:1;overflow-y:auto;padding:12px 14px;display:flex;
  flex-direction:column;gap:10px}
.ai-msg{font-size:13px;line-height:1.45}
.ai-msg.bot .bubble{background:var(--bg);border:1px solid var(--line);
  border-radius:8px 8px 8px 2px;padding:9px 11px}
.ai-msg.user{align-self:flex-end;max-width:85%}
.ai-msg.user .bubble{background:var(--accent);color:#fff;
  border-radius:8px 8px 2px 8px;padding:9px 11px}
.ai-tag{display:inline-block;font-size:9px;font-weight:700;letter-spacing:.4px;
  text-transform:uppercase;padding:1px 6px;border-radius:4px;margin-bottom:4px}
.ai-tag.ai{background:var(--accent);color:#fff}
.ai-tag.user{background:var(--muted);color:#fff}
.ai-sugg{border:1px solid var(--line);border-radius:8px;padding:10px;background:#fff}
.ai-sugg .s-txt{font-size:12.5px;color:var(--ink);margin-bottom:8px;line-height:1.4}
.ai-sacts{display:flex;gap:6px;flex-wrap:wrap}
.ai-foot{border-top:1px solid var(--line);padding:10px 12px;display:flex;gap:8px}
.ai-foot input{flex:1;border:1px solid var(--line);border-radius:20px;
  padding:8px 13px;font-size:13px;font-family:inherit}
.ai-foot input:focus{outline:none;border-color:var(--accent);
  box-shadow:0 0 0 3px var(--accent-soft)}
.ai-foot input:disabled{background:var(--bg);color:var(--muted)}
.ai-foot button{background:var(--accent);color:#fff;border:none;border-radius:50%;
  width:36px;height:36px;cursor:pointer;font-size:15px;flex-shrink:0}
.ai-foot button:hover{background:#0a4750}
.ai-foot button:disabled{background:#9db7b9;cursor:default}
.aibtn{font-size:11.5px;border-radius:6px;padding:5px 11px;cursor:pointer;
  font-weight:600;border:1px solid;font-family:inherit}
.aibtn.primary{background:var(--accent);border-color:var(--accent);color:#fff}
.aibtn.primary:hover{background:#0a4750}
.aibtn.ghost{background:#fff;border-color:var(--line);color:var(--ink)}
.aibtn.ghost:hover{border-color:var(--muted)}
.aibtn.danger{background:#fff;border-color:#e4c2c2;color:var(--danger)}
.aibtn.danger:hover{background:#fbeaea}
/* ── INLINE POP-OVER ── */
.panel{position:relative}
.ai-pop{position:absolute;z-index:60;width:330px;max-width:90vw;background:#fff;
  border:1px solid var(--line);border-radius:10px;
  box-shadow:0 10px 30px rgba(0,0,0,.16);padding:12px;display:none}
.ai-pop.show{display:block;animation:aipop .15s ease}
@keyframes aipop{from{opacity:0;transform:translateY(6px)}to{opacity:1;transform:none}}
.ai-pop .p-head{display:flex;align-items:center;gap:6px;font-size:11px;
  color:var(--muted);margin-bottom:7px}
.ai-pop .p-head .ai-tag{margin:0}
.ai-pop .p-txt{font-size:12.5px;line-height:1.45;color:var(--ink);
  background:var(--bg);border-radius:7px;padding:9px;margin-bottom:9px}
.ai-pop textarea.p-edit{width:100%;font-size:12.5px;min-height:84px;margin-bottom:9px}
.ai-pop .p-act{display:flex;gap:6px;flex-wrap:wrap;align-items:center}
.ai-pop .p-count{margin-left:auto;font-size:11px;color:var(--muted)}
/* ── FORTRYD-TOAST ── */
.ai-toast{position:fixed;bottom:20px;left:50%;transform:translateX(-50%);
  background:var(--ink);color:#fff;font-size:13px;padding:10px 16px;
  border-radius:8px;display:flex;gap:12px;align-items:center;z-index:120;
  opacity:0;pointer-events:none;transition:.25s}
.ai-toast.show{opacity:1;pointer-events:auto}
.ai-toast button{background:none;border:none;color:#ffd1d1;font-weight:700;
  cursor:pointer;font-size:13px;font-family:inherit}
[data-k].ai-focused,[data-upd].ai-focused{box-shadow:0 0 0 3px var(--accent-soft)}
.ai-filled-badge{display:inline-block;font-size:9px;font-weight:700;
  text-transform:uppercase;background:var(--accent);color:#fff;
  border-radius:4px;padding:1px 6px;margin-left:6px;vertical-align:middle}

/* ============================================================
   STEP 2 — SAMMENKLAPPELIGT AI-PANEL + AUTO-POP-OVER (forberedelse)
   ============================================================ */
.ai-panel.collapsed .ai-body,
.ai-panel.collapsed .ai-foot,
.ai-panel.collapsed .ai-tone,
.ai-panel.collapsed .ai-group,
.ai-panel.collapsed .ai-acc{display:none}
.ai-collapse-btn{margin-left:auto;background:rgba(255,255,255,.18);border:none;
  color:#fff;border-radius:6px;width:26px;height:26px;cursor:pointer;
  font-size:14px;line-height:1;flex-shrink:0}
.ai-collapse-btn:hover{background:rgba(255,255,255,.3)}
.ai-panel .ai-section-wrap{display:flex;flex-direction:column}
.ai-acc > summary{cursor:pointer;list-style:none;padding:9px 14px;font-size:11px;
  font-weight:700;letter-spacing:.5px;text-transform:uppercase;color:var(--muted);
  border-bottom:1px solid var(--line);display:flex;align-items:center;gap:8px;user-select:none}
.ai-acc > summary::-webkit-details-marker{display:none}
.ai-acc > summary::before{content:"▸";font-size:10px;transition:transform .2s}
.ai-acc[open] > summary::before{transform:rotate(90deg)}
.ai-acc .ai-group:last-child{border-bottom:1px solid var(--line)}
.ai-pop.auto{box-shadow:0 14px 40px rgba(0,0,0,.22)}
.ai-pop .p-loading{font-size:12px;color:var(--muted);font-style:italic}
[data-k].ai-focused.ai-pop-anchor,
[data-upd].ai-focused.ai-pop-anchor{box-shadow:0 0 0 3px var(--accent)}

/* ============================================================
   STEP 4b — POP-OVER HANDLINGS-BAR + CHAT-TYPING (addendum)
   Gør Step 4's auto-pop-over pæn: per-felt-handlingsknapper ombrydes
   pænt, luk-knap i hovedet, og en diskret "skriver"-indikator i chat.
   Rene tilføjelser – ændrer intet eksisterende.
   ============================================================ */
/* Per-felt-handlinger (øverst i pop-over, før forslag vises) */
.ai-pop .p-actions{display:flex;flex-wrap:wrap;gap:6px;margin-bottom:9px}
.ai-pop .p-actions .aibtn{flex:0 0 auto}
/* Luk-knap (✕) i pop-over-hovedet sidder yderst til højre */
.ai-pop .p-head #aiPopX{margin-left:auto;line-height:1}
/* Lille "skriver…"-indikator i chat (pulserende) */
.ai-typing{display:inline-block;letter-spacing:2px;animation:aitype 1s steps(3,end) infinite}
@keyframes aitype{0%{opacity:.3}50%{opacity:1}100%{opacity:.3}}
/* Sikr at loading-tekst i pop-over bruger samme dæmpede stil */
.ai-pop .p-txt.p-loading{background:transparent;padding:4px 2px}

/* Print: skjul alt AI */
@media print{
  .ai-panel,.ai-pop,.ai-toast{display:none !important}
  .layout{grid-template-columns:1fr !important}
}
/* ============================================================
   OPTION A — FELT-ANKRET HANDLINGS-POP-OVER (additions)
   Rene tilføjelser oven på Step 4b. Ændrer INTET eksisterende.
   Styler: (1) handlings-menu som default-tilstand, (2) flip-above
   variant når feltet er tæt på bunden, (3) manglende spinner til
   vente-tilstanden, (4) "← Handlinger"-knap.
   ============================================================ */

/* (1) Handlings-menuen som pop-over'ens default-tilstand.
   Når kun handlingsknapperne vises (før et forslag hentes), giver vi
   dem lidt mere luft og en diskret understreg, så de læses som en menu. */
.ai-pop .p-actions{padding-bottom:9px;border-bottom:1px solid var(--line)}
.ai-pop .p-actions:empty{display:none;padding:0;border:0}
.ai-pop .p-actions .aibtn.primary{margin-left:auto} /* "Generér forslag" yderst */

/* (2) FLIP-ABOVE: når positionPop() tilføjer .above, vender vi
   skygge/animation så pop-over'en "kommer op" nedefra og peger nedad. */
.ai-pop.above{box-shadow:0 -10px 30px rgba(0,0,0,.16)}
.ai-pop.above.show{animation:aipopUp .15s ease}
@keyframes aipopUp{from{opacity:0;transform:translateY(-6px)}to{opacity:1;transform:none}}

/* (3) VENTE-TILSTAND: spinner + layout (lukker tidligere manglende
   .p-spin/.p-wait-regler, så #aiPopWait faktisk viser en snurrende ring). */
.ai-pop .p-wait{display:none;align-items:center;gap:8px;margin-bottom:9px}
.ai-pop .p-spin{width:16px;height:16px;flex:0 0 16px;border-radius:50%;
  border:2px solid var(--accent-soft);border-top-color:var(--accent);
  animation:aispin .7s linear infinite}
@keyframes aispin{to{transform:rotate(360deg)}}
.ai-pop .p-wait-txt{flex:1;font-size:11.5px;color:var(--muted)}

/* (4) "← Handlinger"-knap: skub den væk fra de primære knapper, så
   forslags-handlingsbaren ikke bliver for trang. */
.ai-pop .p-act #aiPopBack{margin-left:4px}
.ai-pop .p-act #aiPopClose{margin-left:4px}

/* ============================================================
   OPTION A — "✨ AI" FELT-CHIP (hover/focus-affordance)  [NY]
   Rene tilføjelser. Ændrer INTET eksisterende.
   En lille chip der toner frem øverst-til-højre på et AI-egnet felt,
   KUN ved hover eller fokus. Klik => app.ai.core.js fokuserer feltet
   og åbner pop-over'en. Harmløs offline (chips monteres ikke uden AI).
   ============================================================ */

/* Wrapper som JS lægger rundt om hvert felt, så chippen kan
   position:absolute-ankres uden at påvirke feltets eget layout.
   display:block + width:100% bevarer feltets fulde bredde. */
.ai-chip-wrap{position:relative;display:block;width:100%}

/* Selve chippen – skjult som udgangspunkt, toner blødt frem. */
.ai-fieldchip{
  position:absolute;top:4px;right:6px;z-index:8;
  display:inline-flex;align-items:center;gap:3px;
  font-family:inherit;font-size:10.5px;font-weight:700;line-height:1;
  letter-spacing:.3px;
  padding:3px 7px 3px 6px;border-radius:999px;cursor:pointer;
  color:var(--accent);background:#fff;
  border:1px solid var(--accent-soft);
  box-shadow:0 1px 3px rgba(0,0,0,.08);
  opacity:0;transform:translateY(-2px);
  transition:opacity .14s ease, transform .14s ease, background .14s ease;
  pointer-events:none;              /* usynlig => ikke klikbar */
}
.ai-fieldchip .spark{font-size:11px;line-height:1}

/* Vis chippen ved hover på feltet, eller når feltet/chippen har fokus. */
.ai-chip-wrap:hover > .ai-fieldchip,
.ai-chip-wrap:focus-within > .ai-fieldchip{
  opacity:1;transform:translateY(0);pointer-events:auto;
}
.ai-fieldchip:hover{background:var(--accent);color:#fff;border-color:var(--accent)}
.ai-fieldchip:focus-visible{outline:2px solid var(--accent);outline-offset:2px;
  opacity:1;transform:translateY(0);pointer-events:auto}

/* For <textarea> sidder chippen lidt højere inde, så den ikke dækker
   tekst; for 1-linjes <input> giver vi feltet lidt højre-luft så
   chippen ikke lægger sig oven på indtastet tekst. */
.ai-chip-wrap > textarea{padding-top:11px}
.ai-chip-wrap > input[type=text],
.ai-chip-wrap > input[type=tel],
.ai-chip-wrap > input[type=email]{padding-right:66px}

/* I tabel-celler (§3/§7) og handlingskort ligger felterne tæt – hold
   chippen diskret og lidt mindre. */
table.grid .ai-chip-wrap > .ai-fieldchip{font-size:10px;padding:2px 6px}

/* Skjul chips ved print og når AI-panelet er væk (smal skærm). */
@media print{.ai-fieldchip{display:none !important}}
@media(max-width:1240px){.ai-fieldchip{display:none !important}}
/* =========================================================
   Lokal Beredskabsplan – AI-LAG · app.ai.core.js   (1/3 af AI-laget)
   ---------------------------------------------------------
   INDLÆSNINGSRÆKKEFØLGE (i index.html):
     app.core.js  →  app.export.js  →
     app.ai.core.js  →  app.ai.ui.js  →  app.ai.actions.js
   Dette er FØRSTE af TRE AI-filer. Den definerer det delte
   namespace window.__AIP samt FUNDAMENTET:
     • Konfiguration/konstanter
     • Delt tilstand
     • Generiske helpers (el/h/api/fejl)
     • Server-status (dot)
     • Kontekst-sporing (focusin/target)
     • Delte action-helpers (checkedHazards/suggestKey)
     • Chat + besked-stream helpers
     • Toast
   UI-laget (panel, pop-over, felt-chips, init) ligger i
   app.ai.ui.js. Handlingslogikken ligger i app.ai.actions.js.
   Begge hægtes på __AIP dér.
   ---------------------------------------------------------
   Laget er HELT VALGFRIT: hvis core ikke er loadet, eller
   serveren/modellen ikke svarer, forbliver #aiPanel skjult og
   værktøjet fungerer præcis som før (100% offline).
   Rører ALDRIG core/export-symboler destruktivt. Skriver kun til
   felter via jeres egne fillIfEmpty()/insertText()/state/save().
   ---------------------------------------------------------
   SPLIT-NOTE: Opdelt fra tidligere app.ai.core.js (som selv var
     delt fra monolitisk app.ai.js). Denne fil = INFRASTRUKTUR.
     app.ai.ui.js = UI/DOM-flade. Ingen adfærdsændring – kun delt
     op, med al delt tilstand/hjælpere på window.__AIP så alle
     filer kan tilgå dem. PATCH 1/3/4/5-kommentarer bevaret.
   ---------------------------------------------------------
   AI-CONFIG-NOTE (NY): Understøtter nu VALG af AI-server-profil
     (fx lokal vs. ekstern Gemma 26B). Frontend sender KUN et
     profil-id – aldrig en URL. Profilerne hentes fra backend
     (/ai/profiles) og det valgte id gemmes i localStorage og
     vedhæftes ALLE /ai/*-kald ét centralt sted (AIP.api). UI-
     dropdownen bygges/vires i app.ai.ui.js. Bagudkompatibelt:
     hvis /ai/profiles ikke svarer, bruges "local" stiltiende.
   ========================================================= */
(function(){
  "use strict";

  /* ---- Guards: hvis core ikke er loadet, gør intet ---- */
  if (typeof state === "undefined" || typeof save !== "function") {
    console.warn("[ai] core ikke fundet – AI-lag deaktiveret.");
    return;
  }

  /* ====== Delt namespace (fælles for core + ui + actions) ====== */
  var AIP = (window.__AIP = window.__AIP || {});

  /* ========== Konfiguration ========== */
  AIP.AI_BASE = "";
  AIP.READY_URL    = AIP.AI_BASE + "/ai/ready";
  AIP.PROFILES_URL = AIP.AI_BASE + "/ai/profiles";   /* NY: liste af server-profiler */
  AIP.SUGGEST_URL  = AIP.AI_BASE + "/ai/suggest";
  AIP.GUIDE_URL    = AIP.AI_BASE + "/ai/guide";
  AIP.IMPROVE_URL  = AIP.AI_BASE + "/ai/improve";
  AIP.CHAT_URL     = AIP.AI_BASE + "/ai/chat";

  AIP.AI_LONG_TIMEOUT = 300000;

  /* PATCH 5: nøgle til at huske accordion åben/lukket */
  AIP.ACC_KEY = "ai_acc_open";

  /* NY: nøgle til at huske valgt AI-server-profil på tværs af reloads */
  AIP.PROFILE_KEY = "ai_profile";

  /* NY: nøgle til at huske AI-konfigurations-blokkens åben/lukket-tilstand */
  AIP.CFG_ACC_KEY = "ai_cfg_open";

  /* OPTION A (NY): etiket på felt-chippen. Ét sted at ændre teksten. */
  AIP.FIELD_CHIP_LABEL = "AI";

  /* Afsnit (0-index, matcher current/goTo) -> label */
  AIP.SECTIONS = [
    "1 · Om planen","2 · Beredskabsgruppen","3 · Roller & ansvar",
    "4 · Hvad kan gå galt","5 · Handlingsplaner","6 · Kontaktliste",
    "7 · Bygningsoverblik","8 · Kommunikation","9 · Vedligeholdelse",
    "10 · Dokumentation"
  ];

  /* PATCH 3: human-læsbar "afsnit N" ud fra 0-index go-mål, så
     beskedtekst ALTID matcher hvor goTo() faktisk navigerer hen. */
  AIP.secLabel = function(go){
    var n = (typeof go==="number" && go>=0 && go<AIP.SECTIONS.length) ? go : 0;
    return "afsnit " + (n+1);
  };

  /* ========== Delt tilstand (tilgås fra alle filer via AIP) ========== */
  AIP.length = "standard";
  AIP.currentTarget = null;
  AIP.pop = { list:[], idx:0, editing:false, target:null };
  AIP.lastInsert = null;
  AIP.serverOk = false;
  AIP.activeCtrl = null;
  AIP.P = {};                      // DOM-referencer sættes i buildPanel() (app.ai.ui.js)

  /* ---- NY: AI-server-profil-tilstand ----
     profiles: [{id,label,model}] hentet fra /ai/profiles.
     activeProfile: id'et der sendes med hvert kald (default "local").
     Læses fra localStorage ved opstart, så valget huskes. */
  AIP.profiles = [];
  AIP.activeProfile = (function(){
    try { return localStorage.getItem(AIP.PROFILE_KEY) || "local"; }
    catch(e){ return "local"; }
  })();

  /* Gem valgt profil (kaldes fra dropdownen i app.ai.ui.js) */
  AIP.setProfile = function(id){
    var AIP = window.__AIP;
    AIP.activeProfile = id || "local";
    try { localStorage.setItem(AIP.PROFILE_KEY, AIP.activeProfile); } catch(e){}
  };

  /* Hent liste af profiler fra backend. Fejler stiltiende (bevarer
     "local"), så UI'et aldrig går i stykker hvis endpointet mangler. */
  AIP.loadProfiles = function(){
    var AIP = window.__AIP;
    return AIP.api(AIP.PROFILES_URL).then(function(d){
      AIP.profiles = (d && Array.isArray(d.profiles)) ? d.profiles : [];
      // Hvis den gemte profil ikke findes i listen, fald tilbage til default.
      var ids = AIP.profiles.map(function(p){ return p.id; });
      if(AIP.profiles.length && ids.indexOf(AIP.activeProfile) === -1){
        AIP.setProfile(d.default || ids[0]);
      }
      return AIP.profiles;
    }).catch(function(){
      AIP.profiles = [];   // stille fallback – dropdownen vises bare ikke
      return AIP.profiles;
    });
  };

  /* ========== Små helpers (delt) ========== */
  AIP.el = function(tag, cls, html){ var e=document.createElement(tag);
    if(cls) e.className=cls; if(html!=null) e.innerHTML=html; return e; };
  AIP.h = function(s){ return (typeof esc==="function") ? esc(s) : String(s==null?"":s); };

  AIP.api = function(url, body, timeoutMs){
    var AIP = window.__AIP;
    /* NY: vedhæft valgt profil-id ÉT centralt sted, så ALLE /ai/*-POST-kald
       (suggest/guide/improve/chat) automatisk arver serveren. Vi muterer
       ikke kalderens objekt – vi bygger et nyt med profile sat, medmindre
       kalderen selv allerede har angivet en. */
    if(body && typeof body === "object" && body.profile == null){
      var merged = {}; for(var k in body){ if(body.hasOwnProperty(k)) merged[k]=body[k]; }
      merged.profile = AIP.activeProfile || "local";
      body = merged;
    }
    var ctrl = (typeof AbortController !== "undefined") ? new AbortController() : null;
    var to = (ctrl && timeoutMs) ? setTimeout(function(){ ctrl.abort(); }, timeoutMs) : null;
    var p = fetch(url, {
      method: body ? "POST" : "GET",
      headers: body ? {"Content-Type":"application/json"} : undefined,
      body: body ? JSON.stringify(body) : undefined,
      signal: ctrl ? ctrl.signal : undefined
    }).then(function(r){
      if(to) clearTimeout(to);
      if(!r.ok){
        return r.json().catch(function(){ return {}; }).then(function(j){
          var e = new Error("HTTP "+r.status);
          e.status = r.status;
          e.serverMsg = (j && j.error) ? j.error : "";
          throw e;
        });
      }
      return r.json();
    }).catch(function(err){
      if(to) clearTimeout(to);
      throw err;
    });
    p.__ctrl = ctrl;
    return p;
  };
  AIP.isAbort = function(err){ return err && (err.name === "AbortError"); };
  AIP.isServerTimeout = function(err){ return err && err.status === 504; };
  AIP.errText = function(err, fallback){
    if(AIP.isAbort(err)){
      return "Svaret tog for lang tid (timeout) eller blev annulleret. "+
             "Prøv igen – første svar kan være langsomt.";
    }
    if(AIP.isServerTimeout(err)){
      return "Modellen nåede ikke at svare i tide (serveren meldte timeout). "+
             "Første svar kan være langsomt – prøv igen.";
    }
    if(err && err.status === 503){
      return "AI-tjenesten (Ollama) kan ikke nås lige nu. Prøv igen om lidt.";
    }
    if(err && err.status === 429){
      return "For mange forespørgsler lige nu. Vent et øjeblik og prøv igen.";
    }
    if(err && err.serverMsg){ return err.serverMsg; }
    return fallback;
  };

  /* ========== Server-status (dot) ========== */
  AIP.checkReady = function(){
    var AIP = window.__AIP, P = AIP.P;
    /* NY: prob den VALGTE profil, så status-prikken + model-labelen
       afspejler netop den server brugeren har valgt i dropdownen.
       GET med query-param (ingen body → profile vedhæftes ikke af api()). */
    var url = AIP.READY_URL + "?profile=" +
              encodeURIComponent(AIP.activeProfile || "local");
    AIP.api(url).then(function(d){
      AIP.serverOk = true;
      P.model.textContent = (d.model||"lokal") + (d.use_model ? "" : " · demo");
      if(d.model_ready){ AIP.setDot("ok","Model klar"); }
      else if(d.ollama_reachable){ AIP.setDot("warn","Model indlæses ved første svar…"); }
      else { AIP.setDot("warn","Demo-tilstand (canned)"); }
    }).catch(function(){
      AIP.serverOk = false;
      AIP.setDot("off","Offline – AI utilgængelig");
    });
  };
  AIP.setDot = function(cls, title){
    var P = window.__AIP.P;
    if(!P.dot) return;
    P.dot.className = "ai-dot " + cls;
    P.dot.title = title;
  };

  /* ========== Kontekst-sporing (delegeret focusin) ========== */
  AIP.onFocusIn = function(e){
    var AIP = window.__AIP;
    var t = e.target;
    var act = t.closest && t.closest('[data-upd="actions"]');
    if(act){
      var i = parseInt(act.dataset.i,10);
      var ak = act.dataset.key;
      if(ak==="symptom"||ak==="action"||ak==="special"){
        AIP.setTarget({el:act, kind:"action", i:i, actKey:ak,
          key:ak, label:AIP.labelFor(act)});
        return;
      }
    }
    var f = t.closest && t.closest("[data-k]");
    if(f){
      AIP.setTarget({el:f, kind:"field", key:f.dataset.k, label:AIP.labelFor(f)});
      return;
    }
  };
  AIP.labelFor = function(input){
    var fld = input.closest(".field, td, th");
    var lab = fld && fld.querySelector("label");
    if(lab) return lab.textContent.replace(/\s+/g," ").trim();
    var row = input.closest("tr");
    var th = row && row.querySelector("th");
    return th ? th.textContent.trim() : (input.dataset.k || input.dataset.key || "felt");
  };

  AIP.setTarget = function(info){
    var AIP = window.__AIP, P = AIP.P;
    document.querySelectorAll(".ai-focused").forEach(function(x){ x.classList.remove("ai-focused"); });
    info.el.classList.add("ai-focused");
    AIP.currentTarget = info;
    P.ctx.innerHTML = "Afsnit: <b>"+ AIP.h(AIP.SECTIONS[current]) +
                      "</b> · Felt: <b>"+ AIP.h(info.label) +"</b>";
    AIP.renderFieldBtns();
  };
  AIP.clearTarget = function(){
    var AIP = window.__AIP, P = AIP.P;
    AIP.currentTarget = null;
    P.field.innerHTML = '<span class="ai-empty">Vælg et felt for at se handlinger…</span>';
  };

  /* ========== Delte helpers som actions-filen bruger ========== */
  AIP.checkedHazards = function(){
    return (state.hazards||[]).filter(function(x){return x.checked;})
                              .map(function(x){return x.label;});
  };
  AIP.suggestKey = function(){
    var AIP = window.__AIP;
    if(!AIP.currentTarget) return "generic";
    return AIP.currentTarget.kind==="action" ? AIP.currentTarget.actKey : AIP.currentTarget.key;
  };

  /* ========== Chat ========== */
  AIP.sendChat = function(){
    var AIP = window.__AIP;
    var inp = document.getElementById("aiChatIn");
    var q = (inp.value||"").trim();
    if(!q) return;
    AIP.addUser(q); inp.value="";
    AIP.addBot("…");
    AIP.api(AIP.CHAT_URL, { question:q, context:"Afsnit: "+AIP.SECTIONS[current]+
      "; Forening: "+(state.fields.orgName||"") }, AIP.AI_LONG_TIMEOUT)
      .then(function(d){ AIP.replaceLastBot(AIP.h(d.reply||"(intet svar)")); })
      .catch(function(err){
        AIP.replaceLastBot(AIP.h(AIP.errText(err, "Kunne ikke nå assistenten (offline).")));
      });
  };

  /* ========== Besked-stream helpers (delt) ========== */
  AIP.addBot = function(html){
    var P = window.__AIP.P;
    var d = window.__AIP.el("div","ai-msg bot",
      '<span class="ai-tag ai">AI</span><div class="bubble">'+html+'</div>');
    P.body.appendChild(d); P.body.scrollTop=P.body.scrollHeight; return d;
  };
  AIP.addUser = function(txt){
    var AIP = window.__AIP, P = AIP.P;
    var d = AIP.el("div","ai-msg user",
      '<span class="ai-tag user">Du</span><div class="bubble">'+AIP.h(txt)+'</div>');
    P.body.appendChild(d); P.body.scrollTop=P.body.scrollHeight; return d;
  };
  AIP.replaceLastBot = function(html){
    var P = window.__AIP.P;
    var bots = P.body.querySelectorAll(".ai-msg.bot");
    var last = bots[bots.length-1];
    if(last){ last.querySelector(".bubble").innerHTML = html; }
    else window.__AIP.addBot(html);
    P.body.scrollTop = P.body.scrollHeight;
  };

  /* ========== Toast ========== */
  var toastT;
  AIP.showToast = function(msg){
    var P = window.__AIP.P;
    document.getElementById("aiToastMsg").textContent = msg;
    P.toast.classList.add("show");
    clearTimeout(toastT);
    toastT = setTimeout(function(){ P.toast.classList.remove("show"); }, 5000);
  };

})();
