
.nov7-banner{background:#143026;color:#f4fff8;border-radius:12px;padding:8px 12px;font-size:14px;margin:0 0 12px}
.nov7-top{display:flex;justify-content:space-between;align-items:center;gap:12px;margin:0 0 12px;flex-wrap:wrap}
.nov7-board{display:grid;grid-template-columns:repeat(5,minmax(0,1fr));gap:12px;align-items:stretch}
.kcard{background:var(--card,#fff);border:1px solid var(--line,#d5e0d8);border-radius:16px;min-height:220px;height:100%;padding:12px;display:flex;flex-direction:column;gap:4px;min-width:0;box-sizing:border-box}
.kcard h3{margin:0;font-size:15px}
.kcard .val b{font-size:28px;letter-spacing:-.03em}
.kcard .dir,.kcard .period,.nov7-note{color:var(--mut,#3e5248);font-size:12px;margin:0}
.kcard .plot{width:100%;height:132px}
.kcard .ln{fill:none;stroke:#0f766e;stroke-width:2}
.kcard .trendline{fill:none;stroke:#1d4ed8;stroke-width:2;stroke-dasharray:7 4}
.kcard .bar{fill:#1f6f43}.kcard .bar.partial{fill:#8fbfa4}
.kcard .dot{fill:#0f766e}.kcard .ax{font-size:12px;fill:#3e5248}
.kcard .tgtline{stroke:#b45309;stroke-width:2;stroke-dasharray:2 3}
.pleg{display:flex;flex-wrap:wrap;gap:6px 12px;margin:4px 0 0;font-size:13px}
.pleg i{display:inline-block;width:18px;height:0;border-top-width:3px;border-top-style:solid;margin-right:4px;vertical-align:middle}
.pleg .ln{border-top-color:#0f766e}.pleg .tr{border-top-color:#1d4ed8;border-top-style:dashed}.pleg .tg{border-top-color:#b45309;border-top-style:dashed}
.donut-leg{list-style:none;margin:4px 0 0;padding:0;font-size:13px}.donut-leg li{display:flex;gap:6px;align-items:center;margin:2px 0}
.donut-leg i{width:12px;height:12px;border-radius:2px;flex:0 0 auto}
.nov7-rand{min-height:44px}
.nick-fold{display:flex;align-items:center;justify-content:space-between;gap:8px;margin:4px 0 0}
.nick-fold .mut{font-size:13px}
button.nick-toggle{min-height:44px;min-width:44px;padding:4px 12px;font-size:13px;font-weight:700;border:1px solid var(--line,#d5e0d8);border-radius:999px;background:#fff;color:var(--tx,#1b2822)}
.sowhead .nick-name,.n7-sow-nick{font-size:15px;font-weight:700;color:var(--pri,var(--pl-accent,#1f6f43));margin-left:6px;white-space:nowrap;vertical-align:baseline}
.sowhead .no .n7-sow-nick,b .n7-sow-nick,.no .n7-sow-nick{font-size:.55em;font-weight:700;margin-left:6px}
@media (max-width:480px){
  .sowhead .nick-name,.sowhead .n7-sow-nick{font-size:16px;font-weight:700;margin-left:8px;color:var(--pri,var(--pl-accent,#6FD8A6));white-space:nowrap;order:0;flex:0 0 auto;max-width:none}
}
.nick-edit{margin-top:8px}
.nick-edit .row{display:flex;flex-wrap:wrap;gap:6px;align-items:center;margin-top:6px}
.nick-edit input{width:100%}
.nick-info[hidden]{display:none}
.kcard .stk.s0{fill:#1f6f43}.kcard .stk.s1{fill:#0f766e}.kcard .stk.s2{fill:#c4a35a}
#nov7-pick,.nov7-pick button,.nov7-ai button,.msg-app button,.msg-compose button,.nov7-fab,#cal-go,#msg-unlock,.nov7-rand,[data-nick-save]{min-height:44px !important;min-width:44px;padding:8px 14px}
.nov7-pick{position:fixed;inset:8vh 6vw auto;background:#fff;border-radius:16px;padding:16px;z-index:70;max-height:80vh;overflow:auto;box-shadow:0 16px 40px rgba(0,0,0,.2)}
#nov7-pool{display:flex;flex-wrap:wrap;gap:8px}
.nov7-fab{position:fixed;right:16px;bottom:88px;z-index:40;border:0;border-radius:999px;background:#1f6f43;color:#fff;padding:0 16px}
.nov7-ai{display:none}
.nov7-ai textarea{width:100%;min-height:88px;font:inherit}
.msg-app{display:grid;grid-template-columns:220px minmax(0,1fr);min-height:420px;background:#fff;border:1px solid var(--line,#d5e0d8);border-radius:16px;overflow:hidden}
.msg-list{background:#f7faf8;border-right:1px solid var(--line,#d5e0d8);display:flex;flex-direction:column}
.msg-list button{min-height:44px;text-align:left;border:0;background:transparent;padding:8px 12px;font:inherit}
.msg-badge{background:#b42318;color:#fff;border-radius:99px;padding:0 6px;margin-left:6px}
.msg-room{display:flex;flex-direction:column;min-width:0;min-height:420px}
.msg-log{flex:1;overflow:auto;padding:12px;display:flex;flex-direction:column;gap:8px;background:#e7f0ea}
.bubble{max-width:78%;border-radius:16px;padding:8px 12px}
.bubble.out{align-self:flex-end;background:#1f6f43;color:#fff}
.bubble.in{align-self:flex-start;background:#fff}
.bubble .st,.bubble .who{font-size:12px;margin:0;opacity:.85}
.msg-compose{display:flex;gap:8px;padding:8px;padding-bottom:calc(8px + env(safe-area-inset-bottom,0px));background:#fff;position:sticky;bottom:0}
.msg-compose input{flex:1;min-height:44px;font:inherit;border-radius:12px;border:1px solid var(--line,#d5e0d8);padding:0 10px}
#msg-dnd{max-width:280px;width:auto;display:inline-block}
.msg-app{max-height:min(70vh,640px)}
.nov7-toast{position:fixed;left:50%;bottom:96px;transform:translateX(-50%);background:#143026;color:#fff;border-radius:12px;padding:10px 14px;z-index:80}
@media(max-width:1500px){.nov7-board{grid-template-columns:repeat(2,minmax(0,1fr))}}
@media(max-width:720px){
  .nov7-board{grid-template-columns:minmax(0,1fr)}
  .msg-app{grid-template-columns:minmax(0,1fr)}
  .nov7-fab{bottom:calc(76px + env(safe-area-inset-bottom,0px))}
  .nov7-ai{left:8px;right:8px;width:auto;bottom:calc(132px + env(safe-area-inset-bottom,0px))}
}

.ef-breed-hl>label.l{font-weight:700;color:var(--tx,#1b2822)}
.ef-nick-fold{margin:2px 0 4px}
.ef-nick-fold>a{font-size:13px;color:var(--pri,#1f6f43);cursor:pointer;text-decoration:underline;background:none;border:0;padding:0;font:inherit}
.entry [data-k="sowNote"]{min-height:36px;padding:6px 8px}
.entry .lim{margin:0;line-height:1.2}
.nov7-boar-nick .nov7-note{margin:2px 0}
.nov7-name-note{display:none}

.czt-lg{display:flex;flex-wrap:wrap;gap:6px}
.czt-lg button{min-height:48px;padding:10px 12px;font-size:15px;font-weight:700;flex:1 1 30%;border:1px solid var(--line,#d5e0d8);border-radius:10px;background:#fff;color:var(--tx,#1b2822)}
.czt-lg button.on{background:#1F2A24;color:#fff;border-color:#1F2A24}
.cz-free{margin-top:8px;width:100%;min-height:36px;padding:6px 8px}
.cz-free-h{margin:4px 0 0;font-size:12px}

/* t401 마대리 T1 T2 T5 T6 T3 T4 T7 T8 T10 + 홈 v2 */
:root{
  --n7-good:#0A66A8;--n7-warn:#8F5500;--n7-bad:#B23A0A;--n7-none:#9AA39E;
  --n7-link:#20714E;--n7-max:1200px;--n7-wide:1440px;
  --n7-fs-13:13px;--n7-fs-14:14px;--n7-fs-15:15px;--n7-fs-18:18px;--n7-fs-22:22px;--n7-fs-28:28px;--n7-fs-36:36px;
}
html{font-size:15px}
.mut,.sub,.hint{font-size:13px}
.badge{font-size:12.5px!important;font-weight:700}
h1{font-size:28px;line-height:1.25}
h2,#w-title{font-size:22px;line-height:1.3}
h3{font-size:18px;line-height:1.3}
#w-main{max-width:var(--n7-max);margin-left:0;margin-right:auto;width:100%;box-sizing:border-box}
@media (min-width:1280px){
  html[data-n7v="web"] #w-main:has(table.t),html[data-n7v="web"] #w-main:has(.tw){max-width:1040px}
  #w-main:has(table.t),#w-main:has(.tw){max-width:1040px}
}
/* t498 PC 3단: 윗줄 머리글이 가운데+오른쪽을 덮고, 메모/오늘 작업은 같은 틀 안 오른쪽 칸, 본문과 맞닿음 */
@media (min-width:1100px){
  html[data-n7v="web"] .shell{
    display:grid;
    grid-template-columns:228px minmax(0,1fr) var(--n7-rail,340px);
    grid-template-rows:auto minmax(0,1fr);
    grid-template-areas:"nav head head" "nav main rail";
    height:100vh;min-height:100vh;max-height:100vh;overflow:hidden
  }
  html[data-n7v="web"].n7-rail-min .shell{grid-template-columns:228px minmax(0,1fr) 52px}
  html[data-n7v="web"] .shell>aside{grid-area:nav;min-height:0;overflow:auto}
  html[data-n7v="web"] .shell>.top{grid-area:head;position:sticky;top:0;z-index:5;min-width:0}
  html[data-n7v="web"] .shell>.n7-col-main{grid-area:main;min-width:0;min-height:0;overflow:auto;display:flex;flex-direction:column}
  html[data-n7v="web"] #n7-rail{grid-area:rail;position:relative;top:auto;height:auto;min-height:0;overflow:hidden;display:flex;flex-direction:column;padding:12px;border-left:1px solid var(--pl-border,#E3E8E5);background:var(--pl-bg,#F5F7F6)}
  html[data-n7v="web"] #w-main,html[data-n7v="web"] .shell #w-main,html[data-n7v="web"] .n7-col-main #w-main,html[data-n7v="web"] main#w-main{max-width:none;width:100%;margin:0;box-sizing:border-box;flex:1;min-width:0}
  html[data-n7v="web"] #w-main .ensp{display:block}
  html[data-n7v="web"] #w-main .ensp>.ensh{display:none}
}
#n7-rail-btn{flex:0 0 auto}
@media (max-width:1099px){
  html[data-n7v="web"] #n7-rail:not(.open){display:none}
  html[data-n7v="web"] #n7-rail.open,html[data-n7v="m"] #n7-rail.open{display:flex;flex-direction:column;position:fixed;z-index:80;right:0;top:0;width:min(380px,94vw);height:100vh;overflow:hidden;padding:12px;background:var(--pl-bg,#F5F7F6);box-shadow:0 0 28px rgba(20,40,30,.22)}
  html[data-n7v="m"] #n7-rail:not(.open){display:none}
  html[data-n7v="web"] #w-main .ensp>.ensh{display:none}
}
html[data-n7v="m"] #w-main .ensp>.ensh,html[data-n7v="field"] #n7-rail{display:none}
#n7-rail{display:flex;flex-direction:column;min-height:0;box-sizing:border-box}
#n7-rail .n7-memo.shp,#n7-rail>.ensh,#n7-rail>#en-sh{flex:1 1 auto;min-height:0;width:100%;max-height:none;aspect-ratio:auto;display:flex;flex-direction:column;overflow:hidden;box-sizing:border-box}
.n7-memo.shp{background:#fff;color:#111;border:1px solid #d5dad7;box-shadow:0 3px 14px rgba(20,40,30,.12);padding:16px 18px 12px;font-size:13px;box-sizing:border-box}
.n7-memo .shh{display:flex;justify-content:space-between;align-items:flex-start;gap:8px;border-bottom:2px solid #1B2822;padding-bottom:8px;margin-bottom:8px;flex:0 0 auto}
.n7-memo .shh h3{margin:0;font-size:17px;color:#111}
.n7-memo-ta{width:100%;flex:1 1 auto;min-height:0;height:auto;border:0;resize:none;background-color:transparent;background-image:repeating-linear-gradient(to bottom,transparent 0,transparent calc(1.55em - 1px),#e6ebe8 calc(1.55em - 1px),#e6ebe8 1.55em);background-attachment:local;color:#111;font:inherit;line-height:1.55;padding:0;outline:none;box-sizing:border-box}
.n7-memo-ta[readonly]{cursor:default;color:#333;opacity:.95}
.n7-memo.locked .n7-memo-ta{background-image:repeating-linear-gradient(-45deg,transparent,transparent 8px,rgba(27,40,34,.03) 8px,rgba(27,40,34,.03) 16px),repeating-linear-gradient(to bottom,transparent 0,transparent calc(1.55em - 1px),#e6ebe8 calc(1.55em - 1px),#e6ebe8 1.55em);background-attachment:local}
.n7-memo .n7-memo-st{font-size:12px;color:#555;margin-top:8px;flex:0 0 auto}
.n7-lock{border:1px solid #c5cdc8;background:#fff;color:#1B2822;border-radius:8px;min-height:32px;padding:2px 8px;font-size:13px;font-weight:700}
.n7-lock.on{background:#1B2822;color:#fff;border-color:#1B2822}
html.n7-rail-min #n7-rail .n7-memo{aspect-ratio:auto;max-height:none;padding:8px 6px;overflow:hidden}
html.n7-rail-min #n7-rail .n7-memo-ta,html.n7-rail-min #n7-rail .n7-memo-st,html.n7-rail-min #n7-rail .n7-lock{display:none}
html.n7-rail-min #n7-rail .shh h3{writing-mode:vertical-rl;font-size:13px}
.kgrid,.homegrid,.kpigrid,.duegrid,.n7-cards{
  display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:12px
}
.btn{min-height:40px}
.btn.sm{min-height:32px;font-size:14px}
.btn.block,.savebtn,button.btn.block{min-height:48px}
#w-main a:not(.btn):not([data-p]):not([data-v]),#m-main a:not(.btn),.n7h a:not(.btn){
  color:var(--n7-link);font-weight:600;text-decoration:none
}
#w-main a:not(.btn):hover,#m-main a:not(.btn):hover,.n7h a:not(.btn):hover{text-decoration:underline}
table.t tbody tr{min-height:44px}
table.t th,table.t td{vertical-align:middle}
table.t td.n,table.t th.n,table.t td[class*="num"]{text-align:right;font-variant-numeric:tabular-nums}
.n7-empty,.n7-none{color:var(--n7-none)}
.n7-load{padding:24px;color:#5c6a64;font-size:14px}
.n7-load:before{content:"";display:inline-block;width:16px;height:16px;margin-right:8px;border:2px solid #d5e0d8;border-top-color:#20714E;border-radius:50%;vertical-align:-3px;animation:n7spin .8s linear infinite}
@keyframes n7spin{to{transform:rotate(360deg)}}
.n7-err{padding:16px;border:1px solid #ead8d0;background:#fff8f6;border-radius:12px;color:#B23A0A}
.n7-dayhint{font-size:13px;color:#5c6a64;margin-left:8px;font-weight:600;white-space:nowrap}
.n7-hide-feat{display:none!important}

.n7h{font-size:15px;line-height:1.5;color:#1B2822;padding:0 0 28px}
.n7h-hero{background:linear-gradient(135deg,#141e1a 0%,#1e2f28 52%,#16352c 100%);color:#fff;border-radius:18px;padding:22px 24px 20px;margin:0 0 16px;box-shadow:0 10px 28px rgba(20,30,26,.18)}
.n7h-farm{font-size:28px;font-weight:800;letter-spacing:-.02em;margin:0 0 6px;line-height:1.2}
.n7h-week{font-size:15px;opacity:.88;margin:0 0 8px}
.n7h-sum{font-size:14px;opacity:.8;margin:0}
.n7h-sec{margin:0 0 16px;background:#fff;border:1px solid #e3ebe6;border-radius:16px;padding:16px 18px}
.n7h-sec h2{margin:0 0 12px;font-size:18px;font-weight:700}
.n7h-todo{display:flex;flex-direction:column;gap:8px}
.n7h-work{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:8px;margin:0}
.n7h-wchip{display:flex;flex-direction:column;align-items:flex-start;justify-content:center;gap:2px;min-height:56px;padding:8px 10px;border:1px solid #d5e0d8;border-radius:12px;background:#fff;text-align:left;cursor:pointer}
.n7h-wchip b{font-size:20px;line-height:1.1;color:#1b2822}
.n7h-wchip span{font-size:12px;color:#5c6a64;word-break:keep-all}
.n7h-wchip.on{border-color:#1f6f43;background:#eef6f0}
.n7h-wchip.zero{border-style:dashed;opacity:.7}
.n7h-wchip.loss b,.n7h-wchip.loss span{color:#b42318}
.n7h-wchip.loss.on{border-color:#e8b4b0;background:#fff5f4}
@media(max-width:420px){.n7h-work{grid-template-columns:repeat(2,minmax(0,1fr))} .n7h-wchip{min-height:64px}}

.n7h-row{display:flex;align-items:center;gap:12px;padding:10px 8px;border-radius:12px;min-height:52px;cursor:pointer}
.n7h-row:hover{background:#f4f7f5}
.n7h-row .ic{width:36px;height:36px;border-radius:10px;background:#eef3f0;display:flex;align-items:center;justify-content:center;flex:0 0 auto;font-size:16px}
.n7h-row .bd{flex:1;min-width:0}
.n7h-row .ti{font-weight:700;font-size:15px}
.n7h-row .mt{font-size:13px;color:#5c6a64}
.n7h-pill{font-size:12.5px;font-weight:700;border-radius:999px;padding:3px 8px;white-space:nowrap}
.n7h-pill.late{background:#fdece6;color:#B23A0A}
.n7h-pill.today{background:#e8f1fb;color:#0A66A8}
.n7h-row .act{margin-left:auto}
.n7h-empty{color:#9AA39E;font-size:14px;padding:8px 0}
.n7h-alert{display:flex;gap:12px;align-items:flex-start;padding:12px;border-radius:12px;background:#fff8f2;border-left:4px solid #8F5500;margin:0 0 8px}
.n7h-alert.bad{background:#fff6f3;border-left-color:#B23A0A}
.n7h-alert .ti{font-weight:700;font-size:15px}
.n7h-alert .mt{font-size:13px;color:#5c6a64}
.n7h-kpis{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:12px}
.n7h-card{border:1px solid #e3ebe6;border-radius:14px;padding:14px 16px;background:#fff;min-height:148px;display:flex;flex-direction:column;gap:4px}
.n7h-card.st-good{box-shadow:inset 0 3px 0 #0A66A8}
.n7h-card.st-warn{box-shadow:inset 0 3px 0 #8F5500}
.n7h-card.st-bad{box-shadow:inset 0 3px 0 #B23A0A}
.n7h-card.st-none{box-shadow:inset 0 3px 0 #9AA39E}
.n7h-lab{font-size:13px;font-weight:700;color:#3a4742}
.n7h-vs{font-size:13px;min-height:18px}
.n7h-vs.good{color:#0A66A8}.n7h-vs.warn{color:#8F5500}.n7h-vs.bad{color:#B23A0A}.n7h-vs.none{color:#9AA39E}
.n7h-k{font-size:36px;font-weight:800;letter-spacing:-.03em;font-variant-numeric:tabular-nums;line-height:1.1;margin:4px 0}
.n7h-frac{font-size:13px;color:#5c6a64}
.n7h-delta{font-size:13px;font-weight:600;font-variant-numeric:tabular-nums}
.n7h-delta.good{color:#0A66A8}.n7h-delta.bad{color:#B23A0A}.n7h-delta.flat{color:#9AA39E}
.n7h-tag{font-size:12.5px;font-weight:700;color:#5c6a64}
.n7h-spark{display:flex;align-items:flex-end;gap:2px;height:28px;margin-top:6px}
.n7h-spark i{display:block;flex:1;background:#d5e0d8;border-radius:2px 2px 0 0;min-height:2px}
.n7h-spark i.on{background:#0A66A8}
.n7h-need{font-size:13px;color:#5c6a64;margin:4px 0 8px}
.n7h-morts{display:grid;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));gap:10px}
.n7h-mort{padding:8px 0}
.n7h-mort .nm{font-size:13px;font-weight:600;display:flex;justify-content:space-between}
.n7h-bar{height:8px;background:#eef3f0;border-radius:99px;overflow:hidden;margin-top:6px}
.n7h-bar span{display:block;height:100%;border-radius:99px;background:#0A66A8}
.n7h-bar.bad span{background:#B23A0A}.n7h-bar.warn span{background:#8F5500}.n7h-bar.none span{background:#c5cdc8}
.n7h-trend .n7h-tabs{display:flex;flex-wrap:wrap;gap:6px;margin:0 0 12px}
.n7h-trend .n7h-tabs button{min-height:32px;font-size:13px}
.n7h-bars{display:flex;align-items:flex-end;gap:6px;height:120px;padding:8px 0 0}
.n7h-bars>div{flex:1;display:flex;flex-direction:column;align-items:center;justify-content:flex-end;height:100%}
.n7h-bars b{display:block;width:100%;max-width:36px;background:#0A66A8;border-radius:4px 4px 0 0;min-height:2px}
.n7h-bars em{font-style:normal;font-size:13px;color:#5c6a64;margin-top:6px}
.n7h-foot{font-size:13px;color:#5c6a64;padding:8px 4px 0}
.n7h-go{margin-top:6px}
@media (max-width:600px){
  .n7h-hero{padding:16px;border-radius:14px}
  .n7h-farm{font-size:22px}
  .n7h-k{font-size:28px}
  .n7h-kpis{grid-template-columns:repeat(2,minmax(0,1fr));gap:8px}
  .n7h-card{padding:12px;min-height:132px}
  .n7h-row{padding:8px 0;gap:8px}
  .kgrid,.homegrid,.kpigrid,.duegrid,.n7-cards{grid-template-columns:repeat(auto-fit,minmax(148px,1fr))}
}
@media (prefers-reduced-motion:reduce){
  .n7-load:before,.n7h-spark i,.n7h-bar span,.n7h-bars b{animation:none!important;transition:none!important}
}


.n7-dayhint{display:inline-block;font-size:13px;color:#5c6a64;margin-left:8px;font-weight:700;white-space:nowrap}
.entry.big .n7-dayhint,.far-open .n7-dayhint{display:block;flex-basis:100%;width:100%;margin:8px 0 0;font-size:16px;color:#1B2822;font-weight:800}
.entry.big .row:has([data-day]),.entry.big #ef-date{flex-wrap:wrap}
.n7-imp{margin:0 0 16px;padding:14px 16px;border:1px solid #e3ebe6;border-radius:14px;background:#f7faf8}
.n7-imp h3,.n7-imp h4{margin:0 0 8px;font-size:18px}
.n7-imp p,.n7-imp li{font-size:14px;line-height:1.55;margin:0 0 8px}
.n7-imp ol,.n7-imp ul{margin:0 0 10px;padding-left:1.2em}
.n7-imp-pre{white-space:pre-wrap;word-break:break-word;background:#fff;border:1px solid #d5e0d8;border-radius:10px;padding:12px;font-size:13px;line-height:1.5;max-height:280px;overflow:auto}
.n7-imp .row{display:flex;gap:8px;flex-wrap:wrap;align-items:center;margin:8px 0}
.n7-imp-cols{font-size:13px;color:#3a4742;margin:8px 0}
.n7-imp-warn{background:#fff8f2;border-left:4px solid #8F5500;padding:8px 10px;border-radius:8px;margin:8px 0;font-size:14px}
.n7-imp-ok{background:#f3f8f5;border-left:4px solid #20714E;padding:8px 10px;border-radius:8px;margin:8px 0;font-size:14px}

.n7-imp-lead{font-size:14px;line-height:1.55;margin:0 0 12px}
.n7-imp-step{font-weight:800;margin:14px 0 6px;font-size:15px;color:#1B2822}
.n7-imp-hint{font-size:13px;color:#5c6a64;margin:0 0 8px;line-height:1.45}
.n7-imp-prog{margin:10px 0;padding:10px 12px;background:#fff;border:1px solid #d5e0d8;border-radius:10px}
.n7-imp-barw{height:10px;background:#e3ebe6;border-radius:6px;overflow:hidden}
.n7-imp-bar{height:100%;background:#20714E;width:0;transition:width .15s}
.n7-imp-prog span{display:block;margin-top:6px;font-size:13px;font-weight:700;color:#1B2822}
.n7-imp-resume{background:#fff8f2;border:1px solid #ead8d0;border-radius:10px;padding:10px 12px;margin:0 0 12px;font-size:14px}
.n7-imp-flags{background:#fff8f2;border-left:4px solid #8F5500;padding:8px 10px;border-radius:8px;margin:8px 0;font-size:13px}
.n7-imp #im-k{display:none}

/* t408u 마대리 v2: /m · /field · 설정 (lazy n7 css, html gzip 밖) */
html[data-n7v="m"] .mh{background:#fff;color:#1B2822;box-shadow:none;border-bottom:1px solid #E3E8E5;min-height:56px;padding:8px 12px;align-items:center}
html[data-n7v="m"] .mh .t{color:#1B2822;font-size:18px;font-weight:800}
html[data-n7v="m"] .mh .brand{filter:brightness(0) saturate(100%);opacity:.88}
html[data-n7v="m"] .mh>b{color:#1B2822;opacity:1}
html[data-n7v="m"] main{padding-bottom:calc(64px + env(safe-area-inset-bottom,0px) + 24px)}
html[data-n7v="m"] #ai-fab{display:none !important}
html[data-n7v="m"] .tabbar{padding-bottom:env(safe-area-inset-bottom,0px);min-height:calc(56px + env(safe-area-inset-bottom,0px))}
html[data-n7v="m"] .tabbar button{font-size:13px;font-weight:600;min-height:48px;padding:6px 0 8px;color:#5C6661}
html[data-n7v="m"] .tabbar button i{font-size:22px;width:56px;height:30px;display:grid;place-items:center;border-radius:16px}
html[data-n7v="m"] .tabbar button.on{color:#1B2822}
html[data-n7v="m"] .tabbar button.on i{background:#DCEFE6;color:#1B6B45}
html[data-n7v="m"] .tabbar button.mid i{width:64px;height:64px;border-radius:50%;background:#24835A;color:#fff;border:4px solid #fff;box-shadow:0 4px 12px rgba(27,40,34,.2);margin-top:-22px;margin-bottom:2px}
html[data-n7v="m"] .tabbar button.mid.on i{background:#1B6B45;color:#fff}
html[data-n7v="m"].n7-sub .tabbar{display:none}
html[data-n7v="m"].n7-sub main{padding-bottom:calc(72px + env(safe-area-inset-bottom,0px) + 16px)}
html[data-n7v="m"] .n7-back{flex:0 0 44px;width:44px;height:44px;border:0;background:transparent;color:#1B2822;font-size:28px;line-height:1;border-radius:12px}
html[data-n7v="m"] .seg{width:100%;display:flex}
html[data-n7v="m"] .seg button,html[data-n7v="field"] .seg button{flex:1;min-height:48px;min-width:48px}
html[data-n7v="m"] input[type="checkbox"],html[data-n7v="field"] input[type="checkbox"]{width:22px;height:22px;min-width:22px;min-height:22px}
html[data-n7v="m"] label:has(>input[type="checkbox"]),html[data-n7v="field"] label:has(>input[type="checkbox"]){min-height:48px;display:flex;align-items:center;gap:8px}
html[data-n7v="m"] .btn,html[data-n7v="field"] .btn{min-height:48px}
html[data-n7v="field"] .types button{min-height:112px;font-size:22px;border:1px solid #D5DDD8}
html[data-n7v="field"] .types button i{font-size:28px}
html[data-n7v="m"] .tabs,html[data-n7v="m"] .rchips,html[data-n7v="m"] .chiprow{-ms-overflow-style:none;scrollbar-width:none}
html[data-n7v="m"] .tabs::-webkit-scrollbar,html[data-n7v="m"] .rchips::-webkit-scrollbar{display:none}
.n7-abar{position:fixed;left:0;right:0;bottom:0;z-index:30;background:#fff;border-top:1px solid #E3E8E5;padding:8px 12px calc(8px + env(safe-area-inset-bottom,0px));display:flex;gap:8px}
.n7-abar .btn{flex:1;min-height:56px;font-size:16px;font-weight:800}
html[data-n7v="m"]:not(.n7-sub) .n7-abar,html:not([data-n7v="m"]):not([data-n7v="field"]) .n7-abar{display:none}
html[data-theme="barn"]{background:#121A17;color:#EEF3F0}
html[data-theme="barn"] body{background:#121A17;color:#EEF3F0}
html[data-theme="barn"] .card,html[data-theme="barn"] .entry,html[data-theme="barn"] .types button{background:#1C2622;color:#EEF3F0;border-color:#3A4742}
html[data-theme="barn"] .fh,html[data-theme="barn"] .mh{background:#0E1513;color:#EEF3F0;border-color:#3A4742}
html[data-theme="barn"] .mut{color:#B8C2BC}
html[data-theme="barn"] input,html[data-theme="barn"] select,html[data-theme="barn"] textarea{background:#121A17;color:#EEF3F0;border-color:#5A6862}
html[data-theme="sun"]{background:#fff;color:#111}
html[data-theme="sun"] body{background:#fff;color:#111}
html[data-theme="sun"] .mut{color:#1B2822}
html[data-theme="sun"] .card,html[data-theme="sun"] .types button{border:2px solid #1B2822;background:#fff}
html[data-theme="sun"] input,html[data-theme="sun"] select{border:2px solid #1B2822}
.n7-tmap{margin:0 0 14px}
.n7-tmap h3{margin:0 0 8px;font-size:16px}
.n7-tmap-leg{display:flex;flex-wrap:wrap;gap:8px;font-size:12px;color:#5C6661;margin:0 0 8px}
.n7-tmap-b{margin:0 0 12px}
.n7-tmap-b>b{display:block;font-size:13px;margin:0 0 6px}
.n7-tmap-g{display:grid;grid-template-columns:repeat(auto-fill,minmax(88px,1fr));gap:6px}
.n7-tcell{border:0;border-radius:10px;padding:8px;text-align:left;color:#0B1F18;min-height:64px;cursor:pointer}
.n7-tcell .n{font-weight:800;font-size:14px;display:block}
.n7-tcell .h{font-size:12px;opacity:.9}
.n7-tc0{background:#E8EEF2}.n7-tc1{background:#B9D4EA}.n7-tc2{background:#7EB3D9}.n7-tc3{background:#F3C07A}.n7-tc4{background:#E8894A}.n7-tc5{background:#D4532A;color:#fff}
.n7-st-find{margin:0 0 10px}
.n7-st-find input{width:100%;min-height:48px}
.n7-savebar{position:sticky;bottom:0;background:#fff;border-top:1px solid #E3E8E5;padding:10px 0;z-index:4;display:flex;gap:8px;align-items:center}
.n7-rolecard{background:#F6F8F7;border-radius:12px;padding:12px;margin:0 0 12px;font-size:13px;overflow:auto}
.n7-rolecard table{width:100%;border-collapse:collapse}
.n7-rolecard th,.n7-rolecard td{border-bottom:1px solid #E3E8E5;padding:6px 8px;text-align:center}
.n7-rolecard th:first-child,.n7-rolecard td:first-child{text-align:left}
.n7-dots{position:relative}
.n7-dots>button.n7-morebtn{min-width:44px;min-height:44px;border:0;background:#F0F3F1;border-radius:10px;font-weight:800}
.n7-dots .n7-menu{position:absolute;right:0;top:100%;background:#fff;border:1px solid #E3E8E5;border-radius:12px;box-shadow:0 8px 24px rgba(0,0,0,.12);z-index:8;min-width:160px;padding:4px;display:none}
.n7-dots.open .n7-menu{display:block}
.n7-dots .n7-menu button{display:block;width:100%;text-align:left;border:0;background:none;padding:10px 12px;min-height:44px;border-radius:8px}
.n7-dots .n7-menu button.n7-dang{color:#B42318}
@media(max-width:720px){
  .n7-staff-act .btn.sm{display:none}
  .n7-staff-act .n7-dots{display:inline-block}
}
@media(min-width:721px){
  .n7-staff-act .n7-dots{display:none}
}



/* t409u 가져오기 v2 · 도폐사 원인 · 공지 · 데모 · 키패드 */
html[data-n7v="m"] #open-notices{
  width:48px;height:48px;min-width:48px;padding:0;flex:0 0 48px;
  border-radius:12px;font-size:0;line-height:0;color:transparent;overflow:hidden;
  background:#F0F3F1;border:0;position:relative;margin-left:6px
}
html[data-n7v="m"] #open-notices::before{
  content:"";position:absolute;inset:0;
  background:center / 22px 22px no-repeat url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23143026' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'><path d='M15 17h5l-1.4-1.4A2 2 0 0 1 18 14.2V11a6 6 0 1 0-12 0v3.2a2 2 0 0 1-.6 1.4L4 17h5'/><path d='M9 17a3 3 0 0 0 6 0'/></svg>")
}
html[data-n7v="m"] .mh .t,html[data-n7v="m"] #m-title{flex:0 0 auto;min-width:0;max-width:none;overflow:visible;text-overflow:clip;white-space:nowrap}
html[data-n7v="m"] .mh>b,html[data-n7v="m"] #farmsel{
  flex:1 1 0;min-width:0;max-width:46%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap
}
html[data-n7v="m"].n7-sub .mh > b,
html[data-n7v="m"].n7-sub #farmsel,
html[data-n7v="m"].n7-sub .mh .brand{display:none!important}
html[data-n7v="m"].n7-sub .mh .t,html[data-n7v="m"].n7-sub #m-title{flex:1 1 auto;overflow:hidden;text-overflow:ellipsis}
.czt-lg button{min-height:56px}
html[data-n7v="field"] .czt-lg button{min-height:72px}
.n7-cz-miss,.n7-cz-miss .czt{outline:2px solid #C45A00;border-radius:12px}
.n7-tmap{padding-bottom:calc(64px + env(safe-area-inset-bottom,0px) + 24px)}
.n7-tmap-flex{display:flex;flex-wrap:wrap;gap:6px}
.n7-tmap-flex .n7-tcell{flex:var(--n,1) 1 72px;min-height:72px}
.n7-tc-od0{background:#2F6FA8;color:#fff}.n7-tc-od1{background:#8FBFDE;color:#0B1F18}
.n7-tc-od2{background:#F3C07A}.n7-tc-od3{background:#E8894A}.n7-tc-od4{background:#C23B22;color:#fff}
.n7-tmap-err,.n7-tmap-empty{background:#E8F1F8;border-radius:12px;padding:14px;margin:8px 0}
.n7-tmap-err b,.n7-tmap-empty b{display:block;margin:0 0 4px}
.n7-tmap-err p,.n7-tmap-empty p{margin:0 0 10px;font-size:13px;color:#5C6661}
.n7-destfree .mut{margin:0 0 8px;font-size:13px}
.n7-dest-loc{width:100%;min-height:48px}
.n7-sowbar{z-index:31}
body.n7-sowbar-on main,html[data-n7v="m"].n7-sub body.n7-sowbar-on main{padding-bottom:calc(72px + env(safe-area-inset-bottom,0px) + 16px)}
.n7-rolecard .pm{display:inline-block;min-width:22px;padding:2px 6px;border-radius:999px;font-size:12px;font-weight:700}
.n7-rolecard .pm.full{background:#DCEFE6;color:#0F5C3A}
.n7-rolecard .pm.none{background:#F0F3F1;color:#6B756F}
.n7-sow-more{position:absolute;right:8px;top:6px;z-index:3}
.n7-cycbar{display:flex;gap:4px;margin:8px 0 12px;overflow:auto}
.n7-cycbar span{flex:1;min-width:52px;text-align:center;font-size:11px;padding:6px 4px;border-radius:8px;background:#F0F3F1;color:#5C6661}
.n7-cycbar span.on{background:#24835A;color:#fff}
html[data-n7v="m"] #supa-demo-band{display:none!important}
.n7-demo-ribbon{position:sticky;top:0;z-index:40;background:#143026;color:#F4FFF8;font-size:11px;line-height:18px;text-align:center;padding:2px 8px}
.n7-imp-slots{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:8px;margin:10px 0}
.n7-imp-slotcard{display:block;border:1px dashed #C9D4CE;border-radius:12px;padding:10px 12px;background:#fff;cursor:pointer}
.n7-imp-slotcard b{display:block;font-size:13px;color:#143026}
.n7-imp-slotcard span{display:block;font-size:12px;color:#5B6B64;margin-top:2px}
.n7-imp-slotcard.has{border-color:#24835A;background:#F3FBF7}
.n7-imp-all{margin:8px 0 4px;font-size:13px}
.n7-cz-err{color:#B42318;font-size:13px;margin-top:6px}
.n7-pad{display:grid;grid-template-columns:repeat(3,1fr);gap:8px;margin:10px 0 4px;max-width:280px}
.n7-pad button{height:48px;border-radius:12px;border:1px solid #D5DED9;background:#fff;font-size:20px;font-weight:600;color:#143026}
.n7-pad button:active{background:#E8F3EE}
.n7-sug{display:flex;flex-wrap:wrap;gap:6px;margin:6px 0}
.n7-sug button{border:0;background:#E8F3EE;color:#143026;border-radius:999px;padding:6px 12px;font-size:13px}
.n7-dateko{font-size:13px;color:#5B6B64;margin-top:4px}
.n7-st-hub{border:1px solid #E3E8E5;border-radius:12px;margin:8px 0;overflow:hidden;background:#fff}
.n7-st-hub > button{display:flex;width:100%;align-items:center;justify-content:space-between;background:#F7F9F8;border:0;padding:12px 14px;font-weight:600;font-size:14px;color:#143026}
.n7-st-hub > button span{font-weight:500;color:#5B6B64}
.n7-st-hub.on > button{background:#E8F3EE}
.n7-filelab{display:inline-flex;align-items:center;gap:6px}

.n7-qp{display:flex;flex-wrap:wrap;gap:6px;margin:6px 0 8px;align-items:center}
.n7-qpb{border:0;background:#E8F3EE;color:#143026;border-radius:999px;padding:6px 10px;font-size:13px;cursor:pointer}
.n7-qpb b{display:inline-block;min-width:1.1em;color:#24835A;margin-right:2px}
.n7-qp-hint{font-size:11px}
.n7-brs{display:flex;flex-wrap:wrap;gap:6px;margin:4px 0 8px}
.n7-brb{border:1px solid #D5DED9;background:#fff;border-radius:999px;padding:6px 12px;font-size:13px;color:#143026;cursor:pointer}
.n7-brb.on{background:#24835A;color:#fff;border-color:#24835A}
.n7-ageg{margin:8px 0;width:100%;display:grid;gap:12px}
.entry .fg{width:100%;display:grid;gap:12px}
.entry .fc{min-width:0}

/* t502 master console + waiting gate */
.n7-wait,.n7-macc{max-width:1100px;margin:40px auto;padding:24px 24px 40px;background:#fff;border:1px solid #d5e0d8;border-radius:16px}
.n7-wait{max-width:480px;text-align:center}
.n7-wait h2,.n7-macc h2{margin:0 0 8px;font-size:22px}
.n7-wait p,.n7-macc .mut{color:#5c6a64}
.n7-macc table{width:100%;border-collapse:collapse;font-size:13px}
.n7-macc th,.n7-macc td{border-bottom:1px solid #e3ebe6;padding:8px 6px;text-align:left;vertical-align:top}
.n7-macc th{background:#f4f7f5;font-weight:700}
.n7-macc .st{display:inline-block;border-radius:999px;padding:2px 8px;font-weight:700;font-size:12px}
.n7-macc .st-pending{background:#fff4d6;color:#8a4b00}
.n7-macc .st-approved{background:#e7f6ec;color:#0d6b3a}
.n7-macc .st-suspended{background:#fdece6;color:#b42318}
.n7-macc .st-expired{background:#eee;color:#444}
.n7-macc .acts{display:flex;flex-wrap:wrap;gap:4px}
.n7-macc .acts button{min-height:32px;font-size:12px}
html[data-theme=dark] .n7-wait,html[data-theme=dark] .n7-macc{background:#1b2120;border-color:#333}
html[data-theme=dark] .n7-macc th{background:#222;color:#ddd}

.ef-nick-box{margin:6px 0 8px;grid-column:1 / -1}
.ef-breed-hl{margin:6px 0 8px;grid-column:1 / -1}
input[data-k="품종"].n7-br-in{margin-top:6px}


/* t411–t413 */
html[data-n7v="m"] .stepper .step,
html[data-n7v="field"] .stepper .step{
  min-width:48px;min-height:48px;padding:0;font-size:22px;line-height:1;flex:0 0 48px
}
html[data-n7v="m"] .stepper input,
html[data-n7v="field"] .stepper input{min-height:48px;font-size:18px;text-align:center}
.n7-boar-chips{display:flex;flex-wrap:wrap;gap:8px;align-items:center;margin:8px 0 4px}
.n7-boar-chips .chipb{min-height:48px;padding:10px 18px;font-size:16px;border-radius:999px;border:1px solid #D5DED9;background:#fff;color:#143026}
.n7-boar-chips .chipb.on{border-color:#24835A;background:#E8F3EE}
.n7-boar-chips .mut{font-size:13px}
html[data-n7v="field"] .types button[data-n7pd]{min-height:88px}
body.n7-abar-on{padding-bottom:72px}
body.n7-login #n7-abar,html.login #n7-abar{display:none!important}


/* t424 약품/사료 · 월별 FCR · 소독기록부 */
.n7-fs-tabs{display:flex;flex-wrap:wrap;gap:6px;margin:0 0 12px}
.n7-fs-tabs button{min-height:40px;padding:8px 14px;border-radius:999px;border:1px solid #D5DED9;background:#fff;color:#143026;font-weight:600}
.n7-fs-tabs button.on{background:#24835A;border-color:#24835A;color:#fff}
.n7-fcr{padding-top:4px;margin-top:4px}
.n7-fcr .n7-fcr-miss{background:#F8EFE8;color:#7A3B12;border-radius:10px;padding:10px 12px;margin:8px 0}
.n7-fcr .n7-fcr-na{color:#8A5A2B;font-weight:600}
.n7-fcr table.t td, .n7-fcr table.t th{white-space:nowrap}
.n7-dis .n7-chips{display:flex;flex-wrap:wrap;gap:8px;margin:4px 0 10px}
.n7-dis .n7-chips button{min-height:44px;padding:8px 14px;border-radius:999px;border:1px solid #D5DED9;background:#fff;color:#143026}
.n7-dis .n7-chips button.on{background:#24835A;border-color:#24835A;color:#fff}
.n7-dis .n7-steprow{display:flex;align-items:center;gap:8px}
.n7-dis .n7-steprow .step{min-width:48px;min-height:48px;font-size:22px}
.n7-dis .n7-steprow input{min-height:48px;text-align:center;font-size:18px;flex:1}
@media print{
  body.n7-print-dis .noprint, body.n7-print-dis #n7-abar, body.n7-print-dis .tabbar, body.n7-print-dis aside, body.n7-print-dis header, body.n7-print-dis .fh, body.n7-print-dis #m-tabs{display:none!important}
  body.n7-print-dis .n7-dis-print{display:block!important}
}
.n7-dis-print{display:none}
body.n7-print-dis .n7-dis-print{display:block}
.n7-dis-print h2{margin:0 0 8px;font-size:20px}
.n7-dis-print table{width:100%;border-collapse:collapse}
.n7-dis-print th,.n7-dis-print td{border:1px solid #333;padding:6px 8px;font-size:12px}


/* —— t447: PIGLOG AI bottom sheet, mobile settings, entry sizes —— */
html.pai-lock,html.pai-lock body{overflow:hidden !important;overscroll-behavior:none}
#pai-root{position:fixed;inset:0;z-index:80;display:flex;flex-direction:column;justify-content:flex-end}
.pai-back{position:absolute;inset:0;background:rgba(12,24,18,.46)}
.pai-sheet{position:relative;z-index:1;background:#fff;color:#1b2822;border-radius:16px 16px 0 0;max-height:80vh;min-height:min(58vh,80vh);width:100%;display:flex;flex-direction:column;box-shadow:0 -8px 32px rgba(20,40,30,.2);padding-bottom:env(safe-area-inset-bottom,0px);transition:width .2s ease,max-width .2s ease,max-height .2s ease,min-height .2s ease}
.pai-grab{flex:none;display:flex;justify-content:center;padding:8px 0 4px;touch-action:none;cursor:grab}
.pai-grab span{width:42px;height:4px;border-radius:4px;background:#c5d0c8;display:block}
.pai-hd{flex:none;display:flex;align-items:center;justify-content:space-between;gap:8px;padding:4px 8px 8px 12px;border-bottom:1px solid #e6eee8}
.pai-hd strong{font-size:15px;line-height:1.3;min-width:0;flex:1;font-weight:700}
.pai-acts{display:flex;align-items:center;flex:none}
.pai-x,.pai-cancel,.pai-sz{min-width:44px;min-height:44px;border:0;background:none;font-size:20px;border-radius:10px;color:inherit;cursor:pointer}
.pai-hd .pai-cancel{font-size:15px;font-weight:700;color:#1f6f43;min-width:auto;padding:0 10px}
.pai-sz{font-size:18px;line-height:1}
.pai-host{flex:1;min-height:0;display:flex;flex-direction:column;padding:8px 12px 0;overflow:hidden}
#pai-root.pai-wide .pai-sheet{max-height:96vh;min-height:min(88vh,96vh)}
html[data-n7v="web"] #pai-root,#pai-root.pai-pc{flex-direction:row;justify-content:flex-end;align-items:stretch}
html[data-n7v="web"] .pai-sheet,#pai-root.pai-pc .pai-sheet{width:40vw;max-width:40vw;min-width:min(320px,100%);height:100%;max-height:100%;min-height:100%;border-radius:16px 0 0 16px;box-shadow:-8px 0 32px rgba(20,40,30,.2);padding-bottom:0}
html[data-n7v="web"] #pai-root.pai-wide .pai-sheet,#pai-root.pai-pc.pai-wide .pai-sheet{width:80vw;max-width:80vw;min-height:100%;max-height:100%}
html[data-n7v="web"] .pai-grab,#pai-root.pai-pc .pai-grab{display:none}
html[data-theme="dark"] .pai-sheet{background:var(--pl-surface,#121C19);color:var(--pl-text,#E8EFEB)}
html[data-theme="dark"] .pai-hd{border-bottom-color:var(--pl-border,#23322C)}
html[data-theme="dark"] .pai-grab span{background:#3a4a44}
html[data-theme="dark"] .pai-hd .pai-cancel{color:#8fd4a8}
html[data-theme="dark"] .pai-back{background:rgba(0,0,0,.55)}
html[data-theme="dark"] .pai-host,html[data-theme="dark"] .pai,html[data-theme="dark"] .pai-log,html[data-theme="barn"] .pai-sheet,html[data-theme="barn"] .pai-hd,html[data-theme="barn"] .pai-host,html[data-theme="barn"] .pai,html[data-theme="barn"] .pai-log{
  background:var(--pl-surface,#121C19);color:var(--pl-text,#E8EFEB)
}
html[data-theme="dark"] .pai-chip,html[data-theme="dark"] .pai-mini,html[data-theme="barn"] .pai-chip,html[data-theme="barn"] .pai-mini{
  background:#18241F;border-color:#23322C;color:var(--pl-text,#E8EFEB)
}
html[data-theme="dark"] .pai-bar,html[data-theme="dark"] .pai-foot,html[data-theme="barn"] .pai-bar,html[data-theme="barn"] .pai-foot{
  background:var(--pl-surface,#121C19);color:#B5C3BC
}
html[data-theme="dark"] .pai-bar input,html[data-theme="barn"] .pai-bar input{
  background:#0A1210;border-color:#2a3a34;color:var(--pl-text,#E8EFEB)
}
html[data-theme="barn"] .pai-back{background:rgba(0,0,0,.55)}
html[data-theme="barn"] .pai-hd{border-bottom-color:var(--pl-border,#23322C)}
html[data-theme="barn"] .pai-hd .pai-cancel{color:#8fd4a8}
#pai-root[data-theme="dark"] .pai-sheet,#pai-root[data-theme="barn"] .pai-sheet,
#pai-root[data-theme="dark"] .pai-hd,#pai-root[data-theme="barn"] .pai-hd,
#pai-root[data-theme="dark"] .pai-host,#pai-root[data-theme="barn"] .pai-host,
#pai-root[data-theme="dark"] .pai,#pai-root[data-theme="barn"] .pai,
#pai-root[data-theme="dark"] .pai-log,#pai-root[data-theme="barn"] .pai-log,
#pai-root[data-theme="dark"] .pai-bar,#pai-root[data-theme="barn"] .pai-bar{
  background:var(--pl-surface,#121C19)!important;color:var(--pl-text,#E8EFEB)!important
}
#pai-root[data-theme="dark"] .pai-chip,#pai-root[data-theme="barn"] .pai-chip,
#pai-root[data-theme="dark"] .pai-mini,#pai-root[data-theme="barn"] .pai-mini{
  background:#18241F!important;border-color:#23322C!important;color:var(--pl-text,#E8EFEB)!important
}
#pai-root[data-theme="dark"] .pai-bar input,#pai-root[data-theme="barn"] .pai-bar input{
  background:#0A1210!important;border-color:#2a3a34!important;color:var(--pl-text,#E8EFEB)!important
}

#nov7-fab{display:flex !important;align-items:center;justify-content:center}
html[data-n7v="m"] #ai-fab{display:none !important}
html[data-n7v="m"] #nov7-fab{display:flex !important;align-items:center;justify-content:center;width:44px;height:44px;min-width:44px;min-height:44px;padding:0 2px;box-sizing:border-box;font-size:10px;line-height:1.05;text-align:center;right:8px !important;bottom:calc(56px + env(safe-area-inset-bottom,0px)) !important;z-index:20}
html[data-n7v="m"] .tabbar{z-index:6;display:grid !important}
html[data-n7v="m"] .entry,html[data-n7v="m"] #m-main .page{padding-bottom:72px}
html[data-n7v="m"] .rchips,html[data-n7v="m"] .n7-chips,html[data-n7v="m"] .chiprow,html[data-n7v="m"] .n7-dis .n7-chips{padding-right:56px;box-sizing:border-box}
html[data-n7v] .dl2-h h2{font-size:clamp(15px,4.2vw,22px);display:flex;flex-wrap:wrap;align-items:baseline;gap:2px 8px;min-width:0}
html[data-n7v] .dl2-h h2 span{white-space:nowrap;font-size:0.86em;overflow:hidden;text-overflow:ellipsis;min-width:0}

/* entry 소/중/대 — flex so 360px labels stay horizontal */

.entry .fg.n7-mate-top,.entry .fg.n7-mate-mid{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:8px 12px;width:100%;max-width:100%;align-items:start;margin:0 0 8px}
.entry .fg.n7-mate-top>.n7-f,.entry .fg.n7-mate-mid>.n7-f{display:flex;flex-direction:column;gap:4px;min-width:0;max-width:100%;width:100%}
.entry .fg.n7-mate-top .ef-row,.entry .fg.n7-mate-mid .ef-row{display:flex;flex-wrap:nowrap;gap:8px;align-items:center;width:100%}
.entry .fg.n7-mate-top .lim,.entry .n7-f>.lim{margin:0;align-self:flex-end;font-size:12px;line-height:1.2}
.entry .fg.n7-mate-top .ef-nick-box{margin:2px 0 0;grid-column:auto;width:100%}
html[data-n7v="m"] .entry .fg.n7-mate-top,html[data-n7v="m"] .entry .fg.n7-mate-mid,
html[data-n7v="field"] .entry .fg.n7-mate-top,html[data-n7v="field"] .entry .fg.n7-mate-mid{grid-template-columns:minmax(0,1fr)}
.entry #ef-sow:not(:has(*)){display:none!important;margin:0;padding:0;border:0;min-height:0}
.ef-nick-box [hidden] label.l,.ef-nick-box > label.l{display:none}
.ef-nick-box [hidden] [data-limc="nickname"]{display:none!important}
.entry .ef-nick-box label.l{display:none!important}
.entry .ef-nick-box [data-nick-pane]:not([hidden]) label.l,
.entry .ef-nick-box > div:not(.ef-nick-fold):not([hidden]) label.l{display:block!important}
.n7-fgrid{display:flex;flex-wrap:wrap;gap:8px 10px;align-items:flex-start}
.n7-fgrid>.n7-f{display:flex;flex-direction:column;gap:4px;min-width:0;box-sizing:border-box;writing-mode:horizontal-tb;word-break:keep-all;overflow-wrap:anywhere}
.n7-fgrid>.n7-f>label.l{margin:0;writing-mode:horizontal-tb;word-break:keep-all;white-space:normal}
.n7-fs{flex:1 1 calc(33.333% - 8px);max-width:calc(33.333% - 8px)}
.n7-fm{flex:1 1 calc(50% - 8px);max-width:calc(50% - 8px)}
.n7-fl{flex:1 1 100%;max-width:100%}
.n7-tagpair{flex:1 1 100%;width:100%;max-width:100%;display:flex;flex-direction:column;flex-wrap:nowrap;gap:8px;align-items:stretch;box-sizing:border-box}
.n7-tagpair>.n7-f{flex:1 1 auto;max-width:100%;min-width:0;width:100%}
.n7-tagpair .ef-row{display:flex;flex-direction:row;flex-wrap:nowrap;gap:8px;align-items:center;width:100%}
.n7-tagpair #ef-tag{flex:1 1 auto;min-width:0;width:auto;height:var(--n7-btn,44px);min-height:var(--n7-btn,44px);box-sizing:border-box}
.n7-tagpair [data-k="nickname"]{box-sizing:border-box;height:var(--n7-btn,44px);min-height:var(--n7-btn,44px)}
#ef-look.n7-look-sm,.n7-look-sm,#ef-look,#ef-abc{
  flex:0 0 auto;width:auto;min-width:3.2em;max-width:none;
  min-height:var(--n7-btn,44px);height:var(--n7-btn,44px);
  padding:0 12px;font-size:14px;white-space:nowrap;box-sizing:border-box
}

.n7-fgrid .n7-f input,.n7-fgrid .n7-f select,.n7-fgrid .n7-f textarea,.n7-fgrid .n7-f .stepper,.n7-fgrid .n7-f .seg{width:100%;min-width:0;box-sizing:border-box}
.n7-fgrid .n7-f input,.n7-fgrid .n7-f select,.n7-fgrid .n7-f .stepper input{min-height:44px}
@media(max-width:359px){.n7-fs{flex-basis:calc(50% - 8px);max-width:calc(50% - 8px)}}

/* settings cards / controls */
.n7-st-row{display:flex;flex-direction:column;gap:6px;padding:12px 0;border-bottom:1px solid #e6eee8}
.n7-st-k{display:flex;align-items:center;gap:6px;font-weight:700;font-size:15px}
.n7-st-k .n7-i{flex:none;width:32px;height:32px;border:0;border-radius:16px;background:#eef3ef;color:#3a4a40;font-weight:700}
.n7-st-d{display:none;font-size:13px;color:#5c6661;line-height:1.45;background:#f5f8f6;border-radius:10px;padding:8px 10px}
.n7-st-row.open .n7-st-d{display:block}
.n7-wd{display:flex;flex-wrap:wrap;gap:6px}
.n7-wd button{min-width:40px;min-height:40px;border-radius:10px;border:1px solid #c9d1d9;background:#fff;font-weight:700}
.n7-wd button.on{background:#1f6f43;color:#fff;border-color:#1f6f43}
.n7-tog{display:flex;align-items:center;gap:8px;min-height:44px}
.n7-tog input{width:44px;height:24px}
.n7-chiplist{display:flex;flex-wrap:wrap;gap:6px;align-items:center}
.n7-chiplist .n7-chip{display:inline-flex;align-items:center;gap:4px;padding:0 8px;min-height:36px;border-radius:18px;background:#eef6f0;border:1px solid #b7d4c0;font-size:14px}
.n7-chiplist .n7-chip button{border:0;background:none;min-width:28px;min-height:28px;font-size:16px}
.n7-time,.n7-stepn{display:flex;gap:6px;align-items:center}
.n7-stepn input,.n7-time input{min-height:44px;min-width:0;flex:1}
.n7-brn-hint{color:#9a6700;background:#fff8c5;border-radius:8px;padding:6px 8px;font-size:13px;margin-top:4px}
.n7-brn card,.n7-brn{margin:0 0 12px}

/* staff / vet cards */
.n7-staff-cards{display:flex;flex-direction:column;gap:10px;margin-top:8px}
.n7-scard{border:1px solid #d5e0d8;border-radius:14px;padding:12px;background:#fff;display:flex;flex-direction:column;gap:6px}
.n7-scard .n7-sc-top{display:flex;justify-content:space-between;align-items:flex-start;gap:8px}
.n7-scard b,.n7-vetfix b{word-break:keep-all;overflow-wrap:anywhere;white-space:normal;writing-mode:horizontal-tb}
@media(max-width:720px){
  table.t.n7-hide-m, .tw:has(> table.t.n7-hide-m){display:none !important}
  #st-staff .tw:has(.n7-staff-cards), #org-staff .tw:has(.n7-staff-cards){display:block}
  #st-staff table.t.n7-hide-m, #org-staff table.t.n7-hide-m{display:none !important}
  .n7-staff-cards{display:flex !important}
  .n7-vetfix{flex-direction:column !important;min-width:0 !important;width:100%;flex-wrap:wrap}
  .n7-vetfix>div{min-width:0 !important}
}
@media(min-width:721px){.n7-staff-cards{display:none} table.t.n7-hide-m{display:table !important}}


/* confirm card */
#n7-croot{position:fixed;inset:0;z-index:90;display:flex;align-items:flex-end;justify-content:center}
#n7-croot .n7-cback{position:absolute;inset:0;background:rgba(12,24,18,.46)}
#n7-croot .n7-ccard{position:relative;background:#fff;border-radius:16px 16px 0 0;max-height:86vh;overflow:auto;width:100%;max-width:520px;padding:16px 16px calc(16px + env(safe-area-inset-bottom,0px));box-shadow:0 -8px 32px rgba(20,40,30,.2)}
#n7-croot h3{margin:0 0 8px;font-size:18px}
#n7-croot .n7-cacts{display:flex;flex-wrap:wrap;gap:8px;margin-top:14px}
#n7-croot .n7-cacts button{flex:1;min-height:48px}
.n7-pick{display:flex;flex-direction:column;gap:6px;margin-top:10px}
.n7-pick button{min-height:48px;text-align:left;border:1px solid #d5e0d8;border-radius:12px;background:#fff;padding:8px 12px}
.n7-pick button.on{border-color:#1f6f43;background:#eef6f0;font-weight:700}

/* 이유 1복 / 체중 토글 */
.n7-wtog{display:flex;gap:6px;margin:4px 0}
.n7-wtog button{flex:1;min-height:40px;border-radius:10px;border:1px solid #c9d1d9;background:#fff;font-weight:700}
.n7-wtog button.on{background:#1f6f43;color:#fff;border-color:#1f6f43}

@media(max-width:720px){table.t.n7-hide-m{display:none !important}}
@media(min-width:721px){.n7-st-cards,.n7-staff-cards{display:none} table.t.n7-hide-m{display:table !important}}


/* t450 vacc week + week labels */
.n7-vw{border:1px solid #d5e0d8;border-radius:14px;background:#fff;padding:12px;margin:14px 0 0}
.n7-vw h3,.n7-vw .n7-vw-sum{margin:0 0 4px;font-size:17px;font-weight:700;cursor:pointer;list-style:none}
.n7-vw .n7-vw-sum::-webkit-details-marker{display:none}
.n7-vw .n7-vw-sum::after{content:'▾';float:right;font-weight:400;color:#5c6a64}
.n7-vw:not([open]) .n7-vw-sum{margin:0}
.n7-vw:not([open]) .n7-vw-sum::after{content:'▸'}
.n7-vw .n7-vw-sub{color:#5c6a64;font-size:13px;margin:0 0 10px}
.n7-vw-day{margin:0 0 10px}
.n7-vw-day h4{margin:0 0 6px;font-size:14px;color:#1b2822}
.n7-vw-row{display:flex;align-items:flex-start;gap:8px;padding:8px 6px;border-radius:10px;min-height:48px}
.n7-vw-row:nth-child(odd){background:#f4f7f5}
.n7-vw-row.skip{opacity:.7}
.n7-vw-row label{flex:1;min-width:0;display:flex;gap:8px;align-items:flex-start;cursor:pointer}
.n7-vw-row input{width:20px;height:20px;margin-top:2px;flex:0 0 auto}
.n7-vw-row .bd{min-width:0}
.n7-vw-row b{display:block;font-size:15px}
.n7-vw-row .mt{font-size:12px;color:#5c6a64;word-break:keep-all}
.n7-vw-row .why{font-size:12px;color:#8a4b00;font-weight:700}
.n7-vw-empty{color:#5c6a64;padding:8px 0}
.n7-vw-miss h4{color:#b42318}


.n7-sh{padding:0 0 16px}
.n7-sh-tabs{display:flex;gap:8px;flex-wrap:wrap;margin:0 0 12px}
.n7-sh-tabs button{min-height:44px}
.n7-sh-form{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:10px 12px;align-items:end}
.n7-sh-form .n7-sh-span{grid-column:1/-1}
.n7-sh-form label.l{display:block;margin:0 0 4px;font-size:13px;color:#3a4742}
.n7-sh-form input,.n7-sh-form select,.n7-sh-form .btn{width:100%;min-height:44px;height:44px;box-sizing:border-box}
.n7-sh-form .n7-sh-chips{display:flex;flex-wrap:wrap;gap:6px}
.n7-sh-form .n7-sh-chips .btn{width:auto;min-width:44px}
.n7-sh-form #n7-sh-save{width:auto;min-width:120px}
.n7-sh-msg:not([hidden]){color:#b42318;font-size:13px;grid-column:1/-1}
@media (min-width:900px){
  html[data-n7v="web"] .n7-sh-form input,
  html[data-n7v="web"] .n7-sh-form select,
  html[data-n7v="web"] .n7-sh-form .btn{min-height:40px;height:40px}
}
.n7-sh-chips{display:flex;flex-wrap:wrap;gap:6px}
.n7-sh-chips button{min-height:40px;min-width:48px}
.n7-sh-chips button.on{background:#0A66A8;color:#fff;border-color:#0A66A8}
.n7-sh-need{font-size:12px;color:#5c6a64;margin:0}
.n7-sh-msg{min-height:1.2em;color:#b42318;grid-column:1/-1}
.n7-sh-recap{margin-top:16px}
@media(max-width:520px){.n7-sh-form{grid-template-columns:1fr}}
.n7-rp-split{margin:0 0 14px;padding:12px;border:1px solid #e3ebe6;border-radius:14px;background:#fff}
.n7-rp-note{font-size:13px;color:#3a4742;margin:0 0 10px;word-break:keep-all}
.n7-rp-tiles{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:8px}
@media(max-width:520px){.n7-rp-tiles{grid-template-columns:1fr}}
.n7-rp-t{display:block;text-align:left;padding:12px 14px;border:1px solid #d7e0db;border-radius:12px;background:#f7faf8;min-height:64px;cursor:pointer;width:100%}
.n7-rp-t b{display:block;font-size:15px;margin:0 0 2px}
.n7-rp-t .mt{display:block;font-size:12px;color:#5c6a64}
.n7-rp-t.on{border-color:#0A66A8;background:#eef6fb;box-shadow:inset 0 3px 0 #0A66A8}
.n7h-kg{display:flex;align-items:center;gap:12px;margin:4px 0}
.n7h-gag{--p:0;width:52px;height:52px;border-radius:50%;flex:0 0 auto;background:conic-gradient(#0A66A8 calc(var(--p)*1%),#eef3f0 0);position:relative}
.n7h-gag.st-warn{background:conic-gradient(#8F5500 calc(var(--p)*1%),#eef3f0 0)}
.n7h-gag.st-bad{background:conic-gradient(#B23A0A calc(var(--p)*1%),#eef3f0 0)}
.n7h-gag.st-none{background:conic-gradient(#9AA39E calc(var(--p)*1%),#eef3f0 0)}
.n7h-gag:after{content:"";position:absolute;inset:7px;border-radius:50%;background:#fff}
.n7h-bar span{transition:width .8s ease}
.n7h-bars b{transition:height .8s ease}
@media(prefers-reduced-motion:reduce){
  .n7h-bar span,.n7h-bars b,.n7h-gag{transition:none !important}
}


/* t456 compact default + 소/중/대 scale */
html{--n7-ui:1;--n7-ctrl:32px}
html[data-n7ui=sm]{--n7-ui:.86;--n7-ctrl:28px}
html[data-n7ui=md]{--n7-ui:1;--n7-ctrl:32px}
html[data-n7ui=lg]{--n7-ui:1.22;--n7-ctrl:40px}
.btn,.btn.sm,.tabs button,.seg button,.chipb{min-height:var(--n7-ctrl)!important;padding:calc(4px * var(--n7-ui)) calc(9px * var(--n7-ui))!important;font-size:calc(13px * var(--n7-ui))!important;line-height:1.25!important}
input:not([type=checkbox]):not([type=radio]):not([type=range]):not([type=hidden]),select,textarea{min-height:var(--n7-ctrl)!important;padding:calc(4px * var(--n7-ui)) calc(8px * var(--n7-ui))!important;font-size:calc(14px * var(--n7-ui))!important;line-height:1.3!important}
.loginbox input,.loginbox .btn,.loginbox select{min-height:calc(var(--n7-ctrl) + 8px)!important}
@media (pointer:coarse),(max-width:760px){
  .btn,.btn.sm,.tabs button,.seg button,.chipb,
  input:not([type=checkbox]):not([type=radio]):not([type=range]):not([type=hidden]),select{min-height:calc(var(--n7-ctrl) + 4px)!important}
  html[data-n7ui=lg] .btn,html[data-n7ui=lg] .btn.sm,html[data-n7ui=lg] .tabs button,html[data-n7ui=lg] input:not([type=checkbox]):not([type=radio]):not([type=range]):not([type=hidden]),html[data-n7ui=lg] select{min-height:48px!important;padding:10px 14px!important;font-size:16px!important}
}
.n7-ui-sz{display:inline-flex;align-items:stretch;margin-left:8px;flex:0 0 auto;height:32px;border:1px solid #C5D0C8;border-radius:999px;overflow:hidden;background:#fff}
.n7-ui-sz button{min-height:0!important;height:100%;padding:0 8px!important;border:0!important;border-radius:0!important;background:transparent;color:var(--pl-text-2,#3D4842);font-weight:600;font-family:ui-serif,Georgia,"Times New Roman",serif;line-height:1;cursor:pointer;display:flex;align-items:center;justify-content:center}
.n7-ui-sz button[data-u=sm]{font-size:11px!important}
.n7-ui-sz button[data-u=md]{font-size:13px!important}
.n7-ui-sz button[data-u=lg]{font-size:16px!important}
.n7-ui-sz button.on{background:var(--pl-accent,#24835A);color:var(--pl-text-on-accent,#fff)}
.n7-theme{display:inline-flex;align-items:center;justify-content:center;margin-left:8px;flex:0 0 auto;width:32px;height:32px;border:1px solid var(--pl-border-control,#C5D0C8);border-radius:999px;background:var(--pl-surface,#fff);color:var(--pl-text,#16201B);cursor:pointer;padding:0}
.n7-theme svg{display:block;width:16px;height:16px}
/* 마대리 tokens (light then dark). data-theme=light/dark, empty = OS */
:root,
[data-theme="light"]{
  
  --pl-bg:#F5F7F6; 
  --pl-nav:#FFFFFF; 
  --pl-surface:#FFFFFF; 
  --pl-surface-2:#F1F4F2; 
  --pl-elevated:#FFFFFF; 
  --pl-inverse:#16201B; 
  --pl-scrim:rgba(10,16,13,.48); 

  
  --pl-text:#16201B; 
  --pl-text-2:#3D4842; 
  --pl-text-3:#5D6762; 
  --pl-text-inverse:#FFFFFF; 
  --pl-text-on-accent:#FFFFFF; 
  --pl-link:#1F6F4C; 

  
  --pl-border:#E3E8E5; 
  --pl-divider:#EDF0EE; 
  --pl-border-control:#848F89; 
  --pl-icon:#5D6762; 

  
  --pl-accent:#24835A; 
  --pl-accent-hover:#1D7150; 
  --pl-accent-pressed:#175C41; 
  --pl-accent-subtle:#E3F2EA; 
  --pl-accent-subtle-fg:#1C5F42; 
  --pl-focus:#24835A; 

  
  --pl-good:#0A66A8; 
  --pl-good-bg:#E8F1FA; 
  --pl-good-solid:#0B6FB8; 
  --pl-good-on-solid:#FFFFFF; 
  --pl-caution:#8F5500; 
  --pl-caution-bg:#FFF3DC; 
  --pl-caution-solid:#C27400; 
  --pl-caution-on-solid:#16201B; 
  --pl-bad:#B23A0A; 
  --pl-bad-bg:#FDECE4; 
  --pl-bad-solid:#C8500C; 
  --pl-bad-on-solid:#FFFFFF; 
  --pl-nodata:#5D6762; 
  --pl-nodata-bg:#F1F4F2; 
  --pl-info:#2F5D8A; 
  --pl-info-bg:#EEF3F9; 

  
  --pl-tm-good-2:#0A66A8; 
  --pl-tm-good-2-ink:#FFFFFF; 
  --pl-tm-good-1:#6AA8DC; 
  --pl-tm-good-1-ink:#0B1A26; 
  --pl-tm-warn:#E69F00; 
  --pl-tm-warn-ink:#16201B; 
  --pl-tm-bad-1:#C4530A; 
  --pl-tm-bad-1-ink:#FFFFFF; 
  --pl-tm-bad-2:#8E2D07; 
  --pl-tm-bad-2-ink:#FFFFFF; 
  --pl-tm-nodata:#D3D9D5; 
  --pl-tm-nodata-2:#DFE4E1; 
  --pl-tm-nodata-ink:#2E3833; 
  --pl-tm-group:#F1F4F2; 
  --pl-tm-select:#16201B; 

  
  --pl-chart-bar:#B9CFC2; 
  --pl-chart-bar-current:#3D4842; 
  --pl-chart-target:#16201B; 
  --pl-chart-grid:#E6EAE7; 
  --pl-chart-1:#0A66A8; 
  --pl-chart-2:#C27400; 
  --pl-chart-3:#6A4FD8; 
  --pl-chart-4:#C2456A; 
  --pl-chart-5:#5D6762; 

  
  --pl-input-bg:#FFFFFF; 
  --pl-input-text:#16201B; 
  --pl-input-placeholder:#5D6762; 
  --pl-input-border:#848F89; 
  --pl-input-disabled-bg:#F1F4F2; 

  
  --pl-hover:#F1F5F3; 
  --pl-pressed:#E6ECE9; 
  --pl-selected:#E3F2EA; 

  
  --pl-avatar-1-bg:#E3F2EA; 
  --pl-avatar-1-fg:#1C5F42;
  --pl-avatar-2-bg:#E8F1FA; 
  --pl-avatar-2-fg:#0A5A94;
  --pl-avatar-3-bg:#FDECEB; 
  --pl-avatar-3-fg:#A23C36;
  --pl-avatar-4-bg:#FFF3DC; 
  --pl-avatar-4-fg:#7A4A00;

  
  --pl-brand-tile:#24835A; 
  --pl-brand-coral:#F2867F; 
  --pl-logo-ink:#1B2822; 
  --pl-logo-sub:#24835A; 

  
  --pl-shadow-1:0 1px 2px rgba(22,32,27,.05),0 1px 3px rgba(22,32,27,.07); 
  --pl-shadow-2:0 4px 12px rgba(22,32,27,.08),0 1px 3px rgba(22,32,27,.06); 
  --pl-shadow-3:0 16px 40px rgba(22,32,27,.16),0 2px 6px rgba(22,32,27,.08); 
  --pl-shadow-accent:0 6px 16px rgba(36,131,90,.32); 

  
  --pl-focus-ring:0 0 0 2px var(--pl-surface),0 0 0 4px var(--pl-focus);
  --pl-tm-select-ring:0 0 0 2px var(--pl-surface),0 0 0 4px var(--pl-tm-select);

  
  --bg:var(--pl-bg); --surface:var(--pl-surface); --gray-900:var(--pl-text); --gray-700:var(--pl-text-2); --gray-500:var(--pl-text-3); --gray-400:var(--pl-icon); --gray-300:var(--pl-border-control); --gray-200:var(--pl-border); --gray-100:var(--pl-surface-2); --brand-600:var(--pl-accent); --brand-700:var(--pl-accent-subtle-fg); --brand-500:var(--pl-accent-hover); --brand-100:var(--pl-accent-subtle); --brand-050:var(--pl-selected); --good:var(--pl-good); --good-bg:var(--pl-good-bg); --good-fill:var(--pl-good-solid); --warn:var(--pl-caution); --warn-bg:var(--pl-caution-bg); --warn-fill:var(--pl-caution-solid); --bad:var(--pl-bad); --bad-bg:var(--pl-bad-bg); --bad-fill:var(--pl-bad-solid); --nodata:var(--pl-nodata); --nodata-bg:var(--pl-nodata-bg); --info:var(--pl-info); --info-bg:var(--pl-info-bg); --link:var(--pl-link); --link-hover:var(--pl-accent-subtle-fg); --row-line:var(--pl-divider); --th-bg:var(--pl-surface-2); --row-hover:var(--pl-hover); --row-selected:var(--pl-selected); --focus-ring:var(--pl-focus-ring); --shadow-1:var(--pl-shadow-1); --shadow-2:var(--pl-shadow-2); --scrim:var(--pl-scrim); --chart-bar:var(--pl-chart-bar); --chart-bar-current:var(--pl-chart-bar-current); --chart-target:var(--pl-chart-target); --tm-good-2:var(--pl-tm-good-2); --tm-good-1:var(--pl-tm-good-1); --tm-warn:var(--pl-tm-warn); --tm-bad-1:var(--pl-tm-bad-1); --tm-bad-2:var(--pl-tm-bad-2); --tm-nodata:var(--pl-tm-nodata);
  color-scheme:light;
}
[data-theme="dark"]{
  
  --pl-bg:#0A1210; 
  --pl-nav:#0D1714; 
  --pl-surface:#121C19; 
  --pl-surface-2:#18241F; 
  --pl-elevated:#1C2A25; 
  --pl-inverse:#E6EEEA; 
  --pl-scrim:rgba(2,6,5,.66); 

  
  --pl-text:#E8EFEB; 
  --pl-text-2:#B5C3BC; 
  --pl-text-3:#8E9E97; 
  --pl-text-inverse:#0D1714; 
  --pl-text-on-accent:#04150D; 
  --pl-link:#6FD8A6; 

  
  --pl-border:#23322C; 
  --pl-divider:#1C2925; 
  --pl-border-control:#6A7D74; 
  --pl-icon:#93A39B; 

  
  --pl-accent:#3DCB8B; 
  --pl-accent-hover:#5AD69D; 
  --pl-accent-pressed:#2FB377; 
  --pl-accent-subtle:#123526; 
  --pl-accent-subtle-fg:#8DE6BD; 
  --pl-focus:#6FD8A6; 

  
  --pl-good:#7DBBF3; 
  --pl-good-bg:#10263A; 
  --pl-good-solid:#4F9EE6; 
  --pl-good-on-solid:#06121D; 
  --pl-caution:#F4BA5E; 
  --pl-caution-bg:#2F230D; 
  --pl-caution-solid:#E6A23C; 
  --pl-caution-on-solid:#1A1205; 
  --pl-bad:#FF9672; 
  --pl-bad-bg:#371A10; 
  --pl-bad-solid:#F0743F; 
  --pl-bad-on-solid:#1C0904; 
  --pl-nodata:#8E9E97; 
  --pl-nodata-bg:#1A2621; 
  --pl-info:#9CBCE0; 
  --pl-info-bg:#15212E; 

  
  --pl-tm-good-2:#1D67A8; 
  --pl-tm-good-2-ink:#FFFFFF; 
  --pl-tm-good-1:#5E9BD0; 
  --pl-tm-good-1-ink:#07131D; 
  --pl-tm-warn:#D99A32; 
  --pl-tm-warn-ink:#150E03; 
  --pl-tm-bad-1:#C0531C; 
  --pl-tm-bad-1-ink:#FFFFFF; 
  --pl-tm-bad-2:#7E2A0B; 
  --pl-tm-bad-2-ink:#FFFFFF; 
  --pl-tm-nodata:#26332E; 
  --pl-tm-nodata-2:#2D3B35; 
  --pl-tm-nodata-ink:#C6D2CC; 
  --pl-tm-group:#18241F; 
  --pl-tm-select:#F2F7F4; 

  
  --pl-chart-bar:#2F4A3F; 
  --pl-chart-bar-current:#C9D6D0; 
  --pl-chart-target:#E8EFEB; 
  --pl-chart-grid:#1F2D28; 
  --pl-chart-1:#7DBBF3; 
  --pl-chart-2:#E6A23C; 
  --pl-chart-3:#A894FF; 
  --pl-chart-4:#F28BAA; 
  --pl-chart-5:#8E9E97; 

  
  --pl-input-bg:#0F1815; 
  --pl-input-text:#E8EFEB; 
  --pl-input-placeholder:#8E9E97; 
  --pl-input-border:#6A7D74; 
  --pl-input-disabled-bg:#151F1B; 

  
  --pl-hover:#1A2622; 
  --pl-pressed:#22302B; 
  --pl-selected:#123526; 

  
  --pl-avatar-1-bg:#123526; 
  --pl-avatar-1-fg:#8DE6BD;
  --pl-avatar-2-bg:#10263A; 
  --pl-avatar-2-fg:#9CCBF5;
  --pl-avatar-3-bg:#36191C; 
  --pl-avatar-3-fg:#F7A8A2;
  --pl-avatar-4-bg:#2F230D; 
  --pl-avatar-4-fg:#F4BA5E;

  
  --pl-brand-tile:#24835A; 
  --pl-brand-coral:#F2867F; 
  --pl-logo-ink:#EEF4F0; 
  --pl-logo-sub:#6FD8A6; 

  
  --pl-shadow-1:0 0 0 1px rgba(255,255,255,.02),0 1px 2px rgba(0,0,0,.5); 
  --pl-shadow-2:inset 0 1px 0 rgba(255,255,255,.04),0 6px 16px rgba(0,0,0,.45); 
  --pl-shadow-3:inset 0 1px 0 rgba(255,255,255,.06),0 20px 48px rgba(0,0,0,.6),0 0 0 1px rgba(0,0,0,.3); 
  --pl-shadow-accent:0 6px 20px rgba(61,203,139,.22); 

  
  --pl-focus-ring:0 0 0 2px var(--pl-surface),0 0 0 4px var(--pl-focus);
  --pl-tm-select-ring:0 0 0 2px var(--pl-surface),0 0 0 4px var(--pl-tm-select);

  
  --bg:var(--pl-bg); --surface:var(--pl-surface); --gray-900:var(--pl-text); --gray-700:var(--pl-text-2); --gray-500:var(--pl-text-3); --gray-400:var(--pl-icon); --gray-300:var(--pl-border-control); --gray-200:var(--pl-border); --gray-100:var(--pl-surface-2); --brand-600:var(--pl-accent); --brand-700:var(--pl-accent-subtle-fg); --brand-500:var(--pl-accent-hover); --brand-100:var(--pl-accent-subtle); --brand-050:var(--pl-selected); --good:var(--pl-good); --good-bg:var(--pl-good-bg); --good-fill:var(--pl-good-solid); --warn:var(--pl-caution); --warn-bg:var(--pl-caution-bg); --warn-fill:var(--pl-caution-solid); --bad:var(--pl-bad); --bad-bg:var(--pl-bad-bg); --bad-fill:var(--pl-bad-solid); --nodata:var(--pl-nodata); --nodata-bg:var(--pl-nodata-bg); --info:var(--pl-info); --info-bg:var(--pl-info-bg); --link:var(--pl-link); --link-hover:var(--pl-accent-subtle-fg); --row-line:var(--pl-divider); --th-bg:var(--pl-surface-2); --row-hover:var(--pl-hover); --row-selected:var(--pl-selected); --focus-ring:var(--pl-focus-ring); --shadow-1:var(--pl-shadow-1); --shadow-2:var(--pl-shadow-2); --scrim:var(--pl-scrim); --chart-bar:var(--pl-chart-bar); --chart-bar-current:var(--pl-chart-bar-current); --chart-target:var(--pl-chart-target); --tm-good-2:var(--pl-tm-good-2); --tm-good-1:var(--pl-tm-good-1); --tm-warn:var(--pl-tm-warn); --tm-bad-1:var(--pl-tm-bad-1); --tm-bad-2:var(--pl-tm-bad-2); --tm-nodata:var(--pl-tm-nodata);
  color-scheme:dark;
}
@media (prefers-color-scheme: dark){
  :root:not([data-theme="light"]){
    
    --pl-bg:#0A1210; 
    --pl-nav:#0D1714; 
    --pl-surface:#121C19; 
    --pl-surface-2:#18241F; 
    --pl-elevated:#1C2A25; 
    --pl-inverse:#E6EEEA; 
    --pl-scrim:rgba(2,6,5,.66); 

    
    --pl-text:#E8EFEB; 
    --pl-text-2:#B5C3BC; 
    --pl-text-3:#8E9E97; 
    --pl-text-inverse:#0D1714; 
    --pl-text-on-accent:#04150D; 
    --pl-link:#6FD8A6; 

    
    --pl-border:#23322C; 
    --pl-divider:#1C2925; 
    --pl-border-control:#6A7D74; 
    --pl-icon:#93A39B; 

    
    --pl-accent:#3DCB8B; 
    --pl-accent-hover:#5AD69D; 
    --pl-accent-pressed:#2FB377; 
    --pl-accent-subtle:#123526; 
    --pl-accent-subtle-fg:#8DE6BD; 
    --pl-focus:#6FD8A6; 

    
    --pl-good:#7DBBF3; 
    --pl-good-bg:#10263A; 
    --pl-good-solid:#4F9EE6; 
    --pl-good-on-solid:#06121D; 
    --pl-caution:#F4BA5E; 
    --pl-caution-bg:#2F230D; 
    --pl-caution-solid:#E6A23C; 
    --pl-caution-on-solid:#1A1205; 
    --pl-bad:#FF9672; 
    --pl-bad-bg:#371A10; 
    --pl-bad-solid:#F0743F; 
    --pl-bad-on-solid:#1C0904; 
    --pl-nodata:#8E9E97; 
    --pl-nodata-bg:#1A2621; 
    --pl-info:#9CBCE0; 
    --pl-info-bg:#15212E; 

    
    --pl-tm-good-2:#1D67A8; 
    --pl-tm-good-2-ink:#FFFFFF; 
    --pl-tm-good-1:#5E9BD0; 
    --pl-tm-good-1-ink:#07131D; 
    --pl-tm-warn:#D99A32; 
    --pl-tm-warn-ink:#150E03; 
    --pl-tm-bad-1:#C0531C; 
    --pl-tm-bad-1-ink:#FFFFFF; 
    --pl-tm-bad-2:#7E2A0B; 
    --pl-tm-bad-2-ink:#FFFFFF; 
    --pl-tm-nodata:#26332E; 
    --pl-tm-nodata-2:#2D3B35; 
    --pl-tm-nodata-ink:#C6D2CC; 
    --pl-tm-group:#18241F; 
    --pl-tm-select:#F2F7F4; 

    
    --pl-chart-bar:#2F4A3F; 
    --pl-chart-bar-current:#C9D6D0; 
    --pl-chart-target:#E8EFEB; 
    --pl-chart-grid:#1F2D28; 
    --pl-chart-1:#7DBBF3; 
    --pl-chart-2:#E6A23C; 
    --pl-chart-3:#A894FF; 
    --pl-chart-4:#F28BAA; 
    --pl-chart-5:#8E9E97; 

    
    --pl-input-bg:#0F1815; 
    --pl-input-text:#E8EFEB; 
    --pl-input-placeholder:#8E9E97; 
    --pl-input-border:#6A7D74; 
    --pl-input-disabled-bg:#151F1B; 

    
    --pl-hover:#1A2622; 
    --pl-pressed:#22302B; 
    --pl-selected:#123526; 

    
    --pl-avatar-1-bg:#123526; 
    --pl-avatar-1-fg:#8DE6BD;
    --pl-avatar-2-bg:#10263A; 
    --pl-avatar-2-fg:#9CCBF5;
    --pl-avatar-3-bg:#36191C; 
    --pl-avatar-3-fg:#F7A8A2;
    --pl-avatar-4-bg:#2F230D; 
    --pl-avatar-4-fg:#F4BA5E;

    
    --pl-brand-tile:#24835A; 
    --pl-brand-coral:#F2867F; 
    --pl-logo-ink:#EEF4F0; 
    --pl-logo-sub:#6FD8A6; 

    
    --pl-shadow-1:0 0 0 1px rgba(255,255,255,.02),0 1px 2px rgba(0,0,0,.5); 
    --pl-shadow-2:inset 0 1px 0 rgba(255,255,255,.04),0 6px 16px rgba(0,0,0,.45); 
    --pl-shadow-3:inset 0 1px 0 rgba(255,255,255,.06),0 20px 48px rgba(0,0,0,.6),0 0 0 1px rgba(0,0,0,.3); 
    --pl-shadow-accent:0 6px 20px rgba(61,203,139,.22); 

    
    --pl-focus-ring:0 0 0 2px var(--pl-surface),0 0 0 4px var(--pl-focus);
    --pl-tm-select-ring:0 0 0 2px var(--pl-surface),0 0 0 4px var(--pl-tm-select);

    
    --bg:var(--pl-bg); --surface:var(--pl-surface); --gray-900:var(--pl-text); --gray-700:var(--pl-text-2); --gray-500:var(--pl-text-3); --gray-400:var(--pl-icon); --gray-300:var(--pl-border-control); --gray-200:var(--pl-border); --gray-100:var(--pl-surface-2); --brand-600:var(--pl-accent); --brand-700:var(--pl-accent-subtle-fg); --brand-500:var(--pl-accent-hover); --brand-100:var(--pl-accent-subtle); --brand-050:var(--pl-selected); --good:var(--pl-good); --good-bg:var(--pl-good-bg); --good-fill:var(--pl-good-solid); --warn:var(--pl-caution); --warn-bg:var(--pl-caution-bg); --warn-fill:var(--pl-caution-solid); --bad:var(--pl-bad); --bad-bg:var(--pl-bad-bg); --bad-fill:var(--pl-bad-solid); --nodata:var(--pl-nodata); --nodata-bg:var(--pl-nodata-bg); --info:var(--pl-info); --info-bg:var(--pl-info-bg); --link:var(--pl-link); --link-hover:var(--pl-accent-subtle-fg); --row-line:var(--pl-divider); --th-bg:var(--pl-surface-2); --row-hover:var(--pl-hover); --row-selected:var(--pl-selected); --focus-ring:var(--pl-focus-ring); --shadow-1:var(--pl-shadow-1); --shadow-2:var(--pl-shadow-2); --scrim:var(--pl-scrim); --chart-bar:var(--pl-chart-bar); --chart-bar-current:var(--pl-chart-bar-current); --chart-target:var(--pl-chart-target); --tm-good-2:var(--pl-tm-good-2); --tm-good-1:var(--pl-tm-good-1); --tm-warn:var(--pl-tm-warn); --tm-bad-1:var(--pl-tm-bad-1); --tm-bad-2:var(--pl-tm-bad-2); --tm-nodata:var(--pl-tm-nodata);
    color-scheme:dark;
  }
}
body{background:var(--pl-bg,#F5F7F6);color:var(--pl-text,#16201B)}
.card,.loginbox,.shp,.shell aside,aside,.whead,header,.mh{background:var(--pl-nav,#fff);color:var(--pl-text,#16201B);border-color:var(--pl-border,#E3E8E5)}
.card,.loginbox,.shp,.shell .main,#w-main{background:var(--pl-bg,#F5F7F6)}
.card,.loginbox{background:var(--pl-surface,#fff)}
input,select,textarea,.btn.sec,.unit-input{background:var(--pl-input-bg,#fff);color:var(--pl-input-text,#16201B);border-color:var(--pl-border-control,#848F89)}
.mut,.foot{color:var(--pl-text-3,#5D6762)}
.n7-ui-sz{background:var(--pl-surface,#fff);border-color:var(--pl-border-control,#848F89)}
.n7-ui-sz button{color:var(--pl-text-2,#3D4842)}
.btn:not(.sec){background:var(--pl-accent,#24835A);color:var(--pl-text-on-accent,#fff)}
.tm-tile.good-2{color:var(--pl-tm-good-2-ink,#fff)}
.tm-tile.good-1{color:var(--pl-tm-good-1-ink,#0B1A26)}
.tm-tile.warn{color:var(--pl-tm-warn-ink,#16201B)}
.tm-tile.bad-1{color:var(--pl-tm-bad-1-ink,#fff)}
.tm-tile.bad-2{color:var(--pl-tm-bad-2-ink,#fff)}
.tm-tile.nodata,.tm-tile.none{color:var(--pl-tm-nodata-ink,#2E3833)}
@media (max-width:700px){
  .n7-theme{width:28px;height:28px;margin-left:6px}
  .n7-ui-sz{height:28px}
  .mh .n7-ui-sz{margin-left:auto}
}
@media screen and (max-width:1023px){
  html[data-n7v="web"] .top{flex-wrap:wrap!important;gap:8px;min-width:0}
  html[data-n7v="web"] .top h2{flex:1 1 auto;min-width:0}
  html[data-n7v="web"] .top #open-notices,html[data-n7v="web"] .top #n7-ui-sz,html[data-n7v="web"] .top #n7-theme,html[data-n7v="web"] .top #w-out,html[data-n7v="web"] .top #n7-rail-btn{flex:0 0 auto}
  html[data-n7v="web"] .shell,html[data-n7v="web"] .shell>div,html[data-n7v="web"] #w-main{min-width:0;max-width:100%}
  html[data-n7v="web"] #w-main .tw{max-width:100%;overflow-x:auto}
}
html[data-n7v="m"] .entry .n7-f:has([data-k="두수"]),html[data-n7v="m"] .entry .n7-f:has([data-k="폐사두수"]){
  flex:1 1 100%!important;max-width:100%!important;width:100%!important;
}
html[data-n7v="m"] .entry .stepper,html[data-n7v="m"] .entry.big .stepper{
  display:flex!important;flex-direction:row!important;flex-wrap:nowrap!important;align-items:center;gap:8px;max-width:100%;
}
html[data-theme="dark"]{--card:var(--pl-surface,#121C19);--line:var(--pl-border,#23322C);--tx:var(--pl-text,#E8EFEB);--mut:var(--pl-text-2,#B5C3BC);--sub:var(--pl-surface-2,#18241F);--bg:var(--pl-bg,#0A1210);--pl-color-surface-subtle:var(--pl-surface-2,#18241F);--pl-color-surface:var(--pl-surface,#121C19);--pl-color-bg:var(--pl-bg,#0A1210);--pl-color-text:var(--pl-text,#E8EFEB);--pl-color-text-muted:var(--pl-text-2,#B5C3BC);--pl-color-border:var(--pl-border,#23322C)}
html[data-theme="dark"] .n7h-sec,html[data-theme="dark"] .n7h-card,html[data-theme="dark"] .n7h-wchip,
html[data-theme="dark"] .n7h-alert,html[data-theme="dark"] #w-main .card,html[data-theme="dark"] main .card,
html[data-theme="dark"] .kcard,html[data-theme="dark"] .shp{
  background:var(--pl-surface,#121C19)!important;color:var(--pl-text,#E8EFEB);border-color:var(--pl-border,#23322C)!important;
}
html[data-theme="dark"] .kv div,html[data-theme="barn"] .kv div{
  background:var(--pl-surface-2,#18241F)!important;color:var(--pl-text,#E8EFEB)!important;border:1px solid var(--pl-border,#3A4742);
}
html[data-theme="dark"] .kv div span,html[data-theme="barn"] .kv div span{color:var(--pl-text-3,#8E9E97)!important}
html[data-theme="dark"] .kv div b,html[data-theme="barn"] .kv div b{color:var(--pl-text,#E8EFEB)!important}
@media (prefers-color-scheme: dark){
  :root:not([data-theme="light"]):not([data-theme="sun"]){--sub:var(--pl-surface-2,#18241F);--pl-color-surface-subtle:var(--pl-surface-2,#18241F)}
  :root:not([data-theme="light"]):not([data-theme="sun"]) .kv div{background:var(--pl-surface-2,#18241F)!important;color:var(--pl-text,#E8EFEB)!important;border:1px solid var(--pl-border,#23322C)}
  :root:not([data-theme="light"]):not([data-theme="sun"]) .kv div span{color:var(--pl-text-3,#8E9E97)!important}
  :root:not([data-theme="light"]):not([data-theme="sun"]) .kv div b{color:var(--pl-text,#E8EFEB)!important}
}


.mh .n7-ui-sz{margin-left:auto}
/* t455 period */
.n7-per{display:flex;flex-direction:column;gap:6px;margin:0 0 10px}
.n7-per-row{display:flex;align-items:center;flex-wrap:wrap;gap:4px}
.n7-per-row b{font-size:12px;min-width:2.2em;color:#5c6a64}
.n7-per-row button{min-width:2.2em}
.n7-per-c{margin:0}
.n7-per-c>summary{cursor:pointer;font-size:12px;color:#5c6a64;list-style:none}
.n7-per-c>summary::-webkit-details-marker{display:none}
.n7-per-rng{font-size:12px}
/* t451 vacc batch + hist */
.n7-vw-bar{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin:0 0 8px}
.n7-vh{margin-top:14px}
.n7-vh h3{margin:0 0 6px;font-size:16px}
.n7-vh-row{display:flex;gap:10px;align-items:baseline;padding:6px 0;border-bottom:1px solid #e6eee8;font-size:14px}
.n7-vh-row b{min-width:76px}
.n7-vh-row .mt{font-size:12px;color:#5c6a64}
.n7-vh-row.is-cx{opacity:.9}
.n7-vh-cx{display:inline-block;margin-left:6px;padding:0 6px;border-radius:6px;background:#fde8e4;color:#9b2c2c;font-size:12px;font-weight:700}
@media (max-width:420px){.n7-vh-row{font-size:13px;gap:6px}.n7-vh-row b{min-width:64px}}

.n7-cert-card .n7-cert-ops{display:flex;flex-wrap:wrap;gap:8px;margin:8px 0}
.n7-cert-card label.n7-cert-ck{display:inline-flex;align-items:center;gap:6px;border:1px solid var(--line,#d5ddd8);border-radius:999px;padding:6px 10px;min-height:36px;cursor:pointer;font-size:13px}
.n7-cert-card label.n7-cert-ck.on{background:#1E7E48;color:#fff;border-color:#1E7E48}
.n7-cdoc .n7-cdoc-tabs{display:flex;flex-wrap:wrap;gap:6px;margin:8px 0 12px}
.n7-cdoc .n7-cdoc-tabs button{min-height:36px;padding:6px 10px}
.n7-cdoc-sheet{background:#fff;border:1px solid #d5ddd8;border-radius:8px;padding:16px;overflow:auto}
.n7-cdoc-sheet h2{font-size:18px;margin:0 0 4px}
.n7-cdoc-sheet table{width:100%;border-collapse:collapse;font-size:12px}
.n7-cdoc-sheet th,.n7-cdoc-sheet td{border:1px solid #bbb;padding:4px 6px}
.n7-cdoc-sign{display:flex;justify-content:flex-end;gap:24px;margin-top:16px;font-size:13px}
.n7-nextstall{margin-left:6px;white-space:nowrap}
@media print{.n7-cdoc .noprint{display:none!important}.n7-cdoc-sheet{border:0;padding:0}}

/* t450 weekly accordion + offline header chip */
.n7-acc{border:1px solid #d5e0da;border-radius:12px;background:#fff;margin:10px 0;overflow:hidden}
.n7-acc>summary{cursor:pointer;list-style:none;padding:12px 14px;font-weight:700;display:flex;align-items:center;gap:8px;min-height:44px}
.n7-acc>summary::-webkit-details-marker{display:none}
.n7-acc>summary::before{content:'▸';color:#1b6b4a;font-size:14px}
.n7-acc[open]>summary::before{content:'▾'}
.n7-acc-b{padding:0 14px 14px}
.n7-obchip.outbox,.top .outbox,.mh .outbox{position:static!important;left:auto!important;right:auto!important;bottom:auto!important;transform:none!important;min-height:28px!important;padding:2px 8px!important;font-size:12px!important;font-weight:700;border-radius:8px!important;margin-left:6px;width:auto!important;max-width:46vw;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;box-shadow:none!important;background:#1b6b4a!important;color:#fff!important;flex:0 0 auto}
.n7-obchip.outbox.need,.top .outbox.need,.mh .outbox.need{background:#8A4B00!important;outline:2px solid #FFD58A}
.n7-sync{display:inline-flex;align-items:center;margin-left:6px;min-height:28px;padding:2px 8px;font-size:11px;font-weight:600;border:1px solid #c5d0c8;background:#f4f7f5;color:#1b2822;border-radius:8px;cursor:pointer;max-width:42vw;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.n7-sync-card{margin:12px 0;padding:12px 14px}
.n7-sync-card .row{display:flex;gap:8px;flex-wrap:wrap;align-items:center}
@media print{
  .n7-acc{border:0;background:none;margin:8px 0}
  .n7-acc>summary{display:block;padding:0 0 6px;min-height:0}
  .n7-acc>summary::before{content:none}
  .n7-acc:not([open])>.n7-acc-b{display:block!important}
  .n7-obchip,.n7-sync,#pl-offband{display:none!important}
}
/* t458u F01-F03 F07 F08 F10 F16 */
.ef-row > .f, .ef-row > input.f, #ef-date{
  min-width:150px;flex:1 1 150px;width:auto;box-sizing:border-box
}
.stepper input, .far-line .stepper > .f, .entry.big.far .stepper input{
  min-width:56px !important;width:56px !important;flex:0 0 56px !important;box-sizing:border-box
}
.n7-tagpair #ef-tag, #ef-tag{
  min-width:96px !important;flex:1 1 96px !important;width:auto;box-sizing:border-box
}
html[data-n7v="m"] .n7-abar{
  bottom:calc(80px + env(safe-area-inset-bottom,0px));
  padding-bottom:8px;z-index:35
}
html[data-n7v="m"] body.n7-abar-on #m-main,
html[data-n7v="m"] body.n7-abar-on #m-page{
  padding-bottom:calc(80px + 80px + env(safe-area-inset-bottom,0px))
}
html[data-n7v="m"] #m-main, html[data-n7v="field"] #app main{
  padding-bottom:calc(120px + env(safe-area-inset-bottom,0px))
}
html[data-n7v="m"] .card.more, html[data-n7v="m"] #m-main .more{
  padding-bottom:calc(88px + env(safe-area-inset-bottom,0px))
}
html[data-n7v="m"] body.n7-abar-on #nov7-fab,
html[data-n7v="m"] body.m-far #nov7-fab,
body.n7-abar-on #nov7-fab{
  width:40px !important;height:40px !important;min-width:40px !important;min-height:40px !important;
  font-size:0;line-height:0;z-index:25;
  bottom:calc(80px + 72px + env(safe-area-inset-bottom,0px)) !important
}
html[data-n7v="m"] #nov7-fab{
  bottom:calc(80px + env(safe-area-inset-bottom,0px)) !important
}
html[data-n7v="m"] body.n7-abar-on #nov7-fab::after,
html[data-n7v="m"] body.m-far #nov7-fab::after{content:none}
/* t496-P1 F08: FAB must not cover tables / bottom actions */
html[data-n7v="web"] #w-main, html[data-n7v="web"] .shell #w-main{padding-bottom:96px}
html[data-n7v="web"] .tw, html[data-n7v="web"] .card.list, html[data-n7v="web"] .dl2, html[data-n7v="web"] .more{padding-bottom:24px}
html[data-n7v="web"] #nov7-fab{
  width:48px;height:48px;min-width:48px;min-height:48px;padding:0;border-radius:999px;
  font-size:10px;line-height:1.1;text-align:center;right:16px;bottom:16px;z-index:30
}
html[data-n7v="m"] #m-main .list, html[data-n7v="m"] #m-main .card.more, html[data-n7v="m"] .more{padding-bottom:calc(96px + env(safe-area-inset-bottom,0px))}
.n7-vet-ro{margin:8px 0}

/* size pill keeps its own compact 32px tokens; do not force 40px here */
html[data-n7v="m"] .btn.sm, html[data-n7v="m"] .btn.md, html[data-n7v="field"] .btn.sm{
  position:relative
}
html[data-n7v="m"] .btn.sm::before, html[data-n7v="m"] .btn.md::before,
html[data-n7v="field"] .btn.sm::before{
  content:"";position:absolute;top:50%;left:50%;
  width:44px;height:44px;transform:translate(-50%,-50%);
  pointer-events:auto
}


/* t458u P2/P3 + t459u 일보 확정 */
.n7-per{display:flex;flex-wrap:wrap;align-items:center;gap:4px 8px;margin:6px 0}
.n7-per-row{display:inline-flex;align-items:center;gap:4px;margin:0}
.n7-per-row b{font-size:12px;font-weight:600;color:#6B756F;margin-right:2px}
.n7h-delta.flat,.n7-none,.pm.none,.mut.flat{color:#6B756F !important}
.badge.b-blue{color:#1d4f8a;background:#dbeafe}
#en-t{display:flex;flex-wrap:wrap;gap:4px}
#en-t button[data-t]{flex:1 1 28%;min-width:72px}
html[data-n7v="m"] body{font-size:14px}
html[data-n7v="m"][data-n7ui="소"] body{font-size:13px}
html[data-n7v="m"] .ef-row, html[data-n7v="m"] .n7-fgrid{align-items:center}
html[data-n7v="m"] .ef-row > *, html[data-n7v="m"] .n7-fgrid > *{min-width:0}
html[data-n7v="w"] #ev-c, html[data-n7v="w"] #ev-fl, html[data-n7v="w"] .mi,
html[data-n7v="w"] .att-who{min-height:24px;min-width:24px}
html[data-n7v="w"] input[type=checkbox]{min-width:18px;min-height:18px}
html[data-n7v="w"] label:has(>input[type=checkbox]){min-height:24px;display:inline-flex;align-items:center;gap:6px;padding:2px 4px}
@media (min-width:700px){
  html[data-n7v="m"] #m-main, html[data-n7v="m"] .tabbar, html[data-n7v="m"] .mh{
    max-width:560px;margin-left:auto;margin-right:auto;width:100%
  }
}
html[data-n7v="field"] #f-fb{display:none !important}
html[data-n7v="field"] .ef-row{flex-wrap:nowrap;align-items:center;gap:6px}
html[data-n7v="field"] .ef-row [data-day]{flex:0 0 auto;width:auto}
html[data-n7v="field"] .fh.home .fh1{
  display:flex;align-items:center;gap:6px;flex-wrap:nowrap
}
html[data-n7v="field"] .fh.home .fh1 .t,
html[data-n7v="field"] .fh.home .fh1 .brand,
html[data-n7v="field"] .fh.home .fh1 .logo{
  flex:0 0 auto
}
html[data-n7v="field"] .fh.home .fh1 .t{
  order:0 !important;
  flex:1 1 auto !important;
  min-width:0 !important;
  max-width:100%;
  margin-top:0 !important;
  font-size:16px !important;
  white-space:nowrap !important;
  overflow:hidden !important;
  text-overflow:ellipsis !important;
  line-height:1.2
}
html[data-n7v="field"] #n7-field-gear{
  position:relative;margin-left:auto;flex:0 0 auto;z-index:5
}
html[data-n7v="field"] #n7-field-gear > summary{
  list-style:none;cursor:pointer;min-width:40px;min-height:40px;width:40px;
  display:flex;align-items:center;justify-content:center;font-size:18px
}
html[data-n7v="field"] #n7-field-gear > summary::-webkit-details-marker{display:none}
html[data-n7v="field"] #n7-field-gear[open] .n7-fg-pan{
  position:absolute;right:0;top:100%;z-index:40;background:#fff;border:1px solid #d7ddd9;
  border-radius:10px;padding:8px;box-shadow:0 8px 24px rgba(0,0,0,.12);min-width:160px
}
html[data-n7v="field"] .fh.home #f-out,
html[data-n7v="field"] .fh.home .fh1 #f-out{
  flex:0 0 auto !important;
  min-width:auto !important;
  width:auto !important;
  min-height:40px !important;
  height:40px;
  padding:0 10px !important;
  font-size:13px !important;
  line-height:40px;
  white-space:nowrap;
  z-index:4
}
.n7-fold{margin:4px 0;font-size:13px;color:#6B756F}
.n7-fold > summary{cursor:pointer;list-style:none}
.n7-fold > summary::-webkit-details-marker{display:none}
.n7-ilbo{display:flex;flex-wrap:wrap;align-items:center;gap:6px 8px;margin:6px 0;padding:6px 0;font-size:13px}
.n7-ilbo-st{color:#3d4a44}
.n7-ilbo-note{font-size:12px;color:#6B756F}
.n7-ilbo-week{display:flex;flex-wrap:wrap;gap:4px;font-size:12px}
.n7-ilbo-chip{display:inline-flex;align-items:center;gap:4px;padding:2px 8px;border-radius:999px;background:#eef3f0;color:#3d4a44}
.n7-ilbo-chip.ok{background:#e6f4ea;color:#1e6b3a}
.n7-ilbo-chip.wait{background:#f3f4f3;color:#6B756F}
.n7-ask{position:fixed;inset:0;z-index:80;background:rgba(20,24,22,.45);display:flex;align-items:flex-end;justify-content:center;padding:16px}
.n7-ask .n7-ask-c{background:#fff;border-radius:14px 14px 0 0;padding:16px;width:100%;max-width:420px;box-shadow:0 -8px 28px rgba(0,0,0,.16)}
@media (min-width:720px){
  .n7-ask{align-items:center}
  .n7-ask .n7-ask-c{border-radius:14px}
}
.n7-ask h3{margin:0 0 8px;font-size:16px}
.n7-ask p{margin:0 0 10px;font-size:14px;color:#3d4a44}
.n7-ask textarea{width:100%;min-height:64px;font-size:14px;padding:8px;box-sizing:border-box}
.n7-ask .row{display:flex;gap:8px;justify-content:flex-end;margin-top:10px}
.n7-tom2{display:flex;align-items:center;gap:8px;padding:6px 10px;background:#eef3f0;font-size:13px}


.n7-flow{width:100%;border-collapse:collapse;font-variant-numeric:tabular-nums;font-size:13px}
.n7-flow th,.n7-flow td{padding:4px 6px;border-bottom:1px solid #e6ebe8;text-align:right;white-space:nowrap}
.n7-flow th:first-child,.n7-flow td:first-child{text-align:left;white-space:normal}
.n7-flow thead th{font-weight:600;color:#3d4a44;background:#f3f6f4}
.n7-flow tr.sum td{font-weight:700;background:#f7f9f8}
.n7-flow .work.pos{color:#1e6b3a}
.n7-flow .work.neg{color:#b42318}
.n7-flow .work.zero{color:#6B756F}
.n7-flow-sec{margin:8px 0 12px}
.n7-flow-sec h4{margin:0 0 6px;font-size:14px}
.n7-ilbo-weekrow{display:flex;flex-wrap:wrap;align-items:center;gap:6px 8px;margin:4px 0 6px;font-size:13px}
@media (max-width:400px){
  .n7-flow{font-size:12px}
  .n7-flow th,.n7-flow td{padding:3px 4px}
}

#n7-splash{position:fixed;inset:0;z-index:100000;background:#143026;display:flex;flex-direction:column;align-items:center;justify-content:center;color:#F4FFF8;cursor:pointer;transition:opacity .32s ease}
#n7-splash.out{opacity:0;pointer-events:none}
#n7-splash .n7-sp-mark{width:88px;height:88px;animation:n7-sp-in .55s ease both}
#n7-splash .n7-sp-mark svg{width:88px;height:88px;display:block}
#n7-splash .n7-sp-word{margin-top:16px;font-size:22px;font-weight:700;letter-spacing:.14em;animation:n7-sp-in .55s ease .18s both}
@keyframes n7-sp-in{from{opacity:0;transform:translateY(8px) scale(.94)}to{opacity:1;transform:none}}
@media (prefers-reduced-motion:reduce){
  #n7-splash .n7-sp-mark,#n7-splash .n7-sp-word{animation:none}
}
#n7-test-mark{position:fixed;right:8px;bottom:calc(8px + env(safe-area-inset-bottom,0px));z-index:40;background:rgba(20,48,38,.55);color:#fff;font:10px/1.2 sans-serif;border-radius:999px;padding:3px 7px;pointer-events:none;opacity:.7}
@media print{#n7-splash,#n7-test-mark,#n7-demo-ribbon,#supa-demo-band{display:none!important}}

/* t462u/t464u entry tokens: 8px grid, 40/44/48 controls, label above, left align */
html[data-n7v="field"] .entry, html[data-n7v="m"] .entry, .entry.big{
  --n7-btn:44px; --n7-gap:8px;
}
html[data-n7ui="sm"][data-n7v="field"] .entry,
html[data-n7ui="sm"][data-n7v="m"] .entry,
html[data-n7ui="sm"] .entry.big{ --n7-btn:40px; }
html[data-n7ui="lg"][data-n7v="field"] .entry,
html[data-n7ui="lg"][data-n7v="m"] .entry,
html[data-n7ui="lg"] .entry.big{ --n7-btn:48px; }
html[data-n7v="field"] .entry label.l, html[data-n7v="m"] .entry label.l, .entry.big label.l{
  display:block; text-align:left; margin:0 0 4px; font-weight:700;
}
html[data-n7v="field"] .entry.big .tagin{
  font-size:22px!important; min-height:var(--n7-btn)!important; letter-spacing:0!important;
  text-align:left!important; font-weight:700!important; padding:4px 8px!important;
}
html[data-n7v="field"] .entry.big input, html[data-n7v="field"] .entry.big select,
html[data-n7v="m"] .entry.big input, html[data-n7v="m"] .entry.big select{
  font-size:16px!important; padding:8px!important; min-height:var(--n7-btn)!important;
}
html[data-n7v="field"] .entry.big .stepper, html[data-n7v="m"] .entry.big .stepper, .tapc[data-n7step], .n7-step{
  display:flex; align-items:center; gap:var(--n7-gap); flex-wrap:nowrap; max-width:100%;
}
html[data-n7v="field"] .entry.big .step, html[data-n7v="m"] .entry.big .step,
.tapc[data-n7step] .step, .entry.big .wstep .wst{
  width:var(--n7-btn)!important; min-width:var(--n7-btn)!important; max-width:var(--n7-btn)!important;
  height:var(--n7-btn)!important; min-height:var(--n7-btn)!important; flex:0 0 var(--n7-btn)!important;
  font-size:22px!important; padding:0!important;
}
html[data-n7v="field"] .entry.big .stepper input, html[data-n7v="m"] .entry.big .stepper input,
.tapc[data-n7step] input, .entry.big .n7-step input{
  min-height:var(--n7-btn)!important; height:var(--n7-btn)!important; font-size:20px!important;
  width:4.8em; max-width:40%; flex:0 1 4.8em; text-align:center!important; font-weight:700;
}
html[data-n7v="field"] .entry .ef-row:has(#ef-date), html[data-n7v="field"] .entry .row:has(#ef-date),
html[data-n7v="m"] .entry .ef-row:has(#ef-date), html[data-n7v="m"] .entry .row:has(#ef-date){
  display:flex; flex-wrap:nowrap!important; align-items:center; gap:8px;
}
html[data-n7v="field"] .entry #ef-date, html[data-n7v="m"] .entry #ef-date{ flex:1 1 auto!important; min-width:9.5em!important; width:auto!important; }
html[data-n7v="field"] .entry [data-day], html[data-n7v="m"] .entry [data-day],
html[data-n7v="field"] .entry.big [data-day], html[data-n7v="field"] .entry.big #ef-look, html[data-n7v="field"] .entry.big #ef-abc{
  flex:0 0 auto!important; min-height:var(--n7-btn,44px)!important; min-width:44px!important;
  height:var(--n7-btn,44px)!important; padding:0 10px!important; font-size:14px!important;
}
.n7-dateko{display:none!important}
/* t474 item0: date full row, chips fixed size; 웅돈 below */
.n7-fgrid>.n7-f:has(#ef-date),.n7-f:has(#ef-date),
.n7-fgrid>.n7-f:has(input[type="date"]),.entry.far .n7-f:has(#ef-date){
  flex:1 1 100%!important;max-width:100%!important;width:100%!important;
}
html[data-n7v="field"] .entry #ef-date,html[data-n7v="m"] .entry #ef-date,
html[data-n7v="field"] .entry.far #ef-date,html[data-n7v="m"] .entry.far #ef-date,
.entry #ef-date,#ef-date{
  flex:1 1 auto!important;min-width:9.5em!important;width:auto!important;max-width:none!important;box-sizing:border-box;
}
html[data-n7v="field"] .entry [data-day],html[data-n7v="m"] .entry [data-day],
html[data-n7v="field"] .entry.big [data-day],html[data-n7v="m"] .entry.big [data-day],
.entry [data-day]{
  flex:0 0 auto!important;width:auto!important;min-width:3.2em!important;max-width:none!important;
  white-space:nowrap!important;box-sizing:border-box;
}
html[data-n7v="field"] .entry .ef-row:has(#ef-date),html[data-n7v="m"] .entry .ef-row:has(#ef-date),
html[data-n7v="field"] .entry .row:has(#ef-date),html[data-n7v="m"] .entry .row:has(#ef-date),
.entry.far .ef-row:has(#ef-date),.entry.far .row:has(#ef-date){
  display:flex!important;flex-wrap:nowrap!important;align-items:center;gap:8px;width:100%;
}
/* QA1-004 분만 줄: 총산·사산·미라 각 한 줄, 도태 2×2, 스테퍼 − 숫자 + 한 세트.
   n7-f는 세로(칸 하나), far-line만 가로. 총산+사산이 한 n7-f에 묶여도 far-line을 100%로 줄바꿈. */
.entry.far,.entry.far .n7-fgrid,.entry.big.far{flex-wrap:wrap!important}
.entry.far .n7-f:has([data-k="총산"]),
.entry.far .n7-f:has([data-k="사산"]),
.entry.far .n7-f:has([data-k="미라"]),
.entry.far .n7-f:has([data-k="실산"]){
  flex:1 1 100%!important;flex-basis:100%!important;max-width:100%!important;width:100%!important;
  display:flex!important;flex-direction:column!important;flex-wrap:nowrap!important;
  align-items:stretch;gap:8px;box-sizing:border-box;
}
.entry.far .far-line,.entry.far .m-far-line,.m-far-line{
  flex:1 1 100%!important;flex-basis:100%!important;max-width:100%!important;width:100%!important;
  display:flex!important;flex-direction:row!important;flex-wrap:nowrap!important;
  align-items:center;gap:8px;box-sizing:border-box;
}
.m-far-line>.l,.entry.far .far-line>.l,.entry.far .n7-f:has([data-k="총산"])>label.l,
.entry.far .n7-f:has([data-k="사산"])>label.l,
.entry.far .n7-f:has([data-k="미라"])>label.l{
  flex:0 0 4.5em;max-width:5em;white-space:nowrap;margin:0;
}
.entry.far .stepper,.entry.far .tapc,.entry.far .n7-step,
.tapc[data-n7step],.n7-step{
  display:flex!important;flex-direction:row!important;flex-wrap:nowrap!important;
  align-items:center;gap:8px;max-width:100%;
}
.tapc[data-n7step] .tapb,.tapc[data-n7step] .tapk{display:none!important}
.entry.far .far-culls{
  flex:1 1 100%!important;width:100%!important;max-width:100%!important;
  display:grid!important;grid-template-columns:minmax(0,1fr) minmax(0,1fr)!important;
  gap:10px 12px!important;box-sizing:border-box;
}
.entry.far .far-culls>.far-line,.entry.far .far-culls>.far-cull,.entry.far .far-culls>.n7-f{
  flex:none!important;max-width:100%!important;width:auto!important;min-width:0;
  display:flex!important;flex-direction:column!important;flex-wrap:nowrap!important;
  align-items:stretch;gap:4px;box-sizing:border-box;
}
.entry.far .far-culls>.far-line>.l,.entry.far .far-culls>.far-cull>.l,.entry.far .far-culls .l{
  flex:0 0 auto!important;max-width:none!important;min-width:0;width:auto;
  font-size:13px;font-weight:600;white-space:nowrap;margin:0;
}
.entry.far .far-culls .stepper,.entry.far .far-culls .tapc,.entry.far .far-culls .n7-step{
  width:100%;max-width:100%;justify-content:flex-start;gap:6px;
}
.entry.far .n7-f:has(.far-culls){
  flex:1 1 100%!important;max-width:100%!important;width:100%!important;
  display:flex!important;flex-direction:column!important;
}
html[data-n7v="field"] .entry.far #ef-date,html[data-n7v="m"] .entry.far #ef-date,
.entry.far #ef-date,.entry.big.far #ef-date{
  min-width:150px!important;flex:1 1 150px!important;
}
html[data-n7v="field"] .entry.far .ef-row:has(#ef-date),html[data-n7v="m"] .entry.far .ef-row:has(#ef-date),
html[data-n7v="field"] .entry.far .row:has(#ef-date),html[data-n7v="m"] .entry.far .row:has(#ef-date),
.entry.far .ef-row:has(#ef-date),.entry.far .row:has(#ef-date),
.entry.far .n7-f:has(#ef-date){
  flex-wrap:wrap!important;
}

.n7-pad{display:none; margin:8px 0 4px; max-width:280px}
.n7-pad.is-on{display:grid; grid-template-columns:repeat(3,1fr); gap:8px}
.n7-pad button{height:44px; min-height:44px; border-radius:10px; border:1px solid #D5DED9; background:#fff; font-size:18px; font-weight:600; color:#143026}
html[data-n7v="field"] .langpick, html[data-n7v="m"] .langpick,
html[data-n7v="field"] .fh .langpick, html[data-n7v="field"] .fh.sticky .langpick, html[data-n7v="field"] .fh2 .langpick{
  min-height:36px!important; max-width:7.2em!important; width:auto!important;
  font-size:13px!important; padding:2px 6px!important; flex:0 0 auto!important;
}
html[data-n7v="field"] .fh button, html[data-n7v="field"] .fh #f-back{
  min-height:44px!important; min-width:44px!important;
}
html[data-n7v="field"] .fh #f-back{font-size:24px!important; padding:0 10px!important}
html[data-n7v="field"] main .tabs button{min-height:44px!important; font-size:15px!important; padding:0 12px!important}
html[data-n7v="field"] .entry.big .seg button, html[data-n7v="m"] .entry.big .seg button,
html[data-n7v="field"] .entry.big .rchips button, html[data-n7v="m"] .entry.big .rchips button,
html[data-n7v="field"] .entry.big .chipb{
  min-height:var(--n7-btn)!important; min-width:44px!important; font-size:15px!important; padding:0 12px!important;
}
html[data-n7v="field"] .entry.big #ef-save, html[data-n7v="m"] .entry.big #ef-save{
  min-height:48px!important; font-size:17px!important;
}
@media (min-height:481px){
  html[data-n7v="field"] .entry.big #ef-save, html[data-n7v="m"] .entry.big #ef-save{
    position:sticky; bottom:calc(12px + env(safe-area-inset-bottom)); z-index:25;
  }
}
.tapc .tapb, .tapc .tapk{display:none!important}
.tapc{display:flex; align-items:center; gap:8px; flex-wrap:nowrap}
.n7-tagpair{display:flex; align-items:flex-end; gap:8px; flex-wrap:nowrap; margin:0 0 8px}
.n7-tagpair > .n7-f{flex:1 1 0; min-width:0}
.entry.big .n7-dayhint{margin:4px 0 0; font-size:13px; font-weight:600}

.n7-irm{margin:10px 0 16px;text-align:left;max-width:100%}
.n7-irm h3{margin:0 0 8px;font-size:15px;font-weight:700;color:inherit}
.n7-irm .mut{font-size:12px}
.n7-irm-sum{display:flex;flex-wrap:wrap;gap:8px;margin:0 0 10px}
.n7-irm-sum .n7-irm-chip{background:var(--card,#fff);border:1px solid var(--line,#ead9d4);border-radius:10px;padding:8px 10px;min-width:72px;text-align:left}
.n7-irm-sum .n7-irm-chip b{display:block;font-size:22px;line-height:1.15;color:#E8817A;font-variant-numeric:tabular-nums}
.n7-irm-sum .n7-irm-chip span{font-size:11px;color:var(--mut,#8a6f6a)}
.n7-irm-sum .n7-irm-chip.over b{color:#b42318}
.n7-irm-sum .n7-irm-chip.empty{opacity:.5}
.n7-irm-sum .n7-irm-chip.empty b{color:var(--mut,#8a6f6a);font-size:18px}
.n7-irm-wrap{overflow-x:auto;max-width:100%;text-align:left}
.n7-irm table{border-collapse:collapse;font-size:12.5px;margin:0;width:auto;min-width:0}
.n7-irm th,.n7-irm td{border:1px solid var(--line,#ead9d4);padding:5px 8px;white-space:nowrap;text-align:right;font-variant-numeric:tabular-nums}
.n7-irm th{background:rgba(232,129,122,.08);font-weight:600;text-align:center}
.n7-irm td.rname,.n7-irm th.rname{position:sticky;left:0;z-index:1;text-align:left;background:var(--card,#fff);font-weight:600}
.n7-irm tr.today td{font-weight:700;font-size:14px;background:rgba(232,129,122,.12);color:#c45b55}
.n7-irm tr.today td.rname{background:rgba(232,129,122,.16);color:inherit}
.n7-irm td.dead-hot{color:#b42318;font-weight:700}
.n7-irm th.sub, .n7-irm td.sub{background:rgba(0,0,0,.03)}
.n7-irm th.tot, .n7-irm td.tot{background:rgba(232,129,122,.08);font-weight:700}
.n7-irm .warn{margin:6px 0;color:#b42318;font-size:12px}
.n7-irm-cards{display:none;grid-template-columns:1fr 1fr;gap:8px;margin:0 0 8px}
.n7-irm-card{border:1px solid var(--line,#ead9d4);border-radius:12px;padding:10px 12px;text-align:left;background:var(--card,#fff)}
.n7-irm-card .hd{font-size:12px;color:var(--mut,#8a6f6a);margin:0 0 2px}
.n7-irm-card .big{font-size:28px;font-weight:800;color:#E8817A;line-height:1.1;font-variant-numeric:tabular-nums}
.n7-irm-card .meta{font-size:11px;margin-top:4px;color:var(--mut,#8a6f6a)}
.n7-irm-card .flow{font-size:12px;margin-top:4px}
.n7-irm-card.over .big{color:#b42318}
.n7-irm-card.empty{opacity:.55}
.n7-irm-breed{margin:12px 0;text-align:left}
.n7-irm-breed table{min-width:280px}
.n7-irm-bar{height:8px;border-radius:99px;background:rgba(232,129,122,.15);overflow:hidden;min-width:80px}
.n7-irm-bar i{display:block;height:100%;background:#E8817A;border-radius:99px}
@media (max-width:700px){
  .n7-irm-cards{display:grid}
  .n7-irm-pc{display:none}
  .n7-irm-sum{display:none}
  .n7-irm-more{display:block;margin:6px 0}
  .n7-irm-more .n7-irm-wrap{display:none}
  .n7-irm-more[open] .n7-irm-wrap{display:block}
}
@media (min-width:701px){ .n7-irm-more{display:none} }


.n7-wo-hist{margin:8px 0 0;padding:8px 10px;background:#f4f7f5;border-radius:10px;list-style:none}
.n7-wo-hist li{font-size:12px;color:#3a4742;margin:0 0 4px;line-height:1.35}
.n7-wo-hist li:last-child{margin:0}
.n7-wo-acts{display:flex;flex-wrap:wrap;gap:6px;align-items:center;margin:8px 0 0}
.n7-wo-acts input{flex:1 1 140px;min-width:0;min-height:40px;box-sizing:border-box}
.n7-wo-acts .btn{min-height:40px}
.bubble .badge{display:inline-block;margin-right:4px;padding:1px 6px;border-radius:999px;background:#e8f1ec;font-size:11px;font-weight:700}


.n7-wo-bar{display:flex;flex-wrap:wrap;gap:6px;margin:0 0 8px;align-items:center}
.n7-wo-bar .btn{min-height:36px}
.n7-wo-send{display:grid;grid-template-columns:minmax(0,1.2fr) minmax(0,.8fr);gap:8px 12px;align-items:end;padding:10px 0 0;border-top:1px solid var(--line,#d5e0d8);margin:8px 0 0}
.n7-wo-send h3{grid-column:1/-1;margin:0;font-size:15px}
.n7-wo-send label.l{display:block;font-size:12px;margin:0 0 4px;color:#3a4742}
.n7-wo-send select,.n7-wo-send input,.n7-wo-send textarea{width:100%;min-height:40px;box-sizing:border-box}
.n7-wo-send textarea{min-height:64px;grid-column:1/-1}
.n7-wo-send .n7-wo-send-btn{grid-column:1/-1}
@media(max-width:700px){.n7-wo-send{grid-template-columns:1fr}}

</style>
<script>

function n7Iga_(word) {
  var s = String(word || ''), last = s.charAt(s.length - 1), code = last.charCodeAt(0);
  if (!last || code < 0xAC00 || code > 0xD7A3) return s + '가';
  return s + (((code - 0xAC00) % 28) ? '이' : '가');
}
function nov7FoldFeat_(el) {
  if (!el) return;
  var sn = el.querySelector('[data-k="sowNote"]');
  if (!sn) return;
  var memo = el.querySelector('[data-k="비고"]');
  function hide(n) { if (n && n.classList) n.classList.add('n7-hide-feat'); }
  var col = sn.closest && sn.closest('.fc');
  if (col && memo && col.contains(memo)) col = null;
  if (col && col !== el) hide(col);
  else {
    var lab = sn.previousElementSibling;
    if (lab && lab.classList && lab.classList.contains('l')) hide(lab);
    hide(sn);
    var cnt = el.querySelector('[data-limc="sowNote"]');
    if (cnt) hide(cnt);
  }
  function merge() {
    if (!memo) return;
    var a = String(sn.value || '').trim(), b = String(memo.value || '').trim();
    if (!a) return;
    if (!b) memo.value = a;
    else if (b.indexOf(a) === -1) memo.value = a + '\n' + b;
  }
  merge();
  if (!sn.getAttribute('data-n7feat')) {
    sn.setAttribute('data-n7feat', '1');
    sn.addEventListener('input', function () { merge(); });
  }
}
var N7_IMP_SOW_HEAD = ['모돈번호', '품종', '산차', '전입일', '현재상태', '비고', '원본값'];
var N7_IMP_EV_HEAD = ['모돈번호', '작업일', '유형', '산차', '웅돈', '감정결과', '총산', '실산', '사산', '미라', '이유두수', '이유체중', '퇴출구분', '원인', '백신명', '비고', '원본값'];
var N7_IMP_HEAD = N7_IMP_SOW_HEAD;
var N7_IMP_PROMPT = "당신은 양돈 기록을 피그로그(PIGLOG)에 바로 넣을 수 있게 정리하는 도우미입니다.\n\n이 메시지와 함께 받은 파일을 모두 읽으세요. 장부 종류·열 배치·언어가 달라도 됩니다. 한 종류를 여러 해 치로 나눠 받은 경우(예: 2023 교배대장, 2024 교배대장, 지난 교배대장)도 같은 종류로 합칩니다. 장부 종류는 파일 이름과 열 이름을 보고 스스로 판단하세요.\n\n받을 수 있는 장부 예:\n- 모돈 명단\n- 교배대장, 지난 교배대장\n- 분만대장, 지난 분만대장\n- 이유대장, 지난 이유대장\n- 임신감정\n- 도폐사(도태·폐사·판매)\n- 백신\n- 양자·포유자돈 변동, 자돈폐사\n\n할 일\n1) 각 파일의 열을 아래 종류별 피그로그 항목에 맞춥니다. 깔끔하게 맞추지 못한 값은 '원본값' 열에 그대로 남깁니다. 값을 지어내지 마세요.\n2) 모돈번호는 앞자리 0을 지우지 마세요. 숫자로 바꾸지 마세요. 예: 0012는 0012 그대로.\n3) 날짜는 YYYY-MM-DD만 씁니다. 산차는 정수만 씁니다. 1-0 같은 표기는 앞 숫자만 씁니다.\n4) 현재상태는 다음 중 하나만 씁니다: 후보돈, 임신, 포유, 이유, 대기, 사고, 퇴출. 다른 표기는 이 중 가장 가까운 값으로 바꿉니다.\n5) 같은 모돈의 여러 장부를 한 마리로 합칩니다. 같은 번호를 퇴출 뒤에 다시 쓴 경우는 전입일로 구별하고, 전입일이 다르면 별도 모돈으로 둡니다.\n6) 산차는 분만 이력으로 다시 셉니다. 전입 산차에 분만을 시간 순으로 더합니다. 전입산차가 0이면 첫 분만이 1산입니다. 장부에 적힌 산차가 이와 다르면 그 줄은 '확인 필요' 목록에도 적고, 기록 CSV에는 다시 센 산차를 씁니다. 원본 산차는 원본값에 남깁니다.\n7) 판단이 안 되거나 앞뒤가 맞지 않는 줄은 추측해서 고치지 마세요. 예: 교배일이 전입일보다 앞섬, 분만보다 늦은 교배, 필수 값 없음, 전입일 충돌. 그런 줄은 '확인 필요' 목록에만 적습니다.\n8) 없는 값은 빈칸입니다. 설명 문장, 합계 줄, 빈 줄은 빼 주세요.\n\n종류별 규칙 — 피그로그가 실제로 받는 항목만 씁니다.\n- 교배: 한 줄에 1차·2차·3차 교배일(또는 웅돈)이 같이 있으면 교배일마다 한 줄로 나눕니다. 열은 모돈번호,작업일,산차,웅돈,교배방법,작업자,비고,원본값. 교배방법은 인공 또는 자연만 씁니다. 작업자는 이름 그대로 둡니다. 차수 칸은 만들지 마세요. 피그로그가 날짜 순으로 셉니다.\n- 임신감정: 모돈번호,작업일,산차,감정결과,비고,원본값. 감정결과는 임신, 재발, 공태, 유산, 불임 중 하나만 씁니다.\n- 분만: 모돈번호,작업일,산차,총산,실산,사산,미라,생시도태,분만구분,생시체중합,위치,비고,원본값. 약자·기형 두수는 생시도태로 합칩니다. 따로 적은 약자·기형 숫자는 원본값에 남깁니다. 생시체중(평균)만 있고 생시체중합이 없으면 실산×평균으로 합을 구하고, 계산에 썼으면 원본값에 평균을 남깁니다. 분만돈방·분만스톨은 위치 열에 둡니다. 분만구분은 정상, 유도, 조산, 난산 중 하나만 씁니다.\n- 이유: 모돈번호,작업일,산차,이유두수,이유체중합,비고,원본값. 이유체중(평균)만 있으면 이유두수×평균으로 합을 구하고 원본값에 평균을 남깁니다. 이유일령은 피그로그 이유 기록 항목이 아니므로 원본값이나 확인 필요에만 적습니다. 양자 전입·전출은 이유 파일에 넣지 말고 양자 파일로 따로 만듭니다.\n- 도폐사: 모돈번호,작업일,산차,퇴출구분,원인,비고,원본값. 퇴출구분은 도태, 폐사, 판매 중 하나만 씁니다. 원인은 필수입니다. 원인을 모르면 기타를 씁니다. 판매는 원인을 비워도 됩니다.\n- 백신: 모돈번호,작업일,백신명,비고,원본값.\n- 양자: 모돈번호,작업일,양자구분,두수,상대모돈,비고,원본값. 양자구분은 전입 또는 전출만 씁니다.\n- 자돈폐사: 모돈번호,작업일,두수,원인,비고,원본값.\n- 모돈 명단: 모돈번호,품종,산차,전입일,현재상태,비고,원본값. 산차는 분만 이력으로 다시 센 값을 씁니다.\n\n출력 파일 — 사람이 나누지 않습니다. 당신이 나눕니다.\n- 종류마다 다른 CSV를 만듭니다. 한 파일에 여러 종류를 섞지 마세요. 모든 사건을 한 events 파일에 모으지 마세요.\n- 한 파일은 데이터 500줄, 2MB를 넘지 않게 나눕니다. 나눈 파일마다 그 종류 머리글을 첫 줄에 둡니다.\n- 파일 이름(그대로):\n  piglog_모돈_part1.csv, piglog_모돈_part2.csv, …\n  piglog_교배_part1.csv, …\n  piglog_임신감정_part1.csv, …\n  piglog_분만_part1.csv, …\n  piglog_이유_part1.csv, …\n  piglog_도폐사_part1.csv, …\n  piglog_백신_part1.csv, …\n  piglog_양자_part1.csv, …\n  piglog_자돈폐사_part1.csv, …\n- 모돈 명단 파일을 가장 앞에 두고, 그다음 기록 파일은 작업일 순서를 지킬 수 있게 종류별로 이어서 주세요.\n\n마지막에\n- 가능하면 내려받을 수 있는 CSV 파일로 주세요. 파일을 만들 수 없으면 코드 블록으로 CSV 전체를 주세요.\n- 짧은 요약으로 종류별 줄 수, 파일 목록, 확인 필요 건수와 그 내용을 적어 주세요.\n";
var N7_IMP_BATCH = 200;
var N7_IMP_CONCUR = 4;

function n7Nh_(s) { return String(s == null ? '' : s).replace(/[\u200B-\u200D\uFEFF]/g, '').toLowerCase().replace(/[\s_\-\.\(\)\[\]\/·:,#*]/g, ''); }
function n7TagKeep_(s) {
  return String(s == null ? '' : s).replace(/[\u200B-\u200D\uFEFF]/g, '').replace(/[\uFF01-\uFF5E]/g, function (c) { return String.fromCharCode(c.charCodeAt(0) - 0xFEE0); }).trim();
}
function n7NormTag_(s) { return n7TagKeep_(s).replace(/\s+/g, '').toUpperCase(); }
function n7TagOk_(s) { var t = n7NormTag_(s); return /^[0-9A-Z가-힣][0-9A-Z가-힣\-_./#()]{0,19}$/.test(t) && (/\d/.test(t) || /^[A-Z]{1,6}$/.test(t)); }
function n7ParseDate_(v) {
  var s = String(v == null ? '' : v).replace(/[\u200B\uFEFF]/g, '').trim();
  if (!s) return '';
  var m;
  if (/^\d{5}(\.\d+)?$/.test(s) && +s > 20000 && +s < 80000) {
    var d = new Date(Date.UTC(1899, 11, 30) + Math.floor(+s) * 864e5);
    return d.toISOString().slice(0, 10);
  }
  if ((m = s.match(/^(\d{4})[-.\/년\s]+(\d{1,2})[-.\/월\s]+(\d{1,2})/)) || (m = s.match(/^(\d{4})(\d{2})(\d{2})$/))) {
    var r = m[1] + '-' + ('0' + m[2]).slice(-2) + '-' + ('0' + m[3]).slice(-2);
    return /^\d{4}-\d{2}-\d{2}$/.test(r) ? r : '';
  }
  if ((m = s.match(/^(\d{1,2})[-.\/](\d{1,2})[-.\/](\d{4})$/))) {
    var a = +m[1], b = +m[2], y = m[3], mo, da;
    if (a > 12) { da = a; mo = b; } else { mo = a; da = b; }
    r = y + '-' + ('0' + mo).slice(-2) + '-' + ('0' + da).slice(-2);
    return r;
  }
  return '';
}
function n7Parity_(v) {
  var s = String(v == null ? '' : v).trim();
  if (!s) return '';
  var m = s.match(/^(\d+)/);
  return m ? String(+m[1]) : (/^\d+$/.test(s) ? s : '');
}
var N7_STATE = { '후보돈': ['후보돈', '후보', 'gilt', 'maiden', 'reservesow', 'reservepig'], '임신': ['임신', '교배', '임신중', '종부', 'pregnantsow', 'pregnant', 'served', 'bred', 'gestating', 'inpig', '임신확인'], '포유': ['포유', '분만', '포유중', 'lactatingsow', 'lactating', 'nursing', 'suckling', 'farrowed'], '이유': ['이유', '대기', '이유후', '교배대기', 'weaningsow', 'weanedsow', 'weaned', 'open', 'dry', 'empty'], '사고': ['사고', '재발', '공태', '유산', 'repeat', 'return'], '퇴출': ['퇴출', '도태', '폐사', '판매', 'culled', 'dead', 'sold', 'removed'] };
function n7State_(v) {
  var n = n7Nh_(v); if (!n) return '';
  for (var k in N7_STATE) { if (N7_STATE[k].some(function (x) { return n7Nh_(x) === n || n.indexOf(n7Nh_(x)) >= 0; })) return k; }
  return '';
}
var N7_TYPE = { '전입': ['전입', '입식', '구입', 'entry', 'arrival', 'purchase'], '교배': ['교배', '종부', '인공수정', 'service', 'mating', 'breeding', 'bred', 'served', 'ai'], '임신감정': ['임신감정', '임신확인', '감정', 'pregcheck', 'pregnancycheck', 'scan'], '분만': ['분만', 'farrow', 'farrowing', 'birth'], '이유': ['이유', 'wean', 'weaning', 'weaned'], '도폐사': ['도폐사', '도태', '폐사', '판매', '퇴출', 'exit', 'cull', 'culled', 'death', 'dead', 'died', 'sold', 'removal'], '백신': ['백신', '접종', 'vaccine', 'vaccination'], '초발정': ['초발정', 'firstheat', 'firstestrus'], '자돈폐사': ['자돈폐사', 'pigletdeath'], '양자': ['양자', '전입양자', '전출양자', 'foster', 'fosterin', 'fosterout'] };
function n7Type_(v) {
  var n = n7Nh_(v); if (!n) return '';
  for (var k in N7_TYPE) { if (N7_TYPE[k].some(function (x) { return n7Nh_(x) === n || n === n7Nh_(x); })) return k; }
  return '';
}
var N7_COLS = {
  tag: ['모돈번호', '모돈', '개체번호', '이표번호', '귀표', '귀표번호', '돈번', '이각', '이각번호', '귀번호', '돈번호', '모돈no', 'sow', 'sowid', 'sowno', 'sownumber', 'sow no', 'sow number', 'tag', 'eartag', 'animalid'],
  breed: ['품종', '계통', 'breed', 'genetics', 'line'],
  parity: ['산차', '현재산차', '전입산차', '시작산차', '산자수', 'parity', 'startingparity', 'paritystage'],
  entry: ['전입일', '전입일자', '입식일', '입식일자', '도입일', 'incomingdate', 'incoming date', 'entrydate', 'arrivaldate'],
  state: ['현재상태', '상태명', '번식상태', 'currentstatus', 'current status', 'startingstatus'],
  date: ['작업일', '기록일', '발생일', '퇴출일', '접종일', '검사일', 'eventdate', 'workdate'],
  type: ['유형', '기록종류', '이벤트', 'eventtype', 'event type'],
  svcDate: ['1차교배일', '1차종부일', '최근교배일', '교배일', '교배일자', '종부일', '종부일자', '최종교배일', 'servicedate', 'matingdate', 'mating date', 'breedingdate', '교배일자'],
  svcDate2: ['2차교배일', '2차종부일', 'secondmating', 'mating2'],
  svcDate3: ['3차교배일', '3차종부일', 'thirdmating', 'mating3'],
  farrowDate: ['최근분만일', '분만일', '분만일자', '최종분만일', 'farrowdate', 'farrowingdate', 'dayoffarrowing', 'day of farrowing', 'farrowing date'],
  total: ['총산', '총산자수', '총산자', 'totalborn', 'total born', 'total'],
  alive: ['실산', '실산자수', '생존산자', 'liveborn', 'bornalive', 'born alive'],
  still: ['사산', '사산자수', 'stillborn'],
  mummy: ['미라', '미이라', 'mummy'],
  weanDate: ['최근이유일', '이유일', '이유일자', '이유 날짜', '최종이유일', 'weandate', 'weaningdate', 'weaning date', 'weaning day'],
  weaned: ['이유두수', '이유자돈', '이유 두수', 'numberofweaningpiglets', 'noweaned', 'pigsweaned', 'weaned', 'pigs weaned'],
  weanWt: ['이유체중합', '이유체중', 'weanweight', 'weaningweight', 'weaning weight'],
  boar: ['1차웅돈', '웅돈', '웅돈번호', '정액', '정액번호', 'boar', 'sire', 'semen'],
  boar2: ['2차웅돈', 'boar2'],
  boar3: ['3차웅돈', 'boar3'],
  method: ['1차방법', '교배방법', '종부방법', 'method'],
  method2: ['2차방법', 'method2'],
  method3: ['3차방법', 'method3'],
  checkResult: ['감정결과', '임신감정', '임신결과', '결과', 'pregresult', 'scanresult'],
  exitKind: ['퇴출구분', '도폐사구분', '도태구분', '구분', 'exittype', 'removaltype'],
  cause: ['원인', '사유', '도폐사원인', 'cause', 'reason'],
  vaccName: ['백신명', '백신', 'vaccine'],
  memo: ['비고', '메모', 'remarks', 'memo', 'note'],
  staff: ['작업자', '담당', '입력자', 'worker', 'staff'],
  loc: ['위치', '돈방', '분만돈방', '스톨', 'pen', 'room'],
  farrowKind: ['분만구분', 'farrowingtype'],
  weak: ['생시도태', '약자', 'weak'],
  defect: ['기형', 'defect'],
  birthWt: ['생시체중합', '생시총체중', '생시체중', 'avgbirdthwt', 'avg birth wt', 'birthweight'],
  weanAge: ['이유일령', '일령', 'age'],
  fosterKind: ['양자구분'],
  fosterN: ['양두수', '양자두수'],
  partner: ['상대모돈'],
  raw: ['원본값', '원본'],
  deathN: ['폐사두수'],
  femaleAlive: ['실산_암', '실산암'],
  maleAlive: ['실산_수', '실산수']
};
function n7GuessMap_(head) {
  var hn = head.map(n7Nh_), map = {}, used = {};
  function skipCross(f, h) {
    if (/2차|3차|second|third|mating2|mating3|boar2|boar3/.test(h) && !/2|3|second|third/.test(f)) return true;
    return false;
  }
  function find(f) {
    var als = N7_COLS[f] || [];
    var j, a;
    for (a = 0; a < als.length; a++) {
      for (j = 0; j < hn.length; j++) if (!used[j] && hn[j] && hn[j] === n7Nh_(als[a])) { map[f] = j; used[j] = 1; return; }
    }
    for (a = 0; a < als.length; a++) {
      var al = n7Nh_(als[a]); if (al.length < 2) continue;
      for (j = 0; j < hn.length; j++) {
        if (used[j] || !hn[j] || skipCross(f, hn[j])) continue;
        if (hn[j].indexOf(al) >= 0 || (al.indexOf(hn[j]) >= 0 && hn[j].length >= 4 && !/^(age|date|no|id|wt|pen|day|name|note|type)$/.test(hn[j]))) { map[f] = j; used[j] = 1; return; }
      }
    }
  }
  ['tag', 'entry', 'date', 'type', 'breed', 'parity', 'state', 'svcDate', 'svcDate2', 'svcDate3', 'farrowDate', 'weanDate', 'total', 'alive', 'still', 'mummy', 'weaned', 'weanWt', 'boar', 'boar2', 'boar3', 'method', 'method2', 'method3', 'checkResult', 'exitKind', 'cause', 'vaccName', 'memo', 'staff', 'loc', 'farrowKind', 'weak', 'defect', 'birthWt', 'weanAge', 'fosterKind', 'fosterN', 'partner', 'raw', 'deathN', 'femaleAlive', 'maleAlive'].forEach(find);
  return map;
}

function n7ParseCsv_(text) {
  text = String(text || '').replace(/^\uFEFF/, '').replace(/\r\n/g, '\n').replace(/\r/g, '\n');
  var rows = [], row = [], cur = '', q = false, i;
  for (i = 0; i < text.length; i++) {
    var ch = text.charAt(i);
    if (q) {
      if (ch === '"') { if (text.charAt(i + 1) === '"') { cur += '"'; i++; } else q = false; }
      else cur += ch;
    } else if (ch === '"') q = true;
    else if (ch === ',' || ch === '\t') { row.push(cur); cur = ''; }
    else if (ch === '\n') { row.push(cur); rows.push(row); row = []; cur = ''; }
    else cur += ch;
  }
  if (cur !== '' || row.length) { row.push(cur); rows.push(row); }
  return rows.filter(function (r) { return r.some(function (c) { return String(c || '').trim() !== ''; }); });
}
function n7HeaderRow_(rows) {
  var best = 0, bestN = -1, i, n, map;
  for (i = 0; i < Math.min(rows.length, 12); i++) {
    map = n7GuessMap_(rows[i].map(function (x) { return String(x || ''); }));
    n = Object.keys(map).length;
    if (map.tag != null) n += 3;
    if (n > bestN) { bestN = n; best = i; }
  }
  return best;
}
function n7GuessKind_(map, name) {
  var n = String(name || '').toLowerCase();
  var m = n.match(/piglog[_-]?([^_./-]+)_?part/i);
  var alias = { sows: 'sows', '모돈': 'sows', events: 'events', '교배': '교배', '임신감정': '임신감정', '분만': '분만', '이유': '이유', '도폐사': '도폐사', '백신': '백신', '양자': '양자', '자돈폐사': '자돈폐사' };
  if (m && alias[m[1]] != null) return alias[m[1]];
  if ((/sow|모돈|명단/.test(n)) && !/event|기록|교배|종부|분만|이유|도폐|도태|폐사|백신|양자|임신|자돈/.test(n)) return 'sows';
  if (/piglog_sows/.test(n)) return 'sows';
  if (/임신감정|pregcheck|scan/.test(n)) return '임신감정';
  if (/교배|종부|mating|service/.test(n)) return '교배';
  if (/분만|farrow/.test(n)) return '분만';
  if (/이유|wean/.test(n)) return '이유';
  if (/도폐|도태|폐사대장|cull|removal/.test(n) && !/자돈/.test(n)) return '도폐사';
  if (/백신|vacc/.test(n)) return '백신';
  if (/양자|포유자돈|foster/.test(n)) return '양자';
  if (/자돈폐사|pigletdeath/.test(n)) return '자돈폐사';
  if (map.type != null && (map.date != null || map.svcDate != null || map.farrowDate != null || map.weanDate != null)) return 'events';
  if (/events|기록/.test(n) && !/sow|모돈|명단/.test(n)) return 'events';
  if (map.entry != null || map.state != null) return 'sows';
  if (map.svcDate != null && map.farrowDate == null && map.weanDate == null) return '교배';
  if (map.farrowDate != null && map.svcDate == null && map.weanDate == null) return '분만';
  if (map.weanDate != null && map.svcDate == null && map.farrowDate == null) return '이유';
  if (map.exitKind != null || (map.cause != null && map.date != null && map.weaned == null)) return '도폐사';
  if (map.checkResult != null) return '임신감정';
  if (map.vaccName != null) return '백신';
  if (map.fosterKind != null) return '양자';
  return 'sows';
}
function n7G_(row, map, f) { var j = map[f]; return j == null ? '' : String(row[j] == null ? '' : row[j]).trim(); }
function n7SowObj_(row, map) {
  return {
    kind: 'sow',
    tag: n7TagKeep_(n7G_(row, map, 'tag')),
    breed: n7G_(row, map, 'breed'),
    parity: n7Parity_(n7G_(row, map, 'parity')),
    entry: n7ParseDate_(n7G_(row, map, 'entry')),
    state: n7State_(n7G_(row, map, 'state')) || n7G_(row, map, 'state'),
    svcDate: n7ParseDate_(n7G_(row, map, 'svcDate')),
    farrowDate: n7ParseDate_(n7G_(row, map, 'farrowDate')),
    total: n7G_(row, map, 'total'),
    alive: n7G_(row, map, 'alive'),
    still: n7G_(row, map, 'still'),
    weanDate: n7ParseDate_(n7G_(row, map, 'weanDate')),
    weaned: n7G_(row, map, 'weaned'),
    memo: n7G_(row, map, 'memo')
  };
}
function n7Method_(v) {
  var n = n7Nh_(v);
  if (/자연|natural|ns/.test(n) && !/인공/.test(n)) return '자연';
  if (/인공|ai|인공수정/.test(n)) return '인공';
  return v ? String(v).trim() : '';
}
function n7Check_(v) {
  var n = n7Nh_(v);
  if (!n) return '';
  if (n === '+' || /임신|pregnant|preg/.test(n)) return '임신';
  if (/재발|recycle/.test(n)) return '재발';
  if (/공태|open/.test(n)) return '공태';
  if (/유산|abort/.test(n)) return '유산';
  if (/불임/.test(n)) return '불임';
  return String(v).trim();
}
function n7ExitKind_(v) {
  var n = n7Nh_(v);
  if (/판매|sold|sale/.test(n)) return '판매';
  if (/폐사|death|dead|died/.test(n)) return '폐사';
  if (/도태|cull/.test(n)) return '도태';
  return v ? String(v).trim() : '';
}
function n7FarrowKind_(v) {
  var n = n7Nh_(v);
  if (/유도/.test(n)) return '유도';
  if (/조산/.test(n)) return '조산';
  if (/난산/.test(n)) return '난산';
  if (/정상/.test(n)) return '정상';
  return v ? String(v).trim() : '';
}
function n7Num_(v) {
  var s = String(v == null ? '' : v).replace(/,/g, '').trim();
  if (!s) return '';
  var m = s.match(/-?\d+(?:\.\d+)?/);
  return m ? m[0] : '';
}
function n7EvObj_(row, map, defType) {
  var typ = n7Type_(n7G_(row, map, 'type')) || defType || '';
  var date = n7ParseDate_(n7G_(row, map, 'date'));
  if (!date && typ === '교배') date = n7ParseDate_(n7G_(row, map, 'svcDate'));
  if (!date && typ === '분만') date = n7ParseDate_(n7G_(row, map, 'farrowDate'));
  if (!date && typ === '이유') date = n7ParseDate_(n7G_(row, map, 'weanDate'));
  if (!date) date = n7ParseDate_(n7G_(row, map, 'svcDate')) || n7ParseDate_(n7G_(row, map, 'farrowDate')) || n7ParseDate_(n7G_(row, map, 'weanDate'));
  var weak = n7Num_(n7G_(row, map, 'weak')), defect = n7Num_(n7G_(row, map, 'defect'));
  var cull = weak;
  if (defect && weak) cull = String((+weak || 0) + (+defect || 0));
  else if (defect && !weak) cull = defect;
  var birth = n7Num_(n7G_(row, map, 'birthWt'));
  var alive = n7Num_(n7G_(row, map, 'alive'));
  var raw = n7G_(row, map, 'raw') || '';
  var wtHead = (map.birthWt != null && row) ? String((map.birthWt != null) ? 'x' : '') : '';
  if (birth && alive && +birth < 8 && +alive > 0) {
    if (raw) raw += ' ';
    raw += '생시체중=' + birth;
    birth = String(Math.round(+birth * +alive * 100) / 100);
  }
  var weanWt = n7Num_(n7G_(row, map, 'weanWt'));
  var weaned = n7Num_(n7G_(row, map, 'weaned'));
  if (weanWt && weaned && +weanWt < 20 && +weaned > 0) {
    if (raw) raw += ' ';
    raw += '이유체중=' + weanWt;
    weanWt = String(Math.round(+weanWt * +weaned * 100) / 100);
  }
  var age = n7G_(row, map, 'weanAge');
  if (age) raw = (raw ? raw + ' ' : '') + '일령=' + age;
  var fosterMove = n7G_(row, map, 'fosterN');
  return {
    kind: 'event',
    tag: n7TagKeep_(n7G_(row, map, 'tag')),
    date: date,
    type: typ,
    parity: n7Parity_(n7G_(row, map, 'parity')),
    boar: n7G_(row, map, 'boar'),
    method: n7Method_(n7G_(row, map, 'method')),
    staff: n7G_(row, map, 'staff'),
    checkResult: n7Check_(n7G_(row, map, 'checkResult')),
    total: n7G_(row, map, 'total'),
    alive: n7G_(row, map, 'alive'),
    still: n7G_(row, map, 'still'),
    mummy: n7G_(row, map, 'mummy'),
    weak: cull,
    farrowKind: n7FarrowKind_(n7G_(row, map, 'farrowKind')),
    birthWt: birth,
    loc: n7G_(row, map, 'loc'),
    weaned: weaned || n7G_(row, map, 'weaned'),
    weanWt: weanWt,
    weanAge: age,
    exitKind: n7ExitKind_(n7G_(row, map, 'exitKind')),
    cause: n7G_(row, map, 'cause'),
    vaccName: n7G_(row, map, 'vaccName'),
    fosterKind: n7G_(row, map, 'fosterKind'),
    fosterN: n7G_(row, map, 'fosterN') || n7G_(row, map, 'deathN'),
    partner: n7G_(row, map, 'partner'),
    femaleAlive: n7G_(row, map, 'femaleAlive'),
    maleAlive: n7G_(row, map, 'maleAlive'),
    raw: raw,
    memo: n7G_(row, map, 'memo')
  };
}
function n7EvExpand_(row, map, defType) {
  var typ = n7Type_(n7G_(row, map, 'type')) || defType || '';
  var dates = [];
  function add(dateKey, boarKey, methodKey, idx) {
    var d = n7ParseDate_(n7G_(row, map, dateKey));
    if (!d) return;
    dates.push({ date: d, boar: n7G_(row, map, boarKey), method: n7Method_(n7G_(row, map, methodKey)), n: idx });
  }
  if (typ === '교배' || typ === '' && (map.svcDate2 != null || map.svcDate3 != null || map.boar2 != null)) {
    add('svcDate', 'boar', 'method', 1);
    add('svcDate2', 'boar2', 'method2', 2);
    add('svcDate3', 'boar3', 'method3', 3);
    if (dates.length > 1 || (dates.length === 1 && (map.svcDate2 != null || map.svcDate3 != null))) {
      return dates.map(function (x) {
        var o = n7EvObj_(row, map, '교배');
        o.date = x.date; o.boar = x.boar || o.boar; o.method = x.method || o.method; o.type = '교배';
        return o;
      }).filter(function (o) { return o.tag && o.date; });
    }
  }
  if (!typ && map.fosterKind != null) typ = '양자';
  var o = n7EvObj_(row, map, typ);
  if (o.type === '양자') {
    if (!o.fosterKind && (o.exitKind === '전입' || o.exitKind === '전출')) { o.fosterKind = o.exitKind; o.exitKind = ''; }
    if (!o.fosterN && o.weaned) { o.fosterN = o.weaned; o.weaned = ''; }
  }
  if (o.type === '분만' && !o.farrowKind && /정상|유도|조산|난산/.test(o.exitKind || '')) { o.farrowKind = o.exitKind; o.exitKind = ''; }
  return o.tag ? [o] : [];
}
function n7Rollup_(objs) {
  var by = {}, order = [];
  objs.forEach(function (o, i) {
    var k = n7NormTag_(o.tag) + '|' + (o.entry || '');
    if (!o.tag) k = '#row' + i;
    if (!by[k]) { by[k] = o; order.push(k); return; }
    var c = by[k];
    if (o.entry && (!c.entry || o.entry < c.entry)) c.entry = o.entry;
    if (!c.breed && o.breed) c.breed = o.breed;
    if (o.parity !== '' && (c.parity === '' || +o.parity > +c.parity)) c.parity = o.parity;
    if (o.state) c.state = o.state;
    if (o.svcDate && o.svcDate >= (c.svcDate || '')) c.svcDate = o.svcDate;
    if (o.farrowDate && o.farrowDate >= (c.farrowDate || '')) { c.farrowDate = o.farrowDate; if (o.total) c.total = o.total; if (o.alive) c.alive = o.alive; if (o.still) c.still = o.still; }
    if (o.weanDate && o.weanDate >= (c.weanDate || '')) { c.weanDate = o.weanDate; if (o.weaned) c.weaned = o.weaned; }
    if (o.memo && (!c.memo || c.memo.indexOf(o.memo) < 0)) c.memo = c.memo ? (c.memo + ' ' + o.memo) : o.memo;
  });
  return order.map(function (k) { return by[k]; });
}
function n7Yield_() { return new Promise(function (r) { setTimeout(r, 0); }); }
function n7Prog_(el, done, total, msg) {
  if (!el) return;
  var p = el.querySelector('#n7-imp-prog');
  if (!p) {
    p = document.createElement('div');
    p.id = 'n7-imp-prog';
    p.className = 'n7-imp-prog';
    p.innerHTML = '<div class="n7-imp-barw"><div class="n7-imp-bar"></div></div><span></span>';
    el.insertBefore(p, el.firstChild);
  }
  var pct = total ? Math.max(0, Math.min(100, Math.round(done / total * 100))) : 0;
  var bar = p.querySelector('.n7-imp-bar');
  if (bar) bar.style.width = pct + '%';
  var sp = p.querySelector('span');
  if (sp) sp.textContent = msg || (total ? (total + '줄 중 ' + done + '줄 확인') : '');
}
function n7ValidateSows_(rows, sows) {
  var tod = (typeof window.today === 'function' ? window.today() : (new Date()).toISOString().slice(0, 10));
  var max = n7ParseDate_(tod) ? tod : new Date().toISOString().slice(0, 10);
  var maxF = (function () { var p = max.split('-'); var d = new Date(+p[0], +p[1] - 1, +p[2] + 1); return d.getFullYear() + '-' + ('0' + (d.getMonth() + 1)).slice(-2) + '-' + ('0' + d.getDate()).slice(-2); })();
  var byTag = {};
  (sows || []).forEach(function (s) {
    var k = n7NormTag_(s.tag);
    (byTag[k] = byTag[k] || []).push(s);
  });
  var fileSeen = {};
  return rows.map(function (r, i) {
    var errs = [], warns = [], status = 'ok';
    if (!r.tag) errs.push('모돈번호가 없습니다');
    else if (!n7TagOk_(r.tag)) errs.push('모돈번호 형식을 확인해 주세요');
    if (!r.entry) errs.push('전입일이 없거나 날짜 형식이 아닙니다');
    else if (r.entry > maxF) errs.push('전입일이 너무 미래입니다');
    if (!r.breed) warns.push('품종이 없습니다');
    var k = n7NormTag_(r.tag);
    if (k && r.entry && fileSeen[k + '|' + r.entry]) errs.push('파일 안에서 같은 모돈번호·전입일이 겹칩니다');
    if (k && r.entry) fileSeen[k + '|' + r.entry] = i + 1;
    var hits = byTag[k] || [];
    var sameEnt = hits.filter(function (s) { return String(s.entryDate || s.entry || '').slice(0, 10) === r.entry; });
    var active = hits.filter(function (s) { return s.state !== '퇴출' && !s.exitDate; });
    if (sameEnt.length) {
      warns.push('이미 있는 모돈입니다 (번호 ' + r.tag + ' · 전입일 ' + r.entry + '). 기존 기록은 그대로 두고 건너뜁니다');
      status = 'warn';
      r._dup = 1;
    } else if (active.length) {
      errs.push('같은 번호가 이미 사용 중입니다 (전입일 ' + (active[0].entryDate || '') + '). 퇴출된 뒤에만 번호를 다시 쓸 수 있습니다');
    } else if (hits.length) {
      warns.push('예전에 쓰였던 번호입니다. 전입일이 달라 새 모돈으로 가져옵니다');
      r._reuse = 1;
    }
    if (errs.length) { status = 'err'; r._skip = 1; }
    if (r._dup) r._skip = 1;
    r._i = i + 1; r._errs = errs; r._warns = warns; r._status = status;
    return r;
  });
}
function n7ValidateEvs_(rows, sowLines, sows) {
  var entryOf = {};
  (sows || []).forEach(function (s) {
    var k = n7NormTag_(s.tag);
    var ent = String(s.entryDate || s.entry || '').slice(0, 10);
    if (k && ent && (!entryOf[k] || s.state !== '퇴출')) entryOf[k] = ent;
  });
  (sowLines || []).forEach(function (s) {
    var k = n7NormTag_(s.tag);
    if (k && s.entry && !s._skip) entryOf[k] = s.entry;
    else if (k && s.entry && s._dup) entryOf[k] = entryOf[k] || s.entry;
  });
  var seen = {};
  return rows.map(function (r, i) {
    var errs = [], warns = [], flags = [], status = 'ok';
    if (!r.tag) errs.push('모돈번호가 없습니다');
    else if (!n7TagOk_(r.tag)) errs.push('모돈번호 형식을 확인해 주세요');
    if (!r.type) errs.push('유형이 없습니다');
    if (!r.date) errs.push('작업일이 없거나 날짜 형식이 아닙니다');
    var k = n7NormTag_(r.tag);
    var sig = k + '|' + r.type + '|' + r.date;
    if (k && r.type && r.date && seen[sig]) { warns.push('파일 안에서 같은 기록이 겹칩니다'); r._dup = 1; }
    if (k && r.type && r.date) seen[sig] = 1;
    var ent = entryOf[k];
    if (r.date && ent && r.date < ent) {
      flags.push('작업일(' + r.date + ')이 전입일(' + ent + ')보다 앞섭니다. 추측하지 않고 확인 필요에 둡니다');
      r._flagOnly = 1;
      status = 'warn';
    }
    if (!ent && r.date) {
      flags.push('이 번호의 전입일을 모릅니다. 확인 필요에 둡니다');
      r._flagOnly = 1;
      status = 'warn';
    }
    if (r.type === '도폐사' && r.exitKind !== '판매' && !r.cause) {
      r.cause = '기타';
      warns.push('원인을 알 수 없어 기타로 넣습니다');
      if (r.raw) r.raw += ' ';
      r.raw = (r.raw || '') + '원인 없음→기타';
    }
    if (errs.length) { status = 'err'; r._skip = 1; }
    if (r._dup) r._skip = 1;
    r._i = i + 1; r._errs = errs; r._warns = warns.concat(flags); r._flags = flags; r._status = status;
    return r;
  });
}
function n7ParityFix_(sowLines, evLines) {
  var entryP = {};
  (sowLines || []).forEach(function (s) {
    var k = n7NormTag_(s.tag);
    if (k) entryP[k] = s.parity === '' || s.parity == null ? 0 : +s.parity;
  });
  var by = {};
  (evLines || []).forEach(function (e) {
    if (e.type !== '분만' || !e.date || e._skip) return;
    var k = n7NormTag_(e.tag);
    if (!k) return;
    if (!by[k]) by[k] = [];
    by[k].push(e);
  });
  Object.keys(by).forEach(function (k) {
    by[k].sort(function (a, b) { return String(a.date).localeCompare(String(b.date)); });
    by[k].forEach(function (e, i) {
      var expect = (entryP[k] || 0) + i + 1;
      e._parityCalc = expect;
      if (e.parity !== '' && e.parity != null && +e.parity !== expect) {
        e._warns = e._warns || [];
        e._warns.push('산차 ' + e.parity + '가 분만 이력으로 본 산차 ' + expect + '와 다릅니다');
        if (e.raw) e.raw += ' ';
        e.raw = (e.raw || '') + '원본산차=' + e.parity;
        e.parity = expect;
        if (e._status !== 'err') e._status = 'warn';
      } else if (e.parity === '' || e.parity == null) e.parity = expect;
    });
  });
}


function nov7PolishImport_(el) {
  if (!el || el.querySelector('#n7-imp')) {
    if (el && el.querySelector('#n7-imp')) n7ImpShowResume_(el);
    return;
  }
  var card = el.querySelector('.card') || el;
  var box = document.createElement('div');
  box.id = 'n7-imp';
  box.className = 'n7-imp';
  box.innerHTML = '<h3>모돈 명단 가져오기</h3>'
    + '<p class="n7-imp-lead">모돈 명단 엑셀·CSV를 AI로 정리해 넣습니다. <b>지금 열린 농장에만</b> 들어갑니다. 이벤트(교배·분만 등) 엑셀은 아래 종류에서 ‘이벤트’를 고르면 이 안내가 숨겨집니다.</p>'
    + '<div id="n7-imp-resumebox"></div>'
    + '<div class="n7-imp-step">1. 안내문을 복사해 가진 자료와 함께 AI에 넣으세요</div>'
    + '<pre class="n7-imp-pre" id="n7-imp-prompt"></pre>'
    + '<div class="row"><button type="button" class="btn" id="n7-imp-copy">안내문 복사</button></div>'
    + '<div class="n7-imp-step">2. AI가 만든 파일을 올리세요</div>'
    + '<p class="n7-imp-hint">모돈 명단이 많으면 <b>파일을 여러 개로 나눠</b> 올리세요. 한 파일에 행이 너무 많으면 검사가 오래 걸리거나 실패할 수 있습니다. 번호 구간이나 돈사별로 나눠도 됩니다. 여러 해 치를 함께 올려도 됩니다.</p>'
    + '<div class="n7-imp-slots" id="n7-imp-slots"></div>'
    + '<p class="n7-imp-all">또는 파일을 한꺼번에 고르기</p>'
    + '<div id="n7-imp-slot"></div>'
    + '<p class="n7-imp-hint">아주 많은 자료는 나중에 이어서 넣어도 됩니다.</p>';
  var after = card.querySelector('h3');
  if (after && after.parentNode === card) card.insertBefore(box, after.nextSibling);
  else card.insertBefore(box, card.firstChild);
  var slot = box.querySelector('#n7-imp-slot');
  if (slot) {
    var upBtn = card.querySelector('#im-up');
    var fileRow = upBtn && upBtn.parentNode;
    var outEl = card.querySelector('#im-out');
    var mut = fileRow && fileRow.previousElementSibling;
    if (mut && mut.classList && mut.classList.contains('mut')) {
      mut.textContent = '파일을 고르고 검사하기를 누르세요.';
      slot.appendChild(mut);
    }
    if (fileRow) slot.appendChild(fileRow);
    if (outEl) slot.appendChild(outEl);
  }
  var inp = card.querySelector('#im-f');
  if (inp) inp.multiple = true;
  var pre = box.querySelector('#n7-imp-prompt');
  pre.textContent = N7_IMP_PROMPT;
  box.querySelector('#n7-imp-copy').onclick = function () {
    var t = N7_IMP_PROMPT;
    function ok() { if (typeof toast === 'function') toast('안내문을 복사했습니다'); };
    if (navigator.clipboard && navigator.clipboard.writeText) navigator.clipboard.writeText(t).then(ok, function () { n7CopyFail_(pre); });
    else n7CopyFail_(pre);
  };
  n7BindImport_(el);
  n7ImpShowResume_(el);
  function syncKind() {
    var sel = el.querySelector('#im-k');
    var sow = !sel || sel.value === 'sows';
    box.style.display = sow ? '' : 'none';
    box.setAttribute('data-kind', sow ? 'sows' : (sel && sel.value) || '');
  }
  var kindSel = el.querySelector('#im-k');
  if (kindSel && !kindSel.getAttribute('data-n7imp')) {
    kindSel.setAttribute('data-n7imp', '1');
    kindSel.addEventListener('change', syncKind);
  }
  syncKind();
}
function n7CopyFail_(pre) {
  var r = document.createRange(); r.selectNodeContents(pre);
  var s = window.getSelection(); s.removeAllRanges(); s.addRange(r);
  try { document.execCommand('copy'); if (typeof toast === 'function') toast('안내문을 복사했습니다'); } catch (e) { if (typeof toast === 'function') toast('블록을 선택한 뒤 복사해 주세요'); }
}
function n7ImpSlots_(box) {
  var wrap = box.querySelector('#n7-imp-slots'); if (!wrap || wrap.getAttribute('data-on')) return;
  wrap.setAttribute('data-on', '1');
  var types = [
    { k: '모돈', label: '모돈 명단' },
    { k: '교배', label: '교배대장' },
    { k: '임신감정', label: '임신감정' },
    { k: '분만', label: '분만대장' },
    { k: '이유', label: '이유대장' },
    { k: '도폐사', label: '도폐사' },
    { k: '백신', label: '백신' },
    { k: '양자', label: '양자·포유자돈' }
  ];
  types.forEach(function (t) {
    var lab = document.createElement('label');
    lab.className = 'n7-imp-slotcard';
    lab.innerHTML = '<b>' + t.label + '</b><span class="mut" data-cnt>파일 없음</span><input type="file" accept=".csv,.xlsx,text/csv" multiple hidden data-k="' + t.k + '">';
    lab.querySelector('input').onchange = function () {
      var n = (this.files && this.files.length) || 0;
      lab.classList.toggle('has', n > 0);
      lab.querySelector('[data-cnt]').textContent = n ? n + '개 선택' : '파일 없음';
    };
    wrap.appendChild(lab);
  });
}
function n7ImpAllFiles_(el) {
  var out = [], seen = {};
  function add(f) {
    var k = (f.name || '') + ':' + f.size + ':' + (f.lastModified || 0);
    if (seen[k]) return; seen[k] = 1; out.push(f);
  }
  var main = el.querySelector('#im-f');
  if (main && main.files) [].forEach.call(main.files, add);
  var slots = el.querySelectorAll('#n7-imp-slots input[type=file]');
  [].forEach.call(slots, function (inp) { if (inp.files) [].forEach.call(inp.files, add); });
  return out;
}
function n7BindImport_(el) {
  var up = el.querySelector('#im-up'), file = el.querySelector('#im-f'), out = el.querySelector('#im-out');
  var box = el.querySelector('#n7-imp') || el;
  n7ImpSlots_(box);
  if (!up || up.getAttribute('data-n7imp')) return;
  up.setAttribute('data-n7imp', '1');
  up.onclick = function (e) {
    e.preventDefault(); e.stopImmediatePropagation();
    var fs = n7ImpAllFiles_(el);
    if (!fs.length) { if (file) file.click(); return; }
    n7RunImport_(el, fs, out);
  };
  if (file && !file.getAttribute('data-n7imp')) {
    file.setAttribute('data-n7imp', '1');
    file.multiple = true;
  }
}
function n7ReadFile_(f) {
  return new Promise(function (res, rej) {
    if (f.size > 2 * 1024 * 1024) return rej(new Error('파일이 2MB를 넘습니다. 안내문대로 AI가 나눈 파일을 올려 주세요.'));
    var name = String(f.name || '').toLowerCase();
    var rd = new FileReader();
    rd.onerror = function () { rej(new Error('파일을 읽지 못했습니다')); };
    if (/\.xlsx?$/.test(name) && name.slice(-5) === '.xlsx') {
      rd.onload = function () { n7ReadXlsx_(new Uint8Array(rd.result)).then(res, function () { rej(new Error('엑셀을 읽지 못했습니다. CSV로 저장해 다시 올려 주세요.')); }); };
      rd.readAsArrayBuffer(f);
    } else if (/\.xls$/.test(name)) {
      rej(new Error('옛 .xls 형식은 지원하지 않습니다. CSV 또는 .xlsx로 저장해 주세요.'));
    } else {
      rd.onload = function () { res({ sheets: [{ name: f.name, rows: n7ParseCsv_(rd.result) }] }); };
      rd.readAsText(f, 'utf-8');
    }
  });
}

function n7ReadXlsx_(buf) {
  function u16(p) { return buf[p] | (buf[p + 1] << 8); }
  function u32(p) { return (buf[p] | (buf[p + 1] << 8) | (buf[p + 2] << 16) | (buf[p + 3] << 24)) >>> 0; }
  var e = buf.length - 22;
  while (e >= 0 && u32(e) !== 0x06054b50) e--;
  if (e < 0) return Promise.reject(new Error('xlsx'));
  if (typeof DecompressionStream !== 'function') return Promise.reject(new Error('xlsx'));
  var n = u16(e + 10), p = u32(e + 16), parts = {}, i, jobs = [];
  for (i = 0; i < n; i++) {
    var method = u16(p + 10), csize = u32(p + 20), nl = u16(p + 28), xl = u16(p + 30), cl = u16(p + 32), off = u32(p + 42);
    var name = new TextDecoder('utf-8').decode(buf.subarray(p + 46, p + 46 + nl));
    var lnl = u16(off + 26), lxl = u16(off + 28);
    var data = buf.subarray(off + 30 + lnl + lxl, off + 30 + lnl + lxl + csize);
    (function (nm, meth, dat) {
      if (meth === 8) {
        jobs.push(new Response(new Blob([dat]).stream().pipeThrough(new DecompressionStream('deflate-raw'))).arrayBuffer().then(function (ab) { parts[nm] = new TextDecoder('utf-8').decode(new Uint8Array(ab)); }));
      } else parts[nm] = new TextDecoder('utf-8').decode(dat);
    })(name, method, data);
    p += 46 + nl + xl + cl;
  }
  return Promise.all(jobs).then(function () {
    function str(nm) { return (parts[nm] || '').replace(/<(\/?)[A-Za-z]\w*:(?=[A-Za-z])/g, '<$1'); }
    var unesc = function (s) { return String(s).replace(/&lt;/g, '<').replace(/&gt;/g, '>').replace(/&quot;/g, '"').replace(/&apos;/g, "'").replace(/&amp;/g, '&'); };
    var shared = (str('xl/sharedStrings.xml').match(/<si>[\s\S]*?<\/si>/g) || []).map(function (si) {
      return unesc((si.match(/<t[^>]*>[\s\S]*?<\/t>/g) || []).map(function (t) { return t.replace(/<t[^>]*>|<\/t>/g, ''); }).join(''));
    });
    var sheets = [];
    var wb = str('xl/workbook.xml');
    var names = [];
    (wb.match(/<sheet [^>]*>/g) || []).forEach(function (tag) {
      var nm = (tag.match(/name="([^"]+)"/) || [])[1] || 'sheet';
      var id = (tag.match(/r:id="([^"]+)"/) || tag.match(/id="([^"]+)"/) || [])[1];
      names.push({ name: nm, id: id });
    });
    var rels = {};
    (str('xl/_rels/workbook.xml.rels').match(/<Relationship [^>]*>/g) || []).forEach(function (r) {
      var id = (r.match(/Id="([^"]+)"/) || [])[1], tg = (r.match(/Target="([^"]+)"/) || [])[1];
      if (id && tg) rels[id] = tg.replace(/^\//, '').replace(/^xl\//, '');
    });
    names.forEach(function (s) {
      var path = rels[s.id] || '';
      if (path && path.indexOf('xl/') !== 0) path = 'xl/' + path.replace(/^\.\//, '');
      var xml = str(path); if (!xml) return;
      var rows = [], maxC = 0;
      (xml.match(/<row[^>]*>[\s\S]*?<\/row>/g) || []).forEach(function (rw) {
        var rIdx = +((rw.match(/r="(\d+)"/) || [])[1] || (rows.length + 1)) - 1;
        while (rows.length <= rIdx) rows.push([]);
        (rw.match(/<c[^>]*(?:\/>|>[\s\S]*?<\/c>)/g) || []).forEach(function (c) {
          var ref = (c.match(/r="([A-Z]+)(\d+)"/) || [])[1];
          var col = 0, k;
          if (ref) { for (k = 0; k < ref.length; k++) col = col * 26 + (ref.charCodeAt(k) - 64); col -= 1; }
          else col = rows[rIdx].length;
          var t = (c.match(/t="([^"]+)"/) || [])[1];
          var v = ((c.match(/<v[^>]*>([\s\S]*?)<\/v>/) || [])[1] || '');
          var isv = (c.match(/<t[^>]*>([\s\S]*?)<\/t>/) || [])[1];
          var val = '';
          if (t === 's') val = shared[+v] || '';
          else if (t === 'inlineStr') val = unesc(isv || '');
          else val = unesc(v);
          rows[rIdx][col] = val;
          if (col > maxC) maxC = col;
        });
      });
      rows.forEach(function (r) { for (var j = 0; j <= maxC; j++) if (r[j] == null) r[j] = ''; });
      sheets.push({ name: s.name, rows: rows });
    });
    if (!sheets.length) throw new Error('xlsx');
    return { sheets: sheets };
  });
}
function n7FileRank_(f) {
  var n = String((f && f.name) || '').toLowerCase();
  var k = 9;
  if ((/sow|모돈|명단/.test(n) || /piglog_sows/.test(n)) && !/event|기록|교배|분만|이유|도폐|백신|양자|임신/.test(n)) k = 0;
  else if (/교배|종부|mating|service|piglog_교배/.test(n)) k = 2;
  else if (/임신감정|preg|piglog_임신/.test(n)) k = 3;
  else if (/분만|farrow|piglog_분만/.test(n)) k = 4;
  else if (/이유|wean|piglog_이유/.test(n)) k = 5;
  else if (/양자|포유자돈|자돈폐사|foster|piglog_양자|piglog_자돈/.test(n)) k = 6;
  else if (/도폐|도태|폐사|cull|death|piglog_도폐/.test(n)) k = 7;
  else if (/백신|vacc|piglog_백신/.test(n)) k = 8;
  else if (/event|기록|piglog_events/.test(n)) k = 9;
  var part = 0, m = n.match(/part\s*(\d+)/i);
  if (m) part = +m[1];
  return [k, part, n];
}
function n7SortFiles_(files) {
  return files.slice().sort(function (a, b) {
    var A = n7FileRank_(a), B = n7FileRank_(b);
    return A[0] - B[0] || A[1] - B[1] || (A[2] < B[2] ? -1 : A[2] > B[2] ? 1 : 0);
  });
}
function n7RunImport_(el, files, out) {
  if (!out) return;
  files = n7SortFiles_(Array.isArray(files) ? files : [].slice.call(files || []));
  out.innerHTML = '<div class="n7-load">파일을 읽는 중</div>';
  var t0 = Date.now();
  var seen = 0, totalGuess = files.length;
  n7Prog_(out, 0, 1, '파일을 읽는 중');
  var chain = Promise.resolve([]), i;
  files.forEach(function (f) {
    chain = chain.then(function (acc) {
      return n7ReadFile_(f).then(function (u) {
        (u.sheets || []).forEach(function (s) { s.fileName = f.name; acc.push(s); });
        seen++;
        n7Prog_(out, seen, totalGuess, '파일 ' + seen + ' / ' + totalGuess + ' 읽는 중');
        return acc;
      });
    });
  });
  chain.then(function (sheets) {
    if (!sheets.length) throw new Error('읽을 줄이 없습니다');
    return n7BuildImport_(el, out, sheets, t0);
  }).catch(function (e) {
    out.innerHTML = '<div class="n7-err">' + n7Esc_(e && e.message ? e.message : String(e)) + '</div>';
  });
}
function n7BuildImport_(el, out, sheets, t0) {
  var sowObjs = [], evObjs = [], maps = [], i, s, hr, map, kind, body, defType, parsed = 0, all = 0;
  sheets.forEach(function (s) { all += Math.max(0, (s.rows || []).length - 1); });
  for (i = 0; i < sheets.length; i++) {
    s = sheets[i];
    hr = n7HeaderRow_(s.rows || []);
    map = n7GuessMap_((s.rows[hr] || []).map(String));
    if (map.tag == null) continue;
    kind = n7GuessKind_(map, s.fileName || s.name);
    body = (s.rows || []).slice(hr + 1);
    maps.push({ file: s.fileName || s.name, kind: kind, map: map, head: s.rows[hr], n: body.length });
    defType = (kind === 'sows' || kind === 'events' || kind.indexOf('ev-') === 0) ? (kind.indexOf('ev-') === 0 ? kind.slice(3) : '') : kind;
    if (kind === 'sows') {
      body.forEach(function (r) { var o = n7SowObj_(r, map); if (o.tag) sowObjs.push(o); });
    } else {
      body.forEach(function (r) {
        n7EvExpand_(r, map, defType).forEach(function (o) { if (o.tag) evObjs.push(o); });
      });
    }
    parsed += body.length;
  }
  if (!sowObjs.length && !evObjs.length) throw new Error('모돈번호 열을 찾지 못했습니다. 안내문으로 정리한 CSV를 올려 주세요.');
  sowObjs = n7Rollup_(sowObjs);
  n7Prog_(out, 0, sowObjs.length + evObjs.length, (sowObjs.length + evObjs.length) + '줄 중 0줄 확인');
  var loadSows = (typeof apiF === 'function') ? apiF('listSows', { includeExited: true }) : Promise.resolve({ items: [] });
  return loadSows.then(function (r) {
    var items = (r && (r.items || r.sows || r.rows || r)) || [];
    if (!Array.isArray(items)) items = [];
    return n7ValidateChunked_(sowObjs, evObjs, items, function (d, n) { n7Prog_(out, d, n); }).then(function (v) {
      v.meta = { maps: maps, ms: Date.now() - t0, files: maps.map(function (m) { return m.file; }) };
      n7ShowImport_(el, out, v);
    });
  });
}
function n7ValidateChunked_(sowObjs, evObjs, items, onProg) {
  var i = 0, chunk = 80, sows = [];
  function stepSow() {
    if (i >= sowObjs.length) { i = 0; return stepEv(n7ValidateSows_(sows, items)); }
    var end = Math.min(i + chunk, sowObjs.length);
    sows = sows.concat(sowObjs.slice(i, end));
    i = end;
    if (onProg) onProg(sows.length, sowObjs.length + evObjs.length);
    return n7Yield_().then(stepSow);
  }
  function stepEv(sowLines) {
    var evs = [], j = 0;
    function more() {
      if (j >= evObjs.length) {
        var evLines = n7ValidateEvs_(evs, sowLines, items);
        n7ParityFix_(sowLines, evLines);
        if (onProg) onProg(sowObjs.length + evLines.length, sowObjs.length + evObjs.length);
        return { sowLines: sowLines, evLines: evLines };
      }
      var end = Math.min(j + chunk, evObjs.length);
      evs = evs.concat(evObjs.slice(j, end));
      j = end;
      if (onProg) onProg(sowObjs.length + evs.length, sowObjs.length + evObjs.length);
      return n7Yield_().then(more);
    }
    return more();
  }
  if (!sowObjs.length) return Promise.resolve(stepEv([]));
  return stepSow();
}
function n7ShowImport_(el, out, v) {
  var sowLines = v.sowLines || [], evLines = v.evLines || [], meta = v.meta || {};
  var sowOk = sowLines.filter(function (l) { return !l._skip && l._status !== 'err'; });
  var evOk = evLines.filter(function (l) { return !l._skip && l._status !== 'err' && !l._flagOnly; });
  var flags = evLines.filter(function (l) { return l._flagOnly || (l._flags && l._flags.length); }).concat(sowLines.filter(function (l) { return l._status === 'warn' && !l._dup; }));
  var dups = sowLines.filter(function (l) { return l._dup; });
  var errN = sowLines.filter(function (l) { return l._status === 'err'; }).length + evLines.filter(function (l) { return l._status === 'err'; }).length;
  function rowsHtml(lines, ev) {
    var show = lines.slice(0, 40);
    var h = '<div class="tw" style="margin-top:8px"><table class="t"><tr><th class="n">#</th><th>모돈번호</th><th>' + (ev ? '작업일' : '전입일') + '</th><th>' + (ev ? '유형' : '상태') + '</th><th>결과</th><th>설명</th></tr>';
    h += show.map(function (l) {
      var why = (l._errs || []).concat(l._warns || []).join(' · ');
      var st = l._status === 'err' ? '<span class="badge b-red">오류</span>' : l._flagOnly ? '<span class="badge">확인 필요</span>' : l._dup ? '<span class="badge">중복</span>' : l._status === 'warn' ? '<span class="badge">확인</span>' : '<span class="badge b-pri">가능</span>';
      return '<tr><td class="n">' + l._i + '</td><td>' + n7Esc_(l.tag) + '</td><td>' + n7Esc_(l.date || l.entry || '') + '</td><td>' + n7Esc_(l.type || l.state || '') + '</td><td>' + st + '</td><td class="mut">' + n7Esc_(why) + '</td></tr>';
    }).join('');
    if (lines.length > show.length) h += '<tr><td colspan="6" class="mut">외 ' + (lines.length - show.length) + '줄</td></tr>';
    return h + '</table></div>';
  }
  var names = (meta.files || []).map(n7Esc_).join(', ');
  var typeN = {}, ti;
  evLines.forEach(function (l) { var t = l.type || '기록'; typeN[t] = (typeN[t] || 0) + 1; });
  var typeBadges = '<span class="badge">모돈 ' + sowLines.length + '</span>';
  ['교배', '임신감정', '분만', '이유', '양자', '자돈폐사', '도폐사', '백신', '전입', '초발정'].forEach(function (t) {
    if (typeN[t]) typeBadges += '<span class="badge">' + t + ' ' + typeN[t] + '</span>';
  });
  Object.keys(typeN).forEach(function (t) {
    if ('교배임신감정부만이유양자자돈폐사도폐사백신전입초발정'.indexOf(t) < 0) typeBadges += '<span class="badge">' + n7Esc_(t) + ' ' + typeN[t] + '</span>';
  });
  var html = '<div class="mut" style="margin-bottom:6px">' + n7Esc_(names) + (meta.ms != null ? ' · 검사 ' + meta.ms + 'ms' : '') + '</div>'
    + '<div class="row" style="gap:8px;flex-wrap:wrap">' + typeBadges + '<span class="badge">기록 ' + evLines.length + '</span><span class="badge b-pri">가져올 수 있음 ' + (sowOk.length + evOk.length) + '</span><span class="badge">확인 필요 ' + flags.length + '</span><span class="badge">중복 ' + dups.length + '</span><span class="badge b-red">오류 ' + errN + '</span></div>';
  if (flags.length) {
    html += '<div class="n7-imp-flags"><b>확인 필요</b> — 추측하지 않고 아래만 적어 두었습니다. 이 줄은 넣지 않습니다.<ul style="margin:6px 0 0 1.1em">'
      + flags.slice(0, 30).map(function (l) { return '<li>' + n7Esc_(l.tag + ' · ' + (l.type || '') + ' ' + (l.date || l.entry || '') + ' — ' + ((l._flags || l._warns || []).join(' '))) + '</li>'; }).join('')
      + (flags.length > 30 ? '<li>외 ' + (flags.length - 30) + '건</li>' : '') + '</ul></div>';
  }
  if (sowLines.length) html += '<h4 class="n7-imp-step">모돈 명단</h4>' + rowsHtml(sowLines, false);
  if (evLines.length) html += '<h4 class="n7-imp-step">기록</h4>' + rowsHtml(evLines, true);
  var q = n7ImpQueue_(sowOk, evOk);
  if (q.length) {
    html += '<p class="mut" style="margin-top:8px">가져오기를 누르면 새 모돈과 기록을 넣습니다. 이미 있는 기록은 그대로 둡니다. 200줄씩 나누어 넣으며, 중간에 멈추면 이어서 넣을 수 있습니다.</p>'
      + '<button type="button" class="btn" id="n7-imp-go">가져오기 (' + q.length + '건)</button>';
  } else html += '<p class="n7-imp-warn">저장할 새 기록이 없습니다. 중복·확인 필요·오류 설명을 확인해 주세요.</p>';
  out.innerHTML = html;
  var g = out.querySelector('#n7-imp-go');
  if (g) g.onclick = function () { n7CommitImport_(g, out, q, { sows: sowOk.length, evs: evOk.length, flags: flags.length }); };
}
function n7ImpFarm_() { return (typeof PL !== 'undefined' && PL.farmId) || ''; }
function n7ImpUser_() { return (typeof PL !== 'undefined' && PL.user && PL.user.id) || ''; }
function n7ImpKey_() { return 'pl_impjob:' + n7ImpFarm_() + ':' + n7ImpUser_(); }
function n7ImpLoad_() { try { return JSON.parse(localStorage.getItem(n7ImpKey_()) || 'null'); } catch (e) { return null; } }
function n7ImpSave_(job) { try { localStorage.setItem(n7ImpKey_(), JSON.stringify(job)); } catch (e) {} }
function n7ImpClear_() { try { localStorage.removeItem(n7ImpKey_()); } catch (e) {} }
function n7ImpReq_(type, r) {
  return ('plimp:' + n7ImpFarm_() + ':' + n7NormTag_(r.tag) + ':' + (r.entry || r._entry || '') + ':' + type + ':' + (r.date || r.entry || '') + ':' + (r.boar || r.total || '')).slice(0, 140);
}
function n7ImpQueue_(sowOk, evOk) {
  var ORD = { '전입': 0, '격리순치': 1, '초발정': 2, '교배': 3, '임신감정': 4, '분만': 5, '자돈폐사': 6, '양자': 7, '부분이유': 8, '이유': 9, '등지방': 10, '백신': 11, '치료': 12, '이동': 13, '도폐사': 14 };
  function rank(tp) { return ORD[tp] != null ? ORD[tp] : 50; }
  function keyOf(tag, type, date) { return String(tag) + '\t' + String(type) + '\t' + String(date || ''); }
  function evItem(type, tag, date, extra, src) {
    var ev = { type: type, tag: tag, date: date };
    if (extra) Object.keys(extra).forEach(function (k) { if (extra[k] !== '' && extra[k] != null) ev[k] = extra[k]; });
    ev.reqId = n7ImpReq_(type, src || ev);
    return { reqId: ev.reqId, ev: ev, label: tag + ' ' + type, tag: tag };
  }
  var bySow = {}, sowOrder = [];
  function sowOf(tag) {
    if (!bySow[tag]) { bySow[tag] = { enter: null, hist: [], seen: {} }; sowOrder.push(tag); }
    return bySow[tag];
  }
  (sowOk || []).forEach(function (r) {
    var g = sowOf(r.tag);
    var extra = { '품종': r.breed || 'F1', '전입산차': r.parity === '' ? 0 : r.parity, '비고': r.memo || '' };
    var hasHist = !!(r.svcDate || r.farrowDate || r.weanDate);
    if (r.state && !hasHist) extra['초기상태'] = r.state;
    g.enter = evItem('전입', r.tag, r.entry, extra, r);
    function addHist(type, date, ex, src) {
      if (!date || date < r.entry) return;
      var k = keyOf(r.tag, type, date);
      if (g.seen[k]) return;
      g.seen[k] = 1;
      g.hist.push(evItem(type, r.tag, date, ex, src));
    }
    if (r.svcDate) addHist('교배', r.svcDate, {}, { tag: r.tag, entry: r.entry, date: r.svcDate });
    if (r.farrowDate) addHist('분만', r.farrowDate, { '총산': r.total, '실산': r.alive, '사산': r.still }, { tag: r.tag, entry: r.entry, date: r.farrowDate, total: r.total });
    if (r.weanDate) addHist('이유', r.weanDate, { '이유두수': r.weaned }, { tag: r.tag, entry: r.entry, date: r.weanDate });
  });
  (evOk || []).forEach(function (r) {
    var g = sowOf(r.tag);
    var k = keyOf(r.tag, r.type, r.date);
    if (g.seen[k]) return;
    g.seen[k] = 1;
    var extra = { '비고': r.memo || '' };
    if (r.parity !== '' && r.parity != null) extra['산차'] = r.parity;
    if (r.boar) extra['웅돈'] = r.boar;
    if (r.method) extra['교배방법'] = r.method;
    if (r.checkResult) extra['감정결과'] = r.checkResult;
    if (r.total) extra['총산'] = r.total;
    if (r.alive) extra['실산'] = r.alive;
    if (r.still) extra['사산'] = r.still;
    if (r.mummy) extra['미라'] = r.mummy;
    if (r.weak) extra['생시도태'] = r.weak;
    if (r.farrowKind) extra['분만구분'] = r.farrowKind;
    if (r.birthWt) extra['생시체중합'] = r.birthWt;
    if (r.loc) extra['위치'] = r.loc;
    if (r.weaned) extra['이유두수'] = r.weaned;
    if (r.weanWt) extra['이유체중합'] = r.weanWt;
    if (r.exitKind) extra['퇴출구분'] = r.exitKind;
    if (r.cause) extra['원인'] = r.cause;
    if (r.type === '도폐사' && r.exitKind !== '판매' && !extra['원인']) extra['원인'] = '기타';
    if (r.vaccName) extra['백신명'] = r.vaccName;
    if (r.fosterKind) extra['양자구분'] = r.fosterKind;
    if (r.fosterN) extra['두수'] = r.fosterN;
    if (r.partner) extra['상대모돈'] = r.partner;
    if (r.femaleAlive) extra['실산_암'] = r.femaleAlive;
    if (r.maleAlive) extra['실산_수'] = r.maleAlive;
    if (r.staff) extra['비고'] = (extra['비고'] ? extra['비고'] + ' / ' : '') + '작업자 ' + r.staff;
    if (r.raw) extra['비고'] = (extra['비고'] ? extra['비고'] + ' / ' : '') + '원본값 ' + r.raw;
    g.hist.push(evItem(r.type, r.tag, r.date, extra, r));
  });
  sowOrder.forEach(function (tag) {
    var g = bySow[tag];
    g.hist.sort(function (a, b) {
      var da = a.ev.date || '', db = b.ev.date || '';
      if (da < db) return -1;
      if (da > db) return 1;
      return rank(a.ev.type) - rank(b.ev.type);
    });
    if (g.enter && g.hist.length && g.enter.ev['초기상태']) delete g.enter.ev['초기상태'];
  });
  var q = [];
  sowOrder.forEach(function (tag) { if (bySow[tag].enter) q.push(bySow[tag].enter); });
  var rest = [];
  sowOrder.forEach(function (tag) { rest = rest.concat(bySow[tag].hist); });
  rest.sort(function (a, b) {
    var da = a.ev.date || '', db = b.ev.date || '';
    if (da < db) return -1;
    if (da > db) return 1;
    var ra = rank(a.ev.type), rb = rank(b.ev.type);
    if (ra !== rb) return ra - rb;
    return String(a.tag).localeCompare(String(b.tag));
  });
  return q.concat(rest);
}
function n7CommitSliceBySow_(slice, concur, fn) {
  var groups = {}, order = [];
  slice.forEach(function (item) {
    var k = (item.ev && item.ev.tag) || item.tag || item.reqId;
    if (!groups[k]) { groups[k] = []; order.push(k); }
    groups[k].push(item);
  });
  function runSow(tag) {
    var list = groups[tag], p = Promise.resolve();
    list.forEach(function (item) { p = p.then(function () { return fn(item); }); });
    return p;
  }
  return n7MapLimit_(order, concur, runSow);
}
function n7ImpShowResume_(el) {
  var box = el && el.querySelector('#n7-imp-resumebox');
  if (!box) return;
  var job = n7ImpLoad_();
  if (!job || !job.queue || job.status === 'done') { box.innerHTML = ''; return; }
  var doneN = (job.done && job.done.length) || 0;
  var left = job.queue.length - doneN;
  if (left <= 0) { n7ImpClear_(); box.innerHTML = ''; return; }
  box.innerHTML = '<div class="n7-imp-resume">이전에 넣다 멈춘 기록이 있습니다. ' + doneN + '건은 들어갔고 ' + left + '건이 남았습니다. <button type="button" class="btn" id="n7-imp-resume">이어서 넣기</button> <button type="button" class="btn sec" id="n7-imp-discard">지우기</button></div>';
  var b = box.querySelector('#n7-imp-resume');
  if (b) b.onclick = function () {
    var out = el.querySelector('#im-out') || box;
    n7CommitJob_(out, job, true);
  };
  var d = box.querySelector('#n7-imp-discard');
  if (d) d.onclick = function () { n7ImpClear_(); box.innerHTML = ''; };
}
function n7CommitImport_(btn, out, queue, counts) {
  if (!queue.length) return;
  if (btn) { btn.disabled = true; btn.classList.add('busy'); }
  var job = { id: 'IM' + Date.now().toString(36), farm: n7ImpFarm_(), queue: queue, done: [], fail: [], status: 'running', at: Date.now(), counts: counts || {} };
  n7ImpSave_(job);
  n7CommitJob_(out, job, false);
}
function n7MapLimit_(items, limit, fn) {
  return new Promise(function (resolve, reject) {
    var i = 0, act = 0, out = [], stopped = false;
    function next() {
      if (stopped) return;
      if (i >= items.length && act === 0) return resolve(out);
      while (act < limit && i < items.length) {
        (function (idx) {
          act++;
          Promise.resolve(fn(items[idx], idx)).then(function (v) { out[idx] = v; act--; next(); }, function (e) { stopped = true; reject(e); });
        })(i++);
      }
    }
    next();
  });
}
function n7CommitJob_(out, job, resuming) {
  window._n7ImpJob = job;
  job.status = 'running';
  job._pause = false;
  out.innerHTML = '';
  var doneSet = {};
  (job.done || []).forEach(function (id) { doneSet[id] = 1; });
  var t0 = Date.now(), saved = 0, skipped = 0, fail = job.fail || [];
  var total = job.queue.length;
  var start = 0;
  while (start < total && doneSet[job.queue[start].reqId]) start++;
  n7Prog_(out, start, total, (resuming ? '이어서 넣는 중 · ' : '넣는 중 · ') + start + ' / ' + total);
  if (!out.querySelector('#n7-imp-pause')) {
    var row = document.createElement('div');
    row.className = 'row';
    row.innerHTML = '<button type="button" class="btn sec" id="n7-imp-pause">잠시 멈추기</button>';
    out.appendChild(row);
  }
  var pauseBtn = out.querySelector('#n7-imp-pause');
  if (pauseBtn) pauseBtn.onclick = function () { job._pause = true; pauseBtn.disabled = true; pauseBtn.textContent = '멈추는 중'; };
  function batchFrom(i) {
    if (job._pause || (window._n7ImpStopAfter && (start + saved + skipped) >= window._n7ImpStopAfter)) {
      job.status = 'paused';
      n7ImpSave_(job);
      var doneN = (job.done || []).length;
      out.innerHTML = '<div class="n7-imp-warn">가져오기를 잠시 멈췄습니다. ' + doneN + ' / ' + total + '건까지 넣었습니다. 같은 화면에서 이어서 넣을 수 있습니다.</div>'
        + '<div class="row"><button type="button" class="btn" id="n7-imp-resume2">이어서 넣기</button></div>';
      n7ImpShowResume_(document.getElementById('n7-imp') && document.getElementById('n7-imp').closest('#app') || document.body);
      var b = out.querySelector('#n7-imp-resume2');
      if (b) b.onclick = function () { n7CommitJob_(out, n7ImpLoad_() || job, true); };
      return Promise.resolve();
    }
    if (i >= total) {
      job.status = 'done';
      n7ImpClear_();
      var ms = Date.now() - t0;
      out.innerHTML = '<div class="n7-imp-ok">가져오기를 마쳤습니다. 저장 ' + saved + '건' + (skipped ? ', 이미 있음 ' + skipped : '') + (fail.length ? ', 실패 ' + fail.length + '건' : '') + '. 걸린 시간 ' + Math.round(ms / 100) / 10 + '초. 기존 기록은 그대로 두었습니다.</div>'
        + (fail.length ? '<div class="n7-imp-warn">' + fail.slice(0, 20).map(function (x) { return n7Esc_(x); }).join('<br>') + (fail.length > 20 ? '<br>외 ' + (fail.length - 20) + '건' : '') + '</div>' : '')
        + '<div class="row"><button type="button" class="btn" id="n7-imp-sows">모돈 목록 보기</button></div>';
      var b2 = out.querySelector('#n7-imp-sows');
      if (b2) b2.onclick = function () { n7Go_('sows'); };
      return Promise.resolve();
    }
    var end = Math.min(i + N7_IMP_BATCH, total);
    var slice = job.queue.slice(i, end).filter(function (x) { return !doneSet[x.reqId]; });
    return n7CommitSliceBySow_(slice, N7_IMP_CONCUR, function (item) {
      return apiF('saveEvent', item.ev).then(function (r) {
        doneSet[item.reqId] = 1;
        job.done.push(item.reqId);
        if (r && r.duplicate) skipped++; else saved++;
      }).catch(function (err) {
        var msg = (typeof uiMsg === 'function' ? uiMsg(err) : (err && err.message) || '저장 실패');
        fail.push(item.label + ': ' + msg);
        job.fail = fail;
      });
    }).then(function () {
      n7ImpSave_(job);
      n7Prog_(out, end, total, '넣는 중 · ' + Math.min(end, total) + ' / ' + total);
      return n7Yield_().then(function () { return batchFrom(end); });
    });
  }
  return batchFrom(start).catch(function (e) {
    job.status = 'paused';
    n7ImpSave_(job);
    out.innerHTML = '<div class="n7-err">' + n7Esc_(e && e.message ? e.message : String(e)) + '</div><div class="n7-imp-warn">중간까지 넣은 기록은 남겨 두었습니다. 이어서 넣을 수 있습니다.</div>';
    n7ImpShowResume_(document.body);
  });
}

function n7HookImport_() {
  if (typeof pageImport === 'function' && !pageImport._n7i) {
    var _pi = pageImport;
    pageImport = function (el) { _pi(el); nov7PolishImport_(el); };
    pageImport._n7i = 1;
  }
  var up = document.getElementById('im-up');
  if (up) {
    var host = up.closest && (up.closest('#app') || up.closest('main') || up.closest('.card') && up.closest('.card').parentNode);
    if (host) nov7PolishImport_(host);
  }
}

function nov7Esc_(s) { return String(s == null ? '' : s).replace(/[&<>"']/g, function (c) { return { '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;' }[c]; }); }
function nov7CanAi_(user, view) { return !!(user); }   // t418: field·m 포함. 쓰기 권한은 서버 canDraft, 수의사는 조회만
(function () { if (typeof pageOk !== 'function' || pageOk._n7ai) return; var o = pageOk; pageOk = function (p) { if (p === 'ai' && PL.user) return true; return o(p); }; pageOk._n7ai = 1; })();

function nov7Trend_(direction, delta) {
  if (delta == null || Number.isNaN(delta)) return '비교할 자료 없음';
  if (delta === 0) return '지난달과 같음';
  var up = delta > 0;
  if (direction === 'up') return up ? '올라 좋아짐' : '내려 나빠짐';
  if (direction === 'down') return up ? '올라 나빠짐' : '내려 좋아짐';
  return up ? '올랐습니다' : '내렸습니다';
}
function nov7Delta_(trend) {
  if (!trend) return null;
  var nums = trend.filter(function (p) { return p && p.value != null && !p.unavailable; });
  if (nums.length < 2) return null;
  return Math.round((nums[nums.length - 1].value - nums[nums.length - 2].value) * 100) / 100;
}
function nov7Month_(m) { var p = String(m || '').split('-'); return p[1] ? String(Number(p[1])) : ''; }
function nov7Y_(p) {
  if (typeof p === 'number') return isFinite(p) ? p : null;
  if (!p || p.unavailable) return null;
  if (p.value != null && p.value !== '' && isFinite(Number(p.value))) return Number(p.value);
  if (p.parts && p.parts.length) { var s = 0, any = false; p.parts.forEach(function (x) { if (x && x.n != null && isFinite(Number(x.n))) { s += Number(x.n); any = true; } }); return any ? s : null; }
  return null;
}
function nov7Fit_(trend) {
  var xs = [], ys = [];
  (trend || []).forEach(function (p, i) { var y = nov7Y_(p); if (y == null) return; xs.push(i); ys.push(y); });
  if (xs.length < 2) return { ok: false, n: xs.length, reason: 'short' };
  var n = xs.length, sx = 0, sy = 0, i;
  for (i = 0; i < n; i++) { sx += xs[i]; sy += ys[i]; }
  var mx = sx / n, my = sy / n, num = 0, den = 0;
  for (i = 0; i < n; i++) { var dx = xs[i] - mx; num += dx * (ys[i] - my); den += dx * dx; }
  if (!(den > 0)) return { ok: false, n: n, reason: 'flatx' };
  var slope = num / den, a = xs[0], b = xs[0];
  xs.forEach(function (x) { if (x < a) a = x; if (x > b) b = x; });
  var intercept = my - slope * mx;
  return { ok: true, n: n, slope: slope, intercept: intercept, from: a, to: b, y0: intercept + slope * a, y1: intercept + slope * b };
}
function nov7Word_(fit) {
  if (!fit || !fit.ok) return '추세선을 그릴 자료가 부족합니다.';
  if (Math.abs(fit.slope) < 1e-6) return '추세선 · 보합';
  return fit.slope > 0 ? '추세선 · 오름' : '추세선 · 내림';
}
function nov7Donut_(c) {
  var slices = (c.slices || []).filter(function (s) { return s && s.n > 0; }), total = Number(c.denominator) || 0;
  if (!total || !slices.length) return '<p class="period">기준일에 집계할 모돈이 없습니다.</p>';
  var colors = ['#1f6f43', '#0f766e', '#3f6212', '#b45309', '#1d4ed8', '#7c3aed', '#0e7490', '#a16207', '#be123c', '#0369a1'];
  var C = 2 * Math.PI * 36, off = 0, arcs = '', label = '기준일 ' + (c.asOf || '') + ' 현재 구성. 전체 ' + total + '두. ';
  slices.forEach(function (s, i) {
    var len = s.n / total * C, col = s.key === 'unknown' ? '#6b7280' : colors[i % colors.length];
    arcs += '<circle cx="70" cy="64" r="36" fill="none" stroke="' + col + '" stroke-width="18" stroke-dasharray="' + len.toFixed(3) + ' ' + (C - len).toFixed(3) + '" stroke-dashoffset="' + (-off).toFixed(3) + '" transform="rotate(-90 70 64)"><title>' + nov7Esc_(s.name + ' ' + s.n + '두 ' + s.pct + '%') + '</title></circle>';
    off += len; label += s.name + ' ' + s.n + '두 ' + s.pct + '%. ';
  });
  var leg = '<ul class="donut-leg">' + slices.map(function (s, i) { var col = s.key === 'unknown' ? '#6b7280' : colors[i % colors.length]; return '<li><i style="background:' + col + '"></i><span>' + nov7Esc_(s.name) + ' ' + nov7Esc_(s.n) + '두 ' + nov7Esc_(s.pct) + '%</span></li>'; }).join('') + '</ul>';
  var hist = '';
  if (c.history && c.history.length) hist = '<details><summary>월말 구성</summary><p>그 달 말까지 기록으로 다시 계산한 구성입니다. 추세선이 아닙니다.</p>' + c.history.map(function (h) { return '<p>' + nov7Esc_(h.month) + ' ' + (!h.n ? '자료 없음' : ((h.slices || []).map(function (s) { return s.name + ' ' + s.n + '두'; }).join(', ') + ' · 전체 ' + h.n + '두')) + '</p>'; }).join('') + '</details>';
  return '<svg class="plot" data-chart="donut" viewBox="0 0 140 128" role="img" aria-label="' + nov7Esc_(label) + '">' + arcs + '<text x="70" y="68" text-anchor="middle" class="ax">' + total + '</text></svg>' + leg + hist;
}
function nov7Plot_(c) {
  if (c.chart === 'donut' || c.snapshot) return nov7Donut_(c);
  var kind = c.chart || 'bar';
  var trend = (c.trend || []).slice(0, 12); while (trend.length < 12) trend.push({ value: null, unavailable: true, month: '' });
  var w = 320, h = 132, L = 28, R = 6, T = 8, B = 22, nums = [];
  trend.forEach(function (p) { var yv = nov7Y_(p); if (yv != null) nums.push(yv); });
  if (!nums.length) return '<p class="period">최근 12개월 자료가 없습니다.</p>';
  var fit = (kind === 'line' || kind === 'bar' || kind === 'bar-target' || kind === 'stack') ? nov7Fit_(trend) : { ok: false, n: 0 };
  if (fit.ok) { nums.push(fit.y0, fit.y1); }
  var lo = c.chart === 'line' ? Math.min.apply(null, nums) : Math.min.apply(null, [0].concat(nums)), hi = Math.max.apply(null, nums.concat(c.target != null ? [Number(c.target)] : []));
  if (lo === hi) hi = lo + 1;
  var iw = w - L - R, ih = h - T - B;
  function x(i) { return L + iw * (i + 0.5) / 12; }
  function y(v) { return T + ih * (1 - (v - lo) / (hi - lo)); }
  var marks = '', bars = '', path = '', started = false, alt = [];
  trend.forEach(function (p, i) {
    marks += '<text x="' + x(i).toFixed(1) + '" y="' + (h - 4) + '" text-anchor="middle" class="ax">' + nov7Esc_(nov7Month_(p.month)) + '</text>';
    if (c.chart === 'stack' && p && p.parts && !p.unavailable) {
      var acc = 0; p.parts.forEach(function (part, pi) { var v = Number(part.n) || 0, y1 = y(acc + v), y0 = y(acc); bars += '<rect x="' + (x(i) - 7).toFixed(1) + '" y="' + y1.toFixed(1) + '" width="14" height="' + Math.max(0, y0 - y1).toFixed(1) + '" class="stk s' + (pi % 3) + '"><title>' + nov7Esc_(p.month + ' ' + part.name + ' ' + v) + '</title></rect>'; acc += v; });
      alt.push(p.month + ' ' + p.parts.map(function (part) { return part.name + ' ' + part.n; }).join(', ')); return;
    }
    var yv = nov7Y_(p);
    if (yv == null) { started = false; alt.push((p && p.month || i) + ' 자료 없음'); return; }
    alt.push((p.month || '') + ' ' + yv + (p.partial ? ' 이번 달, 오늘까지' : ''));
    if (kind === 'line') { path += (started ? 'L' : 'M') + x(i).toFixed(1) + ' ' + y(yv).toFixed(1) + ' '; started = true; bars += '<circle cx="' + x(i).toFixed(1) + '" cy="' + y(yv).toFixed(1) + '" r="3" class="dot"><title>' + nov7Esc_(p.month + ' ' + yv) + '</title></circle>'; }
    else { var top = y(yv); bars += '<rect x="' + (x(i) - 7).toFixed(1) + '" y="' + top.toFixed(1) + '" width="14" height="' + Math.max(0, y(0) - top).toFixed(1) + '" class="bar' + (p.partial ? ' partial' : '') + '"><title>' + nov7Esc_(p.month + ' ' + yv + (p.partial ? ' 이번 달 오늘까지' : '')) + '</title></rect>'; }
  });
  var trendSvg = '';
  if (fit.ok) trendSvg = '<line class="trendline" data-from="' + fit.from + '" data-to="' + fit.to + '" data-slope="' + fit.slope + '" x1="' + x(fit.from).toFixed(1) + '" y1="' + y(fit.y0).toFixed(1) + '" x2="' + x(fit.to).toFixed(1) + '" y2="' + y(fit.y1).toFixed(1) + '"><title>추세선</title></line>';
  var target = '';
  if ((c.chart === 'bar-target' || c.chart === 'line' || c.chart === 'bar') && c.target != null && c.target !== '') { var ty = y(Number(c.target)); target = '<line x1="' + L + '" x2="' + (w - R) + '" y1="' + ty.toFixed(1) + '" y2="' + ty.toFixed(1) + '" class="tgtline"><title>농장 목표 ' + nov7Esc_(c.target) + '</title></line>'; }
  var leg = '<p class="pleg"><span><i class="ln"></i>실적</span><span><i class="tr"></i>' + nov7Esc_(nov7Word_(fit)) + '</span>' + (c.target != null && c.target !== '' ? '<span><i class="tg"></i>농장 목표</span>' : '') + '</p>';
  return '<svg class="plot" data-chart="' + nov7Esc_(kind) + '" data-trend="' + (fit.ok ? 'on' : 'off') + '" viewBox="0 0 ' + w + ' ' + h + '" role="img" aria-label="최근 12개월 ' + nov7Esc_(c.title) + ' ' + nov7Esc_(nov7Word_(fit)) + '">' + (kind === 'line' ? '<path d="' + path + '" class="ln"/>' : '') + bars + trendSvg + target + marks + '</svg>' + leg + '<details><summary>월별 숫자</summary><p>' + nov7Esc_(alt.join(' · ')) + '</p><p>점선은 값이 있는 달만으로 맞춘 직선입니다. 없는 달은 0으로 넣지 않고, 마지막 값 다음은 그리지 않습니다.</p><p>' + nov7Esc_(c.formula || '') + '</p></details>';
}
function nov7Card_(c) {
  var snap = c.chart === 'donut' || c.snapshot;
  var un = snap ? !(Number(c.denominator) > 0) : (!!c.unavailable || c.value == null);
  var shown = un ? null : Number(snap ? c.denominator : c.value);
  var val = un ? '자료 없음' : (Math.abs(shown) >= 100 || shown % 1 === 0 ? String(Math.round(shown)) : String(Math.round(shown * 10) / 10));
  var dir = snap ? '현재 구성' : nov7Trend_(c.direction, nov7Delta_(c.trend));
  var period = c.period && typeof c.period === 'object' ? (c.period.label || '') : (c.period || '');
  var note = c.note && typeof c.note === 'object' ? (c.note.label || c.note.text || '') : (c.note || '');
  return '<article class="kcard" data-id="' + nov7Esc_(c.id) + '" data-chart="' + nov7Esc_(c.chart) + '"' + (snap ? ' data-snapshot="1"' : '') + '><header><h3>' + nov7Esc_(c.title) + '</h3><span class="dir">' + nov7Esc_(dir) + '</span></header><p class="val"><b>' + nov7Esc_(val) + '</b> <small>' + nov7Esc_(un ? '' : c.unit || '') + '</small></p><p class="period">' + nov7Esc_(period) + (!snap && c.target != null ? ' · 목표 ' + nov7Esc_(c.target) : '') + '</p>' + (note ? '<p class="period">' + nov7Esc_(note) + '</p>' : '') + nov7Plot_(c) + '</article>';
}
function nov7Decide_(o) {
  var msg = o.msg || {}, prefs = o.prefs || { enabled: true, sound: false }, now = o.now || Date.now();
  if (!o.loggedIn) return { toast: false, sound: false, badge: false, reason: 'logout' };
  if (msg.farm && o.farm && msg.farm !== o.farm) return { toast: false, sound: false, badge: false, reason: 'tenant' };
  if (msg.mine || (o.me && msg.senderId === o.me)) return { toast: false, sound: false, badge: false, reason: 'self' };
  if (msg.expired) return { toast: false, sound: false, badge: false, reason: 'expired' };
  if (msg.read || (o.openId && o.openId === msg.id)) return { toast: false, sound: false, badge: true, reason: 'read' };
  if (o.seen && o.seen[msg.id]) return { toast: false, sound: false, badge: true, reason: 'dup' };
  if (prefs.enabled === false) return { toast: false, sound: false, badge: true, reason: 'off' };
  if (prefs.dndUntil && Date.parse(prefs.dndUntil) > now) return { toast: false, sound: false, badge: true, reason: 'dnd' };
  return { toast: true, sound: !!(prefs.sound && o.soundUnlocked), badge: true, reason: 'show', soundBlocked: !!(prefs.sound && !o.soundUnlocked) };
}
function nov7Prefs_() {
  var id = PL.user && PL.user.id || '';
  try { return JSON.parse(localStorage.getItem('pl_msg_pref:' + id) || '') || { enabled: true, sound: false }; } catch (e) { return { enabled: true, sound: false }; }
}
function nov7PrefsSet_(p) { try { localStorage.setItem('pl_msg_pref:' + (PL.user && PL.user.id || ''), JSON.stringify(p)); } catch (e) {} }
function nov7Toast_(text) {
  var old = document.getElementById('nov7-toast'); if (old) old.remove();
  var d = document.createElement('div'); d.id = 'nov7-toast'; d.className = 'nov7-toast'; d.textContent = text; document.body.appendChild(d);
  setTimeout(function () { if (d.parentNode) d.remove(); }, 4000);
}
function pageKpiBoard(el) {
  el.innerHTML = '<div class="nov7-banner">시험용 계산입니다. 외부 AI는 꺼져 있습니다. 2026-11-13은 베타 목표일이며 출시일이 아닙니다.</div><div class="nov7-top"><h2 style="margin:0">핵심 KPI TOP 10</h2><button type="button" class="btn" id="nov7-pick">KPI 설정</button></div><div id="nov7-board" class="nov7-board"></div>';
  var data = { ids: [], catalog: [] };
  function paint(b) {
    data = b; var host = $('#nov7-board', el); if (!host) return;
    host.innerHTML = (b.cards || []).map(nov7Card_).join('') || '<p>표시할 KPI가 없습니다.</p>';
  }
  apiF('getKpiBoard').then(paint).catch(function (e) { el.innerHTML = errHTML(e); });
  $('#nov7-pick', el).onclick = function () { nov7Picker_(data, function (ids) { apiF('saveKpiBoard', ids).then(function () { return apiF('getKpiBoard'); }).then(paint).catch(function (e) { toast(uiMsg(e)); }); }); };
}

function n7Esc_(s) { return typeof nov7Esc_ === 'function' ? nov7Esc_(s) : String(s == null ? '' : s).replace(/[&<>"']/g, function (c) { return ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;' })[c]; }); }
function n7FarmWeek_(iso) {
  var s = String(iso || (typeof window.today === 'function' ? window.today() : ((window.PL && PL._daily && PL._daily.today) || ''))).slice(0, 10);
  var w = (typeof n7SatWeek_ === 'function') ? n7SatWeek_(s) : null;
  if (!w) return null;
  var dt = new Date(s + 'T00:00:00+09:00');
  return { year: w.year, week: w.week, from: w.from, to: w.to, fromMd: w.from.slice(5), toMd: w.to.slice(5), dow: isNaN(dt.getTime()) ? null : dt.getDay(), date: s };
}
function nov7DayHint_(root, inp) {
  if (!inp) return;
  var row = (inp.closest && inp.closest('.row')) || inp.parentNode;
  var big = !!(inp.closest && inp.closest('.entry.big, .far-open, body.far-open'));
  var host = row && row.parentNode ? row.parentNode : (root || inp.parentNode);
  var hint = host && host.querySelector ? host.querySelector('.n7-dayhint') : null;
  if (!hint && row && row.querySelector) hint = row.querySelector('.n7-dayhint');
  if (!hint) {
    hint = document.createElement('span');
    hint.className = 'mut n7-dayhint';
    if (big && row && row.parentNode) row.parentNode.insertBefore(hint, row.nextSibling);
    else if (row) row.appendChild(hint);
    else return;
  }
  var d = inp.value, t = typeof today === 'function' ? today() : '';
  if (!d || !t || d === t) { hint.textContent = ''; return; }
  var n = Math.round((Date.parse(t + 'T00:00:00') - Date.parse(d + 'T00:00:00')) / 864e5);
  var hasQuick = !!(inp.closest && inp.closest('.entry') && inp.closest('.entry').querySelector('[data-day="-1"], [data-day="1"], [data-d="-1"]'));
  if (hasQuick && (n === 1 || n === -1)) { hint.textContent = ''; return; }
  if (n === 1) hint.textContent = hasQuick ? '' : '어제';
  else if (n > 1) hint.textContent = n + '일 전';
  else if (n === -1) hint.textContent = hasQuick ? '' : '내일';
  else if (n < -1) hint.textContent = Math.abs(n) + '일 후';
  else hint.textContent = '';
}
function nov7BindDayBtns_(root, dateSel, onVal) {
  if (!root) return;
  dateSel = dateSel || '#ef-date';
  var inp = typeof $ === 'function' ? $(dateSel, root) : root.querySelector(dateSel);
  if (!inp) return;
  var btns = typeof $$ === 'function' ? $$('[data-day]', root) : root.querySelectorAll('[data-day]');
  Array.prototype.forEach.call(btns, function (b) {
    b.onclick = function () {
      var n = Number(b.dataset.day), v = n ? addDays(inp.value || today(), n) : today();
      if (inp.min && v < inp.min) v = inp.min;
      if (inp.max && v > inp.max) v = inp.max;
      inp.value = v;
      if (onVal) onVal(v);
      nov7DayHint_(root, inp);
    };
  });
  if (!inp.getAttribute('data-n7day')) {
    inp.setAttribute('data-n7day', '1');
    inp.addEventListener('change', function () { nov7DayHint_(root, inp); });
    inp.addEventListener('input', function () { nov7DayHint_(root, inp); });
  }
  nov7DayHint_(root, inp);
}
if (!window._n7dayDel) {
  window._n7dayDel = 1;
  document.addEventListener('click', function (e) {
    var b = e.target && e.target.closest && e.target.closest('[data-day]');
    if (!b) return;
    var root = (b.closest && (b.closest('.entry') || b.closest('.card'))) || document.body;
    var inp = root.querySelector ? (root.querySelector('#ef-date') || root.querySelector('#pa-date')) : null;
    if (inp) setTimeout(function () { nov7DayHint_(root, inp); }, 0);
  }, false);
}
function n7HookFarrowDates_() {
  if (typeof farrowDates_ === 'function' && !farrowDates_._n7) {
    farrowDates_ = function (el) { nov7BindDayBtns_(el, '#ef-date'); };
    farrowDates_._n7 = 1;
  }
}
n7HookFarrowDates_();

function n7Num_(v, d) {
  if (v == null || v === '' || (typeof v === 'number' && isNaN(v))) return null;
  if (typeof nF === 'function') return nF(v, d);
  if (typeof fmtN === 'function') return fmtN(v, d);
  v = +v;
  if (isNaN(v)) return null;
  var p = (d == null) ? (Math.abs(v - Math.round(v)) < 1e-9 ? 0 : 1) : d;
  return v.toLocaleString('ko-KR', { maximumFractionDigits: p, minimumFractionDigits: 0 });
}
function n7CardOf_(h, id) {
  if (!h) return null;
  function find(arr) {
    if (!arr) return null;
    for (var i = 0; i < arr.length; i++) if (arr[i] && arr[i].id === id) return arr[i];
    return null;
  }
  return find(h.primary) || find(h.secondary) || find(h.mort) || null;
}
function n7Band_(val, tgt, hib) {
  if (val == null || val === '' || isNaN(+val)) return 'none';
  if (tgt == null || tgt === '' || isNaN(+tgt)) return 'good';
  val = +val; tgt = +tgt;
  if (hib) {
    if (val >= tgt) return 'good';
    if (tgt && val >= tgt * 0.9) return 'warn';
    return 'bad';
  }
  if (val <= tgt) return 'good';
  if (tgt && val <= tgt * 1.1) return 'warn';
  return 'bad';
}
function n7Frac_(id, c) {
  var b = c && c.breakdown; if (!b) return '';
  if (id === 'psy') return (b.weaned != null && b.avgSows != null) ? ('이유 ' + n7Esc_(n7Num_(b.weaned, 0)) + '두 / 평균 모돈 ' + n7Esc_(n7Num_(b.avgSows, 1)) + '두') : '';
  if (id === 'farrowRate') return b.cohortN != null ? ('교배 코호트 ' + n7Esc_(n7Num_(b.cohortN, 0)) + '복') : '';
  if (id === 'weanPerLitter') return (b.weaned != null && b.nWean != null) ? ('이유 ' + n7Esc_(n7Num_(b.weaned, 0)) + '두 / ' + n7Esc_(n7Num_(b.nWean, 0)) + '복') : '';
  if (id === 'avgTotal') return (b.total != null && b.farrows != null) ? ('총산 ' + n7Esc_(n7Num_(b.total, 0)) + '두 / ' + n7Esc_(n7Num_(b.farrows, 0)) + '복') : '';
  if (id === 'avgAlive') return (b.alive != null && b.farrows != null) ? ('실산 ' + n7Esc_(n7Num_(b.alive, 0)) + '두 / ' + n7Esc_(n7Num_(b.farrows, 0)) + '복') : '';
  if (id === 'mortPre') return (b.dead != null && b.alive != null) ? ('폐사 ' + n7Esc_(n7Num_(b.dead, 0)) + '두 / 실산 ' + n7Esc_(n7Num_(b.alive, 0)) + '두') : '';
  return '';
}
function n7Need_(id) {
  if (id === 'msy') return '출하 기록이 더 있으면 MSY를 계산할 수 있습니다.';
  if (id === 'mortNursery') return '이유 후(육성 전) 폐사 기록이 필요합니다.';
  if (id === 'mortGrower') return '육성 구간 폐사 기록이 필요합니다.';
  if (id === 'mortFinisher') return '비육 구간 폐사 기록이 필요합니다.';
  return '이 지표를 계산할 기록이 충분하지 않습니다.';
}
function n7Go_(name, arg) {
  var fn = (typeof go === 'function' && go) || (typeof PL !== 'undefined' && PL.go);
  if (fn) fn(name, arg);
}

function nov7HomeV2_(el, dash, home, due, goals, goFn, sows) {
  if (!el || !el.isConnected) return;
  var goPage = goFn || n7Go_;
  var d = dash || {}, h = home || {}, items = (due && due.items) || [];
  var plan = (goals && (goals.plan || goals.values || goals)) || {};
  var IND = { psy: 24.5, msy: 22.5, farrowRate: 86, avgTotal: 14, avgAlive: 13, mortPre: 13, mortNursery: 4, mortGrower: 2.5, mortFinisher: 2.5 };
  var HIB = { psy: 1, msy: 1, farrowRate: 1, weanPerLitter: 1, avgTotal: 1, avgAlive: 1, mortPre: 0, mortNursery: 0, mortGrower: 0, mortFinisher: 0, mortSow: 0 };
  var LAB = { psy: 'PSY', msy: 'MSY', farrowRate: '분만율', weanPerLitter: '복당 이유두수', avgTotal: '총산', avgAlive: '실산', mortPre: '포유자돈 폐사율' };
  var UNIT = { farrowRate: '%', mortPre: '%', mortNursery: '%', mortGrower: '%', mortFinisher: '%', mortSow: '%' };
  var DP = { psy: 1, msy: 1, farrowRate: 1, weanPerLitter: 2, avgTotal: 2, avgAlive: 2, mortPre: 1, mortNursery: 1, mortGrower: 1, mortFinisher: 1 };
  function goalOf(id) {
    var v = plan[id];
    if (v != null && v !== '' && !isNaN(+v)) return { v: +v, tag: '내 목표' };
    if (IND[id] != null) return { v: IND[id], tag: '업계 평균' };
    return null;
  }
  function card(id) { return n7CardOf_(h, id); }
  var todayIso = (d.today || h.today || (typeof window.today === 'function' ? window.today() : ((window.PL && PL._daily && PL._daily.today) || ''))).toString().slice(0, 10);
  var wk = n7FarmWeek_(todayIso);
  var farmName = (d.farm && (d.farm.name || d.farm)) || (h.farm && h.farm.name) || (typeof PL !== 'undefined' && PL.farmName) || '우리 농장';
  if (typeof farmName !== 'string') farmName = '우리 농장';
  var dows = ['일', '월', '화', '수', '목', '금', '토'];
  var heroDate = '';
  if (todayIso) {
    var p = todayIso.split('-');
    heroDate = Number(p[1]) + '월 ' + Number(p[2]) + '일 ' + (wk ? (dows[wk.dow] + '요일') : '');
  }
  var dueC = d.due || {};
  function cnt(k) { return (dueC.count && dueC.count[k]) || 0; }
  var heroSum = '이번 주 분만 예정 ' + cnt('분만') + '복 · 이유 예정 ' + cnt('이유') + '복';
  if (wk) heroSum = wk.year + '년 ' + wk.week + '주차 · ' + wk.fromMd + '~' + wk.toMd + ' · ' + heroDate;

  var KIND = [
    { k: '분만', title: '분만 예정', typ: '분만', ic: '●' },
    { k: '이유', title: '이유 예정', typ: '이유', ic: '○' },
    { k: '재발확인', title: '임신감정 대상', typ: '임신감정', ic: '◇' },
    { k: '교배', title: '교배 예정', typ: '교배', ic: '＋' }
  ];
  function group(kind, overdue) {
    return items.filter(function (x) { return x.kind === kind && !!x.overdue === overdue; });
  }
  var rows = [];
  KIND.forEach(function (k) {
    var late = group(k.k, true), soon = group(k.k, false);
    var old = [], recentLate = [];
    var todayS = todayIso || (typeof window.today === 'function' ? window.today() : ((window.PL && PL._daily && PL._daily.today) || ''));
    late.forEach(function (x) {
      var days = 0, d = String(x.date || '');
      if (x.daysLeft != null) days = -Number(x.daysLeft);
      else if (d && todayS) days = Math.round((Date.parse(todayS) - Date.parse(d)) / 86400000);
      if (days > 30) old.push(x); else recentLate.push(x);
    });
    if (recentLate.length) rows.push({ k: k, late: 1, list: recentLate });
    if (old.length) rows.push({ k: k, late: 1, old: 1, list: old });
    if (soon.length) rows.push({ k: k, late: 0, list: soon });
  });
  if (!items.length) {
    KIND.forEach(function (k) {
      var n = cnt(k.k), ov = (dueC.overdue && dueC.overdue[k.k]) || 0;
      if (ov) rows.push({ k: k, late: 1, list: [], n: ov });
      if (n - ov > 0) rows.push({ k: k, late: 0, list: [], n: n - ov });
    });
  }
  function rowHTML(r) {
    var n = r.n != null ? r.n : r.list.length;
    var dates = r.list.map(function (x) { return String(x.date || '').slice(5); }).filter(Boolean);
    var span = dates.length ? (dates[0] + (dates[dates.length - 1] !== dates[0] ? '~' + dates[dates.length - 1] : '')) : '';
    var title = (r.late ? r.k.title.replace(' 예정', ' 예정 경과') : r.k.title);
    if (r.k.k === '재발확인' && r.late) title = '임신감정 경과';
    if (r.old) title = '30일 넘은 ' + r.k.title.replace(' 예정', '');
    var meta = n + '두' + (span ? ' · ' + span : '');
    var pill = r.old ? '' : (r.late ? '<span class="n7h-pill late">지연</span>' : (r.list.some && r.list.some(function (x) { return x.daysLeft === 0; }) ? '<span class="n7h-pill today">오늘</span>' : ''));
    var act = r.old ? '한꺼번에 정리' : (r.late ? '보기' : '입력');
    return '<div class="n7h-row" data-kind="' + n7Esc_(r.k.k) + '" data-typ="' + n7Esc_(r.k.typ) + '" data-late="' + (r.late ? 1 : 0) + '" data-old="' + (r.old ? 1 : 0) + '"><div class="ic">' + r.k.ic + '</div><div class="bd"><div class="ti">' + n7Esc_(title) + '</div><div class="mt">' + n7Esc_(meta) + '</div></div>' + pill + '<button type="button" class="btn sm act">' + act + '</button></div>';
  }

  var KPI = [
    { id: 'psy', pair: null, title: 'PSY' },
    { id: 'farrowRate', pair: null, title: '분만율' },
    { id: 'weanPerLitter', pair: null, title: '복당 이유두수' },
    { id: 'avgTotal', pair: 'avgAlive', title: '총산 / 실산' },
    { id: 'mortPre', pair: null, title: '포유자돈 폐사율' },
    { id: 'msy', pair: null, title: 'MSY' }
  ];
  function kpiHTML(spec) {
    var c = card(spec.id), c2 = spec.pair ? card(spec.pair) : null;
    var isNotPorted = (c && c.notPorted) || /^(msy|mortNursery|mortGrower|mortFinisher)$/.test(spec.id);
    var missing = !c || isNotPorted || c.value == null || c.value === '';
    var g = goalOf(spec.id), hib = !!HIB[spec.id];
    var band = missing ? 'none' : n7Band_(c.value, g && g.v, hib);
    var html = '<div class="n7h-card st-' + band + '"><div class="n7h-lab">' + n7Esc_(spec.title) + (g ? ' <span class="n7h-tag">(' + n7Esc_(g.tag) + ')</span>' : '') + '</div>';
    if (missing) {
      html += '<div class="n7h-k n7-none">' + (isNotPorted ? '현재 미지원' : '—') + '</div><div class="n7h-vs none">' + (isNotPorted ? '자동 계산하지 않습니다' : '판단 불가') + '</div><div class="n7h-need">' + n7Esc_(isNotPorted ? '이 지표는 아직 자동 계산하지 않습니다.' : n7Need_(spec.id)) + '</div><button type="button" class="btn sm n7h-go" data-go="entry">기록 입력</button></div>';
      return html;
    }
    var vs = '';
    if (g) {
      var diff = +c.value - g.v, ad = Math.abs(diff);
      var ds = n7Num_(ad, DP[spec.id]);
      if (diff === 0) vs = '목표와 같습니다';
      else vs = '목표보다 ' + ds + (UNIT[spec.id] || '') + (diff < 0 ? ' 낮음' : ' 높음');
    }
    var valStr;
    if (spec.pair && c2 && c2.value != null) valStr = n7Num_(c.value, DP[spec.id]) + ' / ' + n7Num_(c2.value, DP[spec.pair]);
    else valStr = n7Num_(c.value, DP[spec.id]) + (UNIT[spec.id] || '');
    var del = c.delta, dcls = 'flat', dtxt = '변동 없음';
    if (del != null && !isNaN(+del) && +del !== 0) {
      var up = +del > 0;
      var good = hib ? up : !up;
      dcls = good ? 'good' : 'bad';
      dtxt = (up ? '▲ ' : '▼ ') + n7Num_(Math.abs(+del), DP[spec.id]) + (UNIT[spec.id] || '');
    }
    var frac = n7Frac_(spec.id, c);
    if (spec.pair && c2) {
      var f2 = n7Frac_(spec.pair, c2);
      if (frac && f2 && f2 !== frac) frac += ' · ' + f2;
      else if (!frac) frac = f2;
    }
    var spark = '';
    if (c.spark && c.spark.length) {
      var mx = 0;
      c.spark.forEach(function (x) { if (x != null && +x > mx) mx = +x; });
      spark = '<div class="n7h-spark" aria-hidden="true">' + c.spark.map(function (x, i) {
        var hgt = (x == null || !mx) ? 2 : Math.max(2, Math.round((+x / mx) * 28));
        return '<i class="' + (i === c.spark.length - 1 ? 'on' : '') + '" style="height:' + hgt + 'px"></i>';
      }).join('') + '</div>';
    }
    html += '<div class="n7h-vs ' + band + '">' + n7Esc_(vs) + '</div>';
    var kAttr = ' data-n7v="' + n7Esc_(String(c.value)) + '" data-n7dp="' + (DP[spec.id] || 0) + '" data-n7u="' + n7Esc_(UNIT[spec.id] || '') + '"';
    if (spec.pair && c2 && c2.value != null) kAttr += ' data-n7v2="' + n7Esc_(String(c2.value)) + '" data-n7dp2="' + (DP[spec.pair] || 0) + '"';
    var kEl = '<div class="n7h-k"' + kAttr + '>' + n7Esc_(valStr) + '</div>';
    if (!spec.pair && (UNIT[spec.id] === '%' || spec.id === 'farrowRate' || spec.id === 'mortPre')) {
      kEl = '<div class="n7h-kg">' + kEl + '<div class="n7h-gag st-' + band + '" data-n7g="' + n7Esc_(String(c.value)) + '" aria-hidden="true"></div></div>';
    }
    html += kEl;
    if (frac) html += '<div class="n7h-frac">' + frac + '</div>';
    html += '<div class="n7h-delta ' + dcls + '">' + n7Esc_(dtxt) + '</div>' + spark + '</div>';
    return html;
  }

  var MORT = [
    { id: 'mortPre', title: '포유' },
    { id: 'mortNursery', title: '이유 후' },
    { id: 'mortGrower', title: '육성' },
    { id: 'mortFinisher', title: '비육' }
  ];
  function mortHTML(m) {
    var c = card(m.id), isNotPorted = (c && c.notPorted) || /^(msy|mortNursery|mortGrower|mortFinisher)$/.test(m.id);
    var missing = !c || isNotPorted || c.value == null;
    var g = goalOf(m.id), band = missing ? 'none' : n7Band_(c.value, g && g.v, false);
    var label = missing ? (isNotPorted ? '현재 미지원' : '판단 불가') : (n7Num_(c.value, 1) + '%');
    var w = missing ? 0 : Math.min(100, Math.max(2, +c.value));
    return '<div class="n7h-mort"><div class="nm"><span>' + n7Esc_(m.title) + '</span><span class="n7h-vs ' + band + '">' + n7Esc_(label) + '</span></div><div class="n7h-bar ' + band + '"><span data-n7w="' + w + '" style="width:0"></span></div></div>';
  }

  var alerts = [];
  var fl = d.flagged, gh = 0;
  if (sows && sows.length) {
    sows.forEach(function (s) {
      if (!s.ghost) return;
      var st = String(s.state || '');
      if (st === '퇴출' || st.indexOf('후보') >= 0) return;
      gh++;
    });
  }
  if (typeof fl === 'number' && fl > 0) alerts.push({ title: '확인이 필요한 모돈이 있습니다', body: fl + '두 — 표시를 확인해 주세요', go: 'events', arg: { flagged: true }, bad: 0 });
  if (gh > 0) alerts.push({ title: '기록이 비어 있는 모돈이 있습니다', body: gh + '두', go: 'sows', arg: null, bad: 0 });
  var lateN = items.filter(function (x) { return x.overdue; }).length;
  if (!lateN && dueC.overdue) lateN = ['교배', '재발확인', '분만', '이유'].reduce(function (a, k) { return a + (dueC.overdue[k] || 0); }, 0);
  KPI.forEach(function (spec) {
    var c = card(spec.id);
    if (!c || c.notPorted || c.value == null) return;
    var g = goalOf(spec.id);
    if (n7Band_(c.value, g && g.v, !!HIB[spec.id]) === 'bad') {
      alerts.push({ title: n7Iga_(spec.title) + ' 목표보다 크게 벗어났습니다', body: '목표를 확인하거나 최근 기록을 살펴 보세요.', go: 'goals', arg: null, bad: 1 });
    }
  });
  if (d.paper) alerts.push({ title: '종이대장을 확인하세요', body: '', go: 'home', arg: null, bad: 0, paper: 1 });
  alerts = alerts.slice(0, 3);

  var TREND = [
    { id: 'psy', title: 'PSY' },
    { id: 'farrowRate', title: '분만율' },
    { id: 'weanPerLitter', title: '복당 이유' },
    { id: 'mortPre', title: '포유 폐사율' }
  ];
  function trendHTML(id) {
    var c = card(id);
    if (!c || !c.spark || !c.months) return '<div class="n7h-empty">그릴 자료가 없습니다</div>';
    var mx = 0;
    c.spark.forEach(function (x) { if (x != null && +x > mx) mx = +x; });
    return '<div class="n7h-bars">' + c.spark.map(function (x, i) {
      var hgt = (x == null || !mx) ? 2 : Math.max(2, Math.round((+x / mx) * 100));
      var mo = (c.months[i] || '').slice(5);
      var lab = (x == null) ? '—' : n7Num_(x, DP[id]);
      return '<div title="' + n7Esc_((c.months[i] || '') + ' ' + lab) + '"><b data-n7h="' + hgt + '" style="height:0"></b><em>' + n7Esc_(mo || '') + '</em></div>';
    }).join('') + '</div>';
  }

  var wsum = (h.work && h.work.summary) || {};
  var wn = (h.work && h.work.n) || 0;
  function wv(obj, k2) { return obj && obj[k2] != null ? obj[k2] : 0; }
  var pd = wv(wsum.pigletDeath, 'head'), ex = wv(wsum.sowExit, 'n');
  var foot = wn ? ('오늘 입력 ' + wn + '건' + (pd ? ' · 자돈 폐사 ' + pd + '두' : '') + (ex ? ' · 모돈 도폐사 ' + ex + '건' : '')) : '오늘 입력된 기록이 없습니다';
  var todayStr = (typeof window.today === 'function' ? window.today() : ((window.PL && PL._daily && PL._daily.today) || '')) || (h.today || '');
  var WORK_CHIPS = [
    ['교배', wv(wsum.service, 'n'), '교배'],
    ['임신감정', wv(wsum.preg, 'n'), '임신감정'],
    ['분만', wv(wsum.farrow, 'n'), '분만'],
    ['이유', wv(wsum.wean, 'n'), '이유'],
    ['자돈폐사', wv(wsum.pigletDeath, 'head'), '자돈 폐사', 1],
    ['도폐사', wv(wsum.sowExit, 'n'), '모돈 도폐사', 1],
    ['백신', wv(wsum.vacc, 'n'), '백신'],
    ['치료', wv(wsum.treat, 'n'), '치료']
  ];
  function workChipHTML(c) {
    var typ = c[0], n = c[1] || 0, lab = c[2], loss = c[3];
    return '<button type="button" class="n7h-wchip' + (n ? ' on' : ' zero') + (loss ? ' loss' : '') + '" data-wtyp="' + n7Esc_(typ) + '" data-wdate="' + n7Esc_(todayStr) + '"><b>' + n + '</b><span>' + n7Esc_(lab) + '</span></button>';
  }
  var workReady = !!(home && home.work && home.work.summary);
  var workBasis = (todayStr || todayIso || (h.today || '')).toString().slice(0, 10);
  var workSec = '<section class="n7h-sec n7h-sec-work"><h2>오늘 한 일</h2>' +
    (workBasis ? '<p class="mut n7h-work-basis">작업일 ' + n7Esc_(workBasis) + ' 기준 · 일보와 같음</p>' : '') +
    (workReady
      ? '<div class="n7h-work">' + WORK_CHIPS.map(workChipHTML).join('') + '</div>'
      : '<div class="n7h-work n7h-work-sk" aria-busy="true"><div class="sk" style="height:56px;border-radius:10px"></div></div>') +
    '</section>';

  var html = '<div id="n7h" class="n7h"><div class="n7h-hero"><div class="n7h-farm">' + n7Esc_(farmName) + '</div>'
    + (wk ? '<p class="n7h-week">' + n7Esc_(wk.year + '년 ' + wk.week + '주차 · ' + wk.fromMd + '~' + wk.toMd) + '</p>' : '')
    + '<p class="n7h-sum">' + n7Esc_(heroDate + (cnt('분만') || cnt('이유') ? ' · 이번 주 분만 예정 ' + cnt('분만') + '복 · 이유 예정 ' + cnt('이유') + '복' : '')) + '</p></div>'
    + '<section class="n7h-sec"><h2>오늘 할 일</h2><div class="n7h-todo">' + (rows.length ? rows.map(rowHTML).join('') : '<div class="n7h-empty">이번 주 예정이 없습니다</div>') + '</div></section>'
    + workSec
    + '<section class="n7h-sec"' + (alerts.length ? '' : ' hidden') + '><h2>확인 필요</h2><div id="n7h-al">'
    + alerts.map(function (a, i) { return '<div class="n7h-alert' + (a.bad ? ' bad' : '') + '" data-ai="' + i + '"><div class="bd"><div class="ti">' + n7Esc_(a.title) + '</div>' + (a.body ? '<div class="mt">' + n7Esc_(a.body) + '</div>' : '') + '</div><button type="button" class="btn sm">확인</button></div>'; }).join('')
    + '</div></section>'
    + '<section class="n7h-sec"><h2>주요 성적 <button type="button" class="btn sm sec" id="n7h-goals" style="float:right">목표 설정</button></h2><div class="n7h-kpis">' + KPI.map(kpiHTML).join('') + '</div></section>'
    + '<section class="n7h-sec"><h2>단계별 폐사율</h2><div class="n7h-morts">' + MORT.map(mortHTML).join('') + '</div></section>'
    + '<section class="n7h-sec n7h-trend"><h2>12개월 추이</h2><div class="n7h-tabs" id="n7h-tt">' + TREND.map(function (t, i) { return '<button type="button" class="btn sm' + (i ? ' sec' : '') + '" data-tid="' + t.id + '">' + n7Esc_(t.title) + '</button>'; }).join('') + '</div><div id="n7h-tr">' + trendHTML('psy') + '</div></section>'
    + '<div class="n7h-foot">' + n7Esc_(foot) + '</div></div>';
  el.innerHTML = html;

  el.querySelectorAll('.n7h-row').forEach(function (row) {
    function open() {
      var typ = row.getAttribute('data-typ'), kind = row.getAttribute('data-kind');
      if (row.getAttribute('data-old') === '1') { goPage('due', kind); return; }
      var list = items.filter(function (x) { return x.kind === kind && !!x.overdue === (row.getAttribute('data-late') === '1'); });
      var first = list[0];
      if (first && first.tag) goPage('entry', { type: typ, tag: first.tag });
      else goPage('due', kind);
    }
    row.onclick = open;
  });
  el.querySelectorAll('.n7h-wchip').forEach(function (b) {
    b.onclick = function (e) {
      e.preventDefault(); e.stopPropagation();
      var typ = b.getAttribute('data-wtyp') || '';
      var d = b.getAttribute('data-wdate') || todayStr;
      goPage('events', { from: d, to: d, type: typ });
    };
  });
  el.querySelectorAll('.n7h-alert').forEach(function (box, i) {
    var a = alerts[i];
    box.onclick = function () {
      if (a && a.paper && typeof paperModal === 'function') { paperModal(); return; }
      if (a && a.go && a.go !== 'home') goPage(a.go, a.arg);
    };
  });
  var gb = el.querySelector('#n7h-goals');
  if (gb) gb.onclick = function (e) { e.stopPropagation(); goPage('goals'); };
  el.querySelectorAll('.n7h-go').forEach(function (b) {
    b.onclick = function (e) { e.stopPropagation(); goPage(b.getAttribute('data-go') || 'entry'); };
  });
  var tabs = el.querySelector('#n7h-tt');
  if (tabs) tabs.onclick = function (e) {
    var b = e.target.closest('button[data-tid]'); if (!b) return;
    tabs.querySelectorAll('button').forEach(function (x) { x.className = 'btn sm sec'; });
    b.className = 'btn sm';
    var tr = el.querySelector('#n7h-tr');
    if (tr) { tr.innerHTML = trendHTML(b.getAttribute('data-tid')); if (typeof n7MotionDash_ === 'function') n7MotionDash_(tr); }
  };
  if (typeof n7MotionDash_ === 'function') n7MotionDash_(el);
}

function nov7DashMount_(el, goFn) {
  if (!el) return;
  el.innerHTML = '<div id="n7h" class="n7h"><div class="n7h-load">불러오는 중</div></div>';
  var left = 5, painted = 0, dash = null, home = (typeof PL !== 'undefined' && PL._pref && PL._pref.getHomeDash) || null, due = null, goals = null, sows = null;
  function tryPaint(early) {
    if (!el.isConnected || (PL._page && PL._page !== 'home' && PL._page !== 'dash')) return;
    if (!painted && !(home || dash || early)) return;
    if (!painted && !home && !dash && left > 0) return;
    painted = 1;
    try { nov7HomeV2_(el, dash, home, due, goals, goFn, sows); }
    catch (err) { el.innerHTML = (typeof errHTML === 'function' ? errHTML(err) : '<div class="n7-err">화면을 그리지 못했습니다</div>'); }
  }
  function one(p, set, early) {
    (p && p.then ? p : Promise.resolve(null)).then(function (r) { set(r); }).catch(function () { set(null); }).then(function () { left--; tryPaint(!!early || left === 0); });
  }
  if (home) tryPaint(true);
  one(typeof apiR === 'function' ? apiR('getDashboard') : null, function (r) { dash = r; }, true);
  one(typeof apiF === 'function' ? apiF('getHomeDash') : (typeof apiR === 'function' ? apiR('getHomeDash') : null), function (r) { if (r) home = r; }, true);
  one(typeof apiF === 'function' ? apiF('getDueList', {}) : null, function (r) { due = r; }, true);
  var yr = String((typeof window.today === 'function' ? window.today() : ((window.PL && PL._daily && PL._daily.today) || '')) || '').slice(0, 4);
  one(typeof apiF === 'function' ? apiF('getGoals', yr) : null, function (r) { goals = r; });
  var sowFn = (typeof apiR === 'function') ? apiR : apiF;
  setTimeout(function () {
    one(typeof sowFn === 'function' ? sowFn('listSows', { includeExited: false }) : null, function (r) {
      sows = (r && (r.items || r.sows || r.rows)) || [];
    });
  }, 80);
}

function nov7Picker_(data, onSave) {
  var cat = (data.catalog || []).filter(function (c) { return c.selectable; }), chosen = (data.ids || []).slice();
  var dlg = document.createElement('div'); dlg.className = 'nov7-pick'; dlg.setAttribute('role', 'dialog'); dlg.setAttribute('aria-label', 'KPI 설정');
  dlg.innerHTML = '<h2>KPI 설정</h2><p>표시할 KPI 10개를 선택하세요.</p><p id="nov7-cnt"></p><ol id="nov7-sel"></ol><div id="nov7-pool"></div><p><button type="button" class="btn" id="nov7-ok">저장</button> <button type="button" class="btn sec" id="nov7-no">닫기</button></p>';
  document.body.appendChild(dlg);
  function paint() {
    dlg.querySelector('#nov7-cnt').textContent = chosen.length + ' / 10';
    dlg.querySelector('#nov7-sel').innerHTML = chosen.map(function (id, i) { var hit = cat.filter(function (c) { return c.id === id; })[0]; return '<li><button type="button" data-up="' + i + '" aria-label="위로">위로</button> ' + nov7Esc_(hit ? hit.title : id) + ' <button type="button" data-rm="' + i + '">빼기</button></li>'; }).join('');
    dlg.querySelector('#nov7-pool').innerHTML = cat.map(function (c) { var on = chosen.indexOf(c.id) >= 0; return '<button type="button" data-add="' + nov7Esc_(c.id) + '"' + (on ? ' disabled' : '') + '>' + nov7Esc_(c.title) + '</button>'; }).join('');
    dlg.querySelector('#nov7-ok').disabled = chosen.length !== 10;
  }
  dlg.onclick = function (ev) {
    var t = ev.target;
    if (t.getAttribute('data-add') && chosen.length < 10 && chosen.indexOf(t.getAttribute('data-add')) < 0) { chosen.push(t.getAttribute('data-add')); paint(); }
    if (t.getAttribute('data-rm') != null && t.getAttribute('data-rm') !== '') { chosen.splice(Number(t.getAttribute('data-rm')), 1); paint(); }
    if (t.getAttribute('data-up') != null && t.getAttribute('data-up') !== '') { var i = Number(t.getAttribute('data-up')); if (i > 0) { var x = chosen[i - 1]; chosen[i - 1] = chosen[i]; chosen[i] = x; } paint(); }
  };
  dlg.querySelector('#nov7-no').onclick = function () { dlg.remove(); };
  dlg.querySelector('#nov7-ok').onclick = function () { if (chosen.length !== 10) return; dlg.remove(); onSave(chosen.slice()); };
  paint();
}
function pageCal(el) {
  var t = typeof today === 'function' ? today() : '', f = { from: t, to: t, assignee: '', barn: '', status: '' };
  el.innerHTML = '<div class="nov7-banner">예정과 실제 기록을 구분해 보여 줍니다. 작업자는 본인 담당만 보입니다.</div><div class="row" style="gap:8px;flex-wrap:wrap;margin-bottom:8px"><input class="f" type="date" id="cal-f" value="' + nov7Esc_(f.from) + '"><input class="f" type="date" id="cal-t" value="' + nov7Esc_(f.to) + '"><input class="f" id="cal-a" placeholder="담당자" aria-label="담당자"><input class="f" id="cal-b" placeholder="돈사" aria-label="돈사"><select class="f" id="cal-s" aria-label="상태"><option value="">상태 전체</option><option value="planned">예정</option><option value="in_progress">진행 중</option><option value="completed">완료</option><option value="overdue">지남</option><option value="cancelled">취소</option></select><button class="btn" id="cal-go" type="button">조회</button></div><div id="cal-bdy"></div>';
  var load = function () {
    f.from = $('#cal-f', el).value; f.to = $('#cal-t', el).value; f.assignee = $('#cal-a', el).value.trim(); f.barn = $('#cal-b', el).value.trim(); f.status = $('#cal-s', el).value;
    apiF('farmCalendar', f).then(function (r) {
      $('#cal-bdy', el).innerHTML = (r.items || []).map(function (it) {
        var st = { planned: '예정', in_progress: '진행 중', completed: '완료', overdue: '지남', cancelled: '취소' }[it.status] || it.status || '';
        return '<p>' + nov7Esc_(it.date) + ' · ' + nov7Esc_(it.title) + ' · ' + nov7Esc_(st) + (it.performed ? ' · 실제 기록' : '') + '</p>';
      }).join('') || '<p>이 기간의 일정이 없습니다.</p>';
    }).catch(function (e) { $('#cal-bdy', el).innerHTML = errHTML(e); });
  };
  $('#cal-go', el).onclick = load; load();
}
function n7FarmStamp_(iso) {
  if (!iso) return '';
  var ms = Date.parse(iso);
  if (!isFinite(ms)) {
    var s = String(iso);
    if (/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}/.test(s)) return s.slice(0, 16);
    return s;
  }
  var x = (typeof farmDT_ === 'function') ? farmDT_(ms) : null;
  return x ? (x.d + ' ' + x.hm) : String(iso);
}
function pageMsg(el) {
  el.innerHTML = '<div class="nov7-banner">같은 농장 사람과만 대화합니다. 보낸 지 7일이 지난 글은 열 수 없습니다. 푸시와 외부 번역은 꺼져 있습니다.</div><div class="row" style="gap:8px;margin-bottom:8px;flex-wrap:wrap"><label class="row"><input type="checkbox" id="msg-on" checked> 알림</label><label class="row"><input type="checkbox" id="msg-snd"> 알림 소리</label><button type="button" class="btn sec" id="msg-unlock">소리 켜기</button><button type="button" class="btn sec" id="msg-dnd-btn">방해금지 시각</button><input id="msg-dnd" type="datetime-local" aria-label="방해금지 해제 시각" hidden><span class="mut" id="msg-dnd-lab"></span></div><div id="msg-host"></div>';
  var prefs = nov7Prefs_(), unlocked = false, seen = {};
  $('#msg-on', el).checked = prefs.enabled !== false; $('#msg-snd', el).checked = !!prefs.sound;
  function saveP() { prefs = { enabled: $('#msg-on', el).checked, sound: $('#msg-snd', el).checked, dndUntil: $('#msg-dnd', el).value ? new Date($('#msg-dnd', el).value).toISOString() : '' }; nov7PrefsSet_(prefs); }
  $('#msg-on', el).onchange = saveP; $('#msg-snd', el).onchange = saveP;
  var dnd = $('#msg-dnd', el), dndBtn = $('#msg-dnd-btn', el), dndLab = $('#msg-dnd-lab', el);
  function dndShow(on) {
    if (dnd) dnd.hidden = !on;
    if (dndBtn) dndBtn.hidden = !!on;
    if (dndLab) {
      var v = dnd && dnd.value;
      dndLab.textContent = v ? ('해제: ' + (typeof n7FarmStamp_ === 'function' ? n7FarmStamp_(new Date(v).toISOString()) : String(v).replace('T', ' '))) : '';
    }
  }
  if (prefs.dndUntil && dnd) {
    try {
      var dx = new Date(prefs.dndUntil);
      if (!isNaN(dx.getTime())) {
        var p = (typeof farmDT_ === 'function') ? farmDT_(dx.getTime()) : null;
        dnd.value = (p && p.d && p.hm) ? (p.d + 'T' + p.hm) : dx.toISOString().slice(0, 16);
      }
    } catch (e0) {}
  }
  dndShow(!!(dnd && dnd.value));
  if (dndBtn) dndBtn.onclick = function () { dndShow(true); if (dnd) dnd.focus(); };
  if (dnd) dnd.onchange = function () { saveP(); dndShow(!!dnd.value); };
  $('#msg-unlock', el).onclick = function () { unlocked = true; try { var a = new Audio('data:audio/wav;base64,UklGRiQAAABXQVZFZm10IBAAAAABAAEAQB8AAEAfAAABAAgAZGF0YQAAAAA='); a.play().catch(function () {}); } catch (e) {} };
  var box = { items: [], open: '', filter: 'all', staff: [] };
  function canWoUser_() {
    try {
      return (typeof isOwner === 'function' && isOwner()) || (typeof isFarmMgr === 'function' && isFarmMgr()) || (PL.user && (PL.user.role === '농장주' || PL.user.role === '운영자' || PL.user.role === '관리자' || PL.user.role === '농장 관리자' || PL.user.role === '부관리자'));
    } catch (e) { return !!(PL.user && (PL.user.role === '농장주' || PL.user.role === '관리자')); }
  }
  function staffId_(s) { return (s && (s.id || s.login_id || s.login || s.show)) || ''; }
  function staffLab_(s) {
    var id = staffId_(s), nm = (s && (s.name || s.show)) || id, g = (s && s.grade) || '';
    return nm + (g ? (' · ' + g) : '') + (id && id !== nm ? (' (' + id + ')') : '');
  }

  function draw() {
    var items = box.items || [], me = PL.user && PL.user.id || '';
    if (box.filter === 'open') items = items.filter(function (m) { return m.kind === 'instruction' && !m.taskDone; });
    else if (box.filter === 'done') items = items.filter(function (m) { return m.kind === 'instruction' && m.taskDone; });
    var threads = {}; items.forEach(function (m) { var key = m.peer || m.sender; if (!threads[key]) threads[key] = []; threads[key].push(m); });
    var keys = Object.keys(threads); if (!box.open) box.open = keys[0] || '';
    var list = keys.map(function (k) { var last = threads[k][threads[k].length - 1], n = threads[k].filter(function (m) { return !m.mine && !m.read && !m.expired; }).length; return '<button type="button" data-conv="' + nov7Esc_(k) + '"><span>' + nov7Esc_(k) + '</span>' + (n ? '<b class="msg-badge">' + n + '</b>' : '') + '<small style="display:block">' + nov7Esc_(last.display || last.body || (last.expired ? '기간이 지난 메시지' : '')) + '</small></button>'; }).join('') || '<p>대화가 없습니다.</p>';
    var thread = (threads[box.open] || []).map(function (m) {
      var quote = m.parentExpired ? '<q>기간이 지난 메시지</q>' : '';
      var tr = m.trStatus === 'failed' ? '<span>번역 실패. 원문을 표시합니다.</span>' : (m.showOriginal ? '<button type="button" data-orig="' + nov7Esc_(m.id) + '">원문</button>' : '');
      var woTag = m.kind === 'instruction' ? '<span class="badge">작업지시</span> ' : '';
      if (m.kind === 'instruction' && m.taskAcked) woTag += '<span class="badge">받음</span> ';
      if (m.kind === 'instruction' && m.taskDone) woTag += '<span class="badge">완료</span> ';
      var meId = (PL.user && (PL.user.id || PL.user.login_id)) || '';
      var canAct = m.kind === 'instruction' && !m.taskDone && (m.assignee === meId || (!m.mine && m.kind === 'instruction'));
      var hist = '';
      if (m.kind === 'instruction') {
        var rows = [];
        rows.push('지시 · ' + nov7Esc_(m.sender || '') + (m.due ? (' · 기한 ' + nov7Esc_(String(m.due).slice(0, 10))) : ''));
        (m.history || []).forEach(function (h) {
          var lab = h.action === 'ack' || h.action === '받음' ? '받음' : (h.action === 'done' || h.action === '완료' ? '완료' : (h.action || ''));
          rows.push(nov7Esc_(lab) + ' · ' + nov7Esc_(h.by || '') + (h.at ? (' · ' + nov7Esc_(String(h.at).replace('T', ' ').slice(0, 16))) : '') + (h.note ? (' · ' + nov7Esc_(h.note)) : ''));
        });
        if (!m.history || !m.history.length) {
          if (m.taskAcked) rows.push('받음' + (m.ackBy ? (' · ' + nov7Esc_(m.ackBy)) : '') + (m.ackNote ? (' · ' + nov7Esc_(m.ackNote)) : ''));
          if (m.taskDone) rows.push('완료' + (m.doneBy ? (' · ' + nov7Esc_(m.doneBy)) : '') + (m.doneNote ? (' · ' + nov7Esc_(m.doneNote)) : ''));
        }
        hist = '<ol class="n7-wo-hist">' + rows.map(function (x) { return '<li>' + x + '</li>'; }).join('') + '</ol>';
      }
      var acts = '';
      if (canAct) {
        acts = '<div class="n7-wo-acts"><input type="text" maxlength="200" data-wonote="' + nov7Esc_(m.id) + '" placeholder="메모 (선택)" aria-label="작업지시 메모">'
          + (m.taskAcked ? '' : '<button type="button" class="btn sec" data-ack="' + nov7Esc_(m.id) + '">받음</button>')
          + '<button type="button" class="btn" data-done="' + nov7Esc_(m.id) + '">완료</button></div>';
      } else if (m.kind === 'instruction' && m.taskDone) {
        acts = '<span class="mut">완료됨</span>';
      }
      return '<div class="bubble ' + (m.mine ? 'out' : 'in') + '" data-id="' + nov7Esc_(m.id) + '">' + quote + '<p class="who">' + woTag + nov7Esc_(m.sender) + ' · ' + nov7Esc_(n7FarmStamp_(m.sentAt || '')) + '</p><p class="txt">' + nov7Esc_(m._showOrig ? m.original || m.body : (m.display || m.body)) + '</p>' + tr + '<p class="st">' + (m.read ? '읽음' : '안 읽음') + (m.taskAcked ? ' · 받음' : '') + (m.taskDone ? ' · 완료' : '') + '</p>' + hist + acts + '</div>';
    }).join('');
    var canWo = canWoUser_();
    var woToday = (typeof today === 'function' ? today() : '') || '';
    var filt = box.filter || 'all';
    var filterBar = '<div class="n7-wo-bar" id="n7-wo-bar">'
      + '<button type="button" class="btn sm' + (filt === 'all' ? '' : ' sec') + '" data-wof="all">전체</button>'
      + '<button type="button" class="btn sm' + (filt === 'open' ? '' : ' sec') + '" data-wof="open">미완료</button>'
      + '<button type="button" class="btn sm' + (filt === 'done' ? '' : ' sec') + '" data-wof="done">완료</button>'
      + '</div>';
    var staffHtml = (box.staff || []).map(function (s) {
      if (!s || s.active === false || s.quit) return '';
      var id = staffId_(s); if (!id) return '';
      return '<option value="' + nov7Esc_(id) + '">' + nov7Esc_(staffLab_(s)) + '</option>';
    }).join('');
    var woForm = canWo ? ('<div class="n7-wo-send" id="n7-wo-send"><h3>작업지시 보내기</h3>'
      + '<div><label class="l" for="msg-wo-to">담당자</label><select id="msg-wo-to"><option value="">담당자 고르기</option>' + staffHtml + '</select></div>'
      + '<div><label class="l" for="msg-wo-d">완료 기한</label><input type="date" id="msg-wo-d" value="' + nov7Esc_(woToday) + '"></div>'
      + '<div style="grid-column:1/-1"><label class="l" for="msg-wo-text">할 일</label><textarea id="msg-wo-text" maxlength="200" rows="2" placeholder="할 일을 적으세요"></textarea></div>'
      + '<div class="n7-wo-send-btn"><button type="button" class="btn" id="msg-wo-send">작업지시 보내기</button></div></div>') : '';
    var back = box.open ? '<div class="n7-msg-back"><button type="button" class="btn sec sm" id="n7-msg-back">대화 목록</button><strong>' + nov7Esc_(box.open) + '</strong></div>' : '';
    var emptyThread = thread ? thread : '<p class="mut" style="text-align:center;margin:auto;padding:24px">새 메시지가 없습니다.</p>';
    $('#msg-host', el).innerHTML = filterBar + '<div class="msg-app' + (box.open ? ' n7-msg-open' : '') + '"><aside class="msg-list" aria-label="대화">' + list + '</aside><div class="msg-room">' + back + '<div class="msg-log" id="msg-log">' + emptyThread + '</div><form class="msg-compose" id="msg-form"><input name="to" aria-label="받는 아이디" placeholder="받는 아이디" autocomplete="off"><input name="text" aria-label="메시지" autocomplete="off" placeholder="메시지">'
      + '<button class="btn" type="submit">보내기</button></form></div></div>' + woForm + '<p class="nov7-note">안 읽은 개수는 이 화면 기준입니다. 잠금화면 알림은 아직 오지 않습니다. 푸시는 꺼져 있습니다.</p>';
    var log = $('#msg-log', el); if (log) log.scrollTop = log.scrollHeight;
    $$('[data-conv]', el).forEach(function (b) { b.onclick = function () { box.open = b.getAttribute('data-conv'); draw(); }; });
    var backBtn = el.querySelector('#n7-msg-back');
    if (backBtn) backBtn.onclick = function () { box.open = ''; draw(); };
    $$('[data-wof]', el).forEach(function (b) { b.onclick = function () { box.filter = b.getAttribute('data-wof') || 'all'; draw(); }; });
    var woSend = el.querySelector('#msg-wo-send');
    if (woSend) woSend.onclick = function () {
      var toEl = el.querySelector('#msg-wo-to'), dEl = el.querySelector('#msg-wo-d'), tEl = el.querySelector('#msg-wo-text');
      var to = toEl ? String(toEl.value || '').trim() : '';
      var due = dEl ? String(dEl.value || '').trim() : '';
      var text = tEl ? String(tEl.value || '').trim() : '';
      var miss = [];
      if (!to) miss.push('담당자');
      if (!due) miss.push('완료 기한');
      if (!text) miss.push('할 일');
      if (miss.length) { if (typeof toast === 'function') toast('비어 있는 항목: ' + miss.join(', ')); return; }
      woSend.disabled = true;
      apiF('msgSend', { body: text, to: [to], kind: 'instruction', approve: true, date: due, assignee: to, reqId: (typeof uuid === 'function' ? uuid() : String(Date.now())) }).then(function (r) {
        woSend.disabled = false;
        if (r && r.needsConfirm) { toast('작업지시는 받는 사람과 기한이 필요합니다'); return; }
        if (r && r.needsApproval && !r.written) { toast('작업지시가 저장되지 않았습니다'); return; }
        if (tEl) tEl.value = '';
        if (typeof toast === 'function') toast('작업지시를 보냈습니다');
        box.open = to;
        load();
      }).catch(function (e) { woSend.disabled = false; toast(typeof uiMsg === 'function' ? uiMsg(e) : String(e && e.message || e)); });
    };
    $$('[data-orig]', el).forEach(function (b) { b.onclick = function () { var id = b.getAttribute('data-orig'); items.forEach(function (m) { if (m.id === id) m._showOrig = !m._showOrig; }); draw(); }; });
    function woNote(id) {
      var inp = el.querySelector('[data-wonote="' + id + '"]');
      return inp ? String(inp.value || '').trim() : '';
    }
    function woAct(id, action) {
      var body = { action: action, note: woNote(id) };
      var call = (typeof apiF === 'function' && apiF('msgTaskStatus', id, body)) || Promise.reject(new Error('no api'));
      call.then(load).catch(function () {
        if (action === 'done' && typeof apiF === 'function') return apiF('msgTaskDone', id).then(load);
        throw new Error('작업지시 상태를 남기지 못했습니다');
      }).catch(function (e) { toast(typeof uiMsg === 'function' ? uiMsg(e) : String(e && e.message || e)); });
    }
    $$('[data-ack]', el).forEach(function (b) { b.onclick = function () { woAct(b.getAttribute('data-ack'), 'ack'); }; });
    $$('[data-done]', el).forEach(function (b) { b.onclick = function () { woAct(b.getAttribute('data-done'), 'done'); }; });
    var form = $('#msg-form', el);
    var woEl = form && form.querySelector('#msg-wo');
    var woD = form && form.querySelector('#msg-wo-d');
    if (woEl && woD) woEl.onchange = function () { woD.hidden = !woEl.checked; };
    if (form) form.onsubmit = function (ev) {
      ev.preventDefault();
      var text = form.text.value.trim(); if (!text) return;
      var who = form.to && form.to.value.trim();
      var peer = (threads[box.open] || [])[0];
      var to = who ? [who] : (peer ? [peer.peer || peer.sender] : []);
      if (!to.length || !to[0]) { toast('받는 아이디를 입력하세요'); return; }
      var body = { body: text, to: to, replyTo: !who && peer ? peer.id : '', reqId: (typeof uuid === 'function' ? uuid() : String(Date.now())) };
      if (woEl && woEl.checked) {
        if (!woD || !woD.value) { toast('작업지시 기한을 선택하세요'); return; }
        body.kind = 'instruction'; body.approve = true; body.date = woD.value; body.assignee = to[0];
      }
      var btn = form.querySelector('[type=submit]'); if (btn) btn.disabled = true;
      apiF('msgSend', body).then(function (r) {
        if (btn) btn.disabled = false;
        if (r && r.needsConfirm) { toast('작업지시는 받는 사람과 기한이 필요합니다'); return; }
        if (r && r.needsApproval && !r.written) { toast('작업지시가 저장되지 않았습니다'); return; }
        form.text.value = ''; load();
      }).catch(function (e) { if (btn) btn.disabled = false; toast(uiMsg(e)); });
    };
  }
  function load() {
    var staffP = canWoUser_() ? apiF('ownerListStaff').then(function (r) {
      box.staff = Array.isArray(r) ? r : ((r && (r.items || r.staff || r.list || r.rows)) || []);
    }).catch(function () { box.staff = box.staff || []; }) : Promise.resolve();
    staffP.then(function () { return apiF('msgList'); }).then(function (r) {
      var prev = {}; (box.items || []).forEach(function (m) { prev[m.id] = 1; });
      box.items = r.items || [];
      (r.items || []).forEach(function (m) {
        if (prev[m.id] || seen[m.id]) return;
        var d = nov7Decide_({ loggedIn: !!PL.token, me: PL.user && PL.user.id, farm: PL.farmId, prefs: nov7Prefs_(), soundUnlocked: unlocked, seen: seen, msg: m });
        if (d.badge) seen[m.id] = 1;
        if (d.toast) nov7Toast_('새 메시지가 있습니다');
        if (d.sound) { try { var a = new Audio('data:audio/wav;base64,UklGRiQAAABXQVZFZm10IBAAAAABAAEAQB8AAEAfAAABAAgAZGF0YQAAAAA='); var p = a.play(); if (p && p.catch) p.catch(function () {}); } catch (e) {} }
      });
      draw();
    }).catch(function (e) { $('#msg-host', el).innerHTML = errHTML(e); });
  }
  load();
}
function nov7AiNote_(r) {
  var bits = [];
  if (r.external === 'off' || r.external === 'blocked') bits.push('외부로 보내지 않습니다.');
  else if (r.external) bits.push(String(r.external));
  if (typeof r.breeding === 'number') bits.push('교배 기록 ' + r.breeding + '건.');
  if (typeof r.written === 'number') bits.push('저장 표시 ' + r.written + '.');
  else if (r.written === true) bits.push('기록을 저장했습니다.');
  else bits.push('기록은 저장하지 않았습니다.');
  return bits.join(' ');
}
function n7LoadAi_(cb) { if (window.PiglogAI) return cb();
  var cfg = (window.PIGLOG_SUPA || {}).n7ai || {};
  if (!cfg.js) { if (typeof toast === 'function') toast('PIGLOG AI를 아직 불러오지 못했습니다'); return; }
  var l = document.createElement('link'); l.rel = 'stylesheet'; l.href = cfg.css; document.head.appendChild(l);
  var s = document.createElement('script'); s.src = cfg.js; s.onload = cb; s.onerror = function () { if (typeof toast === 'function') toast('PIGLOG AI를 불러오지 못했습니다'); }; document.head.appendChild(s); }
function pageAi(el) {
  if (!nov7CanAi_(PL.user, PL.view)) { if (el) el.innerHTML = '<p>AI는 로그인한 뒤 사용할 수 있습니다.</p>'; return; }
  if (typeof n7AiOpen_ === 'function') n7AiOpen_();
}

function n7ScoreLoad_(cb) {
  if (window.PiglogScore) { if (cb) cb(); return; }
  var cfg = (window.PIGLOG_SUPA || {}).n7score || {};
  if (!cfg.js) { if (cb) cb(); return; }
  var l = document.createElement('link'); l.rel = 'stylesheet'; l.href = cfg.css; document.head.appendChild(l);
  var s = document.createElement('script'); s.src = cfg.js; s.onload = function () { if (window.PiglogScore && PiglogScore.install) PiglogScore.install(); if (cb) cb(); };
  s.onerror = function () { if (cb) cb(); };
  document.head.appendChild(s);
}
function n7SowcardLoad_(cb) {
  if (window.PiglogSowcard) { if (cb) cb(); return; }
  var cfg = (window.PIGLOG_SUPA || {}).n7sowcard || {};
  if (!cfg.js) { if (cb) cb(); return; }
  var l = document.createElement('link'); l.rel = 'stylesheet'; l.href = cfg.css; document.head.appendChild(l);
  var s = document.createElement('script'); s.src = cfg.js; s.onload = function () { if (window.PiglogSowcard && PiglogSowcard.install) PiglogSowcard.install(); if (cb) cb(); };
  s.onerror = function () { if (cb) cb(); };
  document.head.appendChild(s);
}
function n7T521Load_(cb) {
  if (window.PiglogT521) { if (cb) cb(); return; }
  var cfg = (window.PIGLOG_SUPA || {}).n7t521 || {};
  if (!cfg.js) { if (cb) cb(); return; }
  var l = document.createElement('link'); l.rel = 'stylesheet'; l.href = cfg.css; document.head.appendChild(l);
  var s = document.createElement('script'); s.src = cfg.js; s.onload = function () { if (window.PiglogT521 && PiglogT521.install) PiglogT521.install(); if (cb) cb(); };
  s.onerror = function () { if (cb) cb(); };
  document.head.appendChild(s);
}
function n7FarmsetLoad_(cb) {
  if (window.PiglogFarmSet) { if (cb) cb(); return; }
  var cfg = (window.PIGLOG_SUPA || {}).n7farmset || {};
  if (!cfg.js) { if (cb) cb(); return; }
  var l = document.createElement('link'); l.rel = 'stylesheet'; l.href = cfg.css; document.head.appendChild(l);
  var s = document.createElement('script'); s.src = cfg.js; s.onload = function () { if (window.PiglogFarmSet && PiglogFarmSet.install) PiglogFarmSet.install(); if (cb) cb(); };
  s.onerror = function () { if (cb) cb(); };
  document.head.appendChild(s);
}
function n7SowsearchLoad_(cb) {
  if (window.PiglogSowSearch) { if (cb) cb(); return; }
  var cfg = (window.PIGLOG_SUPA || {}).n7sowsearch || {};
  if (!cfg.js) { if (cb) cb(); return; }
  var l = document.createElement('link'); l.rel = 'stylesheet'; l.href = cfg.css; document.head.appendChild(l);
  var s = document.createElement('script'); s.src = cfg.js; s.onload = function () { if (window.PiglogSowSearch && PiglogSowSearch.install) PiglogSowSearch.install(); if (cb) cb(); };
  s.onerror = function () { if (cb) cb(); };
  document.head.appendChild(s);
}

function n7T524Load_(cb) {
  if (window.PiglogT524) { try { PiglogT524.install(); } catch (e) {} if (cb) cb(); return; }
  var cfg = (window.PIGLOG_SUPA || {}).n7t524 || {};
  if (!cfg.js) { if (cb) cb(); return; }
  if (cfg.css && !document.getElementById('n7t524-css')) {
    var l = document.createElement('link'); l.id = 'n7t524-css'; l.rel = 'stylesheet'; l.href = cfg.css; document.head.appendChild(l);
  }
  var s = document.createElement('script'); s.src = cfg.js; s.onload = function () { try { if (window.PiglogT524) PiglogT524.install(); } catch (e2) {} if (cb) cb(); };
  s.onerror = function () { if (cb) cb(); };
  document.head.appendChild(s);
}
function nov7Chrome_() {
  n7ScoreLoad_(function () { n7SowsearchLoad_(); }); n7SowcardLoad_(); n7FarmsetLoad_(); n7T521Load_(); n7T524Load_();
  var old = document.getElementById('nov7-fab'); if (old) old.remove();
  var stale = document.getElementById('nov7-ai'); if (stale) stale.remove();
  if (typeof n7ViewMark_ === 'function') n7ViewMark_();
  if (!nov7CanAi_(PL.user, PL.view)) return;
  var b = document.createElement('button'); b.id = 'nov7-fab'; b.type = 'button'; b.className = 'nov7-fab'; b.textContent = 'PIGLOG AI';
  b.setAttribute('aria-label', 'PIGLOG AI');
  b.onclick = function () { var r = document.getElementById('pai-root'); if (r) n7AiClose_(false); else n7AiOpen_(); };
  document.body.appendChild(b);
}
var NOV7_NAMES_DEV = false;
function nov7Syl_(s) {
  var t = String(s == null ? '' : s); if (typeof t.normalize === 'function') t = t.normalize('NFC');
  var n = 0, i; for (i = 0; i < t.length; i++) { var c = t.charCodeAt(i); if (c >= 0xAC00 && c <= 0xD7A3) n++; else return -1; } return n;
}
function nov7PrepareNames_(pack) {
  var empty = { ok: false, reason: 'load', production_ready: false, release_status: '', sow: [], boar: [], dropped: { sow: 0, boar: 0 }, kept: { sow: 0, boar: 0 } };
  try {
    if (!pack || typeof pack !== 'object' || !Array.isArray(pack.sow) || !Array.isArray(pack.boar)) return empty;
    function take(arr, sex) {
      var out = [], seen = {}, drop = 0;
      arr.forEach(function (row) {
        var name = typeof row === 'string' ? row : (row && row.name_ko), sx = typeof row === 'string' ? sex : (row && row.source_sex);
        if (sx !== sex) { drop++; return; }
        var t = String(name == null ? '' : name); if (typeof t.normalize === 'function') t = t.normalize('NFC');
        var syl = nov7Syl_(t); if (syl < 1 || syl > 4 || seen[t]) { drop++; return; }
        seen[t] = 1; out.push(t);
      });
      return { list: out, drop: drop };
    }
    var sow = take(pack.sow, 'F'), boar = take(pack.boar, 'M'), status = String(pack.release_status || '');
    return { ok: true, reason: '', version: String(pack.version || ''), release_status: status, production_ready: status === 'approved' && pack.production_ready === true, sow: sow.list, boar: boar.list, dropped: { sow: sow.drop, boar: boar.drop }, kept: { sow: sow.list.length, boar: boar.list.length } };
  } catch (e) { return empty; }
}
function nov7NamesLive_(cat) {
  if (cat && cat.production_ready === true && cat.release_status === 'approved') return true;
  if (NOV7_NAMES_DEV === true) return true;
  try { if (typeof location !== 'undefined' && /(?:^|[?&])nov7names=dev(?:&|$)/.test(location.search || '')) return true; } catch (e) {}
  try { if (typeof window !== 'undefined' && window.PIGLOG_SUPA && window.PIGLOG_SUPA.mode === 'local') return true; } catch (e2) {}
  return false;
}
function nov7SuggestName_(cat, kind, taken, rng) {
  if (!cat || cat.ok === false || !cat.sow || !cat.boar) return { ok: false, saved: false, mutated: false, reason: (cat && cat.reason) || 'load', name: '' };
  if (!nov7NamesLive_(cat)) return { ok: false, saved: false, mutated: false, reason: 'review', name: '' };
  var boar = kind === 'boar' || kind === 'male', pool = boar ? cat.boar : cat.sow, block = {};
  (taken || []).forEach(function (n) { if (n) block[String(n).replace(/\s+/g, '')] = 1; });
  var open = pool.filter(function (n) { return !block[n]; }), duplicate = false;
  if (!open.length) { if (!pool.length) return { ok: false, saved: false, mutated: false, reason: 'empty', name: '' }; open = pool.slice(); duplicate = true; }
  var r = rng ? Number(rng()) : Math.random(); if (!(r >= 0) || r >= 1) r = 0;
  var i = Math.floor(r * open.length); if (i >= open.length) i = open.length - 1;
  return { ok: true, saved: false, mutated: false, duplicate: duplicate, reason: '', name: open[i], pool: boar ? 'boar' : 'sow', review: cat.production_ready !== true };
}
function nov7NameCat_() { return nov7PrepareNames_(typeof NOV7_NAME_PACK === 'undefined' ? null : NOV7_NAME_PACK); }
function nov7NameNote_(sug) {
  return '';
}
function nov7AttachName_(input, opt) {
  opt = opt || {}; if (!input || input.getAttribute('data-named')) return; input.setAttribute('data-named', '1');
  var btn = document.createElement('button'); btn.type = 'button'; btn.className = 'btn sec nov7-rand'; btn.textContent = '랜덤 이름';
  var note = document.createElement('p'); note.className = 'nov7-note nov7-name-note'; note.hidden = true;
  input.parentNode.insertBefore(btn, input.nextSibling); btn.parentNode.insertBefore(note, btn.nextSibling);
  btn.onclick = function () {
    var cat = nov7NameCat_(), cur = input.value.trim();
    var sug = nov7SuggestName_(cat, opt.sex || opt.kind || 'sow', opt.taken || [], opt.rng);
    if (!sug.ok) return;
    if (cur && !window.confirm('입력칸의 애칭을 바꿀까요? 저장을 누르기 전까지 기록은 바뀌지 않습니다.')) return;
    input.value = sug.name; input.setAttribute('data-d', '1'); input.dispatchEvent(new Event('input', { bubbles: true }));
    btn.textContent = '다른 이름';
  };
  nov7FoldNickInput_(input, btn);
}
function nov7BindNick_(el, c) {
  var box = el.querySelector('.sc-nick'); if (!box || !c || !c.found) return;
  var nick = String(c.nickname || '').trim();
  function head() {
    var no = el.querySelector('.sowhead .no');
    if (!no) return;
    Array.prototype.forEach.call(el.querySelectorAll('.sowhead .nick-name, .sowhead .n7-sow-nick'), function (n) { n.remove(); });
    if (!nick) return;
    if (typeof sowNickH_ === 'function') no.insertAdjacentHTML('afterend', sowNickH_({ tag: c.tag, nickname: nick }));
    else { var s = document.createElement('span'); s.className = 'nick-name'; s.setAttribute('data-noi18n', ''); s.textContent = nick; no.insertAdjacentElement('afterend', s); }
  }
  function paint(open) {
    head();
    var label = nick ? '애칭 변경' : '애칭 추가';
    box.innerHTML = '<div class="nick-fold">' + (nick ? '' : '<span class="mut">애칭 미등록</span>') + '<button type="button" class="nick-toggle" data-nick-toggle aria-expanded="' + (open ? 'true' : 'false') + '">' + label + (open ? ' ▴' : ' ▾') + '</button></div>'
      + (open ? '<div class="nick-edit"><input class="f" data-nick-draft maxlength="40" placeholder="직접 입력" value="' + nov7Esc_(nick) + '"><div class="row"><button type="button" class="btn sec nov7-rand" data-nick-rand>랜덤 이름</button><button type="button" class="btn" data-nick-save>저장</button><button type="button" class="btn sec" data-nick-cancel>취소</button><button type="button" class="nick-toggle" data-nick-info aria-label="애칭 안내">ⓘ</button></div><p class="nov7-note nick-info" data-nick-note hidden></p></div>' : '');
    box.querySelector('[data-nick-toggle]').onclick = function () { paint(!open); };
    if (!open) return;
    var draft = box.querySelector('[data-nick-draft]'), note = box.querySelector('[data-nick-note]'), cat0 = nov7NameCat_();
    note.textContent = nov7NameNote_({ reason: nov7NamesLive_(cat0) ? '' : 'review', review: !(cat0 && cat0.production_ready) });
    box.querySelector('[data-nick-info]').onclick = function () { note.hidden = !note.hidden; };
    box.querySelector('[data-nick-rand]').onclick = function () {
      var sug = nov7SuggestName_(nov7NameCat_(), 'sow', [], null), cur = draft.value.trim();
      if (!sug.ok) { note.hidden = false; note.textContent = nov7NameNote_(sug); return; }
      if (cur && !window.confirm('입력칸의 애칭을 바꿀까요? 저장을 누르기 전까지 기록은 바뀌지 않습니다.')) return;
      draft.value = sug.name; this.textContent = '다른 이름'; note.hidden = false; note.textContent = nov7NameNote_(sug);
    };
    box.querySelector('[data-nick-cancel]').onclick = function () { paint(false); };
    box.querySelector('[data-nick-save]').onclick = function () {
      var btn = this; if (btn.disabled) return; btn.disabled = true;
      apiF('setAnimalNickname', 'sow', c.id, draft.value, (typeof uuid === 'function' ? uuid() : String(Date.now()))).then(function (r) {
        nick = String(r && r.nickname != null ? r.nickname : draft.value).trim(); c.nickname = nick;
        if (typeof toast === 'function') toast(r && r.sameName ? '같은 애칭이 있습니다. 번호는 바꾸지 않았습니다.' : '애칭을 저장했습니다');
        paint(false);
      }).catch(function (e) { btn.disabled = false; if (typeof toast === 'function') toast(typeof uiMsg === 'function' ? uiMsg(e) : e); });
    };
    draft.focus();
  }
  paint(false);
}
function nov7MountBoarNick_(el) {
  var inp = el.querySelector('[data-k="웅돈"]'); if (!inp || el.querySelector('.nov7-boar-nick')) return;
  var box = document.createElement('div'); box.className = 'nov7-boar-nick'; inp.parentNode.insertBefore(box, inp.nextSibling);
  var drawn = '';
  function draw() {
    var tag = inp.value.trim(); if (tag === drawn && box.querySelector('[data-boar-draft]')) return; drawn = tag;
    var rows = (window.PL && PL.boot && PL.boot.boars) || [], b = rows.filter(function (x) { return x.tag === tag; })[0];
    if (!b) { box.innerHTML = ''; return; }
    var openB = !!(b.nickname && String(b.nickname).trim());
    box.innerHTML = '<div class="ef-nick-fold"><a href="#" data-boar-toggle>' + (openB ? '애칭 숨기기' : '애칭 추가') + '</a></div><div data-boar-edit' + (openB ? '' : ' hidden') + '><input class="f" data-boar-draft maxlength="40" placeholder="직접 입력" value="' + nov7Esc_(b.nickname || '') + '"><button type="button" class="btn sec" data-boar-save>애칭 저장</button></div>';
    box.querySelector('[data-boar-toggle]').onclick = function (ev) { ev.preventDefault(); var ed = box.querySelector('[data-boar-edit]'); ed.hidden = !ed.hidden; this.textContent = ed.hidden ? '애칭 추가' : '애칭 숨기기'; };
    var draft = box.querySelector('[data-boar-draft]');
    nov7AttachName_(draft, { kind: 'boar', sex: 'boar', taken: rows.map(function (x) { return x.nickname || ''; }).filter(Boolean) });
    box.querySelector('[data-boar-save]').onclick = function () {
      apiF('setAnimalNickname', 'boar', b.id, draft.value, (typeof uuid === 'function' ? uuid() : String(Date.now()))).then(function (r) {
        b.nickname = r.nickname || ''; if (typeof toast === 'function') toast(r && r.sameName ? '같은 애칭이 있습니다. 웅돈번호는 그대로입니다.' : '애칭을 저장했습니다'); drawn = ''; draw();
      }).catch(function (e) { if (typeof toast === 'function') toast(uiMsg(e)); });
    };
  }
  inp.addEventListener('input', function () { draw(); });
  inp.addEventListener('change', function () { drawn = ''; draw(); }); draw();
}
function boarHouseOn_(){var L=(PL.boot&&PL.boot.locs)||[];return L.some(function(x){var k=String(x['돈사종류']||''),n=String(x['이름']||''),c=Number(x['수용두수']||0)+Number(x['스톨수']||0);return (k==='boar'||n.indexOf('웅돈')>=0)&&c>0;});}
function boarPageOk_(){return !!(PL.user&&PL.user.role!=='수의사');}
function entryTypes_(){var ks=Object.keys(FORMS);if(!boarHouseOn_()||ks.indexOf('웅돈')>=0)return ks;var i=ks.indexOf('등지방');ks.splice(i>=0?i+1:ks.length,0,'웅돈');return ks;}
function pageBoars(el) {
  if (typeof boarPageOk_ === 'function' && !boarPageOk_()) { el.innerHTML = '<div class="card"><p class="mut">수의사는 웅돈 관리를 열 수 없습니다.</p></div>'; return; }
  renderBoarForm(el);
}
function renderBoarForm(el) {
  el.innerHTML = '<p class="mut">웅돈 기록을 불러오는 중…</p>';
  apiF('listBoars', {}).then(function (r) {
    var all = r.rows || [];
    var barnNote = (typeof boarHouseOn_ === 'function' && boarHouseOn_()) ? '' : '<p class="mut">웅돈사가 아직 없어도 먼저 등록할 수 있습니다.</p>';
    el.innerHTML = '<h3 style="margin-top:0">웅돈 관리</h3>' + barnNote
      + '<div class="card" id="br-new" style="margin-bottom:14px"><h4 style="margin:0 0 8px">새 웅돈 등록</h4>'
      + '<div class="f"><label class="l" for="br-tag">웅돈번호 <span class="req">*</span></label><input id="br-tag" maxlength="20" autocomplete="off"></div>'
      + '<div class="f"><label class="l" for="br-dob">생년월일</label><input id="br-dob" type="date"></div>'
      + '<div class="f"><label class="l" for="br-ent">들어온 날</label><input id="br-ent" type="date"></div>'
      + '<div class="f"><label class="l" for="br-src">구입처</label><input id="br-src" maxlength="60"></div>'
      + '<div class="f"><label class="l" for="br-memo">비고</label><input id="br-memo" maxlength="200"></div>'
      + '<button class="btn" id="br-reg" type="button">웅돈 등록</button><div id="br-reg-msg" style="margin-top:8px"></div></div>'
      + (all.length ? '<div class="row" id="br-picks" style="flex-wrap:wrap;gap:6px">' + all.map(function (b, i) {
        return '<button type="button" class="btn sec" data-brid="' + esc(b['웅돈ID'] || '') + '">' + (i + 1) + '. ' + esc(b['웅돈번호'] || '') + '</button>';
      }).join('') + '</div>' : '<div class="card empty" id="br-empty"><p class="mut">아직 등록된 웅돈이 없습니다. 위에서 새 웅돈을 등록하세요.</p></div>')
      + '<div id="br-f"></div><div id="br-log"></div>';
    if ($('#br-ent', el) && typeof today === 'function' && !$('#br-ent', el).value) $('#br-ent', el).value = today();
    $('#br-reg', el).onclick = function () {
      var btn = this; if (btn.disabled) return;
      var tag = ($('#br-tag', el).value || '').trim(), msg = $('#br-reg-msg', el);
      msg.innerHTML = '';
      if (!tag) { msg.innerHTML = typeof errHTML === 'function' ? errHTML('웅돈번호를 입력하세요') : '웅돈번호를 입력하세요'; var i = $('#br-tag', el); if (i) i.focus(); return; }
      btn.disabled = true;
      apiF('saveBoar', { tag: tag, dob: $('#br-dob', el).value, entryDate: $('#br-ent', el).value, source: $('#br-src', el).value, memo: $('#br-memo', el).value }).then(function () {
        btn.disabled = false;
        if (typeof toast === 'function') toast('웅돈을 등록했습니다');
        renderBoarForm(el);
      }).catch(function (e) { btn.disabled = false; msg.innerHTML = errHTML(e); });
    };
    function fill(b) {
      var id = b['웅돈ID'] || '', tag = b['웅돈번호'] || '';
      $('#br-f', el).innerHTML = '<p><b>' + esc(tag) + '</b></p><div class="f"><label class="l">훈련</label><select id="br-tr"><option value="">선택</option><option>예</option><option>아니오</option></select></div>'
        + '<div class="f"><label class="l">사용가능</label><select id="br-us"><option value="">선택</option><option>예</option><option>아니오</option></select></div>'
        + '<div class="f"><label class="l">채취정자활력도</label><input id="br-mo" inputmode="decimal" placeholder="0–100"></div>'
        + '<div class="f"><label class="l">제조팩수</label><input id="br-pk" inputmode="numeric"></div>'
        + '<div class="f"><label class="l">특징</label><input id="br-nt" maxlength="200"></div>'
        + '<button class="btn" id="br-save" type="button">이 웅돈 기록 저장</button><div id="br-msg"></div>';
      if (b['훈련']) $('#br-tr', el).value = b['훈련'];
      if (b['사용가능']) $('#br-us', el).value = b['사용가능'];
      if (b['활력'] != null && b['활력'] !== '') $('#br-mo', el).value = b['활력'];
      if (b['제조팩수'] != null && b['제조팩수'] !== '') $('#br-pk', el).value = b['제조팩수'];
      if (b['특징']) $('#br-nt', el).value = b['특징'];
      $('#br-save', el).onclick = function () {
        var btn = this; if (btn.disabled) return; btn.disabled = true;
        apiF('boarEvent', id, { type: '관리', train: $('#br-tr', el).value, usable: $('#br-us', el).value, motility: $('#br-mo', el).value, packs: $('#br-pk', el).value, note: $('#br-nt', el).value, reqId: (typeof uuid === 'function' ? uuid() : String(Date.now())) }).then(function (r) {
          $('#br-msg', el).textContent = '저장했습니다. ' + tag;
          btn.disabled = false;
          fill(Object.assign({}, b, r || {}));
          loadLog(id);
        }).catch(function (e) { btn.disabled = false; $('#br-msg', el).innerHTML = errHTML(e); });
      };
      loadLog(id);
    }
    function loadLog(id) {
      apiF('getBoar', id).then(function (b) {
        var logs = (b.log || []).filter(function (x) { return x['유형'] === '관리'; });
        var box = $('#br-log', el); if (!box) return;
        box.innerHTML = logs.length ? '<table class="t"><tr><th>순번</th><th>작업일</th><th>훈련</th><th>사용가능</th><th>활력</th><th>제조팩수</th><th>특징</th></tr>' + logs.map(function (x, i) {
          return '<tr><td>' + (i + 1) + '</td><td>' + esc(x['작업일'] || '') + '</td><td>' + esc(x['훈련'] || '') + '</td><td>' + esc(x['사용가능'] || '') + '</td><td>' + esc(x['활력'] || '') + '</td><td>' + esc(x['제조팩수'] || x['도즈수'] || '') + '</td><td>' + esc(x['특징'] || '') + '</td></tr>';
        }).join('') + '</table>' : '<p class="mut">아직 관리 기록이 없습니다.</p>';
      }).catch(function (e) { var box = $('#br-log', el); if (box) box.innerHTML = errHTML(e); });
    }
    $$('[data-brid]', el).forEach(function (b) { b.onclick = function () { var id = b.getAttribute('data-brid'); fill(all.filter(function (x) { return x['웅돈ID'] === id; })[0] || { '웅돈ID': id }); }; });
    if (all[0]) fill(all[0]);
  }).catch(function (e) { el.innerHTML = errHTML(e); });
}
function mFarNum_(i, z) {
  var v = i ? String(i.value).trim() : ''; if (v === '') return z;
  var x = +v; return x >= 0 && x % 1 === 0 ? x : NaN;
}
function mFarSync_(box) {
  var q = function (k) { return $('[data-k="' + k + '"]', box); };
  var t = mFarNum_(q('총산'), null), s = mFarNum_(q('사산'), 0), m = mFarNum_(q('미라'), 0), bad = '', live = null;
  if (isNaN(t) || isNaN(s) || isNaN(m)) bad = '0 이상의 정수를 입력하세요';
  else if (t == null) bad = '총산 입력 필요';
  else if (s + m > t) bad = '사산+미라가 총산보다 많습니다';
  else live = t - s - m;
  var cull = mFarNum_(q('생시도태'), 0);
  if (!bad && live != null && !isNaN(cull) && cull > live) bad = '생시도태가 실산보다 많습니다';
  if (!bad && isNaN(cull)) bad = '0 이상의 정수를 입력하세요';
  var a = q('실산'); if (a) a.value = live == null ? '' : String(live);
  var n = $('.m-far-calc', box);
  var bar = $('.n7-far-bar', box);
  var line = live == null ? ('실산 —' + (bad ? ' ' + bad : '')) : ('총산 ' + t + ' · 실산 ' + live + ' · 사산 ' + s + ' · 미라 ' + m + (cull ? ' · 생시도태 ' + cull : '') + '두');
  if (n) n.textContent = line;
  if (bar) { bar.textContent = line; bar.className = 'n7-far-bar mut' + (bad ? ' err' : ''); }
  else if (n && !bar) {
    /* totals bar is the calc line when present */
  }
  return bad;
}
function mFarLay_(el) {
  var box = $('.entry', el); if (!box || box.classList.contains('big')) return;
  var q = function (k) { return $('[data-k="' + k + '"]', box); };
  function lineOf(input) {
    if (!input) return null;
    var sp = input.closest('.stepper') || input, lb = sp.previousElementSibling;
    if (!(lb && lb.classList && lb.classList.contains('l'))) return null;
    var line = document.createElement('div'); line.className = 'm-far-line';
    sp.parentNode.insertBefore(line, lb); line.appendChild(lb); line.appendChild(sp); return line;
  }
  var dateRow = $('#ef-date', box) && $('#ef-date', box).closest('.ef-row'), after = dateRow;
  ['총산', '사산', '미라', '실산'].forEach(function (k) {
    var line = lineOf(q(k)); if (!line || !after) return;
    var lb = $('.l', line); if (lb) { lb.textContent = k === '총산' ? '총산 *' : k; lb.setAttribute('data-noi18n', ''); }
    if (k === '실산') line.hidden = true;
    after.parentNode.insertBefore(line, after.nextSibling); after = line;
  });
  var note = document.createElement('div'); note.className = 'm-far-calc'; note.setAttribute('role', 'status');
  if (after && after.parentNode) after.parentNode.insertBefore(note, after.nextSibling);
  var sync = function () { return mFarSync_(box); };
  sync(); box._mf = sync; box.addEventListener('input', sync);
  var tag = $('#ef-tag', box); if (tag) tag.oninput = function () { if (typeof mfC_ === 'function') mfC_(); sync(); };
  box.addEventListener('click', function (e) { var n = e.target && e.target.closest && e.target.closest('.step,[data-rc]'); if (!n) return; if (n.hasAttribute('data-rc') && typeof mfC_ === 'function') mfC_(); sync(); });
  var msg = $('#ef-msg', box), extras = [], node = note.nextSibling;
  while (node && node !== msg) { var nxt = node.nextSibling; if (!(node.tagName === 'DETAILS')) extras.push(node); node = nxt; }
  if (extras.length && msg) {
    var det = document.createElement('details'); det.className = 'more efmore';
    var sum = document.createElement('summary'); sum.textContent = '추가 항목'; det.appendChild(sum);
    extras.forEach(function (n) { det.appendChild(n); }); msg.parentNode.insertBefore(det, msg);
  }
}
function mFarEd_(el) {
  var box = $('.entry', el), a = $('[data-k="실산"]', box); if (!box || !a) return;
  a.readOnly = true;
  function paint(bad) { var m = $('#ef-msg', box); if (!m) return; if (bad) m.innerHTML = '<div class="err" role="alert">' + esc(bad) + '</div>'; else if (m.querySelector && m.querySelector('.err')) m.textContent = ''; }
  function go() { var bad = mFarSync_(box); paint(bad); try { n7EntrySaveGate_(box); } catch (eG) {} return bad; }
  box._mf = go;
  box.addEventListener('input', function (e) { var k = e.target.getAttribute && e.target.getAttribute('data-k'); if (k === '총산' || k === '사산' || k === '미라' || k === '생시도태') go(); });
  box.addEventListener('click', function (e) { if (e.target && e.target.closest && e.target.closest('.step')) go(); });
}
document.addEventListener('click', function (e) {
  var meta = document.getElementById('plmeta'); if (!meta || meta.getAttribute('data-view') !== 'm') return;
  var b = e.target && e.target.closest && e.target.closest('#ef-save'); if (!b) return;
  var box = b.closest('.entry'); if (!box || !box._mf) return;
  var bad = box._mf(); if (!bad) return;
  e.preventDefault(); e.stopImmediatePropagation();
  var m = $('#ef-msg', box); if (m) m.innerHTML = '<div class="err" role="alert">' + esc(bad) + '</div>';
}, true);

function nov7FoldNickInput_(input, btn) {
  if (!input || input.getAttribute('data-folded')) return; input.setAttribute('data-folded', '1');
  var lab = input.previousElementSibling;
  if (lab && lab.tagName !== 'LABEL') lab = null;
  var wrap = document.createElement('div'); wrap.className = 'ef-nick-box';
  input.parentNode.insertBefore(wrap, input);
  var fold = document.createElement('div'); fold.className = 'ef-nick-fold';
  var a = document.createElement('a'); a.href = '#'; a.textContent = '애칭 추가';
  fold.appendChild(a); wrap.appendChild(fold);
  var pane = document.createElement('div'); pane.setAttribute('data-nick-pane', '');
  if (lab) pane.appendChild(lab);
  var row = document.createElement('div'); row.className = 'ef-nick-row';
  row.appendChild(input); if (btn) row.appendChild(btn); pane.appendChild(row);
  wrap.appendChild(pane);
  function show(on) { pane.hidden = !on; a.textContent = on ? '애칭 숨기기' : '애칭 추가';
    var lim = wrap.querySelector('[data-limc="nickname"]') || (wrap.parentNode && wrap.parentNode.querySelector('[data-limc="nickname"]'));
    if (lim) { if (on && !pane.contains(lim)) pane.appendChild(lim); lim.style.display = on ? '' : 'none'; }
  }
  var has = !!(input.value && input.value.trim());
  show(has);
  a.onclick = function (e) { e.preventDefault(); show(pane.hidden); if (!pane.hidden) input.focus(); };
}
function nov7PolishEntry_(el, opt) {
  if (!el) return;
  var typBtn = el.parentNode && el.parentNode.querySelector('#en-t button.on');
  var typ = (opt && opt.type) || (typBtn ? typBtn.getAttribute('data-t') : '') || '';
  if (typ === '자돈폐사') {
    var labs = el.querySelectorAll('label.l');
    for (var li = 0; li < labs.length; li++) {
      if (labs[li].textContent.indexOf('모돈번호') >= 0) { labs[li].textContent = '모돈번호'; break; }
    }
  }
  var breed = el.querySelector('[data-k="품종"]');
  if (breed && !breed.getAttribute('data-breed')) {
    breed.setAttribute('data-breed', '1');
    breed.setAttribute('list', 'ef-breed-list');
    if (!el.querySelector('#ef-breed-list')) {
      var dl = document.createElement('datalist'); dl.id = 'ef-breed-list';
      ['F1','F2','LY','YL','Y','L','D','요크셔','랜드레이스','두록','버크셔','피어트레인'].forEach(function (x) {
        var o = document.createElement('option'); o.value = x; dl.appendChild(o);
      });
      breed.parentNode.appendChild(dl);
    }
    var lab = breed.previousElementSibling;
    if (lab && lab.classList && lab.classList.contains('l') && lab.textContent.indexOf('*') < 0) lab.textContent = lab.textContent.replace(/\s*$/, '') + ' *';
    var box = document.createElement('div'); box.className = 'ef-breed-hl';
    if (lab && lab.parentNode === breed.parentNode) { breed.parentNode.insertBefore(box, lab); box.appendChild(lab); }
    else breed.parentNode.insertBefore(box, breed);
    box.appendChild(breed);
    var tagRow = el.querySelector('#ef-tag') && el.querySelector('#ef-tag').closest('div');
    if (tagRow && tagRow.parentNode) tagRow.parentNode.insertBefore(box, tagRow.nextSibling);
  }
  var save = el.querySelector('#ef-save');
  if (save && !save.getAttribute('data-breed-val')) {
    save.setAttribute('data-breed-val', '1');
    save.addEventListener('click', function (e) {
      if (!breed || breed.closest !== el && !el.contains(breed)) breed = el.querySelector('[data-k="품종"]');
      if (!breed) return;
      if (!String(breed.value || '').trim()) {
        e.preventDefault(); e.stopImmediatePropagation();
        breed.classList.add('bad'); breed.focus();
        var msg = el.querySelector('#ef-msg') || el.querySelector('.msg');
        if (msg && typeof errHTML === 'function') msg.innerHTML = errHTML('입력하세요: 품종');
        else if (typeof toast === 'function') toast('입력하세요: 품종');
      }
    }, true);
  }
  if (typ === '전입' && !el.querySelector('[data-k="nickname"]')) {
    var host = document.createElement('div');
    var nlab = document.createElement('label'); nlab.className = 'l'; nlab.textContent = '애칭 (선택)';
    var ninp = document.createElement('input'); ninp.className = 'f'; ninp.setAttribute('data-k', 'nickname'); ninp.setAttribute('data-lim', '40'); ninp.maxLength = 40;
    ninp.addEventListener('input', function (e) { if (e.isTrusted) ninp.setAttribute('data-d', '1'); });
    host.appendChild(nlab); host.appendChild(ninp);
    var tagRow = el.querySelector('#ef-tag') && el.querySelector('#ef-tag').closest('div');
    var breedBox = el.querySelector('.ef-breed-hl');
    var note = el.querySelector('[data-k="sowNote"]');
    if (breedBox && breedBox.parentNode) breedBox.parentNode.insertBefore(host, breedBox.nextSibling);
    else if (tagRow && tagRow.parentNode) tagRow.parentNode.insertBefore(host, tagRow.nextSibling);
    else if (note && note.parentNode) note.parentNode.insertBefore(host, note.previousElementSibling && note.previousElementSibling.tagName === 'LABEL' ? note.previousElementSibling : note);
    else if (el.querySelector('#ef-save')) el.querySelector('#ef-save').parentNode.insertBefore(host, el.querySelector('#ef-save'));
    else el.appendChild(host);
    if (typeof nov7AttachName_ === 'function') nov7AttachName_(ninp, { kind: 'sow' });
  }
  var nick = el.querySelector('[data-k="nickname"]');
  if (nick && typeof nov7AttachName_ === 'function' && !nick.getAttribute('data-named')) nov7AttachName_(nick, { kind: 'sow' });
  if (nick && !nick.getAttribute('data-folded')) {
    var nb = (nick.closest && nick.closest('.ef-nick-box, .ef-nick-row') || nick.parentNode).querySelector('.nov7-rand');
    nov7FoldNickInput_(nick, nb);
  }
  nov7FoldFeat_(el);
  nov7BindDayBtns_(el, '#ef-date');
  if (typeof n7HookLocPicker_ === 'function') n7HookLocPicker_();
  if (typ === '이동') {
    if (!el.querySelector('.locpick') && !el.querySelector('.n7-dest-loc')) {
      var destH = (typeof locPickerHTML === 'function') ? locPickerHTML('이동', '') : '';
      if (!destH) destH = '<label class="l">어디로 (선택)</label><div class="n7-destfree"><div class="mut">이 농장은 방이 등록되어 있지 않습니다. <a href="#" id="n7-dest-struct">농장 구조 등록</a></div><input type="text" class="n7-dest-loc" maxlength="40" placeholder="위치 메모"></div>';
      var box = document.createElement('div'); box.innerHTML = destH;
      var saveBtn = el.querySelector('#ef-save');
      var host = (saveBtn && saveBtn.parentNode) || el;
      while (box.firstChild) host.insertBefore(box.firstChild, saveBtn || null);
      if (typeof bindLocPicker === 'function') bindLocPicker(el);
    }
    if (typeof n7MoveReq_ === 'function') n7MoveReq_(el);
  }
  if (typeof n7CauseReq_ === 'function') n7CauseReq_(el);
  if (typeof n7QuickPicks_ === 'function') n7QuickPicks_(el);
  if (typeof n7BoarChips_ === 'function') n7BoarChips_(el, typ);
  if (typeof n7BigSteppers_ === 'function') n7BigSteppers_(el);
  if (typeof n7SugSows_ === 'function') n7SugSows_(el);
  if (typeof n7Keypad_ === 'function') n7Keypad_(el);
  if (typeof n7KoDate_ === 'function') n7KoDate_(el);
  if (typeof n7ActionBar_ === 'function') n7ActionBar_((window.PL && PL._page) || 'entry');
}
if (typeof renderEntryForm === 'function' && !renderEntryForm._nov7p) {
  var _refEnt = renderEntryForm;
  renderEntryForm = function (el, opt) { _refEnt(el, opt); nov7PolishEntry_(el, opt); if (typeof n7PolishEntryT447_ === 'function') n7PolishEntryT447_(el, opt); };
  renderEntryForm._nov7p = 1;
}


if (typeof causeBind === 'function' && !causeBind._t394u) {
  causeBind = function (cz, type, kindFn) {
    var draw = function () {
      var ctx = causeCtxC(type, kindFn ? kindFn() : ''), v = cz.dataset.v || '';
      var sl = v.indexOf('/'), top = sl < 0 ? v : v.slice(0, sl), rest = sl < 0 ? '' : v.slice(sl + 1);
      var known = (typeof CAUSE_SUB_C !== 'undefined' && CAUSE_SUB_C[top]) ? CAUSE_SUB_C[top] : [];
      var sub = '', custom = '';
      if (rest) {
        var sl2 = rest.indexOf('/'), first = sl2 < 0 ? rest : rest.slice(0, sl2), after = sl2 < 0 ? '' : rest.slice(sl2 + 1);
        if (known.indexOf(first) >= 0) { sub = first; custom = after; } else custom = rest;
      }
      if (!ctx) {
        cz.innerHTML = type === '도폐사' && kindFn && kindFn() === '판매' ? '<div class="mut czno">' + esc(T('ef.why.none')) + '</div>' : '';
        cz.dataset.on = ''; return;
      }
      var list = CAUSES_C[ctx].slice(); if (top && list.indexOf(top) < 0) list.push(top);
      cz.dataset.on = '1';
      var open = !!(sub || custom || top === '기타');
      var more = '<details class="more czsub"' + (open ? ' open' : '') + '><summary>' + esc(T('ef.why.more')) + '</summary>'
        + (known.length ? '<div class="seg czs">' + known.map(function (x) { return '<button type="button" class="' + (x === sub ? 'on' : '') + '" data-v="' + esc(x) + '">' + esc(tc('csub', x)) + '</button>'; }).join('') + '</div>' : '')
        + '<input class="f cz-free" maxlength="80" placeholder="직접 입력" value="' + esc(custom) + '"><div class="mut cz-free-h">자세한 원인은 직접 적어도 됩니다</div></details>';
      cz.innerHTML = '<div class="seg czt czt-lg">' + list.map(function (x) { return '<button type="button" class="' + (x === top ? 'on' : '') + '" data-v="' + esc(x) + '">' + esc(tc('cause', x)) + '</button>'; }).join('') + '</div>' + more;
      function pack(t, s, c) { return t ? (t + (s ? '/' + s : '') + (c ? '/' + c : '')) : ''; }
      $$('.czt button', cz).forEach(function (b) {
        b.onclick = function () {
          var x = b.getAttribute('data-v');
          cz.dataset.v = pack(x === top ? '' : x, '', custom);
          draw();
        };
      });
      $$('.czs button', cz).forEach(function (b) {
        b.onclick = function () {
          var x = b.getAttribute('data-v');
          cz.dataset.v = pack(top, x === sub ? '' : x, custom);
          draw();
        };
      });
      var inp = cz.querySelector('.cz-free');
      if (inp) inp.addEventListener('input', function () { cz.dataset.v = pack(top, sub, inp.value.replace(/^\s+|\s+$/g, '')); });
      if (open && top === '기타' && inp) setTimeout(function () { try { inp.focus(); } catch (e1) {} }, 0);
    };
    draw(); return draw;
  };
  causeBind._t394u = 1;
}


if (typeof I18N_DFMT !== 'undefined' && I18N_DFMT.ko) {
  I18N_DFMT.ko.s = '{Y}. {M}. {D}. ({w})';
  I18N_DFMT.ko.l = '{Y}. {M}. {D}. ({w})';
}
function n7HookHome_() {
  function wrap(name) {
    var fn = typeof window !== 'undefined' ? window[name] : null;
    if (typeof fn === 'function' && !fn._n7v2) {
      window[name] = function (el, goFn) {
        if (typeof hasSowHerd === 'function' && !hasSowHerd() && typeof pageHomeFin_ === 'function') return pageHomeFin_(el);
        nov7DashMount_(el, goFn || (typeof go === 'function' ? go : undefined));
      };
      window[name]._n7v2 = 1;
      window[name]._ft434 = 1;
    }
  }
  wrap('pageHome'); wrap('pageHomeK');
}
n7HookHome_();
if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', n7HookHome_);
else n7HookHome_();
function n7ViewMark_() {
  try {
    var v = (window.PL && PL.view) || (document.getElementById('plmeta') && document.getElementById('plmeta').dataset.view) || '';
    if (v) document.documentElement.setAttribute('data-n7v', v);
    var th = '';
    try {
      th = localStorage.getItem('pl_theme') || localStorage.getItem('pl_n7theme') || '';
      if (!th) {
        for (var i = 0; i < localStorage.length; i++) {
          var k = localStorage.key(i);
          if (k && k.indexOf('pl_theme:') === 0) { th = localStorage.getItem(k) || ''; if (th) break; }
        }
      }
    } catch (e2) {}
    if (typeof hcOn === 'function' && hcOn() && !th) th = 'sun';
    if (th === 'dark' || th === 'light' || th === 'barn' || th === 'sun') document.documentElement.setAttribute('data-theme', th);
    else if (!th) document.documentElement.removeAttribute('data-theme');
    if (typeof n7DemoRibbon_ === 'function') n7DemoRibbon_();
    if (typeof n7BellFix_ === 'function') n7BellFix_();
  } catch (e) {}
}
n7ViewMark_();
function n7ThemeInit_() {
  n7ViewMark_();
  var hc = document.getElementById('f-hc');
  if (!hc && window.PL && PL.view === 'field' && !n7ThemeInit_._tries) n7ThemeInit_._tries = 0;
  if (!hc && window.PL && PL.view === 'field' && n7ThemeInit_._tries < 20) {
    n7ThemeInit_._tries++;
    setTimeout(n7ThemeInit_, 200);
  }
  if (hc) n7ThemeInit_._tries = 0;
  if (hc && !document.getElementById('n7-barn')) {
    var b = document.createElement('button');
    b.id = 'n7-barn'; b.type = 'button'; b.className = 'hcbtn';
    var cur = document.documentElement.getAttribute('data-theme') === 'barn';
    b.textContent = cur ? '돈사 켜짐' : '돈사 모드';
    b.setAttribute('aria-pressed', cur ? 'true' : 'false');
    hc.parentNode.insertBefore(b, hc.nextSibling);
    b.onclick = function () {
      var on = document.documentElement.getAttribute('data-theme') !== 'barn';
      try {
        if (on) {
          var curT = document.documentElement.getAttribute('data-theme') || 'light';
          if (curT === 'light' || curT === 'dark') localStorage.setItem('pl_theme_prev', curT);
          localStorage.setItem('pl_theme', 'barn');
          localStorage.setItem('pl_n7theme', 'barn');
        } else {
          var prev = 'light';
          try { prev = localStorage.getItem('pl_theme_prev') || 'light'; } catch (e4) {}
          if (prev !== 'light' && prev !== 'dark') prev = 'light';
          localStorage.setItem('pl_theme', prev);
          localStorage.setItem('pl_n7theme', prev);
        }
      } catch (e) {}
      if (on && typeof hcApply === 'function') {
        try { localStorage.setItem('pl_hc', '0'); hcApply(); } catch (e3) {}
      }
      n7ThemeInit_();
      var x = document.getElementById('n7-barn');
      if (x) { x.textContent = on ? '돈사 켜짐' : '돈사 모드'; x.setAttribute('aria-pressed', on ? 'true' : 'false'); }
    };
  }
  if (typeof hcApply === 'function' && !hcApply._n7t) {
    var _hc = hcApply;
    hcApply = function () {
      _hc();
      if (typeof hcOn === 'function' && hcOn()) {
        try { localStorage.setItem('pl_n7theme', 'sun'); } catch (e) {}
      } else {
        try { if (localStorage.getItem('pl_n7theme') === 'sun') localStorage.setItem('pl_n7theme', ''); } catch (e) {}
      }
      n7ViewMark_();
    };
    hcApply._n7t = 1;
  }
}
function n7SubPage_(p) {
  return p && !({ home: 1, sows: 1, more: 1, dash: 1, due: 1 }[p]) ? 1 : 0;
}
function n7BackOf_(p) {
  return ({ entry: 'home', sow: 'sows', sowcard: 'sows', events: 'more', settings: 'more', org: 'more', users: 'more', board: 'more', struct: 'more' })[p] || 'more';
}
function n7SubHead_(p) {
  if (!(window.PL && PL.view === 'm')) return;
  var mh = document.querySelector('.mh');
  if (!mh) return;
  var back = document.getElementById('n7-back');
  if (!n7SubPage_(p)) {
    document.documentElement.classList.remove('n7-sub');
    if (back) back.remove();
    return;
  }
  document.documentElement.classList.add('n7-sub');
  if (!back) {
    back = document.createElement('button');
    back.id = 'n7-back'; back.type = 'button'; back.className = 'n7-back';
    back.setAttribute('aria-label', '뒤로'); back.textContent = '‹';
    var title = document.getElementById('m-title');
    mh.insertBefore(back, title || mh.firstChild);
    back.onclick = function () {
      var to = n7BackOf_(PL._page || p);
      (PL.go || window.go)(to);
    };
  }
}
function n7Vis_(el) {
  if (!el) return false;
  var s = window.getComputedStyle(el);
  if (s.display === 'none' || s.visibility === 'hidden' || Number(s.opacity) === 0) return false;
  var r = el.getBoundingClientRect();
  return r.width > 0 && r.height > 0;
}
function n7LoginVisible_() {
  var id = document.getElementById('lg-id') || document.getElementById('login-id') || document.getElementById('pw');
  if (n7Vis_(id)) return true;
  var box = document.querySelector('.loginbox, .loginwrap, #login-box, .auth-box, form.login');
  return n7Vis_(box);
}
function n7HideAbar_() {
  var old = document.getElementById('n7-abar');
  if (old) old.remove();
  document.body.classList.remove('n7-abar-on');
  var save = document.getElementById('ef-save');
  if (save) save.style.display = '';
}
function n7EntryActive_() {
  if (n7LoginVisible_()) return null;
  if (!(window.PL && PL.token)) return null;
  var save = document.getElementById('ef-save');
  if (!save || !document.body.contains(save)) return null;
  var entry = save.closest && save.closest('.entry');
  if (!entry || !document.body.contains(entry)) return null;
  if (document.body.classList.contains('n7-login')) return null;
  if (!n7Vis_(save) && !n7Vis_(entry)) return null;
  return save;
}
function n7ActionBar_(p) {
  if (n7LoginVisible_() || !(window.PL && PL.token)) { n7HideAbar_(); return; }
  var save = n7EntryActive_();
  var view = window.PL && PL.view;
  var page = p || (window.PL && PL._page) || '';
  var onM = view === 'm' && (page === 'entry' || page === '' || (typeof n7SubPage_ === 'function' && n7SubPage_(page)));
  var onF = view === 'field' && !!save;
  if (!save || (!onM && !onF) || (view === 'm' && page && page !== 'entry' && !(typeof n7SubPage_ === 'function' && n7SubPage_(page)))) {
    n7HideAbar_();
    return;
  }
  var old = document.getElementById('n7-abar');
  if (!old) {
    old = document.createElement('div');
    old.id = 'n7-abar'; old.className = 'n7-abar';
    old.innerHTML = '<button type="button" class="btn" id="n7-abar-save">저장하고 다음 모돈</button>';
    document.body.appendChild(old);
  }
  document.body.classList.add('n7-abar-on');
  save.style.display = 'none';
  try {
    var tb = document.querySelector('.tabbar');
    if (tb && old) {
      var th = Math.ceil(tb.getBoundingClientRect().height || 80);
      if (th < 56) th = 80;
      old.style.bottom = th + 'px';
    }
  } catch (eAb) {}
  var b = document.getElementById('n7-abar-save');
  if (b) b.onclick = function () {
    if (b.getAttribute('data-n7lock') === '1' || (save && save.disabled)) return;
    b.setAttribute('data-n7lock', '1'); b.disabled = true;
    var prev = b.getAttribute('data-n7lbl') || b.textContent;
    b.setAttribute('data-n7lbl', prev);
    b.textContent = '저장 중…';
    try { save.click(); } catch (e) {}
    var n = 0, watch = function () {
      if (!save || !save.disabled || n > 120) {
        b.removeAttribute('data-n7lock'); b.disabled = false;
        b.textContent = b.getAttribute('data-n7lbl') || '저장하고 다음 모돈';
        return;
      }
      n++; setTimeout(watch, 200);
    };
    setTimeout(watch, 200);
  };
}
function n7WatchAbar_() {
  if (n7WatchAbar_._on) return;
  n7WatchAbar_._on = 1;
  var tick = function () { n7ActionBar_((window.PL && PL._page) || ''); };
  var mo = new MutationObserver(function () {
    if (n7LoginVisible_() || !(window.PL && PL.token) || !n7EntryActive_()) tick();
  });
  mo.observe(document.body, { childList: true, subtree: true });
  function wrap(fn, key) {
    if (typeof fn !== 'function' || fn[key]) return fn;
    var w = function () {
      var r = fn.apply(this, arguments);
      n7HideAbar_();
      setTimeout(tick, 0);
      setTimeout(tick, 200);
      setTimeout(tick, 800);
      return r;
    };
    w[key] = 1;
    return w;
  }
  if (typeof logoutNow === 'function') logoutNow = wrap(logoutNow, '_n7abar');
  if (typeof forceLogout === 'function') forceLogout = wrap(forceLogout, '_n7abar');
  if (window.PL && typeof PL.showLogin === 'function') PL.showLogin = wrap(PL.showLogin, '_n7abar');
}
function n7FsLab_() { return '약품/사료'; }
function n7MonthKeys_(n) {
  n = n || 12;
  var t = (typeof today === 'function') ? today() : new Date().toISOString().slice(0, 10);
  var y = +t.slice(0, 4), m = +t.slice(5, 7) - (n - 1);
  while (m <= 0) { m += 12; y--; }
  var ks = [];
  for (var i = 0; i < n; i++) { ks.push(y + '-' + ('0' + m).slice(-2)); if (++m > 12) { m = 1; y++; } }
  return { keys: ks, from: ks[0] + '-01', to: t };
}
function n7MonthEnd_(ym, todayS) {
  var y = +ym.slice(0, 4), m = +ym.slice(5, 7);
  var last = new Date(y, m, 0);
  var s = y + '-' + ('0' + m).slice(-2) + '-' + ('0' + last.getDate()).slice(-2);
  return (todayS && s > todayS) ? todayS : s;
}
function n7FstockTabs_(el, kind) {
  if (!el || el.querySelector('.n7-fs-tabs')) return;
  var tabs = [['feed', '사료'], ['drug', '약품'], ['fcr', '월별 FCR'], ['disinfect', '소독기록부']];
  var bar = document.createElement('div');
  bar.className = 'n7-fs-tabs noprint';
  bar.innerHTML = tabs.map(function (t) {
    return '<button type="button" data-n7fs="' + t[0] + '"' + (t[0] === kind ? ' class="on"' : '') + '>' + t[1] + '</button>';
  }).join('');
  el.insertBefore(bar, el.firstChild);
  bar.onclick = function (e) {
    var b = e.target.closest && e.target.closest('[data-n7fs]');
    if (!b) return;
    n7FstockHub_(el, b.getAttribute('data-n7fs'));
  };
}
function n7HookFstock_() {
  if (window.PAGES_M && !PAGES_M.fstock) {
    PAGES_M.fstock = function (el, arg) { n7FstockHub_(el, arg || 'feed'); };
  }
  if (typeof pageFstock === 'function' && !pageFstock._n7fs) {
    var _fs = pageFstock;
    pageFstock = function (el, kind) {
      kind = kind || 'feed';
      if (kind === 'fcr') return n7FcrView_(el);
      if (kind === 'disinfect') return n7DisinfectView_(el);
      _fs(el, kind === 'drug' ? 'drug' : 'feed');
    };
    pageFstock._n7fs = 1;
  }
  if (typeof pageFstockDraw_ === 'function' && !pageFstockDraw_._n7fs) {
    var _d = pageFstockDraw_;
    pageFstockDraw_ = function (el, kind) {
      var r = _d.apply(this, arguments);
      n7FstockTabs_(el, kind === 'drug' ? 'drug' : 'feed');
      return r;
    };
    pageFstockDraw_._n7fs = 1;
  }
  n7RenameStockTab_();
  n7InjectStockMenus_();
}
function n7FstockHub_(el, kind) {
  if (!el) return;
  kind = kind || 'feed';
  if (kind === 'fcr') return n7FcrView_(el);
  if (kind === 'disinfect') return n7DisinfectView_(el);
  if (typeof pageFstock === 'function') { pageFstock(el, kind === 'drug' ? 'drug' : 'feed'); return; }
  if (n7FstockHub_._lz) {
    el.innerHTML = '<div class="err">재고 화면을 불러오지 못했습니다. 월별 FCR과 소독기록부는 위 단추로 열 수 있습니다.</div>';
    n7FstockTabs_(el, kind);
    return;
  }
  if (typeof loading === 'function') loading(el); else el.innerHTML = '<div class="mut">불러오는 중…</div>';
  n7FstockTabs_(el, kind);
  if (typeof lzLoad_ === 'function') {
    lzLoad_(function () { n7HookFstock_(); n7FstockHub_(el, kind); }, function () { n7FstockHub_._lz = 1; n7FstockHub_(el, kind); });
  } else {
    n7FstockHub_._lz = 1; n7FstockHub_(el, kind);
  }
}
function n7RenameStockTab_() {
  var lab = n7FsLab_();
  var nodes = document.querySelectorAll('a[data-p="fstock"], button[data-p="fstock"], [data-p="fstock"]');
  Array.prototype.forEach.call(nodes, function (a) {
    var txt = (a.textContent || '').replace(/\s+/g, ' ').trim();
    if (!txt || txt === lab) {
      if (!/약품\/사료/.test(a.textContent || '')) {
        /* keep icon, set label */
        var only = a.childNodes.length === 1 && a.childNodes[0].nodeType === 3;
        if (only) a.textContent = lab;
      }
      return;
    }
    if (/사료/.test(txt) || /약품/.test(txt) || /재고/.test(txt) || /fstock/i.test(txt)) {
      var html = a.innerHTML;
      a.innerHTML = html.replace(/사료·약품 재고|사료\/약품 재고|사료·약품|약품재고/g, lab);
      if (!/약품\/사료/.test(a.innerHTML)) {
        var last = a.lastChild;
        if (last && last.nodeType === 3) last.textContent = ' ' + lab;
      }
    }
  });
  ['w-title', 'm-title'].forEach(function (id) {
    var t = document.getElementById(id);
    if (!t) return;
    if (window.PL && PL._page === 'fstock') t.textContent = lab;
    else if (/사료·약품 재고|사료\/약품 재고|nav\.fstock/.test(t.textContent || '')) t.textContent = lab;
  });
}
function n7InjectStockMenus_() {
  var lab = n7FsLab_();
  /* mobile 더보기 */
  var lists = document.querySelectorAll('#m-main a[data-p], #m-page a[data-p], #m-main button[data-p]');
  var has = false, stockEl = null, wrap = null;
  Array.prototype.forEach.call(lists, function (a) {
    if (a.getAttribute('data-p') === 'fstock') has = true;
    if (a.getAttribute('data-p') === 'stock' || a.getAttribute('data-p') === 'drugs') { stockEl = a; wrap = a.parentNode; }
  });
  if (!has && wrap && stockEl && window.PAGES_M) {
    var b = stockEl.cloneNode(true);
    b.setAttribute('data-p', 'fstock');
    b.textContent = lab;
    b.onclick = function (e) { e.preventDefault(); if (window.PL && PL.go) PL.go('fstock'); };
    wrap.insertBefore(b, stockEl);
  }
  /* field 약품 줄 */
  var fTabs = document.querySelector('#app .tabs, .fh ~ main .tabs, #app');
  var host = document.querySelector('#app .tabs') || document.querySelector('.types');
  if (host && !host.querySelector('[data-n7fs-open]') && (window.PL && PL.view === 'field')) {
    var more = document.createElement('button');
    more.type = 'button'; more.setAttribute('data-n7fs-open', '1'); more.setAttribute('data-fp', 'fstock');
    more.textContent = lab;
    more.onclick = function () { n7FieldFstock_(); };
    host.appendChild(more);
  }
}
function n7FieldFstock_() {
  var app = document.getElementById('app'); if (!app) return;
  var title = n7FsLab_();
  var head = (typeof header === 'function') ? header(title, true) : '<div class="fh"><button id="f-back">←</button><div class="t">' + title + '</div></div>';
  app.innerHTML = head + '<main id="n7-fs-main"></main>';
  var back = document.getElementById('f-back');
  if (back) back.onclick = function () { if (typeof fHome === 'function') fHome(); };
  var el = document.getElementById('n7-fs-main');
  n7FstockHub_(el, 'feed');
}
function n7FarmTitle_() {
  try {
    var fs = (window.PL && PL.farms) || [];
    var id = window.PL && PL.farmId;
    for (var i = 0; i < fs.length; i++) if (fs[i].id === id) return fs[i].name || fs[i].farmName || '';
    return (fs[0] && (fs[0].name || fs[0].farmName)) || '';
  } catch (e) { return ''; }
}
function n7FcrView_(el) {
  loading(el);
  var per = n7MonthKeys_(12);
  var from = per.from, to = per.to, ks = per.keys;
  var shipP = (typeof apiF === 'function') ? apiF('getShipGrades', { from: from, to: to }).catch(function () { return null; }) : Promise.resolve(null);
  var invP = (typeof apiF === 'function') ? apiF('getInvMonthly', 12).catch(function () { return null; }) : Promise.resolve(null);
  var invListP = (typeof apiF === 'function') ? apiF('listInv', 'feed', { from: from, to: to }).catch(function () { return { rows: [] }; }) : Promise.resolve({ rows: [] });
  var books = ks.map(function (ym) {
    var d = n7MonthEnd_(ym, to);
    return (typeof apiF === 'function') ? apiF('getGroupBook', d).catch(function () { return null; }) : Promise.resolve(null);
  });
  Promise.all([shipP, invP, invListP].concat(books)).then(function (a) {
    var ship = a[0], inv = a[1], invL = a[2], books = a.slice(3);
    n7FcrDraw_(el, ks, from, to, ship, inv, invL, books);
  }).catch(function (e) { el.innerHTML = (typeof errHTML === 'function' ? errHTML(e) : '<div class="err">불러오지 못했습니다</div>'); });
}
function n7Num_(v) { var n = Number(v); return isFinite(n) ? n : 0; }
function n7FcrDraw_(el, ks, from, to, ship, inv, invL, books) {
  var stages = ['자돈', '육성', '비육'];
  var byM = {};
  ks.forEach(function (k) {
    byM[k] = { feedOut: null, feedIn: 0, shipKg: null, shipHead: 0, shipWHead: 0, stageShip: {}, miss: [] };
  });
  if (inv && inv.months) inv.months.forEach(function (x) {
    var o = byM[x.month]; if (!o) return;
    o.feedIn = n7Num_(x.feedKg);
    o.feedOut = n7Num_(x.feedOutKg);
    o.feedN = n7Num_(x.feedN);
  });
  if (ship && ship.months) ship.months.forEach(function (x) {
    var o = byM[x.month]; if (!o) return;
    o.shipKg = x.kg == null ? null : n7Num_(x.kg);
    o.shipHead = n7Num_(x.head);
    o.shipWHead = n7Num_(x.wHead);
  });
  books.forEach(function (b, i) {
    var k = ks[i]; if (!b || !byM[k]) return;
    var st = b.stages || [];
    st.forEach(function (s) {
      var name = s.stage || s.name;
      if (!name) return;
      byM[k].stageShip[name] = { kg: s.shipW == null ? null : n7Num_(s.shipW), head: n7Num_(s.ship), wHead: n7Num_(s.shipWN) };
    });
  });
  /* 재고 실사·이동 체중·상시 재고 체중은 API에 월별 kg가 없음 → 가짜로 채우지 않음 */
  function fmt(n, d) { d = d == null ? 1 : d; return (typeof n1 === 'function') ? n1(n, d) : (Math.round(n * Math.pow(10, d)) / Math.pow(10, d)).toFixed(d); }
  var rows = ks.map(function (k) {
    var o = byM[k];
    var miss = [];
    if (o.feedOut == null) miss.push('사료 사용량');
    if (o.shipHead > 0 && o.shipWHead < o.shipHead) miss.push('출하 ' + (o.shipHead - o.shipWHead) + '두 체중 없음');
    if (o.shipHead === 0 && !(o.shipKg > 0)) miss.push('출하 체중(출하 기록 없음)');
    miss.push('이동·전입 체중(기록 없음)');
    miss.push('재고 체중 증감(실사 체중 없음)');
    var feed = o.feedOut;
    var gain = (o.shipKg != null && o.shipWHead > 0) ? o.shipKg : null;
    var fcr = (feed != null && gain > 0) ? (feed / gain) : null;
    /* 전체 FCR은 출하 체중만으로 계산 가능해도, 빠진 항목을 분명히 적음 */
    var fcrCell, note;
    if (fcr == null) {
      fcrCell = '<span class="n7-fcr-na">자료 부족</span>';
      note = miss.join(', ');
    } else if (miss.length) {
      fcrCell = fmt(fcr, 2) + ' <span class="n7-fcr-na">참고</span>';
      note = '출하 체중만으로 계산. 빠짐: ' + miss.filter(function (m) { return m.indexOf('출하') !== 0; }).join(', ');
    } else {
      fcrCell = fmt(fcr, 2);
      note = '';
    }
    var st = stages.map(function (s) {
      var g = o.stageShip[s];
      if (!g || !(g.kg > 0)) return '<td class="n7-fcr-na">자료 부족</td>';
      if (!(feed > 0)) return '<td class="n7-fcr-na">자료 부족</td>';
      /* 사료가 단계별로 나뉘지 않음 */
      return '<td class="n7-fcr-na">자료 부족</td>';
    }).join('');
    var empty = !(feed > 0) && !(gain > 0) && !o.shipHead;
    return '<tr><td>' + k.replace(/-/g, '.') + '</td><td>' + (feed == null ? '—' : fmt(feed, 1)) + '</td><td>' + (o.feedIn ? fmt(o.feedIn, 1) : '—') + '</td><td>' + (gain == null ? '—' : fmt(gain, 1)) + '</td><td>' + (o.shipHead || '—') + '</td><td>' + fcrCell + '</td>' + st + '</tr>' +
      (!empty && note ? '<tr><td></td><td colspan="8" class="n7-fcr-miss">' + note + '</td></tr>' : '');
  }).join('');
  var anyMiss = '사료 사용량은 사용 기록 합입니다. 월말 재고 실사가 없어 재고 증감으로 보정치 않았습니다. 증체량은 체중이 적힌 출하만 합쳤습니다. 이동·전입 체중과 재고 체중 증감, 단계별 사료량은 자료가 없어 FCR에 넣지 않았습니다.';
  el.innerHTML = '<div class="n7-fcr"><h3>월별 FCR (최근 12개월)</h3>' +
    '<div class="mut">' + (typeof fmtD === 'function' ? fmtD(from) : from) + ' ~ ' + (typeof fmtD === 'function' ? fmtD(to) : to) + '</div>' +
    '<div class="def">' + anyMiss + '</div>' +
    '<div class="tw"><table class="t num"><tr><th>월</th><th>사료 사용 kg</th><th>사료 입고 kg</th><th>출하 체중 kg</th><th>출하 두수</th><th>FCR</th><th>자돈</th><th>육성</th><th>비육</th></tr>' +
    rows + '</table></div></div>';
  n7FstockTabs_(el, 'fcr');
  if (typeof xlAttach === 'function') xlAttach(el);
}
function n7DisMemo_(o) {
  return '[[소독]]장소=' + (o.place || '') + ';희석=' + (o.dilute || '') + ';방법=' + (o.method || '') + ';작업자=' + (o.staff || '') + ';비고=' + (o.memo || '');
}
function n7ParseDis_(row) {
  var m = String(row['비고'] || row.memo || '');
  if (m.indexOf('[[소독]]') !== 0) return null;
  var o = { date: row['입고일'] || row.date, drug: row['약품명'] || row.drug, qty: Number(row['수량'] || row.qty || 0), unit: row['단위'] || row.unit || '', id: row['입고ID'] || row.id, canEdit: !!row.canEdit };
  m.slice(6).split(';').forEach(function (p) {
    var i = p.indexOf('='); if (i < 0) return;
    o[({ '장소': 'place', '희석': 'dilute', '방법': 'method', '작업자': 'staff', '비고': 'memo' })[p.slice(0, i)] || p.slice(0, i)] = p.slice(i + 1);
  });
  return o;
}
function n7StaffNames_() {
  var a = [];
  try {
    var b = window.PL && PL.boot;
    var list = (b && (b.staff || b.users || b.members)) || [];
    list.forEach(function (s) { var n = s.name || s.displayName || s.staffName; if (n) a.push(n); });
  } catch (e) {}
  return a;
}
function n7DisinfectView_(el) {
  loading(el);
  var per = n7MonthKeys_(12);
  Promise.all([
    (typeof apiF === 'function') ? apiF('listInv', 'drug', { from: per.from, to: per.to }).catch(function () { return { rows: [] }; }) : { rows: [] },
    (typeof apiF === 'function') ? apiF('getFarmDrugs').catch(function () { return { items: [] }; }) : { items: [] },
    (typeof apiF === 'function') ? apiF('getInvStock').catch(function () { return { drugs: [] }; }) : { drugs: [] }
  ]).then(function (a) { n7DisinfectDraw_(el, a[0], a[1], a[2]); })
    .catch(function (e) { el.innerHTML = (typeof errHTML === 'function' ? errHTML(e) : '<div class="err">불러오지 못했습니다</div>'); });
}
function n7DisinfectDraw_(el, L, farm, stock) {
  var rows = ((L && L.rows) || []).map(n7ParseDis_).filter(Boolean);
  var items = ((farm && farm.items) || []).filter(function (x) { return x.active !== false; });
  var dis = items.filter(function (x) { return /소독/.test(x.major || '') || /소독/.test(x.cat || '') || /소독/.test(x.name || ''); });
  var names = (dis.length ? dis : items).map(function (x) { return x.name; });
  if (!names.length) names = ((stock && stock.drugs) || []).map(function (x) { return x.drug; }).filter(Boolean);
  var places = ['돈방', '축사', '차량', '출입구'];
  var methods = ['분무', '연무', '세척'];
  var staff = n7StaffNames_();
  var histDrug = (typeof n7HistTop_ === 'function') ? n7HistTop_('소독약', 5) : [];
  var histStaff = (typeof n7HistTop_ === 'function') ? n7HistTop_('작업자', 5) : [];
  var todayS = (typeof today === 'function') ? today() : new Date().toISOString().slice(0, 10);
  function chips(arr, name, extra) {
    var all = arr.slice();
    (extra || []).forEach(function (x) { if (x && all.indexOf(x) < 0) all.push(x); });
    return '<div class="n7-chips" data-k="' + name + '">' + all.map(function (v, i) {
      return '<button type="button" data-v="' + String(v).replace(/"/g, '&quot;') + '">' + (name === 'drug' || name === 'staff' ? (i + 1) + ' ' : '') + v + '</button>';
    }).join('') + '</div>';
  }
  function step(id, val, min, step) {
    return '<div class="n7-steprow stepper"><button type="button" class="btn sec step" data-d="-1" data-for="' + id + '">−</button><input id="' + id + '" type="number" min="' + (min == null ? 0 : min) + '" step="' + (step || 1) + '" value="' + val + '"><button type="button" class="btn sec step" data-d="1" data-for="' + id + '">＋</button></div>';
  }
  var farmN = n7FarmTitle_();
  var pr = n7MonthKeys_(12);
  var prA = rows.length ? rows[rows.length - 1].date : pr.from;
  var prB = rows.length ? rows[0].date : pr.to;
  function n7Fd_(x){ return (typeof fmtD === 'function') ? fmtD(x) : x; }
  var prRange = n7Fd_(prA) + ' ~ ' + n7Fd_(prB);
  var list = rows.length ? '<div class="tw"><table class="t"><tr><th>날짜</th><th>장소</th><th>소독약</th><th>희석배수</th><th>사용량</th><th>방법</th><th>작업자</th><th>비고</th></tr>' +
    rows.map(function (r) {
      return '<tr><td>' + (typeof fmtD === 'function' ? fmtD(r.date) : r.date) + '</td><td>' + (r.place || '') + '</td><td data-noi18n>' + (r.drug || '') + '</td><td>' + (r.dilute || '') + '</td><td>' + (r.qty || '') + (r.unit ? ' ' + r.unit : '') + '</td><td>' + (r.method || '') + '</td><td>' + (r.staff || '') + '</td><td>' + (r.memo || '') + '</td></tr>';
    }).join('') + '</table></div>' : '<div class="mut">아직 소독 기록이 없습니다</div>';
  el.innerHTML = '<div class="n7-dis"><h3>소독기록부</h3>' +
    '<div class="card noprint"><label class="l">날짜 *</label><div class="row" style="gap:8px;flex-wrap:wrap"><input id="n7-dd" type="date" value="' + todayS + '"><button type="button" class="btn sec" id="n7-dd-today">오늘</button></div>' +
    '<label class="l">장소 *</label>' + chips(places, 'place') +
    '<label class="l">소독약 * (농장 약품)</label>' + chips(names.slice(0, 24).concat(histDrug.map(function (x) { return x.v || x; })), 'drug') +
    '<input id="n7-ddrug" list="n7-ddrug-l" placeholder="소독약 이름"><datalist id="n7-ddrug-l">' + names.map(function (n) { return '<option value="' + String(n).replace(/"/g, '&quot;') + '">'; }).join('') + '</datalist>' +
    '<label class="l">희석배수</label>' + step('n7-ddil', 500, 0, 50) +
    '<label class="l">사용량 *</label>' + step('n7-dqty', 1, 0, 1) +
    '<label class="l">단위</label><select id="n7-du"><option>L</option><option>mL</option><option>kg</option><option>g</option><option>병</option><option>개</option></select>' +
    '<label class="l">방법 *</label>' + chips(methods, 'method') +
    '<label class="l">작업자</label>' + chips(staff.concat(histStaff.map(function (x) { return x.v || x; })), 'staff') +
    '<input id="n7-dstaff" placeholder="작업자 이름">' +
    '<label class="l">비고</label><textarea id="n7-dmemo" maxlength="200" rows="2"></textarea>' +
    '<div id="n7-dmsg"></div>' +
    '<div class="row" style="gap:8px;margin-top:10px"><button type="button" class="btn" id="n7-dsave">저장하고 재고에서 빼기</button><button type="button" class="btn sec" id="n7-dprint">인쇄 (HACCP 기록)</button></div></div>' +
    '<div class="card"><h3>기록 목록</h3>' + list + '</div>' +
    '<div class="n7-dis-print" id="n7-dprintv"><h2>소독기록부 (HACCP)</h2><div>' + (farmN || '') + ' · ' + prRange + '</div>' + list + '<div class="mut" style="margin-top:12px">확인: ______________ 　 작성: ______________</div></div></div>';
  n7FstockTabs_(el, 'disinfect');
  var st = { place: '', method: '', drug: '' };
  el.querySelectorAll('.n7-chips').forEach(function (g) {
    g.addEventListener('click', function (e) {
      var b = e.target.closest && e.target.closest('button[data-v]'); if (!b) return;
      var k = g.getAttribute('data-k'), v = b.getAttribute('data-v');
      st[k] = v;
      g.querySelectorAll('button').forEach(function (x) { x.classList.toggle('on', x === b); });
      if (k === 'drug') { var inp = document.getElementById('n7-ddrug'); if (inp) inp.value = v; }
      if (k === 'staff') { var s = document.getElementById('n7-dstaff'); if (s) s.value = v; }
    });
  });
  var td = document.getElementById('n7-dd-today');
  if (td) td.onclick = function () { document.getElementById('n7-dd').value = todayS; };
  el.addEventListener('click', function (e) {
    var b = e.target.closest && e.target.closest('.n7-steprow .step'); if (!b || !el.contains(b)) return;
    var id = b.getAttribute('data-for'); var i = document.getElementById(id); if (!i) return;
    var step = parseFloat(i.step); if (!step || isNaN(step)) step = 1;
    var d = Number(b.getAttribute('data-d') || 0);
    var v = Number(i.value); if (isNaN(v)) v = 0;
    var nv = v + d * step;
    var min = i.min === '' ? 0 : Number(i.min);
    if (nv < min) nv = min;
    i.value = (Math.abs(step - Math.round(step)) < 1e-9) ? String(Math.round(nv)) : String(Math.round(nv * 100) / 100);
  });
  document.getElementById('n7-dsave').onclick = function () {
    var date = document.getElementById('n7-dd').value;
    var drug = (document.getElementById('n7-ddrug').value || st.drug || '').trim();
    var qty = Number(document.getElementById('n7-dqty').value);
    var unit = document.getElementById('n7-du').value;
    var dilute = document.getElementById('n7-ddil').value;
    var place = st.place, method = st.method;
    var staffV = (document.getElementById('n7-dstaff').value || '').trim();
    var memo = (document.getElementById('n7-dmemo').value || '').trim();
    var msg = document.getElementById('n7-dmsg');
    function err(t) { msg.innerHTML = '<div class="err">' + t + '</div>'; }
    if (!date) return err('날짜를 고르세요.');
    if (!place) return err('장소를 고르세요.');
    if (!drug) return err('소독약을 고르거나 이름을 적으세요.');
    if (!(qty > 0)) return err('사용량을 0보다 크게 적으세요.');
    if (!method) return err('방법을 고르세요.');
    var x = { date: date, drug: drug, qty: qty, unit: unit, out: true, cat: '소독제', memo: n7DisMemo_({ place: place, dilute: dilute, method: method, staff: staffV, memo: memo }), reqId: (typeof uuid === 'function' ? uuid() : 'dis-' + Date.now()) };
    var btn = this; btn.disabled = true;
    apiF('saveInv', 'drug', x).then(function () {
      btn.disabled = false;
      if (typeof n7HistAdd_ === 'function') { n7HistAdd_('소독약', drug); if (staffV) n7HistAdd_('작업자', staffV); }
      if (typeof toast === 'function') toast('저장했습니다. 약품 재고에서 뺐습니다.');
      n7DisinfectView_(el);
    }).catch(function (e) { btn.disabled = false; msg.innerHTML = (typeof errHTML === 'function' ? errHTML(e) : '<div class="err">저장하지 못했습니다</div>'); });
  };
  document.getElementById('n7-dprint').onclick = function () {
    document.body.classList.add('n7-print-dis');
    try { window.print(); } finally { setTimeout(function () { document.body.classList.remove('n7-print-dis'); }, 400); }
  };
}


function n7HookGo_() {
  var wrap = function (fn) {
    if (typeof fn !== 'function' || fn._n7v) return fn;
    var w = function (p, arg) {
      var r = fn.apply(this, arguments);
      setTimeout(function () { n7AfterGo_(p); }, 0);
      setTimeout(function () { n7AfterGo_(p); }, 200);
      return r;
    };
    w._n7v = 1;
    return w;
  };
  if (typeof go === 'function') {
    go = wrap(go);
    if (window.PL) PL.go = go;
  } else if (window.PL && typeof PL.go === 'function') {
    PL.go = wrap(PL.go);
  }
  function wrapShell(name) {
    var fn = typeof window[name] === 'function' ? window[name] : (typeof eval !== 'undefined' && typeof window !== 'undefined' ? null : null);
    fn = (name === 'wShell' && typeof wShell === 'function') ? wShell : (name === 'mShell' && typeof mShell === 'function') ? mShell : null;
    if (!fn || fn._n7go) return;
    var _s = fn;
    var w = function () { var r = _s.apply(this, arguments); n7HookGo_(); return r; };
    w._n7go = 1;
    if (name === 'wShell') wShell = w;
    if (name === 'mShell') mShell = w;
    if (window.PL && PL.reshell === _s) PL.reshell = w;
  }
  wrapShell('wShell');
  wrapShell('mShell');
}

function n7EntrySaveGate_(root) {
  /* t528: never disable save for missing fields. #ef-sow is a status div, not the tag. */
  if (typeof isVet === 'function' && isVet()) return;
  var box = (root && root.querySelector) ? (root.querySelector('.entry') || (root.classList && root.classList.contains('entry') ? root : null)) : null;
  if (!box) box = document.querySelector('.entry');
  if (!box) return;
  var btns = [];
  function add(b) { if (b && btns.indexOf(b) < 0) btns.push(b); }
  add(document.getElementById('ef-save'));
  add(document.getElementById('n7-abar-save'));
  box.querySelectorAll('button.savebtn').forEach(add);
  btns.forEach(function (b) {
    if (b.getAttribute('data-vet-lock') || b.getAttribute('data-flight')) return;
    b.disabled = false;
    b.removeAttribute('aria-disabled');
    var ti = b.getAttribute('title') || '';
    if (ti === '모돈번호를 입력하세요' || /총산|사산|실산|생시도태/.test(ti)) b.removeAttribute('title');
  });
}
function n7EntryCtrl_(lab, box) {
  if (!lab || !box) return null;
  var n = lab.nextElementSibling;
  if (n && (n.matches('input, select, textarea, .seg, .cz, .n7-br, .row, .ef-row, .stepper, .n7-ageg') || n.querySelector)) {
    var c = n.matches('input, select, textarea') ? n : (n.querySelector && n.querySelector('input, select, textarea, .seg, .n7-br'));
    if (c) return c;
    if (n.matches('.seg, .cz, .n7-br')) return n;
  }
  var k = '';
  var fb = lab.parentNode && lab.parentNode.querySelector && lab.parentNode.querySelector('[data-k], #ef-tag, #ef-date');
  return fb || null;
}
function n7EntryMissing_(box) {
  var miss = [];
  if (!box) return miss;
  var typ = (window.PL && PL._entType) || '';
  var typBtn = document.querySelector('#en-t button.on, [data-t].on');
  if (!typ && typBtn) typ = typBtn.getAttribute('data-t') || typBtn.getAttribute('data-type') || '';
  function add(el, label) {
    var lab = String(label || '').replace(/\s*\*\s*/g, '').replace(/\s+/g, ' ').trim();
    if (!lab) return;
    for (var i = 0; i < miss.length; i++) if (miss[i].label === lab) return;
    miss.push({ el: el, label: lab });
  }
  var tag = box.querySelector('#ef-tag, input.tagin, [data-k="모돈번호"]');
  if (tag && tag.id === 'ef-sow') tag = box.querySelector('#ef-tag');
  if (typ !== '자돈폐사' && (!tag || !String(tag.value || '').trim())) add(tag || box.querySelector('#ef-tag'), '모돈번호');
  var date = box.querySelector('#ef-date, input[type="date"][id="ef-date"]');
  if (!date) date = box.querySelector('input[type="date"]');
  if (!date || !String(date.value || '').trim()) add(date, '작업일');
  box.querySelectorAll('label.l').forEach(function (lab) {
    var txt = (lab.textContent || '').replace(/\s+/g, ' ').trim();
    if (!/\*/.test(txt) && !lab.querySelector('.n7-req')) return;
    if (/모돈번호|작업일|애칭|특징|비고/.test(txt) && !/품종/.test(txt)) return;
    var ctrl = n7EntryCtrl_(lab, box);
    if (!ctrl) return;
    var v = '';
    if (ctrl.tagName === 'INPUT' || ctrl.tagName === 'SELECT' || ctrl.tagName === 'TEXTAREA') v = String(ctrl.value || '').trim();
    else if (ctrl.classList && (ctrl.classList.contains('seg') || ctrl.querySelector && ctrl.querySelector('.seg, button.on'))) {
      var on = (ctrl.matches && ctrl.matches('.seg') ? ctrl : ctrl.querySelector('.seg'));
      var b = (on || ctrl).querySelector('button.on');
      v = b ? (b.getAttribute('data-v') != null ? b.getAttribute('data-v') : b.textContent) : '';
    } else v = String(ctrl.value || '').trim();
    if (v === '') add(ctrl, txt);
  });
  if (typ === '전입') {
    var br = box.querySelector('[data-k="품종"]');
    var bv = br ? String(br.value || br.getAttribute('data-v') || '').trim() : '';
    if (!br) {
      var onb = box.querySelector('.n7-br button.on, .ef-breed-hl button.on, [data-k="품종"] button.on');
      if (onb) bv = (onb.getAttribute('data-v') || onb.textContent || '').trim();
      br = box.querySelector('.n7-br, .ef-breed-hl') || onb;
    }
    if (!bv) add(br || box.querySelector('.n7-br, .ef-breed-hl'), '품종');
  }
  return miss;
}
function n7EntryShowMiss_(box, miss) {
  if (!box || !miss || !miss.length) return;
  var save = box.querySelector('#ef-save') || document.getElementById('ef-save');
  var msg = box.querySelector('#ef-msg') || document.getElementById('ef-msg');
  if (!msg && save && save.parentNode) {
    msg = document.createElement('div');
    msg.id = 'ef-msg';
    save.parentNode.insertBefore(msg, save);
  }
  if (msg && save && msg.nextElementSibling !== save && save.parentNode) save.parentNode.insertBefore(msg, save);
  var names = miss.map(function (m) { return m.label; });
  if (msg) msg.innerHTML = '<div class="err n7-miss" role="alert">다음을 입력해 주세요: ' + names.join(', ') + '</div>';
  var saveBtn = box.querySelector('#ef-save') || document.getElementById('ef-save');
  if (saveBtn) {
    var lbl = saveBtn.getAttribute('data-n7lbl');
    if (lbl) saveBtn.textContent = lbl;
    else if (/저장 중/.test(saveBtn.textContent || '')) saveBtn.textContent = (saveBtn.getAttribute('data-old') || saveBtn.textContent || '저장').replace(/저장 중…/, '저장');
    saveBtn.disabled = false;
    saveBtn.removeAttribute('data-flight');
  }
  box.querySelectorAll('.bad').forEach(function (n) { n.classList.remove('bad'); });
  var first = miss[0] && miss[0].el;
  if (first) {
    first.classList.add('bad');
    var wrap = first.closest && (first.closest('.n7-f, .ef-row, .row, .n7-br, .n7-ageg') || first);
    if (wrap && wrap.classList) wrap.classList.add('bad');
    try { first.scrollIntoView({ block: 'center', behavior: 'smooth' }); } catch (e1) { try { first.scrollIntoView(); } catch (e2) {} }
    try { if (first.focus) first.focus(); } catch (e3) {}
  }
}
function n7EntryValidateBind_() {
  if (document._n7ev) return;
  document._n7ev = 1;
  document.addEventListener('click', function (e) {
    var b = e.target && e.target.closest && e.target.closest('#ef-save, #n7-abar-save, button.savebtn');
    if (!b) return;
    if (b.getAttribute('data-vet-lock') || b.getAttribute('data-flight')) return;
    if (b._n7valok) { b._n7valok = 0; return; }
    var box = (b.closest && b.closest('.entry')) || document.querySelector('.entry');
    if (!box) return;
    var miss = n7EntryMissing_(box);
    if (!miss.length) return;
    e.preventDefault();
    e.stopImmediatePropagation();
    n7EntryShowMiss_(box, miss);
  }, true);
}
function n7EntrySaveGateBind_() {
  if (document._n7sg) return;
  document._n7sg = 1;
  var tick = function () { try { n7EntrySaveGate_(); } catch (e) {} };
  document.addEventListener('input', function (e) {
    if (e.target && e.target.closest && e.target.closest('.entry, #n7-abar')) tick();
  }, true);
  document.addEventListener('click', function (e) {
    if (e.target && e.target.closest && e.target.closest('#en-t, .entry .step, .entry .tapb')) setTimeout(tick, 0);
  }, true);
  try { n7EntryValidateBind_(); } catch (eV) {}
}

function n7AfterGo_(p) {
  try { if (typeof lockVetSave_ === 'function') lockVetSave_(document); } catch (eV) {}
  try { n7EntrySaveGateBind_(); n7EntrySaveGate_(document); } catch (eSg) {}
  n7ViewMark_();
  n7ThemeInit_();
  if (typeof n7HistInstall_ === 'function') n7HistInstall_();
  if (typeof n7StaffWatch_ === 'function') n7StaffWatch_();
  if (typeof n7SignupHint_ === 'function') n7SignupHint_();
  var _host = (typeof n7PageHost_ === 'function' ? n7PageHost_() : (document.getElementById('w-main') || document.getElementById('m-main') || document.getElementById('app') || document.body));
  if (typeof n7PolishEntryT447_ === 'function' && _host) {
    var _ent = _host.querySelector('.entry') || _host;
    n7PolishEntryT447_(_host, { type: (PL && PL._entType) || '' });
  }
  if (typeof n7LookFix_ === 'function' && _host) n7LookFix_(_host);
  if (typeof n7HookGuards_ === 'function') n7HookGuards_();
  if (typeof n7HookSlowPages_ === 'function') n7HookSlowPages_();
  if (typeof n7FieldHist_ === 'function') n7FieldHist_();
  n7SubHead_(p || (PL && PL._page));
  n7WatchAbar_();
  n7ActionBar_(p || (PL && PL._page));
  if (typeof n7FieldHomeTiles_ === 'function') n7FieldHomeTiles_();
  n7PolishSettings_(document.getElementById('m-main') || document.getElementById('app') || document.body);
  n7PolishStaff_(document.getElementById('m-main') || document.getElementById('app') || document.body);
  n7BoardTmap_(p || (PL && PL._page));
  if (typeof n7HookImport_ === 'function') n7HookImport_();
  if (typeof n7HookFstock_ === 'function') n7HookFstock_();
  if (typeof n7RenameStockTab_ === 'function') n7RenameStockTab_();
  if (typeof n7HookLocPicker_ === 'function') n7HookLocPicker_();
  if (typeof n7HookPages_ === 'function') n7HookPages_();
  if (typeof n7TabRecLbl_ === 'function') n7TabRecLbl_();
  if (typeof n7HookRoleLbl_ === 'function') n7HookRoleLbl_();
  if (typeof n7SowBarSync_ === 'function') n7SowBarSync_(p || (PL && PL._page));
  if (typeof n7VaccWatch_ === 'function') n7VaccWatch_(_host, p || (PL && PL._page));
  else if (typeof n7VaccWeekMount_ === 'function') n7VaccWeekMount_(_host, p || (PL && PL._page));
  if (typeof n7WeekLabels_ === 'function') n7WeekLabels_(_host);
  if (typeof n7HookShip_ === 'function') n7HookShip_();
  if (typeof n7HookReport_ === 'function') n7HookReport_();
  if (typeof n7RenameShipMenu_ === 'function') n7RenameShipMenu_(_host);
  var _pg = p || (PL && PL._page);
  if (_host && (_pg === 'ship' || _pg === 'rep' || _pg === 'home' || _pg === 'kpi')) {
    var n7Later_ = function (n) {
      if (_pg === 'ship' && typeof n7ShipEnsure_ === 'function') n7ShipEnsure_(_host, n);
      if (_pg === 'rep' && typeof n7PolishReport_ === 'function') {
        n7HookReport_();
        n7PolishReport_(n7PageHost_(_host) || _host);
        if (!(n7PageHost_(_host) || _host).querySelector('#n7-rp-split') && (n || 0) < 40) setTimeout(function () { n7Later_((n || 0) + 1); }, 120);
      }
      if (typeof n7MotionDash_ === 'function') n7MotionDash_(_host);
    };
    setTimeout(function () { n7Later_(0); }, 80);
  }
  if (typeof n7DeskLayout_ === 'function') {
    n7DeskLayout_(p || (PL && PL._page));
    setTimeout(function () { n7DeskLayout_(p || (PL && PL._page)); }, 400);
  }
}
function n7LocVal_(root) {
  var free = root && root.querySelector('.n7-dest-loc');
  if (free && String(free.value || '').trim()) return String(free.value).trim();
  var pick = root && root.querySelector('.locpick');
  if (!pick) return '';
  var bs = pick.querySelector('[data-lv="b"]'), rs = pick.querySelector('[data-lv="r"]'), ss = pick.querySelector('[data-lv="s"]');
  return (ss && ss.value && rs && rs.value) ? (rs.value + '-S' + ('0' + ss.value).slice(-2)) : ((rs && rs.value) || (bs && bs.value) || '');
}
function n7HookLocPicker_() {
  if (typeof locPickerHTML === 'function' && !locPickerHTML._n7) {
    var _lp = locPickerHTML;
    locPickerHTML = function (type, cur) {
      var html = _lp(type, cur);
      if (html) return html;
      if (type !== '이동') return html;
      var recent = (typeof n7HistTop_ === 'function') ? n7HistTop_('위치', 3) : [];
      var esc = (typeof n7EscAttr_ === 'function') ? n7EscAttr_ : function (s) { return String(s == null ? '' : s).replace(/[&<>"']/g, function (c) { return ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;' })[c]; }); };
      var chips = recent.length ? ('<div class="n7-sug n7-dest-chips">' + recent.map(function (v) {
        return '<button type="button" data-v="' + esc(v) + '">' + esc(v) + '</button>';
      }).join('') + '</div>') : '';
      return '<label class="l">어디로 (선택)</label><div class="n7-destfree">'
        + '<div class="mut">이 농장은 방이 등록되어 있지 않습니다. <a href="#" id="n7-dest-struct">농장 구조 등록</a></div>'
        + '<input type="text" class="n7-dest-loc" maxlength="40" placeholder="위치 메모" value="' + esc(cur || '') + '">'
        + chips + '</div>';
    };
    locPickerHTML._n7 = 1;
  }
  if (typeof bindLocPicker === 'function' && !bindLocPicker._n7) {
    var _bp = bindLocPicker;
    bindLocPicker = function (root) {
      var p = _bp(root);
      if (p) return p;
      var inp = root && root.querySelector('.n7-dest-loc');
      if (!inp) return null;
      var chips = root.querySelector('.n7-dest-chips');
      if (chips && !chips.getAttribute('data-on')) {
        chips.setAttribute('data-on', '1');
        chips.addEventListener('click', function (e) {
          var b = e.target.closest && e.target.closest('button[data-v]');
          if (!b) return;
          inp.value = b.getAttribute('data-v') || '';
        });
      }
      var a = root.querySelector('#n7-dest-struct');
      if (a && !a.getAttribute('data-on')) {
        a.setAttribute('data-on', '1');
        a.onclick = function (e) { e.preventDefault(); (PL.go || window.go)('struct'); };
      }
      return { get: function () { return String(inp.value || '').trim(); }, suggest: function (code) { if (!inp.value) inp.value = code || ''; } };
    };
    bindLocPicker._n7 = 1;
  }
}
function n7MoveReq_(el) {
  n7HookLocPicker_();
  var hasRooms = el.querySelector('.locpick');
  var labs = el.querySelectorAll('label.l');
  for (var i = 0; i < labs.length; i++) {
    var tx = labs[i].textContent || '';
    if (tx.indexOf('위치') >= 0 || tx.indexOf('돈사') >= 0 || tx.indexOf('목적지') >= 0 || tx.indexOf('어디로') >= 0) {
      labs[i].textContent = hasRooms ? '목적지 *' : '어디로 (선택)';
      break;
    }
  }
  var save = el.querySelector('#ef-save');
  if (!save || save.getAttribute('data-n7loc')) return;
  save.setAttribute('data-n7loc', '1');
  function block(ev, msg, focus) {
    ev.preventDefault();
    ev.stopImmediatePropagation();
    if (typeof toast === 'function') toast(msg);
    if (focus) try { focus.focus(); } catch (e) {}
    return false;
  }
  save.addEventListener('click', function (ev) {
    var tag = el.querySelector('#ef-tag');
    var tagV = tag ? String(tag.value || '').trim() : '';
    var dest = n7LocVal_(el);
    if (!tagV && !dest) return block(ev, '모돈번호나 목적지를 적으세요', tag || el.querySelector('.n7-dest-loc'));
    if (hasRooms && !dest) return block(ev, '목적지를 고르세요', el.querySelector('[data-lv="b"]'));
  }, true);
  var abar = document.getElementById('n7-abar-save');
  if (abar && !abar.getAttribute('data-n7loc')) {
    abar.setAttribute('data-n7loc', '1');
    abar.addEventListener('click', function () { /* save.click already hooked */ }, true);
  }
}
function n7PolishSettings_(root) {
  var tbl = root && root.querySelector('#st-go') && root.querySelector('table.t');
  if (!tbl) { if (typeof n7StaffCards_ === 'function') n7StaffCards_(root); return; }
  if (root.querySelector('.n7-st-find')) { if (typeof n7StaffCards_ === 'function') n7StaffCards_(root); return; }
  var card = tbl.closest('.card') || tbl.parentNode;
  var find = document.createElement('div');
  find.className = 'n7-st-find';
  find.innerHTML = '<input type="search" id="n7-st-q" placeholder="설정 찾기" aria-label="설정 찾기">';
  card.insertBefore(find, tbl.parentNode === card ? tbl : tbl.parentNode);
  var q = find.querySelector('input');
  q.oninput = function () {
    var s = q.value.replace(/\s+/g, '').toLowerCase();
    Array.prototype.forEach.call(tbl.rows, function (r, i) {
      if (!i) return;
      var t = (r.textContent || '').replace(/\s+/g, '').toLowerCase();
      r.style.display = !s || t.indexOf(s) >= 0 ? '' : 'none';
    });
  };
  var go = root.querySelector('#st-go');
  if (go && !root.querySelector('.n7-savebar')) {
    var bar = document.createElement('div');
    bar.className = 'n7-savebar';
    go.parentNode.insertBefore(bar, go);
    bar.appendChild(go);
  }
  if (typeof n7SettingsHub_ === 'function') n7SettingsHub_(root);
  if (typeof n7DangerConfirm_ === 'function') n7DangerConfirm_(root);
  if (typeof n7SettingsControls_ === 'function') n7SettingsControls_(root);
  if (typeof n7FarmTzCtl_ === 'function') n7FarmTzCtl_(root);
  if (typeof n7CertCard_ === 'function') n7CertCard_(root);
  if (typeof n7SyncCard_ === 'function') n7SyncCard_(root);
  if (typeof n7StaffCards_ === 'function') n7StaffCards_(root);
}

function n7Pm_(on) { return on ? '<span class="pm full">○</span>' : '<span class="pm none">—</span>'; }
function n7RoleCardHTML_() {
  var o = n7Pm_(1), x = n7Pm_(0);
  return '<div class="n7-rolecard"><b>역할별로 할 수 있는 일</b><table><tr><th>일</th><th>작업자</th><th>부관리자</th><th>농장 관리자</th><th>농장주</th><th>운영자</th></tr>'
    + '<tr><td>기록 입력·모돈·예정</td><td>' + o + '</td><td>' + o + '</td><td>' + o + '</td><td>' + o + '</td><td>' + o + '</td></tr>'
    + '<tr><td>성적·주간 리포트·가져오기</td><td>' + x + '</td><td>' + x + '</td><td>' + o + '</td><td>' + o + '</td><td>' + o + '</td></tr>'
    + '<tr><td>약품 입고·재고</td><td>' + x + '</td><td>' + o + '</td><td>' + x + '</td><td>' + o + '</td><td>' + o + '</td></tr>'
    + '<tr><td>농장 목표·구조·인증</td><td>' + x + '</td><td>' + x + '</td><td>' + o + '</td><td>' + o + '</td><td>' + o + '</td></tr>'
    + '<tr><td>전체 농장·계정 관리</td><td>' + x + '</td><td>' + x + '</td><td>' + x + '</td><td>' + x + '</td><td>' + o + '</td></tr></table>'
    + '<div class="mut" style="margin-top:6px">운영자는 피그로그 플랫폼 운영자입니다. 농장 관리자는 그 농장의 관리 직급입니다.</div></div>';
}
function n7PolishStaff_(root) {
  var box = (root && (root.querySelector('#org-staff') || root.querySelector('#st-staff') || (root.id === 'org-staff' || root.id === 'st-staff' ? root : null))) || null;
  if (!box) {
    var h = root && root.querySelector && root.querySelector('h3');
    if (h && /직원/.test(h.textContent || '')) box = h.parentNode;
  }
  if (!box) return;
  if (!box.querySelector('.n7-rolecard')) {
    var h3 = box.querySelector('h3');
    if (h3) {
      var card = document.createElement('div');
      card.innerHTML = n7RoleCardHTML_();
      h3.parentNode.insertBefore(card.firstChild, h3.nextSibling);
    }
  }
  n7StaffMenu_(box);
  if (typeof n7StaffCards_ === 'function') n7StaffCards_(root || box);
}
function n7StaffMenu_(box) {
  Array.prototype.forEach.call(box.querySelectorAll('table.t tr'), function (tr, i) {
    if (!i) return;
    var cell = tr.cells[tr.cells.length - 1];
    if (!cell || cell.querySelector('.n7-dots')) return;
    var btns = cell.querySelectorAll('button');
    if (!btns.length) return;
    cell.classList.add('n7-staff-act');
    var wrap = document.createElement('span');
    wrap.className = 'n7-dots';
    wrap.innerHTML = '<button type="button" class="n7-morebtn" aria-label="더보기">⋯</button><div class="n7-menu"></div>';
    var menu = wrap.querySelector('.n7-menu');
    Array.prototype.forEach.call(btns, function (b) {
      var c = b.cloneNode(true);
      if (/지우기|퇴사|삭제/.test(b.textContent || '') || b.getAttribute('data-quit') || b.getAttribute('data-del')) c.classList.add('n7-dang');
      menu.appendChild(c);
    });
    wrap.querySelector('.n7-morebtn').onclick = function (e) {
      e.stopPropagation();
      var open = wrap.classList.contains('open');
      Array.prototype.forEach.call(box.querySelectorAll('.n7-dots.open'), function (x) { x.classList.remove('open'); });
      wrap.classList.toggle('open', !open);
    };
    cell.appendChild(wrap);
  });
}
function n7SowsOf_(r) { return (r && (r.items || r.sows || r.rows)) || []; }
function n7StructRooms_(st) {
  var rooms = [], L = (window.PL && PL.boot && PL.boot.locs) || [];
  if (L.length) L.filter(function (x) { return x.level === 'room'; }).forEach(function (r) { rooms.push(r); });
  if (rooms.length) return rooms;
  if (!st) return rooms;
  if (st.locs) return (st.locs || []).filter(function (x) { return x.level === 'room'; });
  (st.barns || []).forEach(function (b) {
    (b.rooms || []).forEach(function (r) {
      rooms.push({ code: r.code, name: r.name || r.label, label: r.label, parent: b.code || r.parent, stalls: r.stalls || r.cap || 0, cap: r.cap || r.stalls || 0 });
    });
  });
  return rooms;
}
function n7HasRooms_(st) { return n7StructRooms_(st).length > 0; }
function n7OdCol_(n) {
  n = n || 0;
  return n <= 0 ? 'n7-tc-od0' : n <= 2 ? 'n7-tc-od1' : n <= 5 ? 'n7-tc-od2' : n <= 10 ? 'n7-tc-od3' : 'n7-tc-od4';
}
function n7TmapKey_(s, rooms) {
  var loc = String(s.loc || '').trim();
  if (!loc || loc === '위치 없음' || loc === '위치 미지정') return '위치 미지정';
  if (rooms && rooms.length) {
    var m = loc.match(/^(B\d+(?:-[RH]\d+)?)/);
    if (m) return m[1];
    return loc;
  }
  return loc || (s.state || '상태 없음');
}
function n7BoardTmap_(p) {
  if (p && p !== 'board') return;
  var root = document.getElementById('w-main') || document.getElementById('m-main') || document.getElementById('app');
  if (!root) return;
  var body = root.querySelector('#sb-body');
  if (!body) return;
  var host = root.querySelector('#n7-tmap');
  if (!host) {
    host = document.createElement('div');
    host.id = 'n7-tmap'; host.className = 'card n7-tmap';
    body.parentNode.insertBefore(host, body.parentNode.firstChild === body ? body : body.parentNode.firstChild);
    if (host.parentNode.firstChild !== host) body.parentNode.insertBefore(host, body.parentNode.firstChild);
  }
  if (!host.getAttribute('data-ready')) host.innerHTML = '<h3>돈방 두수</h3><div class="mut">불러오는 중…</div>';
  var call = function (fn, a, b) {
    if (typeof apiF === 'function') return apiF(fn, a, b);
    if (typeof apiR === 'function') return apiR(fn, a);
    return Promise.reject(new Error('noapi'));
  };
  var headsP = call('roomHeadCounts').catch(function () { return null; });
  var stP = call('getFarmStructure').catch(function () { return null; });
  var dueP = call('getDueList', {}).catch(function () { return null; });
  var to = new Promise(function (res) { setTimeout(function () { res('timeout'); }, 8000); });
  Promise.race([Promise.all([headsP, stP, dueP]), to]).then(function (a) {
    if (a === 'timeout') {
      if (!host.getAttribute('data-ready')) {
        host.innerHTML = '<h3>돈방 두수</h3><div class="n7-tmap-err"><b>두수를 다시 불러 주세요</b><p>시간이 너무 오래 걸립니다.</p><button type="button" class="btn" id="n7-tmap-retry">다시 시도</button></div>';
        var rb = host.querySelector('#n7-tmap-retry');
        if (rb) rb.onclick = function () { host.removeAttribute('data-ready'); n7BoardTmap_('board'); };
      }
      return;
    }
    var rooms = (a[0] && a[0].rooms) || [];
    var sows = [];
    rooms.forEach(function (x) {
      var n = Number(x.n) || 0, i;
      for (i = 0; i < n; i++) sows.push({ loc: x.loc || '' });
    });
    n7DrawTmap_(host, { sows: sows, struct: a[1], due: a[2] });
    if (host.querySelector('.n7-tcell, .n7-tmap-empty')) host.setAttribute('data-ready', '1');
  }).catch(function (e) {
    var msg = (typeof uiMsg === 'function' ? uiMsg(e) : (e && e.message) || '');
    host.innerHTML = '<h3>돈방 두수</h3><div class="n7-tmap-err"><b>두수를 다시 불러 주세요</b><p>' + (msg ? n7Esc_(msg) : '목록을 받지 못했습니다.') + '</p><button type="button" class="btn" id="n7-tmap-retry">다시 시도</button></div>';
    var b = host.querySelector('#n7-tmap-retry');
    if (b) b.onclick = function () { host.removeAttribute('data-ready'); n7BoardTmap_('board'); };
  });
}
function n7DrawTmap_(host, d) {
  var sows = (d && d.sows) || [];
  var rooms = n7StructRooms_(d && d.struct);
  var dues = ((d && d.due && d.due.items) || []);
  function esc(s) { return String(s == null ? '' : s).replace(/[&<>"']/g, function (c) { return ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;' })[c]; }); }
  if (!sows.length && !rooms.length) {
    host.innerHTML = '<h3>돈방 두수</h3><div class="n7-tmap-empty"><b>아직 그릴 두수가 없습니다</b><p>모돈을 등록하거나 농장 구조를 넣으면 칸이 생깁니다.</p><div class="row" style="gap:8px;flex-wrap:wrap"><button type="button" class="btn sec" id="n7-tmap-status">단계별로 보기</button><button type="button" class="btn" id="n7-tmap-struct">농장 구조 등록</button></div></div>';
    var st = host.querySelector('#n7-tmap-struct'); if (st) st.onclick = function () { (PL.go || window.go)('struct'); };
    var st2 = host.querySelector('#n7-tmap-status'); if (st2) st2.onclick = function () { (PL.go || window.go)('sows'); };
    return;
  }
  var by = {}, od = {}, labs = {}, caps = {};
  var roomBy = {};
  rooms.forEach(function (r) { roomBy[r.code] = r; labs[r.code] = r.name || r.label || r.code; caps[r.code] = r.stalls || r.cap || 0; });
  sows.forEach(function (s) {
    var k = n7TmapKey_(s, rooms);
    by[k] = (by[k] || 0) + 1;
    if (!labs[k]) labs[k] = k;
  });
  dues.forEach(function (x) {
    if (!(x.overdue || (typeof x.daysLeft === 'number' && x.daysLeft < 0))) return;
    var k = n7TmapKey_(x, rooms);
    od[k] = (od[k] || 0) + 1;
  });
  var unspec = by['위치 미지정'] || 0;
  delete by['위치 미지정'];
  var groups = Object.keys(by);
  if (rooms.length) {
    rooms.forEach(function (r) { if (groups.indexOf(r.code) < 0) groups.push(r.code); });
  }
  if (!groups.length) {
    host.innerHTML = '<h3>돈방 두수</h3><div class="n7-tmap-empty"><b>아직 그릴 두수가 없습니다</b></div>';
    return;
  }
  groups.sort(function (a, b) { return (by[b] || 0) - (by[a] || 0); });
  var useCap = rooms.length && groups.some(function (k) { return caps[k] > 0; });
  var barg = {};
  groups.forEach(function (k) {
    var barn = '위치';
    if (rooms.length && roomBy[k]) barn = roomBy[k].parent || String(k).split('-')[0] || '위치';
    else if (!rooms.length) barn = '묶음';
    if (!barg[barn]) barg[barn] = [];
    barg[barn].push(k);
  });
  var leg = useCap
    ? '칸 크기는 두수, 색은 사용 두수와 스톨 대비입니다.'
    : '칸 크기는 두수, 색은 지난 예정 작업 수입니다. (0 진파랑 · 1–2 연파랑 · 3–5 주황 · 6–10 주홍 · 11+ 진주홍)';
  var h = '<h3>돈방 두수</h3><div class="n7-tmap-leg">' + leg + '</div>';
  if (unspec) h += '<div class="n7-tmap-unspec" style="margin:6px 0 10px;padding:8px 10px;border:1px dashed var(--line,#d5e0d8);border-radius:8px;font-size:13px">위치 미지정 <b>' + unspec + '두</b> — 방 위치가 아직 없는 모돈입니다. 아래 칸 그림에는 넣지 않았습니다.</div>';
  Object.keys(barg).forEach(function (b) {
    var bl = ((window.PL && PL.boot && PL.boot.locs) || []).filter(function (x) { return x.code === b; })[0];
    h += '<div class="n7-tmap-b"><b>' + esc((bl && (bl.name || bl.label)) || b) + '</b><div class="n7-tmap-g n7-tmap-flex">';
    barg[b].forEach(function (k) {
      var nhead = by[k] || 0, nOd = od[k] || 0, cap = caps[k] || 0;
      var cls = useCap ? (function () {
        if (!nhead) return 'n7-tc0';
        if (!cap) return n7OdCol_(nOd);
        var r = nhead / cap;
        return r < .5 ? 'n7-tc1' : r < .85 ? 'n7-tc2' : r < 1 ? 'n7-tc3' : r < 1.15 ? 'n7-tc4' : 'n7-tc5';
      })() : n7OdCol_(nOd);
      var sub = nhead + '두' + (useCap && cap ? ' / ' + cap : '') + (nOd ? ' · 지남 ' + nOd : '');
      h += '<button type="button" class="n7-tcell ' + cls + '" style="--n:' + Math.max(1, nhead) + '" data-loc="' + esc(k) + '"><span class="n">' + esc(labs[k] || k) + '</span><span class="h">' + sub + '</span></button>';
    });
    h += '</div></div>';
  });
  host.innerHTML = h;
  Array.prototype.forEach.call(host.querySelectorAll('[data-loc]'), function (btn) {
    btn.onclick = function () {
      var sel = document.getElementById('sb-loc');
      if (sel) { sel.value = btn.getAttribute('data-loc'); var go = document.getElementById('sb-go'); if (go) go.click(); }
    };
  });
}
function n7TabRecLbl_() {
  if (window.TABS) TABS.forEach(function (t) { if (t[0] === 'entry') t[1] = '기록'; });
  var lab = document.querySelector('.tabbar button[data-p="entry"] .tl, .tabbar button.mid .tl');
  if (lab && (lab.textContent || '').replace(/\s+/g, '') === '입력') lab.textContent = '기록';
}
function n7HookRoleLbl_() {
  if (typeof roleLbl_ !== 'function' || roleLbl_._n7) return;
  var _rl = roleLbl_;
  roleLbl_ = function (u) {
    u = u || {};
    if (u.role === '관리자') return '운영자';
    if (u.role === '직원' && (u.mgr || u.grade === '관리자')) return '농장 관리자';
    var t = _rl(u);
    if (t === '관리자' && u.role === '직원') return '농장 관리자';
    return t;
  };
  roleLbl_._n7 = 1;
}
function n7SowBarSync_(p) {
  var page = p || (window.PL && PL._page) || '';
  var on = window.PL && PL.view === 'm' && (page === 'sow' || page === 'sowcard') && !n7LoginVisible_();
  if (!on) {
    var old = document.getElementById('n7-sowbar');
    if (old) old.remove();
    document.body.classList.remove('n7-sowbar-on');
    return;
  }
  var root = document.getElementById('m-main') || document.getElementById('app');
  if (root && root.querySelector('.sowcard, #sc-add')) n7PolishSowCard_(root);
}
function n7PolishSowCard_(el) {
  if (!el) return;
  var card = el.querySelector('.sowcard');
  var add = el.querySelector('#sc-add');
  if (!card && !add) return;
  var tagEl = el.querySelector('.sowhead .no') || el.querySelector('.n7scard .idbox .no');
  var tag = tagEl ? tagEl.textContent.trim() : '';
  if (card && tag && !(card.classList && card.classList.contains('n7scard'))) setTimeout(function () { try { n7SowVaccHist_(card, tag); } catch (e) {} }, 0);
  var back = el.querySelector('#sc-back');
  if (back && window.PL && PL.view === 'm') back.style.display = 'none';
  var row = el.querySelector('.row.noprint');
  if (row && !row.querySelector('.n7-sow-more') && window.PL && PL.view === 'm') {
    var wrap = document.createElement('span');
    wrap.className = 'n7-dots n7-sow-more';
    wrap.innerHTML = '<button type="button" class="n7-morebtn" aria-label="더보기">⋯</button><div class="n7-menu"></div>';
    var menu = wrap.querySelector('.n7-menu');
    Array.prototype.forEach.call(row.querySelectorAll('button'), function (b) {
      if (b.id === 'sc-add' || b.id === 'sc-back') { b.style.display = 'none'; return; }
      var c = b.cloneNode(true);
      c.style.display = '';
      menu.appendChild(c);
      b.style.display = 'none';
    });
    if (!menu.childNodes.length) {
      var pr = document.createElement('button'); pr.type = 'button'; pr.textContent = '인쇄 / PDF';
      pr.onclick = function () { if (typeof printEl === 'function') printEl(el); else window.print(); };
      menu.appendChild(pr);
    }
    wrap.querySelector('.n7-morebtn').onclick = function (e) {
      e.stopPropagation();
      wrap.classList.toggle('open');
    };
    row.appendChild(wrap);
    row.style.position = 'relative';
    row.style.minHeight = '44px';
    row.style.marginBottom = '0';
  }
  if (card && !card.querySelector('.n7-cycbar') && !(card.classList && card.classList.contains('n7scard'))) {
    var due = card.querySelectorAll('.kv div');
    var steps = ['후보', '교배', '감정', '분만', '이유'];
    var on = '';
    var st = (card.querySelector('.sowhead .badge') || {}).textContent || '';
    if (/후보/.test(st)) on = '후보';
    else if (/포유/.test(st)) on = '이유';
    else if (/임신/.test(st)) on = '감정';
    else if (/교배/.test(st)) on = '교배';
    else if (/대기|이유/.test(st)) on = '이유';
    var bar = document.createElement('div');
    bar.className = 'n7-cycbar';
    bar.innerHTML = steps.map(function (s) { return '<span class="' + (s === on ? 'on' : '') + '">' + s + '</span>'; }).join('');
    var head = card.querySelector('.sowhead');
    if (head && head.parentNode) head.parentNode.insertBefore(bar, head.nextSibling);
  }
  var hold = document.getElementById('n7-sowbar');
  if (!hold) {
    hold = document.createElement('div');
    hold.id = 'n7-sowbar'; hold.className = 'n7-abar n7-sowbar';
    document.body.appendChild(hold);
  }
  hold.innerHTML = (add ? '<button type="button" class="btn" id="n7-sow-rec">이 모돈 기록 입력</button>' : '')
    + '<button type="button" class="btn sec" id="n7-sow-move">이동</button>';
  document.body.classList.add('n7-sowbar-on');
  var rec = hold.querySelector('#n7-sow-rec');
  if (rec && add) rec.onclick = function () { add.click(); };
  var mv = hold.querySelector('#n7-sow-move');
  if (mv) mv.onclick = function () {
    var go = PL.go || window.go;
    if (go) go('entry', { tag: tag, type: '이동' });
  };
}

function n7ReduceMotion_() {
  try { return !!(window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches); } catch (e) { return false; }
}
function n7MotionDash_(root) {
  root = root || document;
  if (!root || !root.querySelectorAll) return;
  var reduce = n7ReduceMotion_(), fmt = function (v, d) { d = Math.max(0, Number(d) || 0); var n = Number(v); if (!isFinite(n)) n = 0; try { if (typeof nF === 'function') return nF(n, d); } catch (e) {} return n.toFixed(d); };
  root.querySelectorAll('.n7h-k[data-n7v]').forEach(function (el) {
    if (el.getAttribute('data-n7done')) return;
    el.setAttribute('data-n7done', '1');
    var to = +el.getAttribute('data-n7v'), dp = +el.getAttribute('data-n7dp') || 0, unit = el.getAttribute('data-n7u') || '';
    var v2 = el.getAttribute('data-n7v2'), dp2 = +el.getAttribute('data-n7dp2') || 0;
    function set(p) {
      var a = (isNaN(to) ? 0 : to) * p, t = fmt(a, dp) + unit;
      if (v2 != null && v2 !== '') t = fmt(a, dp) + ' / ' + fmt((+v2) * p, dp2);
      el.textContent = t;
    }
    if (reduce) { set(1); return; }
    var t0 = (window.performance && performance.now()) || Date.now();
    (function tick(now) {
      var p = Math.min(1, (now - t0) / 800);
      p = 1 - Math.pow(1 - p, 3);
      set(p);
      if (p < 1) requestAnimationFrame(tick);
    })(t0);
  });
  function grow(sel, attr, css, unit) {
    root.querySelectorAll(sel).forEach(function (sp) {
      if (sp.getAttribute('data-n7mdone')) return;
      sp.setAttribute('data-n7mdone', '1');
      var v = sp.getAttribute(attr);
      if (reduce) { sp.style[css] = v + unit; return; }
      sp.style[css] = '0' + unit;
      requestAnimationFrame(function () { requestAnimationFrame(function () { sp.style[css] = v + unit; }); });
    });
  }
  grow('.n7h-bar span[data-n7w]', 'data-n7w', 'width', '%');
  grow('.n7h-bars b[data-n7h]', 'data-n7h', 'height', 'px');
  root.querySelectorAll('.n7h-gag[data-n7g]').forEach(function (g) {
    if (g.getAttribute('data-n7mdone')) return;
    g.setAttribute('data-n7mdone', '1');
    var p = Math.max(0, Math.min(100, +g.getAttribute('data-n7g') || 0));
    if (reduce) { g.style.setProperty('--p', p); return; }
    g.style.setProperty('--p', 0);
    var t0 = (window.performance && performance.now()) || Date.now();
    (function tick(now) {
      var k = Math.min(1, (now - t0) / 800);
      k = 1 - Math.pow(1 - k, 3);
      g.style.setProperty('--p', (p * k).toFixed(2));
      if (k < 1) requestAnimationFrame(tick);
    })(t0);
  });
}
function n7CfgGet_(k) {
  try {
    var c = (window.PL && PL.boot && PL.boot.cfg) || {};
    return c[k];
  } catch (e) { return ''; }
}
function n7IsPigletFlow_() {
  try { return String(n7CfgGet_('생산흐름') || '') === '자돈생산'; } catch (e) { return false; }
}
function n7NeedShipGrade_() {
  try {
    if (n7IsPigletFlow_()) return false;
    var use = String(n7CfgGet_('출하등급_사용') || n7CfgGet_('등급 사용') || '').trim();
    if (use === '아니오' || use === 'N' || use === 'false') return false;
    if (use === '예' || use === 'Y' || use === 'true') return true;
    return typeof farmTypes === 'function' && farmTypes().indexOf('FIN') >= 0;
  } catch (e) { return false; }
}
function n7ShowShipGrade_() {
  try { if (n7IsPigletFlow_()) return false; } catch (e) {}
  return true;
}
function n7RenameShipMenu_(root) {
  root = root || document;
  try {
    var tw = document.createTreeWalker(root, NodeFilter.SHOW_TEXT, null);
    var n, skip = { SCRIPT: 1, STYLE: 1, TEXTAREA: 1, INPUT: 1 };
    while ((n = tw.nextNode())) {
      if (!n.nodeValue || n.nodeValue.indexOf('출하 등급') < 0) continue;
      var p = n.parentNode;
      if (p && skip[p.nodeName]) continue;
      n.nodeValue = n.nodeValue.replace(/출하 등급/g, '출하');
    }
    document.querySelectorAll('[data-p="ship"]').forEach(function (el) {
      if ((el.getAttribute('title') || '').indexOf('출하 등급') >= 0) el.setAttribute('title', el.getAttribute('title').replace(/출하 등급/g, '출하'));
    });
  } catch (e) { }
}
function n7PageHost_(root) {
  return (root && root.querySelector && (root.querySelector('#w-main') || root.querySelector('#m-main')))
    || document.getElementById('w-main')
    || document.getElementById('m-main')
    || (root && root.id === 'w-main' ? root : null)
    || (root && root.id === 'm-main' ? root : null)
    || root
    || document.body;
}
function n7ShipEnsure_(root, n) {
  var host = n7PageHost_(root);
  if (!host) return;
  var pageIsShip = (typeof PL !== 'undefined' && PL._page === 'ship');
  if (!pageIsShip) return;
  if (typeof n7HookShip_ === 'function') n7HookShip_();
  if (typeof pageShip !== 'function' || !pageShip._n7sh) {
    if ((n || 0) < 50) setTimeout(function () { n7ShipEnsure_(root, (n || 0) + 1); }, 120);
    return;
  }
  if (!(host.querySelector && host.querySelector('#n7-sh-tabs'))) pageShip(host);
  if ((n || 0) < 50) setTimeout(function () { n7ShipEnsure_(root, (n || 0) + 1); }, 150);
}
function n7HookShip_() {
  if (typeof pageShip === 'function' && !pageShip._n7sh) {
    var _ps = pageShip;
    pageShip = function (el, f) {
      if (!el) return _ps(el, f);
      if (el.id === 'n7-sh-host' || (el.getAttribute && el.getAttribute('data-n7sh') === 'grades')) return _ps(el, f);
      var want = (f && f.tab === 'grades') ? 'grades' : 'in';
      el.innerHTML = '<div class="n7-sh"><div class="n7-sh-tabs" id="n7-sh-tabs">'
        + '<button type="button" class="btn sm' + (want === 'in' ? '' : ' sec') + '" data-tab="in">출하 입력</button>'
        + '<button type="button" class="btn sm' + (want === 'grades' ? '' : ' sec') + '" data-tab="grades">등급 조회</button>'
        + '</div><div id="n7-sh-host"></div></div>';
      var host = el.querySelector('#n7-sh-host'), tabs = el.querySelector('#n7-sh-tabs');
      function show(tab) {
        tabs.querySelectorAll('button').forEach(function (b) { b.className = 'btn sm' + (b.getAttribute('data-tab') === tab ? '' : ' sec'); });
        if (tab === 'grades') { host.setAttribute('data-n7sh', 'grades'); _ps(host, f || {}); }
        else n7ShipForm_(host);
      }
      tabs.onclick = function (e) {
        var b = e.target.closest && e.target.closest('button[data-tab]');
        if (!b) return;
        show(b.getAttribute('data-tab'));
      };
      show(want);
    };
    pageShip._n7sh = 1;
  }
  if (typeof pageGroups === 'function' && !pageGroups._n7sh) {
    var _pg = pageGroups;
    pageGroups = function (el, date) {
      var r = _pg(el, date);
      var watch = function (n) {
        if (el && el.querySelector('#gb-t')) n7PolishGroupShip_(el);
        else if ((n || 0) < 40) setTimeout(function () { watch((n || 0) + 1); }, 80);
      };
      watch(0);
      return r;
    };
    pageGroups._n7sh = 1;
  }
}
function n7PolishGroupShip_(el) {
  if (!el) return;
  var need = n7NeedShipGrade_(), lab = el.querySelector('#gb-grw label, #gb-grw .l');
  if (lab) lab.textContent = need ? '등급 *' : '등급 (선택)';
  var btn = el.querySelector('#gb-save');
  if (btn && !btn._n7g) {
    var old = btn.onclick;
    btn.onclick = function () {
      var tEl = el.querySelector('#gb-t'), gEl = el.querySelector('#gb-gr');
      var t = tEl ? tEl.value : '', g = gEl ? String(gEl.value || '').trim() : '';
      if (t === '출하' && n7NeedShipGrade_() && !g) {
        var msg = el.querySelector('#gb-msg');
        if (msg) msg.innerHTML = '<div class="mut" style="color:#b42318">비육 출하는 등급을 고르세요.</div>';
        if (typeof toast === 'function') toast('비육 출하는 등급을 고르세요.');
        return;
      }
      if (typeof old === 'function') return old.apply(this, arguments);
    };
    btn._n7g = 1;
  }
}
function n7ShipForm_(host) {
  if (!host) return;
  host.removeAttribute('data-n7sh');
  host.innerHTML = '<div class="card"><h3>출하 입력</h3><div class="mut">불러오는 중…</div></div>';
  var need = n7NeedShipGrade_();
  var showG = typeof n7ShowShipGrade_ === 'function' ? n7ShowShipGrade_() : !n7IsPigletFlow_();
  var grades = ['1+', '1', '2', '3', '등외'];
  apiF('getGroupBook', '').then(function (b) {
    b = b || {};
    var groups = b.groups || [], stages = b.stageList || [];
    var opt = function (a, lab) { return (a || []).map(function (x) { return '<option value="' + (typeof esc === 'function' ? esc(x) : x) + '">' + (typeof esc === 'function' ? esc(lab ? lab(x) : x) : x) + '</option>'; }).join(''); };
    var F = function (l, h, cls) { return '<div class="n7-sh-f ' + (cls || '') + '"><label class="l">' + l + '</label>' + h + '</div>'; };
    var todayV = (typeof today === 'function') ? today() : '';
    var gradeBlock = '';
    if (showG) {
      gradeBlock = F(need ? '등급 *' : '등급 (선택)', '<div class="n7-sh-chips" id="n7-sh-chips">' + grades.map(function (g) { return '<button type="button" class="btn sm sec" data-g="' + g + '">' + g + '</button>'; }).join('') + '<input type="hidden" id="n7-sh-gr"></div>', 'n7-sh-span');
    }
    host.innerHTML = '<div class="card"><h3>출하 입력</h3>'
      + (need ? '<p class="n7-sh-need">이 농장은 비육 포함이라 등급을 고릅니다. 자돈생산 농장에는 등급을 묻지 않습니다.</p>' : (showG ? '<p class="n7-sh-need">등급은 선택입니다.</p>' : '<p class="n7-sh-need">자돈생산 농장이라 등급을 넣지 않습니다.</p>'))
      + '<div class="n7-sh-form">'
      + F('날짜 *', '<input type="date" id="n7-sh-d" value="' + (typeof esc === 'function' ? esc(todayV) : todayV) + '" max="' + (typeof esc === 'function' ? esc(todayV) : todayV) + '">')
      + F('두수 *', '<input type="number" id="n7-sh-n" min="1" step="1" inputmode="numeric">')
      + F('총체중(kg)', '<input type="number" id="n7-sh-w" min="0" step="0.1" inputmode="decimal">')
      + F('평균체중(kg)', '<input type="number" id="n7-sh-avg" min="0" step="0.1" inputmode="decimal">')
      + F('출하처', '<input id="n7-sh-buyer" maxlength="60" placeholder="거래처·출하처">')
      + F('단계 *', '<select id="n7-sh-s">' + opt(stages) + '</select>')
      + F('돈군', '<select id="n7-sh-g"><option value="">(단계로만)</option>' + groups.map(function (g) { return '<option value="' + (typeof esc === 'function' ? esc(g.id) : g.id) + '">' + (typeof esc === 'function' ? esc((g.name || g.id) + ' · ' + g.stage) : (g.name || g.id)) + '</option>'; }).join('') + '</select>')
      + gradeBlock
      + F('메모', '<input id="n7-sh-m" maxlength="200">', 'n7-sh-span')
      + '<div class="n7-sh-span n7-sh-actions"><button type="button" class="btn" id="n7-sh-save">저장</button></div>'
      + '<div class="n7-sh-msg" id="n7-sh-msg" hidden></div>'
      + '</div></div><div class="card n7-sh-recap" id="n7-sh-recap"></div>';
    var chips = host.querySelector('#n7-sh-chips');
    if (chips) chips.onclick = function (e) {
      var b = e.target.closest && e.target.closest('button[data-g]');
      if (!b) return;
      var on = b.classList.contains('on');
      chips.querySelectorAll('button').forEach(function (x) { x.className = 'btn sm sec'; });
      host.querySelector('#n7-sh-gr').value = '';
      if (!on) { b.className = 'btn sm on'; host.querySelector('#n7-sh-gr').value = b.getAttribute('data-g') || ''; }
    };
    var lockW = 0;
    function numOf(id) {
      var el = host.querySelector(id); if (!el) return NaN;
      var v = String(el.value || '').trim(); if (!v) return NaN;
      return Number(v);
    }
    function syncW(from) {
      if (lockW) return;
      lockW = 1;
      try {
        var n = numOf('#n7-sh-n'), tot = numOf('#n7-sh-w'), avg = numOf('#n7-sh-avg');
        var totEl = host.querySelector('#n7-sh-w'), avgEl = host.querySelector('#n7-sh-avg');
        if (from === 'avg' && n > 0 && avg >= 0) { if (totEl) totEl.value = (avg * n).toFixed(1).replace(/\.0$/, ''); }
        else if (n > 0 && tot >= 0) { if (avgEl) avgEl.value = (tot / n).toFixed(2).replace(/\.00$/, ''); }
      } finally { lockW = 0; }
    }
    ['#n7-sh-n', '#n7-sh-w'].forEach(function (id) {
      var el = host.querySelector(id); if (el) el.addEventListener('input', function () { syncW('tot'); });
    });
    var avgEl = host.querySelector('#n7-sh-avg');
    if (avgEl) avgEl.addEventListener('input', function () { syncW('avg'); });
    var recap = function () {
      var box = host.querySelector('#n7-sh-recap'); if (!box) return;
      var to = (typeof today === 'function') ? today() : '';
      var from = to ? (to.slice(0, 8) + '01') : '';
      apiF('getShipGrades', { from: from, to: to }).then(function (r) {
        var head = (r && r.total && r.total.head) || 0, recs = (r && r.total && r.total.recs) || 0;
        var kg = (r && r.total && (r.total.kg || r.total.weight)) || 0;
        box.innerHTML = '<h3>이달 출하</h3><div class="mut">두수 ' + head + ' · 체중 ' + kg + 'kg · 기록 ' + recs + '건. 일보·월간 보고의 출하 칸에도 같은 기록이 잡힙니다.</div>';
      }).catch(function () { box.innerHTML = ''; });
    };
    recap();
    var req = (typeof uuid === 'function') ? uuid() : String(Date.now());
    var saving = false;
    host.querySelector('#n7-sh-save').onclick = function () {
      var msg = host.querySelector('#n7-sh-msg');
      var miss = [];
      var d = host.querySelector('#n7-sh-d').value;
      var n = host.querySelector('#n7-sh-n').value;
      var stage = host.querySelector('#n7-sh-s').value;
      var gEl = host.querySelector('#n7-sh-gr');
      var g = gEl ? gEl.value : '';
      if (!d) miss.push('날짜');
      if (!n || +n <= 0) miss.push('두수');
      if (!stage) miss.push('단계');
      if (need && showG && !String(g || '').trim()) miss.push('등급');
      var tot = numOf('#n7-sh-w'), avg = numOf('#n7-sh-avg'), hn = Number(n);
      if (String(host.querySelector('#n7-sh-w').value || '').trim() && (!(tot > 0) || (hn > 0 && tot / hn > 300))) miss.push('총체중(두당 300kg 이하)');
      if (msg) {
        if (miss.length) {
          msg.hidden = false;
          msg.textContent = '비어 있는 항목: ' + miss.join(', ');
          if (typeof toast === 'function') toast('비어 있는 항목: ' + miss.join(', '));
          return;
        }
        msg.hidden = true;
        msg.textContent = '';
      }
      if (saving) return;
      var x = { type: '출하', date: d, stage: stage, groupId: host.querySelector('#n7-sh-g').value, head: n, memo: host.querySelector('#n7-sh-m').value, reqId: req };
      if (tot > 0) x.weight = tot;
      if (g) x.grade = g;
      var buyer = host.querySelector('#n7-sh-buyer'); if (buyer && buyer.value) x.buyer = buyer.value;
      saving = true;
      apiF('saveGroupEvent', x).then(function (r) {
        req = (typeof uuid === 'function') ? uuid() : String(Date.now());
        if (typeof toast === 'function') toast((typeof Tk_ === 'function') ? Tk_('ld.saved', null, '저장했습니다') : '저장했습니다');
        if (r && r.flags && r.flags.length && typeof toast === 'function') toast(r.flags.join(' / '), 4000);
        host.querySelector('#n7-sh-n').value = ''; host.querySelector('#n7-sh-w').value = ''; host.querySelector('#n7-sh-avg').value = ''; host.querySelector('#n7-sh-m').value = '';
        if (buyer) buyer.value = '';
        if (gEl) gEl.value = '';
        if (chips) chips.querySelectorAll('button').forEach(function (b) { b.className = 'btn sm sec'; });
        recap();
      }).catch(function (e) {
        if (msg) { msg.hidden = false; msg.innerHTML = (typeof errHTML === 'function') ? errHTML(e) : String((e && e.message) || e); }
      }).then(function () { saving = false; });
    };
  }).catch(function (e) {
    host.innerHTML = (typeof errHTML === 'function') ? errHTML(e) : '출하 입력 화면을 열 수 없습니다.';
  });
}

function n7HookReport_() {
  if (typeof pageReport !== 'function' || pageReport._n7rp) return;
  var _pr = pageReport;
  pageReport = function (el, arg) {
    var r = _pr(el, arg);
    var watch = function (n) {
      if (el && (el.querySelector('#rp-kind') || el.querySelector('[name="rp-kind"]') || el.querySelector('#rp-from'))) n7PolishReport_(el);
      else if ((n || 0) < 50) setTimeout(function () { watch((n || 0) + 1); }, 80);
    };
    watch(0);
    return r;
  };
  pageReport._n7rp = 1;
}
function n7PolishReport_(el) {
  if (!el || el.querySelector('#n7-rp-split')) return;
  var bar = el.querySelector('#rp-kind') || el.querySelector('.seg') || el.querySelector('#rp-from');
  if (!bar) return;
  var box = document.createElement('div');
  box.id = 'n7-rp-split';
  box.className = 'n7-rp-split';
  box.innerHTML = '<div class="n7-rp-tiles">'
    + '<button type="button" class="n7-rp-t" data-k="exit"><b>모돈 도태·폐사</b></button>'
    + '<button type="button" class="n7-rp-t" data-k="piglet"><b>포유자돈 폐사</b></button>'
    + '</div>';
  var parent = bar.parentNode, insertAt = bar;
  if (bar.id === 'rp-from') insertAt = bar.parentNode || bar;
  if (insertAt && insertAt.parentNode) insertAt.parentNode.insertBefore(box, insertAt.nextSibling);
  else el.insertBefore(box, el.firstChild);
  function mark() {
    var kind = '';
    var on = el.querySelector('#rp-kind button.on, #rp-kind .btn:not(.sec), [data-seg="rp-kind"] .on');
    if (on) kind = on.getAttribute('data-v') || on.getAttribute('data-k') || on.value || (on.textContent || '');
    box.querySelectorAll('.n7-rp-t').forEach(function (b) {
      var k = b.getAttribute('data-k');
      var hit = kind === k || (k === 'exit' && String(kind).indexOf('모돈 도태') >= 0) || (k === 'piglet' && String(kind).indexOf('포유자돈') >= 0);
      b.className = 'n7-rp-t' + (hit ? ' on' : '');
    });
  }
  box.onclick = function (e) {
    var b = e.target.closest && e.target.closest('.n7-rp-t'); if (!b) return;
    var k = b.getAttribute('data-k');
    var btns = el.querySelectorAll('#rp-kind button, #rp-kind [data-v], [data-seg="rp-kind"] button');
    var hit = null;
    Array.prototype.forEach.call(btns, function (x) {
      var v = x.getAttribute('data-v') || x.getAttribute('data-k') || x.value || '';
      if (v === k || (k === 'exit' && String(x.textContent || '').indexOf('모돈 도태') >= 0) || (k === 'piglet' && String(x.textContent || '').indexOf('포유자돈') >= 0)) hit = x;
    });
    if (hit) hit.click();
    setTimeout(mark, 200);
  };
  mark();
  var mo = new MutationObserver(function () { mark(); });
  var kindEl = el.querySelector('#rp-kind');
  if (kindEl) mo.observe(kindEl, { attributes: true, subtree: true, childList: true });
}

function n7HookPages_() {
  if (typeof fHome === 'function' && !fHome._n7t411) {
    var _fh = fHome;
    fHome = function () { _fh.apply(this, arguments); n7FieldHomeTiles_(); n7ActionBar_(''); };
    fHome._n7t411 = 1;
  }
  if (typeof pageSow === 'function' && !pageSow._n7v2) {
    var _psow = pageSow;
    pageSow = function (el, id, go) {
      var r = _psow(el, id, go);
      var watch = function (n) {
        if (el && el.querySelector('.sowcard, #sc-add')) n7PolishSowCard_(el);
        else if ((n || 0) < 50) setTimeout(function () { watch((n || 0) + 1); }, 80);
      };
      watch(0);
      return r;
    };
    pageSow._n7v2 = 1;
  }
  if (typeof pageSowK === 'function' && !pageSowK._n7v2) {
    var _psk = pageSowK;
    pageSowK = function (el, tag) {
      var r = _psk(el, tag);
      setTimeout(function () { if (el) n7PolishSowCard_(el); }, 200);
      return r;
    };
    pageSowK._n7v2 = 1;
  }
  if (typeof pageBoard === 'function' && !pageBoard._n7t) {
    var _pb = pageBoard;
    pageBoard = function (el, arg) { _pb(el, arg); setTimeout(function () { n7BoardTmap_('board'); }, 80); };
    pageBoard._n7t = 1;
  }
  if (typeof pageSettings === 'function' && !pageSettings._n7s) {
    var _ps = pageSettings;
    pageSettings = function (el) {
      var r = _ps(el);
      var tryCard = function () {
        if (el && el.querySelector('#st-go')) n7PolishSettings_(el);
        if (el && typeof n7CertCard_ === 'function') n7CertCard_(el);
      };
      tryCard();
      if (el && !el._n7certObs) {
        el._n7certObs = 1;
        try {
          var mo = new MutationObserver(function () { tryCard(); });
          mo.observe(el, { childList: true, subtree: true });
        } catch (e0) {}
        var n = 0;
        var tick = function () {
          tryCard();
          if (el.querySelector('#n7-cert-card') && el.querySelector('#st-go, #st-lrn, #st-ft')) return;
          if ((n++) < 100) setTimeout(tick, 200);
        };
        tick();
      }
      return r;
    };
    pageSettings._n7s = 1;
  }
  
function n7OrgTabs_(el) {
  if (!el || el.querySelector('#n7-org-tabs')) return;
  var staff = el.querySelector('#org-staff');
  var tree = el.querySelector('#org-tree') || el.querySelector('#org-tree'.replace('org-tree','org-tree'));
  if (!staff && !el.querySelector('#org-tree')) return;
  tree = el.querySelector('#org-tree');
  var bar = document.createElement('div');
  bar.id = 'n7-org-tabs';
  bar.className = 'row';
  bar.style.cssText = 'gap:8px;flex-wrap:wrap;margin:0 0 12px';
  bar.innerHTML = '<button type="button" class="btn" data-org="staff">직원</button>'
    + '<button type="button" class="btn sec" data-org="tree">조직도</button>'
    + '<button type="button" class="btn sec" data-org="att">근무</button>';
  el.insertBefore(bar, el.firstChild);
  function show(k) {
    [].forEach.call(bar.querySelectorAll('button'), function (b) { b.className = 'btn' + (b.getAttribute('data-org') === k ? '' : ' sec'); });
    if (staff) staff.style.display = k === 'staff' ? '' : 'none';
    if (tree) tree.style.display = k === 'tree' ? '' : 'none';
    var att = el.querySelector('#n7-org-att');
    if (k === 'att') {
      if (!att) {
        att = document.createElement('div');
        att.id = 'n7-org-att';
        el.appendChild(att);
        if (typeof pageAtt === 'function') pageAtt(att);
      }
      att.style.display = '';
    } else if (att) att.style.display = 'none';
  }
  bar.onclick = function (e) {
    var b = e.target.closest && e.target.closest('button[data-org]');
    if (b) show(b.getAttribute('data-org'));
  };
  show(staff ? 'staff' : 'tree');
}

if (typeof pageOrg === 'function' && !pageOrg._n7s) {
    var _po = pageOrg;
    pageOrg = function (el) {
      var r = _po(el);
      var watch = function (n) {
        n7PolishStaff_(el);
        try { n7OrgTabs_(el); } catch (eOt) {}
        if ((n || 0) < 40) setTimeout(function () { watch((n || 0) + 1); }, 150);
      };
      watch(0);
      return r;
    };
    pageOrg._n7s = 1;
  }
  if (typeof staffCard === 'function' && !staffCard._n7s) {
    var _sc = staffCard;
    staffCard = function (box) {
      var r = _sc(box);
      var watch = function (n) {
        if (box && box.querySelector('table.t')) n7PolishStaff_(box);
        else if ((n || 0) < 40) setTimeout(function () { watch((n || 0) + 1); }, 150);
      };
      watch(0);
      return r;
    };
    staffCard._n7s = 1;
  }
  if (typeof n7HookShip_ === 'function') n7HookShip_();
  if (typeof n7HookReport_ === 'function') n7HookReport_();
}
(function () {
  if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', function () { n7ViewMark_(); n7ThemeInit_(); });
  else { n7ViewMark_(); n7ThemeInit_(); }
  document.addEventListener('click', function (e) {
    Array.prototype.forEach.call(document.querySelectorAll('.n7-dots.open'), function (x) {
      if (!x.contains(e.target)) x.classList.remove('open');
    });
  });
})();

if (typeof n7HookGo_ === 'function') n7HookGo_();
if (typeof n7HookFstock_ === 'function') n7HookFstock_();
if (typeof n7HookPages_ === 'function') n7HookPages_();
if (typeof n7TabRecLbl_ === 'function') n7TabRecLbl_();
if (typeof n7HookRoleLbl_ === 'function') n7HookRoleLbl_();
if (typeof n7HookLocPicker_ === 'function') n7HookLocPicker_();
(function n7WaitHome_(n) {
  n7HookHome_();
  if (typeof n7HookImport_ === 'function') n7HookImport_();
  if (typeof n7HookFarrowDates_ === 'function') n7HookFarrowDates_();
  if (typeof n7HookGo_ === 'function') n7HookGo_();
  if (typeof n7HookFstock_ === 'function') n7HookFstock_();
  if (typeof n7HookPages_ === 'function') n7HookPages_();
  if (typeof n7TabRecLbl_ === 'function') n7TabRecLbl_();
  if (typeof n7HookRoleLbl_ === 'function') n7HookRoleLbl_();
  if (typeof n7HookLocPicker_ === 'function') n7HookLocPicker_();
  if (typeof n7ViewMark_ === 'function') n7ViewMark_();
  var needHome = typeof pageHomeK !== 'function' || !pageHomeK._n7v2;
  var needImp = typeof pageImport !== 'function' || !pageImport._n7i;
  if ((needHome || needImp) && (n || 0) < 200) setTimeout(function () { n7WaitHome_((n || 0) + 1); }, 50);
})(0);
function n7TuneTable_(tb) {
  if (!tb || tb.getAttribute('data-n7t') || tb.closest('#rp-doc') || tb.closest('.printonly')) return;
  tb.setAttribute('data-n7t', '1');
  var head = tb.rows && tb.rows[0]; if (!head) return;
  function hideCol(i) {
    for (var r = 0; r < tb.rows.length; r++) { if (tb.rows[r].children[i]) tb.rows[r].children[i].style.display = 'none'; }
  }
  for (var i = 0; i < head.children.length; i++) {
    var tx = (head.children[i].textContent || '').replace(/\s+/g, '');
    if (tx === '순번') hideCol(i);
    if (tx === '품종') {
      var allF1 = true, any = false;
      for (var r = 1; r < tb.rows.length; r++) {
        var c = tb.rows[r].cells[i]; if (!c) continue;
        var v = (c.textContent || '').trim();
        if (!v) continue;
        any = true;
        if (v !== 'F1') { allF1 = false; break; }
      }
      if (any && allF1) hideCol(i);
    }
  }
}
(function () {
  function scan(root) {
    var list = (root || document).querySelectorAll ? (root.querySelectorAll ? root.querySelectorAll('table.t') : []) : [];
    if (root && root.matches && root.matches('table.t')) n7TuneTable_(root);
    Array.prototype.forEach.call(list, n7TuneTable_);
  }
  if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', function () { scan(document); });
  else scan(document);
  if (typeof MutationObserver === 'function') {
    var mo = new MutationObserver(function (muts) {
      muts.forEach(function (m) {
        Array.prototype.forEach.call(m.addedNodes || [], function (n) {
          if (n.nodeType !== 1) return;
          scan(n);
        });
      });
    });
    mo.observe(document.documentElement, { childList: true, subtree: true });
  }
})();


function n7EscAttr_(s) { return String(s == null ? '' : s).replace(/[&<>"']/g, function (c) { return { '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;' }[c]; }); }
function n7TestMarkOn_() {
  return !!(window.PIGLOG_SUPA && PIGLOG_SUPA.testMark);
}
function n7DemoRibbon_() {
  var old = document.getElementById('n7-demo-ribbon');
  if (old) old.remove();
  var band = document.getElementById('supa-demo-band');
  if (band) band.remove();
  if (!n7TestMarkOn_()) {
    var m = document.getElementById('n7-test-mark');
    if (m) m.remove();
    return;
  }
  if (document.getElementById('n7-test-mark')) return;
  var mark = document.createElement('div');
  mark.id = 'n7-test-mark'; mark.className = 'n7-test-mark'; mark.setAttribute('title', '시험 서버'); mark.textContent = '시험';
  document.body.appendChild(mark);
}
function n7ProdCopy_() {
  if (typeof appEd_ === 'function' && !appEd_._n7prod) {
    appEd_ = function () { return '피그로그'; };
    appEd_._n7prod = 1;
  }
  if (typeof demoNoteHTML_ === 'function' && !demoNoteHTML_._n7prod) {
    demoNoteHTML_ = function () { return ''; };
    demoNoteHTML_._n7prod = 1;
  }
  if (typeof showLogin === 'function' && !showLogin._n7prod) {
    var _sl = showLogin;
    showLogin = function () {
      var r = _sl.apply(this, arguments);
      try { n7ProdCopy_(); } catch (e2) {}
      try { n7LoginLogo_(); } catch (e3) {}
      return r;
    };
    showLogin._n7prod = 1;
  }
  try {
    [].forEach.call(document.querySelectorAll('.cs-tip'), function (el) {
      if (/v2\.0-draft|시행/.test(el.textContent || '')) el.remove();
    });
    [].forEach.call(document.querySelectorAll('.demo-note,#supa-demo-band,#n7-demo-ribbon'), function (el) { el.remove(); });
    [].forEach.call(document.querySelectorAll('.foot, .mut, aside .foot'), function (el) {
      var tx = el.textContent || '';
      if (/예시 데이터/.test(tx)) {
        el.textContent = tx.replace(/\s*·\s*예시 데이터는 실제 농장 자료가 아닙니다/g, '').replace(/피그로그 베타/g, '피그로그').trim() || '피그로그';
      }
    });
    var walk = function (root) {
      var it = document.createNodeIterator(root, NodeFilter.SHOW_TEXT, null);
      var node, drop = [];
      while ((node = it.nextNode())) {
        var p = node.parentNode;
        if (!p || p.id === 'n7-test-mark' || (p.className && String(p.className).indexOf('n7-test-mark') >= 0)) continue;
        var tx = node.nodeValue || '';
        if (!/피그로그 베타|예시 데이터는 실제|시험판 · 가짜|베타 데모/.test(tx)) continue;
        var nx = tx.replace(/피그로그 베타/g, '피그로그')
          .replace(/\s*·\s*예시 데이터는 실제 농장 자료가 아닙니다/g, '')
          .replace(/예시 데이터는 실제 농장 자료가 아닙니다/g, '')
          .replace(/피그로그 베타 데모/g, '피그로그')
          .replace(/시험판 · 가짜 자료만/g, '')
          .trim();
        if (nx) node.nodeValue = nx;
        else drop.push(p);
      }
      drop.forEach(function (el) { if (el && el.parentNode && !(el.childNodes && el.childNodes.length)) el.parentNode.removeChild(el); });
    };
    try { walk(document.body); } catch (eW) {}
    n7DemoRibbon_();
    var marks = document.querySelectorAll('#n7-test-mark, .n7-test-mark');
    for (var mi = 1; mi < marks.length; mi++) marks[mi].parentNode && marks[mi].parentNode.removeChild(marks[mi]);
  } catch (e) {}
}
function n7HasSess_() {
  try {
    var raw = localStorage.getItem('pl');
    if (!raw) return false;
    var s = JSON.parse(raw);
    return !!(s && (s.token || (s.user && (s.t || s.t0))));
  } catch (e) { return false; }
}
function n7Splash_() {
  if (typeof document === 'undefined' || !document.body) return;
  /* t537: do not play the old splash over the new login — show the login immediately */
  var onLogin = (typeof n7OnLoginScreen_ === 'function' && n7OnLoginScreen_()) || (typeof n7HasSess_ === 'function' && !n7HasSess_());
  if (onLogin) {
    try { sessionStorage.setItem('n7-splash-done', '1'); } catch (eSk) {}
    var stale = document.getElementById('n7-splash') || document.getElementById('piglog-splash');
    if (stale && stale.parentNode) stale.parentNode.removeChild(stale);
    return;
  }
  try { if (sessionStorage.getItem('n7-splash-done') === '1') return; } catch (e0) {}
  if (n7HasSess_()) return;
  if (document.getElementById('n7-splash')) return;
  var box = document.createElement('div');
  box.id = 'n7-splash';
  box.setAttribute('role', 'img');
  box.setAttribute('aria-label', '피그로그');
  box.style.cssText = 'position:fixed;inset:0;z-index:100000;background:#0B0F0D;';
  document.body.appendChild(box);
  var done = 0;
  function hide() {
    if (done) return;
    done = 1;
    try { sessionStorage.setItem('n7-splash-done', '1'); } catch (e2) {}
    box.style.transition = 'opacity .35s ease';
    box.style.opacity = '0';
    box.style.pointerEvents = 'none';
    setTimeout(function () { if (box.parentNode) box.parentNode.removeChild(box); }, 400);
    window.removeEventListener('piglog:splash-done', hide);
  }
  box.addEventListener('click', hide);
  box.addEventListener('keydown', function (e) { if (e.key === 'Enter' || e.key === ' ' || e.key === 'Escape') hide(); });
  box.tabIndex = 0;
  window.addEventListener('piglog:splash-done', hide);
  var mobile = false;
  try {
    mobile = (window.innerWidth || 0) < 700 || (window.matchMedia && window.matchMedia('(max-width:700px)').matches)
      || (typeof location !== 'undefined' && /\/m(?:\.html)?(?:$|[?#])/.test(location.pathname));
  } catch (e3) {}
  var src = mobile ? '/splash/mobile.html' : '/splash/pc.html';
  fetch(src, { credentials: 'same-origin' }).then(function (r) { return r.text(); }).then(function (html) {
    if (done) return;
    var doc = new DOMParser().parseFromString(html, 'text/html');
    var st = doc.querySelector('style');
    var root = doc.getElementById('piglog-splash');
    if (st) box.appendChild(st.cloneNode(true));
    if (root) box.appendChild(document.importNode(root, true));
    [].forEach.call(doc.querySelectorAll('script'), function (s) {
      var ns = document.createElement('script');
      ns.textContent = s.textContent;
      box.appendChild(ns);
    });
  }).catch(function () { setTimeout(hide, 400); });
  setTimeout(function () { if (!done) hide(); }, 8000);
}
function n7LoginLogo_(root) {
  root = root || document;
  var top = root.querySelector && root.querySelector('.brandtop');
  if (!top || top.getAttribute('data-n7logo')) return;
  top.setAttribute('data-n7logo', '1');
  var img = document.createElement('img');
  img.src = '/splash/piglog_logo.svg';
  img.alt = '피그로그';
  img.className = 'n7-login-logo';
  img.style.cssText = 'display:block;width:min(220px,70vw);height:auto;margin:0 auto 4px;';
  var brand = top.querySelector('.brand');
  if (brand && brand.parentNode) brand.parentNode.replaceChild(img, brand);
  else top.insertBefore(img, top.firstChild);
}

function n7BellFix_() {
  var b = document.getElementById('open-notices');
  if (!b) return;
  b.setAttribute('aria-label', '공지사항');
  b.setAttribute('title', '공지사항');
}
function n7CauseReq_(el) {
  if (!el) return;
  var typBtn = el.parentNode && el.parentNode.querySelector('#en-t button.on');
  var typ = (typBtn && typBtn.getAttribute('data-t')) || (el.getAttribute && el.getAttribute('data-type')) || '';
  if (!typ && window.PL) typ = PL._lastType || '';
  var save = el.querySelector('#ef-save');
  if (!save) return;
  function kind() {
    var b = el.querySelector('[data-k="퇴출구분"] button.on');
    return b ? b.getAttribute('data-v') : '';
  }
  function isCull() { return typ === '도폐사' || !!(el.querySelector('[data-k="퇴출구분"]') && el.querySelector('.cz')); }
  function check(e) {
    if (!isCull() || kind() === '판매') return;
    var cz = el.querySelector('.cz');
    var v = (typeof causeVal === 'function' && cz) ? causeVal(cz) : ((cz && cz.dataset.v) || '');
    if (v && String(v).trim()) return;
    if (e) { e.preventDefault(); e.stopImmediatePropagation(); }
    var msg = el.querySelector('#ef-msg');
    if (msg && typeof errHTML === 'function') msg.innerHTML = errHTML('원인을 고르세요. 모르면 기타를 고르세요.');
    else if (typeof toast === 'function') toast('원인을 고르세요. 모르면 기타를 고르세요.');
    var old = el.querySelector('.n7-cz-err'); if (old) old.remove();
    if (cz) {
      cz.classList.add('n7-cz-miss');
      var d = document.createElement('div'); d.className = 'n7-cz-err';
      d.textContent = '원인을 고르세요. 모르면 기타를 고르세요.';
      cz.appendChild(d);
      try { cz.scrollIntoView({ block: 'center', behavior: 'smooth' }); } catch (e2) { try { cz.scrollIntoView(); } catch (e3) {} }
      try { if (navigator.vibrate) navigator.vibrate(40); } catch (e4) {}
    }
    return true;
  }
  if (!save.getAttribute('data-n7cz')) {
    save.setAttribute('data-n7cz', '1');
    save.addEventListener('click', check, true);
  }
  var abar = document.getElementById('n7-abar-save');
  if (abar && !abar.getAttribute('data-n7cz')) {
    abar.setAttribute('data-n7cz', '1');
    abar.addEventListener('click', function (e) { check(e); }, true);
  }
}

var N7_BREEDS = ['F1', 'LL', 'YY', 'DD', 'YBD', 'LY', 'YL', 'F2', 'L', 'Y', 'D'];
var N7_PICK_K = ['품종', '구입처', '웅돈', '백신명', '약품명', '상대모돈', '사용단위', '원인'];
function n7HistKey_() { return 'pl_n7hist:' + ((window.PL && PL.user && PL.user.id) || '') + ':' + ((window.PL && PL.farmId) || ''); }
function n7HistGet_() { try { return JSON.parse(localStorage.getItem(n7HistKey_()) || '{}'); } catch (e) { return {}; } }
function n7HistAdd_(k, v) {
  v = String(v == null ? '' : v).trim(); if (!v || v.length > 40) return;
  var o = n7HistGet_(), a = o[k] || [], now = Date.now(), i, hit = null;
  for (i = 0; i < a.length; i++) if (a[i].v === v) { hit = a[i]; break; }
  if (hit) { hit.n = (hit.n || 1) + 1; hit.t = now; } else a.push({ v: v, n: 1, t: now });
  a.sort(function (x, y) { return (y.t || 0) - (x.t || 0); });
  o[k] = a.slice(0, 24);
  try { localStorage.setItem(n7HistKey_(), JSON.stringify(o)); } catch (e2) {}
}
function n7HistTop_(k, n) {
  n = n || 5;
  var a = (n7HistGet_()[k] || []).slice(), out = [], seen = {};
  if (typeof lastVal === 'function' && window.PL) {
    var types = ['전입', '교배', '백신', '치료', '도폐사', '자돈폐사', '양자'];
    types.forEach(function (tp) {
      var lv = lastVal(tp, k); if (lv) a.push({ v: lv, n: 2, t: Date.now() });
    });
  }
  a.sort(function (x, y) {
    var sc = function (z) { return (z.n || 1) * 8 + Math.max(0, 40 - (Date.now() - (z.t || 0)) / 864e5); };
    return sc(y) - sc(x);
  });
  a.forEach(function (x) { if (x.v && !seen[x.v]) { seen[x.v] = 1; out.push(x.v); } });
  return out.slice(0, n);
}
function n7SeedHistFromFarm_() {
  if (n7SeedHistFromFarm_._on) return n7SeedHistFromFarm_._on;
  if (typeof apiF !== 'function') return Promise.resolve();
  n7SeedHistFromFarm_._on = apiF('listSows', { includeExited: true }).then(function (r) {
    var items = (r && (r.items || r.sows || r.rows || r)) || [];
    if (!Array.isArray(items)) items = [];
    items.forEach(function (s) {
      var b = s.breed || s['품종']; if (b) n7HistAdd_('품종', b);
      var src = s.source || s['구입처']; if (src) n7HistAdd_('구입처', src);
    });
  }).catch(function () {});
  return n7SeedHistFromFarm_._on;
}
function n7FillInput_(inp, v) {
  if (!inp) return;
  inp.value = v;
  try { inp.dispatchEvent(new Event('input', { bubbles: true })); } catch (e) {}
  try { inp.dispatchEvent(new Event('change', { bubbles: true })); } catch (e2) {}
}
function n7DrawPicks_(inp, k) {
  if (!inp || !inp.parentNode) return;
  var host = (inp.closest && (inp.closest('.stepper') || inp.closest('.row'))) || inp;
  var par = host.parentNode, old = par.querySelector('.n7-qp[data-qk="' + k + '"]');
  if (old) old.remove();
  var tops = n7HistTop_(k, 5);
  if (!tops.length) return;
  var bar = document.createElement('div');
  bar.className = 'n7-qp'; bar.setAttribute('data-qk', k);
  bar.innerHTML = tops.map(function (v, i) {
    return '<button type="button" class="n7-qpb" data-i="' + (i + 1) + '" data-v="' + n7EscAttr_(v) + '"><b>' + (i + 1) + '</b> ' + n7EscAttr_(v) + '</button>';
  }).join('') + (((window.PL && PL.view) === 'web' || document.documentElement.getAttribute('data-n7v') === 'web') ? '<span class="mut n7-qp-hint">Alt+1~5</span>' : '');
  par.insertBefore(bar, host.nextSibling);
  bar.addEventListener('click', function (e) {
    var b = e.target.closest && e.target.closest('.n7-qpb'); if (!b) return;
    n7FillInput_(inp, b.getAttribute('data-v'));
  });
}
function n7CausePicks_(el) {
  var cz = el.querySelector('.cz'); if (!cz) return;
  var old = cz.parentNode.querySelector('.n7-qp[data-qk="원인"]'); if (old) old.remove();
  var tops = n7HistTop_('원인', 5); if (!tops.length) return;
  var bar = document.createElement('div');
  bar.className = 'n7-qp'; bar.setAttribute('data-qk', '원인');
  bar.innerHTML = tops.map(function (v, i) {
    return '<button type="button" class="n7-qpb" data-i="' + (i + 1) + '" data-v="' + n7EscAttr_(v) + '"><b>' + (i + 1) + '</b> ' + n7EscAttr_(v) + '</button>';
  }).join('');
  cz.parentNode.insertBefore(bar, cz.nextSibling);
  bar.addEventListener('click', function (e) {
    var b = e.target.closest && e.target.closest('.n7-qpb'); if (!b) return;
    var v = b.getAttribute('data-v');
    cz.dataset.v = v;
    if (typeof causeBind === 'function') {
      /* already bound; poke top button if present */
      var bt = cz.querySelector('.czt button[data-v="' + v.split('/')[0] + '"]');
      if (bt) bt.click();
      else cz.dataset.v = v;
    }
  });
}
function n7BreedChips_(el) {
  var inp = el.querySelector('[data-k="품종"]');
  if (!inp || inp.getAttribute('data-n7br')) return;
  inp.setAttribute('data-n7br', '1');
  inp.removeAttribute('list');
  var dl = el.querySelector('#ef-breed-list'); if (dl) dl.remove();
  var used = n7HistTop_('품종', 12);
  var std = N7_BREEDS.slice();
  var rest = used.filter(function (x) { return std.indexOf(x) < 0; });
  var box = document.createElement('div'); box.className = 'n7-br';
  function btn(v, on) { return '<button type="button" class="n7-brb' + (on ? ' on' : '') + '" data-v="' + n7EscAttr_(v) + '">' + n7EscAttr_(v) + '</button>'; }
  var cur = String(inp.value || '').trim();
  var known = std.concat(rest);
  box.innerHTML = '<div class="n7-brs">' + std.map(function (v) { return btn(v, v === cur); }).join('') +
    rest.map(function (v) { return btn(v, v === cur); }).join('') +
    '<button type="button" class="n7-brb n7-br-free" data-free="1">직접 입력</button></div>';
  var wrap = inp.closest && inp.closest('.ef-breed-hl');
  if (!wrap) { wrap = document.createElement('div'); wrap.className = 'ef-breed-hl'; inp.parentNode.insertBefore(wrap, inp); wrap.appendChild(inp); }
  wrap.appendChild(box);
  function showIn(on) { inp.hidden = !on; inp.style.display = on ? '' : 'none'; if (on) inp.focus(); }
  showIn(cur && known.indexOf(cur) < 0);
  if (cur && known.indexOf(cur) < 0) {
    var fr = box.querySelector('[data-free]'); if (fr) fr.classList.add('on');
  }
  box.addEventListener('click', function (e) {
    var b = e.target.closest && e.target.closest('button'); if (!b) return;
    var all = box.querySelectorAll('.n7-brb'); for (var i = 0; i < all.length; i++) all[i].classList.remove('on');
    b.classList.add('on');
    if (b.getAttribute('data-free')) { n7FillInput_(inp, ''); showIn(true); return; }
    showIn(false);
    n7FillInput_(inp, b.getAttribute('data-v'));
  });
}
function n7BindAlt_(el) {
  if (el.getAttribute('data-n7alt')) return;
  el.setAttribute('data-n7alt', '1');
  el.addEventListener('keydown', function (e) {
    if (!(e.altKey && !e.ctrlKey && !e.metaKey)) return;
    var n = (e.code && /^Digit[1-5]$/.test(e.code)) ? e.code.slice(-1) : e.key;
    if (!/^[1-5]$/.test(n)) return;
    var t = document.activeElement;
    var inp = (t && el.contains(t) && t.getAttribute && N7_PICK_K.indexOf(t.getAttribute('data-k')) >= 0) ? t : el._n7lastPick;
    if (!inp || !el.contains(inp)) inp = el.querySelector('[data-k="품종"],[data-k="구입처"],[data-k="웅돈"],[data-k="백신명"]');
    var k = inp && inp.getAttribute('data-k');
    var bar = k && el.querySelector('.n7-qp[data-qk="' + k + '"]');
    var b = bar && bar.querySelector('.n7-qpb[data-i="' + n + '"]');
    if (!b) return;
    e.preventDefault();
    n7FillInput_(inp, b.getAttribute('data-v'));
  });
  el.addEventListener('focusin', function (e) {
    var t = e.target;
    if (t && t.getAttribute && N7_PICK_K.indexOf(t.getAttribute('data-k')) >= 0) el._n7lastPick = t;
  });
}
function n7EntryGrid_(el) {
  var entry = (el && el.querySelector && el.querySelector('.entry')) || el;
  if (!entry) return;
  var fg = null, i, kids = entry.querySelectorAll('.fg');
  for (i = 0; i < kids.length; i++) if (!kids[i].classList.contains('n7-ageg')) { fg = kids[i]; break; }
  var nick = entry.querySelector('.ef-nick-box');
  var breed = entry.querySelector('.ef-breed-hl');
  if (fg && fg.parentNode) {
    var after = fg;
    if (breed && (fg.contains(breed) || (breed.closest && breed.closest('.fc') && fg.contains(breed.closest('.fc'))))) {
      fg.parentNode.insertBefore(breed, fg.nextSibling); after = breed;
    }
    if (nick && (fg.contains(nick) || (nick.closest && nick.closest('.fc') && fg.contains(nick.closest('.fc'))))) {
      fg.parentNode.insertBefore(nick, after.nextSibling);
    }
  }
  if (entry.querySelector('.n7-ageg')) return;
  var bI = entry.querySelector('[data-k="생년월일"]');
  var aI = entry.querySelector('[data-k="전입일령"]');
  if (!bI || !aI) return;
  function labOf(inp) {
    var node = inp;
    while (node && node !== entry) {
      var prev = node.previousElementSibling;
      if (prev && prev.tagName === 'LABEL') return prev;
      node = node.parentNode;
    }
    return null;
  }
  var bL = labOf(bI), aL = labOf(aI);
  var g = document.createElement('div'); g.className = 'fg n7-ageg'; g.style.gridTemplateColumns = '1fr 1fr';
  function fc(lab, inp) {
    var c = document.createElement('div'); c.className = 'fc';
    if (lab) c.appendChild(lab);
    c.appendChild(inp);
    return c;
  }
  var hint = entry.querySelector('#ef-agehint');
  var anchor = bL || bI;
  if (anchor && anchor.parentNode) anchor.parentNode.insertBefore(g, anchor);
  else entry.insertBefore(g, bI);
  g.appendChild(fc(bL, bI));
  var right = fc(aL, aI);
  if (hint) right.appendChild(hint);
  g.appendChild(right);
}
function n7QuickPicks_(el) {
  if (!el) return;
  n7SeedHistFromFarm_().then(function () {
    if (!document.body.contains(el)) return;
    N7_PICK_K.forEach(function (k) {
      if (k === '원인') return n7CausePicks_(el);
      var inp = el.querySelector('input[data-k="' + k + '"]');
      if (inp) n7DrawPicks_(inp, k);
    });
  });
  N7_PICK_K.forEach(function (k) {
    if (k === '원인') return n7CausePicks_(el);
    var inp = el.querySelector('input[data-k="' + k + '"]');
    if (inp) n7DrawPicks_(inp, k);
  });
  n7BreedChips_(el);
  n7BindAlt_(el);
  n7EntryGrid_(el);
}
function n7HookRemember_() {
  if (typeof rememberVals === 'function' && !rememberVals._n7) {
    var _rv = rememberVals;
    rememberVals = function (type, defs, ev) {
      _rv(type, defs, ev);
      (defs || []).forEach(function (f) { if (N7_PICK_K.indexOf(f.k) >= 0 && ev && ev[f.k]) n7HistAdd_(f.k, ev[f.k]); });
      if (ev && ev['원인']) n7HistAdd_('원인', ev['원인']);
    };
    rememberVals._n7 = 1;
  }
}
function n7SugSows_(el) {
  var tag = el.querySelector('#ef-tag'); if (!tag || el.querySelector('.n7-sug')) return;
  var bar = document.createElement('div'); bar.className = 'n7-sug';
  var row = tag.closest && tag.closest('.ef-row');
  if (row && row.parentNode) row.parentNode.insertBefore(bar, row.nextSibling);
  else tag.parentNode.appendChild(bar);
  function draw(q) {
    var items = n7SugSows_._items || [];
    q = String(q || '').replace(/\s+/g, '').toLowerCase();
    var scored = items.map(function (s) {
      var t = String(s.tag || ''), tl = t.toLowerCase(), sc = -1;
      if (!q) sc = 0;
      else if (tl === q) sc = 3;
      else if (q && tl.slice(-q.length) === q) sc = 2;
      else if (tl.indexOf(q) === 0) sc = 1;
      else if (tl.indexOf(q) >= 0) sc = 0;
      return sc < 0 ? null : { s: s, sc: sc };
    }).filter(Boolean).sort(function (a, b) { return b.sc - a.sc; });
    var uniq = scored.filter(function (x) { return x.sc >= 2; });
    var show = (uniq.length === 1 ? uniq : scored).slice(0, 5).map(function (x) { return x.s; });
    bar._uniq = (uniq.length === 1) ? uniq[0].s.tag : '';
    bar.innerHTML = show.map(function (s) {
      return '<button type="button" data-tag="' + n7EscAttr_(s.tag) + '">' + n7EscAttr_(typeof sowLbl_==='function' ? sowLbl_(s) : s.tag) + (s.breed ? ' · ' + n7EscAttr_(s.breed) : '') + '</button>';
    }).join('');
  }
  bar.addEventListener('click', function (e) {
    var b = e.target.closest && e.target.closest('button'); if (!b) return;
    n7FillInput_(tag, b.getAttribute('data-tag'));
    var look = el.querySelector('#ef-look'); if (look) look.click();
  });
  tag.addEventListener('input', function () { draw(tag.value); });
  tag.addEventListener('keydown', function (e) {
    if (e.key !== 'Enter') return;
    if (bar._uniq && String(tag.value || '').replace(/\s+/g, '') !== bar._uniq) {
      e.preventDefault(); n7FillInput_(tag, bar._uniq);
      var look2 = el.querySelector('#ef-look'); if (look2) look2.click();
    }
  });
  if (!n7SugSows_._items && typeof apiF === 'function') {
    apiF('listSows', { includeExited: false }).then(function (r) {
      n7SugSows_._items = (r && (r.items || r.sows || r.rows || [])) || [];
      draw(tag.value);
    }).catch(function () {});
  } else draw(tag.value);
}
function n7Keypad_(el) {
  var view = (window.PL && PL.view) || '';
  if (view !== 'field' && view !== 'm') return;
  var tag = el.querySelector('#ef-tag'); if (!tag) return;
  if (tag.getAttribute('inputmode') !== 'numeric' && view !== 'field') return;
  var pad = el.querySelector('.n7-pad');
  if (!pad) {
    pad = document.createElement('div'); pad.className = 'n7-pad';
    var keys = ['1','2','3','4','5','6','7','8','9','지움','0','←'];
    pad.innerHTML = keys.map(function (k) { return '<button type="button" data-k="' + k + '">' + k + '</button>'; }).join('');
    var row = tag.closest && tag.closest('.ef-row');
    (row && row.parentNode ? row.parentNode : tag.parentNode).insertBefore(pad, (row && row.nextSibling) || tag.nextSibling);
    pad.addEventListener('mousedown', function (e) { e.preventDefault(); });
    pad.addEventListener('click', function (e) {
      var b = e.target.closest && e.target.closest('button'); if (!b) return;
      var k = b.getAttribute('data-k');
      if (k === '지움') tag.value = '';
      else if (k === '←') tag.value = String(tag.value || '').slice(0, -1);
      else tag.value = String(tag.value || '') + k;
      try { tag.dispatchEvent(new Event('input', { bubbles: true })); } catch (err) {}
      try { tag.focus(); } catch (err2) {}
    });
  }
  function show() { pad.classList.add('is-on'); }
  function hide() { setTimeout(function () { if (document.activeElement !== tag && !pad.contains(document.activeElement)) pad.classList.remove('is-on'); }, 180); }
  if (!tag.getAttribute('data-n7pad')) {
    tag.setAttribute('data-n7pad', '1');
    tag.addEventListener('focus', show);
    tag.addEventListener('blur', hide);
  }
}
function n7KoDate_(el) {
  /* t462: date row already has #ef-date + 오늘/어제 chips; do not duplicate the date text */
  if (!el) return;
  [].forEach.call(el.querySelectorAll('.n7-dateko'), function (n) { if (n.parentNode) n.parentNode.removeChild(n); });
}

/* t480u / QA1-005: 농장 설정 시간대 선택. IANA 목록, 한국어 이름, 기본 Asia/Seoul */
function n7TzOff_(tz, ms) {
  try {
    var p = {}, fmt = new Intl.DateTimeFormat('en-US', { timeZone: tz, timeZoneName: 'shortOffset', hour: '2-digit', minute: '2-digit', hour12: false, hourCycle: 'h23' });
    fmt.formatToParts(new Date(ms == null ? Date.now() : ms)).forEach(function (x) { p[x.type] = x.value; });
    var n = String(p.timeZoneName || '').replace(/^GMT/, 'UTC').replace(/^UTC(?=$|[^+-])/, 'UTC+0');
    return n.indexOf('UTC') === 0 ? n : ('UTC' + n);
  } catch (e) { return ''; }
}
function n7TzLabel_(tz) {
  var map = {
    'Asia/Seoul': '한국 (서울)',
    'Asia/Tokyo': '일본 (도쿄)',
    'Asia/Shanghai': '중국 (상하이)',
    'Asia/Hong_Kong': '홍콩',
    'Asia/Taipei': '대만 (타이베이)',
    'Asia/Ho_Chi_Minh': '베트남 (호찌민)',
    'Asia/Bangkok': '태국 (방콕)',
    'Asia/Kathmandu': '네팔 (카트만두)',
    'Asia/Kolkata': '인도 (콜카타)',
    'Asia/Calcutta': '인도 (콜카타)',
    'Asia/Manila': '필리핀 (마닐라)',
    'Asia/Jakarta': '인도네시아 (자카르타)',
    'Asia/Singapore': '싱가포르',
    'Asia/Kuala_Lumpur': '말레이시아 (쿠알라룸푸르)',
    'Asia/Phnom_Penh': '캄보디아 (프놈펜)',
    'Asia/Yangon': '미얀마 (양곤)',
    'Asia/Vientiane': '라오스 (비엔티안)',
    'Asia/Ulaanbaatar': '몽골 (울란바토르)',
    'Asia/Dhaka': '방글라데시 (다카)',
    'Asia/Karachi': '파키스탄 (카라치)',
    'Asia/Tashkent': '우즈베키스탄 (타슈켄트)',
    'Asia/Dubai': '아랍에미리트 (두바이)',
    'Australia/Sydney': '호주 (시드니)',
    'Australia/Melbourne': '호주 (멜버른)',
    'Pacific/Auckland': '뉴질랜드 (오클랜드)',
    'Pacific/Guam': '괌',
    'Europe/London': '영국 (런던)',
    'Europe/Berlin': '독일 (베를린)',
    'Europe/Paris': '프랑스 (파리)',
    'Europe/Madrid': '스페인 (마드리드)',
    'Europe/Rome': '이탈리아 (로마)',
    'Europe/Amsterdam': '네덜란드 (암스테르담)',
    'Europe/Warsaw': '폴란드 (바르샤바)',
    'Europe/Moscow': '러시아 (모스크바)',
    'Africa/Cairo': '이집트 (카이로)',
    'Africa/Johannesburg': '남아프리카 (요하네스버그)',
    'America/Los_Angeles': '미국 (로스앤젤레스)',
    'America/Denver': '미국 (덴버)',
    'America/Chicago': '미국 (시카고)',
    'America/New_York': '미국 (뉴욕)',
    'America/Toronto': '캐나다 (토론토)',
    'America/Vancouver': '캐나다 (밴쿠버)',
    'America/Sao_Paulo': '브라질 (상파울루)',
    'America/Mexico_City': '멕시코시티',
    'Pacific/Honolulu': '미국 (호놀룰루)',
    'UTC': '협정 세계시',
    'Etc/UTC': '협정 세계시'
  };
  var ko = map[tz], off = n7TzOff_(tz);
  if (ko) return ko + (off ? ' ' + off : '');
  var nice = String(tz || '').replace(/_/g, ' ').split('/');
  var lab = nice.length > 1 ? (nice[nice.length - 1] + ' (' + nice.slice(0, -1).join(' / ') + ')') : String(tz || '');
  return lab + (off ? ' ' + off : '');
}
function n7TzList_() {
  var prefer = ['Asia/Seoul','Asia/Tokyo','Asia/Shanghai','Asia/Hong_Kong','Asia/Taipei','Asia/Ho_Chi_Minh','Asia/Bangkok','Asia/Kathmandu','Asia/Kolkata','Asia/Manila','Asia/Jakarta','Asia/Singapore','Asia/Kuala_Lumpur','Asia/Phnom_Penh','Asia/Yangon','Asia/Vientiane','Asia/Ulaanbaatar','Asia/Dhaka','Asia/Karachi','Asia/Tashkent','Asia/Dubai','Australia/Sydney','Australia/Melbourne','Pacific/Auckland','Pacific/Guam','Europe/London','Europe/Berlin','Europe/Paris','Europe/Madrid','Europe/Rome','Europe/Amsterdam','Europe/Warsaw','Europe/Moscow','Africa/Cairo','Africa/Johannesburg','America/Los_Angeles','America/Denver','America/Chicago','America/New_York','America/Toronto','America/Vancouver','America/Sao_Paulo','America/Mexico_City','Pacific/Honolulu','UTC'];
  var all = [];
  try { if (typeof Intl !== 'undefined' && Intl.supportedValuesOf) all = Intl.supportedValuesOf('timeZone') || []; } catch (e) { all = []; }
  var seen = {}, out = [];
  function add(z) {
    if (!z || seen[z]) return;
    try { new Intl.DateTimeFormat('en-US', { timeZone: z }).format(new Date()); } catch (e) { return; }
    seen[z] = 1; out.push(z);
  }
  prefer.forEach(add);
  all.forEach(add);
  if (!seen['Asia/Seoul']) out.unshift('Asia/Seoul');
  return out;
}
function n7FarmTzCtl_(root) {
  if (!root) return;
  function buildSel(cur) {
    var sel = document.createElement('select');
    sel.className = 'f';
    sel.setAttribute('data-k', '시간대');
    sel.style.minHeight = '44px';
    sel.style.maxWidth = '100%';
    sel.style.width = '100%';
    var zones = n7TzList_();
    if (zones.indexOf(cur) < 0) zones = [cur].concat(zones);
    var preferN = 45, i, z, op, g1, g2;
    g1 = document.createElement('optgroup'); g1.label = '자주 쓰는 시간대';
    g2 = document.createElement('optgroup'); g2.label = '모든 시간대 (IANA)';
    for (i = 0; i < zones.length; i++) {
      z = zones[i];
      op = document.createElement('option');
      op.value = z;
      op.textContent = n7TzLabel_(z);
      if (z === cur) op.selected = true;
      (i < preferN ? g1 : g2).appendChild(op);
    }
    sel.appendChild(g1);
    if (g2.children.length) sel.appendChild(g2);
    sel.value = cur;
    return sel;
  }
  function applyCfg(z) {
    if (!z) return;
    if (window.PL && PL.boot) { PL.boot.cfg = PL.boot.cfg || {}; PL.boot.cfg['시간대'] = z; }
    if (typeof farmTz_ === 'function') farmTz_();
  }
  function sync(from) {
    var z = from && from.value;
    Array.prototype.forEach.call(root.querySelectorAll('[data-k="시간대"]'), function (el) {
      if (el !== from && el.value !== z) el.value = z;
    });
    applyCfg(z);
  }
  var existing = root.querySelector('[data-k="시간대"]');
  var cur = String((existing && existing.value) || (window.PL && PL.boot && PL.boot.cfg && PL.boot.cfg['시간대']) || 'Asia/Seoul').trim() || 'Asia/Seoul';
  var hosts = [];
  Array.prototype.forEach.call(root.querySelectorAll('tr, .n7-st-row'), function (row) {
    var k = '';
    var inp = row.querySelector && row.querySelector('[data-k="시간대"]');
    if (inp) k = '시간대';
    else {
      var cell = row.cells ? row.cells[0] : row.querySelector('.n7-st-k');
      k = ((cell && cell.textContent) || '').replace(/\s+/g, '');
    }
    if (k.indexOf('시간대') !== 0) return;
    hosts.push(row);
  });
  if (!hosts.length && existing) hosts.push(existing.parentNode);
  hosts.forEach(function (row) {
    var old = row.querySelector('[data-k="시간대"]');
    var sel = buildSel(old ? (old.value || cur) : cur);
    if (old && old.tagName === 'SELECT' && old.options && old.options.length > 10) {
      old.addEventListener('change', function () { sync(old); });
      return;
    }
    if (old && old.parentNode) old.parentNode.replaceChild(sel, old);
    else {
      var val = row.cells && row.cells[1] ? row.cells[1] : row;
      val.appendChild(sel);
    }
    if (row.cells && row.cells[1]) {
      row.cells[1].style.width = 'auto';
      row.cells[1].style.minWidth = '320px';
      row.cells[1].style.maxWidth = '440px';
      sel.style.minWidth = '300px';
    }
    sel.addEventListener('change', function () { sync(sel); });
  });
  var go = root.querySelector('#st-go');
  if (go && !go.getAttribute('data-n7tz')) {
    go.setAttribute('data-n7tz', '1');
    var prev = go.onclick;
    go.onclick = function (ev) {
      var zEl = root.querySelector('[data-k="시간대"]');
      applyCfg(zEl && zEl.value);
      if (typeof prev === 'function') return prev.call(this, ev);
    };
  }
}


function n7SettingsHub_(root) {
  var tbl = root && root.querySelector('#st-go') && root.querySelector('table.t');
  if (!tbl || tbl.getAttribute('data-n7hub')) return;
  tbl.setAttribute('data-n7hub', '1');
  var groups = [
    ['내 계정', /언어|암호|PIN|비밀번호|표시이름|내 이름|이름$/],
    ['농장', /농장|주소|전화|사업자|농장명|농장ID|위치|시간대|타임존|timezone/i],
    ['번식 기준', /임신|이유일령|재발|교배|후보|포유|대기|산차/],
    ['성적·목표', /KPI|PSY|MSY|목표|업계|확인필요|출하/],
    ['화면·알림', /화면|달력|표시|알림|메일|테마|글자/],
    ['약품·인증', /약품|백신|HACCP|인증|주사|무항생|복지/],
    ['위험 구역', /탈퇴|삭제|초기화|백업|내보내기|위험/]
  ];
  var rows = [].slice.call(tbl.rows, 1);
  var buckets = groups.map(function (g) { return { title: g[0], re: g[1], rows: [] }; });
  var other = [];
  rows.forEach(function (r) {
    var t = (r.textContent || '').replace(/\s+/g, '');
    var hit = -1, i;
    for (i = 0; i < buckets.length; i++) if (buckets[i].re.test(t)) { hit = i; break; }
    if (hit >= 0) buckets[hit].rows.push(r); else other.push(r);
  });
  var host = tbl.parentNode;
  buckets.forEach(function (b, i) {
    if (!b.rows.length) return;
    var box = document.createElement('div'); box.className = 'n7-st-hub' + (i < 2 ? ' on' : '');
    var btn = document.createElement('button'); btn.type = 'button';
    btn.innerHTML = b.title + '<span>' + b.rows.length + '</span>';
    var pane = document.createElement('div');
    var sub = document.createElement('table'); sub.className = 't';
    b.rows.forEach(function (r) { sub.appendChild(r); });
    pane.appendChild(sub);
    pane.hidden = i >= 2;
    btn.onclick = function () { box.classList.toggle('on'); pane.hidden = !box.classList.contains('on'); };
    box.appendChild(btn); box.appendChild(pane);
    host.insertBefore(box, tbl);
  });
  if (other.length) {
    other.forEach(function (r) { tbl.querySelector('tbody') ? tbl.tBodies[0].appendChild(r) : tbl.appendChild(r); });
  } else tbl.style.display = 'none';
}
function n7DangerConfirm_(root) {
  if (!root || root.getAttribute('data-n7dang')) return;
  root.setAttribute('data-n7dang', '1');
  root.addEventListener('click', function (e) {
    var b = e.target.closest && e.target.closest('.n7-dang, .btn.warn, [data-danger]');
    if (!b || b.getAttribute('data-n7ok')) return;
    var t = (b.textContent || '').replace(/\s+/g, '');
    if (!/삭제|탈퇴|초기화|해지/.test(t)) return;
    e.preventDefault(); e.stopImmediatePropagation();
    if (window.confirm(t + ' — 계속할까요?')) { b.setAttribute('data-n7ok', '1'); b.click(); }
  }, true);
}

n7HookRemember_();


function n7FieldHomeTiles_() {
  if (!(window.PL && PL.view === 'field')) return;
  var types = document.querySelector('.types');
  if (!types || types.querySelector('[data-n7pd]')) return;
  var exitBtn = types.querySelector('[data-t="도폐사"]');
  var wr = types.querySelector('#f-wr');
  function mk(id, icon, label, fn) {
    var b = document.createElement('button');
    b.setAttribute('data-n7pd', id);
    b.type = 'button';
    b.innerHTML = '<i>' + icon + '</i>' + label;
    b.onclick = fn;
    return b;
  }
  var a = mk('pd', '−', '포유자돈 폐사', function () {
    if (typeof fEntry === 'function') fEntry('자돈폐사');
  });
  var b = mk('gd', '▤', '자육비 폐사', function () { n7GrpDeath_(); });
  var after = exitBtn && exitBtn.nextSibling;
  if (exitBtn && exitBtn.parentNode === types) {
    types.insertBefore(a, after || wr || null);
    types.insertBefore(b, a.nextSibling);
  } else if (wr) { types.insertBefore(a, wr); types.insertBefore(b, wr); }
  else { types.appendChild(a); types.appendChild(b); }
}
function n7GrpDeath_() {
  if (typeof header !== 'function') { if (typeof toast === 'function') toast('현장 화면에서만 쓸 수 있습니다'); return; }
  if (window.PL) PL._fre = n7GrpDeath_;
  var app = document.getElementById('app'); if (!app) return;
  app.innerHTML = header('자육비 폐사', 1) + '<main><div class="entry big" id="n7-gd"><div class="loading">…</div></div></main>';
  var back = document.getElementById('f-back'); if (back) back.onclick = function () { fHome(); };
  document.body.classList.remove('far-open');
  n7ActionBar_('');
  (typeof apiF === 'function' ? apiF('getGroupBook', '') : Promise.reject(new Error('no api'))).then(function (b) {
    b = b || {};
    var stages = b.stageList || ['자돈', '육성', '비육'];
    var groups = b.groups || [];
    var causes = (b.causes || []).slice();
    if (causes.indexOf('기타') < 0) causes.push('기타');
    var locs = (window.PL && PL.boot && PL.boot.locs) || [];
    var rooms = [];
    (locs || []).forEach(function (x) {
      var code = x.code || x['위치코드'] || x.id || '';
      var step = x.level || x['단계'] || '';
      if (code && (step === 'room' || /R\d+/.test(code))) rooms.push({ code: code, name: x.name || x['이름'] || code });
    });
    var box = document.getElementById('n7-gd'); if (!box) return;
    var locH = rooms.length ? '<label class="l">돈방</label><select id="n7-gd-loc" class="f"><option value="">(선택)</option>' + rooms.map(function (r) { return '<option value="' + n7EscAttr_(r.code) + '">' + n7EscAttr_(r.name) + '</option>'; }).join('') + '</select>' : '';
    box.innerHTML = '<label class="l">작업일 *</label><div class="row ef-row"><input class="f" id="n7-gd-d" type="date" value="' + (typeof window.today === 'function' ? window.today() : ((window.PL && PL._daily && PL._daily.today) || '')) + '"><button type="button" class="btn sec" data-day="0">오늘</button><button type="button" class="btn sec" data-day="-1">어제</button></div>'
      + '<label class="l">단계 *</label><div class="seg" id="n7-gd-st">' + stages.map(function (s, i) { return '<button type="button" class="' + (i === 0 ? 'on' : '') + '" data-v="' + n7EscAttr_(s) + '">' + n7EscAttr_(s) + '</button>'; }).join('') + '</div>'
      + '<label class="l">돈군</label><select id="n7-gd-g" class="f"><option value="">(단계로만)</option>' + groups.map(function (g) { return '<option value="' + n7EscAttr_(g.id) + '">' + n7EscAttr_((g.name || g.id) + ' · ' + (g.stage || '')) + '</option>'; }).join('') + '</select>'
      + locH
      + '<label class="l">두수 *</label><div class="row stepper"><button type="button" class="btn sec step" data-d="-1">−</button><input class="f num" id="n7-gd-n" type="number" inputmode="numeric" min="1" value="1"><button type="button" class="btn sec step" data-d="1">＋</button></div>'
      + '<label class="l">원인 *</label><div class="seg" id="n7-gd-cz">' + causes.map(function (c) { return '<button type="button" data-v="' + n7EscAttr_(c) + '">' + n7EscAttr_(c) + '</button>'; }).join('') + '</div>'
      + '<div class="n7-cz-err" id="n7-gd-cerr" hidden>원인을 고르세요. 모르면 기타를 고르세요.</div>'
      + '<label class="l">비고</label><input class="f" id="n7-gd-m" maxlength="200">'
      + '<div id="n7-gd-msg"></div>'
      + '<button class="btn block savebtn" id="n7-gd-save" style="margin-top:16px">자육비 폐사 저장</button>';
    n7BigSteppers_(box);
    if (typeof nov7BindDayBtns_ === 'function') nov7BindDayBtns_(box, '#n7-gd-d');
    else box.querySelectorAll('[data-day]').forEach(function (btn) {
      btn.onclick = function () { var d = box.querySelector('#n7-gd-d'); if (d && typeof addDays === 'function') d.value = addDays(today(), Number(btn.getAttribute('data-day'))); };
    });
    box.querySelectorAll('#n7-gd-st button').forEach(function (btn) {
      btn.onclick = function () { box.querySelectorAll('#n7-gd-st button').forEach(function (x) { x.classList.remove('on'); }); btn.classList.add('on'); };
    });
    box.querySelectorAll('#n7-gd-cz button').forEach(function (btn) {
      btn.onclick = function () {
        var on = btn.classList.contains('on');
        box.querySelectorAll('#n7-gd-cz button').forEach(function (x) { x.classList.remove('on'); });
        if (!on) btn.classList.add('on');
        var err = box.querySelector('#n7-gd-cerr'); if (err) err.hidden = true;
      };
    });
    box.querySelector('#n7-gd-save').onclick = function () {
      var stBtn = box.querySelector('#n7-gd-st button.on');
      var czBtn = box.querySelector('#n7-gd-cz button.on');
      var head = box.querySelector('#n7-gd-n').value;
      var msg = box.querySelector('#n7-gd-msg');
      if (!czBtn) {
        var err = box.querySelector('#n7-gd-cerr'); if (err) err.hidden = false;
        if (msg && typeof errHTML === 'function') msg.innerHTML = errHTML('원인을 고르세요. 모르면 기타를 고르세요.');
        return;
      }
      if (!head || +head < 1) { if (msg && typeof errHTML === 'function') msg.innerHTML = errHTML('두수를 입력하세요'); return; }
      var x = { type: '폐사', date: box.querySelector('#n7-gd-d').value, stage: stBtn ? stBtn.getAttribute('data-v') : '', groupId: box.querySelector('#n7-gd-g').value, head: head, cause: czBtn.getAttribute('data-v'), memo: box.querySelector('#n7-gd-m').value, reqId: (typeof uuid === 'function' ? uuid() : ('n7gd-' + Date.now())) };
      var loc = box.querySelector('#n7-gd-loc'); if (loc && loc.value) x.loc = loc.value;
      var btn = box.querySelector('#n7-gd-save'); btn.disabled = true;
      apiF('saveGroupEvent', x).then(function (r) {
        if (typeof toast === 'function') toast('저장했습니다');
        if (typeof fHome === 'function') fHome();
      }).catch(function (e) {
        btn.disabled = false;
        if (msg && typeof errHTML === 'function') msg.innerHTML = errHTML(e);
      });
    };
  }).catch(function (e) {
    var box = document.getElementById('n7-gd');
    if (box && typeof errHTML === 'function') box.innerHTML = errHTML(e);
  });
}
function n7BoarChips_(el, typ) {
  var view = window.PL && PL.view;
  if (view !== 'm' && view !== 'field') return;
  var inp = el.querySelector('[data-k="웅돈"]'); if (!inp) return;
  if (typ === '교배' && !inp.getAttribute('data-n7boar-clr')) {
    inp.setAttribute('data-n7boar-clr', '1');
    inp.value = '';
  }
  var old = el.querySelector('.n7-boar-chips'); if (old) old.remove();
  var qp = el.querySelector('.n7-qp[data-qk="웅돈"]'); if (qp) qp.remove();
  var tops = (typeof n7HistTop_ === 'function' ? n7HistTop_('웅돈', 3) : []).slice(0, 3);
  if (!tops.length) return;
  var bar = document.createElement('div');
  bar.className = 'n7-boar-chips rchips';
  bar.innerHTML = '<span class="mut">최근 번호</span>' + tops.map(function (v) {
    return '<button type="button" class="chipb" data-v="' + n7EscAttr_(v) + '">' + n7EscAttr_(v) + '</button>';
  }).join('');
  var host = (inp.closest && inp.closest('.row')) || inp;
  host.parentNode.insertBefore(bar, host.nextSibling);
  bar.addEventListener('click', function (e) {
    var b = e.target.closest && e.target.closest('.chipb'); if (!b) return;
    n7FillInput_(inp, b.getAttribute('data-v'));
    bar.querySelectorAll('.chipb').forEach(function (x) { x.classList.remove('on'); });
    b.classList.add('on');
  });
}
function n7BigSteppers_(el) {
  if (!el) return;
  var view = window.PL && PL.view;
  if (view !== 'm' && view !== 'field') return;
  var inputs = el.querySelectorAll('input[type="number"], input.num');
  [].forEach.call(inputs, function (inp) {
    if (inp.closest && inp.closest('.stepper')) return;
    if (inp.disabled || inp.readOnly) return;
    var row = document.createElement('div'); row.className = 'row stepper n7-step';
    var m = document.createElement('button'); m.type = 'button'; m.className = 'btn sec step'; m.setAttribute('data-d', '-1'); m.textContent = '−';
    var p = document.createElement('button'); p.type = 'button'; p.className = 'btn sec step'; p.setAttribute('data-d', '1'); p.textContent = '＋';
    inp.parentNode.insertBefore(row, inp);
    row.appendChild(m); row.appendChild(inp); row.appendChild(p);
  });
  if (el.getAttribute('data-n7step')) return;
  el.setAttribute('data-n7step', '1');
  el.addEventListener('click', function (e) {
    var b = e.target.closest && e.target.closest('.step'); if (!b || !el.contains(b)) return;
    if (b.onclick) return;
    var i = b.parentNode && b.parentNode.querySelector('input'); if (!i) return;
    var step = parseFloat(i.step); if (!step || isNaN(step)) step = 1;
    var d = Number(b.getAttribute('data-d') || b.dataset.d || 0);
    var v = Number(i.value); if (isNaN(v)) v = 0;
    var nv = v + d * step;
    var min = i.min === '' || i.min == null ? 0 : Number(i.min);
    var max = i.max === '' || i.max == null ? Infinity : Number(i.max);
    if (nv < min) nv = min; if (nv > max) nv = max;
    i.value = (Math.abs(step - Math.round(step)) < 1e-9) ? String(Math.round(nv)) : String(Math.round(nv * 100) / 100);
    try { i.dispatchEvent(new Event('input', { bubbles: true })); } catch (err) {}
    try { i.dispatchEvent(new Event('change', { bubbles: true })); } catch (err2) {}
  });
}

var PiglogNov7 = { canAi: nov7CanAi_, trendWord: nov7Trend_, decideNotice: nov7Decide_, trendFit: nov7Fit_, suggestName: nov7SuggestName_, prepareNames: nov7PrepareNames_, pushLockText: function () { return { title: '피그로그', body: '새 메시지가 있습니다', tag: 'piglog-msg' }; } };


function n7MenuSoon_(items, cur) {
  if (typeof soonPage_ !== 'function' || typeof menuHTML !== 'function') return menuHTML(items, cur);
  var rest = items.filter(function (m) { return !soonPage_(m[0]); });
  var soon = items.filter(function (m) { return soonPage_(m[0]); });
  var html = menuHTML(rest, cur);
  if (!soon.length) return html;
  var open = soon.some(function (m) { return m[0] === cur; });
  function lbl(m) { return /^nav\./.test(m[1]) ? T(m[1]) : m[1]; }
  var links = soon.map(function (m) {
    return '<a data-p="' + m[0] + '" class="sub' + (m[0] === cur ? ' on' : '') + '"><span>' + m[2] + '</span>' + lbl(m) + ' <small class="mut">곧 열려요</small></a>';
  }).join('');
  return html + '<div class="grp soon-grp' + (open ? ' open' : '') + '"><button type="button" class="gh" aria-expanded="' + open + '">곧 열려요<i aria-hidden="true">▾</i></button><div class="gi">' + links + '</div></div>';
}


function n7EntryKeys_(el) {
  if (!el || el._n7keys) return;
  el._n7keys = 1;
  el.addEventListener('keydown', function (e) {
    var t = e.target;
    if (!t) return;
    if (e.key === 'Enter' && t.id === 'ef-tag') return;
    if (e.key === 'Enter' && t.closest && t.closest('#ef-save, button.btn, .btn')) return;
    if (e.key === 'Enter' && t.tagName === 'INPUT') { e.preventDefault(); return; }
    if (e.key === 'Tab' && !e.shiftKey && t && (t.id === 'ef-date' || t.getAttribute('type') === 'date')) {
      var form = (t.closest && (t.closest('.entry') || t.closest('form'))) || el;
      var fields = [].slice.call(form.querySelectorAll('input:not([type=hidden]):not([disabled]), select, textarea')).filter(function (x) { return x.offsetParent && x.type !== 'checkbox' && x.type !== 'radio' && x.type !== 'file'; });
      var i = fields.indexOf(t), next = i >= 0 ? fields[i + 1] : null;
      if (next) { e.preventDefault(); next.focus(); if (next.select) try { next.select(); } catch (x) {} }
    }
  });
}
function n7HookEntryKeys_() {
  function wrap(name) {
    var fn = typeof window[name] === 'function' ? window[name] : null;
    if (!fn || fn._n7keys) return;
    window[name] = function (el) {
      var r = fn.apply(this, arguments);
      try { var host = el && el.querySelector ? (el.querySelector('.entry') || el) : el; n7EntryKeys_(host); } catch (e) {}
      return r;
    };
    window[name]._n7keys = 1;
  }
  wrap('renderEntryForm'); wrap('pageEntry'); wrap('pageEntryW_'); wrap('fEntry');
  if (typeof document !== 'undefined' && !n7HookEntryKeys_._obs) {
    n7HookEntryKeys_._obs = 1;
    try {
      var mo = new MutationObserver(function () {
        var ev = document.querySelector('.entry');
        if (ev) n7EntryKeys_(ev);
      });
      mo.observe(document.body, { childList: true, subtree: true });
    } catch (e2) {}
  }
}
function n7MatingConfirm_() {
  if (typeof document === 'undefined' || document._n7mc) return;
  document._n7mc = 1;
  document.addEventListener('click', function (e) {
    var b = e.target && e.target.closest && e.target.closest('#ef-save, button#ef-save');
    if (!b) return;
    var form = b.closest && (b.closest('.entry') || b.closest('#ef-form') || document.querySelector('.entry'));
    if (!form) return;
    var typ = (form.getAttribute('data-type') || form.getAttribute('data-k') || (window.PL && (PL._entryType || PL._lastType)) || '');
    var onBtn = document.querySelector('#en-t button.on, .tabs button.on');
    if (onBtn) typ += ' ' + (onBtn.getAttribute('data-t') || onBtn.textContent || '');
    var title = ((document.getElementById('w-title') || document.getElementById('m-title') || {}).textContent || '');
    if (!/교배/.test(typ + ' ' + title) && !(form.className && /mat|교배/.test(form.className))) {
      var lab = (form.querySelector('h2,h3,.entry h2, legend, .l') || {}).textContent || '';
      if (!/교배/.test(lab + typ)) return;
    }
    if (b._n7ok) { b._n7ok = 0; return; }
    var methodEl = form.querySelector('[data-k="교배방법"] button.on, [data-k="교배방법"] .on, #ef-method button.on, .seg[data-k="교배방법"] button.on, select[name="교배방법"]');
    var boarEl = form.querySelector('[data-k="웅돈"] input, #ef-boar, input[name="웅돈"], #ef-boarNm, [data-k="웅돈"]');
    var method = methodEl ? (methodEl.value || methodEl.getAttribute('data-v') || methodEl.textContent || '').trim() : '인공';
    var boar = boarEl ? (boarEl.value || '').trim() : '';
    if (!method) method = '인공';
    e.preventDefault();
    if (e.stopImmediatePropagation) e.stopImmediatePropagation();
    else e.stopPropagation();
    if (b.getAttribute('data-n7lbl')) b.textContent = b.getAttribute('data-n7lbl');
    else if (/저장 중/.test(b.textContent||'')) b.textContent = '교배 저장';
    b.disabled = false; b.removeAttribute('data-flight');
    var ok = true;
    if (typeof n7Ask_ === 'function') {
      n7Ask_({
        title: '교배 저장',
        body: (boar ? ('웅돈 ' + boar + ', ') : '') + '교배방법 ' + method + '으로 저장할까요?',
        yes: '저장', no: '취소',
        done: function (yes) {
          if (!yes) return;
          b._n7ok = 1; try { b.click(); } catch (x) {}
        }
      });
      return;
    }
    if (window.confirm((boar ? ('웅돈 ' + boar + ', ') : '') + '교배방법 ' + method + '으로 저장할까요?')) {
      b._n7ok = 1; b.click();
    }
  }, true);
}

function soonPage_(p) { return false; }
function soonHTML_() { return '<div class="card empty" style="text-align:center;padding:28px 16px"><div class="mut" style="font-size:13px">곧 열려요</div><p style="margin:8px 0 0">이 기능은 아직 열리지 않았어요. 메뉴에만 표시합니다.</p></div>'; }
function vetCode_() { try { var h = String(location.hash || ''), q = new URLSearchParams(location.search).get('vet'); var m = /(?:^|#|&)vet=([A-Za-z0-9_-]+)/.exec(h); return (m && m[1]) || q || ''; } catch (e) { return ''; } }



/* t532u: 마대리 로그인 시안. Keep #lg-id #lg-pw #lg-go hooks. No AAA/dark on login. No ?state= preview script. */
function n7LoginCssLoad_(cb) {
  if (document.getElementById('n7login-css')) { if (cb) cb(); return; }
  var href = ((window.PIGLOG_SUPA || {}).n7login || {}).css;
  if (!href) { if (cb) cb(); return; }
  var l = document.createElement('link');
  l.id = 'n7login-css'; l.rel = 'stylesheet'; l.href = href;
  l.onload = function () { if (cb) cb(); };
  l.onerror = function () { if (cb) cb(); };
  document.head.appendChild(l);
}
function n7LoginLeave_() {
  document.documentElement.classList.remove('pl-login');
  if (document.body) document.body.classList.remove('pl-login', 'is-error', 'is-locked');
  var l = document.getElementById('n7login-css');
  if (l && l.parentNode) l.parentNode.removeChild(l);
  var svg = document.getElementById('n7login-svg');
  if (svg && svg.parentNode) svg.parentNode.removeChild(svg);
  if (n7LoginLeave_._theme != null) {
    try {
      if (n7LoginLeave_._theme) document.documentElement.setAttribute('data-theme', n7LoginLeave_._theme);
      else document.documentElement.removeAttribute('data-theme');
    } catch (e) {}
    n7LoginLeave_._theme = null;
  }
}
function n7LoginSvg_() {
  if (document.getElementById('n7login-svg')) return;
  var s = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
  s.id = 'n7login-svg';
  s.setAttribute('width', '0'); s.setAttribute('height', '0');
  s.setAttribute('aria-hidden', 'true');
  s.style.position = 'absolute';
  s.innerHTML = '<symbol id="i-globe" viewBox="0 0 24 24"><circle cx="12" cy="12" r="10"/><path d="M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20"/><path d="M2 12h20"/></symbol><symbol id="i-chevron" viewBox="0 0 24 24"><path d="m6 9 6 6 6-6"/></symbol><symbol id="i-user" viewBox="0 0 24 24"><circle cx="12" cy="8" r="5"/><path d="M20 21a8 8 0 0 0-16 0"/></symbol><symbol id="i-lock" viewBox="0 0 24 24"><rect x="3" y="11" width="18" height="11" rx="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/></symbol><symbol id="i-eye" viewBox="0 0 24 24"><path d="M2.06 12.35a1 1 0 0 1 0-.7 10.75 10.75 0 0 1 19.88 0 1 1 0 0 1 0 .7 10.75 10.75 0 0 1-19.88 0"/><circle cx="12" cy="12" r="3"/></symbol><symbol id="i-phone" viewBox="0 0 24 24"><rect x="5" y="2" width="14" height="20" rx="2"/><path d="M12 18h.01"/></symbol><symbol id="i-shield" viewBox="0 0 24 24"><path d="M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z"/></symbol><symbol id="i-alert" viewBox="0 0 24 24"><circle cx="12" cy="12" r="10"/><path d="M12 8v4"/><path d="M12 16h.01"/></symbol><symbol id="i-clock" viewBox="0 0 24 24"><circle cx="12" cy="12" r="10"/><path d="M12 6v6l4 2"/></symbol><symbol id="i-arrow" viewBox="0 0 24 24"><path d="M5 12h14"/><path d="m12 5 7 7-7 7"/></symbol><symbol id="i-check" viewBox="0 0 24 24"><path d="M20 6 9 17l-5-5"/></symbol><symbol id="i-mascot" viewBox="0 0 1024 1024"><rect width="1024" height="1024" rx="190" fill="#258258"/><path d="M-125 40C-118-60-70-160-18-178 14-188 40-172 58-138 86-86 112-24 125 40Z" fill="#fff" stroke="#fff" stroke-width="22" stroke-linejoin="round" transform="translate(352 338) rotate(-30)"/><path d="M-125 40C-118-60-70-160-18-178 14-188 40-172 58-138 86-86 112-24 125 40Z" fill="#fff" stroke="#fff" stroke-width="22" stroke-linejoin="round" transform="translate(1024 0) scale(-1 1) translate(352 338) rotate(-30)"/><path d="M512 262C714.8 262 840 392 850 582 856 762 762.12 872 512 872 261.88 872 168 762 174 582 184 392 309.2 262 512 262Z" fill="#fff"/><circle cx="384" cy="545" r="36" fill="#14312B"/><circle cx="640" cy="545" r="36" fill="#14312B"/><ellipse cx="512" cy="712" rx="150" ry="92" fill="#F0827C"/><ellipse cx="458" cy="716" rx="23" ry="31" fill="#14312B"/><ellipse cx="566" cy="716" rx="23" ry="31" fill="#14312B"/></symbol>';
  document.body.insertBefore(s, document.body.firstChild);
}
function n7LoginSkin_(el) {
  el = el || document.getElementById('app') || document.body;
  if (!el || !el.querySelector || !el.querySelector('#lg-id')) return;
  n7LoginCssLoad_();
  n7LoginSvg_();
  if (typeof n7StripLoginChrome_ === 'function') n7StripLoginChrome_();
  document.documentElement.classList.add('pl-login');
  if (document.body) document.body.classList.add('pl-login');
  if (n7LoginLeave_._theme == null) {
    n7LoginLeave_._theme = document.documentElement.getAttribute('data-theme') || '';
    try { document.documentElement.removeAttribute('data-theme'); } catch (eT) {}
  }
  if (el.querySelector('.pl-login__layout')) return;
  var idIn = el.querySelector('#lg-id');
  var pwIn = el.querySelector('#lg-pw');
  var goBtn = el.querySelector('#lg-go');
  var err = el.querySelector('#lg-err');
  var forgot = el.querySelector('#lg-forgot');
  var signup = el.querySelector('#lg-signup');
  var lang = el.querySelector('#lang-pick');
  var legalBox = document.createElement('span');
  el.querySelectorAll('.lglinks a, .ver a, a[href*="terms"], a[href*="privacy"], a[href*="legal"]').forEach(function (a) {
    if (a.id === 'lg-forgot' || a.id === 'lg-signup') return;
    legalBox.appendChild(a.cloneNode(true));
  });
  function detach(n) { if (n && n.parentNode) n.parentNode.removeChild(n); return n; }
  idIn = detach(idIn); pwIn = detach(pwIn); goBtn = detach(goBtn); err = detach(err);
  forgot = detach(forgot); signup = detach(signup); lang = detach(lang);
  idIn.classList.add('pl-input');
  if (!idIn.getAttribute('placeholder')) idIn.setAttribute('placeholder', '아이디 입력');
  pwIn.classList.add('pl-input');
  if (!pwIn.getAttribute('placeholder')) pwIn.setAttribute('placeholder', '비밀번호 입력');
  goBtn.classList.add('pl-btn', 'pl-btn--primary');
  goBtn.type = 'button';
  var wrap = document.createElement('div');
  wrap.className = 'pl-login__layout';
  wrap.innerHTML =
    '<section class="pl-brand" aria-label="PIGLOG 소개">' +
      '<div class="pl-brand__lockup"><svg class="pl-brand__mark" aria-hidden="true"><use href="#i-mascot"></use></svg><span class="pl-brand__word">PIGLOG</span></div>' +
      '<svg class="pl-brand__hero" aria-hidden="true"><use href="#i-mascot"></use></svg>' +
      '<div class="pl-brand__copy"><p class="pl-brand__eyebrow">양돈 기록 관리</p><h1 class="pl-brand__title">기록은 한곳에.<br>농장은 한눈에.</h1><p class="pl-brand__lead">교배부터 분만, 이유까지. 오늘 할 일과 이번 주 흐름을 한 화면에서 확인하세요.</p></div>' +
      '<div class="pl-preview" aria-hidden="true">' +
        '<div class="pl-preview__card pl-preview__card--main">' +
          '<div class="pl-preview__head"><span class="pl-preview__title">이번 주 한눈에</span><span class="pl-preview__tag">화면 예시</span></div>' +
          '<div class="pl-preview__kpis">' +
            '<div class="pl-kpi"><span class="pl-kpi__label">분만 예정</span><span class="pl-kpi__value">3<small>복</small></span></div>' +
            '<div class="pl-kpi"><span class="pl-kpi__label">교배 예정</span><span class="pl-kpi__value">4<small>복</small></span></div>' +
            '<div class="pl-kpi"><span class="pl-kpi__label">이유 예정</span><span class="pl-kpi__value">2<small>복</small></span></div>' +
            '<div class="pl-kpi"><span class="pl-kpi__label">평균 총산자수</span><span class="pl-kpi__value">13.2<small>두</small></span></div>' +
          '</div>' +
          '<div class="pl-chart"><div class="pl-chart__bars"><i style="--h:46%"></i><i style="--h:58%"></i><i style="--h:40%"></i><i style="--h:66%"></i><i style="--h:54%"></i><i style="--h:72%"></i><i style="--h:62%"></i><i class="is-now" style="--h:84%"></i></div>' +
          '<div class="pl-chart__axis"><span>39</span><span>40</span><span>41</span><span>42</span><span>43</span><span>44</span><span>45</span><span>46주</span></div></div>' +
        '</div>' +
        '<div class="pl-preview__card pl-preview__card--todo"><span class="pl-preview__title">오늘 할 일</span><ul class="pl-todo">' +
          '<li class="is-done"><span class="pl-todo__dot"><svg><use href="#i-check"></use></svg></span>분만 기록 · 0012</li>' +
          '<li><span class="pl-todo__dot"></span>이유 예정 · 2복</li>' +
          '<li><span class="pl-todo__dot"></span>백신 접종 · 자돈사 2</li>' +
        '</ul></div>' +
        '<div class="pl-preview__toast"><span class="pl-preview__toast-icon"><svg><use href="#i-check"></use></svg></span>기록이 저장됐어요 · 오전 7:42</div>' +
      '</div>' +
      '<p class="pl-brand__note">화면 예시 · 실제 수치는 농장마다 다릅니다</p>' +
    '</section>' +
    '<section class="pl-auth" aria-labelledby="auth-title">' +
      '<div class="pl-auth__top"><label class="pl-lang"><span class="sr-only">언어 선택</span><svg class="pl-icon pl-lang__icon" aria-hidden="true"><use href="#i-globe"></use></svg><span class="pl-lang__slot"></span><svg class="pl-icon pl-lang__chevron" aria-hidden="true"><use href="#i-chevron"></use></svg></label></div>' +
      '<div class="pl-auth__body">' +
        '<header class="pl-auth__header"><h2 id="auth-title" class="pl-auth__title">로그인</h2><p class="pl-auth__sub">농장주 · 관리자 계정으로 로그인하세요.</p></header>' +
        '<div class="pl-alert-slot"></div>' +
        '<div class="pl-form" id="n7-lg-form">' +
          '<div class="pl-field"><label class="pl-field__label" for="lg-id">아이디</label><div class="pl-field__control"><svg class="pl-icon pl-field__icon" aria-hidden="true"><use href="#i-user"></use></svg><span class="pl-id-slot"></span></div></div>' +
          '<div class="pl-field pl-field--password"><div class="pl-field__row"><label class="pl-field__label" for="lg-pw">비밀번호</label><span class="pl-forgot-slot"></span></div><div class="pl-field__control"><svg class="pl-icon pl-field__icon" aria-hidden="true"><use href="#i-lock"></use></svg><span class="pl-pw-slot"></span><button class="pl-field__toggle" type="button" aria-label="비밀번호 보기"><svg class="pl-icon"><use href="#i-eye"></use></svg></button></div></div>' +
          '<span class="pl-go-slot"></span>' +
        '</div>' +
        '<div class="pl-signup"><span class="pl-signup__text">처음 오셨나요?</span><span class="pl-signup-slot"></span></div>' +
        '<p class="pl-signup__note">가입하면 농장 관리자가 승인한 뒤 사용할 수 있어요.</p>' +
        '<ul class="pl-notes"><li class="pl-note"><svg class="pl-icon" aria-hidden="true"><use href="#i-shield"></use></svg><p>비밀번호를 <b class="pl-lock-max">5회</b> 틀리면 <b class="pl-lock-min">10분</b> 동안 로그인이 잠겨요.</p></li><li class="pl-note"><svg class="pl-icon" aria-hidden="true"><use href="#i-phone"></use></svg><p>현장 직원은 휴대폰에서 <b>PIN</b>으로 로그인해요. PIN을 잊었다면 농장주에게 초기화를 요청하세요.</p></li></ul>' +
      '</div>' +
      '<footer class="pl-auth__footer"><nav class="pl-legal" aria-label="약관"><span class="pl-legal-slot"></span></nav><span class="pl-copy">© PIGLOG</span></footer>' +
    '</section>';
  var host = el.querySelector('.loginwrap') || el;
  host.innerHTML = '';
  host.appendChild(wrap);
  var slot;
  slot = wrap.querySelector('.pl-id-slot'); if (slot) slot.replaceWith(idIn);
  slot = wrap.querySelector('.pl-pw-slot'); if (slot) slot.replaceWith(pwIn);
  slot = wrap.querySelector('.pl-go-slot'); if (slot) slot.replaceWith(goBtn);
  slot = wrap.querySelector('.pl-alert-slot');
  if (slot) {
    if (!err) { err = document.createElement('div'); err.id = 'lg-err'; }
    err.classList.add('pl-alert-live');
    slot.replaceWith(err);
  }
  if (forgot) {
    forgot.classList.add('pl-link', 'pl-link--sm');
    slot = wrap.querySelector('.pl-forgot-slot');
    if (slot) slot.replaceWith(forgot);
  }
  if (signup) {
    signup.classList.add('pl-link', 'pl-link--strong');
    if (!signup.querySelector('.pl-icon')) {
      var ic = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
      ic.setAttribute('class', 'pl-icon'); ic.setAttribute('aria-hidden', 'true');
      ic.innerHTML = '<use href="#i-arrow"></use>';
      signup.appendChild(ic);
    }
    slot = wrap.querySelector('.pl-signup-slot');
    if (slot) slot.replaceWith(signup);
  }
  if (lang) {
    lang.classList.add('pl-lang__select');
    slot = wrap.querySelector('.pl-lang__slot');
    if (slot) slot.replaceWith(lang);
  }
  slot = wrap.querySelector('.pl-legal-slot');
  if (slot && legalBox.childNodes.length) slot.replaceWith(legalBox);
  else if (slot) slot.remove();
  var tog = wrap.querySelector('.pl-field__toggle');
  if (tog && !tog._n7eye) {
    tog._n7eye = 1;
    tog.onclick = function () {
      var on = pwIn.type === 'password';
      pwIn.type = on ? 'text' : 'password';
      tog.setAttribute('aria-label', on ? '비밀번호 숨기기' : '비밀번호 보기');
    };
  }
  if (typeof legalLinkBind === 'function') try { legalLinkBind(el); } catch (eL) {}
  var mx = (window.PL && PL.lockMax) || 5, mn = (window.PL && PL.lockMin) || 10;
  wrap.querySelectorAll('.pl-lock-max').forEach(function (n) { n.textContent = mx + '회'; });
  wrap.querySelectorAll('.pl-lock-min').forEach(function (n) { n.textContent = mn + '분'; });
  if (err && !err._n7obs) {
    err._n7obs = 1;
    var syncErr = function () {
      var txt = (err.innerText || err.textContent || '').trim();
      var locked = /잠겼|잠겨|lock/i.test(txt);
      var bad = !!txt && !/확인하고|기다리는|느려요/.test(txt);
      if (document.body) {
        document.body.classList.toggle('is-locked', locked);
        document.body.classList.toggle('is-error', !locked && bad);
      }
      if (locked) {
        wrap.querySelectorAll('.pl-form input, .pl-form button, #lg-id, #lg-pw, #lg-go').forEach(function (x) { x.disabled = true; });
      }
    };
    try { new MutationObserver(syncErr).observe(err, { childList: true, subtree: true, characterData: true }); } catch (eO) {}
  }
}
if (typeof renderLogin === 'function' && !renderLogin._t532) {
  var _rl532 = renderLogin;
  renderLogin = function (el, o) {
    var r = _rl532(el, o);
    try { n7LoginSkin_(el || document.getElementById('app') || document.body); } catch (eS) {}
    return r;
  };
  renderLogin._t532 = 1;
}
if (typeof afterLogin === 'function' && !afterLogin._t532) {
  var _al532 = afterLogin;
  afterLogin = function (r, o) {
    try { n7LoginLeave_(); } catch (eL2) {}
    return _al532(r, o);
  };
  afterLogin._t532 = 1;
}

function n7L_(msg, shell, titleK, subK, pin) {
  var d = function () { boot(shell); };
  var o = { title: T(titleK), sub: T(subK), msg: msg, pin: !!pin, onDone: function () { typeof _vetAfterLogin === 'function' ? _vetAfterLogin(d) : d(); } };
  if (typeof vetCode_ === 'function' && vetCode_()) { renderVetAccept($('#app'), o); return; }
  renderLogin($('#app'), o);
}
function n7M_(items, cur) { return typeof n7MenuSoon_ === 'function' ? n7MenuSoon_(items, cur) : menuHTML(items, cur); }
function n7SoonGate_(el, p) {
  if (!el || typeof soonPage_ !== 'function' || !soonPage_(p)) return false;
  try { el.innerHTML = soonHTML_(); } catch (e) {}
  return true;
}

function _vetAfterLogin(done) {
  var code = typeof vetCode_ === 'function' ? vetCode_() : '';
  if (!code || !PL.user || PL.user.role !== '수의사') { if (done) done(); return; }
  api('acceptFarmVet', PL.token, code, {}).then(function (a) {
    try { history.replaceState(null, '', location.pathname + location.search); } catch (x) {}
    if (a && a.farmId) { PL.farmId = a.farmId; saveSess(); }
    toast('수의사로 연결되었습니다');
    if (done) done();
  }).catch(function (e) { toast(uiMsg(e)); if (done) done(); });
}

function renderVetAccept(el, o) {
  o = o || {}; var code = o.code || vetCode_();
  authBox(el, o, '수의사 초대 수락', '초대 링크를 확인하고 수락합니다.', '<div id="va-b"><div class="mut">불러오는 중…</div></div><div id="va-e"></div><div class="lglinks" style="margin-top:12px"><a href="#" id="va-login">로그인 화면으로</a></div>');
  $('#va-login', el).onclick = function (e) { e.preventDefault(); try { history.replaceState(null, '', location.pathname + location.search); } catch (x) {} renderLogin(el, o); };
  api('vetInviteInfo', '', code).then(function (r) {
    var b = $('#va-b', el); if (!r || !r.ok) { b.innerHTML = '<div class="flag">초대 링크가 없거나 만료되었습니다.</div>'; return; }
    if (r.needLogin) { b.innerHTML = '<div class="okbox">이미 피그로그 수의사 계정이 있습니다.</div><p>' + esc(r.farmName || '') + ' · 만료 ' + esc(r.expiresAt || '') + '</p><p class="mut">로그인한 뒤 자동으로 수락됩니다.</p><button class="btn block" id="va-go" style="margin-top:12px">로그인하고 수락</button>'; $('#va-go', el).onclick = function () { renderLogin(el, o); }; return; }
    b.innerHTML = '<div class="mut">농장</div><b>' + esc(r.farmName || '') + '</b><div class="mut" style="margin-top:8px">이름</div><input class="f" id="va-nm" value="' + esc(r.name || '') + '"><div class="mut" style="margin-top:8px">비밀번호 (8자 이상, 영문과 숫자)</div><input class="f" id="va-pw" type="password" autocomplete="new-password"><div class="mut" style="margin-top:8px">비밀번호 확인</div><input class="f" id="va-pw2" type="password" autocomplete="new-password"><button class="btn block" id="va-ok" style="margin-top:16px">수락하고 시작</button><div class="mut" style="margin-top:8px">만료 ' + esc(r.expiresAt || '') + '</div>';
    $('#va-ok', el).onclick = function () {
      var pw = $('#va-pw', el).value, ebox = $('#va-e', el); ebox.innerHTML = '';
      if (pw !== $('#va-pw2', el).value) { ebox.innerHTML = errHTML('비밀번호가 서로 다릅니다'); return; }
      this.disabled = true;
      api('acceptFarmVet', '', code, { pw: pw, name: $('#va-nm', el).value }).then(function (a) {
        api('login', a.id, pw, PL.view).then(function (r) { try { history.replaceState(null, '', location.pathname + location.search); } catch (x) {} afterLogin(r, o); }).catch(function (e) { ebox.innerHTML = errHTML(e); });
      }).catch(function (e) { $('#va-ok', el).disabled = false; ebox.innerHTML = errHTML(e); });
    };
  }).catch(function (e) { $('#va-b', el).innerHTML = errHTML(e); });
}


if (typeof farmSelectHTML === 'function' && !farmSelectHTML._vet) {
  var _fs0 = farmSelectHTML;
  farmSelectHTML = function () {
    var h = _fs0();
    return (PL.user && PL.user.role === '수의사') ? h + ' <span class="badge" style="margin-left:6px">수의사 · 보기만</span>' : h;
  };
  farmSelectHTML._vet = 1;
}
if (typeof openHelp === 'function' && !openHelp._soon) {
  var _oh0 = openHelp;
  openHelp = function () {
    if (typeof soonPage_ === 'function' && soonPage_('help')) {
      return modal('<h3>💬 도움 요청</h3><div class="card empty" style="text-align:center;padding:20px 12px"><b>곧 열려요</b><p>지금은 도움 요청을 보낼 수 없습니다. 급한 일은 농장주나 운영자에게 연락해 주세요.</p></div><div class="row" style="margin-top:10px"><button type="button" class="btn" data-close>닫기</button></div>');
    }
    return _oh0.apply(this, arguments);
  };
  openHelp._soon = 1;
}


/* t434u: 농장유형(GGP/GP/PS/비육/일관) — 화면만 갈라짐. 기존 농장유형 값(PS/GP/GGP)은 그대로, 상세는 농장유형_상세 */
function farmTypes() {
  var c = (PL.boot && PL.boot.cfg) || {}, t = String(c['농장유형_상세'] || c['농장유형'] || 'PS').trim().toUpperCase().replace(/\s+/g, '');
  t = t.replace(/일관/g, 'INT').replace(/비육/g, 'FIN');
  if (t === 'INT') return ['PS', 'FIN'];
  if (t === 'FIN') return ['FIN'];
  var o = [], s = {};
  String(t).split(/[+,/]/).forEach(function (x) {
    if (x === 'INT') { x = 'PS'; if (!s.FIN) { o.push('FIN'); s.FIN = 1; } }
    if ((x === 'PS' || x === 'GP' || x === 'GGP' || x === 'FIN') && !s[x]) { o.push(x); s[x] = 1; }
  });
  return o.length ? o : ['PS'];
}
function farmType() { var a = farmTypes(); return a.indexOf('GGP') >= 0 ? 'GGP' : a.indexOf('GP') >= 0 ? 'GP' : a.indexOf('PS') >= 0 ? 'PS' : 'FIN'; }
function isBreeder() { var a = farmTypes(); return a.indexOf('GP') >= 0 || a.indexOf('GGP') >= 0; }
function hasSowHerd() { var a = farmTypes(); return !(a.length === 1 && a[0] === 'FIN'); }
function hasFinishHerd() { var a = farmTypes(); return a.indexOf('FIN') >= 0 || a.indexOf('PS') >= 0; }
function menuTypeOk_(p, fl) {
  if (!p) return true;
  if (typeof hasSowHerd === 'function' && !hasSowHerd() && /^(sows|sow|sowcard|board|cards|boars|pigs|ped|due|vweek)$/.test(p)) return false;
  if (fl === 'B' && typeof isBreeder === 'function' && !isBreeder()) return false;
  if (typeof isBreeder === 'function' && !isBreeder() && /^(pigs|ped)$/.test(p)) return false;
  return true;
}
function ftLab_(k) {
  var ko = { PS: 'PS (번식)', GP: 'GP (원종돈)', GGP: 'GGP (원원종돈)', FIN: '비육', INT: '일관 (번식+비육)' };
  return typeof Tk_ === 'function' ? Tk_('ft.' + k, null, ko[k] || k) : (ko[k] || k);
}
function ftSelected_() {
  var a = farmTypes(), hasPs = a.indexOf('PS') >= 0, hasFin = a.indexOf('FIN') >= 0, hasGp = a.indexOf('GP') >= 0, hasGgp = a.indexOf('GGP') >= 0;
  if (hasPs && hasFin && !hasGp && !hasGgp && a.length === 2) return ['INT'];
  if (a.length === 1 && a[0] === 'FIN') return ['FIN'];
  return a.slice();
}
function ftTokSave_(sel) {
  var s = {};
  (sel || []).forEach(function (k) {
    if (k === 'INT') { s.PS = 1; s.FIN = 1; }
    else if (k === 'PS' || k === 'GP' || k === 'GGP' || k === 'FIN') s[k] = 1;
  });
  var a = ['GGP', 'GP', 'PS', 'FIN'].filter(function (k) { return s[k]; });
  if (!a.length) a = ['PS'];
  var detail = (s.PS && s.FIN && !s.GP && !s.GGP) ? 'INT' : (a.length === 1 && a[0] === 'FIN' ? 'FIN' : a.join(','));
  var primary = s.GGP ? 'GGP' : s.GP ? 'GP' : 'PS';
  return { primary: primary, detail: detail };
}
if (typeof FT_KEYS !== 'undefined' && FT_KEYS.indexOf('농장유형_상세') < 0) FT_KEYS.push('농장유형_상세');
function installFtCard_() {
if (typeof ftCard === 'function' && !ftCard._ft434) {
  ftCard = function (box, rows, can) {
    if (rows && rows.rows) { can = rows.can; rows = rows.rows; }
    if (!box) return;
    var cfg = {}; (rows || []).forEach(function (r) { cfg[r.key] = r.value; });
    if (PL.boot && PL.boot.cfg) {
      if (cfg['농장유형'] == null && PL.boot.cfg['농장유형']) cfg['농장유형'] = PL.boot.cfg['농장유형'];
      if (cfg['농장유형_상세'] == null && PL.boot.cfg['농장유형_상세']) cfg['농장유형_상세'] = PL.boot.cfg['농장유형_상세'];
    }
    var cur = (function () {
      var saved = PL.boot && PL.boot.cfg ? Object.assign({}, PL.boot.cfg, cfg) : cfg;
      var hold = PL.boot && PL.boot.cfg;
      if (PL.boot) PL.boot.cfg = saved;
      var s = ftSelected_();
      if (hold) PL.boot.cfg = hold; else if (PL.boot) PL.boot.cfg = saved;
      return s;
    })();
    var sep = ['-', '.', '/'].indexOf(String(cfg['이각_구분자'])) >= 0 ? String(cfg['이각_구분자']) : '-', mx = Number(cfg['이각_최대값']); if (!(mx >= 9 && mx <= 400)) mx = 188;
    var dis = can ? '' : ' disabled';
    var keys = ['PS', 'GP', 'GGP', 'FIN', 'INT'];
    var on = function (k) { return cur.indexOf(k) >= 0; };
    var note = Tk_('ft.note2', null, '한 농장이 여러 층을 겸하면 여러 개를 고를 수 있어요. 비육만 고르면 모돈·교배 화면이 숨고 돈군·입식·출하가 가운데로 옵니다. 일관은 지금 번식 화면과 같습니다.');
    box.innerHTML = '<h3>' + esc(T('ft.title')) + '</h3><div class="mut">' + esc(note) + '</div>' +
      '<div class="seg ftseg" id="ft-seg" style="margin-top:10px;flex-wrap:wrap">' + keys.map(function (k) {
        return '<button type="button" data-ft="' + k + '" aria-pressed="' + on(k) + '" class="' + (on(k) ? 'on' : '') + '"' + dis + '>' + esc(ftLab_(k)) + '</button>';
      }).join('') + '</div>' +
      '<div id="ft-n"' + (isBreeder() ? '' : ' hidden') + '><h4 style="margin:14px 0 4px">' + esc(T('ft.notch')) + '</h4><div class="mut">' + esc(T('ft.notchHow')) + '</div><div class="g3" style="margin-top:6px">' +
      '<div><label class="l" for="ft-max">' + esc(T('ft.max')) + '</label><input id="ft-max" type="number" inputmode="numeric" min="9" max="400" step="1" value="' + mx + '"' + dis + '></div>' +
      '<div><label class="l" for="ft-sep">' + esc(T('ft.sep')) + '</label><select id="ft-sep"' + dis + '>' + ['-', '.', '/'].map(function (k) { return '<option' + (k === sep ? ' selected' : '') + '>' + k + '</option>'; }).join('') + '</select></div></div>' +
      '<div class="mut" id="ft-ex" style="margin-top:6px"></div></div>' +
      (can ? '<div id="ft-e"></div><button class="btn" id="ft-go" style="margin-top:10px">' + esc(T('ft.save')) + '</button>' : '');
    var getSel = function () {
      return $$('[data-ft]', box).filter(function (b) { return b.classList.contains('on'); }).map(function (b) { return b.dataset.ft; });
    };
    var paint = function () {
      var sel = getSel(), tok = ftTokSave_(sel);
      var hold = PL.boot && PL.boot.cfg;
      if (PL.boot) { PL.boot.cfg = Object.assign({}, hold || {}, { '농장유형': tok.primary, '농장유형_상세': tok.detail }); }
      if ($('#ft-n', box)) $('#ft-n', box).hidden = !isBreeder();
      if (hold) PL.boot.cfg = hold;
    };
    var ex = function () { var s = $('#ft-sep', box), mEl = $('#ft-max', box); if (!s || !mEl) return; var m = Math.max(9, Math.min(400, Number(mEl.value) || 188)); $('#ft-ex', box).textContent = T('ft.ex', { a: '12' + s.value + Math.min(188, m), max: m }); };
    if ($('#ft-sep', box)) { ex(); $('#ft-sep', box).onchange = ex; $('#ft-max', box).oninput = ex; }
    $$('[data-ft]', box).forEach(function (b) {
      b.onclick = function () {
        var k = b.dataset.ft, was = b.classList.contains('on');
        if (k === 'INT') {
          $$('[data-ft]', box).forEach(function (x) { var onI = x.dataset.ft === 'INT' || x.dataset.ft === 'PS' || x.dataset.ft === 'FIN'; if (was && x.dataset.ft === 'INT') onI = false; x.classList.toggle('on', onI && !was ? (x.dataset.ft === 'INT' || x.dataset.ft === 'PS' || x.dataset.ft === 'FIN') : (!was && (x.dataset.ft === 'INT' || x.dataset.ft === 'PS' || x.dataset.ft === 'FIN'))); x.setAttribute('aria-pressed', x.classList.contains('on')); });
          /* simpler: 일관 exclusive preset */
          $$('[data-ft]', box).forEach(function (x) {
            var on2 = !was && (x.dataset.ft === 'INT');
            x.classList.toggle('on', on2);
            x.setAttribute('aria-pressed', on2);
          });
        } else if (k === 'FIN') {
          if (!was) {
            var only = true;
            $$('[data-ft]', box).forEach(function (x) { if (x !== b && x.classList.contains('on') && x.dataset.ft !== 'PS' && x.dataset.ft !== 'INT') only = false; });
            /* toggle FIN; if INT was on, turn INT off and keep PS if present */
            b.classList.add('on'); b.setAttribute('aria-pressed', 'true');
            var intB = box.querySelector('[data-ft="INT"]'); if (intB) { intB.classList.remove('on'); intB.setAttribute('aria-pressed', 'false'); }
          } else {
            b.classList.remove('on'); b.setAttribute('aria-pressed', 'false');
            var intB2 = box.querySelector('[data-ft="INT"]'); if (intB2) { intB2.classList.remove('on'); intB2.setAttribute('aria-pressed', 'false'); }
          }
        } else if (k === 'PS') {
          if (!was) { b.classList.add('on'); b.setAttribute('aria-pressed', 'true'); }
          else { b.classList.remove('on'); b.setAttribute('aria-pressed', 'false'); var intB3 = box.querySelector('[data-ft="INT"]'); if (intB3) { intB3.classList.remove('on'); intB3.setAttribute('aria-pressed', 'false'); } }
          /* if PS+FIN only, light INT */
          var psOn = box.querySelector('[data-ft="PS"]') && box.querySelector('[data-ft="PS"]').classList.contains('on');
          var finOn = box.querySelector('[data-ft="FIN"]') && box.querySelector('[data-ft="FIN"]').classList.contains('on');
          var oth = $$('[data-ft]', box).some(function (x) { return (x.dataset.ft === 'GP' || x.dataset.ft === 'GGP') && x.classList.contains('on'); });
          var intB4 = box.querySelector('[data-ft="INT"]');
          if (intB4) { intB4.classList.toggle('on', !!(psOn && finOn && !oth)); intB4.setAttribute('aria-pressed', intB4.classList.contains('on')); }
        } else {
          b.classList.toggle('on', !was); b.setAttribute('aria-pressed', !was);
          var intB5 = box.querySelector('[data-ft="INT"]'); if (intB5) { intB5.classList.remove('on'); intB5.setAttribute('aria-pressed', 'false'); }
        }
        if (!getSel().length) { b.classList.add('on'); b.setAttribute('aria-pressed', 'true'); }
        paint();
      };
    });
    paint();
    var go = $('#ft-go', box); if (go) go.onclick = function () {
      var tok = ftTokSave_(getSel());
      var ch = { '농장유형': tok.primary, '농장유형_상세': tok.detail };
      if ($('#ft-sep', box)) { ch['이각_구분자'] = $('#ft-sep', box).value; ch['이각_최대값'] = String($('#ft-max', box).value).trim(); }
      go.disabled = true;
      apiF('updateSettings', ch).then(function () {
        go.disabled = false;
        if (PL.boot && PL.boot.cfg) Object.keys(ch).forEach(function (k) { PL.boot.cfg[k] = ch[k]; });
        toast(T('ft.saved'));
        if (typeof PL.reshell === 'function') PL.reshell();
      }).catch(function (e) { go.disabled = false; $('#ft-e', box).innerHTML = errHTML(e); });
    };
  };
  ftCard._ft434 = 1;
}
}
installFtCard_();


/* 입력 종류: 비육만이면 모돈 기록을 숨김 */
if (typeof entryTypes_ === 'function' && !entryTypes_._ft434) {
  var _et0 = entryTypes_;
  entryTypes_ = function () {
    var ks = _et0.apply(this, arguments) || [];
    if (typeof hasSowHerd === 'function' && !hasSowHerd()) {
      ks = ks.filter(function (t) { return /^(백신|치료|이동)$/.test(t); });
      if (!ks.length) ks = ['치료'];
    }
    return ks;
  };
  entryTypes_._ft434 = 1;
}

/* t524u: 기록 종류 단추를 돈군 생산 흐름 순서로 */
(function () {
  var FLOW = ['전입','초발정','등지방','교배','임신감정','분만','이유','부분이유','양자','도폐사','백신','치료','자돈폐사','이동'];
  function sortTypes(ks) {
    var rank = {};
    FLOW.forEach(function (k, i) { rank[k] = i; });
    return (ks || []).slice().sort(function (a, b) {
      var ia = Object.prototype.hasOwnProperty.call(rank, a) ? rank[a] : (a === '웅돈' ? 901 : 900);
      var ib = Object.prototype.hasOwnProperty.call(rank, b) ? rank[b] : (b === '웅돈' ? 901 : 900);
      return ia - ib;
    });
  }
  if (typeof entryTypes_ === 'function' && !entryTypes_._t524ord) {
    var _etf = entryTypes_;
    entryTypes_ = function () { return sortTypes(_etf.apply(this, arguments) || []); };
    entryTypes_._t524ord = 1;
  }
  if (typeof MAIN_TYPES !== 'undefined') {
    var mainSet = {};
    MAIN_TYPES.forEach(function (k) { mainSet[k] = 1; });
    var more = (typeof MORE_TYPES !== 'undefined' ? MORE_TYPES.slice() : []);
    FLOW.forEach(function (k) { if (!mainSet[k] && more.indexOf(k) < 0) more.push(k); });
    MAIN_TYPES = sortTypes(MAIN_TYPES);
    if (typeof MORE_TYPES !== 'undefined') MORE_TYPES = sortTypes(more);
  }
})();


function n7FcrCurrent_(done) {
  var ym = '';
  try { ym = (typeof window.today === 'function' ? window.today() : ((window.PL && PL._daily && PL._daily.today) || '')).slice(0, 7); } catch (e0) {}
  if (!ym || !/^\d{4}-\d{2}$/.test(ym)) ym = new Date().toISOString().slice(0, 7);
  var from = ym + '-01', to = ym + '-28';
  try { if (typeof n7MonthEnd_ === 'function') to = n7MonthEnd_(ym, from); } catch (e1) {}
  if (typeof apiF !== 'function') { done({ ym: ym, fcr: null }); return; }
  Promise.all([
    apiF('getShipGrades', { from: from, to: to }).catch(function () { return null; }),
    apiF('getInvMonthly', 12).catch(function () { return null; })
  ]).then(function (a) {
    var ship = a[0], inv = a[1], feed = null, gain = null, wHead = 0;
    if (inv && inv.months) inv.months.forEach(function (x) { if (x.month === ym) feed = (x.feedOutKg == null ? null : n7Num_(x.feedOutKg)); });
    if (ship && ship.months) ship.months.forEach(function (x) {
      if (x.month === ym) { gain = x.kg == null ? null : n7Num_(x.kg); wHead = n7Num_(x.wHead); }
    });
    var fcr = (feed != null && gain > 0 && wHead > 0) ? (feed / gain) : null;
    done({ ym: ym, fcr: fcr });
  }).catch(function () { done({ ym: ym, fcr: null }); });
}
function n7FcrTxt_(r) {
  if (!r || r.fcr == null || !isFinite(r.fcr)) return '자료 부족';
  return (typeof n1 === 'function') ? n1(r.fcr, 2) : (Math.round(r.fcr * 100) / 100).toFixed(2);
}

function pageHomeFin_(el) {
  loading(el);
  var farm = (PL.boot && PL.boot.farm && (PL.boot.farm.name || PL.boot.farm.농장명)) || (PL.farm && PL.farm.name) || '';
  apiF('getGroupBook', '').then(function (b) {
    if (!el.isConnected || (PL._page && PL._page !== 'home' && PL._page !== 'dash')) return;
    b = b || {};
    var stages = b.stages || [], groups = b.groups || [];
    var tot = { open: 0, inn: 0, dead: 0, cull: 0, ship: 0, close: 0 };
    stages.forEach(function (s) { tot.open += +s.open || 0; tot.inn += +s.in || 0; tot.dead += +s.dead || 0; tot.cull += +s.cull || 0; tot.ship += +s.ship || 0; tot.close += +s.close || 0; });
    var den = tot.open + tot.inn; var mort = den > 0 ? Math.round((tot.dead / den) * 1000) / 10 : null;
    var chip = function (p, n, lab) { return '<div class="chip' + (n ? ' on' : '') + '" data-p="' + p + '"><b>' + (n == null ? '—' : n) + '</b><span>' + lab + '</span></div>'; };
    el.innerHTML = '<div class="card"><div class="row"><h3 style="flex:1;margin:0">' + esc(Tk_('ft.finHome', null, '비육 현황')) + ' · ' + esc(b.date || '') + '</h3><span class="mut">' + esc(farm) + '</span></div>' +
      '<div class="chips">' + chip('groups', tot.close, Tk_('ft.finNow', null, '현재 두수')) + chip('groups', tot.inn, Tk_('ft.finIn', null, '입식')) + chip('groups', tot.dead, Tk_('ft.finDead', null, '폐사')) + chip('ship', tot.ship, Tk_('ft.finShip', null, '출하')) + chip('groups', mort, Tk_('ft.finMort', null, '폐사율 %')) + '<div class="chip" id="n7-fin-fcr" data-p="fstock"><b>…</b><span>' + esc(Tk_('ft.finFcrM', null, '이번 달 FCR')) + '</span></div></div>' +
      '<div class="row" style="margin-top:12px;gap:8px;flex-wrap:wrap"><button type="button" class="btn" data-p="groups">' + esc(Tk_('ft.finGrp', null, '돈군·입식')) + '</button><button type="button" class="btn sec" data-p="ship">' + esc(Tk_('ft.finSh', null, '출하')) + '</button><button type="button" class="btn sec" data-p="fstock">' + esc(Tk_('ft.finFcr', null, '사료·FCR')) + '</button></div></div>' +
      (stages.length ? '<div class="card"><h4>' + esc(Tk_('ft.finStages', null, '단계별 두수')) + '</h4><div class="tw"><table class="t num"><tr><th>단계</th><th>현재</th><th>입식</th><th>폐사</th><th>출하</th><th>폐사율 %</th></tr>' +
        stages.map(function (s) { return '<tr><td>' + esc(s.stage) + '</td><td><b>' + (s.close || 0) + '</b></td><td>' + (s.in || 0) + '</td><td>' + (s.dead || 0) + '</td><td>' + (s.ship || 0) + '</td><td>' + (s.mort == null ? '—' : s.mort) + '</td></tr>'; }).join('') + '</table></div></div>' : '<div class="card empty"><p class="mut">' + esc(Tk_('ft.finEmpty', null, '아직 돈군 기록이 없습니다. 돈군·입식에서 시작해 주세요.')) + '</p></div>');
    el.querySelectorAll('[data-p]').forEach(function (x) { x.style.cursor = 'pointer'; x.onclick = function () { if (typeof PL.go === 'function') PL.go(x.getAttribute('data-p')); }; });
    if (typeof n7FcrCurrent_ === 'function') n7FcrCurrent_(function (r) {
      var c = el.querySelector('#n7-fin-fcr b');
      if (c) c.textContent = n7FcrTxt_(r);
    });
  }).catch(function (e) { el.innerHTML = '<div class="card">' + (typeof errHTML === 'function' ? errHTML(e) : esc(String(e))) + '</div>'; });
}
function n7HookKpiFin_() {
  if (typeof pageKpi === 'function' && !pageKpi._ft450) {
    var _pkpi = pageKpi;
    pageKpi = function (el) {
      if (typeof hasSowHerd === 'function' && !hasSowHerd()) return n7PageKpiFin_(el);
      return _pkpi.apply(this, arguments);
    };
    pageKpi._ft450 = 1;
  }
}
n7HookKpiFin_();
function n7PageKpiFin_(el) {
  if (!el) return;
  el.innerHTML = '<div class="card n7-fin-kpi"><h3>' + esc(Tk_('ft.finKpi', null, '비육 성적')) + '</h3>'
    + '<div class="chips"><div class="chip on" id="n7-fk-fcr" data-p="fstock"><b id="n7-fk-fcr-v">…</b><span>' + esc(Tk_('ft.finFcrM', null, '이번 달 FCR')) + '</span></div></div>'
    + '<p class="mut">' + esc(Tk_('ft.finKpiNote', null, '모돈 PSY·분만율 같은 번식 지표는 비육 전용 농장에서는 보여 주지 않습니다.')) + '</p>'
    + '<button type="button" class="btn sec" data-p="fstock">' + esc(Tk_('ft.finFcr', null, '사료·FCR')) + '</button></div><div id="n7-fk-home"></div>';
  el.querySelectorAll('[data-p]').forEach(function (x) { x.onclick = function () { if (typeof PL.go === 'function') PL.go(x.getAttribute('data-p')); }; });
  if (typeof n7FcrCurrent_ === 'function') n7FcrCurrent_(function (r) {
    var v = el.querySelector('#n7-fk-fcr-v');
    if (v) v.textContent = n7FcrTxt_(r);
  });
  var home = el.querySelector('#n7-fk-home');
  if (home && typeof pageHomeFin_ === 'function') pageHomeFin_(home);
}
if (typeof pageHomeK === 'function' && !pageHomeK._ft434) {
  var _phk = pageHomeK;
  pageHomeK = function (el) {
    if (typeof hasSowHerd === 'function' && !hasSowHerd()) return pageHomeFin_(el);
    return _phk.apply(this, arguments);
  };
  pageHomeK._ft434 = 1;
}

function n7LzPage_(fn) {
  return function (el, arg) {
    if (fn === 'pageShip' && typeof n7HookShip_ === 'function') n7HookShip_();
    if (fn === 'pageReport' && typeof n7HookReport_ === 'function') n7HookReport_();
    if (typeof window[fn] === 'function') return window[fn](el, arg);
    if (typeof lzPage_ === 'function') {
      var r = lzPage_(fn)(el, arg);
      setTimeout(function () {
        if (fn === 'pageShip') { if (typeof n7HookShip_ === 'function') n7HookShip_(); if (typeof n7ShipEnsure_ === 'function') n7ShipEnsure_(el); }
        if (fn === 'pageReport') { if (typeof n7HookReport_ === 'function') n7HookReport_(); if (typeof n7PolishReport_ === 'function') n7PolishReport_(el); }
      }, 80);
      return r;
    }
  };
}
function n7HookFarmTypePages_() {
  if (typeof installFtCard_ === 'function') installFtCard_();
  if (window.PAGES_M) {
    if (!PAGES_M.groups) PAGES_M.groups = n7LzPage_('pageGroups');
    if (!PAGES_M.ship) PAGES_M.ship = n7LzPage_('pageShip');
    if (!PAGES_M.rep) PAGES_M.rep = n7LzPage_('pageReport');
    if (!PAGES_M.mgmt) PAGES_M.mgmt = n7LzPage_('pageMgmt');
  }
  if (window.PAGES_W) {
    if (!PAGES_W.ship || !PAGES_W.ship._n7sh) { PAGES_W.ship = n7LzPage_('pageShip'); PAGES_W.ship._n7sh = 1; }
    if (!PAGES_W.rep || !PAGES_W.rep._n7sh) { PAGES_W.rep = n7LzPage_('pageReport'); PAGES_W.rep._n7sh = 1; }
    if (!PAGES_W.groups || !PAGES_W.groups._n7sh) { /* leave existing groups */ }
  }
  if (typeof more === 'function' && !more._n7sh) {
    var _moreSh = more;
    more = function (el) {
      var r = _moreSh.apply(this, arguments);
      try {
        var box = (el && el.querySelector && el.querySelector('.card.more')) || (el && el.querySelector('.more'));
        if (box) {
          var add = function (p, lab) {
            if (box.querySelector('[data-p="' + p + '"]')) return;
            if (typeof pageOk === 'function' && !pageOk(p)) return;
            var a = document.createElement('a');
            a.href = '#'; a.setAttribute('data-p', p);
            a.innerHTML = lab + '<span class="mut">›</span>';
            var ev = box.querySelector('[data-p="events"]');
            if (ev && ev.nextSibling) box.insertBefore(a, ev.nextSibling);
            else box.appendChild(a);
          };
          add('ship', '출하');
          add('rep', '보고서');
        }
      } catch (e) { }
      return r;
    };
    more._n7sh = 1;
  }
  function wrapGo(obj, name) {
    if (typeof obj[name] !== 'function' || obj[name]._ft434) return;
    var g = obj[name];
    obj[name] = function (p, arg) {
      if (p && typeof menuTypeOk_ === 'function' && !menuTypeOk_(p) && p !== 'home' && p !== 'settings' && p !== 'more' && p !== 'entry' && p !== 'groups' && p !== 'ship' && p !== 'fstock') p = (typeof hasSowHerd === 'function' && !hasSowHerd()) ? 'home' : p;
      return g.call(this, p, arg);
    };
    obj[name]._ft434 = 1;
  }
  if (typeof PL !== 'undefined') wrapGo(PL, 'go');
  if (typeof wShell === 'function' && !wShell._ft434) {
    var _w = wShell;
    wShell = function () {
      var r = _w.apply(this, arguments);
      wrapGo(PL, 'go');
      if (PL && PL._page && typeof menuTypeOk_ === 'function' && !menuTypeOk_(PL._page) && PL._page !== 'settings' && PL._page !== 'entry' && PL._page !== 'home' && PL._page !== 'fstock' && PL._page !== 'groups' && PL._page !== 'ship') {
        PL._page = 'home'; _w();
      }
      return r;
    };
    wShell._ft434 = 1;
  }
  if (typeof mShell === 'function' && !mShell._ft434) {
    var _m = mShell;
    mShell = function () {
      var r = _m.apply(this, arguments);
      wrapGo(PL, 'go');
      n7FinTabs_();
      return r;
    };
    mShell._ft434 = 1;
  }
  if (typeof more === 'function' && !more._ft434) {
    var _moreFt = more;
    more = function (el) {
      _moreFt.apply(this, arguments);
      if (typeof hasSowHerd === 'function' && !hasSowHerd() && el) {
        el.querySelectorAll('a[data-p]').forEach(function (a) {
          if (!menuTypeOk_(a.getAttribute('data-p'))) a.remove();
        });
        var box = el.querySelector('.card.more') || el;
        if (box && !box.querySelector('a[data-p="groups"]')) {
          var add = function (p, lab) { var a = document.createElement('a'); a.href = '#'; a.setAttribute('data-p', p); a.innerHTML = lab + '<span class="mut">›</span>'; a.onclick = function (e) { e.preventDefault(); if (typeof PL.go === 'function') PL.go(p); }; box.insertBefore(a, box.firstChild); };
          add('fstock', Tk_('ft.finFcr', null, '사료·FCR'));
          add('ship', Tk_('ft.finSh', null, '출하'));
          add('groups', Tk_('ft.finGrp', null, '돈군·입식'));
        }
      }
    };
    more._ft434 = 1;
  }
  if (typeof pageEntryW_ === 'function' && !pageEntryW_._ft434) {
    var _pew = pageEntryW_;
    pageEntryW_ = function (el, opt) {
      opt = opt || {};
      var ks = typeof entryTypes_ === 'function' ? entryTypes_() : [];
      if (opt.type && ks.indexOf(opt.type) < 0) opt.type = ks[0] || '치료';
      if (!opt.type && PL._lastType && ks.indexOf(PL._lastType) < 0) { PL._lastType = ks[0] || '치료'; }
      if (!opt.type && !PL._lastType) opt.type = ks[0] || '치료';
      return _pew.call(this, el, opt);
    };
    pageEntryW_._ft434 = 1;
  }
  if (typeof pageEntry === 'function' && !pageEntry._ft434) {
    var _pe = pageEntry;
    pageEntry = function (el, opt) {
      opt = opt || {};
      var ks = typeof entryTypes_ === 'function' ? entryTypes_() : [];
      if (opt.type && ks.indexOf(opt.type) < 0) opt.type = ks[0] || '치료';
      if (!opt.type && PL._lastType && ks.indexOf(PL._lastType) < 0) PL._lastType = ks[0] || '치료';
      return _pe.call(this, el, opt);
    };
    pageEntry._ft434 = 1;
  }
  if (typeof renderSignup === 'function' && !renderSignup._ft434) {
    var _rs = renderSignup;
    renderSignup = function (el, o, v, step) {
      var r = _rs.apply(this, arguments);
      var s = el && $('#su-farmType', el);
      if (s) {
        var cur = s.value || (v && v.farmType) || 'PS';
        s.innerHTML = ['PS', 'GP', 'GGP', 'FIN', 'INT'].map(function (k) { return '<option value="' + k + '"' + (cur === k ? ' selected' : '') + '>' + esc(ftLab_(k)) + '</option>'; }).join('');
        if (['PS', 'GP', 'GGP', 'FIN', 'INT'].indexOf(cur) >= 0) s.value = cur;
      }
      return r;
    };
    renderSignup._ft434 = 1;
  }
  if (typeof fHome === 'function' && !fHome._ft434) {
    var _fh = fHome;
    fHome = function () {
      var r = _fh.apply(this, arguments);
      if (typeof hasSowHerd === 'function' && !hasSowHerd()) {
        document.querySelectorAll('.types [data-t], .tabs [data-t]').forEach(function (b) {
          if (!/^(백신|치료|이동)$/.test(b.getAttribute('data-t') || '')) b.remove();
        });
        var wr = document.getElementById('f-wr'), fc = document.getElementById('f-card');
        if (wr) wr.remove(); if (fc) fc.remove();
        var types = document.querySelector('.types');
        if (types && !document.getElementById('ft-fin-note')) {
          var p = document.createElement('div'); p.id = 'ft-fin-note'; p.className = 'mut'; p.style.margin = '8px 0'; p.textContent = Tk_('ft.finField', null, '비육 농장은 돈군·입식·출하를 사무실(웹) 화면에서 입력합니다. 현장에서는 백신·치료·이동만 남깁니다.');
          types.parentNode.insertBefore(p, types);
        }
      }
      return r;
    };
    fHome._ft434 = 1;
  }
}
function n7FinTabs_() {
  var nav = document.querySelector('nav.tabbar'); if (!nav) return;
  if (typeof hasSowHerd !== 'function' || hasSowHerd()) {
    if (nav.getAttribute('data-ft') === 'fin') { /* leave mShell to rebuild on type change via reshell */ }
    return;
  }
  if (nav.getAttribute('data-ft') === 'fin') return;
  nav.setAttribute('data-ft', 'fin');
  var tabs = [['home', '홈', '⌂'], ['groups', '돈군', '◫'], ['entry', '입력', '＋'], ['ship', '출하', '⚖'], ['more', '더보기', '⋯']];
  nav.innerHTML = tabs.map(function (t) { return '<button data-p="' + t[0] + '"' + (t[0] === 'entry' ? ' class="mid"' : '') + '><i aria-hidden="true">' + t[2] + '</i><span class="tl">' + t[1] + '</span>' + (t[0] === 'more' ? '<span class="hbadge" hidden></span>' : '') + '</button>'; }).join('');
  nav.querySelectorAll('button').forEach(function (b) { b.onclick = function () { if (typeof PL.go === 'function') PL.go(b.dataset.p); }; });
  if (typeof fitTabs_ === 'function') fitTabs_();
}
if (typeof nov7Chrome_ === 'function' && !nov7Chrome_._ft434) {
  var _nc = nov7Chrome_;
  nov7Chrome_ = function () { _nc.apply(this, arguments); n7HookFarmTypePages_(); n7FinTabs_(); };
  nov7Chrome_._ft434 = 1;
}
n7HookFarmTypePages_();
setTimeout(n7HookFarmTypePages_, 0);
setTimeout(n7HookFarmTypePages_, 80);


function n7NatTag_(a, b) {
  var pa = String(a == null ? '' : a).split(/(\d+)/), pb = String(b == null ? '' : b).split(/(\d+)/), i, na, nb, c;
  for (i = 0; i < pa.length || i < pb.length; i++) {
    na = pa[i] || ''; nb = pb[i] || '';
    if (na === nb) continue;
    if (/^\d+$/.test(na) && /^\d+$/.test(nb)) { c = Number(na) - Number(nb); if (c) return c; continue; }
    return na < nb ? -1 : 1;
  }
  return 0;
}
function n7SowSortGet_() {
  var d = { k: 'tag', d: 'asc' };
  try {
    var o = JSON.parse(localStorage.getItem('pl_sowSort:' + ((PL && PL.farmId) || '')) || '');
    if (o && (o.k === 'tag' || o.k === 'parity' || o.k === 'due') && (o.d === 'asc' || o.d === 'desc')) return o;
  } catch (e) {}
  return d;
}
function n7SowSortSet_(s) { try { localStorage.setItem('pl_sowSort:' + ((PL && PL.farmId) || ''), JSON.stringify(s)); } catch (e) {} }
function n7SowCmp_(a, b, s) {
  var c = 0;
  if (s.k === 'parity') c = (Number(a.parity) || 0) - (Number(b.parity) || 0);
  else if (s.k === 'due') {
    var da = a.nextDate || '', db = b.nextDate || '';
    if (!da && !db) c = 0; else if (!da) c = 1; else if (!db) c = -1; else c = da < db ? -1 : da > db ? 1 : 0;
  } else c = n7NatTag_(a.tag, b.tag);
  if (!c && s.k !== 'tag') c = n7NatTag_(a.tag, b.tag);
  return s.d === 'desc' ? -c : c;
}
function n7SowTh_(key, lab, s) {
  var on = s.k === key, arrow = on ? (s.d === 'desc' ? ' ↓' : ' ↑') : '';
  return '<th class="click" data-sk="' + key + '" aria-sort="' + (on ? (s.d === 'asc' ? 'ascending' : 'descending') : 'none') + '" style="cursor:pointer">' + lab + arrow + '</th>';
}
if (typeof pageSows === 'function' && !pageSows._sort) {
  pageSows = function (el, go) {
    var f = PL._sowF || { q: '', state: '' }, sort = f.sort || n7SowSortGet_();
    f.sort = sort;
    el.innerHTML = '<div class="row" style="margin-bottom:10px"><input class="f" id="sw-q" placeholder="모돈번호·애칭 검색" value="' + esc(f.q) + '"><label class="row mut" style="flex:0 0 auto;white-space:nowrap"><input type="checkbox" id="sw-fl" style="width:auto"' + (f.flagged ? ' checked' : '') + '> 확인 필요만</label></div>' +
      '<div class="tabs" id="sw-st">' + STATES.map(function (s) { return '<button data-s="' + s[0] + '" class="' + (f.state === s[0] ? 'on' : '') + '">' + esc(phOne(s[1])) + ' <span class="cnt" data-c="' + s[0] + '"></span></button>'; }).join('') + '</div>' +
      '<div class="row" id="sw-sk" style="gap:6px;flex-wrap:wrap;margin:8px 0">' +
        [['tag', '모돈번호'], ['parity', '산차'], ['due', '다음 예정']].map(function (x) {
          return '<button type="button" class="btn sec' + (sort.k === x[0] ? ' on' : '') + '" data-sk="' + x[0] + '">' + x[1] + (sort.k === x[0] ? (sort.d === 'desc' ? ' ↓' : ' ↑') : '') + '</button>';
        }).join('') + '</div><div id="sw-b"></div>';
    var load = function () {
      PL._sowF = f; var b = $('#sw-b', el); loading(b);
      apiR('listSows', { q: f.q, state: f.state, includeExited: f.state === '퇴출', flagged: f.flagged }).then(function (r) {
        $$('.cnt', el).forEach(function (c) { var k = c.dataset.c; c.textContent = k ? (r.counts[k] || 0) : ''; });
        var rows = (r.rows || []).slice().sort(function (a, c) { return n7SowCmp_(a, c, sort); });
        if (!rows.length) { b.innerHTML = '<div class="card mut">' + esc(T('sow.none')) + '</div>'; return; }
        b.innerHTML = PL.wide ?
          '<div class="mut" style="margin-bottom:6px">' + r.total + '두</div>' + parLegendHTML() + dueLeg_(rows) + '<div class="tw" style="max-height:70vh"><table class="t"><tr><th>순번</th>' + n7SowTh_('tag', '모돈번호', sort) + n7SowTh_('parity', '산차', sort) + '<th>상태</th><th>품종</th><th>전입일</th><th>최근 작업</th>' + n7SowTh_('due', '다음 예정', sort) + '<th>확인</th></tr>' + rows.map(function (s, i) {
            return '<tr class="click" data-id="' + esc(s.id) + '"><td class="n">' + (i + 1) + '</td><td><b>' + sowLblH_(s) + '</b>' + '</td><td class="n">' + parityBadge(s.parity, { size: 'sm', state: s.state }) + '</td><td>' + esc(stLbl(s)) + '</td><td>' + esc(s.breed) + '</td><td>' + s.entryDate + '</td><td>' + esc(s.lastType) + ' ' + fmtD(s.lastDate) + '</td><td>' + (s.next ? esc(s.next) + ' ' + fmtD(s.nextDate) + dueMark_(s) : '') + '</td><td>' + (s.flagged || s.ghost ? '<span class="badge b-yel">확인 필요</span>' : '') + '</td></tr>';
          }).join('') + '</table></div>' :
          '<div class="mut">' + r.total + '두</div>' + parLegendHTML() + dueLeg_(rows) + '<div class="card list" style="padding:4px 12px">' + rows.map(function (s, i) {
            return '<div class="it click" data-id="' + esc(s.id) + '"><span class="n" data-seq>' + (i + 1) + '</span><span class="no">' + sowLblH_(s) + '</span>' + parityBadge(s.parity, { state: s.state }) + '<div class="m">' + esc(stLbl(s)) + (s.flagged || s.ghost ? ' <span class="badge b-yel">확인</span>' : '') + '<div class="mut">' + (s.next ? esc(s.next) + ' ' + fmtD(s.nextDate) + dueMark_(s) : '최근 ' + esc(s.lastType) + ' ' + fmtD(s.lastDate)) + '</div></div><span class="mut">›</span></div>';
          }).join('') + '</div>';
        $$('[data-id]', b).forEach(function (x) { x.onclick = function () { go('sow', x.dataset.id); }; });
        $$('[data-sk]', b).forEach(function (th) { th.onclick = function (ev) { ev.stopPropagation(); applySort(th.getAttribute('data-sk')); }; });
      }).catch(function (e) { b.innerHTML = errHTML(e); });
    };
    function applySort(key) {
      if (sort.k === key) sort.d = sort.d === 'asc' ? 'desc' : 'asc';
      else { sort.k = key; sort.d = 'asc'; }
      f.sort = sort; n7SowSortSet_(sort);
      $$('#sw-sk button', el).forEach(function (bt) {
        var on = bt.getAttribute('data-sk') === sort.k;
        bt.classList.toggle('on', on);
        bt.textContent = ({ tag: '모돈번호', parity: '산차', due: '다음 예정' }[bt.getAttribute('data-sk')] || '') + (on ? (sort.d === 'desc' ? ' ↓' : ' ↑') : '');
      });
      load();
    }
    var tm; $('#sw-q', el).oninput = function () { clearTimeout(tm); tm = setTimeout(function () { f.q = $('#sw-q', el).value.trim(); load(); }, 300); };
    $('#sw-fl', el).onchange = function () { f.flagged = this.checked; load(); };
    $$('#sw-st button', el).forEach(function (bt) { bt.onclick = function () { $$('#sw-st button', el).forEach(function (x) { x.classList.remove('on'); }); bt.classList.add('on'); f.state = bt.dataset.s; load(); }; });
    $$('#sw-sk button', el).forEach(function (bt) { bt.onclick = function () { applySort(bt.getAttribute('data-sk')); }; });
    load();
  };
  pageSows._sort = 1;
}


function n7TagFocusInstall_() {
  if (typeof renderEntryForm !== 'function' || renderEntryForm._tagF) return;
  var _ref0 = renderEntryForm;
  renderEntryForm = function (el, opt) {
    opt = opt || {};
    var prev = opt.onSaved;
    opt.onSaved = function (r, html) {
      var ret;
      if (prev) ret = prev.apply(this, arguments);
      setTimeout(function () { var t = (el && $('#ef-tag', el)) || document.getElementById('ef-tag'); if (t && t.focus && document.body.contains(t)) t.focus(); }, 50);
      return ret;
    };
    var ret0 = _ref0.call(this, el, opt);
    if (typeof n7PolishEntryT447_ === 'function') try { n7PolishEntryT447_(el, opt); } catch (eP) {}
    return ret0;
  };
  renderEntryForm._tagF = 1;
}
n7TagFocusInstall_();
setTimeout(n7TagFocusInstall_, 0);
setTimeout(n7TagFocusInstall_, 50);



/* —— t447 afternoon batch (settings, entry, back, wean/death, AI sheet, BRN) —— */
function n7Esc2_(s) { return String(s == null ? '' : s).replace(/[&<>"']/g, function (c) { return { '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;' }[c]; }); }

function n7AiEsc_(e) { if (e && e.key === 'Escape') n7AiClose_(false); }
function n7AiClose_(fromPop) {
  var root = document.getElementById('pai-root');
  if (!root) return;
  root.remove();
  document.documentElement.classList.remove('pai-lock');
  document.removeEventListener('keydown', n7AiEsc_);
  if (typeof n7AiClose_._unlock === 'function') { n7AiClose_._unlock(); n7AiClose_._unlock = null; }
  if (n7AiClose_._vv && window.visualViewport) {
    try { visualViewport.removeEventListener('resize', n7AiClose_._vv); visualViewport.removeEventListener('scroll', n7AiClose_._vv); } catch (e) {}
    n7AiClose_._vv = null;
  }
  if (n7AiClose_._hist && !fromPop) {
    n7AiClose_._hist = 0;
    try { if (history.state && history.state.ai) history.back(); } catch (e2) {}
  }
  n7AiClose_._hist = 0;
}
function n7AiPinKb_(root) {
  var sheet = root && root.querySelector('.pai-sheet');
  if (!sheet || !window.visualViewport) return;
  var fn = function () {
    var vv = visualViewport;
    var kb = Math.max(0, window.innerHeight - vv.height - vv.offsetTop);
    var web = (document.documentElement.getAttribute('data-n7v') === 'web') || (root && root.classList && root.classList.contains('pai-pc'));
    if (web) { sheet.style.paddingBottom = ''; sheet.style.maxHeight = ''; return; }
    sheet.style.paddingBottom = (kb ? kb + 'px' : '');
    sheet.style.maxHeight = (root && root.classList && root.classList.contains('pai-wide')) ? '96vh' : '80vh';
  };
  n7AiClose_._vv = fn;
  visualViewport.addEventListener('resize', fn);
  visualViewport.addEventListener('scroll', fn);
  fn();
}
function n7AiTheme_() {
  var th = '';
  try { th = document.documentElement.getAttribute('data-theme') || ''; } catch (e) {}
  if (th === 'dark' || th === 'light' || th === 'barn') return th;
  try { if (typeof n7ThemeResolved_ === 'function') return n7ThemeResolved_() || 'light'; } catch (e2) {}
  try { if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) return 'dark'; } catch (e3) {}
  return 'light';
}
function n7AiSyncTheme_(root) {
  if (!root) return;
  var th = n7AiTheme_();
  if (th) root.setAttribute('data-theme', th);
  else root.removeAttribute('data-theme');
  var dark = (th === 'dark' || th === 'barn');
  var bg = dark ? '#121C19' : '#ffffff';
  var fg = dark ? '#E8EFEB' : '#1b2822';
  var chipBg = dark ? '#18241F' : '';
  var chipBd = dark ? '#23322C' : '';
  var inpBg = dark ? '#0A1210' : '';
  function paint(el, b, c) {
    if (!el) return;
    el.style.backgroundColor = b;
    if (c) el.style.color = c;
  }
  paint(root.querySelector('.pai-sheet'), bg, fg);
  paint(root.querySelector('.pai-hd'), bg, fg);
  paint(root.querySelector('#pai-host'), bg, fg);
  paint(root.querySelector('.pai'), bg, fg);
  paint(root.querySelector('.pai-log'), bg, fg);
  paint(root.querySelector('.pai-bar'), bg, fg);
  paint(root.querySelector('.pai-foot'), bg, dark ? '#B5C3BC' : '#57606a');
  var inp = root.querySelector('.pai-bar input');
  if (inp) { inp.style.backgroundColor = inpBg || ''; inp.style.color = fg; if (dark) inp.style.borderColor = '#2a3a34'; else inp.style.borderColor = ''; }
  root.querySelectorAll('.pai-chip').forEach(function (el) {
    if (dark) { el.style.backgroundColor = chipBg; el.style.color = fg; el.style.borderColor = chipBd; }
    else { el.style.backgroundColor = ''; el.style.color = ''; el.style.borderColor = ''; }
  });
}
function n7AiOpen_(seed) {
  if (document.getElementById('pai-root')) return;
  if (typeof nov7CanAi_ === 'function' && !nov7CanAi_(PL.user, PL.view)) return;
  var y = window.scrollY || 0;
  var root = document.createElement('div');
  root.id = 'pai-root';
  var pc = (document.documentElement.getAttribute('data-n7v') === 'web') || (window.innerWidth >= 901);
  if (pc) root.classList.add('pai-pc');
  var th = (typeof n7AiTheme_ === 'function' ? n7AiTheme_() : (document.documentElement.getAttribute('data-theme') || ''));
  if (th) root.setAttribute('data-theme', th);
  root.innerHTML = '<div class="pai-back" data-pai-close="1"></div>' +
    '<div class="pai-sheet" role="dialog" aria-modal="true" aria-label="PIGLOG AI (구현 준비중)">' +
    '<div class="pai-grab" data-pai-swipe="1"><span></span></div>' +
    '<header class="pai-hd"><strong>PIGLOG AI (구현 준비중)</strong><span class="pai-acts">' +
    '<button type="button" class="pai-sz" aria-label="창 크게" title="크게">⤢</button>' +
    '<button type="button" class="pai-cancel">취소</button>' +
    '<button type="button" class="pai-x" aria-label="닫기">✕</button></span></header>' +
    '<div id="pai-host" class="pai-host"></div></div>';
  document.body.appendChild(root);
  document.documentElement.classList.add('pai-lock');
  document.body.style.position = 'fixed';
  document.body.style.top = '-' + y + 'px';
  document.body.style.left = '0';
  document.body.style.right = '0';
  document.body.style.width = '100%';
  n7AiClose_._unlock = function () {
    document.body.style.position = '';
    document.body.style.top = '';
    document.body.style.left = '';
    document.body.style.right = '';
    document.body.style.width = '';
    window.scrollTo(0, y);
  };
  function close() { n7AiClose_(false); }
  root.querySelector('.pai-x').onclick = close;
  root.querySelector('.pai-cancel').onclick = close;
  root.querySelector('.pai-back').onclick = close;
  var sz = root.querySelector('.pai-sz');
  if (sz) sz.onclick = function (e) {
    if (e && e.stopPropagation) e.stopPropagation();
    var on = !root.classList.contains('pai-wide');
    root.classList.toggle('pai-wide', on);
    sz.setAttribute('aria-label', on ? '창 원래 크기' : '창 크게');
    sz.setAttribute('title', on ? '원래 크기' : '크게');
    sz.textContent = on ? '⤡' : '⤢';
    if (n7AiClose_._vv) n7AiClose_._vv();
  };
  var sheet = root.querySelector('.pai-sheet');
  var grab = root.querySelector('.pai-grab');
  var sy = 0, dy = 0, drag = 0;
  function start(e) { drag = 1; sy = (e.touches ? e.touches[0].clientY : e.clientY); dy = 0; sheet.style.transition = 'none'; }
  function move(e) { if (!drag) return; var y2 = (e.touches ? e.touches[0].clientY : e.clientY); dy = Math.max(0, y2 - sy); sheet.style.transform = 'translateY(' + dy + 'px)'; }
  function end() { if (!drag) return; drag = 0; sheet.style.transition = 'transform .2s ease'; if (dy > 80) close(); else sheet.style.transform = ''; }
  grab.addEventListener('touchstart', start, { passive: true });
  grab.addEventListener('touchmove', move, { passive: true });
  grab.addEventListener('touchend', end);
  document.addEventListener('keydown', n7AiEsc_);
  try { history.pushState({ pl: 'in', ai: 1, p: (PL && PL._page) || 'home' }, ''); n7AiClose_._hist = 1; } catch (e3) { n7AiClose_._hist = 0; }
  n7AiPinKb_(root);
  var host = document.getElementById('pai-host');
  n7LoadAi_(function () {
    if (!window.PiglogAI || !host) return;
    var api = PiglogAI.mount(host, {
      call: window.__plAi,
      farm: PL.farmId,
      lang: (window.I18N && I18N.lang) || PL.lang || 'ko',
      staff: PL.staffList,
      me: PL.user && PL.user.id,
      close: close,
      goSow: function (tag) { close(); n7OpenSow_(tag); },
      goRecord: function (typ, tag) { close(); n7GoEntry_(typ, tag); }
    });
    if (seed && api && api.ask) api.ask(seed);
    n7AiSyncTheme_(document.getElementById('pai-root'));
  });
  n7AiSyncTheme_(root);
}
function n7OpenSow_(tag) {
  if (!tag) return;
  try {
    if (typeof go === 'function') go('sows', { q: tag, open: tag });
    else if (PL && PL.go) PL.go('sows', { q: tag, open: tag });
  } catch (e) {}
}
function n7GoEntry_(typ, tag) {
  var arg = { type: typ || '전입', tag: tag || '' };
  try {
    if (typeof go === 'function') go('entry', arg);
    else if (PL && PL.go) PL.go('entry', arg);
  } catch (e) {}
}
function n7ConfirmCard_(opts) {
  return new Promise(function (resolve) {
    var old = document.getElementById('n7-croot'); if (old) old.remove();
    var root = document.createElement('div'); root.id = 'n7-croot';
    root.innerHTML = '<div class="n7-cback"></div><div class="n7-ccard" role="dialog" aria-modal="true"><h3>' + n7Esc2_(opts.title || '확인') + '</h3><div class="n7-cbody"></div><div class="n7-cacts"></div></div>';
    var body = root.querySelector('.n7-cbody');
    if (opts.html) body.innerHTML = opts.html; else body.textContent = opts.text || '';
    var acts = root.querySelector('.n7-cacts');
    function done(v) { root.remove(); resolve(v); }
    root.querySelector('.n7-cback').onclick = function () { done(null); };
    (opts.actions || [{ k: 'ok', l: '확인', pri: 1 }, { k: null, l: '취소' }]).forEach(function (a) {
      var b = document.createElement('button');
      b.type = 'button'; b.className = 'btn' + (a.pri ? '' : ' sec'); b.textContent = a.l;
      b.onclick = function () { done(a.k); };
      acts.appendChild(b);
    });
    document.body.appendChild(root);
  });
}

function n7FieldSize_(lab, ctrl) {
  var k = '';
  if (ctrl) {
    if (ctrl.getAttribute) k = ctrl.getAttribute('data-k') || ctrl.id || '';
    if (!k && ctrl.querySelector) {
      var inn = ctrl.querySelector('[data-k], #ef-tag, input, select, textarea');
      if (inn) k = inn.getAttribute('data-k') || inn.id || '';
    }
  }
  var t = ((lab && lab.textContent) || '') + ' ' + k;
  if (ctrl && (ctrl.id === 'ef-tag' || (ctrl.querySelector && ctrl.querySelector('#ef-tag')) || k === 'nickname' || /애칭|모돈번호/.test(t))) return 'n7-fl';
  if (/비고|메모|원인|위치|주소|백신·|약품명|설명|sowNote/.test(t) || (ctrl && (ctrl.tagName === 'TEXTAREA' || (ctrl.classList && ctrl.classList.contains('cz'))))) return 'n7-fl';
  if ((/총산|사산|미라/.test(t) || ((/^실산|실산 \*/.test(t)) && !/생시도태/.test(t))) && !/생시도태/.test(t)) return 'n7-fl';
  if (/도태_|기형|허약|압사|생시도태/.test(t)) return 'n7-fm';
  if (/폐사\s*두수|폐사두수/.test(t) || k === '폐사두수') return 'n7-fl';
  if (/두수|산차|체중|등지방|BCS|일령|회수|전입산차/.test(t) || (ctrl && ctrl.classList && ctrl.classList.contains('stepper'))) return 'n7-fs';
  if (/작업일|^날짜|날짜 \*/.test(t) || (ctrl && (ctrl.id === 'ef-date' || ctrl.type === 'date' || (ctrl.querySelector && ctrl.querySelector('#ef-date,input[type=date]'))))) return 'n7-fl';
  if (/웅돈|정액/.test(t) || /^(boar|semen|sire|sperm)$/i.test(k)) return 'n7-fl';
  if (/감정결과|교배방법/.test(t)) return 'n7-fl';
  if (ctrl && (ctrl.tagName === 'SELECT' || (ctrl.classList && ctrl.classList.contains('seg')))) return 'n7-fm';
  if (ctrl && ctrl.type === 'number') return 'n7-fs';
  return 'n7-fm';
}
function n7EntryLayout_(el) {
  if (!el) return;
  var entry = el.querySelector('.entry') || (el.classList && el.classList.contains('entry') ? el : null);
  if (!entry) return;
  var tagIn = entry.querySelector('#ef-tag');
  var nick = entry.querySelector('[data-k="nickname"]');
  if (tagIn && nick && !(nick.closest && nick.closest('.ef-nick-box'))) {
    var nickLab = nick.previousElementSibling && nick.previousElementSibling.matches && nick.previousElementSibling.matches('label.l') ? nick.previousElementSibling : null;
    var tagLab = tagIn.closest && tagIn.closest('.entry') ? null : null;
    var labs = entry.querySelectorAll('label.l');
    var i, tLab = null;
    for (i = 0; i < labs.length; i++) if (/모돈번호/.test(labs[i].textContent || '')) { tLab = labs[i]; break; }
    var tagRow = tagIn.closest('.row') || tagIn.parentNode;
    if (tLab && tagRow && nickLab) {
      /* keep as siblings; grid will size them as 중+중 after wrap */
      if (nickLab.parentNode) {
        var ref = tagRow.nextSibling;
        tagRow.parentNode.insertBefore(nickLab, ref);
        tagRow.parentNode.insertBefore(nick, nickLab.nextSibling);
      }
    }
  }
  (function () {
    var tagIn = entry.querySelector('#ef-tag');
    var nick = entry.querySelector('[data-k="nickname"]');
    if (!tagIn || !nick || (nick.closest && nick.closest('.ef-nick-box'))) return;
    var tagBox = tagIn.closest('.n7-f');
    var nickBox = nick.closest('.n7-f');
    if (!tagBox) {
      var tLab = null, labs = entry.querySelectorAll('label.l'), i;
      for (i = 0; i < labs.length; i++) if (/모돈번호/.test(labs[i].textContent || '')) { tLab = labs[i]; break; }
      var tagRow = tagIn.closest('.row') || tagIn.parentNode;
      if (tLab && tagRow) {
        tagBox = document.createElement('div'); tagBox.className = 'n7-f n7-fm';
        tLab.parentNode.insertBefore(tagBox, tLab);
        tagBox.appendChild(tLab); tagBox.appendChild(tagRow);
      }
    }
    if (!nickBox) {
      var nLab = nick.previousElementSibling && nick.previousElementSibling.matches && nick.previousElementSibling.matches('label.l') ? nick.previousElementSibling : null;
      nickBox = document.createElement('div'); nickBox.className = 'n7-f n7-fm';
      if (nLab) { nLab.parentNode.insertBefore(nickBox, nLab); nickBox.appendChild(nLab); }
      else nick.parentNode.insertBefore(nickBox, nick);
      nickBox.appendChild(nick);
    }
    if (tagBox && nickBox && !(tagBox.closest && (tagBox.closest('.n7-tagpair') || tagBox.closest('.n7-mate-top')))) {
      var pair = document.createElement('div'); pair.className = 'n7-tagpair';
      tagBox.parentNode.insertBefore(pair, tagBox);
      pair.appendChild(tagBox); pair.appendChild(nickBox);
    }
  })();
    var kids = [].slice.call(entry.children);
  var pairs = [];
  for (var i = 0; i < kids.length; i++) {
    var a = kids[i];
    if (!a || (a.classList && (a.classList.contains('n7-f') || a.classList.contains('n7-fgrid')))) continue;
    if (a.matches && a.matches('label.l') && kids[i + 1] && !(kids[i + 1].matches && kids[i + 1].matches('label.l'))) {
      pairs.push([a, kids[i + 1]]);
      i++;
    }
  }
  if (pairs.length) {
    var grid = entry.querySelector(':scope > .n7-fgrid');
    if (!grid) {
      grid = document.createElement('div');
      grid.className = 'n7-fgrid';
      entry.insertBefore(grid, pairs[0][0]);
    }
    pairs.forEach(function (p) {
      if (p[0].closest && p[0].closest('.n7-f')) return;
      var box = document.createElement('div');
      box.className = 'n7-f ' + n7FieldSize_(p[0], p[1]);
      grid.appendChild(box);
      box.appendChild(p[0]);
      box.appendChild(p[1]);
    });
  }
  entry.setAttribute('data-n7grid', '1');
}
function n7TapcFix_(el) {
  if (!el) return;
  [].forEach.call(el.querySelectorAll('.tapc'), function (c) {
    if (c.getAttribute('data-n7step')) return;
    var i = c.querySelector('input.tapi, input[data-k], input[type="number"]');
    if (!i) return;
    c.setAttribute('data-n7step', '1');
    c.classList.add('n7-step');
    var tapb = c.querySelector('.tapb'), tapk = c.querySelector('.tapk'), tapm = c.querySelector('.tapm');
    if (tapb && tapb.parentNode) tapb.parentNode.removeChild(tapb);
    if (tapk && tapk.parentNode) tapk.parentNode.removeChild(tapk);
    i.hidden = false;
    i.classList.add('tapi');
    if (tapm) { tapm.textContent = '−'; tapm.className = 'btn sec step tapm'; tapm.setAttribute('aria-label', '−'); }
    else {
      tapm = document.createElement('button');
      tapm.type = 'button'; tapm.className = 'btn sec step tapm'; tapm.textContent = '−';
      c.insertBefore(tapm, c.firstChild);
      tapm.onclick = function () { i.value = String(Math.max(0, (Number(i.value) || 0) - 1)); i.dispatchEvent(new Event('input', { bubbles: true })); };
    }
    var plus = c.querySelector('.tap-plus');
    if (!plus) {
      plus = document.createElement('button');
      plus.type = 'button'; plus.className = 'btn sec step tap-plus'; plus.textContent = '+';
      plus.setAttribute('aria-label', '+');
      plus.onclick = function () { i.value = String(Math.max(0, (Number(i.value) || 0) + 1)); i.dispatchEvent(new Event('input', { bubbles: true })); };
      c.appendChild(plus);
    }
    if (tapm.nextSibling !== i) c.insertBefore(i, tapm.nextSibling);
    if (plus.parentNode === c) c.appendChild(plus);
    var minuses = [].filter.call(c.querySelectorAll('button'), function (b) {
      var tx = (b.textContent || '').trim();
      return b.classList.contains('tapm') || tx === '−' || tx === '-' || tx === '–';
    });
    minuses.forEach(function (b, ix) { if (ix > 0 && b.parentNode) b.parentNode.removeChild(b); });
    var pluses = [].filter.call(c.querySelectorAll('button'), function (b) {
      return b.classList.contains('tap-plus') || (b.textContent || '').trim() === '+';
    });
    pluses.forEach(function (b, ix) { if (ix > 0 && b.parentNode) b.parentNode.removeChild(b); });
  });
}
function n7EntryOrder_(el) {
  var entry = (el && el.querySelector && el.querySelector('.entry')) || (el && el.classList && el.classList.contains('entry') ? el : null);
  if (!entry || entry.classList.contains('far') || entry.getAttribute('data-n7ord') === '1') return;
  function wrapOf(node) {
    if (!node) return null;
    return (node.closest && (node.closest('.n7-tagpair') || node.closest('.n7-f') || node.closest('.ef-row') || node.closest('.row') || node.closest('details.efmore'))) || node.parentNode;
  }
  var tag = entry.querySelector('#ef-tag');
  var date = entry.querySelector('#ef-date');
  var cause = entry.querySelector('.rchips');
  var more = entry.querySelector('details.efmore');
  var save = entry.querySelector('.far-bar') || entry.querySelector('#ef-save');
  var tagW = entry.querySelector('.n7-tagpair') || wrapOf(tag);
  var dateW = wrapOf(date);
  var causeW = wrapOf(cause);
  var blocks = [];
  function add(n) { if (n && entry.contains(n) && blocks.indexOf(n) < 0 && n.parentNode === entry || (n && n.parentNode && n.parentNode === entry)) { blocks.push(n); } }
  /* only reorder direct children */
  function childOf(n) {
    while (n && n.parentNode !== entry) n = n.parentNode;
    return n;
  }
  var tC = childOf(tagW || tag), dC = childOf(dateW || date), cC = childOf(causeW || cause), mC = childOf(more), sC = childOf(save);
  var rest = [].filter.call(entry.children, function (ch) {
    return ch !== tC && ch !== dC && ch !== cC && ch !== mC && ch !== sC && ch.tagName !== 'SCRIPT';
  });
  var ordered = [];
  if (tC) ordered.push(tC);
  if (dC && dC !== tC) ordered.push(dC);
  rest.forEach(function (ch) { ordered.push(ch); });
  if (cC && ordered.indexOf(cC) < 0) ordered.push(cC);
  if (mC && ordered.indexOf(mC) < 0) ordered.push(mC);
  if (sC && ordered.indexOf(sC) < 0) ordered.push(sC);
  ordered.forEach(function (ch) { if (ch && ch.parentNode === entry) entry.appendChild(ch); });
  entry.setAttribute('data-n7ord', '1');
}
function n7AlignNick_(entry) {
  if (!entry) return;
  var tag = entry.querySelector('#ef-tag');
  var nick = entry.querySelector('[data-k="nickname"]');
  if (!tag || !nick) return;
  if (nick.closest && nick.closest('.ef-nick-row, .ef-nick-box')) {
    nick.style.width = nick.style.maxWidth = nick.style.minWidth = nick.style.height = nick.style.minHeight = '';
    return;
  }
  var apply = function () {
    var w = tag.getBoundingClientRect().width;
    var h = tag.getBoundingClientRect().height;
    if (w < 40) return;
    nick.style.boxSizing = 'border-box';
    nick.style.width = w + 'px';
    nick.style.maxWidth = w + 'px';
    nick.style.minWidth = w + 'px';
    if (h > 0) {
      nick.style.height = h + 'px';
      nick.style.minHeight = h + 'px';
    }
  };
  apply();
  if (typeof requestAnimationFrame === 'function') requestAnimationFrame(apply);
  if (!entry._n7nickResize) {
    entry._n7nickResize = 1;
    window.addEventListener('resize', function () { n7AlignNick_(entry); });
  }
}
function n7DateRowFix_(el) {
  var entry = (el && el.querySelector && el.querySelector('.entry')) || (el && el.classList && el.classList.contains('entry') ? el : null);
  if (!entry) return;
  var date = entry.querySelector('#ef-date');
  if (date) {
    var row = (date.closest && (date.closest('.ef-row') || date.closest('.row'))) || date.parentNode;
    if (row) {
      [].slice.call(row.children).forEach(function (ch) {
        if (!ch || ch === date) return;
        if (ch.id === 'ef-date' || (ch.contains && ch.contains(date))) return;
        if (ch.matches && (ch.matches('[data-day]') || ch.matches('label') || ch.matches('.n7-dayhint') || ch.matches('.l'))) return;
        var box = (date.closest && date.closest('.n7-f')) || row;
        if (ch.parentNode === row && box && box.parentNode) box.parentNode.insertBefore(ch, box.nextSibling);
      });
    }
  }
  n7AlignNick_(entry);
}

function n7FarFix_(el) {
  var entry = (el && el.querySelector && el.querySelector('.entry')) || (el && el.classList && el.classList.contains('entry') ? el : null);
  if (!entry) return;
  /* 총산 줄을 사산 칸 앞으로 옮기다가 두 far-line이 한 n7-f에 묶이면 한 줄로 붙음 → 칸마다 n7-f로 분리 */
  [].slice.call(entry.querySelectorAll('.n7-f')).forEach(function (box) {
    var lines = [].filter.call(box.children, function (ch) {
      return ch.classList && (ch.classList.contains('far-line') || ch.classList.contains('m-far-line') || ch.classList.contains('far-cull'));
    });
    if (lines.length < 2) return;
    var grid = box.parentNode;
    lines.slice(1).forEach(function (line) {
      var nb = document.createElement('div');
      nb.className = 'n7-f n7-fl';
      if (grid) grid.insertBefore(nb, box.nextSibling);
      else box.parentNode.insertBefore(nb, box.nextSibling);
      nb.appendChild(line);
      box = nb;
    });
  });
  ['총산', '사산', '미라', '실산'].forEach(function (k) {
    var inp = entry.querySelector('[data-k="' + k + '"]');
    if (!inp) return;
    var line = (inp.closest && (inp.closest('.far-line') || inp.closest('.m-far-line'))) || null;
    var box = (inp.closest && inp.closest('.n7-f')) || line || inp.parentNode;
    if (box && box.classList) { box.classList.remove('n7-fs', 'n7-fm'); box.classList.add('n7-fl'); }
    [line, box].forEach(function (n) {
      if (!n || !n.style) return;
      n.style.flex = '1 1 100%';
      n.style.flexBasis = '100%';
      n.style.maxWidth = '100%';
      n.style.width = '100%';
    });
    if (box && box.style) box.style.flexDirection = 'column';
  });
  var culls = entry.querySelector('.far-culls');
  if (culls) {
    culls.style.width = '100%';
    culls.style.maxWidth = '100%';
    culls.style.flex = '1 1 100%';
    var wrap = culls.closest && culls.closest('.n7-f');
    if (wrap) {
      wrap.classList.remove('n7-fs', 'n7-fm'); wrap.classList.add('n7-fl');
      wrap.style.flex = '1 1 100%'; wrap.style.width = '100%'; wrap.style.maxWidth = '100%';
    }
    if (typeof n7TapcFix_ === 'function') {
      [].forEach.call(culls.querySelectorAll('.far-line, .far-cull, .tapc'), function (c) { n7TapcFix_(c.parentNode || culls); });
      n7TapcFix_(culls);
    }
  }
  var date = entry.querySelector('#ef-date');
  if (date) {
    date.style.minWidth = '150px';
    var row = (date.closest && (date.closest('.ef-row') || date.closest('.row') || date.closest('.n7-f'))) || date.parentNode;
    if (row && row.style) row.style.flexWrap = 'wrap';
  }
}
function n7HookFarFix_() {
  if (typeof farrowField_ === 'function' && !farrowField_._n7far) {
    var orig = farrowField_;
    farrowField_ = function (el, o) {
      var r = orig.apply(this, arguments);
      if (typeof n7FarFix_ === 'function') try { n7FarFix_(el); } catch (e) {}
      return r;
    };
    farrowField_._n7far = 1;
  }
}
n7HookFarFix_();
function n7Age10_(el) {
  var aI = el.querySelector('[data-k="전입일령"]');
  if (!aI || aI.closest('.n7-age10')) return;
  var wrap = document.createElement('div');
  wrap.className = 'n7-age10 row stepper n7-step';
  var m = document.createElement('button'); m.type = 'button'; m.className = 'btn sec step'; m.setAttribute('data-d', '-10'); m.textContent = '−10';
  var p = document.createElement('button'); p.type = 'button'; p.className = 'btn sec step'; p.setAttribute('data-d', '10'); p.textContent = '+10';
  aI.parentNode.insertBefore(wrap, aI);
  wrap.appendChild(m); wrap.appendChild(aI); wrap.appendChild(p);
  function bump(d) {
    var v = Number(aI.value); if (isNaN(v) || aI.value === '') v = 0;
    var nv = v + d;
    var min = aI.min === '' || aI.min == null ? 1 : Number(aI.min);
    var max = aI.max === '' || aI.max == null ? 1500 : Number(aI.max);
    if (nv < min) nv = min; if (nv > max) nv = max;
    aI.value = String(Math.round(nv));
    try { aI.dispatchEvent(new Event('input', { bubbles: true })); } catch (e) {}
  }
  m.onclick = function (e) { e.preventDefault(); e.stopPropagation(); bump(-10); };
  p.onclick = function (e) { e.preventDefault(); e.stopPropagation(); bump(10); };
}

function n7WeanUi_(el, typ) {
  if (typ !== '이유' || !el || el.getAttribute('data-n7wean')) return;
  el.setAttribute('data-n7wean', '1');
  var heads = el.querySelector('[data-k="이유두수"]');
  var tot = el.querySelector('[data-k="이유체중합"]');
  if (heads) {
    var lab = heads.closest('.n7-f') ? heads.closest('.n7-f').querySelector('label.l') : (heads.previousElementSibling);
    if (!lab || !/이유/.test(lab.textContent || '')) {
      var labs = el.querySelectorAll('label.l'), li;
      for (li = 0; li < labs.length; li++) if (/이유\s*두수/.test(labs[li].textContent || '')) { lab = labs[li]; break; }
    }
    if (lab && /이유/.test(lab.textContent || '') && lab.textContent.indexOf('1복') < 0) lab.textContent = '이유 두수 (1복) *';
  }
  if (!tot) return;
  var totLab = tot.closest('.n7-f') ? tot.closest('.n7-f').querySelector('label.l') : tot.previousElementSibling;
  var mode = 'avg';
  try { mode = localStorage.getItem('pl_weanWt:' + (PL && PL.farmId || '')) || 'avg'; } catch (e) {}
  var tog = document.createElement('div'); tog.className = 'n7-wtog n7-fl';
  tog.innerHTML = '<button type="button" data-m="avg">평균 체중</button><button type="button" data-m="lit">복당 체중</button>';
  var host = tot.closest('.n7-f') || tot.parentNode;
  host.parentNode.insertBefore(tog, host);
  var avg = document.createElement('input');
  avg.type = 'number'; avg.inputMode = 'decimal'; avg.step = '0.1'; avg.min = '0';
  avg.className = 'f'; avg.setAttribute('data-n7avg', '1');
  avg.placeholder = '평균 kg';
  var avgBox = document.createElement('div'); avgBox.className = 'n7-f n7-fs';
  avgBox.innerHTML = '<label class="l">평균 이유체중 kg</label>';
  avgBox.appendChild(avg);
  host.parentNode.insertBefore(avgBox, host);
  function apply() {
    tog.querySelectorAll('button').forEach(function (b) { b.classList.toggle('on', b.getAttribute('data-m') === mode); });
    avgBox.style.display = mode === 'avg' ? '' : 'none';
    host.style.display = mode === 'lit' ? '' : 'none';
    if (totLab) totLab.textContent = mode === 'lit' ? '복당 이유체중 kg (선택)' : '이유 총체중 kg (자동)';
  }
  function syncTot() {
    if (mode !== 'avg' || !heads) return;
    var n = Number(heads.value), a = Number(avg.value);
    if (!isNaN(n) && !isNaN(a) && n > 0 && a > 0) tot.value = String(Math.round(n * a * 100) / 100);
  }
  tog.querySelectorAll('button').forEach(function (b) {
    b.onclick = function () {
      mode = b.getAttribute('data-m');
      try { localStorage.setItem('pl_weanWt:' + (PL && PL.farmId || ''), mode); } catch (e2) {}
      apply();
    };
  });
  avg.addEventListener('input', syncTot);
  if (heads) heads.addEventListener('input', syncTot);
  apply();
}

function n7SowStateOk_(st, typ) {
  var s = String(st || '');
  if (typ === '이유' && (/교배/.test(s) || /임신/.test(s))) return '교배했거나 임신 중인 모돈은 이유할 수 없습니다.';
  return '';
}
function n7IsNursing_(c) {
  if (!c) return false;
  var s = String(c.state || c.stateLabel || '');
  if (/포유/.test(s)) return true;
  var left = c.left != null ? Number(c.left) : 0;
  return left > 0 && !/퇴출|이유|임신|교배|후보/.test(s);
}
function n7FarrowDate_(c) {
  if (!c) return '';
  var far = c.far || c.farrowDates || [];
  if (far && far.length) return String(far[far.length - 1] || far[0] || '').slice(0, 10);
  var hist = c.history || c.hist || [];
  var i, d = '';
  for (i = 0; i < hist.length; i++) {
    var h = hist[i];
    var typ = h['유형'] || h.type || '';
    if (typ === '분만' && (h['상태'] === '정상' || !h['상태'])) d = String(h['작업일'] || h.date || '').slice(0, 10);
  }
  return d;
}

function n7EntryGuards_(el, typ) {
  var save = el.querySelector('#ef-save');
  if (!save || save.getAttribute('data-n7g')) return;
  save.setAttribute('data-n7g', '1');
  save.addEventListener('click', function (e) {
    if (save.getAttribute('data-n7run')) return;
    var tagEl = el.querySelector('#ef-tag');
    var tag = tagEl ? tagEl.value.trim() : '';
    if (!tag || typ === '전입') return;
    var goOn = function (c) {
      var block = n7SowStateOk_(c && (c.stateLabel || c.state), typ);
      if (block) {
        e.preventDefault(); e.stopImmediatePropagation();
        var msg = el.querySelector('#ef-msg') || el.querySelector('.msg');
        if (msg) msg.innerHTML = '<div class="sowinfo no">⚠ ' + n7Esc2_(block) + '</div>';
        else if (typeof toast === 'function') toast(block);
        n7ConfirmCard_({ title: '이유할 수 없습니다', text: block, actions: [{ k: 'ok', l: '확인', pri: 1 }] });
        return;
      }
      if (typ === '도폐사') {
        var kindBtn = el.querySelector('.seg[data-k="퇴출구분"] button.on');
        var kind = kindBtn ? String(kindBtn.getAttribute('data-v') || kindBtn.textContent || '').trim() : '';
        if (kind === '폐사' || kind === '도태') {
          var cz = el.querySelector('.cz[data-k="원인"]') || el.querySelector('[data-k="원인"]');
          var why = cz ? String((cz.dataset && cz.dataset.v) || cz.getAttribute('data-v') || cz.value || '').trim() : '';
          if (!why) {
            e.preventDefault(); e.stopImmediatePropagation();
            n7ConfirmCard_({ title: '원인을 고르세요', text: '도태·폐사는 원인(다섯 가지 또는 기타)을 고른 뒤 저장해 주세요.', actions: [{ k: 'ok', l: '확인', pri: 1 }] });
            return;
          }
        }
        if (n7IsNursing_(c) && (kind === '폐사' || kind === '도태')) {
          e.preventDefault(); e.stopImmediatePropagation();
          n7NursingDeath_(el, typ, tag, c);
        }
      }
    };
    if (typeof apiF !== 'function') return;
    e.preventDefault(); e.stopImmediatePropagation();
    apiF('getSowCard', tag).then(function (c) {
      if (!c || !c.found) {
        save.setAttribute('data-n7run', '1');
        save.click();
        setTimeout(function () { save.removeAttribute('data-n7run'); }, 0);
        return;
      }
      var block = n7SowStateOk_(c.stateLabel || c.state, typ);
      if (block) {
        var msg = el.querySelector('#ef-msg') || el.querySelector('.msg');
        if (msg) msg.innerHTML = '<div class="sowinfo no">⚠ ' + n7Esc2_(block) + '</div>';
        n7ConfirmCard_({ title: '이유할 수 없습니다', text: block, actions: [{ k: 'ok', l: '확인', pri: 1 }] });
        return;
      }
      if (typ === '도폐사' && n7IsNursing_(c)) {
        var kindBtn = el.querySelector('.seg[data-k="퇴출구분"] button.on');
        var kind = kindBtn ? (kindBtn.getAttribute('data-v') || kindBtn.textContent) : '';
        if (!kind || kind === '폐사' || kind === '도태') { n7NursingDeath_(el, typ, tag, c); return; }
      }
      save.setAttribute('data-n7run', '1');
      save.click();
      setTimeout(function () { save.removeAttribute('data-n7run'); }, 0);
    }, function () {
      save.setAttribute('data-n7run', '1');
      save.click();
      setTimeout(function () { save.removeAttribute('data-n7run'); }, 0);
    });
  }, true);
}

function n7ReadEntry_(el, typ) {
  var ev = { type: typ, tag: (el.querySelector('#ef-tag') || {}).value, date: (el.querySelector('#ef-date') || {}).value, ask: 1 };
  ev.tag = String(ev.tag || '').trim();
  ev.date = String(ev.date || '').trim();
  [].forEach.call(el.querySelectorAll('[data-k]'), function (i) {
    var k = i.getAttribute('data-k'); if (!k) return;
    if (i.classList && i.classList.contains('seg')) {
      var on = i.querySelector('button.on'); ev[k] = on ? (on.getAttribute('data-v') != null ? on.getAttribute('data-v') : on.textContent) : '';
    } else ev[k] = i.value;
  });
  return ev;
}

function n7NursingDeath_(el, typ, tag, card) {
  var left = card && card.left != null ? Number(card.left) : 0;
  var far = n7FarrowDate_(card);
  var ev0 = n7ReadEntry_(el, typ);
  var load = (typeof apiF === 'function') ? apiF('listSows', { state: '포유', includeExited: false }) : Promise.resolve({ rows: [] });
  load.then(function (r) {
    var rows = (r && (r.rows || r.items || r.sows)) || [];
    var cands = rows.filter(function (s) { return String(s.tag) !== String(tag); });
    return Promise.all(cands.slice(0, 40).map(function (s) {
      return apiF('getSowCard', s.tag).then(function (c) {
        c.list = s; return c;
      }, function () { return { found: false, tag: s.tag, list: s }; });
    })).then(function (cs) {
      var same = cs.filter(function (c) { return c && c.found && n7IsNursing_(c) && far && n7FarrowDate_(c) === far; });
      var near = cs.filter(function (c) { return c && c.found && n7IsNursing_(c); });
      var pick = same.length ? same : near;
      return n7PickAndRun_(el, ev0, tag, card, left, pick, far, !!same.length);
    });
  }).catch(function (e) {
    if (typeof toast === 'function') toast(String(e && e.message || e));
  });
}

function n7PickAndRun_(el, ev0, tag, card, left, pick) {
  return new Promise(function (resolve) {
    var old = document.getElementById('n7-croot'); if (old) old.remove();
    var root = document.createElement('div'); root.id = 'n7-croot';
    var far = n7FarrowDate_(card);
    var html = '<p>아직 포유자돈이 이유 상태가 아닙니다. 동일 분만일의 살아있는 포유모돈에게 자돈들을 양자 보낼까요?</p>' +
      (far ? '<p class="mut">이 모돈 분만일 ' + n7Esc2_(far) + (left ? ' · 남은 자돈 ' + left + '두' : '') + '</p>' : '') +
      '<div class="n7-pick">' + pick.slice(0, 16).map(function (c, i) {
        return '<button type="button" data-tag="' + n7Esc2_(c.tag) + '"' + (i === 0 ? ' class="on"' : '') + '>' + n7Esc2_(c.tag) + (c.nickname ? ' · ' + n7Esc2_(c.nickname) : '') + ' · ' + n7Esc2_(c.stateLabel || '포유') + (n7FarrowDate_(c) ? ' · 분만 ' + n7Esc2_(n7FarrowDate_(c)) : '') + '</button>';
      }).join('') + '</div>';
    root.innerHTML = '<div class="n7-cback"></div><div class="n7-ccard" role="dialog" aria-modal="true"><h3>포유 중 폐사</h3><div class="n7-cbody">' + html + '</div><div class="n7-cacts">' +
      '<button type="button" class="btn" data-k="go">양자 보내고 이유·폐사 기록</button>' +
      '<button type="button" class="btn sec" data-k="x">취소</button></div></div>';
    document.body.appendChild(root);
    var sel = pick[0] && pick[0].tag;
    root.querySelectorAll('.n7-pick button').forEach(function (b) {
      b.onclick = function () {
        root.querySelectorAll('.n7-pick button').forEach(function (x) { x.classList.remove('on'); });
        b.classList.add('on'); sel = b.getAttribute('data-tag');
      };
    });
    root.querySelector('.n7-cback').onclick = function () { root.remove(); resolve(null); };
    root.querySelector('[data-k="x"]').onclick = function () { root.remove(); resolve(null); };
    root.querySelector('[data-k="go"]').onclick = function () {
      var b = this; b.disabled = true; b.textContent = '기록 중…';
      n7RunFosterWeanDeath_(el, ev0, tag, card, left, sel).then(function (ok) { root.remove(); resolve(ok); }, function (err) {
        b.disabled = false; b.textContent = '양자 보내고 이유·폐사 기록';
        var p = document.createElement('p'); p.className = 'pai-err'; p.textContent = String(err && err.message || err);
        root.querySelector('.n7-cbody').appendChild(p);
      });
    };
  });
}

function n7SaveEvOk_(ev) {
  ev = ev || {};
  ev.ask = 1;
  function go() {
    return apiF('saveEvent', ev).catch(function (e) {
      if (!e || e.key !== 'e.ev.confirm') throw e;
      var cp = (typeof confParams_ === 'function') ? confParams_(e) : {};
      var codes = String(cp.codes || '').split(',').filter(Boolean);
      if (!codes.length) throw e;
      ev.okConf = [ev.okConf, codes.join(',')].filter(Boolean).join(',');
      return apiF('saveEvent', ev);
    });
  }
  return go();
}
function n7RunFosterWeanDeath_(el, ev0, tag, card, left, partner) {
  var n = left && left > 0 ? left : 0;
  var date = ev0.date;
  var chain = Promise.resolve();
  if (partner && n > 0) {
    chain = n7SaveEvOk_({ type: '양자', tag: tag, date: date, '양자구분': '전출', '두수': String(n), '상대모돈': partner, '비고': '포유 중 폐사 전 양자' }).then(function () {
      return n7SaveEvOk_({ type: '양자', tag: partner, date: date, '양자구분': '전입', '두수': String(n), '상대모돈': tag, '비고': '포유 중 폐사 양자 받음' });
    });
  }
  return chain.then(function () {
    return n7SaveEvOk_({ type: '이유', tag: tag, date: date, '이유두수': '0', '이유체중합': '', '비고': '포유 중 폐사에 이은 이유' });
  }).then(function () {
    var ev = ev0; ev.type = '도폐사'; ev.tag = tag; ev.date = date;
    return n7SaveEvOk_(ev);
  }).then(function (r) {
    var msg = el.querySelector('#ef-msg') || el.querySelector('.msg');
    if (msg) msg.innerHTML = '<div class="sowinfo ok">양자' + (partner ? '(' + n7Esc2_(partner) + ')' : '') + ' → 이유 → 도폐사를 기록했습니다.</div>';
    if (typeof toast === 'function') toast('양자·이유·도폐사를 기록했습니다');
    if (typeof el.onSaved === 'function') try { el.onSaved(r); } catch (e) {}
    return r;
  });
}


function n7FieldGroup_(entry, labRe, ctrl, size) {
  if (!ctrl || !entry) return null;
  var existing = ctrl.closest && ctrl.closest('.n7-f');
  if (existing && entry.contains(existing)) return existing;
  var lab = null, labs = entry.querySelectorAll('label.l'), i;
  if (labRe) {
    for (i = 0; i < labs.length; i++) if (labRe.test(labs[i].textContent || '')) { lab = labs[i]; break; }
  }
  var row = ctrl;
  if (ctrl.id === 'ef-date' || ctrl.id === 'ef-tag') row = ctrl.closest('.ef-row') || ctrl.closest('.row') || ctrl;
  else if (ctrl.closest) row = ctrl.closest('.seg') || ctrl.closest('.stepper') || ctrl.closest('.ef-nick-box') || ctrl;
  var box = document.createElement('div');
  box.className = 'n7-f ' + (size || 'n7-fm');
  if (lab) box.appendChild(lab);
  box.appendChild(row);
  var k = ctrl.getAttribute && ctrl.getAttribute('data-k');
  if (k) {
    var lim = entry.querySelector('[data-limc="' + k + '"]');
    if (lim) box.appendChild(lim);
  }
  return box;
}
function n7NickPaneFix_(entry) {
  if (!entry) return;
  var box = entry.querySelector('.ef-nick-box');
  var inp = entry.querySelector('[data-k="nickname"]');
  if (!box || !inp) return;
  var pane = box.querySelector('[data-nick-pane]');
  if (!pane) {
    pane = box.querySelector(':scope > div:not(.ef-nick-fold)');
    if (pane) pane.setAttribute('data-nick-pane', '');
    else { pane = document.createElement('div'); pane.setAttribute('data-nick-pane', ''); box.appendChild(pane); }
  }
  var row = box.querySelector('.ef-nick-row');
  if (!row) { row = document.createElement('div'); row.className = 'ef-nick-row'; }
  if (row.parentNode !== pane) pane.appendChild(row);
  var btn = box.querySelector('.nov7-rand') || entry.querySelector('.nov7-rand');
  if (!btn) {
    btn = document.createElement('button');
    btn.type = 'button'; btn.className = 'btn sec nov7-rand'; btn.textContent = '랜덤 이름';
    btn.onclick = function () {
      if (typeof nov7SuggestName_ !== 'function') return;
      var sug = nov7SuggestName_(typeof nov7NameCat_ === 'function' ? nov7NameCat_() : null, 'sow', [], null);
      if (!sug || !sug.ok) return;
      if (inp.value && inp.value.trim() && !window.confirm('입력칸의 애칭을 바꿀까요? 저장을 누르기 전까지 기록은 바뀌지 않습니다.')) return;
      inp.value = sug.name; inp.setAttribute('data-d', '1'); inp.dispatchEvent(new Event('input', { bubbles: true }));
      btn.textContent = '다른 이름';
    };
  }
  if (inp.parentNode !== row) row.appendChild(inp);
  inp.style.width = inp.style.maxWidth = inp.style.minWidth = inp.style.height = inp.style.minHeight = '';
  if (btn) { if (btn.parentNode !== row) row.appendChild(btn); row.appendChild(inp); row.appendChild(btn); }
  var lim = entry.querySelector('[data-limc="nickname"]');
  if (lim) { if (!pane.contains(lim)) pane.appendChild(lim); lim.style.display = pane.hidden ? 'none' : ''; }
}
function n7MateLay_(el) {
  var entry = (el && el.querySelector && el.querySelector('.entry')) || (el && el.classList && el.classList.contains('entry') ? el : null);
  if (!entry) return;
  var tag = entry.querySelector('#ef-tag');
  var date = entry.querySelector('#ef-date');
  if (!tag || !date) return;
  var tagBox = n7FieldGroup_(entry, /모돈번호/, tag, 'n7-fm');
  var dateBox = n7FieldGroup_(entry, /작업일/, date, 'n7-fm');
  if (!tagBox || !dateBox) return;
  /* 애칭은 모돈번호 바로 아래(접힘). 남은 애칭 칸은 모은 뒤 하나만 둔다. */
  var nickBox = entry.querySelector('.ef-nick-box');
  var nickInp = entry.querySelector('[data-k="nickname"]');
  var nickLim = entry.querySelector('[data-limc="nickname"]');
  entry.querySelectorAll('label.l').forEach(function (lab) {
    if (/애칭|예정 \(선택\)/.test(lab.textContent || '') && nickBox && !nickBox.contains(lab) && !tagBox.contains(lab)) {
      if (nickBox) nickBox.appendChild(lab);
      else tagBox.appendChild(lab);
    }
  });
  if (nickBox) tagBox.appendChild(nickBox);
  else if (nickInp) tagBox.appendChild(nickInp);
  if (typeof n7NickPaneFix_ === 'function') n7NickPaneFix_(entry);
  else if (nickLim) tagBox.appendChild(nickLim);
  if (nickBox && nickInp) {
    var pane = nickInp.parentNode;
    entry.querySelectorAll('label.l').forEach(function (lab) {
      if (/애칭/.test(lab.textContent || '') && !pane.contains(lab)) pane.insertBefore(lab, pane.firstChild);
    });
    if (!(nickInp.value || '').trim() && pane && pane !== nickBox) pane.hidden = true;
  }
  if (nickBox && nickBox.querySelector && nickBox.querySelector('[hidden], [style*="display: none"]')) {
    /* keep counter hidden when folded — handled in show() */
  }
  var pane = nickBox && nickBox.querySelector('div:nth-of-type(2), [data-k="nickname"]') && nickInp && nickInp.parentNode;
  var foldedOff = !!(nickBox && nickInp && nickInp.offsetParent === null);
  if (nickLim && foldedOff) nickLim.style.display = 'none';
  var top = entry.querySelector(':scope > .fg.n7-mate-top');
  if (!top) { top = document.createElement('div'); top.className = 'fg n7-mate-top'; }
  top.appendChild(tagBox); top.appendChild(dateBox);
  /* t524u: 반복 배치로 남은 빈 칸이 모돈번호 위에 공백을 만듦 — 실제 두 칸만 남김 */
  [].slice.call(top.children).forEach(function (ch) {
    if (ch !== tagBox && ch !== dateBox) top.removeChild(ch);
  });
  var nicks = entry.querySelectorAll('.ef-nick-box');
  if (nicks.length > 1) {
    var keep = tagBox.querySelector('.ef-nick-box') || nicks[0];
    [].forEach.call(nicks, function (n) { if (n !== keep && n.parentNode) n.parentNode.removeChild(n); });
  }
  var keepNick = tagBox.querySelector('.ef-nick-box') || entry.querySelector('.ef-nick-box');
  if (keepNick) {
    var pane = keepNick.querySelector('[data-nick-pane], .ef-nick-box > div:not(.ef-nick-fold)') || keepNick;
    [].slice.call(entry.querySelectorAll('label.l')).forEach(function (lab) {
      if (!/애칭/.test(lab.textContent || '')) return;
      if (keepNick.contains(lab)) return;
      if (pane) pane.insertBefore(lab, pane.firstChild);
      else if (lab.parentNode) lab.parentNode.removeChild(lab);
    });
  }
  if (typeof n7NickPaneFix_ === 'function') n7NickPaneFix_(entry);
  [].slice.call(entry.querySelectorAll('.n7-tagpair, .n7-f')).forEach(function (n) {
    if (n === tagBox || n === dateBox || (tagBox && tagBox.contains(n)) || (dateBox && dateBox.contains(n))) return;
    if (n.querySelector && n.querySelector('#ef-tag, #ef-date, [data-k], input, textarea, select, button:not(.n7-look-sm), .ef-nick-box, .locpick, .shp')) return;
    if (n.parentNode) n.parentNode.removeChild(n);
  });
  var boar = entry.querySelector('[data-k="웅돈"]');
  var method = entry.querySelector('[data-k="교배방법"]');
  var mid = entry.querySelector(':scope > .fg.n7-mate-mid');
  if (boar || method) {
    if (!mid) { mid = document.createElement('div'); mid.className = 'fg n7-mate-mid'; }
    if (boar) mid.appendChild(n7FieldGroup_(entry, /웅돈/, boar, 'n7-fm'));
    if (method) mid.appendChild(n7FieldGroup_(entry, /교배방법/, method, 'n7-fm'));
  }
  var memo = entry.querySelector('[data-k="비고"]');
  var memoBox = memo ? n7FieldGroup_(entry, /^\s*비고/, memo, 'n7-fl') : null;
  if (memoBox) { memoBox.style.flex = '1 1 100%'; memoBox.style.maxWidth = '100%'; memoBox.style.width = '100%'; }
  var sow = entry.querySelector('#ef-sow');
  if (sow && tagBox) {
    var nickSlot = tagBox.querySelector('.ef-nick-box');
    if (nickSlot) tagBox.insertBefore(sow, nickSlot);
    else tagBox.appendChild(sow);
    sow.classList.add('n7-sow-status');
    sow = null;
  }
  var score = entry.querySelector('.n7sc-box, .n7sc-entry, #n7sc-entry');
  var recent = entry.querySelector('.recent, .ef-recent, #ef-recent, .n7-recent');
  var loc = entry.querySelector('.locpick');
  var more = entry.querySelector('details.efmore');
  var msg = entry.querySelector('#ef-msg');
  var save = entry.querySelector('#ef-save');
  var locBlock = loc && (function () {
    var n = loc, lab = loc.previousElementSibling;
    while (n && n.parentNode !== entry) n = n.parentNode;
    return n;
  })();
  /* 확정 순서: 모돈+작업일 → 확인칸 → 특징 → 최근칩 → 웅돈+교배방법 → 비고 → 위치 → 추가 → 저장 */
  var seq = [top, sow, score, recent, mid, memoBox, locBlock, more, msg, save].filter(function (n, i, a) { return n && a.indexOf(n) === i && (n.parentNode === entry || n === top || n === mid || n === memoBox || !n.parentNode || n.parentNode === entry); });
  seq.forEach(function (n) {
    if (n === locBlock && loc) {
      var lab = loc.previousElementSibling;
      if (lab && lab.matches && lab.matches('label.l') && lab.parentNode === entry) entry.appendChild(lab);
    }
    entry.appendChild(n);
  });
  /* 묶지 못한 칸(최근 칩, 모돈 비고, 특징)은 모돈 확인 칸과 웅돈 사이에 둔다. 맨 위로 올리지 않음. */
  var park = mid || memoBox || msg || save;
  [].slice.call(entry.children).forEach(function (ch) {
    if (!park || ch === park) return;
    if (ch === top || ch === sow || ch === mid || ch === memoBox || ch === locBlock || ch === more || ch === msg || ch === save) return;
    if (ch.tagName === 'SCRIPT') return;
    if (park.parentNode === entry) entry.insertBefore(ch, park);
  });
  if (loc && loc.parentNode === entry) {
    var l2 = loc.previousElementSibling;
    if (l2 && l2.matches && l2.matches('label.l')) { /* already with loc if wrapped */ }
  }
  [].slice.call(entry.querySelectorAll(':scope > .fg, :scope > .fc, :scope > .n7-tagpair')).forEach(function (n) {
    if (n.classList.contains('n7-mate-top') || n.classList.contains('n7-mate-mid') || n.classList.contains('n7-ageg')) return;
    if (n.querySelector && n.querySelector('#ef-tag, #ef-date, [data-k="웅돈"], [data-k="교배방법"]')) return;
    if (n.parentNode) {
      while (n.firstChild) n.parentNode.insertBefore(n.firstChild, n);
      n.parentNode.removeChild(n);
    }
  });
  /* 비어 있는 애칭 라벨만 남은 경우 제거 */
  [].slice.call(entry.children).forEach(function (n) {
    if (n === top || n === mid || n === tagBox) return;
    if (n.matches && n.matches('label.l') && /애칭/.test(n.textContent || '') && !tagBox.contains(n)) n.parentNode.removeChild(n);
  });
}

function n7PolishEntryT447_(el, opt) {
  if (!el) return;
  var typBtn = el.parentNode && el.parentNode.querySelector('#en-t button.on');
  var typ = (opt && opt.type) || (typBtn ? typBtn.getAttribute('data-t') : '') || '';
  var look = el.querySelector('#ef-look');
  if (look) { look.classList.add('n7-look-sm'); look.setAttribute('aria-label', '확인'); }
  n7EntryLayout_(el);
  n7TapcFix_(el);
  n7EntryOrder_(el);
  n7DateRowFix_(el);
  n7FarFix_(el);
  if (typeof n7MateLay_ === 'function') n7MateLay_(el);
  n7Age10_(el);
  n7WeanUi_(el, typ);
  n7EntryGuards_(el, typ);
  var host = document.getElementById('w-main') || document.getElementById('m-main') || el;
  if (typeof n7VaccWatch_ === 'function') n7VaccWatch_(host, typ);
  if (typeof n7NextStall_ === 'function') n7NextStall_(el);
}

function n7SettingsControls_(root) {
  if (!root) return;
  var tables = root.querySelectorAll('.n7-st-hub table.t, table.t');
  [].forEach.call(tables, function (tbl) {
    if (!tbl.querySelector('#st-go') && !(root.querySelector('#st-go') && tbl.closest && (tbl.closest('.card') || tbl.closest('.n7-st-hub')))) {
      /* still process hub tables */
    }
    if (tbl.getAttribute('data-n7ctl')) return;
    if (!tbl.rows || !tbl.rows.length) return;
    var head = (tbl.rows[0].textContent || '');
    if (!/값|내용|설정/.test(head) && !tbl.querySelector('[data-k]')) return;
    tbl.setAttribute('data-n7ctl', '1');
    var host = document.createElement('div'); host.className = 'n7-st-cards';
    tbl.parentNode.insertBefore(host, tbl);
    for (var i = 1; i < tbl.rows.length; i++) {
      var tr = tbl.rows[i];
      var keyCell = tr.cells[0], valCell = tr.cells[1], descCell = tr.cells[2];
      if (!valCell) continue;
      var inp = valCell.querySelector('[data-k]');
      var key = inp ? inp.getAttribute('data-k') : (keyCell && keyCell.textContent || '').trim();
      var desc = descCell ? (descCell.textContent || '').trim() : '';
      var row = document.createElement('div'); row.className = 'n7-st-row';
      var kh = document.createElement('div'); kh.className = 'n7-st-k';
      kh.appendChild(document.createTextNode((keyCell && keyCell.textContent || key || '').trim()));
      if (desc) {
        var ib = document.createElement('button'); ib.type = 'button'; ib.className = 'n7-i'; ib.setAttribute('aria-label', '설명'); ib.textContent = 'ⓘ';
        ib.onclick = function (rr) { return function () { rr.classList.toggle('open'); }; }(row);
        kh.appendChild(ib);
        var dd = document.createElement('div'); dd.className = 'n7-st-d'; dd.textContent = desc;
        row.appendChild(kh); row.appendChild(dd);
      } else row.appendChild(kh);
      var ctl = document.createElement('div');
      n7BuildSettingCtl_(ctl, key, inp, valCell);
      row.appendChild(ctl);
      host.appendChild(row);
    }
    tbl.classList.add('n7-hide-m');
  });
  n7BrnCard_(root);
  if (typeof n7StaffCards_ === 'function') n7StaffCards_(root);
}
function n7BuildSettingCtl_(ctl, key, inp, valCell) {
  if (!inp) { if (valCell) ctl.appendChild(valCell); return; }
  function keepHidden() { /* inp stays, we just restyle around it */ }
  if (key === '근무_요일') {
    var cur = String(inp.value || '').split(',').map(function (x) { return x.trim(); }).filter(Boolean);
    var days = [['1', '월'], ['2', '화'], ['3', '수'], ['4', '목'], ['5', '금'], ['6', '토'], ['7', '일']];
    var wrap = document.createElement('div'); wrap.className = 'n7-wd';
    days.forEach(function (d) {
      var b = document.createElement('button'); b.type = 'button'; b.textContent = d[1];
      if (cur.indexOf(d[0]) >= 0) b.className = 'on';
      b.onclick = function () {
        b.classList.toggle('on');
        inp.value = days.filter(function (x, i) { return wrap.children[i].classList.contains('on'); }).map(function (x) { return x[0]; }).join(',');
        try { inp.dispatchEvent(new Event('input', { bubbles: true })); } catch (e) {}
      };
      wrap.appendChild(b);
    });
    inp.style.display = 'none';
    ctl.appendChild(wrap); ctl.appendChild(inp);
    return;
  }
  if (/시작$|끝$/.test(key) && /근무|야간/.test(key)) {
    inp.type = 'time'; inp.style.minHeight = '44px';
    ctl.appendChild(inp);
    return;
  }
  if (key === '이동기준') {
    if (inp.tagName !== 'SELECT') {
      var sel = document.createElement('select'); sel.className = 'f'; sel.setAttribute('data-k', key);
      ['일령', '이유후일수'].forEach(function (o) { var op = document.createElement('option'); op.value = o; op.textContent = o; if (o === inp.value) op.selected = true; sel.appendChild(op); });
      inp.parentNode && inp.parentNode.replaceChild(sel, inp);
      ctl.appendChild(sel);
    } else ctl.appendChild(inp);
    return;
  }
  if (inp.tagName === 'SELECT' && /예|아니오/.test(Array.prototype.map.call(inp.options, function (o) { return o.value; }).join(' ')) || key === '테스트농장') {
    var lab = document.createElement('label'); lab.className = 'n7-tog';
    var chk = document.createElement('input'); chk.type = 'checkbox';
    var on = inp.tagName === 'SELECT' ? inp.value === '예' : (inp.value === '예');
    chk.checked = on;
    var hid = inp;
    if (inp.tagName === 'SELECT') {
      /* keep select hidden to preserve save path that reads select */
      inp.style.display = 'none';
    } else {
      inp.type = 'hidden';
    }
    chk.onchange = function () {
      var v = chk.checked ? '예' : '아니오';
      hid.value = v;
      try { hid.dispatchEvent(new Event('input', { bubbles: true })); hid.dispatchEvent(new Event('change', { bubbles: true })); } catch (e) {}
    };
    lab.appendChild(chk); lab.appendChild(document.createTextNode(chk.checked ? '켜짐' : '꺼짐'));
    chk.addEventListener('change', function () { lab.lastChild.textContent = chk.checked ? '켜짐' : '꺼짐'; });
    ctl.appendChild(lab); ctl.appendChild(hid);
    return;
  }
  if (/약품_분류_목록|격리순치_단계|당직_점검/.test(key)) {
    n7ChipList_(ctl, inp);
    return;
  }
  if (inp.getAttribute && inp.getAttribute('data-num') === '1' || (inp.type === 'number' && key)) {
    var wrap = document.createElement('div'); wrap.className = 'n7-stepn';
    var step = /일령/.test(key) ? 10 : 1;
    var m = document.createElement('button'); m.type = 'button'; m.className = 'btn sec'; m.textContent = step === 10 ? '−10' : '−';
    var p = document.createElement('button'); p.type = 'button'; p.className = 'btn sec'; p.textContent = step === 10 ? '+10' : '+';
    function bump(d) {
      var v = Number(inp.value); if (isNaN(v)) v = 0;
      var nv = v + d; if (nv < 0) nv = 0; inp.value = String(nv);
      try { inp.dispatchEvent(new Event('input', { bubbles: true })); } catch (e) {}
    }
    m.onclick = function () { bump(-step); };
    p.onclick = function () { bump(step); };
    wrap.appendChild(m); wrap.appendChild(inp); wrap.appendChild(p);
    ctl.appendChild(wrap);
    return;
  }
  ctl.appendChild(inp);
}
function n7ChipList_(ctl, inp) {
  var wrap = document.createElement('div'); wrap.className = 'n7-chiplist';
  function items() { return String(inp.value || '').split(/[;\n]+/).map(function (s) { return s.trim(); }).filter(Boolean); }
  function write(arr) { inp.value = arr.join(';'); try { inp.dispatchEvent(new Event('input', { bubbles: true })); } catch (e) {} paint(); }
  function paint() {
    wrap.innerHTML = '';
    items().forEach(function (s, i) {
      var c = document.createElement('span'); c.className = 'n7-chip';
      c.appendChild(document.createTextNode(s));
      var x = document.createElement('button'); x.type = 'button'; x.setAttribute('aria-label', '지우기'); x.textContent = '×';
      x.onclick = function () { var a = items(); a.splice(i, 1); write(a); };
      c.appendChild(x); wrap.appendChild(c);
    });
    var add = document.createElement('input'); add.className = 'f'; add.placeholder = '추가 후 Enter'; add.style.minHeight = '36px'; add.style.maxWidth = '140px';
    add.onchange = add.onkeydown = function (e) {
      if (e.type === 'keydown' && e.key !== 'Enter') return;
      var v = add.value.trim(); if (!v) return;
      var a = items(); if (a.indexOf(v) < 0) a.push(v); write(a);
    };
    wrap.appendChild(add);
  }
  inp.style.display = 'none';
  ctl.appendChild(wrap); ctl.appendChild(inp);
  paint();
}

function n7BrnCard_(root) {
  if (!root || root.querySelector('#n7-brn') || typeof apiF !== 'function') return;
  if (!root.querySelector('#st-go')) return;
  var card = document.createElement('div');
  card.id = 'n7-brn'; card.className = 'card n7-brn';
  card.innerHTML = '<h3>사업자등록번호</h3><div class="mut">불러오는 중…</div>';
  var box = root.querySelector('.card') || root;
  box.parentNode ? box.parentNode.insertBefore(card, box) : root.insertBefore(card, root.firstChild);
  var get = (typeof apiR === 'function' ? apiR : apiF);
  get('getFarmBrn').then(function (r) {
    var brn = (r && r.brn) || '';
    var ph = !r || r.placeholder;
    card.innerHTML = '<h3>사업자등록번호</h3>' +
      '<label class="l">사업자등록번호</label><input id="n7-brn-in" class="f" inputmode="numeric" maxlength="12" placeholder="000-00-00000" value="' + n7Esc2_(ph ? '' : brn) + '">' +
      '<div id="n7-brn-msg" class="mut"></div>' +
      (typeof isOwner === 'function' && !isOwner() ? '' : '<button type="button" class="btn" id="n7-brn-go" style="margin-top:8px">사업자번호 저장</button>');
    var inp = card.querySelector('#n7-brn-in');
    if (inp && typeof brnFmt === 'function') inp.addEventListener('input', function () { inp.value = brnFmt(inp.value); });
    var go = card.querySelector('#n7-brn-go');
    if (go) go.onclick = function () {
      var v = inp.value.trim(); var msg = card.querySelector('#n7-brn-msg');
      go.disabled = true;
      get('updateFarmBrn', v).then(function (z) {
        go.disabled = false;
        msg.textContent = z && z.placeholder ? '임시 번호로 저장했습니다.' : '저장했습니다: ' + (z && z.brn || v);
        var hint = card.querySelector('.n7-brn-hint');
        if (hint && z && !z.placeholder) hint.remove();
      }, function (e) {
        go.disabled = false;
        msg.innerHTML = (typeof errHTML === 'function') ? errHTML(e) : n7Esc2_(String(e && e.message || e));
      });
    };
  }, function () { card.querySelector('.mut').textContent = '사업자번호를 불러오지 못했습니다.'; });
}

function n7StaffCards_(root) {
  if (!root || !root.querySelectorAll) root = document.getElementById('m-main') || document.getElementById('app') || document.body;
  if (!root) return;
  var tables = root.querySelectorAll('#st-staff table.t, #org-staff table.t, table.t');
  [].forEach.call(tables, function (tbl) {
    if (tbl.getAttribute('data-n7sc')) return;
    if (!tbl.rows || tbl.rows.length < 2) return;
    if (!/아이디|직급|입사|로그인/.test(tbl.rows[0].textContent || '')) return;
    tbl.setAttribute('data-n7sc', '1');
    var heads = [].map.call(tbl.rows[0].cells, function (c) { return (c.textContent || '').trim(); });
    var host = document.createElement('div');
    host.className = 'n7-staff-cards';
    function take(src, dest) {
      if (!src) return;
      var c = src.cloneNode(true);
      dest.appendChild(c);
      var a = src.querySelectorAll('*');
      var b = c.querySelectorAll('*');
      if (src.onclick && !c.onclick) c.onclick = src.onclick;
      if (src.onchange && !c.onchange) c.onchange = src.onchange;
      for (var i = 0; i < a.length && i < b.length; i++) {
        if (a[i].onclick) b[i].onclick = a[i].onclick;
        if (a[i].onchange) b[i].onchange = a[i].onchange;
      }
    }
    for (var r = 1; r < tbl.rows.length; r++) {
      var tr = tbl.rows[r];
      if (!tr.cells || !tr.cells.length) continue;
      var card = document.createElement('div');
      card.className = 'n7-scard';
      var name = tr.cells[1] ? (tr.cells[1].textContent || '').trim() : '';
      var loginHtml = tr.cells[0] ? tr.cells[0].innerHTML : '';
      card.innerHTML = '<div class="n7-sc-top"><div><b></b><div class="mut n7-sc-id"></div></div><div class="n7-sc-act"></div></div><div class="n7-sc-mid"></div>';
      card.querySelector('b').textContent = name;
      card.querySelector('.n7-sc-id').innerHTML = loginHtml;
      var midEl = card.querySelector('.n7-sc-mid');
      var lastIdx = tr.cells.length - 1;
      for (var c = 2; c < lastIdx; c++) {
        var line = document.createElement('div');
        line.className = 'n7-sc-line';
        var lab = document.createElement('span');
        lab.className = 'mut';
        lab.textContent = heads[c] || '';
        line.appendChild(lab);
        take(tr.cells[c], line);
        midEl.appendChild(line);
      }
      take(tr.cells[lastIdx], card.querySelector('.n7-sc-act'));
      host.appendChild(card);
    }
    var wrap = tbl.parentNode;
    wrap.insertBefore(host, tbl);
    tbl.classList.add('n7-hide-m');
  });
  [].forEach.call(root.querySelectorAll('.card'), function (c) {
    if (c && /담당 수의사|수의사/.test(c.textContent || '')) c.classList.add('n7-vetfix');
  });
}
function n7StaffWatch_() {
  if (n7StaffWatch_._on) return;
  n7StaffWatch_._on = 1;
  var t = null;
  var run = function () {
    var host = document.getElementById('m-main') || document.getElementById('app') || document.body;
    if (typeof n7StaffCards_ === 'function') n7StaffCards_(host);
    if (typeof staffCard === 'function' && !staffCard._n7s && typeof n7HookPages_ === 'function') {
      /* wrap if lazy chunk just arrived */
      try { n7HookPages_(); } catch (e) {}
    }
  };
  var obs = new MutationObserver(function () {
    if (t) clearTimeout(t);
    t = setTimeout(run, 80);
  });
  try { obs.observe(document.body, { childList: true, subtree: true }); } catch (e2) {}
  setTimeout(run, 0);
  setTimeout(run, 400);
  setTimeout(run, 1200);
  setTimeout(run, 2500);
}


function n7SignupHint_() { /* t452: 0000000000 안내문은 보이지 않음. 10자리 0 가입은 그대로 */ }

function n7HistHome_() {
  if (PL && PL.view === 'field') return 'home';
  return 'home';
}
function n7HistSeed_() {
  if (!window.PL || !PL.user) return;
  try {
    if (!history.state || history.state.pl !== 'in') history.replaceState({ pl: 'in', p: PL._page || n7HistHome_(), root: 1 }, '', location.href);
    if (!n7HistInstall_._seeded) {
      history.pushState({ pl: 'in', p: PL._page || n7HistHome_(), root: 1 }, '', location.href);
      n7HistInstall_._seeded = 1;
    }
  } catch (e) {}
}
function n7HistInstall_() {
  if (!window.PL || typeof PL.go !== 'function') {
    if (typeof n7FieldHist_ === 'function') n7FieldHist_();
    return;
  }
  n7HistSeed_();
  if (n7HistInstall_._wrapped) return;
  n7HistInstall_._wrapped = 1;
  n7HistInstall_._on = 1;
  var _go = PL.go;
  PL.go = function (p, arg) {
    var r = _go.apply(this, arguments);
    if (!n7HistInstall_._quiet && PL.user && !n7HistInstall_._skip) {
      try { history.pushState({ pl: 'in', p: p, arg: arg }, ''); } catch (e2) {}
    }
    return r;
  };
  window.addEventListener('popstate', function (e) {
    if (document.getElementById('pai-root')) {
      n7AiClose_(true);
      return;
    }
    if (!PL.user) return;
    var st = e.state;
    if (!st || st.pl !== 'in' || st.root) {
      try { history.pushState({ pl: 'in', p: n7HistHome_(), root: 1 }, '', location.href); } catch (e3) {}
      if (PL._page && PL._page !== n7HistHome_()) {
        n7HistInstall_._quiet = 1;
        try { _go.call(PL, n7HistHome_()); } catch (e4) { try { PL.go(n7HistHome_()); } catch (e5) {} }
        n7HistInstall_._quiet = 0;
      }
      return;
    }
    n7HistInstall_._quiet = 1;
    try { _go.call(PL, st.p, st.arg); } catch (e6) { try { PL.go(st.p, st.arg); } catch (e7) {} }
    n7HistInstall_._quiet = 0;
  });
  function wrapOut(fnName) {
    var fn = window[fnName];
    if (typeof fn !== 'function' || fn._n7h) return;
    window[fnName] = function () {
      n7HistInstall_._seeded = 0;
      try { history.replaceState({ pl: 'out' }, ''); } catch (e) {}
      return fn.apply(this, arguments);
    };
    window[fnName]._n7h = 1;
  }
  wrapOut('logout'); wrapOut('mLogout'); wrapOut('doLogout');
  if (PL.logout && !PL.logout._n7h) {
    var lo = PL.logout;
    PL.logout = function () { try { history.replaceState({ pl: 'out' }, ''); } catch (e) {} return lo.apply(this, arguments); };
    PL.logout._n7h = 1;
  }
}

function n7SowSearchNick_() {
  /* list_sows already matches nickname; show it next to the tag in the list when missing */
  var root = document.getElementById('m-main') || document.getElementById('app');
  if (!root) return;
  [].forEach.call(root.querySelectorAll('[data-tag], .sow, .sw-row, tr'), function (row) {
    /* light touch: if a sow row has nickname in data-nick, ensure it is visible */
  });
}


function n7WeekText_(iso) {
  iso = String(iso || (typeof window.today === 'function' ? window.today() : ((window.PL && PL._daily && PL._daily.today) || ''))).slice(0, 10);
  if (typeof farmWeekTitle_ === 'function') {
    var s = farmWeekTitle_(iso);
    if (s) return s;
  }
  if (typeof farmWeek_ === 'function') {
    var w = farmWeek_(iso);
    if (w) return w.year + '년 ' + w.week + '주차 · ' + w.fromMd + '~' + w.toMd;
  }
  return iso;
}
function n7WeekLabels_(root) {
  if (!root || !root.querySelectorAll) return;
  [].forEach.call(root.querySelectorAll('[data-n7week], .n7-week, #cal-wk, .farm-week'), function (el) {
    if (el.getAttribute('data-n7wl')) return;
    var iso = el.getAttribute('data-n7week') || (typeof window.today === 'function' ? window.today() : ((window.PL && PL._daily && PL._daily.today) || ''));
    var lab = n7WeekText_(iso);
    if (lab) { el.textContent = lab; el.setAttribute('data-n7wl', '1'); }
  });
}
function n7VaccEasy_(it) {
  var p = String((it && (it.prog || it.program || it.basis || '')) || '');
  var v = String((it && it.vaccine) || '');
  var d = Number(it && (it.days != null ? it.days : it.progDays));
  var blob = p + ' ' + v;
  if ((isFinite(d) && d === 7) || (/1주|7일/.test(blob) && /분만/.test(blob))) return '분만 1주 전';
  if ((isFinite(d) && d === 14) || (/2주|14일/.test(blob) && /분만/.test(blob))) return '분만 2주 전';
  if (/분만전|분만 전/.test(blob) || (it && it.basis === '분만전')) return (isFinite(d) && d === 7) ? '분만 1주 전' : '분만 전 주사';
  if (/후보/.test(blob)) return '후보돈';
  if (/이유/.test(blob)) return '이유 후';
  if (/교배/.test(blob)) return '교배 후';
  if (/자돈/.test(blob)) return '자돈';
  return p || v || '백신';
}
function n7VaccSkip_(it, sow) {
  var st = sow ? String(sow.stateLabel || sow.state || '') : '';
  var d = String((it && (it.date || it.due || it._d)) || '').slice(0, 10);
  var td = (typeof window.today === 'function' ? window.today() : ((window.PL && PL._daily && PL._daily.today) || ''));
  if (/재발/.test(st)) return '재발';
  if (/공태|유산|불임/.test(st)) return st.replace(/\s+/g, ' ').trim() || '임신 아님';
  var pre = /분만전|분만 전|분만 1주/.test(String((it && (it.prog || it.basis)) || '') + n7VaccEasy_(it));
  if (pre && d && td && d >= td) return '';
  if (/포유|이유/.test(st) && pre) return '이미 분만';
  if (sow && /분만/.test(String(sow.lastType || '')) && pre) return '이미 분만';
  return '';
}
function n7EntryTyp_() {
  var btn = document.querySelector('#en-t button.on, #en-t [data-t].on');
  if (btn && btn.getAttribute('data-t')) return btn.getAttribute('data-t');
  return (window.PL && PL._entType) || '';
}
function n7VaccWatch_(host, typHint) {
  if (!document._n7vwBound) {
    document._n7vwBound = 1;
    document.addEventListener('click', function (e) {
      var b = e.target && e.target.closest && e.target.closest('#en-t button, #en-t [data-t]');
      if (!b) return;
      var t = b.getAttribute('data-t');
      if (t && window.PL) PL._entType = t;
      setTimeout(function () { n7VaccWeekMount_(host || document.getElementById('w-main') || document.getElementById('m-main') || document.body, (window.PL && PL._page) || 'entry'); }, 0);
    }, true);
  }
  n7VaccWeekMount_(host, typHint || (window.PL && PL._page) || 'entry');
}
function n7VaccWeekMount_(host, page) {
  var typHint = page || '';
  page = (window.PL && PL._page) || typHint || '';
  var typ = n7EntryTyp_();
  if (!typ && typHint && typHint !== 'entry' && typHint !== 'vweek' && typHint !== 'vacc') typ = typHint;
  if (typHint === '백신') typ = typ || '백신';
  var onVweek = typHint === 'vweek' || typHint === 'vacc' || page === 'vweek' || page === 'vacc';
  var want = onVweek || typ === '백신';
  var old = document.getElementById('n7-vaccweek');
  if (!want) {
    if (old && old.parentNode) old.parentNode.removeChild(old);
    return;
  }
  if (old && old.getAttribute('data-ready') === '1' && old.getAttribute('data-pg') === (onVweek ? 'vweek' : 'entry백신')) return;
  if (old && old.parentNode) old.parentNode.removeChild(old);
  var box = document.createElement('details');
  box.id = 'n7-vaccweek';
  box.className = 'n7-vw';
  box.open = true;
  box.setAttribute('data-pg', onVweek ? 'vweek' : 'entry백신');
  box.innerHTML = '<summary class="n7-vw-sum">이번 주 주사할 모돈</summary><div class="n7-vw-sub">' + n7Esc2_(n7WeekText_()) + '</div><div class="n7-vw-body n7-vw-empty">불러오는 중…</div>';
  var mountHost = host && host.appendChild ? host : (document.getElementById('w-main') || document.getElementById('m-main') || document.body);
  if (onVweek) {
    mountHost.insertBefore(box, mountHost.firstChild);
  } else {
    var form = document.querySelector('#w-main #en-f, #m-main #en-f, #w-main .entry, #m-main .entry, #en-f, .entry');
    if (form && form.parentNode) form.parentNode.insertBefore(box, form.nextSibling);
    else {
      var bar = document.querySelector('#en-t');
      if (bar && bar.parentNode) {
        var nxt = bar.nextSibling;
        while (nxt && nxt.nodeType !== 1) nxt = nxt.nextSibling;
        bar.parentNode.insertBefore(box, nxt ? nxt.nextSibling : null);
      } else mountHost.appendChild(box);
    }
  }
  n7VaccWeekLoad_(box);
}
function n7VaccWeekLoad_(box) {
  if (typeof apiF !== 'function') { box.querySelector('.n7-vw-body').textContent = '백신 예정 기능을 불러올 수 없습니다.'; return; }
  var todayStr = (typeof window.today === 'function' ? window.today() : ((window.PL && PL._daily && PL._daily.today) || ''));
  var wk = (typeof farmWeek_ === 'function') ? farmWeek_(todayStr) : null;
  var from = wk ? wk.from : todayStr, to = wk ? wk.to : todayStr;
  Promise.all([
    apiF('getVaccDue'),
    apiF('listSows', { includeExited: false }).catch(function () { return { rows: [] }; }),
    apiF('listVaccPrograms').catch(function () { return { rows: [] }; })
  ]).then(function (arr) {
    var due = (arr[0] && (arr[0].due || arr[0].rows || arr[0].items)) || [];
    var sows = ((arr[1] && (arr[1].rows || arr[1].items || arr[1].sows)) || []);
    var progs = ((arr[2] && (arr[2].rows || arr[2].items || arr[2].programs)) || (Array.isArray(arr[2]) ? arr[2] : [])) || [];
    var byProg = {};
    progs.forEach(function (pg) { if (pg && (pg.id || pg.progId)) byProg[String(pg.id || pg.progId)] = pg; });
    var byTag = {};
    sows.forEach(function (s) { byTag[String(s.tag || s['모돈번호'] || '')] = s; });
    var days = ['토','일','월','화','수','목','금'];
    function dow(iso) {
      var p = String(iso || '').split('-');
      if (p.length < 3) return 0;
      var d = new Date(+p[0], +p[1]-1, +p[2]).getDay();
      return (d + 1) % 7;
    }
    var week = [], next = [], miss = [], skip = [];
    var nextTo = (typeof addDays === 'function' && to) ? addDays(to, 7) : to;
    due.forEach(function (it) {
      var d = String(it.date || it.due || '').slice(0, 10);
      var sow = byTag[String(it.tag || '')];
      var pg = byProg[String(it.progId || '')] || {};
      if (it.days == null && pg.days != null) it.days = pg.days;
      if (!it.basis && pg.basis) it.basis = pg.basis;
      var why = n7VaccSkip_(it, sow);
      it._d = d; it._why = why; it._sow = sow;
      if (why) skip.push(it);
      else if (from && d && d < from) miss.push(it);
      else if (!to || !d || (d >= from && d <= to)) week.push(it);
      else if (nextTo && d && d > to && d <= nextTo) next.push(it);
    });
    function rowsHTML(list, canCheck) {
      return list.map(function (it) {
        var easy = n7VaccEasy_(it);
        var loc = it.loc ? ' · ' + it.loc : '';
        var vac = it.vaccine ? ' · ' + it.vaccine : '';
        var why = it._why ? '<div class="why">' + n7Esc2_(it._why) + '</div>' : '';
        var chk = canCheck ? '<input type="checkbox" data-tag="' + n7Esc2_(it.tag) + '" data-vac="' + n7Esc2_(it.vaccine || '') + '" data-prog="' + n7Esc2_(it.progId || it.prog || '') + '" data-date="' + n7Esc2_(it._d) + '" aria-label="주사 완료">' : '';
        return '<div class="n7-vw-row' + (it._why ? ' skip' : '') + '"><label>' + chk + '<div class="bd"><b>' + n7Esc2_((typeof sowLbl_==='function' ? sowLbl_(it._sow || it) : it.tag)) + '</b><div class="mt">' + n7Esc2_(easy + vac + loc) + (it._d ? ' · ' + n7Esc2_(it._d) : '') + '</div>' + why + '</div></label></div>';
      }).join('');
    }
    var html = '';
    if (!week.length && !next.length && !miss.length) html += '<div class="n7-vw-empty">이번 주 대상이 없습니다</div>';
    var groups = {};
    week.forEach(function (it) {
      var k = dow(it._d);
      (groups[k] = groups[k] || []).push(it);
    });
    [0,1,2,3,4,5,6].forEach(function (k) {
      if (!groups[k] || !groups[k].length) return;
      var d0 = groups[k][0]._d;
      html += '<div class="n7-vw-day"><h4>' + days[k] + '요일' + (d0 ? ' · ' + d0 : '') + ' · ' + groups[k].length + '두</h4>' + rowsHTML(groups[k], true) + '</div>';
    });
    if (next.length) {
      var nlab = (typeof farmWeekTitle_ === 'function' && next[0]._d) ? farmWeekTitle_(next[0]._d) : '다음 주';
      html += '<div class="n7-vw-day"><h4>다음 주 · ' + n7Esc2_(nlab) + ' · ' + next.length + '두</h4>' + rowsHTML(next, true) + '</div>';
    }
    if (miss.length) html += '<div class="n7-vw-day n7-vw-miss"><h4>놓친 접종 ' + miss.length + '두</h4>' + rowsHTML(miss, true) + '</div>';
    if (skip.length) html += '<div class="n7-vw-day"><h4>이미 분만·재발 등으로 제외 ' + skip.length + '두</h4>' + rowsHTML(skip, false) + '</div>';
    var body = box.querySelector('.n7-vw-body');
    body.className = 'n7-vw-body';
    var bar = (week.length || next.length || miss.length) ? '<div class="n7-vw-bar"><label><input type="checkbox" id="n7-vw-all"> 전체</label> <button type="button" class="btn sm" id="n7-vw-go">일괄 접종확인</button><span class="mut" id="n7-vw-sum"></span></div>' : '';
    body.innerHTML = bar + html;
    box.setAttribute('data-ready', '1');
    function boxes() { return [].filter.call(body.querySelectorAll('.n7-vw-row input[type="checkbox"]'), function (x) { return !x.disabled; }); }
    function markDone(inp) { inp.disabled = true; inp.checked = true; var row = inp.closest('.n7-vw-row'); if (row) row.style.opacity = '0.55'; }
    function markOpen(inp, key) {
      if (inp) { inp.disabled = false; inp.checked = false; var row = inp.closest('.n7-vw-row'); if (row) row.style.opacity = ''; }
      if (key && box._n7saved) delete box._n7saved[key];
    }
    function saveOne(inp) {
      if (!inp || inp.disabled) return Promise.resolve('skip');
      var tag = inp.getAttribute('data-tag') || '', key = 'n7vw-' + tag + '-' + (inp.getAttribute('data-date') || todayStr) + '-' + (inp.getAttribute('data-vac') || '');
      if (box._n7saved && box._n7saved[key]) { markDone(inp); return Promise.resolve('skip'); }
      inp.disabled = true;
      var due = inp.getAttribute('data-date') || todayStr;
      var date = (due > todayStr) ? todayStr : due;
      var ev = { targetKind: '개체', tags: tag, date: date, vaccine: inp.getAttribute('data-vac') || '', programId: inp.getAttribute('data-prog') || '', reqId: key + '-' + Date.now() };
      return apiF('saveVaccination', ev).then(function (r) {
        box._n7saved = box._n7saved || {}; box._n7saved[key] = 1; markDone(inp);
        var vid = r && r.row && (r.row['접종ID'] || r.row.id);
        return { ok: 'ok', id: vid, tag: tag, inp: inp, key: key };
      }, function (err) {
        markOpen(inp, key); return err;
      });
    }
    [].forEach.call(body.querySelectorAll('.n7-vw-row input[type="checkbox"]'), function (inp) {
      inp.onchange = function () { if (all) all.checked = boxes().length && boxes().every(function (x) { return x.checked; }); };
    });
    var all = body.querySelector('#n7-vw-all');
    if (all) all.onchange = function () { boxes().forEach(function (x) { x.checked = all.checked; }); };
    var go = body.querySelector('#n7-vw-go'), sum = body.querySelector('#n7-vw-sum');
    if (go) go.onclick = function () {
      var sel = boxes().filter(function (x) { return x.checked && !x.disabled; });
      if (!sel.length) { if (typeof toast === 'function') toast('대상을 고르세요'); return; }
      var future = sel.filter(function (x) { return (x.getAttribute('data-date') || '') > todayStr; });
      if (future.length && typeof confirm === 'function' && !confirm('오늘 접종으로 기록할까요? (예정일보다 앞선 대상 ' + future.length + '두)')) return;
      if (go.getAttribute('data-busy')) return;
      go.setAttribute('data-busy', '1'); go.disabled = true;
      var ok = 0, fail = 0, skip = 0, i = 0;
      var next = function () {
        if (i >= sel.length) {
          go.removeAttribute('data-busy'); go.disabled = false;
          if (sum) sum.textContent = (ok ? ok + '두 기록' : '') + (fail ? (ok ? ' · ' : '') + fail + '두 실패' : '') + (skip && !ok && !fail ? '' : '');
          if (typeof toast === 'function') toast((ok ? ok + '두 접종 확인' : '기록된 항목 없음') + (fail ? ' · ' + fail + '두 실패' : ''));
          if (ok && savedIds.length) {
            (function (ids) {
              var btn = document.createElement('button');
              btn.type = 'button'; btn.className = 'btn sm sec n7-vw-undo'; btn.textContent = '되돌리기';
              btn.style.marginLeft = '8px';
              btn.onclick = function () {
                if (btn.disabled) return; btn.disabled = true;
                var j = 0, nOk = 0;
                var run = function () {
                  if (j >= ids.length) {
                    if (typeof toast === 'function') toast(nOk ? nOk + '두 되돌림' : '되돌리지 못했습니다');
                    if (btn.parentNode) btn.parentNode.removeChild(btn);
                    return;
                  }
                  var it = ids[j++];
                  var vid = (it && typeof it === 'object') ? it.id : it;
                  apiF('cancelVaccination', vid, '되돌리기', '').then(function () {
                    if (it && typeof it === 'object') markOpen(it.inp, it.key);
                    nOk++; run();
                  }, function () { run(); });
                };
                run();
              };
              if (go && go.parentNode) go.parentNode.appendChild(btn);
              setTimeout(function () { if (btn.parentNode) btn.parentNode.removeChild(btn); }, 5000);
            })(savedIds.slice());
          }
          return;
        }
        saveOne(sel[i++]).then(function (r) {
          if (r && r.ok === 'ok') { ok++; if (r.id) savedIds.push(r); }
          else if (r === 'ok') ok++;
          else if (r === 'skip') skip++;
          else fail++;
          next();
        });
      };
      var savedIds = [];
      next();
    };
  }).catch(function (e) {
    var body = box.querySelector('.n7-vw-body');
    if (!body) return;
    body.className = 'n7-vw-body';
    var msg = '불러오지 못했어요.';
    body.innerHTML = (typeof errHTML === 'function' ? errHTML({ message: msg, read: 1 }, 1) : ('<div class="err">' + msg + ' <button type="button" class="btn sec" data-retry>다시 시도</button></div>'));
    if (typeof bindRetry_ === 'function') bindRetry_(body, function () { n7VaccWeekLoad_(box); });
    else { var b = body.querySelector('[data-retry]'); if (b) b.onclick = function () { n7VaccWeekLoad_(box); }; }
  });
}



var N7_CERTS = [
  { k: 'HACCP', l: 'HACCP' },
  { k: 'AB', l: '무항생제' },
  { k: 'WELFARE', l: '동물복지' },
  { k: 'CLEAN', l: '깨끗한 축산' },
  { k: 'LOWCARBON', l: '저탄소' },
  { k: 'BIOSEC', l: '방역우수' }
];
function n7FarmCerts_() {
  var c = (window.PL && PL.boot && PL.boot.cfg) || {};
  var raw = String(c['농장인증'] || '').trim();
  if (!raw || raw === '미적용' || raw === 'NONE') return [];
  return raw.split(/[,;]+/).map(function (x) { return x.trim(); }).filter(Boolean);
}
function n7HasCert_(k) { return n7FarmCerts_().indexOf(k) >= 0; }
function n7CertCard_(root) {
  if (!root) return;
  if (root.querySelector('#n7-cert-card')) return;
  var lrn = root.querySelector('#st-lrn') || root.querySelector('#st-ft') || root.querySelector('#st-go') || root.querySelector('#st-logo');
  if (!lrn) return;
  var can = !root.querySelector('#st-ro');
  var box = document.createElement('div');
  box.className = 'card n7-cert-card';
  box.id = 'n7-cert-card';
  lrn.parentNode.insertBefore(box, lrn.nextSibling);
  var cur = n7FarmCerts_();
  var ops = '<label class="n7-cert-ck' + (cur.length ? '' : ' on') + '"><input type="checkbox" data-c="NONE"' + (cur.length ? '' : ' checked') + '> 미적용</label>' +
    N7_CERTS.map(function (c) {
      var on = cur.indexOf(c.k) >= 0;
      return '<label class="n7-cert-ck' + (on ? ' on' : '') + '"><input type="checkbox" data-c="' + c.k + '"' + (on ? ' checked' : '') + '> ' + c.l + '</label>';
    }).join('');
  box.innerHTML = '<h3>농장 인증</h3><div class="mut">고른 인증의 서류만 메뉴에 보여요.</div><div class="n7-cert-ops">' + ops + '</div>' +
    (can ? '<button type="button" class="btn" id="n7-cert-save">인증 설정 저장</button><span class="mut" id="n7-cert-msg"></span>' : '');
  function syncNone() {
    var none = box.querySelector('[data-c="NONE"]');
    var others = [].slice.call(box.querySelectorAll('[data-c]:not([data-c="NONE"])'));
    var any = others.some(function (x) { return x.checked; });
    if (none) { none.checked = !any; none.parentNode.classList.toggle('on', !any); }
    others.forEach(function (x) { x.parentNode.classList.toggle('on', x.checked); });
  }
  box.addEventListener('change', function (e) {
    var t = e.target;
    if (!t || !t.getAttribute('data-c')) return;
    if (t.getAttribute('data-c') === 'NONE' && t.checked) {
      [].slice.call(box.querySelectorAll('[data-c]:not([data-c="NONE"])')).forEach(function (x) { x.checked = false; });
    }
    syncNone();
  });
  var go = box.querySelector('#n7-cert-save');
  if (go) go.onclick = function () {
    var v = [].slice.call(box.querySelectorAll('[data-c]:not([data-c="NONE"])')).filter(function (x) { return x.checked; }).map(function (x) { return x.getAttribute('data-c'); }).join(',');
    go.disabled = true;
    apiF('updateSettings', { '농장인증': v }).then(function () {
      if (PL.boot) { PL.boot.cfg = PL.boot.cfg || {}; PL.boot.cfg['농장인증'] = v; }
      var m = box.querySelector('#n7-cert-msg'); if (m) m.textContent = '저장했습니다';
      if (typeof toast === 'function') toast('저장했습니다');
      if (typeof renderMenu === 'function') try { renderMenu(); } catch (e1) {}
      if (typeof drawMenu === 'function') try { drawMenu(); } catch (e2) {}
      n7MenuFilter_(true);
    }).catch(function (e) {
      if (typeof toast === 'function') toast(typeof uiMsg === 'function' ? uiMsg(e) : String(e && e.message || e));
    }).then(function () { go.disabled = false; });
  };
}
function n7MenuFilter_(redraw) {
  if (typeof MENU !== 'undefined' && Array.isArray(MENU) && !MENU._n7cdocs) {
    var has = MENU.some(function (m) { return m[0] === 'cdocs'; });
    if (!has) MENU.push(['cdocs', '인증서류', '📄', 1]);
    if (typeof MENU_GROUPS !== 'undefined') {
      MENU_GROUPS.forEach(function (g) {
        if (g[0] === 'nav.gFarm' && g[1].indexOf('cdocs') < 0) g[1].splice(Math.max(0, g[1].indexOf('settings')), 0, 'cdocs');
      });
    }
    MENU._n7cdocs = 1;
  }
  if (typeof PAGES === 'object' && !PAGES.cdocs) PAGES.cdocs = function (el, a) { pageCertDocs(el, a); };
  if (typeof PAGES_W === 'object' && !PAGES_W.cdocs) PAGES_W.cdocs = function (el, a) { pageCertDocs(el, a); };
  if (typeof PAGES_M === 'object' && !PAGES_M.cdocs) PAGES_M.cdocs = function (el, a) { pageCertDocs(el, a); };
  if (typeof menuHTML === 'function' && !menuHTML._n7cert) {
    var _mh = menuHTML;
    menuHTML = function (items, cur) {
      var hideNeedle = !n7HasCert_('HACCP');
      var hasCert = n7FarmCerts_().length > 0;
      items = (items || []).filter(function (m) {
        if (hideNeedle && m[0] === 'needle') return false;
        if (!hasCert && m[0] === 'cdocs') return false;
        return true;
      });
      return _mh(items, cur);
    };
    menuHTML._n7cert = 1;
  }
}
function n7CdocFarm_() {
  var f = (window.PL && (PL.farm || (PL.boot && PL.boot.farm))) || {};
  return { name: f.name || f['농장명'] || (PL.boot && PL.boot.cfg && PL.boot.cfg['농장명']) || '', lrn: (PL.boot && PL.boot.cfg && PL.boot.cfg['축산업등록번호']) || '' };
}
function n7CdocForms_() {
  var c = n7FarmCerts_(), all = [];
  if (c.indexOf('HACCP') >= 0 || c.indexOf('AB') >= 0) {
    all.push({ id: 'disinfect', t: '소독실시 기록부' });
    all = all.concat([
      { id: 'visit', t: '출입관리부' },
      { id: 'buy', t: '구입돼지 관리기록부' },
      { id: 'daily', t: '농장일보' },
      { id: 'inject', t: '개체주사·약품사용기록부' },
      { id: 'needle', t: '주사침 분실서' },
      { id: 'drug', t: '약품관리기록부' },
      { id: 'dead', t: '돼지폐사 기록부' },
      { id: 'improve', t: '개선조치 기록부' },
      { id: 'ship', t: '출하기록부 (CCP)' }
    ]);
  }
  if (c.indexOf('CLEAN') >= 0) all.push({ id: 'manure', t: '가축분뇨·퇴액비 관리대장' });
  if (c.indexOf('WELFARE') >= 0) all.push({ id: 'welfare', t: '동물복지 운영 현황' });
  return all;
}
function n7CdocHead_(title, month) {
  var f = n7CdocFarm_();
  return '<div class="mut">' + n7Esc2_(f.name || '') + (f.lrn ? ' · ' + n7Esc2_(f.lrn) : '') + (month ? ' · ' + n7Esc2_(month) : '') + '</div><h2>' + n7Esc2_(title) + '</h2>';
}
function n7CdocTable_(cols, rows) {
  var th = '<tr>' + cols.map(function (c) { return '<th>' + n7Esc2_(c) + '</th>'; }).join('') + '</tr>';
  var body = (rows && rows.length ? rows : []).map(function (r) {
    return '<tr>' + cols.map(function (_, i) { return '<td>' + n7Esc2_(r[i] == null ? '' : r[i]) + '</td>'; }).join('') + '</tr>';
  }).join('');
  if (!(rows && rows.length)) body += Array(7).join('<tr>' + cols.map(function () { return '<td>&nbsp;</td>'; }).join('') + '</tr>');
  return '<table><thead>' + th + '</thead><tbody>' + body + '</tbody></table>';
}
function n7CdocSign_() {
  return '<div class="n7-cdoc-sign"><span>담당 ________</span><span>팀장 ________</span></div>';
}
function pageCertDocs(el) {
  var _ti = document.getElementById('w-title') || document.getElementById('m-title');
  if (_ti) _ti.textContent = '인증서류';
  if (!el) return;
  if (!n7FarmCerts_().length) {
    el.innerHTML = '<div class="card"><h3>인증서류</h3><p class="mut">농장 설정에서 인증을 고르면 서류가 열립니다. 인증을 쓰지 않는 농장에는 이 메뉴가 보이지 않습니다.</p></div>';
    return;
  }
  var forms = n7CdocForms_();
  var month = (typeof today === 'function' ? today() : new Date().toISOString().slice(0, 10)).slice(0, 7);
  el.classList.add('n7-cdoc');
  el.innerHTML = '<div class="card"><h3>인증서류</h3><div class="mut noprint">고른 인증의 기록양식입니다. 기존 약품·백신·치료 기록으로 채웁니다.</div>' +
    '<div class="row noprint" style="gap:8px;flex-wrap:wrap;margin-top:8px"><label>월 <input type="month" id="n7-cd-m" value="' + month + '"></label>' +
    '<button type="button" class="btn sec" id="n7-cd-print">인쇄</button></div>' +
    '<div class="n7-cdoc-tabs noprint" id="n7-cd-tabs"></div></div><div class="n7-cdoc-sheet" id="n7-cd-sheet"></div>';
  var tabs = el.querySelector('#n7-cd-tabs');
  tabs.innerHTML = forms.map(function (f, i) { return '<button type="button" class="' + (i ? 'btn sec' : 'btn') + '" data-f="' + f.id + '">' + f.t + '</button>'; }).join('');
  var cur = forms[0] && forms[0].id;
  function mark() {
    [].forEach.call(tabs.querySelectorAll('button'), function (b) {
      b.className = b.getAttribute('data-f') === cur ? 'btn' : 'btn sec';
    });
  }
  function paint(html) {
    var sh = el.querySelector('#n7-cd-sheet');
    var f = forms.filter(function (x) { return x.id === cur; })[0];
    var m = el.querySelector('#n7-cd-m').value || month;
    sh.innerHTML = n7CdocHead_((f && f.t) || '', m) + html + n7CdocSign_();
  }
  function empty(cols) { paint(n7CdocTable_(cols, [])); }
  function load() {
    mark();
    var m = el.querySelector('#n7-cd-m').value || month;
    var from = m + '-01';
    if (cur === 'disinfect') { empty(['날짜', '대상', '방법', '약품', '사용량', '실시자']); return; }
    if (cur === 'visit') { empty(['날짜', '성명', '소속', '방문목적', '72시간 방문지', '확인']); return; }
    if (cur === 'buy') { empty(['날짜', '모돈번호', '구입처', '두수', '비고']); return; }
    if (cur === 'manure') { empty(['날짜', '사육두수', '발생량', '처리량', '잔량', '비고']); return; }
    if (cur === 'welfare') { empty(['돈방', '면적(㎡)', '수용두수', '현재두수', '두당면적']); return; }
    if (cur === 'improve') { empty(['날짜', '사고내용', '원인', '개선내용', '재발방지']); return; }
    if (cur === 'needle') { empty(['날짜', '돈방', '잔류부위', '주사침', '사유', '출하처']); return; }
    if (cur === 'daily') { empty(['구분', '전일', '전입', '전출', '폐사', '금일']); return; }
    var job = null;
    if ((cur === 'inject' || cur === 'drug') && typeof apiF === 'function') job = apiF('getHaccpMonth', { doc: cur === 'inject' ? 'treat' : 'vacc', month: m });
    else if (cur === 'dead' && typeof apiF === 'function') job = apiF('listEvents', { type: 'exit', from: from, to: m + '-31' });
    else if (cur === 'ship' && typeof apiF === 'function') job = apiF('listShipments', { from: from, to: m + '-31' });
    if (!job) { empty(['날짜', '내용', '비고']); return; }
    job.then(function (r) {
      var list = (r && (r.rows || r.items || r.events)) || [];
      if (cur === 'inject') {
        var ab = n7HasCert_('AB');
        var cols = ['날짜', '대상', '제품', '두수', '용법', '휴약만료'].concat(ab ? ['무항생제 만료'] : []);
        var rows = list.map(function (o) {
          var wd = o.wdEnd || o.shipDate || o['출하가능일'] || '';
          var row = [o.date || o['날짜'] || '', o.target || o.tg || o['대상'] || '', o.drug || o.prod || o['제품'] || '', o.head || o.h || o['두수'] || '', o.use || o['용법'] || '', wd];
          if (ab) row.push(wd);
          return row;
        });
        paint(n7CdocTable_(cols, rows)); return;
      }
      if (cur === 'drug') {
        paint(n7CdocTable_(['날짜', '대상', '상태', '두수', '작업자'], list.map(function (o) {
          return [o.date || '', o.target || o.tg || '', o.state || o['상태'] || '', o.head || o.h || '', o.staff || o['작업자'] || ''];
        }))); return;
      }
      if (cur === 'dead') {
        paint(n7CdocTable_(['날짜', '모돈번호', '구분', '원인', '비고'], list.map(function (o) {
          return [o['작업일'] || o.date || '', o['모돈번호'] || o.tag || '', o['퇴출구분'] || o.kind || '', o['원인'] || o.cause || '', o['비고'] || o.memo || ''];
        }))); return;
      }
      if (cur === 'ship') {
        paint(n7CdocTable_(['날짜', '돈방', '두수', '출하처', '등급', '주사침·휴약 확인'], list.map(function (o) {
          return [o.date || o['작업일'] || '', o.pen || o.loc || o['위치'] || '', o.head || o['두수'] || '', o.dest || o['출하처'] || '', o.grade || o['등급'] || '', ''];
        }))); return;
      }
      empty(['날짜', '내용', '비고']);
    }).catch(function () { empty(['날짜', '내용', '비고']); });
  }
  tabs.addEventListener('click', function (e) {
    var b = e.target.closest && e.target.closest('button[data-f]'); if (!b) return;
    cur = b.getAttribute('data-f'); load();
  });
  el.querySelector('#n7-cd-m').onchange = load;
  el.querySelector('#n7-cd-print').onclick = function () { window.print(); };
  load();
}
function n7NextStall_(el) {
  if (!el) return;
  var ss = el.querySelector('.locpick [data-lv="s"]');
  if (!ss) return;
  var b = el.querySelector('.n7-nextstall');
  if (!b) {
    b = document.createElement('button');
    b.type = 'button'; b.className = 'btn sm n7-nextstall';
    ss.parentNode.appendChild(b);
    b.onclick = function () {
      var n = Number(ss.value || 0) + 1;
      if (ss.querySelector('option[value="' + n + '"]')) {
        ss.value = String(n);
        try { ss.dispatchEvent(new Event('change', { bubbles: true })); } catch (e) {}
      }
      lab();
    };
  }
  function lab() {
    var n = Number(ss.value || 0);
    var next = n + 1;
    var ok = n && ss.querySelector('option[value="' + next + '"]');
    b.textContent = ok ? ('다음 칸 ' + next) : '다음 칸';
    b.disabled = !ok;
    b.style.display = (ss.options && ss.options.length > 2) ? '' : 'none';
  }
  if (!ss._n7ns) { ss.addEventListener('change', lab); ss._n7ns = 1; }
  lab();
}
function n7CertBoot_() {
  n7MenuFilter_();
  var host = document.getElementById('m-main') || document.getElementById('app') || document.body;
  if (host) n7CertCard_(host);
}




function n7NormLocs_(boot) {
  var src = (boot && boot.locs) || (window.PL && PL.boot && PL.boot.locs);
  if (boot == null && window.PL) boot = PL.boot;
  if (!boot || !Array.isArray(boot.locs) || !boot.locs.length) return;
  boot.locs = boot.locs.map(function (x) {
    if (!x || typeof x !== 'object') return x;
    if (x.code && x.level) return x;
    var out = {};
    Object.keys(x).forEach(function (k) { out[k] = x[k]; });
    out.code = x.code || x['위치코드'] || '';
    out.parent = x.parent || x['상위코드'] || '';
    out.level = x.level || x['단계'] || x['구분'] || '';
    out.type = x.type || x['돈사종류'] || '';
    out.name = x.name || x['이름'] || '';
    out.stalls = (x.stalls != null ? x.stalls : x['스톨수']) || 0;
    out.cap = (x.cap != null ? x.cap : x['수용두수']) || 0;
    out.kind = x.kind || x['구분'] || out.level;
    var act = x.active != null ? x.active : x['활성'];
    out.active = !(act === false || act === 'N' || act === 'n');
    return out;
  }).filter(function (x) { return x && x.active !== false; });
}

function n7ClockLocHook_() {
  if (typeof clockCheck_ === 'function' && !clockCheck_._n7loc) {
    var _c = clockCheck_;
    clockCheck_ = function (b) {
      n7NormLocs_(b || (window.PL && PL.boot));
      return _c.apply(this, arguments);
    };
    clockCheck_._n7loc = 1;
  }
  n7NormLocs_(window.PL && PL.boot);
}
function n7NormLocsBoot_() {
  n7ClockLocHook_();

  n7NormLocs_(window.PL && PL.boot);
  if (typeof refreshLocs === 'function' && !refreshLocs._n7loc) {
    var _r = refreshLocs;
    refreshLocs = function () {
      var ret = _r.apply(this, arguments);
      var after = function () { n7NormLocs_(window.PL && PL.boot); };
      if (ret && typeof ret.then === 'function') return ret.then(function (v) { after(); return v; }, function (e) { after(); throw e; });
      after();
      return ret;
    };
    refreshLocs._n7loc = 1;
  }
}

function n7AccPrintBoot_() {
  if (n7AccPrintBoot_._on) return;
  n7AccPrintBoot_._on = 1;
  var openAll = function () {
    document.querySelectorAll('details.n7-acc').forEach(function (d) { d.setAttribute('data-was', d.open ? '1' : '0'); d.open = true; });
  };
  var restore = function () {
    document.querySelectorAll('details.n7-acc').forEach(function (d) { if (d.getAttribute('data-was') === '0') d.open = false; d.removeAttribute('data-was'); });
  };
  window.addEventListener('beforeprint', openAll);
  window.addEventListener('afterprint', restore);
}
function n7OffBandSoft_() {
  if (typeof offBand_ !== 'function' || offBand_._n7) return;
  var _b = offBand_;
  offBand_ = function () {
    _b.apply(this, arguments);
    var el = document.getElementById('pl-offband');
    if (!el) return;
    el.style.background = '#1b6b4a';
    el.style.color = '#fff';
    if (typeof offNow_ === 'function' && offNow_()) el.textContent = '인터넷이 약해요. 기록은 이 기기에 저장되고, 연결되면 자동으로 보내요.';
    else el.textContent = '연결을 다시 확인하는 중이에요. 기록은 이 기기에 남아 있어요.';
  };
  offBand_._n7 = 1;
}
function n7ObChip_() {
  var host = document.getElementById('n7-ui-sz');
  if (!host) host = document.querySelector('.mh') || document.querySelector('.shell .top');
  if (!host) return;
  var b = document.getElementById('pl-outbox');
  var idle = document.getElementById('n7-sync');
  if (b) {
    if (idle) idle.remove();
    b.classList.add('n7-obchip');
    if (b.parentNode !== host.parentNode || b.previousElementSibling !== host) {
      if (host.parentNode) host.parentNode.insertBefore(b, host.nextSibling);
    }
    return;
  }
  if (!idle) {
    idle = document.createElement('button');
    idle.id = 'n7-sync';
    idle.type = 'button';
    idle.className = 'n7-sync noprint';
    idle.title = '지금 보내기';
    idle.onclick = function () { if (typeof obFlush === 'function') obFlush(true); };
    if (host.parentNode) host.parentNode.insertBefore(idle, host.nextSibling);
  }
  var pending = 0;
  try { pending = (typeof obGet === 'function' && window.PL && PL.token) ? (obGet() || []).length : 0; } catch (e0) { pending = 0; }
  var offline = typeof offNow_ === 'function' && offNow_();
  if (!offline && pending === 0) { idle.style.display = 'none'; return; }
  idle.style.display = '';
  idle.textContent = offline ? (pending ? ('인터넷 없음 · ' + pending + '건 대기') : '인터넷 없음') : (pending + '건 대기');
}
function n7ObChipBoot_() {
  n7OffBandSoft_();
  if (typeof obBadge === 'function' && !obBadge._n7chip) {
    var _ob = obBadge;
    obBadge = function () { _ob.apply(this, arguments); n7ObChip_(); };
    obBadge._n7chip = 1;
  }
  n7ObChip_();
  if (typeof obBadge === 'function') { try { obBadge(); } catch (e) {} }
}
function n7SyncCard_(root) {
  if (!root || root.querySelector('#n7-sync-card')) return;
  var host = root.querySelector('#n7-cert-card') || root.querySelector('#st-lrn') || root.querySelector('.n7-st-find') || root.querySelector('#st-go');
  if (!host) return;
  var card = document.createElement('div');
  card.id = 'n7-sync-card';
  card.className = 'card n7-sync-card';
  var ls = typeof lastSyncText === 'function' ? lastSyncText() : '';
  var n = (typeof obGet === 'function' && PL.token) ? (obGet() || []).length : 0;
  card.innerHTML = '<h3>미전송 기록</h3><div class="mut">' + (n ? ('이 기기에 ' + n + '건이 있어, 연결되면 자동으로 보내요.') : '끊기면 기록은 이 기기에 저장되고, 연결되면 자동으로 보내요.') + (ls ? ' · ' + ls : '') + '</div><div class="row" style="margin-top:8px"><button type="button" class="btn sm" id="n7-sync-go">지금 보내기</button></div>';
  if (host.parentNode) host.parentNode.insertBefore(card, host.nextSibling);
  var go = card.querySelector('#n7-sync-go');
  if (go) go.onclick = function () { if (typeof obFlush === 'function') obFlush(true); if (typeof toast === 'function') toast(n ? '보내는 중' : '보낼 기록이 없습니다'); };
}

function n7MorePage_(el) {
  if (!el) return;
  try {
    if (typeof more === 'function') { more(el); if (el.querySelector('.more a[data-p], a[data-p]')) return; }
  } catch (e) { try { window.__n7moreErr = String(e && e.stack || e); } catch (e0) {} }
  try {
    var items = [
      ['daily', '일보'], ['dash', '대시보드'], ['events', '기록 조회·수정'], ['weekly', '주간 리포트'],
      ['kpi', '성적(KPI)'], ['ledger', '작업 대장'], ['vweek', '주차 백신'], ['board', '돈방 현황판'],
      ['cal', '농장 달력'], ['msg', '메시지'], ['count', '월말 실재고'], ['kboard', '핵심 KPI TOP 10'],
      ['settings', '설정 · 내 계정']
    ];
    var soon = items.filter(function (x) { return typeof soonPage_ === 'function' && soonPage_(x[0]); });
    items = items.filter(function (x) { return !(typeof soonPage_ === 'function' && soonPage_(x[0])); });
    el.innerHTML = '<div class="card more">' + items.map(function (x) {
      return '<a href="#" data-p="' + x[0] + '">' + x[1] + '<span class="mut">›</span></a>';
    }).join('') + (soon.length ? '<div class="mut" style="padding:10px 12px 4px;font-size:12px">곧 열려요</div>' +
      soon.map(function (x) {
        return '<a href="#" data-p="' + x[0] + '">' + x[1] + ' <small class="mut">곧 열려요</small><span class="mut">›</span></a>';
      }).join('') : '') + '</div>';
    Array.prototype.forEach.call(el.querySelectorAll('[data-p]'), function (a) {
      a.onclick = function (e) { e.preventDefault(); if (typeof go === 'function') go(a.getAttribute('data-p')); };
    });
  } catch (e2) {
    el.innerHTML = '<div class="card err" role="alert">더보기 메뉴를 열지 못했습니다. 다시 눌러 주세요.</div>';
  }
}
function n7HookGoSafe_() {
  function wrap(fn) {
    if (typeof fn !== 'function' || fn._n7safe) return fn;
    var w = function (p, arg) {
      if (w._n7in) return;
      w._n7in = 1;
      try { return fn.apply(this, arguments); }
      catch (e) {
        var el = document.getElementById('m-page') || document.getElementById('m-main') || document.getElementById('w-main');
        if (el && p === 'more') n7MorePage_(el);
      }
      finally { w._n7in = 0; }
    };
    w._n7safe = 1;
    return w;
  }
  if (typeof go === 'function') { go = wrap(go); if (window.PL) PL.go = go; }
  else if (window.PL && typeof PL.go === 'function') PL.go = wrap(PL.go);
  if (typeof PAGES_M === 'object' && PAGES_M && !PAGES_M._n7more) {
    PAGES_M.more = function (el) { n7MorePage_(el); };
    PAGES_M._n7more = 1;
  }
}
function n7FieldHist_() {
  if (typeof fHome !== 'function') return;
  var isField = (window.PL && PL.view === 'field') || (document.documentElement.getAttribute('data-n7v') === 'field') || /\/field(?:\/|$)/.test(location.pathname || '');
  if (!isField) return;
  if (window.PL && PL.user) {
    try {
      if (!history.state || history.state.pl !== 'in') history.replaceState({ pl: 'in', field: 1, root: 1 }, '', location.href);
      if (!n7FieldHist_._seeded) {
        history.pushState({ pl: 'in', field: 1, root: 1 }, '', location.href);
        n7FieldHist_._seeded = 1;
      }
    } catch (e) {}
  }
  if (n7FieldHist_._wrapped) return;
  n7FieldHist_._wrapped = 1;
  function wrap(name, kind) {
    var fn = window[name];
    if (typeof fn !== 'function' || fn._n7fh) return;
    window[name] = function () {
      var r = fn.apply(this, arguments);
      if (window.PL && PL.user && !n7FieldHist_._quiet) {
        try {
          if (kind === 'home') history.replaceState({ pl: 'in', field: 1, root: 1 }, '', location.href);
          else history.pushState({ pl: 'in', field: 1, p: name }, '');
        } catch (e) {}
      }
      return r;
    };
    window[name]._n7fh = 1;
  }
  wrap('fHome', 'home'); wrap('fEntry', 'page'); wrap('fPage', 'page'); wrap('fCard', 'page');
  window.addEventListener('popstate', function (e) {
    if (window.PL && PL.view && PL.view !== 'field') return;
    if (!window.PL || !PL.user) return;
    var st = e.state;
    if (!st || st.pl !== 'in' || st.root) {
      try { history.pushState({ pl: 'in', field: 1, root: 1 }, '', location.href); } catch (e3) {}
      n7FieldHist_._quiet = 1;
      try { fHome(); } catch (e4) {}
      n7FieldHist_._quiet = 0;
    }
  });
}
function n7LookFix_(root) {
  root = root || document;
  var tagIn = root.querySelector && root.querySelector('#ef-tag');
  var info = root.querySelector && root.querySelector('#ef-sow');
  if (!tagIn || tagIn.getAttribute('data-n7look') === '1') return;
  tagIn.setAttribute('data-n7look', '1');
  tagIn.addEventListener('input', function () {
    var msg = root.querySelector('#ef-msg');
    if (msg && /입력하세요/.test(msg.textContent || '')) msg.innerHTML = '';
    if (info && /확인 중/.test(info.textContent || '')) info.innerHTML = '';
  });
  var mo = new MutationObserver(function () {
    if (!info) return;
    var t = info.textContent || '';
    if (/확인 중/.test(t) && info.getAttribute('data-n7lk') === 'stuck') return;
    if (/등록되지 않은 번호|모돈번호를 확인하세요/.test(t) && !/없는 번호예요/.test(t)) {
      var extra = info.querySelector('[data-sim]') ? info.innerHTML : '';
      info.innerHTML = '<div class="sowinfo no">없는 번호예요 · 전입 먼저<br><a href="#" id="ef-to-in">전입 입력</a></div>' + (extra ? '<div class="mut">' + extra + '</div>' : '');
      var a = info.querySelector('#ef-to-in');
      if (a) a.onclick = function (e) {
        e.preventDefault();
        if (typeof go === 'function') go('entry', '전입');
        else if (typeof fEntry === 'function') fEntry('전입');
      };
    }
  });
  if (info) mo.observe(info, { childList: true, subtree: true, characterData: true });
}
function n7PageCacheKey_(name, arg) {
  return 'pl_n7pc_' + name + '_' + ((window.PL && PL.farmId) || '') + '_' + JSON.stringify(arg || '');
}
function n7HookSlowPages_() {
  if (typeof loading === 'function' && !loading._n7keep) {
    var _ld = loading;
    loading = function (el) {
      if (el && (el._n7keep || el.querySelector('.n7-cache-hit') || el.querySelector('.n7-lite'))) return;
      return _ld.apply(this, arguments);
    };
    loading._n7keep = 1;
  }
  function saveWhenReady(el, name, arg, n) {
    n = n || 0;
    try {
      if (!el) return;
      var ready = el.querySelector('#dl-doc, .daily, #n7-per, .n7-rp-split') || (el.querySelector('.loading') == null && (el.innerText || '').length > 80);
      if (!ready || el.querySelector('.loading')) {
        if (n < 80) setTimeout(function () { saveWhenReady(el, name, arg, n + 1); }, 80);
        return;
      }
      if (el.querySelector('.err')) return;
      var txt = (el.innerText || '').replace(/\s+/g, ' ').trim();
      if (txt.length < 80) return;
      if (el.querySelector('[class*=skel], [class*=skeleton], .n7h-ph')) return;
      var clone = el.cloneNode(true);
      var ban = clone.querySelector('.n7-cache-hit, .n7-lite');
      if (ban && ban.parentNode) ban.parentNode.removeChild(ban);
      sessionStorage.setItem(n7PageCacheKey_(name, arg), clone.innerHTML);
    } catch (e2) {}
  }
  function wrap(name) {
    var fn = typeof window[name] === 'function' ? window[name] : null;
    if (!fn || fn._n7cache) return;
    window[name] = function (el, arg) {
      if (el) {
        try {
          var raw = sessionStorage.getItem(n7PageCacheKey_(name, arg));
          if (raw && !el.querySelector('.n7-cache-hit')) {
            el._n7keep = 1;
            el.innerHTML = '<div class="mut noprint n7-cache-hit" style="margin:0 0 8px">이전에 본 내용입니다. 새로 불러오는 중…</div>' + raw;
          }
        } catch (e) {}
      }
      var r = fn.apply(this, arguments);
      saveWhenReady(el, name, arg, 0);
      return r;
    };
    window[name]._n7cache = 1;
  }
  wrap('pageDaily'); wrap('pageWeeklyOps_'); wrap('pageMonthlyOps_'); wrap('pageNeedle'); wrap('pageMgmt'); wrap('pageKpi'); wrap('pageReport');
  n7HookDailyLite_();
}
function n7HookDailyLite_() {
  if (typeof pageDaily !== 'function' || pageDaily._n7lite) return;
  var _pd = pageDaily;
  pageDaily = function (el, date) {
    var seq = (n7HookDailyLite_._n = (n7HookDailyLite_._n || 0) + 1);
    var per = (date && typeof date === 'object' && date.period) || (window.PL && PL._page) || '';
    var liteDate = (date && typeof date === 'object') ? (date.date || date.ref || '') : (date || '');
    if (el && typeof apiF === 'function' && per !== 'weekly' && per !== 'monthly' && (window.PL && PL._page !== 'weekly' && PL._page !== 'monthly')) {
      apiF('ilboDailyLite', liteDate).then(function (L) {
        if (n7HookDailyLite_._n !== seq) return;
        if (!el || el.getAttribute('data-n7full') === String(seq)) return;
        if (!L || !L.work) return;
        if (el.querySelector('#dl-doc') && !el.querySelector('.n7-lite') && !el.querySelector('.loading')) return;
        try { n7PaintDailyLite_(el, L); el._n7keep = 1; } catch (e) {}
      }).catch(function () {});
    }
    var r = _pd.apply(this, arguments);
    var n = 0;
    (function tick() {
      if (!el) return;
      if (el.querySelector('#dl-doc') && !el.querySelector('.n7-lite')) {
        el.setAttribute('data-n7full', String(seq));
        el._n7keep = 0;
        return;
      }
      if ((n += 1) < 120) setTimeout(tick, 50);
    })();
    return r;
  };
  pageDaily._n7lite = 1;
  if (typeof pageWeeklyOps_ === 'function') pageDaily._n7liteW = 1;
}
function n7PaintDailyLite_(el, d) {
  if (!el || !d) return;
  var wk = d.work || {};
  function n(x, k) { x = x || {}; return (x[k] != null ? x[k] : (x.n || 0)); }
  var date = d.date || '';
  el.innerHTML = '<div class="n7-lite noprint mut" style="margin:0 0 8px">핵심 숫자입니다. 나머지 집계를 불러오는 중…</div>'
    + '<div class="card daily" style="padding:12px 14px"><h2 style="margin:0 0 8px">일보 <span>' + n7Esc_(date) + '</span></h2>'
    + '<div class="n7-lite-kpi" style="display:grid;grid-template-columns:1fr 1fr;gap:8px">'
    + '<div class="card" style="margin:0"><b>교배</b> ' + n7Esc_(String(n(wk.service, "litters"))) + '복</div>'
    + '<div class="card" style="margin:0"><b>분만</b> ' + n7Esc_(String(n(wk.farrow, "n"))) + '복</div>'
    + '<div class="card" style="margin:0"><b>이유</b> ' + n7Esc_(String(n(wk.wean, "head"))) + '두</div>'
    + '<div class="card" style="margin:0"><b>자돈 폐사</b> ' + n7Esc_(String(n(wk.pigletDeath, "head"))) + '두</div>'
    + '<div class="card" style="margin:0"><b>모돈 도태·폐사</b> ' + n7Esc_(String(n(wk.sowExit, "n"))) + '건</div>'
    + '</div></div>';
}
function n7HookGuards_() {
  if (typeof pageNeedle === 'function' && !pageNeedle._n7g) {
    var _pn = pageNeedle;
    pageNeedle = function (el) {
      try { return _pn.apply(this, arguments); }
      catch (e) {
        if (el) el.innerHTML = '<div class="card err" role="alert">화면을 열지 못했습니다. <button type="button" class="btn sec" id="n7-nd-retry">다시 불러오기</button></div>';
        var b = el && el.querySelector('#n7-nd-retry');
        if (b) b.onclick = function () { pageNeedle(el); };
      }
    };
    pageNeedle._n7g = 1;
  }
  if (typeof pageReport === 'function' && !pageReport._n7g) {
    var _pr = pageReport;
    pageReport = function (el, arg) {
      try { return _pr.apply(this, arguments); }
      catch (e) {
        if (el) el.innerHTML = '<div class="card err" role="alert">보고서를 열지 못했습니다. <button type="button" class="btn sec" id="n7-rp-retry">다시 불러오기</button></div>';
        var b = el && el.querySelector('#n7-rp-retry');
        if (b) b.onclick = function () { pageReport(el, arg); };
      }
    };
    pageReport._n7g = 1;
  }
  if (typeof repMgmtHTML_ === 'function' && !repMgmtHTML_._n7g) {
    var _rm = repMgmtHTML_;
    repMgmtHTML_ = function (r) {
      r = r || {};
      if (!r.sum) r.sum = [];
      if (!r.list) r.list = [];
      if (!r.reg) r.reg = [];
      try { return _rm(r); }
      catch (e) { return '<div class="card err" role="alert">관리대상·모돈 대장을 그리지 못했습니다. 다시 보기를 눌러 주세요.</div>'; }
    };
    repMgmtHTML_._n7g = 1;
  }
}
function n7SaveLockBoot_() {
  if (n7SaveLockBoot_._on) return;
  n7SaveLockBoot_._on = 1;
  document.addEventListener('click', function (e) {
    var b = e.target && e.target.closest && e.target.closest('#ef-save, #n7-abar-save');
    if (!b) return;
    var box = b.closest('.entry') || document;
    if (box._efFlight && b.id === 'ef-save') {
      e.preventDefault(); e.stopPropagation();
      return;
    }
    if (b.id === 'ef-save' && !b.getAttribute('data-n7lbl')) {
      b.setAttribute('data-n7lbl', b.textContent || '저장');
    }
    if (b.id === 'ef-save') {
      var entry = b.closest('.entry') || document.querySelector('.entry');
      if (typeof n7EntryMissing_ === 'function' && entry && n7EntryMissing_(entry).length) return;
      b.textContent = '저장 중…';
    }
  }, true);
  var mo = new MutationObserver(function () {
    var btn = document.getElementById('ef-save');
    if (btn && !btn.disabled) {
      var lbl = btn.getAttribute('data-n7lbl');
      if (lbl && btn.textContent === '저장 중…') btn.textContent = lbl;
    }
  });
  mo.observe(document.body, { subtree: true, attributes: true, attributeFilter: ['disabled'] });
}
function n7AuditBoot_() {
  n7HookGoSafe_();
  n7FieldHist_();
  n7HookSlowPages_();
  n7HookGuards_();
  n7SaveLockBoot_();
  n7LookFix_(document);
  setTimeout(function () { n7HookGoSafe_(); n7FieldHist_(); n7HookGuards_(); n7LookFix_(document); }, 0);
  setTimeout(function () { n7HookGoSafe_(); n7FieldHist_(); n7HookGuards_(); n7LookFix_(document); }, 400);
}

(function n7T447Boot_() {
  n7SignupHint_();
  if (typeof n7AuditBoot_ === 'function') n7AuditBoot_();
  if (typeof n7UiScaleBoot_ === 'function') n7UiScaleBoot_();
  if (typeof n7HookKpiPeriod_ === 'function') n7HookKpiPeriod_();
  if (typeof n7HookVaccPages_ === 'function') n7HookVaccPages_();
  if (typeof n7CertBoot_ === 'function') n7CertBoot_();
  if (typeof n7AccPrintBoot_ === 'function') n7AccPrintBoot_();
  if (typeof n7ObChipBoot_ === 'function') n7ObChipBoot_();
  if (typeof n7NormLocsBoot_ === 'function') n7NormLocsBoot_();
  n7HistInstall_();
  if (typeof n7StaffWatch_ === 'function') n7StaffWatch_();
  setTimeout(n7SignupHint_, 0);
  setTimeout(n7HistInstall_, 0);
  setTimeout(n7HistInstall_, 50);
  setTimeout(n7HistInstall_, 400);
  [400, 1200, 2500].forEach(function (ms) {
    setTimeout(function () {
      var host = document.getElementById('m-main') || document.getElementById('app') || document.body;
      if (typeof n7StaffCards_ === 'function') n7StaffCards_(host);
      if (typeof n7HistInstall_ === 'function') n7HistInstall_();
    }, ms);
  });
})();



function n7AddMonths_(iso, n) {
  var p = String(iso || '').slice(0, 10).split('-');
  if (p.length < 3) return iso;
  var y = +p[0], m = +p[1] + n, d = +p[2];
  while (m > 12) { m -= 12; y++; }
  while (m < 1) { m += 12; y--; }
  var last = new Date(y, m, 0).getDate();
  if (d > last) d = last;
  function z(x) { return (x < 10 ? '0' : '') + x; }
  return y + '-' + z(m) + '-' + z(d);
}
function n7PerRange_(mode, cnt, t) {
  t = String(t || (typeof window.today === 'function' ? window.today() : ((window.PL && PL._daily && PL._daily.today) || ''))).slice(0, 10);
  var from = t, to = t;
  cnt = Number(cnt) || 1;
  if (mode === 'm') {
    from = n7AddMonths_(t, -cnt);
    if (typeof addDays === 'function') from = addDays(from, 1);
  } else if (mode === 'w') {
    var w = (typeof farmWeek_ === 'function') ? farmWeek_(t) : null;
    var mon = w && w.from ? w.from : t;
    from = (typeof addDays === 'function') ? addDays(mon, -(cnt - 1) * 7) : mon;
    to = t;
  }
  return { from: from, to: to };
}
function n7PerSave_(st) {
  try { localStorage.setItem('pl_kpi_per', JSON.stringify(st)); } catch (e) {}
}
function n7PerLoad_() {
  try { return JSON.parse(localStorage.getItem('pl_kpi_per') || 'null'); } catch (e) { return null; }
}
function n7PerYmd_(s) {
  var p = String(s || '').split('-');
  if (p.length < 3) return s || '';
  return p[0].slice(-2) + '.' + p[1] + '.' + p[2];
}
function n7PerLabel_(st, rg) {
  if (!rg) return '';
  var a = n7PerYmd_(rg.from), b = n7PerYmd_(rg.to);
  if (st.mode === 'w' && typeof farmWeek_ === 'function') {
    var wa = farmWeek_(rg.from), wb = farmWeek_(rg.to);
    if (wa && wb) return wa.week + '–' + wb.week + '주차 · ' + a + '~' + b;
  }
  var unit = (st && st.mode === 'w') ? '주' : '개월';
  var n = st && st.n ? st.n : '';
  return a + '~' + b + (n ? ' (' + n + unit + ')' : '');
}
function n7PerBarHTML_(st) {
  st = st || { mode: 'm', n: 12 };
  var btn = function (mode, n) {
    var on = st.mode === mode && Number(st.n) === Number(n);
    return '<button type="button" class="btn sm ' + (on ? 'on' : 'sec') + '" data-pm="' + mode + '" data-n="' + n + '">' + n + '</button>';
  };
  return '<div class="n7-per" id="n7-per">'
    + '<div class="n7-per-row"><b>개월</b>' + [1, 3, 6, 12].map(function (n) { return btn('m', n); }).join('') + '</div>'
    + '<div class="n7-per-row"><b>주</b>' + [4, 12, 26, 52].map(function (n) { return btn('w', n); }).join('') + '</div>'
    + '<details class="n7-per-c"' + (st.mode === 'c' ? ' open' : '') + '><summary>기간</summary><div class="n7-per-custom"></div></details>'
    + '<div class="n7-per-rng mut"></div></div>';
}
function n7KpiPeriodMount_(el) {
  if (!el || el.querySelector('#n7-per')) return;
  var row = el.querySelector('.row.noprint');
  if (!row) return;
  var st = n7PerLoad_() || { mode: 'm', n: 12 };
  var wrap = document.createElement('div');
  wrap.innerHTML = n7PerBarHTML_(st);
  var bar = wrap.firstChild;
  row.parentNode.insertBefore(bar, row);
  var custom = bar.querySelector('.n7-per-custom');
  var f = row.querySelector('#kp-f'), t = row.querySelector('#kp-t'), go = row.querySelector('#kp-go');
  if (custom) {
    [].forEach.call(row.querySelectorAll('[data-p]'), function (b) { b.style.display = 'none'; });
    if (f && t) { custom.appendChild(f); custom.appendChild(t); }
    if (go) custom.appendChild(go);
  }
  row.style.display = 'none';
  function apply(next, trigger) {
    st = next;
    n7PerSave_(st);
    var rg = st.mode === 'c' ? { from: (f && f.value) || '', to: (t && t.value) || '' } : n7PerRange_(st.mode, st.n, typeof today === 'function' ? today() : '');
    if (f && rg.from) f.value = rg.from;
    if (t && rg.to) t.value = rg.to;
    var lab = bar.querySelector('.n7-per-rng');
    if (lab) lab.textContent = n7PerLabel_(st, rg);
    bar.querySelectorAll('[data-pm]').forEach(function (b) {
      var on = b.getAttribute('data-pm') === st.mode && b.getAttribute('data-n') === String(st.n);
      b.className = 'btn sm ' + (on ? 'on' : 'sec');
    });
    if (trigger && go) go.click();
  }
  bar.addEventListener('click', function (e) {
    var b = e.target.closest && e.target.closest('[data-pm]');
    if (!b) return;
    apply({ mode: b.getAttribute('data-pm'), n: Number(b.getAttribute('data-n')) }, true);
  });
  apply(st, true);
}

function n7ParseKpiNum_(s) {
  s = String(s || '').replace(/,/g, '').replace(/%/g, '').trim();
  var n = parseFloat(s);
  return isFinite(n) ? n : null;
}

function n7HookAttFab_() {
  if (typeof pageAtt === 'function' && !pageAtt._n7fab) {
    var _pa = pageAtt;
    pageAtt = function (el) {
      var r = _pa.apply(this, arguments);
      try {
        if (el && el.getAttribute && !el.getAttribute('data-n7att')) {
          el.setAttribute('data-n7att', '1');
          el.classList.add('n7-att-host');
        }
        document.body.classList.add('n7-on-att');
        if (!document.getElementById('n7-att-fab-css')) {
          var st = document.createElement('style');
          st.id = 'n7-att-fab-css';
          st.textContent = 'body.n7-on-att #nov7-fab{bottom:112px}'
            + '.n7-att-host, #pa-team, #pa-cal, #fw-team{padding-bottom:96px}'
            + '.att-seg, #pa-team .att-mt, #pa-team .row{position:relative;z-index:2;padding-right:12px}';
          document.head.appendChild(st);
        }
        setTimeout(function () {
          var team = el && el.querySelector('#pa-team');
          if (!team || typeof attTeamView !== 'function') return;
          if (typeof attTeamOk === 'function' && !attTeamOk()) return;
          var hasBtn = !!team.querySelector('[data-tm]');
          var empty = !hasBtn;
          if (empty) attTeamView(team);
        }, 1600);
      } catch (e) {}
      return r;
    };
    pageAtt._n7fab = 1;
  }
  if (typeof PL !== 'undefined' && PL && PL._page && PL._page !== 'att' && PL._page !== 'org') {
    try { document.body.classList.remove('n7-on-att'); } catch (e2) {}
  }
}

function n7HookKpiMotion_() {
  if (typeof pageKpi === 'function' && !pageKpi._n7mo) {
    var _pk = pageKpi;
    pageKpi = function (el) {
      var r = _pk.apply(this, arguments);
      try { n7WatchKpiMo_(el); } catch (e) {}
      return r;
    };
    pageKpi._n7mo = 1;
  }
}
function n7WatchKpiMo_(el) {
  if (!el) return;
  var host = el.querySelector('#kp-b');
  if (!host) {
    if ((n7WatchKpiMo_._n = (n7WatchKpiMo_._n || 0) + 1) < 40) setTimeout(function () { n7WatchKpiMo_(el); }, 120);
    return;
  }
  n7WatchKpiMo_._n = 0;
  if (host._n7moObs) return;
  host._n7moObs = 1;
  var mo = new MutationObserver(function () { n7EnhanceKpiMo_(host); });
  mo.observe(host, { childList: true });
  n7EnhanceKpiMo_(host);
}
function n7EnhanceKpiMo_(host) {
  if (!host || !host.querySelector('.kpigrid, .stat')) return;
  if (!host.querySelector('#n7-kpi-mo-css')) {
    var st = document.createElement('style');
    st.id = 'n7-kpi-mo-css';
    st.textContent = '.n7-kpi-gag{--p:0;width:56px;height:56px;border-radius:50%;background:conic-gradient(#1f6f43 calc(var(--p)*1%),#e6eee8 0);display:inline-block;vertical-align:middle;margin-left:8px}'
      + '.n7-kpi-gag i{display:block;width:40px;height:40px;margin:8px;border-radius:50%;background:#fff;text-align:center;font-size:11px;line-height:40px}'
      + '.n7-kpi-bars{display:flex;align-items:flex-end;gap:6px;height:88px;padding:8px 0}'
      + '.n7-kpi-bars i{flex:1;display:flex;flex-direction:column;align-items:center;justify-content:flex-end;height:100%;min-width:0}'
      + '.n7-kpi-bars b{display:block;width:100%;max-width:18px;background:#1f6f43;border-radius:4px 4px 0 0;height:0;transition:height .7s cubic-bezier(.22,1,.36,1)}'
      + '.n7-kpi-bars small{margin-top:4px;font-size:10px;color:#667}'
      + '@media(prefers-reduced-motion:reduce){.n7-kpi-bars b{transition:none}}';
    host.appendChild(st);
  }
  var reduce = typeof n7ReduceMotion_ === 'function' && n7ReduceMotion_();
  host.querySelectorAll('.kpigrid .stat').forEach(function (card) {
    var b = card.querySelector('b');
    if (!b || b.getAttribute('data-n7done')) return;
    var raw = (b.textContent || '').trim();
    var num = n7ParseKpiNum_(raw), unit = /%/.test(raw) ? '%' : '';
    if (num == null) { b.setAttribute('data-n7done', '1'); return; }
    var dp = /\./.test(String(raw).replace(/,/g, '')) ? (String(raw).split('.')[1] || '').replace(/\D/g, '').length : 0;
    b.setAttribute('data-n7v', String(num));
    b.setAttribute('data-n7dp', String(dp));
    b.setAttribute('data-n7u', unit);
    b.setAttribute('data-n7done', '1');
    if (unit === '%' && !card.querySelector('.n7-kpi-gag')) {
      var g = document.createElement('span');
      g.className = 'n7-kpi-gag';
      g.setAttribute('data-n7g', String(Math.max(0, Math.min(100, num))));
      g.innerHTML = '<i>' + Math.round(num) + '%</i>';
      b.appendChild(g);
    }
  });
  if (typeof n7MotionDash_ === 'function') {
    // map knum-like attrs onto .n7h-k so existing motion can run: also run local count-up on b[data-n7v]
    host.querySelectorAll('.kpigrid .stat b[data-n7v]').forEach(function (el) {
      if (el.getAttribute('data-n7ran')) return;
      el.setAttribute('data-n7ran', '1');
      var to = +el.getAttribute('data-n7v'), dp = +el.getAttribute('data-n7dp') || 0, unit = el.getAttribute('data-n7u') || '';
      var gag = el.querySelector('.n7-kpi-gag');
      function fmt(n) { try { return (typeof nF === 'function' ? nF(n, dp) : n.toFixed(dp)) + unit; } catch (e) { return String(n) + unit; } }
      if (reduce) { el.firstChild ? null : (el.innerHTML = fmt(to) + (gag ? gag.outerHTML : '')); return; }
      var t0 = (window.performance && performance.now()) || Date.now();
      (function tick(now) {
        var p = Math.min(1, (now - t0) / 800); p = 1 - Math.pow(1 - p, 3);
        var label = fmt(to * p);
        if (gag) { el.innerHTML = label; el.appendChild(gag); gag.style.setProperty('--p', (Math.max(0, Math.min(100, to)) * p).toFixed(2)); }
        else el.textContent = label;
        if (p < 1) requestAnimationFrame(tick);
      })(t0);
    });
    host.querySelectorAll('.n7-kpi-gag[data-n7g]').forEach(function (g) {
      if (reduce) g.style.setProperty('--p', g.getAttribute('data-n7g'));
    });
  }
  var box = host.querySelector('#n7-kpi-mo');
  if (!box) {
    box = document.createElement('div');
    box.id = 'n7-kpi-mo';
    box.className = 'card';
    box.style.marginTop = '12px';
    box.innerHTML = '<h3>최근 12개월</h3><div class="mut">월별 막대를 불러오는 중…</div>';
    var grid = host.querySelector('.kpigrid');
    if (grid && grid.parentNode) grid.parentNode.insertBefore(box, grid.nextSibling);
    else host.appendChild(box);
    if (typeof apiF === 'function' || (typeof PL !== 'undefined' && PL._pref && PL._pref.getHomeDash)) {
      var dashP = (function () {
        var pref = (typeof PL !== 'undefined' && PL._pref && PL._pref.getHomeDash) || null;
        if (pref && typeof pref.then !== 'function' && (pref.primary || pref.cards || pref.items)) return Promise.resolve(pref);
        if (typeof PL !== 'undefined' && PL._n7HomeDashP) return PL._n7HomeDashP;
        var src = (pref && typeof pref.then === 'function') ? pref : (typeof apiF === 'function' ? apiF('getHomeDash') : Promise.reject(new Error('no dash')));
        var p = src.then(function (r) {
          if (typeof PL !== 'undefined') { PL._pref = PL._pref || {}; if (r) PL._pref.getHomeDash = r; }
          return r;
        });
        if (typeof PL !== 'undefined') PL._n7HomeDashP = p;
        return p;
      })();
      setTimeout(function () {
        if (box && /불러오는 중/.test(box.innerText || '')) box.innerHTML = '<h3>최근 12개월</h3><div class="mut">월별 막대를 불러오는 중… 홈 성적과 같은 자료라서, 농장이 크면 조금 걸립니다.</div>';
      }, 8000);
      dashP.then(function (home) {
        var cards = (home && (home.primary || home.secondary || (home.kpi && home.kpi.primary) || home.cards || home.items)) || [];
        if (!cards.length && home && home.catalog) cards = home.catalog;
        var c = null, psy = null;
        (cards || []).forEach(function (x) {
          var spark = (x && (x.spark || x.months)) || [];
          if (x && spark.length > 1) {
            if (!c) c = x;
            if (x.id === 'psy' || x.title === 'PSY') psy = x;
          }
        });
        if (psy) c = psy;
        if (!c) { box.innerHTML = '<h3>최근 12개월</h3><p class="mut">이 농장의 월별 성적이 아직 없어 막대를 그리지 않습니다.</p>'; return; }
        var spark = (c.spark || []).map(function (v) { return (v && typeof v === 'object') ? (v.value != null ? v.value : v.v) : v; }), months = c.months || [], vals = spark.filter(function (v) { return v != null && isFinite(+v); });
        var mx = vals.length ? Math.max.apply(null, vals) : 1; if (mx <= 0) mx = 1;
        var bars = spark.map(function (v, i) {
          var h = v == null || !isFinite(+v) ? 0 : Math.max(v ? 4 : 0, Math.round((+v / mx) * 64));
          var lab = String(months[i] || '').slice(5);
          return '<i title="' + n7Esc_((c.title || c.id || '') + ' ' + (months[i] || '') + ' ' + v) + '"><b data-n7h="' + h + '"></b><small>' + n7Esc_(lab) + '</small></i>';
        }).join('');
        box.innerHTML = '<h3>최근 12개월 · ' + n7Esc_(c.title || c.id || '') + '</h3><div class="n7-kpi-bars">' + bars + '</div>';
        var red = typeof n7ReduceMotion_ === 'function' && n7ReduceMotion_();
        box.querySelectorAll('b[data-n7h]').forEach(function (b) {
          var h = b.getAttribute('data-n7h') || '0';
          if (red) { b.style.height = h + 'px'; return; }
          b.style.height = '0px';
          requestAnimationFrame(function () { requestAnimationFrame(function () { b.style.height = h + 'px'; }); });
        });
      }).catch(function () {
        box.innerHTML = '<h3>최근 12개월</h3><p class="mut">월별 막대를 불러오지 못했습니다.</p>';
      });
    }
  }
}

function n7HookKpiPeriod_() {
  if (typeof pageKpi === 'function' && !pageKpi._n7per) {
    var _pk = pageKpi;
    pageKpi = function (el) {
      var r = _pk.apply(this, arguments);
      try { n7KpiPeriodMount_(el); } catch (e) {}
      return r;
    };
    pageKpi._n7per = 1;
  }
  if (typeof pageReport === 'function' && !pageReport._n7per) {
    var _pr = pageReport;
    pageReport = function (el, arg) {
      var r = _pr.apply(this, arguments);
      setTimeout(function () { try { n7ReportPeriodMount_(el); } catch (e) {} }, 80);
      return r;
    };
    pageReport._n7per = 1;
  }
}
function n7ReportPeriodMount_(el) {
  if (!el || el.querySelector('#n7-per')) return;
  var from = el.querySelector('#rp-from'), to = el.querySelector('#rp-to');
  if (!from || !to) return;
  var st = n7PerLoad_() || { mode: 'm', n: 12 };
  var wrap = document.createElement('div');
  wrap.innerHTML = n7PerBarHTML_(st);
  var bar = wrap.firstChild;
  var row = from.closest('.row') || from.parentNode;
  if (row && row.parentNode) row.parentNode.insertBefore(bar, row);
  else el.insertBefore(bar, el.firstChild);
  var custom = bar.querySelector('.n7-per-custom');
  if (custom) {
    var lab = row && row.querySelector('label.mut');
    if (lab) custom.appendChild(lab);
    custom.appendChild(from);
    var sp = row && row.querySelector('span');
    if (sp && (sp.textContent || '').indexOf('~') >= 0) custom.appendChild(sp);
    custom.appendChild(to);
  }
  function ym(iso) { return String(iso || '').slice(0, 7); }
  function apply(next, trigger) {
    st = next; n7PerSave_(st);
    var rg = st.mode === 'c' ? { from: from.value, to: to.value } : n7PerRange_(st.mode, st.n, typeof today === 'function' ? today() : '');
    if (st.mode !== 'c') { from.value = ym(rg.from); to.value = ym(rg.to); }
    var lab2 = bar.querySelector('.n7-per-rng');
    if (lab2) lab2.textContent = n7PerLabel_(st, st.mode === 'c' ? { from: from.value, to: to.value } : rg);
    bar.querySelectorAll('[data-pm]').forEach(function (b) {
      var on = b.getAttribute('data-pm') === st.mode && b.getAttribute('data-n') === String(st.n);
      b.className = 'btn sm ' + (on ? 'on' : 'sec');
    });
    var run = el.querySelector('#rp-run');
    if (trigger && run) run.click();
    else if (trigger && from.onchange) from.onchange();
  }
  bar.addEventListener('click', function (e) {
    var b = e.target.closest && e.target.closest('[data-pm]');
    if (!b) return;
    apply({ mode: b.getAttribute('data-pm'), n: Number(b.getAttribute('data-n')) }, true);
  });
  apply(st, false);
}

function n7SowVaccHist_(card, tag) {
  if (!card || !tag || card.querySelector('#n7-vacc-hist')) return;
  var box = document.createElement('div');
  box.id = 'n7-vacc-hist';
  box.className = 'n7-vh';
  box.innerHTML = '<h3>접종기록</h3><div class="n7-vh-body mut">…</div>';
  var after = card.querySelector('.kv') || card.querySelector('.sowhead');
  if (after && after.parentNode) after.parentNode.insertBefore(box, after.nextSibling);
  else card.appendChild(box);
  var body = box.querySelector('.n7-vh-body');
  var from = (typeof addDays === 'function' && typeof today === 'function') ? addDays(today(), -365 * 3) : '2020-01-01';
  var to = (typeof today === 'function') ? today() : '';
  if (typeof apiF !== 'function') { body.textContent = '기록을 불러올 수 없습니다'; return; }
  apiF('listVaccinations', { from: from, to: to, q: tag, includeCancelled: true }).then(function (r) {
    var rows = ((r && r.rows) || []).filter(function (x) {
      var tgt = String(x['대상'] || x.target || x.tag || '');
      return tgt === tag || tgt.split(/[,，\s]+/).indexOf(tag) >= 0;
    });
    rows.sort(function (a, b) { return String(b['접종일'] || b.date || '').localeCompare(String(a['접종일'] || a.date || '')); });
    if (!rows.length) { body.textContent = '기록 없음'; return; }
    body.className = 'n7-vh-body';
    var esc2 = (typeof n7Esc2_ === 'function') ? n7Esc2_ : function (s) { return String(s || ''); };
    body.innerHTML = rows.map(function (x) {
      var d = String(x['접종일'] || x.date || '').slice(0, 10);
      var wk = (typeof farmWeek_ === 'function' && d) ? farmWeek_(d) : null;
      var wlab = wk ? (wk.week + '주차') : '';
      var vac = x['백신명'] || x.vaccine || '';
      var dose = (x['용량'] || x.dose || '') !== '' ? String(x['용량'] || x.dose) + (x['사용단위'] || x.unit || 'mL') : '';
      var stt = String(x['상태'] || '');
      var cx = (stt && stt !== '정상') ? ' <span class="n7-vh-cx">' + esc2(stt) + '</span>' : '';
      return '<div class="n7-vh-row' + (cx ? ' is-cx' : '') + '"><b>' + esc2(d) + '</b><span>' + esc2(vac) + (dose ? ' · ' + dose : '') + cx + '</span><span class="mt">' + esc2(wlab) + '</span></div>';
    }).join('') || '기록 없음';
  }, function () { body.textContent = '기록을 불러오지 못했습니다'; });
}

function n7UiScale_(v) {
  v = (v === 'sm' || v === 'lg') ? v : 'md';
  try { document.documentElement.setAttribute('data-n7ui', v); } catch (e0) {}
  try { localStorage.setItem('pl_n7ui', v); } catch (e) {}
  try {
    var bar = document.getElementById('n7-ui-sz');
    if (bar) [].forEach.call(bar.querySelectorAll('button'), function (b) { b.className = (b.getAttribute('data-u') === v) ? 'on' : ''; });
  } catch (e2) {}
}
function n7OnLoginScreen_() {
  if (document.documentElement && document.documentElement.classList.contains('pl-login')) return true;
  if (document.body && document.body.classList.contains('pl-login')) return true;
  if (document.querySelector('.pl-login, .loginbox, #lg-id') && !document.querySelector('.shell')) return true;
  if (window.PL && !PL.token && !document.querySelector('.shell')) return true;
  return false;
}
function n7StripLoginChrome_() {
  ['n7-ui-sz', 'n7-theme'].forEach(function (id) {
    var n = document.getElementById(id);
    if (n && n.parentNode) n.parentNode.removeChild(n);
  });
}
function n7ChromeHost_() {
  if (typeof n7OnLoginScreen_ === 'function' && n7OnLoginScreen_()) return null;
  var mh = document.querySelector('.mh');
  if (mh) return mh;
  /* t522u: PC·태블릿은 오른쪽 위 헤더(.top). 로고 옆이 아님 */
  return document.querySelector('.shell .top') || document.querySelector('#w-narrow, .w-narrow') || document.querySelector('.shell .whead, .shell header, #n7h');
}
function n7ChromeAnchor_() {
  var host = n7ChromeHost_();
  if (!host) return null;
  return host.querySelector('#w-out') || host.querySelector('#open-notices') || host.querySelector('#n7-rail-btn');
}
function n7ChromePlace_(el, afterId) {
  var host = n7ChromeHost_();
  if (!host || !el) return;
  var after = afterId ? document.getElementById(afterId) : null;
  if (after && after.parentNode === host) {
    if (el.parentNode !== host || el.previousSibling !== after) {
      if (after.nextSibling) host.insertBefore(el, after.nextSibling);
      else host.appendChild(el);
    }
    return;
  }
  var a = n7ChromeAnchor_();
  if (a && a.parentNode === host) {
    if (el.parentNode !== host || el.nextSibling !== a) host.insertBefore(el, a);
  } else if (el.parentNode !== host) host.appendChild(el);
}
function n7UiScaleMount_() {
  if (typeof n7OnLoginScreen_ === 'function' && n7OnLoginScreen_()) { n7StripLoginChrome_(); return; }
  var host = n7ChromeHost_();
  if (!host) return;
  var bar = document.getElementById('n7-ui-sz');
  if (bar) { n7ChromePlace_(bar); return; }
  var bar = document.createElement('span');
  bar.id = 'n7-ui-sz';
  bar.className = 'n7-ui-sz';
  bar.setAttribute('aria-label', '글자 크기');
  bar.innerHTML = '<button type="button" data-u="sm" aria-label="소" title="소">A</button><button type="button" data-u="md" aria-label="중" title="중">A</button><button type="button" data-u="lg" aria-label="대" title="대">A</button>';
  n7ChromePlace_(bar);
  bar.onclick = function (e) {
    var b = e.target.closest && e.target.closest('button[data-u]');
    if (b) n7UiScale_(b.getAttribute('data-u'));
  };
  var cur = 'md';
  try { cur = localStorage.getItem('pl_n7ui') || 'md'; } catch (e) {}
  n7UiScale_(cur);
  if (typeof n7ObChip_ === 'function') n7ObChip_();
}
function n7ThemeKey_() {
  var u = (window.PL && PL.user && PL.user.id) || '';
  return u ? ('pl_theme:' + u) : 'pl_theme';
}
function n7ThemePref_() {
  try {
    var s = localStorage.getItem(n7ThemeKey_());
    if (s === 'light' || s === 'dark') return s;
    s = localStorage.getItem('pl_theme');
    if (s === 'light' || s === 'dark') return s;
  } catch (e) {}
  return '';
}
function n7ThemeResolved_() {
  var p = n7ThemePref_();
  if (p) return p;
  try { if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) return 'dark'; } catch (e2) {}
  return 'light';
}
function n7ThemeApply_(v) {
  try {
    if (v === 'dark' || v === 'light') document.documentElement.setAttribute('data-theme', v);
    else document.documentElement.removeAttribute('data-theme');
  } catch (e) {}
  var shown = (v === 'dark' || v === 'light') ? v : n7ThemeResolved_();
  var b = document.getElementById('n7-theme');
  if (b) {
    b.setAttribute('aria-label', shown === 'dark' ? '밝은 화면으로' : '어두운 화면으로');
    b.setAttribute('title', shown === 'dark' ? '밝은 화면' : '어두운 화면');
    b.innerHTML = shown === 'dark'
      ? '<svg viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="5" fill="currentColor"/><g stroke="currentColor" stroke-width="2" stroke-linecap="round"><path d="M12 2v2M12 20v2M2 12h2M20 12h2M4.6 4.6l1.4 1.4M18 18l1.4 1.4M4.6 19.4L6 18M18 6l1.4-1.4"/></g></svg>'
      : '<svg viewBox="0 0 24 24" aria-hidden="true"><path fill="currentColor" d="M16.5 13.5A7 7 0 0 1 10 4.1 7.5 7.5 0 1 0 19.9 14a7 7 0 0 1-3.4-.5z"/></svg>';
  }
  try { if (typeof n7ProdCopy_ === 'function') n7ProdCopy_(); } catch (e2) {}
}
function n7ThemeToggle_() {
  var next = (n7ThemeResolved_() === 'dark') ? 'light' : 'dark';
  try { localStorage.setItem(n7ThemeKey_(), next); localStorage.setItem('pl_theme', next); localStorage.setItem('pl_n7theme', next); } catch (e) {}
  n7ThemeApply_(next);
}
function n7ThemeMount_() {
  if (typeof n7OnLoginScreen_ === 'function' && n7OnLoginScreen_()) { n7StripLoginChrome_(); return; }
  var host = (typeof n7ChromeHost_ === 'function' && n7ChromeHost_()) || document.querySelector('.mh, .shell .top, .shell .whead, .shell header, #n7h');
  var existing = document.getElementById('n7-theme');
  if (existing) {
    n7ChromePlace_(existing, 'n7-ui-sz');
    n7ThemeApply_(n7ThemePref_()); return;
  }
  if (!host) return;
  var b = document.createElement('button');
  b.type = 'button'; b.id = 'n7-theme'; b.className = 'n7-theme';
  b.onclick = function () { n7ThemeToggle_(); };
  n7ChromePlace_(b, 'n7-ui-sz');
  n7ThemeApply_(n7ThemePref_());
}
function n7UiScaleBoot_() {
  var onLogin = (typeof n7OnLoginScreen_ === 'function' && n7OnLoginScreen_());
  if (!onLogin) {
    var cur = 'md';
    try { cur = localStorage.getItem('pl_n7ui') || 'md'; } catch (e) {}
    document.documentElement.setAttribute('data-n7ui', (cur === 'sm' || cur === 'lg') ? cur : 'md');
    try { n7ThemeApply_(n7ThemePref_()); } catch (eT) {}
  } else {
    n7StripLoginChrome_();
  }
  n7UiScaleMount_();
  n7ThemeMount_();
  [0, 400, 1200, 2500].forEach(function (ms) { setTimeout(function () { n7UiScaleMount_(); n7ThemeMount_(); }, ms); });
  if (typeof MutationObserver === 'function' && !n7UiScaleBoot_._mo) {
    n7UiScaleBoot_._mo = 1;
    try {
      new MutationObserver(function () {
        if (typeof n7OnLoginScreen_ === 'function' && n7OnLoginScreen_()) { n7StripLoginChrome_(); return; }
        if (!document.getElementById('n7-ui-sz')) n7UiScaleMount_();
        if (!document.getElementById('n7-theme')) n7ThemeMount_();
      }).observe(document.body, { childList: true, subtree: true });
    } catch (e) {}
  }
}

function n7HookVaccPages_() {
  if (typeof pageVweek === 'function' && !pageVweek._n7vw) {
    var _pv = pageVweek;
    pageVweek = function (el) {
      var r = _pv.apply(this, arguments);
      setTimeout(function () { if (el && typeof n7VaccWeekMount_ === 'function') n7VaccWeekMount_(el, 'vweek'); }, 200);
      return r;
    };
    pageVweek._n7vw = 1;
  }
  if (typeof openSowModal === 'function' && !openSowModal._n7vh) {
    var _om = openSowModal;
    openSowModal = function () {
      var r = _om.apply(this, arguments);
      var watch = function (n) {
        var host = document.querySelector('#sm-b');
        if (host && host.querySelector('.sowcard')) n7PolishSowCard_(host);
        else if ((n || 0) < 40) setTimeout(function () { watch((n || 0) + 1); }, 80);
      };
      watch(0);
      return r;
    };
    openSowModal._n7vh = 1;
  }
}

function n7AfterLazy_() {
  try { if (typeof n7HookPages_ === 'function') n7HookPages_(); } catch (e) {}
  try { if (typeof n7HookShip_ === 'function') n7HookShip_(); } catch (e) {}
  try { if (typeof n7HookReport_ === 'function') n7HookReport_(); } catch (e) {}
  try { if (typeof n7HookFstock_ === 'function') n7HookFstock_(); } catch (e) {}
  try { if (typeof installFtCard_ === 'function') installFtCard_(); } catch (e) {}
  try { if (typeof n7HookKpiFin_ === 'function') n7HookKpiFin_(); } catch (e) {}
  try { if (typeof n7HookKpiPeriod_ === 'function') n7HookKpiPeriod_(); } catch (e) {} try { if (typeof n7HookKpiMotion_ === 'function') n7HookKpiMotion_(); } catch (eMo) {} try { if (typeof n7HookAttFab_ === 'function') n7HookAttFab_(); } catch (eAf) {}
  try { if (typeof n7HookVaccPages_ === 'function') n7HookVaccPages_(); } catch (e) {}
  try { if (typeof n7CertBoot_ === 'function') n7CertBoot_(); } catch (e) {}
  try { if (typeof n7AccPrintBoot_ === 'function') n7AccPrintBoot_(); } catch (e) {}
  try { if (typeof n7ObChipBoot_ === 'function') n7ObChipBoot_(); } catch (e) {}
  try { if (typeof n7NormLocsBoot_ === 'function') n7NormLocsBoot_(); } catch (e) {}
  try { if (typeof n7UiScaleMount_ === 'function') n7UiScaleMount_(); } catch (e) {}
  try { if (typeof n7P2Boot_ === 'function') n7P2Boot_(); } catch (e) {}
}

function n7ApiCacheHook_() {
  if (n7ApiCacheHook_._on) {
    if (typeof apiF === 'function' && !apiF._n7c) n7ApiCacheHook_._on = 0;
    else return;
  }
  function wrap(fn) {
    if (typeof fn !== 'function' || fn._n7c) return fn;
    var TTL = {
      getHomeDash: 120000, getDashboard: 60000, getGoals: 120000, getDueList: 30000,
      getFarmStructure: 120000, listSows: 60000, roomHeadCounts: 30000,
      getVaccDue: 30000, getFarmMemo: 30000, getKpi: 60000, getSowBoard: 20000,
      getBootstrap: 60000, listQuarantine: 60000
    };
    var INVAL = {
      saveEvent: 1, editEvent: 1, cancelEvent: 1, saveGroupEvent: 1, cancelGroupEvent: 1,
      attPunch: 1, updateSettings: 1, confirmDrugPrograms: 1, saveFarmMemo: 1,
      editStructure: 1, saveVaccination: 1, cancelVaccination: 1, saveTreatBatch: 1,
      saveWeanBatch: 1, saveOrder: 1, uploadEvents: 1
    };
    var inflight = {}, cache = {};
    var w = function (name) {
      var args = [].slice.call(arguments, 1);
      var k = String(name) + ':' + JSON.stringify(args);
      var ttl = TTL[name];
      if (ttl) {
        var hit = cache[k];
        if (hit && (Date.now() - hit.t) < ttl) return Promise.resolve(hit.v);
        if (inflight[k]) return inflight[k];
      }
      if (INVAL[name] && typeof isVet === 'function' && isVet()) {
        return Promise.reject({ message: '수의사는 기록을 볼 수만 있습니다', key: 'e.forbidden' });
      }
      var p = fn.apply(this, arguments);
      if (ttl && p && typeof p.then === 'function') {
        p = Promise.race([p, new Promise(function (_, rej) {
          setTimeout(function () { rej({ message: '불러오지 못했어요.', read: 1, fn: name, slow: 1 }); }, 20000);
        })]);
      }
      if (ttl && p && typeof p.then === 'function') {
        inflight[k] = p;
        p.then(function (v) {
          cache[k] = { t: Date.now(), v: v };
          try {
            if (typeof sowNickIndex_ === 'function') {
              if (name === 'listSows' || name === 'getSowBoard' || name === 'getDueList') sowNickIndex_(v && (v.rows || v.items || v.sows || v.list || v));
              else if (name === 'getSowCard' && v) sowNickIndex_([v]);
              else if (name === 'getBootstrap' && v) sowNickIndex_(v.sows || v.rows || []);
            }
          } catch (eN) {}
        }, function () {}).then(function () { if (inflight[k] === p) delete inflight[k]; });
      }
      if (INVAL[name] && p && typeof p.then === 'function') {
        p.then(function () {
          var keys = Object.keys(cache), i;
          for (i = 0; i < keys.length; i++) {
            var n = keys[i].split(':')[0];
            if (n !== 'getFarmStructure' || name === 'editStructure' || name === 'updateSettings') {
              if (n === 'getFarmMemo' && name !== 'saveFarmMemo') continue;
              delete cache[keys[i]];
            }
          }
        }, function () {});
      }
      return p;
    };
    w._n7c = 1;
    return w;
  }
  if (typeof apiF === 'function') apiF = wrap(apiF);
  if (typeof apiR === 'function') apiR = wrap(apiR);
  if (typeof window !== 'undefined') {
    if (typeof window.apiF === 'function' && !window.apiF._n7c) window.apiF = apiF;
    if (typeof window.apiR === 'function' && !window.apiR._n7c) window.apiR = apiR;
  }
  n7ApiCacheHook_._on = 1;
}
function n7P2Boot_() {
  try { n7ApiCacheHook_(); } catch (eC) {}
  try { n7Splash_(); } catch (eSp) {}
  try { n7ProdCopy_(); } catch (ePc) {} try { n7LoginLogo_(); } catch (eLg) {}
  if (n7P2Boot_._on) return;
  n7P2Boot_._on = 1;
  try { n7I18nShort_(); } catch (e) {}
  try { n7HookLeave_(); } catch (e) {}
  try { n7WrapWeeklyStock_(); } catch (eWs) {} try { n7HookEntryKeys_(); } catch (eEk) {} try { n7MatingConfirm_(); } catch (eMc) {} try { n7HookProg_(); } catch (ePg) {} try { n7HookIlbo_(); } catch (e) {}
  try { n7HookFarmWeek_(); } catch (eFw) {}
  try { n7HookFarFix_(); } catch (eFf) {}
  (function retryHooks() {
    var n = 0;
    (function tick() {
      try { n7WrapWeeklyStock_(); } catch (eWs) {} try { n7HookEntryKeys_(); } catch (eEk) {} try { n7MatingConfirm_(); } catch (eMc) {} try { n7HookProg_(); } catch (ePg) {} try { n7HookIlbo_(); } catch (e1) {}
      try { n7HookFarmWeek_(); } catch (e2) {}
      try { n7HookFarFix_(); } catch (e2b) {}
      try { n7ProdCopy_(); } catch (e3) {}
      if ((n += 1) < 80) setTimeout(tick, 50);
    })();
  })();
  try { n7WebMobileAsk_(); } catch (e) {}
  try { n7FieldHead_(); } catch (e) {}
  try { n7HookEntryDate_(); } catch (e) {}
  try { n7AriaInputs_(document); } catch (e) {}
  try { n7FoldLong_(document); } catch (e) {}
  if (!n7P2Boot_._fw) {
    n7P2Boot_._fw = 1;
    var n = 0, t = setInterval(function () {
      try { n7FieldHead_(); } catch (e) {}
      if (document.getElementById('n7-field-gear') || (n += 1) > 50) clearInterval(t);
    }, 400);
  }
  document.addEventListener('click', function () {
    setTimeout(function () {
      try { n7AriaInputs_(document); } catch (e) {}
      try { n7FoldLong_(document); } catch (e) {}
      try { n7FieldHead_(); } catch (e) {}
      try { n7HookEntryDate_(); } catch (e) {}
    }, 200);
  }, true);
}
function n7I18nShort_() {
  var pack = (typeof I18N === 'object' && I18N) ? (I18N[typeof lang === 'function' ? lang() : 'ko'] || I18N.ko) : null;
  if (pack) {
    pack['e.date.futureMax'] = '미래 날짜는 저장할 수 없어요';
    pack['e.sess.issue'] = '로그인 세션을 만들지 못했습니다. 잠시 뒤 다시 하세요';
  }
}
function n7Ask_(opts) {
  opts = opts || {};
  var old = document.getElementById('n7-ask');
  if (old) old.remove();
  var wrap = document.createElement('div');
  wrap.id = 'n7-ask';
  wrap.className = 'n7-ask';
  wrap.innerHTML = '<div class="n7-ask-c" role="dialog" aria-modal="true"><h3>' + n7Esc_(opts.title || '확인') + '</h3><p>' + n7Esc_(opts.body || '') + '</p>'
    + (opts.input ? '<textarea id="n7-ask-in" placeholder="' + n7Esc_(opts.ph || '') + '"></textarea>' : '')
    + '<div class="row"><button type="button" class="btn sec" data-k="no">' + n7Esc_(opts.no || '닫기') + '</button>'
    + '<button type="button" class="btn" data-k="yes">' + n7Esc_(opts.yes || '확인') + '</button></div></div>';
  document.body.appendChild(wrap);
  var done = false;
  function close(v) {
    if (done) return;
    done = true;
    wrap.remove();
    if (typeof opts.done === 'function') opts.done(v);
  }
  wrap.addEventListener('click', function (e) {
    var b = e.target.closest && e.target.closest('[data-k]');
    if (!b) { if (e.target === wrap) close(null); return; }
    if (b.getAttribute('data-k') === 'no') { close(null); return; }
    var v = true;
    if (opts.input) {
      var inp = wrap.querySelector('#n7-ask-in');
      v = ((inp && inp.value) || '').trim();
      if (!v) { if (inp) inp.focus(); return; }
    }
    close(v);
  });
}
function n7HookLeave_() {
  if (typeof leaveOk_ !== 'function' || leaveOk_._n7) return;
  var _pending = null;
  function wrapNav(fn) {
    if (typeof fn !== 'function' || fn._n7lv) return fn;
    var _f = fn;
    var w = function () {
      var ctx = this, args = arguments;
      _pending = function () { return _f.apply(ctx, args); };
      return _f.apply(ctx, args);
    };
    w._n7lv = 1;
    return w;
  }
  if (typeof go === 'function') go = wrapNav(go);
  if (typeof goPage === 'function') goPage = wrapNav(goPage);
  if (typeof goView === 'function') goView = wrapNav(goView);
  if (typeof fHome === 'function') fHome = wrapNav(fHome);
  var _ok = leaveOk_;
  leaveOk_ = function () {
    if (typeof formDirty_ === 'function' && !formDirty_()) return true;
    var resume = _pending;
    n7Ask_({
      title: '저장하지 않은 기록',
      body: '쓰던 기록이 저장되지 않았습니다. 버리고 나갈까요?',
      yes: '버리기',
      no: '남기기',
      done: function (ok) {
        if (!ok) return;
        [].forEach.call(document.querySelectorAll('[data-efdirty]'), function (f) { f.removeAttribute('data-efdirty'); });
        if (typeof resume === 'function') resume();
      }
    });
    return false;
  };
  leaveOk_._n7 = 1;
}
function n7CanIlboConfirm_() {
  var u = window.PL && PL.user;
  if (!u) return false;
  return u.role === '농장주' || u.role === '관리자' || u.mgr === true || u.grade === '관리자';
}
function n7CanIlboCancel_() {
  var u = window.PL && PL.user;
  return !!(u && u.role === '농장주');
}
function n7IlboFmt_(at) {
  var s = String(at || '');
  if (s.length >= 16) return s.slice(5, 16).replace('-', '-');
  return s;
}

function n7ProgField_(k) {
  return ({ group: '대상군', kind: '종류', vaccine: '백신', name: '이름', basis: '기준', days: '시작 일수', to: '끝 일수', dose: '용량', unit: '단위', active: '사용' }[k] || k);
}
function n7ProgPanel_(el, r) {
  if (!el || !r) return;
  var old = el.querySelector('#n7-prog-x');
  if (old) old.remove();
  var box = document.createElement('div');
  box.id = 'n7-prog-x';
  box.className = 'card';
  box.style.marginTop = '12px';
  var asof = (typeof today === 'function' ? today() : '') || '';
  var rows = (r.rows || []).filter(function (p) { return p.active !== false; });
  var props = r.proposals || [];
  if (typeof props === 'string') try { props = JSON.parse(props); } catch (e0) { props = []; }
  if (!Array.isArray(props)) props = [];
  var can = !!r.canEdit && (typeof isOwner === 'function' ? isOwner() : true);
  function laneHTML(list, asOf) {
    var by = {}, order = [];
    list.forEach(function (p) {
      var g = p.group || '기타';
      if (!by[g]) { by[g] = []; order.push(g); }
      by[g].push(p);
    });
    var max = 14;
    list.forEach(function (p) { var n = Math.max(Number(p.to) || 0, Number(p.days) || 0); if (n > max) max = n; });
    max = Math.max(14, Math.ceil((max + 3) / 7) * 7);
    var ticks = '', i;
    for (i = 0; i <= max; i += 7) ticks += '<span style="position:absolute;left:' + ((i / max) * 100) + '%;transform:translateX(-50%);font-size:11px;color:var(--mut,#667)">' + i + '일</span>';
    var lanes = order.map(function (g) {
      var cells = (by[g] || []).map(function (p) {
        var a = Math.max(0, Number(p.days) || 0), b = Math.max(a, Number(p.to) || a);
        var left = (a / max) * 100, w = Math.max(3, ((b - a) / max) * 100);
        var lab = (p.vaccine || p.name || '') + (p.basis ? ' · ' + p.basis : '') + (a === b ? ' D+' + a : ' D+' + a + '~' + b);
        return '<span class="n7-lane-it" title="' + n7Esc_(lab) + '" style="left:' + left + '%;width:' + w + '%"></span>';
      }).join('');
      var labs = (by[g] || []).map(function (p) {
        var a = Math.max(0, Number(p.days) || 0), b = Math.max(a, Number(p.to) || a);
        return n7Esc_(p.vaccine || p.name || '') + (p.basis ? ' · ' + n7Esc_(p.basis) : '') + (a === b ? ' D+' + a : ' D+' + a + '~' + b);
      }).join(' · ');
      return '<div class="n7-lane-row"><div class="n7-lane-g">' + n7Esc_(g) + '</div><div class="n7-lane-main"><div class="n7-lane-tr">' + cells + '</div><div class="n7-lane-labs">' + labs + '</div></div></div>';
    }).join('') || '<p class="mut">표시할 프로그램이 없습니다.</p>';
    return '<div id="pg-lane" class="n7-lane"><div class="n7-lane-hd"><b>프로그램 모식</b><span class="mut">기준일 ' + n7Esc_(asOf || '') + ' · 숫자 = 기준일로부터의 일수</span></div>'
      + '<div class="n7-lane-axis">' + ticks + '</div>' + lanes + '</div>';
  }
  function changesHTML(ch, last) {
    if (!ch) return '<p class="mut">변동을 아직 불러오지 못했습니다.</p>';
    if (last == null && !(ch.added || []).length && !(ch.removed || []).length && !(ch.changed || []).length)
      return '<p class="mut">아직 확정한 적이 없습니다. 기준일을 확인하고 [프로그램 확정]을 누르면 첫 버전이 남습니다.</p>';
    if (!ch.has) return '<p class="mut">이전 확정(' + n7Esc_((last && (last.asOf || '').toString().slice(0, 10)) || '') + (last && last.by ? ' · ' + last.by : '') + ')과 같습니다.</p>';
    var bits = [];
    (ch.added || []).forEach(function (x) { bits.push('<li>추가 · ' + n7Esc_((x.group ? x.group + ' / ' : '') + (x.label || x.id)) + '</li>'); });
    (ch.removed || []).forEach(function (x) { bits.push('<li>삭제 · ' + n7Esc_((x.group ? x.group + ' / ' : '') + (x.label || x.id)) + '</li>'); });
    (ch.changed || []).forEach(function (x) { bits.push('<li>변경 · ' + n7Esc_(x.label || x.id) + ' · ' + n7Esc_(n7ProgField_(x.field)) + ' ' + n7Esc_(String(x.old)) + ' → ' + n7Esc_(String(x.new)) + '</li>'); });
    return '<p class="mut">이전 확정' + (last && last.asOf ? ' ' + n7Esc_(String(last.asOf).slice(0, 10)) : '') + ' 대비</p><ul class="n7-prog-ch">' + bits.join('') + '</ul>';
  }
  function propHTML() {
    if (!props.length) return '';
    if (!can) return '<div class="flag">수의사 제안 ' + props.length + '건이 승인을 기다립니다.</div>';
    return '<h3>수의사 제안 · 확정</h3><div class="tw"><table class="t">' + props.map(function (p) {
      var body = p.body || p['내용'] || p.content || '';
      var name = p.name || p['제안자'] || p.by || '';
      var at = p.at || p['제안일시'] || '';
      var id = p.id || p.key || p['제안ID'] || '';
      return '<tr data-prop="' + n7Esc_(id) + '"><td>' + n7Esc_(name) + '</td><td class="mut">' + n7Esc_(String(at).slice(0, 16)) + '</td><td><button type="button" class="btn sm" data-pyes>승인</button> <button type="button" class="btn sm sec" data-pno>거절</button></td></tr>';
    }).join('') + '</table></div>';
  }
  box.innerHTML = '<style>'
    + '.n7-lane{padding:8px 0}.n7-lane-hd{display:flex;justify-content:space-between;gap:8px;flex-wrap:wrap;margin-bottom:8px}'
    + '.n7-lane-axis{position:relative;height:16px;margin:0 0 6px 110px;border-bottom:1px solid var(--line,#d5e0d8)}'
    + '.n7-lane-row{display:flex;align-items:flex-start;gap:8px;margin:8px 0}'
    + '.n7-lane-g{width:102px;flex:none;font-size:13px;padding-top:4px}'
    + '.n7-lane-main{flex:1;min-width:0}'
    + '.n7-lane-tr{position:relative;height:16px;background:#f4f7f5;border-radius:8px}'
    + '.n7-lane-it{position:absolute;top:2px;bottom:2px;min-width:10px;background:#1f6f43;border-radius:6px}'
    + '.n7-lane-labs{margin-top:4px;font-size:12px;line-height:1.4;color:var(--ink,#123);word-break:keep-all;white-space:normal}'
    + '.n7-prog-ch{margin:6px 0 0 1.1em;padding:0}'
    + '@media print{body *{visibility:hidden!important}#pg-lane,#pg-lane *{visibility:visible!important}#pg-lane{position:absolute;left:12px;top:12px;right:12px}}'
    + '