/* /Components/Layout/AdminNoticeProposer.razor.rz.scp.css */
/* AdminNoticeProposer — messenger layout, scoped. MudButton/MudIcon internals via ::deep. no !important. */
.np[b-7bebbaqaxq] {
    display: grid;
    grid-template-columns: 1fr 240px;
    /* 🔴 행 정의는 필수다. 생략하면 암묵 행이 auto(=max-content) 로 잡히고, `1fr` 도 minmax(auto,1fr) 이라
       최소값이 콘텐츠라 **행이 콘텐츠보다 작아질 수 없다**. 본문(.tl)에 메시지가 쌓이면 그만큼 행이 커져
       .np-main 이 .np 를 밀어내고, 하단 버튼줄·컴포저가 패널 밖으로 나가 .fdr-panel 의 overflow:hidden 에 잘린다.
       (.tl 의 overflow:auto 도 이때는 무력하다 — 부모 행의 최소 크기가 콘텐츠라 스크롤이 생기지 않고 밀린다.)
       minmax(0,1fr) 이라야 최소값이 0이 되어 행이 컨테이너 높이에 고정되고, 그제서야 .tl 이 스크롤을 흡수한다. */
    grid-template-rows: minmax(0, 1fr);
    flex: 1;
    min-height: 0;
    height: 100%;
}
.np-main[b-7bebbaqaxq] { display: flex; flex-direction: column; min-height: 0; min-width: 0; }
.np-hd-ico[b-7bebbaqaxq] { font-size: 16px; line-height: 1; }

/* small action row above the composer while the notice is running */
.np-actions[b-7bebbaqaxq] {
    flex-shrink: 0;
    display: flex; gap: 8px; padding: 8px 16px 0;
    border-top: 1px solid var(--mud-palette-lines-default, #e2e8f0);
    background: #fff;
}
.np-actions[b-7bebbaqaxq]  .np-btn {
    flex: 1;
    height: 32px;
    border-radius: 10px;
    font-weight: 700;
    font-size: 12.5px;
    text-transform: none;
    letter-spacing: normal;
    box-shadow: none;
    transition: transform 150ms ease-out, opacity 150ms ease-out;
}
.np-actions[b-7bebbaqaxq]  .np-btn:hover:not(.mud-disabled) { transform: translateY(-1px); }
.np-actions[b-7bebbaqaxq]  .np-btn.mud-disabled { opacity: 0.45; }
.np-actions[b-7bebbaqaxq]  .np-btn-danger { border-width: 1.5px; background: rgba(211, 47, 47, 0.06); }

/* composer */
.np-composer[b-7bebbaqaxq] {
    min-height: 64px;   /* 1줄 상태 최소 높이 — 내용(1줄 박스 40.9px)+상하 패딩 16px 이 이보다 작아 겉모습 불변 */
    display: flex;
    align-items: center;
    padding: 8px 16px;  /* 세로 8px: 여러 줄로 커진 박스가 패널 하단 모서리에 맞닿지 않게 (1줄에선 min-height 안이라 무영향) */
    box-sizing: border-box;
    background: #fff;
    flex-shrink: 0;
}
.np-main > .np-composer:first-of-type[b-7bebbaqaxq] { border-top: 1px solid var(--mud-palette-lines-default, #e2e8f0); }

/* 입력 박스의 시각 껍데기는 textarea 가 아니라 wrap 이 담당한다 (2026-08-26).
   🔴 이유: textarea 의 상하 padding 은 스크롤 영역 **안**에 있어서, 내용이 rows 상한(4)을 넘겨 스크롤이 생기면
   브라우저가 캐럿 줄을 스크롤포트 바닥까지만 보이게 스크롤한다 → padding-bottom 이 화면 밖으로 밀려
   마지막 줄이 테두리에 붙는다. 패딩을 wrap(스크롤 밖)으로 옮기면 위아래 여백이 스크롤과 무관하게 항상 보인다. */
.np-input-wrap[b-7bebbaqaxq] {
    position: relative; flex: 1; display: flex; align-items: center;
    padding: 10px 0;                  /* 1줄 상태: 구 .np-input 상하 padding 10px 과 동일 → 픽셀 불변 */
    border: 1px solid var(--mud-palette-lines-default, #cbd5e1);
    border-radius: 20px;
    background: #f8fafc;
    transition: border-color 150ms ease-out, background-color 150ms ease-out;
}
.np-input-wrap:focus-within[b-7bebbaqaxq] { border-color: var(--mud-palette-primary); background: #fff; }
/* 여러 줄(rows≥2)에서만 상하 여백 확대 (오너 요청 "쉬프트 엔터로 키울 땐 위아래 여백") — razor 가 InputRows>1 로 토글 */
.np-input-wrap.multi[b-7bebbaqaxq] { padding-top: 14px; padding-bottom: 14px; }
.np-input[b-7bebbaqaxq] {
    flex: 1;
    width: 100%;
    box-sizing: border-box;
    resize: none;
    padding: 0 48px 0 14px;           /* 상하 0 — 세로 여백은 wrap 담당(스크롤에 안 쓸려감). 높이는 rows(≤4)가 제한 */
    border: none;
    background: transparent;
    font: inherit;
    font-size: 13.5px;
    line-height: 1.4;
    overflow: auto;
}
.np-input:focus[b-7bebbaqaxq] { outline: none; }
.np-send[b-7bebbaqaxq] {
    all: unset;
    position: absolute;
    right: 5px;
    top: 50%;
    transform: translateY(-50%);
    width: 32px; height: 32px;
    border-radius: 50%;
    display: inline-flex; align-items: center; justify-content: center;
    background: var(--mud-palette-primary);
    color: #fff;
    font-size: 15px;
    cursor: pointer;
    transition: opacity 150ms ease-out, transform 150ms ease-out;
}
.np-send:hover:not(:disabled)[b-7bebbaqaxq] { transform: translateY(-50%) scale(1.06); }
.np-send:disabled[b-7bebbaqaxq] { opacity: 0.35; cursor: default; }
.np-send:focus-visible[b-7bebbaqaxq] { outline: 2px solid var(--mud-palette-primary); outline-offset: 2px; }

/* sidebar */
.np-side[b-7bebbaqaxq] {
    display: flex;
    flex-direction: column;
    min-height: 0;
    background: #f8fafc;
    border-left: 1px solid var(--mud-palette-lines-default, #e2e8f0);
}
.np-side-head[b-7bebbaqaxq] {
    display: flex; align-items: center; justify-content: space-between; gap: 8px;
    height: 44px; padding: 0 12px 0 16px; box-sizing: border-box;
    border-bottom: 1px solid var(--mud-palette-lines-default, #e2e8f0);
}
.np-side-title[b-7bebbaqaxq] { font-size: 12.5px; font-weight: 700; color: #475569; font-variant-numeric: tabular-nums; }
.np-side-chip[b-7bebbaqaxq] {
    font-size: 11.5px; font-weight: 700; padding: 2px 8px; border-radius: 999px;
    background: #fff7e6; color: #b45309; border: 1px solid #fde9c0;
    font-variant-numeric: tabular-nums;
    transition: background-color 200ms ease-out, color 200ms ease-out, border-color 200ms ease-out;
}
.np-side-chip.done[b-7bebbaqaxq] { background: #16a34a; color: #fff; border-color: #16a34a; }
.np-side-empty[b-7bebbaqaxq] {
    margin: auto; padding: 0 16px;
    font-size: 12.5px; color: #94a3b8; text-align: center; text-wrap: balance;
    display: flex; flex-direction: column; gap: 6px; align-items: center;
}
.np-side-empty span[b-7bebbaqaxq] { font-size: 22px; line-height: 1; }

.np-members[b-7bebbaqaxq] { list-style: none; margin: 0; padding: 8px; overflow: auto; flex: 1; min-height: 0; }

/* member row: whole row changes on confirm (tint + 3px left bar + avatar badge + colored label) */
.np-member[b-7bebbaqaxq] {
    display: flex; align-items: center; gap: 10px;
    padding: 6px 8px 6px 9px; margin-bottom: 2px;
    border-radius: 10px;
    border-left: 3px solid transparent;
    transition: background-color 200ms ease-out, border-color 200ms ease-out;
}
.np-member:hover[b-7bebbaqaxq] { background: rgba(15, 23, 42, 0.04); }
.np-member.confirm[b-7bebbaqaxq] { background: #ecfdf3; border-left-color: #22c55e; animation: npPop-b-7bebbaqaxq 250ms ease-out; }
.np-member.confirm:hover[b-7bebbaqaxq] { background: #e1fbe9; }
@keyframes npPop-b-7bebbaqaxq { 0% { transform: scale(1); } 50% { transform: scale(1.03); } 100% { transform: scale(1); } }

.np-avatar-wrap[b-7bebbaqaxq] { position: relative; flex-shrink: 0; width: 30px; height: 30px; }
.np-avatar[b-7bebbaqaxq] {
    width: 30px; height: 30px; border-radius: 50%;
    display: inline-flex; align-items: center; justify-content: center;
    color: #fff; font-weight: 800; font-size: 12px;
    transition: filter 200ms ease-out, opacity 200ms ease-out;
}

/* avatar badge (bottom-right): check (MudIcon), waiting dots, online dot */
.np-badge[b-7bebbaqaxq] {
    position: absolute; right: -5px; bottom: -4px;
    width: 18px; height: 18px; border-radius: 50%;
    display: inline-flex; align-items: center; justify-content: center;
    box-shadow: 0 0 0 2px #f8fafc;
}
.np-badge.confirm[b-7bebbaqaxq] { background: #16a34a; color: #fff; }
.np-badge[b-7bebbaqaxq]  .mud-icon-root { width: 13px; height: 13px; font-size: 13px; }
.np-badge.online[b-7bebbaqaxq] { width: 10px; height: 10px; right: -1px; bottom: -1px; background: #22c55e; animation: npPulse-b-7bebbaqaxq 1.6s ease-out infinite; }
.np-badge.wait[b-7bebbaqaxq] { width: auto; height: 14px; padding: 0 4px; gap: 2px; border-radius: 999px; background: #fff7e6; color: #b45309; right: -8px; }
.np-badge.wait i[b-7bebbaqaxq] { width: 4px; height: 4px; border-radius: 50%; background: currentColor; opacity: 0.35; animation: npBlink-b-7bebbaqaxq 1.2s ease-out infinite; }
.np-badge.wait i:nth-child(2)[b-7bebbaqaxq] { animation-delay: 0.2s; }
.np-badge.wait i:nth-child(3)[b-7bebbaqaxq] { animation-delay: 0.4s; }
@keyframes npPulse-b-7bebbaqaxq {
    0%   { transform: scale(0.9); opacity: 1; }
    70%  { transform: scale(1.25); opacity: 0.55; }
    100% { transform: scale(0.9); opacity: 1; }
}
@keyframes npBlink-b-7bebbaqaxq { 0%, 100% { opacity: 0.35; } 40% { opacity: 1; } }

.np-name[b-7bebbaqaxq] { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 13px; font-weight: 600; color: #1e293b; }
.np-label[b-7bebbaqaxq] { font-size: 12px; font-weight: 500; white-space: nowrap; flex-shrink: 0; color: #94a3b8; transition: color 200ms ease-out; }
.np-label.confirm[b-7bebbaqaxq] { color: #15803d; }
.np-label.wait[b-7bebbaqaxq]   { color: #b45309; }
.np-label.online[b-7bebbaqaxq] { color: #15803d; }

/* dock */
.dk-ico[b-7bebbaqaxq] { font-size: 16px; line-height: 1; }
.dk-title[b-7bebbaqaxq] { font-weight: 700; font-size: 13px; white-space: nowrap; }
.dk-people[b-7bebbaqaxq] { display: inline-flex; align-items: center; gap: 1px; overflow: hidden; }
.dk-p[b-7bebbaqaxq] { position: relative; display: inline-flex; width: 20px; height: 20px; align-items: center; justify-content: center; }
.dk-p[b-7bebbaqaxq]  .dk-ov {
    position: absolute; right: -3px; bottom: -2px;
    width: 11px; height: 11px; font-size: 11px; border-radius: 50%;
    color: #fff; box-shadow: 0 0 0 1.5px #fff;
}
.dk-p.confirm[b-7bebbaqaxq]  .dk-ov { background: #16a34a; }
.dk-count[b-7bebbaqaxq] { font-size: 12.5px; font-weight: 800; font-variant-numeric: tabular-nums; color: #1b2038; white-space: nowrap; }

@media (max-width: 720px) {
    .np[b-7bebbaqaxq] { grid-template-columns: 1fr; grid-template-rows: minmax(0, 1fr) auto; }   /* 1fr = minmax(auto,1fr) 이라 콘텐츠 바닥이 남는다 */
    .np-side[b-7bebbaqaxq] { border-left: none; border-top: 1px solid var(--mud-palette-lines-default, #e2e8f0); max-height: 160px; }
}

@media (prefers-reduced-motion: reduce) {
    .np-badge.online[b-7bebbaqaxq], .np-badge.wait i[b-7bebbaqaxq], .np-member.confirm[b-7bebbaqaxq] { animation: none; }
    .np-send:hover:not(:disabled)[b-7bebbaqaxq] { transform: translateY(-50%); }
    .np-actions[b-7bebbaqaxq]  .np-btn:hover:not(.mud-disabled) { transform: none; }
}
/* /Components/Layout/AdminNoticeReceiver.razor.rz.scp.css */
/* AdminNoticeReceiver — messenger tone, scoped. MudButton internals via ::deep. no !important. */
.nr[b-cnzof9czo7] { display: flex; flex-direction: column; flex: 1; min-height: 0; height: 100%; }
.nr-hd-ico[b-cnzof9czo7] { font-size: 16px; line-height: 1; }

/* composer */
.nr-composer[b-cnzof9czo7] {
    min-height: 56px; flex-shrink: 0;   /* 1줄 최소 높이 — 내용(36.9px)+상하 패딩 16px 이 이보다 작아 겉모습 불변 */
    display: flex; align-items: center;
    padding: 8px 16px; box-sizing: border-box;
    border-top: 1px solid var(--mud-palette-lines-default, #e2e8f0);
    background: #fff;
}
/* 시각 껍데기는 wrap 담당 — 스크롤 상태에서도 위아래 여백 유지 (공지자 창 .np-input-wrap 주석 참조) */
.nr-input-wrap[b-cnzof9czo7] {
    position: relative; flex: 1; display: flex; align-items: center;
    padding: 8px 0;                    /* 1줄 상태: 구 .nr-input 상하 padding 8px 과 동일 */
    border: 1px solid var(--mud-palette-lines-default, #cbd5e1);
    border-radius: 18px; background: #f8fafc;
    transition: border-color 150ms ease-out, background-color 150ms ease-out;
}
.nr-input-wrap:focus-within[b-cnzof9czo7] { border-color: var(--mud-palette-primary); background: #fff; }
.nr-input-wrap.multi[b-cnzof9czo7] { padding-top: 14px; padding-bottom: 14px; }
.nr-input[b-cnzof9czo7] {
    flex: 1; width: 100%; box-sizing: border-box; resize: none;
    padding: 0 44px 0 14px;            /* 상하 0 — 세로 여백은 wrap 담당. 높이는 rows(≤3)가 제한 */
    border: none; background: transparent;
    font: inherit; font-size: 13.5px; line-height: 1.4; overflow: auto;
}
.nr-input:focus[b-cnzof9czo7] { outline: none; }
.nr-send[b-cnzof9czo7] {
    all: unset; position: absolute; right: 5px; top: 50%; transform: translateY(-50%);
    width: 28px; height: 28px; border-radius: 50%;
    display: inline-flex; align-items: center; justify-content: center;
    background: var(--mud-palette-primary); color: #fff; font-size: 13px; cursor: pointer;
    transition: opacity 150ms ease-out, transform 150ms ease-out;
}
.nr-send:hover:not(:disabled)[b-cnzof9czo7] { transform: translateY(-50%) scale(1.06); }
.nr-send:disabled[b-cnzof9czo7] { opacity: 0.35; cursor: default; }
.nr-send:focus-visible[b-cnzof9czo7] { outline: 2px solid var(--mud-palette-primary); outline-offset: 2px; }

.nr-avatar[b-cnzof9czo7] {
    width: 32px; height: 32px; border-radius: 50%; flex-shrink: 0;
    display: inline-flex; align-items: center; justify-content: center;
    color: #fff; font-weight: 800; font-size: 13px;
}
.nr-avatar-sm[b-cnzof9czo7] { width: 26px; height: 26px; font-size: 11px; }

/* bottom bar: one full-width confirm button, or the confirmed state */
.nr-btns[b-cnzof9czo7] {
    display: grid; grid-template-columns: 1fr; gap: 8px;
    height: 56px; box-sizing: border-box; padding: 8px 16px; flex-shrink: 0;
    border-top: 1px solid var(--mud-palette-lines-default, #e2e8f0);
    background: #fff;
}
.nr-state[b-cnzof9czo7] {
    display: flex; align-items: center; justify-content: center;
    border-radius: 12px; font-size: 12.5px; font-weight: 700; text-wrap: balance; text-align: center;
}
.nr-state.confirm[b-cnzof9czo7] { background: #ecfdf3; color: #15803d; }

.nr-btns[b-cnzof9czo7]  .nr-btn,
.nr-dk-btns[b-cnzof9czo7]  .nr-btn {
    height: 40px; border-radius: 12px; font-weight: 700; font-size: 13.5px;
    text-transform: none; letter-spacing: normal; box-shadow: none;
    transition: transform 150ms ease-out;
}
.nr-btns[b-cnzof9czo7]  .nr-btn:hover,
.nr-dk-btns[b-cnzof9czo7]  .nr-btn:hover { transform: translateY(-1px); }

/* dock */
.nr-dk-from[b-cnzof9czo7] { font-weight: 700; font-size: 13px; white-space: nowrap; }
.nr-dk-msg[b-cnzof9czo7] { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 12.5px; color: #475569; }
.nr-dk-btns[b-cnzof9czo7] { display: inline-flex; gap: 6px; flex-shrink: 0; align-items: center; }
.nr-dk-btns[b-cnzof9czo7]  .nr-btn-sm { height: 32px; min-width: 0; padding: 0 10px; border-radius: 10px; font-size: 15px; }
.nr-dk-state[b-cnzof9czo7] { font-size: 15px; }

@media (prefers-reduced-motion: reduce) {
    .nr-btns[b-cnzof9czo7]  .nr-btn:hover, .nr-dk-btns[b-cnzof9czo7]  .nr-btn:hover { transform: none; }
    .nr-send:hover:not(:disabled)[b-cnzof9czo7] { transform: translateY(-50%); }
}
/* /Components/Layout/AdminNoticeTimeline.razor.rz.scp.css */
/* AdminNoticeTimeline — scoped. column-reverse keeps the scroll pinned to the newest message without JS. */
.tl[b-1m3lksi90v] {
    flex: 1;
    min-height: 0;
    overflow: auto;
    padding: 16px;
    display: flex;
    flex-direction: column-reverse;
    gap: 8px;
    background: #fff;
}
.tl-empty[b-1m3lksi90v] { margin: auto; color: #94a3b8; font-size: 13px; text-align: center; text-wrap: balance; }

.tl-msg[b-1m3lksi90v] { display: flex; max-width: 80%; gap: 8px; }
.tl-msg.mine[b-1m3lksi90v] { align-self: flex-end; flex-direction: column; align-items: flex-end; }
.tl-msg.theirs[b-1m3lksi90v] { align-self: flex-start; align-items: flex-start; }
.tl-col[b-1m3lksi90v] { display: flex; flex-direction: column; min-width: 0; }

.tl-bubble[b-1m3lksi90v] {
    padding: 9px 12px;
    border-radius: 12px;
    font-size: 13.5px;
    line-height: 1.5;
    white-space: pre-wrap;
    overflow-wrap: anywhere;
    text-wrap: pretty;
    color: #1e293b;
}
.tl-msg.mine .tl-bubble[b-1m3lksi90v] { background: rgba(var(--mud-palette-primary-rgb), 0.12); border-bottom-right-radius: 4px; }
.tl-msg.theirs .tl-bubble[b-1m3lksi90v] { background: #f1f5f9; border-top-left-radius: 4px; }
.tl-msg.notice .tl-bubble[b-1m3lksi90v] { border: 1px solid rgba(var(--mud-palette-primary-rgb), 0.35); }

.tl-name[b-1m3lksi90v] { font-size: 11.5px; font-weight: 700; color: #475569; margin-bottom: 3px; }
.tl-time[b-1m3lksi90v] { font-size: 11px; color: #94a3b8; margin-top: 3px; font-variant-numeric: tabular-nums; }
.tl-avatar[b-1m3lksi90v] {
    width: 28px; height: 28px; border-radius: 50%; flex-shrink: 0; margin-top: 16px;
    display: inline-flex; align-items: center; justify-content: center;
    color: #fff; font-weight: 800; font-size: 12px;
}

.tl-sys[b-1m3lksi90v] {
    align-self: center;
    font-size: 12px;
    color: #64748b;
    text-align: center;
    padding: 2px 10px;
    border-radius: 999px;
    background: #f1f5f9;
    font-variant-numeric: tabular-nums;
}
.tl-sys.confirm[b-1m3lksi90v] { color: #15803d; background: #ecfdf3; }
/* /Components/Layout/DialogHeader.razor.rz.scp.css */
/* dialog drag handle (dialogDrag.js). no !important; scoped to .dialog-title only. */
.dialog-title[b-ykjz6lr8c4] {
    cursor: move;
    user-select: none;
    -webkit-user-select: none;
    touch-action: none;
}

.dialog-title.dialog-title--dragging[b-ykjz6lr8c4] {
    cursor: grabbing;
}

@media (max-width: 720px) {
    .dialog-title[b-ykjz6lr8c4] {
        cursor: default;
        touch-action: auto;
    }
}
/* /Components/Layout/DraggablePanel.razor.rz.scp.css */
/* DraggablePanel — scoped. z-index scale: panel 1500 / dock item inherits .fdr-dock-bar (1490, MainLayout). no !important. */
.fdr-panel[b-fpyyqome81] {
    position: fixed;
    /* default placement fallback (inline Style overrides). top >= appbar 56px + 16 so the header is never under the bar */
    top: 80px;
    left: 50%;
    margin-left: -360px;
    z-index: 1500;
    pointer-events: auto; /* guard: never inherit none from any ancestor rail/overlay */
    background: #fff;
    color: #1e293b;
    border: 1px solid var(--mud-palette-lines-default, #e2e8f0);
    border-radius: 12px;
    box-shadow: 0 10px 15px -3px rgba(15, 23, 42, 0.12), 0 4px 6px -4px rgba(15, 23, 42, 0.10);
    max-width: calc(100vw - 16px);
    max-height: calc(100dvh - 16px);
    display: flex;
    flex-direction: column;
    overflow: hidden;
    font-size: 13.5px;
    animation: fdrPanelIn-b-fpyyqome81 0.18s ease-out;
}

@keyframes fdrPanelIn-b-fpyyqome81 {
    from { opacity: 0; transform: translateY(6px); }
    to   { opacity: 1; transform: none; }
}

/* header: muted navy tint (galaxy appbar family, flat — no gradient) */
.fdr-panel-head[b-fpyyqome81] {
    display: flex;
    align-items: center;
    gap: 8px;
    height: 48px;
    padding: 0 8px 0 16px;
    box-sizing: border-box;
    background: #eef0f7;
    color: #1b2038;
    border-bottom: 1px solid var(--mud-palette-lines-default, #e2e8f0);
    font-weight: 700;
    font-size: 14px;
    cursor: grab;
    user-select: none;
    -webkit-user-select: none;
    touch-action: none;
    flex-shrink: 0;
}

.fdr-panel-head.dialog-title--dragging[b-fpyyqome81],
.fdr-panel-head:active[b-fpyyqome81] { cursor: grabbing; }

.fdr-panel-title[b-fpyyqome81] { flex: 1; text-wrap: balance; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* icon buttons in header (minimize / close) */
.fdr-panel-ib[b-fpyyqome81] {
    all: unset;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 30px;
    height: 30px;
    border-radius: 8px;
    color: #4b5577;
    transition: background-color 150ms ease-out, color 150ms ease-out;
}
.fdr-panel-ib:hover[b-fpyyqome81] { background: rgba(27, 32, 56, 0.08); color: #1b2038; }
.fdr-panel-ib:focus-visible[b-fpyyqome81] { outline: 2px solid var(--mud-palette-primary); outline-offset: 1px; }

/* body is flush — children own their padding (messenger grid needs edge-to-edge columns) */
.fdr-panel-body[b-fpyyqome81] { padding: 0; overflow: hidden; display: flex; flex-direction: column; min-height: 0; flex: 1; }

/* ── dock item (minimized) ── */
.fdr-dock[b-fpyyqome81] {
    display: flex;
    align-items: center;
    gap: 8px;
    height: 48px;
    padding: 0 10px 0 6px;
    background: #fff;
    color: #1e293b;
    border: 1px solid var(--mud-palette-lines-default, #e2e8f0);
    border-bottom: none;
    border-radius: 12px 12px 0 0;
    box-shadow: 0 -4px 12px rgba(15, 23, 42, 0.10);
    max-width: min(420px, 100vw);
    pointer-events: auto;
    animation: fdrDockIn-b-fpyyqome81 0.18s ease-out;
}

@keyframes fdrDockIn-b-fpyyqome81 {
    from { opacity: 0; transform: translateY(8px); }
    to   { opacity: 1; transform: none; }
}

.fdr-dock-restore[b-fpyyqome81] {
    all: unset;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    border-radius: 8px;
    color: #4b5577;
    flex-shrink: 0;
    transition: background-color 150ms ease-out;
}
.fdr-dock-restore:hover[b-fpyyqome81] { background: rgba(27, 32, 56, 0.08); }
.fdr-dock-restore[b-fpyyqome81] { position: relative; }
.fdr-dock-badge[b-fpyyqome81] {
    position: absolute; top: -4px; right: -6px;
    min-width: 16px; height: 16px; padding: 0 4px; box-sizing: border-box;
    border-radius: 999px; background: #d32f2f; color: #fff;
    font-size: 10px; font-weight: 800; line-height: 16px; text-align: center;
    font-variant-numeric: tabular-nums;
}
.fdr-dock-restore:focus-visible[b-fpyyqome81] { outline: 2px solid var(--mud-palette-primary); outline-offset: 1px; }

.fdr-dock-body[b-fpyyqome81] { display: flex; align-items: center; gap: 10px; min-width: 0; flex: 1; }

@media (max-width: 720px) {
    .fdr-dock[b-fpyyqome81] { max-width: none; width: 100%; border-radius: 0; }
}

@media (prefers-reduced-motion: reduce) {
    .fdr-panel[b-fpyyqome81], .fdr-dock[b-fpyyqome81] { animation: none; }
}
/* /Components/Layout/EditorWithImage.razor.rz.scp.css */
/* 블러 오버레이는 그대로 */
.ewi-overlay-fixed[b-d30zrm1buy] {
    position: fixed;
    inset: 0;
    background: rgba(255,255,255,.55);
    backdrop-filter: blur(3px);
    z-index: 100000;
    pointer-events: all; /* 클릭 막기 */
}

/* 🔵 스피너: 화면 중앙 고정 */
.ewi-spinner-fab[b-d30zrm1buy] {
    position: fixed;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%); /* 가로·세로 모두 중앙 보정 */
    z-index: 100001; /* 오버레이 위 */
    display: flex;
    align-items: center;
    gap: 10px;
    flex-direction: row;
    padding: 10px 14px;
    background: #fff;
    border-radius: 12px;
    box-shadow: 0 6px 24px rgba(0,0,0,.15);
    pointer-events: none; /* 클릭 통과 (원하면 all) */
}

.ewi-spinner[b-d30zrm1buy] {
    width: 28px;
    height: 28px;
    border: 3px solid #ddd;
    border-top-color: #666;
    border-radius: 50%;
    animation: ewi-spin-b-d30zrm1buy .8s linear infinite;
}

@keyframes ewi-spin-b-d30zrm1buy {
    to {
        transform: rotate(360deg);
    }
}
/* /Components/Layout/ListState.razor.rz.scp.css */
/* /Components/Layout/LoadingOverlay.razor.rz.scp.css */

/* loading ----------------------------------------------------------------------------------- */
.loading-overlay[b-h4pcci5rsc] {
    height: 100%; /* 다이얼로그 높이에 맞춰 적당히 */
    display: flex;
    top: 0;
    left: 0;
    min-height:30vh;
    width: 100%;
    height: 100%;
    display: flex;
    justify-content: center;
    align-items: center;
    z-index: 9999; /* 화면 위에 표시되도록 설정 */
}


.loading-inside[b-h4pcci5rsc] {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    display: flex;
    justify-content: center;
    align-items: center;
    z-index: 9999; /* 화면 위에 표시되도록 설정 */
}
.loading-spinner[b-h4pcci5rsc] {
    border: 16px solid #f3f3f3;
    border-radius: 50%;
    border-top: 16px solid var(--mud-palette-primary);
    width: 120px;
    height: 120px;
    animation: spin-b-h4pcci5rsc 2s linear infinite;
}

@keyframes spin-b-h4pcci5rsc {
    0% {
        transform: rotate(0deg);
    }

    100% {
        transform: rotate(360deg);
    }
}
/* /Components/Layout/MainLayout.razor.rz.scp.css */
@keyframes pulse-green-b-va5ec7765s {
    0% {
        transform: scale(0.95);
        box-shadow: 0 0 0 0 rgba(76, 175, 80, 0.7);
    }

    70% {
        transform: scale(1);
        box-shadow: 0 0 0 6px rgba(76, 175, 80, 0);
    }

    100% {
        transform: scale(0.95);
        box-shadow: 0 0 0 0 rgba(76, 175, 80, 0);
    }
}

.live-dot[b-va5ec7765s] {
    width: 8px;
    height: 8px;
    background-color: #4CAF50;
    border-radius: 50%;
    display: inline-block;
    margin-right: 8px;
    animation: pulse-green-b-va5ec7765s 2s infinite;
}

/* admin notice dock rail (bottom-right). z-index 1490 (< panel 1500). children = DraggablePanel dock items.
   NO pointer-events:none here: pointer-events is INHERITED, and the restored .fdr-panel (position:fixed) is a DOM child
   of this rail -> it inherited none and the whole panel stopped receiving drag/click/focus (2026-08-23 incident).
   The rail is sized by its in-flow dock items only (fixed panels are out of flow), so it never covers page content. */
.fdr-dock-bar[b-va5ec7765s] {
    position: fixed;
    right: 16px;
    bottom: env(safe-area-inset-bottom, 0);
    z-index: 1490;
    display: flex;
    flex-direction: row-reverse;
    align-items: flex-end;
    gap: 8px;
    width: max-content;
    max-width: 100vw;
}

@media (max-width: 720px) {
    .fdr-dock-bar[b-va5ec7765s] { right: 0; left: 0; width: auto; flex-direction: column-reverse; gap: 0; }
}

/* ── header presence popover (2026-08-25) ──────────────────────────────────────
   Replaces the ONLINE MudTooltip. Opens ON HOVER (owner, 2026-08-25) - and IN PLACE inside the app bar
   (like the Radzen profile dropdown), NOT via MudPopover: Mud popovers portal to MudPopoverProvider at
   the layout root, where neither this scoped stylesheet nor the surrounding tokens reach (this project
   already lost gaps/radii/text colour that way). The app bar must keep its "no overflow:hidden" rule
   for this panel to escape the 56px bar.

   Hover is judged on the WRAPPER, not the trigger: the panel is a DOM child of the wrapper, so moving
   the pointer trigger -> panel (or scrolling inside the 380px list) never leaves it and mouseleave
   never fires. The only dead zone is the 3px visual gap that sits OUTSIDE the wrapper box, and
   `.hdr-presence.open::after` bridges exactly that. A 260ms close delay is the third layer.
   Without these, hover would recreate the very failure the tooltip was replaced for.

   Gap and bridge are ONE PAIR: bridge height = gap + 1px overlap. Change one, change the other -
   a short bridge reopens the dead zone, a tall one eats into the 56px bar. */
.hdr-presence[b-va5ec7765s] {
    position: relative;
    align-self: stretch;      /* full toolbar height -> the panel can anchor to the BAR's bottom edge */
    display: flex;
    align-items: center;
    flex-shrink: 0;
}

/* invisible bridge across the 3px gap between the bar and the panel. Same width/edge as the panel so it
   never widens the hover area sideways. Lives on the WRAPPER, not the panel: the panel is overflow:hidden
   (it clips the head's square corners) and would have clipped a pseudo-element of its own away.
   Only while open - otherwise a strip under the bar would arm the popup on its own. */
.hdr-presence.open[b-va5ec7765s]::after {
    content: "";
    position: absolute;
    top: 100%;
    right: 0;
    width: 272px;
    max-width: calc(100vw - 24px);
    height: 4px;              /* = gap(3px) + 1px overlap, so no sub-pixel seam. Keep in step with the panel's top. */
}

/* trigger keeps the old pill's look; it is a real <button> now so Enter/Space/Tab work */
.hdr-presence-trigger[b-va5ec7765s] {
    display: inline-flex;
    align-items: center;
    gap: 0;
    height: 28px;
    padding: 0 12px;
    margin-right: 10px;
    border: 1px solid rgba(74, 222, 128, 0.35);
    border-radius: 999px;
    background-color: rgba(74, 222, 128, 0.10);
    backdrop-filter: blur(2px);
    color: #7ee2a8;
    font: inherit;
    cursor: help;             /* hover reveals; there is no click action to promise (owner, 2026-08-26) */
    -webkit-appearance: none;
    appearance: none;
    transition: background-color 160ms ease-out, border-color 160ms ease-out;
}
.hdr-presence-trigger:hover[b-va5ec7765s] { background-color: rgba(74, 222, 128, 0.18); border-color: rgba(74, 222, 128, 0.55); }
.hdr-presence-trigger[aria-expanded="true"][b-va5ec7765s] { background-color: rgba(74, 222, 128, 0.22); border-color: rgba(74, 222, 128, 0.65); }
.hdr-presence-trigger:focus-visible[b-va5ec7765s] { outline: 2px solid #a5f3c4; outline-offset: 2px; }

.hdr-presence-count[b-va5ec7765s] {
    font-size: 0.75rem;
    font-weight: 700;
    line-height: 1;
    letter-spacing: 0.5px;
    color: #7ee2a8;
    text-shadow: 0 0 8px rgba(74, 222, 128, 0.35);
    font-variant-numeric: tabular-nums;
}

/* The app bar sets color:#fff on itself, so EVERY colour in here is stated explicitly -
   inheriting white text onto a white card would render the list invisible. */
.hdr-presence-pop[b-va5ec7765s] {
    position: absolute;
    top: calc(100% + 3px);    /* owner 2026-08-26 "조금만 더 위로". Bar is 56px; 3px keeps its 1px border + shadow readable. */
    right: 0;
    z-index: 2;
    width: 272px;
    max-width: calc(100vw - 24px);
    max-height: min(60vh, 380px);
    display: flex;
    flex-direction: column;
    box-sizing: border-box;
    background: #ffffff;
    color: #1e293b;
    text-align: left;
    text-shadow: none;
    border: 1px solid #e2e8f0;
    border-radius: 14px;
    box-shadow: 0 18px 40px -12px rgba(15, 23, 42, 0.38), 0 4px 10px -4px rgba(15, 23, 42, 0.18);
    overflow: hidden;
    transform-origin: top right;
    animation: hppIn-b-va5ec7765s 170ms cubic-bezier(0.22, 1, 0.36, 1);
}
@keyframes hppIn-b-va5ec7765s {
    from { opacity: 0; transform: translateY(-6px) scale(0.97); }
    to   { opacity: 1; transform: none; }
}

.hpp-head[b-va5ec7765s] {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 8px;
    padding: 11px 14px 9px;
    border-bottom: 1px solid #e2e8f0;
    background: #f8fafc;
}
.hpp-title[b-va5ec7765s] { font-size: 12.5px; font-weight: 700; color: #334155; font-variant-numeric: tabular-nums; }
.hpp-sub[b-va5ec7765s] { font-size: 11.5px; font-weight: 600; color: #94a3b8; font-variant-numeric: tabular-nums; }
.hpp-sub.warn[b-va5ec7765s] { color: #b45309; }

.hpp-empty[b-va5ec7765s] {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 6px;
    padding: 22px 16px;
    font-size: 12.5px;
    color: #94a3b8;
    text-align: center;
    text-wrap: balance;
}
.hpp-empty span[aria-hidden][b-va5ec7765s] { font-size: 22px; line-height: 1; }

.hpp-list[b-va5ec7765s] { list-style: none; margin: 0; padding: 6px; overflow: auto; flex: 1; min-height: 0; }

.hpp-sep[b-va5ec7765s] {
    display: flex;
    align-items: center;
    gap: 8px;
    margin: 6px 4px 4px;
    font-size: 10.5px;
    font-weight: 700;
    letter-spacing: 0.6px;
    color: #b6c0cd;
}
.hpp-sep[b-va5ec7765s]::after { content: ""; flex: 1; height: 1px; background: #eef2f6; }

.hpp-row[b-va5ec7765s] {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 6px 8px;
    border-radius: 10px;
}
.hpp-row:hover[b-va5ec7765s] { background: rgba(15, 23, 42, 0.04); }

.hpp-av-wrap[b-va5ec7765s] { position: relative; flex-shrink: 0; width: 30px; height: 30px; }
/* same initial + colour rule as the ops board / notice panel (AdminNoticeService.Initial / AvatarColor) */
.hpp-av[b-va5ec7765s] {
    width: 30px;
    height: 30px;
    border-radius: 50%;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    color: #ffffff;
    font-weight: 800;
    font-size: 12px;
    line-height: 1;
}
.hpp-row.off .hpp-av[b-va5ec7765s] { filter: grayscale(1); opacity: 0.5; }

.hpp-dot[b-va5ec7765s] {
    position: absolute;
    right: -1px;
    bottom: -1px;
    width: 10px;
    height: 10px;
    border-radius: 50%;
    box-shadow: 0 0 0 2px #ffffff;
}
.hpp-dot.on[b-va5ec7765s] { background: #22c55e; animation: hppPulse-b-va5ec7765s 1.6s ease-out infinite; }
.hpp-dot.off[b-va5ec7765s] { background: #cbd5e1; }
@keyframes hppPulse-b-va5ec7765s {
    0%   { transform: scale(0.9); opacity: 1; }
    70%  { transform: scale(1.25); opacity: 0.55; }
    100% { transform: scale(0.9); opacity: 1; }
}

.hpp-name[b-va5ec7765s] {
    flex: 1;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-size: 13px;
    font-weight: 600;
    color: #1e293b;
}
.hpp-row.off .hpp-name[b-va5ec7765s] { color: #64748b; font-weight: 500; }

.hpp-state[b-va5ec7765s] { flex-shrink: 0; font-size: 12px; font-weight: 600; white-space: nowrap; font-variant-numeric: tabular-nums; }
.hpp-state.on[b-va5ec7765s] { color: #15803d; }
.hpp-state.off[b-va5ec7765s] { color: #94a3b8; font-weight: 500; }

@media (prefers-reduced-motion: reduce) {
    .hdr-presence-pop[b-va5ec7765s] { animation: none; }
    .hpp-dot.on[b-va5ec7765s] { animation: none; }
}

/* Full-bleed page wrapper (2026-08-24, ops board). Used INSTEAD of MudContainer for routes in
   MainLayout.FullBleedRoutes, so the page can use the whole area right of the drawer.
   No max-width and no side padding here: the page itself owns its gutters.
   Scoped to MainLayout - other screens keep the MudContainer path untouched. */
.fdr-fullbleed[b-va5ec7765s] {
    width: 100%;
    min-width: 0;
    margin: 0;
    padding: 0;
}
/* /Components/Layout/MessageBoxLayout.razor.rz.scp.css */
/* 블러 + 라운드 박스 */
.message-box.blur-box .mud-dialog[b-ejr469ok9o] {
    border-radius: 1rem !important; /* 16px */
}

/* 설명 */
.message-box-description[b-ejr469ok9o] {
    font-size: 0.8125rem; /* 13px */
    font-weight: 300;
    font-family: 'Pretendard Variable', Arial, sans-serif;
    text-align: center;
    padding: 0 0 1.25rem 0; /* 20px */
    white-space: normal; /* 줄바꿈 허용 */
    word-break: break-word; /* 단어가 길면 줄바꿈 */
    overflow: visible; /* 스크롤 막기 */
}
/* 본문 */
.message-box .message-box-content[b-ejr469ok9o] {
    font-size: 1.0625rem; /* 17px */
    text-align: center;
    font-weight: 600;
    color: rgba(0, 0, 0, 0.8);
    white-space: pre-line;
    padding: 0.875rem 1.25rem 0.625rem 1.25rem; /* 30 20 10 20 */
    font-family: 'Pretendard Variable', Arial, sans-serif;
}

/* 버튼 영역 */
.message-box .message-box-actions[b-ejr469ok9o] {
    justify-content: center;
    padding-bottom: 1rem; /* 16px */
    gap: 0.625rem; /* 10px */
    margin: 0.625rem; /* 10px */
}

/* 버튼 */
.message-box .message-box-btn[b-ejr469ok9o] {
    min-width: 6.25rem; /* 100px */
    font-family: 'Pretendard Variable', Arial, sans-serif;
    font-size: 1rem; /* 16px */
    font-weight: 600;
}
/* /Components/Layout/NavMenu.razor.rz.scp.css */
.mud-nav-link[b-ian7qkq1ye] {
    background-color: transparent;
}

.mud-navmenu[b-ian7qkq1ye] {
    background-color: transparent;
}

.mud-nav-link-text[b-ian7qkq1ye] {
    color: black;
}

.mud-navmenu.mud-navmenu-primary .mud-nav-link.active:not(.mud-nav-link-disabled)[b-ian7qkq1ye] {
    background-color: white;
}
/* /Components/Layout/PagingNav.razor.rz.scp.css */
.paging-nav[b-17nilg4vvj] { /* ���̾ƿ��� �ζ��� Style �⺻ ����, ���⼱ ���븸 */
}

.paging-btn[b-17nilg4vvj] {
    min-width: 36px;
}
/* /Components/Layout/PopupLayout.razor.rz.scp.css */
/* /Components/Pages/EmptyPage.razor.rz.scp.css */

body[b-6cp91sk29q] {
    background-color: #fff;
}

/* /Components/Pages/Home.razor.rz.scp.css */
.aaa[b-crxsuha5qy] {
    font-family:Roboto;
    font-weight:500;
    font-size:1rem;
}

body[b-crxsuha5qy] {
    background-color: #fff;
}
/* /Components/Pages/Login/Login.razor.rz.scp.css */
/* /Components/Pages/Manager/Admin/Admin.razor.rz.scp.css */

body[b-7pvipdi0zz] {
    background-color: #fff;
}


/* table ----------------------------------------------------------------------------------- */
.table-wrapper[b-7pvipdi0zz] {
    width: 100%;
    overflow-x: auto; /* 가로 스크롤 생성을 허용 */
}

table[b-7pvipdi0zz] {
    width: 100%;
    border-collapse: collapse; /* 테두리가 겹치지 않도록 설정 */
    /*min-width: 100px; 테이블이 일정 크기 이하로 줄어들지 않도록 설정 */
}

.main-table[b-7pvipdi0zz] {
}
.main-table td[b-7pvipdi0zz] {
    border: 1px solid #ddd; /* 셀의 테두리 설정 */
    padding: 15px; /* 셀 내부의 여백 설정 */
    text-align: left; /* 텍스트 정렬 */
}


/* ----------------------------------------------------------------------------------- */
.top-menu[b-7pvipdi0zz]{

}

.top-menu td[b-7pvipdi0zz] {
}

.btn[b-7pvipdi0zz] {
    min-width: 100px;
    margin: 0 5px 0 5px;
}

/* ----------------------------------------------------------------------------------- */
.section[b-7pvipdi0zz] {
    width: 100px;
    font-weight: bold;
    vertical-align: top;
    font-size: 13px;
}

.section-item[b-7pvipdi0zz]{
    text-align:left;
    font-size: 13px;
}

.store[b-7pvipdi0zz] {
    margin: 10px 0 5px 0;
    display: flex;
    align-items: center;
    font-size: 14px; /* 아이콘과 텍스트 크기 조정 */
    font-weight: bold;
}

.store .material-icons[b-7pvipdi0zz] {
    font-size: 20px; /* 아이콘 크기 */
    margin-right: 5px; /* 아이콘과 텍스트 사이의 간격 조정 */
}


.container[b-7pvipdi0zz] {
    text-align: left;
    display: flex;
}

.item[b-7pvipdi0zz] {
    margin:2px;
    background-color: #fff;
    padding: 5px;
    font-size: 12px;
    text-align:left;
}
.item:first-child[b-7pvipdi0zz] {
    max-width:70px;
   text-align: end;
   width: 60px;
   background-color: #f8f8f8;
}
 
.item:last-child[b-7pvipdi0zz] {
}


.custom-th[b-7pvipdi0zz] {
    min-width: 50px;
}

/* /Components/Pages/Manager/Admin/AdminEditor.razor.rz.scp.css */
/* /Components/Pages/Manager/AdProducts/AdBanners.razor.rz.scp.css */

body[b-zxfv2iddlz] {
    background-color: #fff;
}


.section[b-zxfv2iddlz] {
    width: 200px;
    font-weight: bold;
    vertical-align: central;
    font-size: 14px;
}
.section-title[b-zxfv2iddlz] {
    display: flex;
    align-items: center;
    font-size:18px;
    padding-bottom: 5px;
    color: #aaa;
    border-bottom: solid 5px #ccc;
}
/* /Components/Pages/Manager/AdProducts/AdHistory.razor.rz.scp.css */

body[b-0d5gf70wxh] {
    background-color: #fff;
}


/* table ----------------------------------------------------------------------------------- */
.table-wrapper[b-0d5gf70wxh] {
    width: 100%;
    overflow-x: auto; /* 가로 스크롤 생성을 허용 */
}

table[b-0d5gf70wxh] {
    width: 100%;
    border-collapse: collapse; /* 테두리가 겹치지 않도록 설정 */
    /*min-width: 100px; 테이블이 일정 크기 이하로 줄어들지 않도록 설정 */
}

.main-table[b-0d5gf70wxh] {
}
.main-table td[b-0d5gf70wxh] {
    border: 1px solid #ddd; /* 셀의 테두리 설정 */
    padding: 15px; /* 셀 내부의 여백 설정 */
    text-align: left; /* 텍스트 정렬 */
}


/* ----------------------------------------------------------------------------------- */
.top-menu[b-0d5gf70wxh]{

}

.top-menu td[b-0d5gf70wxh] {
}

.btn[b-0d5gf70wxh] {
    min-width: 100px;
    margin: 0 5px 0 5px;
}

/* ----------------------------------------------------------------------------------- */
.section[b-0d5gf70wxh] {
    width: 100px;
    font-weight: bold;
    vertical-align: top;
    font-size: 13px;
}

.section-item[b-0d5gf70wxh]{
    text-align:left;
    font-size: 13px;
}

.store[b-0d5gf70wxh] {
    margin: 10px 0 5px 0;
    display: flex;
    align-items: center;
    font-size: 14px; /* 아이콘과 텍스트 크기 조정 */
    font-weight: bold;
}

.store .material-icons[b-0d5gf70wxh] {
    font-size: 20px; /* 아이콘 크기 */
    margin-right: 5px; /* 아이콘과 텍스트 사이의 간격 조정 */
}


.container[b-0d5gf70wxh] {
    text-align: left;
    display: flex;
}

.item[b-0d5gf70wxh] {
    margin:2px;
    background-color: #fff;
    padding: 5px;
    font-size: 12px;
    text-align:left;
}
.item:first-child[b-0d5gf70wxh] {
    max-width:70px;
   text-align: end;
   width: 60px;
   background-color: #f8f8f8;
}
 
.item:last-child[b-0d5gf70wxh] {
}


.custom-th[b-0d5gf70wxh] {
    min-width: 50px;
}

/* /Components/Pages/Manager/AdProducts/AdProductEditor.razor.rz.scp.css */

.upload-btn .plus[b-qxeozetn40] {
    font-size: 36px;
    line-height: 1;
}

.upload-btn[b-qxeozetn40] {
    border: 1px dashed #ccc;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
}


.image-preview-container[b-qxeozetn40] {
    position: relative;
    border: 1px solid #eee;
    display: flex;
    align-items: center;
    justify-content: center;
}

.image-preview-img[b-qxeozetn40] {
    max-width: 100%;
    max-height: 100%;
    display: block;
}

.image-action[b-qxeozetn40] {
    position: absolute;
    right: 6px;
    top: 6px;
    z-index: 3;
    display: flex;
    gap: 6px;
}


.actions-cell[b-qxeozetn40] {
    display: flex;
    gap: 6px;
    align-items: center;
    justify-content: center;
}
/* /Components/Pages/Manager/AdProducts/AdProductList.razor.rz.scp.css */
/* /Components/Pages/Manager/AppMain/AppMainEditor.razor.rz.scp.css */

.image-preview-container[b-51cczm5tzf] {
    position: relative;
    background: #f4f4f4;
    border: 1px solid #e0e0e0;
    border-radius: 7px;
    display: flex;
    justify-content: center;
    align-items: center;
    overflow: hidden;
}

.image-preview-img[b-51cczm5tzf] {
    width: 100%;
    height: 100%;
    object-fit: cover;
    border-radius: 14px;
}

/* /Components/Pages/Manager/AppMain/AppMainList.razor.rz.scp.css */



body[b-34zjo48r5t] {
    background-color: #fff;
}

.sortablejs-list[b-34zjo48r5t] {
    display: grid !important;
    grid-template-columns: repeat(2, 1fr);
    gap: 25px;
    padding: 0;
}

.appmain-grid[b-34zjo48r5t] {
    display: grid;
    grid-template-columns: repeat(2, 200px); /* 2개 고정 */
    justify-content: left; /* 가운데 정렬 원하면 center */
    gap: 10px;
    padding: 15px 0 25px 0;
}

.appmain-card[b-34zjo48r5t] {
    cursor: pointer;
    background: #1A1230;
    border-radius: 16px;
    padding: 0;
    overflow: hidden;
    box-shadow: 0 2px 12px #0002;
    display: flex;
    flex-direction: column;
    height: 200px;
    width: 200px;
    transition: transform .1s;
}

.appmain-card:hover[b-34zjo48r5t] {
    transform: translateY(-4px) scale(1.03);
    box-shadow: 0 4px 24px #0004;
}


.appmain-card-img[b-34zjo48r5t] {
    width: calc(100% - 20px); /* 좌우 10px씩 여백 */
    margin: 10px 10px 0 10px; /* 상단 10px, 좌우 10px, 하단 0 */
    height: 100px; /* 원하는 높이 고정 */
    object-fit: cover;
    border-radius: 10px; /* 카드보다 살짝 작게 */
    box-shadow: 0 2px 8px #0002;
    display: block;
}

.appmain-card-title[b-34zjo48r5t] {
    font-size: 18px;
    font-weight: 600;
    color: #fff;
    padding: 10px 0 0 13px;
    letter-spacing: -1px;
}

.appmain-card-desc[b-34zjo48r5t] {
    font-size: 13px;
    font-weight: 500;
    color: #bbbbbb;
    opacity: 50%;
    padding: 3px 0 0 13px;
}



/* /Components/Pages/Manager/Artist/ArtistEditor.razor.rz.scp.css */
.image-preview-container[b-fgn0aqkv9v] {
    height: 130px !important;
    width: 130px !important;
    margin-top: 10px !important;
    display: flex !important;
    align-items: center !important;
    justify-content: center !important;
    overflow: hidden !important;
}
/* /Components/Pages/Manager/Artist/ArtistList.razor.rz.scp.css */

body[b-eaxpvui5sz] {
    background-color: #fff;
}


/* table ----------------------------------------------------------------------------------- */
.table-wrapper[b-eaxpvui5sz] {
    width: 100%;
    overflow-x: auto; /* 가로 스크롤 생성을 허용 */
}

table[b-eaxpvui5sz] {
    width: 100%;
    border-collapse: collapse; /* 테두리가 겹치지 않도록 설정 */
    /*min-width: 100px; 테이블이 일정 크기 이하로 줄어들지 않도록 설정 */
}

.main-table[b-eaxpvui5sz] {
}
.main-table td[b-eaxpvui5sz] {
    border: 1px solid #ddd; /* 셀의 테두리 설정 */
    padding: 15px; /* 셀 내부의 여백 설정 */
    text-align: left; /* 텍스트 정렬 */
}


/* ----------------------------------------------------------------------------------- */
.top-menu[b-eaxpvui5sz]{

}

.top-menu td[b-eaxpvui5sz] {
}

.btn[b-eaxpvui5sz] {
    min-width: 100px;
    margin: 0 5px 0 5px;
}

/* ----------------------------------------------------------------------------------- */
.section[b-eaxpvui5sz] {
    width: 100px;
    font-weight: bold;
    vertical-align: top;
    font-size: 13px;
}

.section-item[b-eaxpvui5sz]{
    text-align:left;
    font-size: 13px;
}

.store[b-eaxpvui5sz] {
    margin: 10px 0 5px 0;
    display: flex;
    align-items: center;
    font-size: 14px; /* 아이콘과 텍스트 크기 조정 */
    font-weight: bold;
}

.store .material-icons[b-eaxpvui5sz] {
    font-size: 20px; /* 아이콘 크기 */
    margin-right: 5px; /* 아이콘과 텍스트 사이의 간격 조정 */
}


.container[b-eaxpvui5sz] {
    text-align: left;
    display: flex;
}

.item[b-eaxpvui5sz] {
    margin:2px;
    background-color: #fff;
    padding: 5px;
    font-size: 12px;
    text-align:left;
}
.item:first-child[b-eaxpvui5sz] {
    max-width:70px;
   text-align: end;
   width: 60px;
   background-color: #f8f8f8;
}
 
.item:last-child[b-eaxpvui5sz] {
}


.custom-th[b-eaxpvui5sz] {
    min-width: 50px;
}

/* /Components/Pages/Manager/Artist/FanChatList.razor.rz.scp.css */
/* /Components/Pages/Manager/Artist/GroupSelector.razor.rz.scp.css */
/* /Components/Pages/Manager/Banner/BannerEditor.razor.rz.scp.css */

.image-preview-container[b-qncmfyuuj4] {
    position: relative;
    background: #f4f4f4;
    border: 1px solid #e0e0e0;
    border-radius: 7px;
    display: flex;
    justify-content: center;
    align-items: center;
    overflow: hidden;
}

.image-preview-img[b-qncmfyuuj4] {
    width: 100%;
    height: 100%;
    object-fit: cover;
    border-radius: 14px;
}

/* /Components/Pages/Manager/Banner/BannerList.razor.rz.scp.css */

/* loading ----------------------------------------------------------------------------------- */
/* /Components/Pages/Manager/Dashboard/Dashboard.razor.rz.scp.css */

body[b-fkn573r7sj] {
    background-color: #fff;
}


/* table ----------------------------------------------------------------------------------- */
.table-wrapper[b-fkn573r7sj] {
    width: 100%;
    overflow-x: auto; /* 가로 스크롤 생성을 허용 */
}

table[b-fkn573r7sj] {
    width: 100%;
    border-collapse: collapse; /* 테두리가 겹치지 않도록 설정 */
    /*min-width: 100px; 테이블이 일정 크기 이하로 줄어들지 않도록 설정 */
}

.main-table[b-fkn573r7sj] {
}
.main-table td[b-fkn573r7sj] {
    border: 1px solid #ddd; /* 셀의 테두리 설정 */
    padding: 12px; /* 셀 내부의 여백 설정 */
    text-align: left; /* 텍스트 정렬 */
}


/* ----------------------------------------------------------------------------------- */
.top-menu[b-fkn573r7sj]{

}

.top-menu td[b-fkn573r7sj] {
}

.btn[b-fkn573r7sj] {
    min-width: 100px;
    margin: 0 5px 0 5px;
}

/* ----------------------------------------------------------------------------------- */
.section[b-fkn573r7sj] {
    width: 130px;
    font-weight: bold;
    vertical-align: top;
    font-size: 13px;
}

.section-item[b-fkn573r7sj]{
    text-align:left;
    font-size: 13px;
}

.store[b-fkn573r7sj] {
    margin: 10px 0 5px 0;
    display: flex;
    align-items: center;
    font-size: 14px; /* 아이콘과 텍스트 크기 조정 */
    font-weight: bold;
}

.store .material-icons[b-fkn573r7sj] {
    font-size: 20px; /* 아이콘 크기 */
    margin-right: 5px; /* 아이콘과 텍스트 사이의 간격 조정 */
}


.container[b-fkn573r7sj] {
    text-align: left;
    display: flex;
}

.item[b-fkn573r7sj] {
    margin:2px;
    background-color: #fff;
    padding: 5px;
    font-size: 12px;
    text-align:left;
}
.item:first-child[b-fkn573r7sj] {
    max-width:70px;
   text-align: end;
   width: 60px;
   background-color: #f8f8f8;
}
 
.item:last-child[b-fkn573r7sj] {
}




/* /Components/Pages/Manager/Dashboard/OpsBoard.razor.rz.scp.css */
/* 운영 보드 — 스코프 CSS (전역 오염 금지: 모든 셀렉터는 .ob-root 하위)
   2026-08-24 3차:
   - 스크롤 3층 = 툴바 고정(.ob-top) / 날짜 헤더 sticky(.ob-heads) / 본문만 세로 스크롤(.ob-scroll)
     가로 스크롤은 헤더·본문이 같은 컨테이너 안이라 자동 동기화된다.
   - 프로그램 레인(수평 막대) 폐기 → 열 안 프로그램 라벨 스택(.ob-progs)
     (2단계 용어 정리: 여기서 말하는 '레인'은 프로그램 기간 막대다. `일정`은 이제 수동 카드 타입의 이름이므로 섞어 쓰지 않는다.)
   2026-08-25:
   - ⛔ hover 팝업(.ob-tip / body 직속 포털 #ob-tip-layer) **폐지**(오너 지시).
     카드·라벨·시스템 칩은 **클릭하면 그 자리에서 아래로 펼쳐진다**(.ob-exp) → 팝업이 없으니
     좌표 계산·stacking context·포털·경계 반전(.tl/.tr)이 통째로 사라졌다. 확장은 in-flow 라
     .ob-scroll 의 overflow 에 잘릴 수도, 다른 열 뒤로 깔릴 수도 없다(예전 사고의 원인 2개가 구조적으로 제거). */

.ob-root[b-x5libd1jj1] {
    /* 2026-08-24: 220 → 260 → 312(+20%).
       🔄 2026-10-02 오너 지시 "기본 DAY 섹션의 넓이를 지금의 절반으로" — 312 → **156px**(제목은 여러 줄 허용 → .ob-prog-t).
       ⚠️ 이 값은 **기본값**이다. 사용자가 헤더 경계(.ob-col-rsz)를 끌면 opsBoard.js(initColResize)가
          #ob-scroll 에 인라인 `--ob-col` 을 얹어 덮고 localStorage 에 기억한다. 경계 더블클릭 = 인라인 제거 → 이 값으로 복귀. */
    --ob-col: 156px;
    /* 열 카드 사이 간격 — 총 폭 = days × (col + gap) − gap.
       🔄 2026-10-02 오너 지시 "Day간 여백도 제거해" — 12px → **0**(폭과 무관하게 항상). 열 구분은 1px 경계선 한 줄뿐
          (이웃 열의 왼쪽 테두리를 지워 2px 이중선을 막는다 → 아래 §열 사이 경계선). */
    --ob-gap: 0px;
    --ob-gutter: 16px;
    /* MudMainContent 가 상단에 var(--mud-appbar-height)(기본 64px) 만큼 padding 을 준다 → 그만큼 뺀다.
       ⚠️ 실제 앱바는 56px(MainLayout 이 .mud-toolbar 를 56px !important 로 고정)이지만
          여기서 빼야 하는 값은 '앱바 높이'가 아니라 'MudMainContent 의 padding-top' 이다. */
    --ob-main-pad: 64px;
    /* 🔵 파랑 두 갈래(2026-08-25 오너 지시 B-7 — 편집기가 먼저 쓰던 규칙을 보드로 가져왔다).
       실측(WCAG 상대 휘도로 계산):
         · #1e88e5 = 흰 배경 3.68:1 · 열 머리(#f8fafc) 3.52:1 → **글자에는 AA(4.5:1) 미달**, 비텍스트(3:1)는 통과.
         · #1565c0 = 흰 배경 5.75:1 · 열 머리 5.49:1 → 글자·채움면 모두 통과.
       ⇒ **읽는 것(글자·아이콘·채움면)은 --ob-accent, 그리는 것(테두리·구조선)은 --ob-ring.**
       (편집기 주석의 "3.39:1" 은 계산 오차였다. 결론은 같다 — 텍스트에는 부족하다.) */
    --ob-accent: #1565c0;
    /* ⚠️ 2026-08-25: --ob-ring 은 **더 이상 포커스 링이 아니다**(아래 --ob-focus 로 이관).
       고정 배경 위의 테두리·구조선·채움면 전용으로 남는다(.ob-seg 활성 탭 인셋선, .ob-today 표시 등). */
    --ob-ring: #1e88e5;

    /* 🎯 포커스 링 = **이중 링**(2026-08-25 오너 지시 "포커스 아웃라인이 잘 안 보이는 것 같아").
       왜 고정 1색이 원리상 불가능한가: 카드 배경은 팔레트 20색 + 프리셋 8색 + 오너가 임의로 고르는 hex 다.
       옛 방식(--ob-ring #1e88e5 단선)을 그 28색에 실제로 계산해 보면 **24색이 3:1 미달**이고
       최악은 #875ae2 위 1.24:1 — 사실상 안 보였다(오너 제보와 일치).
       해법(WCAG 2.2 SC 2.4.11 이 권하는 전형): 밝은 헤일로 + 어두운 링을 겹쳐
       **배경이 밝든 어둡든 둘 중 하나가 반드시 대비를 확보**하게 한다. 실측 최악값 3.34:1(#fd7878) — 통과.
         · 두 링끼리의 대비 8.63:1 → 배경과 무관하게 링 자체가 항상 형태로 읽힌다.
         · 바깥 어두운 링은 늘 페이지 배경(#fff/#fafafa)과 만난다 → 8.27~8.63:1.
       ⛔ 색을 하나로 되돌리지 말 것. ⛔ border 로 그리지 말 것 — outline/box-shadow 라 **박스 크기가 안 변한다**. */
    --ob-focus: #0d47a1;        /* 바깥 링 — --ob-accent(#1565c0) 계열의 한 단계 어두운 파랑(브랜드 유지) */
    --ob-focus-halo: #ffffff;   /* 안쪽 헤일로 — 어두운 카드 위에서 바깥 링을 떠받친다 */

    /* 🔄 2026-08-25 오너 지시 "코멘트 수 라운드를 분류태그와 같은 각도로 / 예정과 이름도 맞춰줘".
       기준은 **분류 태그(.ob-kind)** 다 — 실측 `border-radius: 6px`. 그 값을 이름으로 뽑아
       카드 안의 나머지 칩 셋(댓글 뱃지·상태 select·담당자 칩)이 같은 각도를 쓰게 한다.
       ⛔ `.ob-kind` 자체는 건드리지 않는다(오너가 기준으로 지목한 쪽이다).
          그래서 이 토큰은 **`.ob-kind` 의 6px 을 비추는 값**이다 — 한쪽을 바꾸면 다른 쪽도 같이 바꿔야 한다. */
    --ob-chip-r: 6px;
    --ob-line: #e2e8f0;
    /* 시스템/할일 구분선(.ob-div)의 상하 여백. 2026-08-26 오너 지시 "상하 간격을 살짝만 더 띄워"로 12 → 16px.
       ℹ️ 한때 더미의 드롭 도달 범위가 이 값을 공유했으나(32번), 그 확장은 회귀를 만들어 **철회**됐다.
          지금은 이 여백만 쓰는 값이라 자유롭게 조정해도 드래그 동작에 영향이 없다. */
    --ob-div-gap: 16px;
    /* 보드 자체 배경색은 없다(오너 지시 2026-08-24). --ob-page 는 sticky 헤더가 아래 내용을 가리기 위한
       '페이지와 같은 색'일 뿐이다 — app.css 의 .mud-main-content 배경(#fafafa)과 맞춘다. */
    --ob-page: #fafafa;
    --ob-head-bg: #f8fafc;          /* 열 카드 상단부 틴트 */
    --ob-head-bg-today: #eaf3fd;    /* 오늘 열 헤더 틴트(강조색 연한 톤) */
    /* 보조 글자(요일·필터 머리글). 2026-08-25: #64748b(열 머리 위 4.55:1 — AA 겨우 통과)에서 한 스텝 진하게.
       오너 지시 14("전체적으로 우중충하다")의 가장 큰 원인이 이 회색이었다 → #475569 로 7.24:1. */
    --ob-muted: #475569;
    --ob-ink: #0f172a;
    /* 토요일 요일 글자 = **텍스트**다 → 링용 밝은 파랑이 아니라 --ob-accent 계열(#1565c0, 5.49:1).
       ⚠️ 일요일 --ob-sun(#e53935)은 같은 자리에서 4.04:1 로 **AA 미달**이지만 이번 지시 범위 밖이라 두었다
          (권고값 #d32f2f = 4.76:1). 오너 결정 대기. */
    --ob-sat: #1565c0;
    --ob-sun: #e53935;

    box-sizing: border-box;
    display: flex;
    flex-direction: column;
    height: calc(100dvh - var(--ob-main-pad));
    padding: 0 var(--ob-gutter) var(--ob-gutter) var(--ob-gutter);
}

/* ── 1층: 툴바(고정) ───────────────────────────────────────────────── */
.ob-top[b-x5libd1jj1] {
    flex: 0 0 auto;
    width: 100%;
}

/* ── 툴바 (2026-08-24 컨트롤 언어 통일) ────────────────────────────
   높이 32 · 라운드 8 · 폰트 13px · 아이콘 16px · 아이콘-텍스트 6px
   컨트롤 간 8px / 그룹 간 16px / 수직 중앙. 하단 경계선 1px 하나만(그림자·그라데이션 없음).
   위계 = 채움 정도(solid 1개 + 나머지 ghost). 알약(999px) 금지. */
.ob-toolbar[b-x5libd1jj1] {
    display: flex;
    align-items: center;
    gap: 16px;                 /* 그룹 간 */
    min-height: 48px;
    padding: 0 0 8px 0;
    margin-bottom: 8px;
    border-bottom: 1px solid var(--ob-line);
    min-width: 0;
}

.ob-group[b-x5libd1jj1] {
    display: flex;
    align-items: center;
    gap: 8px;                  /* 컨트롤 간 */
    min-width: 0;
}

/* 월 이동 세그먼트 — [◀ | 2026년 8월 | ▶]. 테두리는 **바깥에 한 번만**, 안은 1px 세로선으로 나눈다.
   .ob-btn.outline 과 같은 테두리 색·라운드·높이·호버를 써서 툴바가 한 벌로 읽히게 한다. 그림자·그라데이션 없음. */
.ob-seg[b-x5libd1jj1] {
    box-sizing: border-box;
    display: inline-flex;
    align-items: stretch;
    flex: 0 0 auto;
    height: 32px;
    border: 1px solid #cbd5e1;
    border-radius: 8px;
    background: #ffffff;
    overflow: hidden;   /* 내부 칸의 호버 배경이 라운드 밖으로 새지 않게 */
}

.ob-seg-nav[b-x5libd1jj1] {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 32px;        /* 정사각 — 액션 버튼(32px)과 같은 높이·리듬 */
    padding: 0;
    border: none;
    background: transparent;
    color: #64748b;
    cursor: pointer;
    transition: background-color 150ms ease-out, color 150ms ease-out;
}

.ob-seg-nav:hover[b-x5libd1jj1] {
    background: #f1f5f9;
    color: var(--ob-ink);
}

/* 이중 링 — **인셋판**. 세그먼트 버튼은 그룹 테두리에 딱 붙어 있어 링이 밖으로 나가면 이웃 칸을 덮는다.
   outline(어두운 링)이 안쪽 가장자리 0→2px, inset box-shadow(헤일로)가 그 안쪽 2→4px 를 받친다. */
.ob-seg-nav:focus-visible[b-x5libd1jj1] {
    outline: 2px solid var(--ob-focus);
    outline-offset: -2px;
    box-shadow: inset 0 0 0 4px var(--ob-focus-halo);
}

.ob-seg-nav[b-x5libd1jj1]  .mud-icon-root {
    font-size: 16px;
}

/* 월 표기 = 이 화면의 제목. 세그먼트 안에서 가장 강하다.
   ⛔ 클릭 대상이 아니므로 호버 효과를 주지 않는다(월 선택 팝오버는 아직 도입 안 함). */
.ob-seg-title[b-x5libd1jj1] {
    display: flex;
    align-items: center;
    margin: 0;
    padding: 0 14px;
    border-left: 1px solid #cbd5e1;
    border-right: 1px solid #cbd5e1;
    font-size: 15px;
    font-weight: 700;
    color: var(--ob-ink);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

/* 공통 컨트롤 */
.ob-btn[b-x5libd1jj1] {
    box-sizing: border-box;   /* outline 1px 이 32px 높이 안에 들어오게 */
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 6px;                  /* 아이콘-텍스트 */
    height: 32px;
    padding: 0 10px;
    border: none;
    border-radius: 8px;
    background: transparent;
    color: #334155;
    font-size: 13px;
    font-weight: 600;
    line-height: 1;
    cursor: pointer;
    white-space: nowrap;
    flex: 0 0 auto;
    transition: background-color 150ms ease-out, color 150ms ease-out;
}

.ob-btn.icon[b-x5libd1jj1] {
    width: 32px;
    padding: 0;
}

.ob-btn[b-x5libd1jj1]  .mud-icon-root {
    font-size: 16px;
}

/* ghost — 테두리 없음, 호버는 배경 톤만. 아이콘 버튼(◀ ▶ ⚙)에만 남긴다. */
.ob-btn.ghost:hover[b-x5libd1jj1] {
    background: #f1f5f9;
    color: var(--ob-ink);
}

/* outline — 오너 지시(2026-08-24): 연한 배경 대신 **1px 아웃라인 + 흰 배경**.
   `오늘` · `분류 N/10` · `+ 프로그램` · `설정(톱니)` 네 개가 완전히 같은 형태라 한 벌로 읽힌다.
   테두리와 배경 톤을 **같이** 쓰지 않는다 — 평상시는 흰 배경, 호버에서만 배경이 생긴다. */
.ob-btn.outline[b-x5libd1jj1] {
    border: 1px solid #cbd5e1;
    background: #ffffff;
    color: #334155;
}

.ob-btn.outline:hover[b-x5libd1jj1] {
    background: #f1f5f9;
    border-color: #94a3b8;
    color: var(--ob-ink);
}

/* 팝오버가 열려 있는 동안은 눌린 상태로 고정 */
.ob-btn.outline.on[b-x5libd1jj1] {
    background: #f1f5f9;
    border-color: #94a3b8;
    color: var(--ob-ink);
}

.ob-btn:disabled[b-x5libd1jj1] {
    opacity: 0.45;
    cursor: default;
    background: transparent;
}

/* 이중 링 — **아웃셋판**(보드 공통). 헤일로가 0→2px, 어두운 링이 2→4px.
   offset 을 1 → 2px 로 올린 이유: 헤일로 두께(2px)와 맞춰야 두 링이 겹치지 않고 또렷하게 갈린다. */
.ob-btn:focus-visible[b-x5libd1jj1] {
    outline: 2px solid var(--ob-focus);
    outline-offset: 2px;
    box-shadow: 0 0 0 2px var(--ob-focus-halo);
}

/* 분류 필터 팝오버 — MudPopover 를 쓰지 않는 자체 패널.
   .ob-tip 과 같은 방식: position:fixed + JS 가 --pop-l/--pop-t 주입 + 바깥 클릭/ESC 로 닫기.
   display:none 이 아니라 visibility 로 감춘다 — JS 가 **열기 전에** 크기를 재야 좌표 경합이 없다. */
.ob-pop[b-x5libd1jj1] {
    position: fixed;
    top: var(--pop-t, 96px);
    left: var(--pop-l, 16px);
    z-index: 1350;
    visibility: hidden;
    opacity: 0;
    pointer-events: none;
    transform: translateY(-2px);
    transition: opacity 120ms ease-out, transform 120ms ease-out;
    background: #ffffff;
    border: 1px solid var(--ob-line);
    border-radius: 10px;
    box-shadow: 0 12px 24px -6px rgba(15, 23, 42, 0.18), 0 2px 6px rgba(15, 23, 42, 0.06);
    max-height: calc(100vh - 16px);
    overflow-y: auto;
    scrollbar-width: thin;
}

.ob-pop.open[b-x5libd1jj1] {
    visibility: visible;
    opacity: 1;
    pointer-events: auto;
    transform: none;
}

/* 분류·담당자 필터 목록 — 2026-08-24 5차(오너 지시 2번) **2단 가로 배치**.
   이전: 한 세로 열에 분류 12행 + 담당자 (N+1)행이 이어 붙어 팝업이 500px 넘게 길어졌다.
   지금: 분류 영역과 담당자 영역이 **좌우로 나란히** 서고, 영역 안에서도 항목이 여러 열로 흐른다
         (.ob-fl-grid.k3 = 3열 · .k2 = 2열) → 관리자가 늘어도 세로 길이가 거의 안 늘어난다.
         실측 기준 높이: 분류 4행 + 머리글 + 액션 ≒ 220px(이전 12+N+1 행 ≒ 520px 이상).
   폭은 계속 내용 기준(width:max-content)이되 좁은 화면에서 잘리지 않게 상한을 둔다 —
   좌표를 넣는 JS(initPanel)가 measure 한 실제 폭으로 클램프하므로 상한만 있으면 화면 밖으로 안 나간다. */
.ob-filter[b-x5libd1jj1] {
    display: grid;
    grid-template-columns: auto auto;
    align-items: start;
    column-gap: 14px;
    row-gap: 2px;
    padding: 8px;
    width: max-content;
    min-width: 200px;
    max-width: calc(100vw - 32px);
}

/* 한 영역(분류 / 담당자) = 머리글 + 항목 격자 */
.ob-fl-sec[b-x5libd1jj1] {
    min-width: 0;
}

/* 담당자 영역은 분류 영역과 **세로선 하나**로만 나뉜다(2단이 되면서 머리글 위 가로선은 의미를 잃었다) */
.ob-fl-sec.people[b-x5libd1jj1] {
    padding-left: 14px;
    border-left: 1px solid var(--ob-line);
}

/* 항목 격자 — 열 수만 클래스로 갈린다. minmax(0,1fr) 이라 긴 이름이 열 폭을 밀지 않는다. */
.ob-fl-grid[b-x5libd1jj1] {
    display: grid;
    gap: 2px;
}

.ob-fl-grid.k3[b-x5libd1jj1] {
    grid-template-columns: repeat(3, minmax(0, 1fr));
}

.ob-fl-grid.k2[b-x5libd1jj1] {
    grid-template-columns: repeat(2, minmax(0, 1fr));
}

.ob-fl[b-x5libd1jj1] {
    display: flex;
    align-items: center;
    gap: 10px;          /* 체크박스 — (분류)칩 / (담당자)이름. 두 목록이 같은 축을 쓴다 */
    /* 🔄 2026-08-26: 36 → **28px 원복**. 36 은 분류 칩이 커졌을 때 거기 맞춰 늘렸던 값인데,
       29번으로 칩이 다시 작아지고(≈17.8px) 28번으로 담당자 배지가 빠져 **두 행 모두 글자 한 줄**이 됐다.
       36 을 그대로 두면 패널만 이유 없이 헐렁해진다. */
    height: 28px;
    padding: 0 8px;
    border-radius: 8px;
    cursor: pointer;
}

.ob-fl:hover[b-x5libd1jj1] {
    background: #f1f5f9;
}

.ob-fl input[b-x5libd1jj1] {
    width: 17px;
    height: 17px;
    flex: 0 0 auto;
    accent-color: var(--ob-accent);
    cursor: pointer;
}

/* 필터 팝오버 안 분류칩만 한 단계 크게 — 보드 안 칩(.ob-prog 안)과 호버 팝업 칩은 그대로 둔다.
   보드 칩을 키우면 열 폭 계산과 1줄 정렬이 흔들리기 때문. */
/* 🔄 2026-08-26 오너 지시 "분류 태그 크기가 담당자 이름에 비해 너무 커".
   기준 = **같은 패널의 담당자 이름**(`.ob-fl-name` 0.8rem/600 → line box ≈ 18.3px).
   실측 대조(이전): 칩 0.8rem/800 + padding 4px 10px → 높이 ≈ 23.4px.
     **글자 크기는 이미 같았고**(둘 다 0.8rem) 무게(800)·패딩·색면이 겹쳐 더 크게 읽혔다.
   → font-size 0.8→0.72rem · padding 4/10→2/7 → 높이 ≈ **17.8px** 로 이름 line box(18.3px)와 거의 같아진다.
   ⛔ **색과 무게(800)는 그대로** — 12종 색 배정(`OpsKindChips`)은 단일 출처·확정분이고, 굵기는 색칩의 정체성이다.
   ⛔ 선택자를 `.ob-filter` 하위로 **한정**했다 — 공용 `.ob-kind`(보드 카드·시스템 칩·프로그램 라벨·
      상세 타이틀바)에 걸면 보드 전체가 따라 바뀐다. */
.ob-filter .ob-kind[b-x5libd1jj1] {
    font-size: 0.72rem;
    line-height: 1.2;
    padding: 2px 7px;
    border-radius: 6px;
}

/* 액션 줄은 2단 아래에 **한 줄로 걸친다**(grid-column: 1/-1) — 두 영역 중 어느 쪽에도 속하지 않는다. */
.ob-fl-actions[b-x5libd1jj1] {
    grid-column: 1 / -1;
    display: flex;
    gap: 6px;
    margin-top: 6px;
    padding-top: 8px;
    border-top: 1px solid var(--ob-line);
}

/* 전체 선택/해제 — 행과 같은 밀도로 폭을 반씩 나눠 갖는다 */
.ob-fl-actions .ob-btn[b-x5libd1jj1] {
    flex: 1 1 0;
    height: 34px;
}

/* 필터가 걸려 있음을 알리는 점(장식 최소 — 색 하나) */
.ob-dot-on[b-x5libd1jj1] {
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: var(--ob-ring);
    margin-left: 2px;
}

/* ── 2·3층: 스크롤 컨테이너 ────────────────────────────────────────── */
.ob-scroll[b-x5libd1jj1] {
    flex: 1 1 auto;
    min-height: 0;
    overflow: auto;
    scrollbar-width: thin;
    /* ⛔ 보드를 둘러싸는 테두리·라운드 없음(2026-08-24) — 경계는 **열 카드 한 겹**만 그린다.
       배경도 없다(페이지 그대로). */
    background: transparent;
}

/* 스페이스 패닝(피그마 hand tool) — JS 가 .ob-pan / .ob-grabbing 을 붙인다 */
.ob-scroll.ob-pan[b-x5libd1jj1] {
    cursor: grab;
    user-select: none;
}

.ob-scroll.ob-grabbing[b-x5libd1jj1] {
    cursor: grabbing;
}

/* 패닝 중에는 카드가 드래그를 가로채지 못하게 (MudDropContainer 와 충돌 차단) */
.ob-scroll.ob-pan[b-x5libd1jj1]  .ob-prog {
    pointer-events: none;
}

.ob-board[b-x5libd1jj1] {
    display: flex;
    flex-direction: column;
    width: max-content;
    min-width: 100%;
    min-height: 100%;
    padding: 0 12px 16px 12px;
}

/* ── 2층: 날짜 헤더(유일한 sticky) ─────────────────────────────────── */
.ob-heads[b-x5libd1jj1] {
    position: sticky;
    top: 0;
    z-index: 3;
    display: grid;
    grid-template-columns: repeat(var(--ob-days), var(--ob-col));
    column-gap: var(--ob-gap);
    /* 고정 시 아래 카드가 비치지 않도록 페이지와 같은 색을 칠하고, 상단 여백까지 sticky 안에 포함한다
       (열 사이 간격까지 이 색이라 이음매가 보이지 않는다) */
    background: var(--ob-page);
    padding-top: 12px;
}

/* 열 헤더 = 열 카드의 '윗부분'. 아래 .ob-col 과 테두리를 이어 하나의 카드로 보이게 한다. */
.ob-head[b-x5libd1jj1] {
    display: flex;
    align-items: center;   /* DAY·날짜 텍스트 블록과 + 버튼을 수직 중앙 정렬 */
    justify-content: space-between;
    gap: 4px;
    min-width: 0;
    position: relative;
    z-index: 1;
    padding: 12px 12px 8px 12px;
    background: var(--ob-head-bg);
    border: 1px solid var(--ob-line);
    border-bottom: 1px solid var(--ob-line);
    border-radius: 12px 12px 0 0;
}

/* 주말 열 — **헤더 배경만** 아주 옅게 눌러 한 달을 훑을 때 주 단위 리듬이 보이게 한다(2단계, 오너 지시).
   ⚠️ 반드시 `.ob-head.today` / `.ob-head.outside` **위에** 둘 것 — 셋 다 클래스 2개라 특이도가 같아
      나중에 선언된 쪽이 이긴다(= 오늘·이번 달 밖 표시가 주말 틴트를 덮어야 한다).
   본문(.ob-col)에는 넣지 않는다: 카드 배경색이 곧 정보라 열 전체가 물들면 색 판단이 흐려진다. */
.ob-head.sat[b-x5libd1jj1],
.ob-head.sun[b-x5libd1jj1] {
    background: #f4f6f8;
}

/* 오늘 열 강조 — 헤더 배경 틴트 + **파란 아웃라인**(오너 요청으로 복원, 2026-08-24).
   ⛔ border-width 를 2px 로 키우면 헤더/본문이 1px 어긋난다(기록된 함정) → **inset box-shadow** 로 그린다(레이아웃 영향 0).
   헤더는 위·좌·우 3변만, 본문은 좌·우·아래 3변만 그려 **맞닿는 변에서 이중선이 생기지 않게** 한다.
   1px 테두리는 폭을 바꾸지 않고 **색만** 강조색으로 (역시 정렬 영향 0). */
.ob-head.today[b-x5libd1jj1] {
    background: var(--ob-head-bg-today);
    border-color: var(--ob-ring);
    box-shadow:
        inset 0 2px 0 0 var(--ob-ring),
        inset 2px 0 0 0 var(--ob-ring),
        inset -2px 0 0 0 var(--ob-ring);
}

/* ── 열 폭 조절 핸들(2026-10-02 오너 지시 "DAY 섹션 좌우를 마우스로 넓혔다 줄였다") ──────────
   각 열 헤더의 **오른쪽 경계**(열 사이 12px 간격의 가운데)에 걸친 10px 세로 띠. 끌면 **모든 날짜 열이 같은 폭으로** 바뀐다.
   동작은 전부 opsBoard.js(initColResize) — 이벤트 위임이라 월 이동으로 헤더가 다시 그려져도 그대로 동작한다.
   🛑 카드 드래그(MudDropContainer)와 겹치지 않는다: 핸들은 **헤더 행(.ob-heads)** 에만 있고 드래그 대상 카드는 본문(.ob-cols)에만 있다.
      헤더는 draggable 이 아니므로 핸들에서 HTML5 드래그가 시작될 수 없다.
   📐 위치(2026-10-02 열 간격 0 이후): **열의 오른쪽 경계선 위** — 헤더 안쪽 9px + 경계선 1px = 10px 히트 영역.
      바깥으로 내밀지 않는 이유: 다음 헤더가 같은 z-index 로 뒤에 그려져 내민 부분을 덮는다(헤더마다 z-index:1 쌓임 맥락). */
.ob-col-rsz[b-x5libd1jj1] {
    position: absolute;
    top: 0;
    bottom: 0;
    right: -1px;
    width: 10px;
    z-index: 2;
    cursor: col-resize;
    touch-action: none;
}

/* 호버·조절 중에만 가는 세로선으로 "여기를 끌 수 있다"를 알린다(평소엔 보이지 않음 — 장식 총량 유지) */
.ob-col-rsz[b-x5libd1jj1]::after {
    content: "";
    position: absolute;
    top: 8px;
    bottom: 8px;
    right: 0;
    width: 2px;
    border-radius: 1px;
    background: var(--ob-ring);
    opacity: 0;
    transition: opacity 120ms ease-out;
}

.ob-col-rsz:hover[b-x5libd1jj1]::after,
.ob-scroll.ob-col-resizing .ob-col-rsz[b-x5libd1jj1]::after {
    opacity: 1;
}

/* 조절 중: 커서를 고정하고 글자 선택을 막는다(포인터가 핸들 밖으로 나가도 col-resize 유지) */
.ob-scroll.ob-col-resizing[b-x5libd1jj1] {
    cursor: col-resize;
    user-select: none;
}

.ob-head-l[b-x5libd1jj1] {
    display: flex;
    flex-direction: column;
    gap: 1px;
    min-width: 0;
}

/* DAY nn — 칸의 1차 정보. Figma 원본(20px ExtraBold) 이상으로 두껍게. */
.ob-day-n[b-x5libd1jj1] {
    font-size: 1.2rem;
    font-weight: 900;
    line-height: 1.15;
    color: var(--ob-ink);
    font-variant-numeric: tabular-nums;
}

.ob-day-d[b-x5libd1jj1] {
    display: flex;
    align-items: baseline;
    gap: 0 6px;
    min-width: 0;
    flex-wrap: wrap;   /* 2026-10-02: 열 폭을 좁게 끌었을 때 요일이 옆 열로 넘치지 않고 아랫줄로 내려간다(넓을 땐 종전과 같다) */
}

.ob-day-md[b-x5libd1jj1] {
    font-size: 0.88rem;
    font-weight: 700;
    color: #334155;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

/* 숫자 = 1차 정보 / 단위(월·일) = 한 단계 작고 흐리게. 숫자와 붙어 답답하지 않게 앞에 1px 틈. */
.ob-day-md b[b-x5libd1jj1] {
    font-weight: 800;
    letter-spacing: -0.01em;
}

.ob-day-md i[b-x5libd1jj1] {
    font-style: normal;
    font-size: 0.72rem;
    font-weight: 600;
    color: var(--ob-muted);
    margin-left: 1px;
}

/* 요일 색은 **요일 글자에만** — 주말 배경 틴트 없음, DAY·날짜 숫자는 검정 유지(오너 지시 2026-08-24) */
.ob-day-w[b-x5libd1jj1] {
    font-size: 0.88rem;
    font-weight: 800;
    color: var(--ob-muted);
}

.ob-head.sat .ob-day-w[b-x5libd1jj1] {
    color: var(--ob-sat);
}

.ob-head.sun .ob-day-w[b-x5libd1jj1] {
    color: var(--ob-sun);
}

/* 열 헤더의 + = **카드 추가의 유일한 진입점**(2026-08-24. 2단계부터 다이얼로그가 아니라 빠른 추가 입력을 연다).
   ⚠️ MudIconButton 의 루트 <button> 에는 스코프 속성이 붙지 않는다 → 반드시 ::deep 로 선택해야 적용된다.
      (::deep 없이 쓴 이전 규칙은 실제로는 먹지 않았다.)
   유일한 진입점이므로 크기를 키운다: 아이콘 20px / 히트 영역 32×32px. */
.ob-head[b-x5libd1jj1]  .ob-head-add {
    flex: 0 0 auto;
    width: 32px;
    height: 32px;
    min-width: 32px;
    padding: 0;
    opacity: 0.58;                 /* 처음 봐도 있다는 걸 알 수 있는 정도 */
    transition: opacity 150ms ease-out, background-color 150ms ease-out;
}

.ob-head[b-x5libd1jj1]  .ob-head-add .mud-icon-root {
    font-size: 20px;
}

.ob-head:hover[b-x5libd1jj1]  .ob-head-add,
.ob-head[b-x5libd1jj1]  .ob-head-add:focus-visible {
    opacity: 1;
    background-color: #e8edf3;
}

/* ⚠️ 위 규칙은 hover 와 focus 가 **완전히 같은 모습**이었다(둘 다 불투명 + 회색 면).
   키보드 사용자에게는 "여기 있다"는 신호가 마우스 호버와 구별되지 않는다는 뜻이라 링을 따로 준다.
   열 머리는 배경이 고정(#f8fafc·오늘 #eaf3fd)이지만 **한 화면 안에서 포커스 표현이 갈리면 안 되므로**
   보드 공통 이중 링을 그대로 쓴다. */
.ob-head[b-x5libd1jj1]  .ob-head-add:focus-visible {
    outline: 2px solid var(--ob-focus);
    outline-offset: 2px;
    box-shadow: 0 0 0 2px var(--ob-focus-halo);
}

/* 오늘 열은 기본 상태에서도 조금 더 또렷하게(이 화면의 단일 강조색) */
.ob-head.today[b-x5libd1jj1]  .ob-head-add {
    opacity: 0.8;
    color: var(--ob-accent);
}

/* ── 3층: 날짜 열(본문) ────────────────────────────────────────────── */
.ob-board[b-x5libd1jj1]  .ob-cols {
    flex: 1 1 auto;
    display: grid;
    grid-template-columns: repeat(var(--ob-days), var(--ob-col));
    column-gap: var(--ob-gap);
    align-items: stretch;
}

/* 열 카드의 '아랫부분' — 헤더와 테두리를 이어 하나의 카드가 된다.
   세로 구분선은 없앴다: 카드 경계(간격 + 테두리)가 칼럼 구분을 대신한다(오너 지시 2026-08-24). */
.ob-col[b-x5libd1jj1] {
    min-width: 0; /* ⛔ 그리드 자식 기본 min-width:auto — 긴 제목이 열을 밀어내는 것을 막는다 */
    position: relative;
    display: flex;
    flex-direction: column;
    background: #fff;
    border: 1px solid var(--ob-line);
    border-top: none;
    border-radius: 0 0 12px 12px;
    padding: 0 4px 8px 4px;
}

/* 다음 달 1일 열 — "이번 달 밖"임을 톤으로 알린다(Figma 원본의 32번째 칸) */
.ob-head.outside[b-x5libd1jj1] {
    background: #f1f3f6;
}

.ob-head.outside .ob-day-n[b-x5libd1jj1],
.ob-head.outside .ob-day-md[b-x5libd1jj1] {
    color: #64748b;
}

.ob-next-tag[b-x5libd1jj1] {
    margin-left: 4px;
    font-size: 0.62rem;
    font-weight: 800;
    color: #64748b;
    background: #e2e8f0;
    border-radius: 6px;
    padding: 1px 5px;
    vertical-align: middle;
}



/* 오늘 열 본문 — 헤더와 이어지는 파란 아웃라인(좌·우·아래 3변만; 맞닿는 위 변은 헤더가 그린다) */
.ob-col.today[b-x5libd1jj1] {
    border-color: var(--ob-ring);
    box-shadow:
        inset 0 -2px 0 0 var(--ob-ring),
        inset 2px 0 0 0 var(--ob-ring),
        inset -2px 0 0 0 var(--ob-ring);
}

/* 프로그램 라벨 스택 — Figma 원본 ②층(테두리 있음). 헤더에 고정하지 않고 본문과 함께 스크롤. */
.ob-progs[b-x5libd1jj1] {
    display: flex;
    flex-direction: column;
    gap: 4px;
    padding: 6px 4px 0 4px;
    min-width: 0;
}

.ob-prog[b-x5libd1jj1] {
    position: relative;
    display: flex;
    align-items: center;
    gap: 6px;
    min-width: 0;
    padding: 4px 8px;
    /* ⛔ 테두리 없음 — 배경색 면이 이미 경계를 만든다(같은 경계를 두 번 그리지 않는다) */
    border: none;
    border-radius: 6px;
    background: var(--lane, #e2e8f0);
    color: var(--lane-fg, #0f172a);
    font-size: 0.74rem;
    line-height: 1.45;
    cursor: pointer;
    /* ── 호버 아웃라인(2026-08-25 오너 지시 11) ─────────────────────────────
       왜: 호버 팝업을 걷어내면서 "여기를 누를 수 있다"는 신호가 통째로 사라졌다. 클릭이 이 화면의 핵심 동작인데
           마우스를 올려도 아무 반응이 없었다. 카드·시스템 칩·프로그램 라벨 **셋 모두 같은 규칙**으로 되살린다.
       방법: `border` 가 아니라 **`outline`**. 테두리를 새로 붙이면 박스가 1px 커져 호버할 때마다 카드가 밀린다
             (outline 은 레이아웃에 전혀 기여하지 않는다). 기본값을 `transparent` 로 깔아 두어야 색 전이가 가능하다.
       ⚠️ `outline-offset` 은 **음수**다. 양수로 카드 밖에 그리면 그 자리는 열의 흰 바닥인데,
          오너가 어두운 색을 고른 카드에서는 currentColor 가 흰색이라 **흰 바탕에 흰 선 = 보이지 않는다.**
          안쪽에 그리면 선이 항상 카드 자기 배경 위에 놓이므로 24색 파스텔이든 임의 어두운 색이든 성립한다.
       색: 새로 만들지 않는다 — currentColor(=--lane-fg, 배경 휘도로 이미 자동 반전된 값)에서 알파만 낮춘다.
           이 파일의 기존 관례와 같다(.ob-exp / .ob-act / .ob-cmt 테두리). */
    outline: 1px solid transparent;
    outline-offset: -1px;
    transition: outline-color 160ms ease-out, transform 160ms cubic-bezier(0.16, 1, 0.3, 1), box-shadow 160ms ease-out;
}

/* ── 호버 = 미세 확대 + 그림자 부양(2026-08-25 오너 지시) ─────────────────
   왜 아웃라인만으로는 부족했나: 1px 색 변화는 **이미 색이 칠해진 면 안쪽**에 그려지므로, 24색 파스텔 카드에서는
   "무언가 바뀌었다"가 거의 안 읽혔다. 들어 올리면 카드가 열 바닥에서 분리돼 포인터가 어디에 있는지 한눈에 잡힌다.
   ⚠️ 아웃라인은 **걷지 않았다** — 어두운 카드(오너 임의 hex)에서는 그림자가 배경에 묻히므로 아웃라인이 유일한 보험이고,
      reduced-motion 에서 그대로 남는 대체 신호이기도 하다(아래 @@media 참조).

   📏 확대율 = **1.015**(+1.5%). 근거(수치):
     · 카드 콘텐츠 폭 278px(열 312 − 테두리 2 − .ob-col 패딩 8 − .ob-zone 패딩 8 − 카드 패딩 16)
       → 1.015 에서 +4.17px, **좌우 각 2.08px** 팽창.
     · 카드에서 열 안쪽 벽까지의 여유는 .ob-zone 4px + .ob-col 4px = **8px** → 2.08px 은 그 안에서 끝난다.
       열 카드 테두리·이웃 열·가로 스크롤 컨테이너 어디에도 닿지 않는다(잘림 0).
     · 세로: 카드 ≈57px → +0.86px(위아래 각 0.43px). 카드 사이 간격 6px 이라 이웃 카드와 겹치지 않는다.
     · 1.02 면 좌우 2.78px 로 여전히 안전하지만, 0.74rem 글자가 눈에 띄게 흔들려 1.015 에서 멈췄다.
   🚫 `.expanded` 는 확대에서 **제외**한다 — 펼친 패널까지 통째로 늘어나면 본문 글자가 뭉개지고,
      "선택된 것"에 호버 어포던스를 또 주지 않는다는 기존 판단(아래 .expanded 규칙 주석)과도 어긋난다.

   🎨 그림자 색은 새로 만들지 않는다 — 이 파일이 이미 쓰는 먹 계열 알파 rgba(15,23,42,α) 그대로
      (.ob-pop 그림자 · .ob-stsel 호버 · .ob-who 테두리와 같은 색 어휘). 팝오버(0.18)보다 얕은 0.14/0.06 이라
      "떠오르되 팝업만큼 뜨지는 않는" 위계가 유지된다.

   🚨 stacking context: `transform` 은 새 stacking context 를 만든다(이 파일 상단·개발 규칙의 사고 이력 참조).
      확인 결과 **.ob-prog 안에 position:fixed 팝업이 하나도 없다** — 호버 팝업(.ob-tip)은 2026-08-25 에 삭제됐고,
      남은 유일한 fixed 패널 `.ob-pop`(#ob-kind-pop)은 툴바 소속으로 .ob-scroll 의 **형제**다. 갇힐 것이 없다.
      상태 드롭다운은 네이티브 <select> 라 목록을 OS 가 그린다 → transform 영향 밖.
   ↕ z-index 는 **호버에만** 준다(상시 부여 금지 — 드래그 레이어와 충돌). 값 2 는 sticky 날짜 헤더(.ob-heads, 3)
      **아래**로 골랐다: 카드가 헤더 위로 떠오르면 스크롤 중에 날짜가 가려진다. .ob-head(1)보다는 위다. */
.ob-prog:hover[b-x5libd1jj1] {
    outline-color: color-mix(in srgb, currentColor 45%, transparent);
}

.ob-prog:not(.expanded):hover[b-x5libd1jj1] {
    transform: scale(1.015);
    box-shadow: 0 6px 14px -4px rgba(15, 23, 42, 0.14), 0 2px 4px rgba(15, 23, 42, 0.06);
    z-index: 2;
}

/* 호버 + 키보드 포커스가 겹칠 때. 두 규칙은 특이도가 같아 소스 순서로 뒤가 이기고, box-shadow 는
   **하나의 속성**이라 한쪽이 다른 쪽을 통째로 지운다 → 여기서 합쳐 둘 다 살린다(헤일로가 먼저,
   그 밖에 부양 그림자). 이렇게 해야 이중 링의 흰 헤일로가 그림자에 먹혀 흐려지지 않는다.
   outline 은 별개 속성이라 충돌하지 않는다(포커스의 2px 어두운 링이 그대로 유지). */
.ob-prog:not(.expanded):hover:focus-visible[b-x5libd1jj1] {
    box-shadow: 0 0 0 2px var(--ob-focus-halo), 0 6px 14px -4px rgba(15, 23, 42, 0.14), 0 2px 4px rgba(15, 23, 42, 0.06);
}

/* 펼쳐진 칩은 **항상** 윤곽을 유지한다 — 열 안에서 갑자기 키가 커진 이 덩어리가 어디서 끝나는지 알려 주는
   경계이자 "지금 열려 있는 것은 이것" 이라는 선택 표시다. 호버해도 값이 같으므로 열린 카드는 더 반응하지 않는다
   (이미 선택된 것에 호버 어포던스를 또 주지 않는다). */
.ob-prog.expanded[b-x5libd1jj1] {
    outline-color: color-mix(in srgb, currentColor 45%, transparent);
}

/* 드래그 중에는 호버 아웃라인을 끈다 — 드롭 자리표시자(2px 파선)와 나란히 뜨면 어느 쪽이 "놓일 자리"인지 흐려진다.
   신호는 이미 있다: MudDropZone 이 드래그 트랜잭션 동안 유효한 존에 `CanDropClass`(=.ob-can-drop)를 붙인다
   (MudBlazor 9.7.0 문서 실측). 네이티브 HTML5 드래그는 mouseover 를 안 쏘므로 :hover 가 남는 요소는
   **드래그를 시작한 그 카드뿐**이고, 그 카드는 반드시 이 존 안에 있다. */
.ob-col[b-x5libd1jj1]  .ob-zone.ob-can-drop .ob-prog.task:hover {
    outline-color: transparent;
    /* 2026-08-25: 포커스가 이중 링이 되면서 헤일로(box-shadow)도 같이 꺼야 한다.
       안 그러면 드래그 중에 어두운 링만 사라지고 **흰 테두리만 남아** 드롭 자리표시자(2px 파선)와
       나란히 떠서 "어디에 놓이는가"가 흐려진다. 이 규칙은 .ob-prog:focus-visible 보다 특이도가 높아 이긴다. */
    box-shadow: none;
    /* 2026-08-25 부양 호버 도입에 따른 추가 억제. 드래그 중에 원본 카드가 확대된 채로 떠 있으면
       드래그 고스트·드롭 자리표시자와 셋이 동시에 움직여 "무엇이 어디로 가는가"가 흐려진다.
       ⚠️ transform 을 끄면 그 순간 stacking context 도 사라지므로 z-index:2 도 함께 지운다
          (안 지우면 확대 없이 z 만 남아 드롭 자리표시자 위로 올라온다). */
    transform: none;
    z-index: auto;
}

/* 프로그램 이름 = 라벨의 1순위 정보(위계 정의: 이름 > DAY > 분류 > 시각) */
/* 🔄 2026-10-02 오너 지시 "제목은 여러줄 나와도 됨" — 말줄임(ellipsis·nowrap) → **줄바꿈**.
   기본 열 폭이 절반(156px)이 되고 사용자가 폭을 줄일 수도 있어 한 줄 말줄임이면 제목이 거의 안 읽힌다.
   적용 범위 = 이 클래스를 쓰는 셋(프로그램 라벨·시스템 칩·할 일 카드의 제목)뿐. DAY·시각·분류칩 등 보조 텍스트는 그대로다.
   keep-all = 한글 단어 단위로 끊고, anywhere = 한 단어가 폭보다 길 때만 그 안에서 끊는다(열 밖으로 넘치지 않게). */
/* 🔄 2026-10-02 2차(오너: "줄바꿈을 해서 내용을 좀 가득 채워줘. 지금 텍스트가 한줄로 나와").
   원인: 제목이 [분류칩][제목][DAY/시각] **한 가로줄** 가운데 칸이라, 칩(flex 0 0 auto)·DAY(flex-shrink 0)가 폭을 먼저 먹고
         좁은 열에서 제목 칸이 몇 px 로 짓눌려 **글자 하나씩 세로로** 쌓였다.
   해법: 제목을 `order:-1` + `flex-basis:100%` 로 **그 줄의 첫 행 전체**로 올리고, 칩·DAY/시각은 아랫줄로 내린다
         (부모 행에 flex-wrap — 아래 §제목 줄 분리). 마크업 순서는 그대로다(화면 순서만 CSS 로). 폭과 무관하게 항상 같은 배치. */
.ob-prog-t[b-x5libd1jj1] {
    order: -1;
    flex: 1 0 100%;
    min-width: 0;
    white-space: normal;
    word-break: keep-all;
    overflow-wrap: anywhere;
    font-weight: 700;
}

/* 1줄 묶음 — 1줄짜리 라벨에서는 display:contents 로 사라져 기존 가로 배치를 그대로 쓴다 */
.ob-prog-1[b-x5libd1jj1] {
    display: flex;
    align-items: center;
    gap: 6px;
    min-width: 0;
}

/* 접힌 1줄 칩은 예전 그대로 — 래퍼가 사라져 부모의 가로 flex 를 직접 쓴다.
   ⚠️ `.expanded` 를 제외하는 이유: 펼치면 부모가 세로 flex 로 바뀌므로 래퍼가 **실제 행**이어야
      [분류칩][제목][DAY] 가 한 줄로 남는다(contents 인 채로 두면 세 조각이 세로로 흩어진다). */
.ob-prog:not(.two-line):not(.expanded) .ob-prog-1[b-x5libd1jj1] {
    display: contents;
}

/* 시작·종료가 있는 날만 2줄 */
.ob-prog.two-line[b-x5libd1jj1] {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 3px;
}

/* 펼쳐진 칩 — 세로 스택으로 바뀐다(2줄 라벨과 같은 문법). 수동 카드(.ob-prog.task)는 원래 세로라 무해하다.
   ⚠️ 이 규칙이 없으면 프로그램 라벨·시스템 칩이 가로 flex 인 채로 남아 확장 패널이 옆으로 붙는다. */
.ob-prog.expanded[b-x5libd1jj1] {
    display: flex;
    flex-direction: column;
    align-items: stretch;
}

/* 키보드 포커스 — 세 칩 모두 role="button" + tabindex="0" 이므로 **보이는 포커스**가 있어야 한다.
   보드의 다른 컨트롤(.ob-btn/.ob-stsel)과 같은 강조색 2px 아웃라인으로 통일. */
/* 카드·시스템 칩·프로그램 라벨의 포커스 = 이중 링(아웃셋판).
   🔑 이 화면에서 **이중 링이 반드시 필요한 이유가 바로 여기**다 — 다른 컨트롤은 배경이 고정이지만
      이 요소들만 배경이 --lane(팔레트 20색 + 오너 임의 hex)이다.
   ↕ 호버와의 구별: 호버는 `outline-color: currentColor 45%` **1px 한 겹**, 포커스는 **4px 두 겹**이다
      (호버는 .ob-prog 기본 outline 의 색만 바꾼다 → 굵기·겹수 모두 다르다). */
.ob-prog:focus-visible[b-x5libd1jj1] {
    outline: 2px solid var(--ob-focus);
    outline-offset: 2px;
    box-shadow: 0 0 0 2px var(--ob-focus-halo);
}

/* 2줄 — 1줄과 같은 문법([태그] + 텍스트). 같은 날 두 쌍이면 나란히. */
.ob-prog-2[b-x5libd1jj1] {
    display: flex;
    align-items: center;
    gap: 8px;
    min-width: 0;
    flex-wrap: wrap;
}

/* ⛔ `.ob-when`(태그+시각 묶음) 규칙 **삭제**(2026-08-26 오너 지시) — 시각이 1줄 `DAY` 자리로 올라가
   묶을 것이 없어졌다. 태그 칩은 이제 `.ob-prog-2` 의 직접 자식이고 그 줄의 gap(8px)을 그대로 쓴다. */

/* 시작·종료 시각 — 2026-08-26 오너 **재조정**으로 **둘째 줄 우측 끝**에 선다(`DAY nn` 바로 아래).
   이력: 원래 2줄에서 태그 옆 → (21번) 1줄 `DAY 15 · 15:00` → (23번) **2줄 우측 끝**.
   오너 원문: "프로그램에서 종료시 종료 시간은 **데이 아래**로 옮겨줘."
   📐 `margin-left: auto` 로 오른쪽 끝에 붙는다. 뱃지의 `margin-right:auto` 와 **충돌하지 않는다** —
      두 auto 마진이 모두 뱃지~시각 **사이**에 있어 남는 폭을 나눠 먹을 뿐, 뱃지는 왼쪽·시각은 오른쪽 끝이다.
      뱃지가 없는 날에도 이 한 줄로 같은 결과가 나온다.
   증상: 시각만 둘째 줄에 있어 **`종료` 카드의 시각이 다른 카드(시스템 칩·다른 프로그램 라벨)의
         우측 정렬 축에서 혼자 내려와 있었다.** 이제 세 종류의 카드가 같은 자리에서 시각·DAY 를 읽는다.
   📐 크기·굵기는 종전 그대로(0.74rem/700) — DAY 숫자(0.8rem/800)보다 **작게** 두어 위계가 뒤집히지 않는다.
   ℹ️ 가운뎃점은 `::before` 로 그린다(마크업에 글자를 넣지 않는다). `DAY 15` 와 `15:00` 사이의 구분자일 뿐이라
      투명도를 낮춰 둘 중 어느 값보다도 약하게 읽히게 했다. */
.ob-when-t[b-x5libd1jj1] {
    margin-left: auto;
    /* 🔄 2026-08-26 오너 지시 "시간 표시가 기존 다른 시스템 시간과 굵기와 크기가 다른거 같아".
       기준 = **1줄 시스템 칩의 시각**(`.ob-prog-d` 에 들어가는 `sc.Time`).
       실측 대조 → font-size 0.74→0.8rem · font-weight 700→800 · letter-spacing 없음→-0.01em.
       (color: inherit · tabular-nums 는 이미 같았고, opacity 는 양쪽 모두 없다.)
       ⛔ `DAY nn` 은 그 나름의 위계가 있으므로 **시각끼리만** 맞췄다 — `.ob-prog-d b`(900/1.05em)는 무변경. */
    font-size: 0.8rem;
    font-weight: 800;
    letter-spacing: -0.01em;
    color: inherit;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

/* ⛔ `.ob-when-t::before`(가운뎃점 구분자) **삭제**(2026-08-26) — 21번에서 `DAY 15 · 15:00` 으로
   한 줄에 합칠 때 만든 구분자다. 오너 재조정으로 시각이 **둘째 줄**로 내려가 DAY 와 붙어 있지 않으므로
   구분할 대상이 사라졌다(죽은 규칙을 남기지 않는다). */

/* DAY n — 라벨의 1차 정보. 이름보다 한 단계 크고 진하게, 숫자는 한 번 더 강조. */
.ob-prog-d[b-x5libd1jj1] {
    flex: 0 0 auto;
    flex-shrink: 0;      /* 분류칩이 붙어 1줄이 좁아져도 DAY 숫자는 절대 잘리지 않는다 */
    font-size: 0.8rem;
    font-weight: 800;
    letter-spacing: -0.01em;
    color: inherit;
    font-variant-numeric: tabular-nums;
}

.ob-prog-d b[b-x5libd1jj1] {
    font-weight: 900;
    font-size: 1.05em;
}

/* 분류칩 — 작고 진한 칩 + 흰 글자. 라벨에서 색을 담당하는 유일한 요소. */
.ob-kind[b-x5libd1jj1] {
    flex: 0 0 auto;
    text-align: center;   /* 라벨이 전부 2글자라 폭이 자연히 균일해진다(고정폭 불필요) */
    font-size: 0.58rem;
    font-weight: 800;
    line-height: 1.5;
    padding: 0 5px;
    border-radius: 6px;
    white-space: nowrap;
}

/* 시스템 항목 묶음 — 프로그램 라벨 스택 바로 아래 */
.ob-sys[b-x5libd1jj1] {
    display: flex;
    flex-direction: column;
    /* 6px: 2026-08-25 오너 지시 "카드 간격을 조금만 더 넓혀줘" — 4 → 6px.
       .ob-zone 과 **반드시 같은 값**을 쓴다(시스템 밴드와 카드 목록이 한 열에서 이어지는 리듬이라
       한쪽만 바꾸면 밴드 경계에서 간격이 튄다). 한쪽을 고치면 다른 쪽도 같이 고칠 것. */
    gap: 6px;
    padding: 4px 4px 0 4px;
    min-width: 0;
}

/* 시스템 항목 — 본문 배경색 없음(흰 면). 색은 분류칩 하나만 담당한다.
   🔑 2026-08-25: 하드코딩 `#f8fafc` → **`var(--ob-sys-face)`**. 값의 단일 출처는 C# 의 `OpsPalette.SystemFace` 이고
      `OpsBoard.razor` 가 `.ob-root` 에 인라인으로 주입한다. 같은 날 `일정` 카드의 기본색이 이 면과 같아졌기 때문에
      (오너 지시 "일정 기본색도 그냥 시스템이랑 같은 색으로") **두 곳이 갈라지면 안 되는 값**이 됐다.
   ⚠️ 폴백을 적어 두는 이유: 주입이 어떤 이유로 비면 종전 색으로 그려져야 한다(빈 배경으로 무너지지 않게). */
.ob-prog.sys[b-x5libd1jj1] {
    background: var(--ob-sys-face, #f8fafc);
    color: var(--ob-ink);
    cursor: pointer;
}

/* ④ 수동 카드 섹션 = 드롭존. **시스템 밴드 아래**에 오고 `flex:1` 로 열 바닥까지 늘어난다
   → 카드가 0건인 날도 빈 아래쪽 어디에나 떨어뜨릴 수 있다(드롭 대상이 칩 목록 크기로 쪼그라들지 않는다). */
.ob-col[b-x5libd1jj1]  .ob-zone {
    display: flex;
    flex-direction: column;
    gap: 6px;                 /* 시스템 밴드(.ob-sys)와 같은 간격 — 2026-08-25 오너 지시로 4 → 6px */
    padding: 4px 4px 4px 4px;
    flex: 1 1 auto;
    min-height: 48px;
}

/* 🔧 첫 번째 카드 클릭·드래그 복구(4단계, 3번 지시 — 원인 **확정**, MudBlazor 9.7.0 소스 실측).
   AllowReorder=true 인 MudDropZone 은 아이템이 있으면 첫 아이템 **앞에** 자리 예약용 더미 아이템
   (.mud-drop-item-preview-start)을 **상시** 렌더한다(MudDropZone.razor). MudBlazor 기본 CSS 가 이걸
   `position:absolute; top:0; left:0; width:100%; height:20px; z-index:1` 로 깔아 놓아
   **드롭존 맨 위 20px — 곧 첫 카드의 1줄(제목 줄) — 을 투명하게 덮는다.**
   그 띠 안에서는 ①클릭이 더미(disabled)에게 먹히고 ②draggable=false 라 dragstart 도 죽는다.
   3단계에서 AllowReorder 를 켠 순간부터 생긴 증상이라 시점도 맞는다.
   드래그 중 이 더미에 놓으면 IndexInZone=-1 인데 OnRowDropped 는 음수를 "위치 못 받음"으로 무시하므로
   이 화면에서 더미는 **아무 역할이 없다** → pointer-events 를 끊어 이벤트가 첫 카드로 흐르게 한다
   (맨 위 드롭은 첫 카드에 dragenter = index 0 으로 이미 성립한다). */
.ob-col[b-x5libd1jj1]  .ob-zone .mud-drop-item-preview-start {
    /* 유휴 상태: 투명하게 — 이 20px 띠가 첫 카드의 제목 줄을 덮어 클릭·드래그를 삼킨다(2026-08-24 사고). */
    pointer-events: none;
}

/* 🔴 **드래그 중에만 더미를 살린다** — 2026-08-26 "위로 끌어 첫 자리로" 버그의 해법.

   📌 원인(MudBlazor v9.7.0 소스 직독으로 확정):
     `MudDropZone.razor` 는 `AllowReorder` 이고 아이템이 있으면 첫 카드 **앞**에
     `<MudDynamicDropItem Disabled="true" Class="mud-drop-item-preview-start" />` 를 **무조건** 렌더한다.
     그 더미가 바로 **"맨 앞에 삽입" 전용 드롭 타깃**이다(index = -1).
     그 위에서 `dragenter` 가 나면 `UpdateTransactionIndex(-1)` → `MudDropZone.HandleDrop` 이
     `Container.GetTransactionIndex()` 로 그 값을 읽어 맨 앞 삽입으로 처리한다.
     ⇒ 위 `pointer-events:none` 이 **그 더미의 `dragenter` 를 통째로 막고 있었다** →
       같은 열에서는 "맨 앞"이라는 위치 자체에 도달할 수가 없었다.
     ℹ️ 카드 위에서는 아이템의 `dragenter` 가 그대로 도달하므로 **아래로 끌기는 멀쩡했다**(증상과 일치).
     ℹ️ `dragover:preventDefault` 는 **존(.ob-zone)에 무조건**으로 걸려 있다(아이템에는 없다) →
       존 바깥(시스템 밴드·구분선 영역)으로 벗어나면 금지 커서가 뜬다 — 오너가 본 그것.

   ✅ `DraggingClass` 는 **MudDropZone 공식 파라미터**다
      (*"CSS classes applied to drop zones during a drag-and-drop operation"*) → 드래그 중에만 붙는다.
      그래서 유휴 상태의 `pointer-events:none` 는 **그대로 살아 있고**(첫 카드 클릭 안전),
      드래그 중에만 더미가 이벤트를 받는다.
   ⛔ `pointer-events:none` 자체를 지우면 유휴 상태에서 첫 카드 클릭이 다시 죽는다(2026-08-24). 지우지 말 것. */
.ob-col[b-x5libd1jj1]  .ob-zone.ob-zone-dragging .mud-drop-item-preview-start {
    pointer-events: auto;
    /* ⛔ **32번(구분선까지 히트 영역 확장) 철회**(2026-08-26) — 회귀를 만들었다.
       `margin-top:-24px; height:44px` 로 더미 상자를 위로 24px 넓혔더니, 첫 카드를 **조금만 들어 올려도**
       커서가 그 띠에 들어가 index −1(맨 앞)이 잡혔다 → ①이미 맨 앞인 카드가 또 "맨 앞"으로 놓이고
       ②그 상태에서 아래로 내려도 두 번째 아래로 안 갔다(오너 제보).
       ⚖️ 판단: **회귀가 기능보다 우선**이다. 확장을 걷으면 "구분선까지 끌면 첫 행"은 사라지지만
          더미 본래의 20px 띠가 그대로 있어 **"위로 끌어 첫 행"(오너가 확인한 핵심 기능)은 유지**된다.
       ⛔ 다시 넓히지 마라 — 넓히는 순간 첫 카드의 조준 여유를 잡아먹는다. */
}

/* 🆕 2026-08-26 — **드래그 중인 카드가 이미 맨 앞이면 더미를 끈다.**
   맨 앞 카드를 "맨 앞으로" 옮기는 것은 의미가 없는데, 더미가 살아 있으면 그 무의미한 드롭이 성립해
   ①자기보다 위로 놓이고 ②인덱스가 −1 에 갇혀 아래로 내려도 두 번째 아래로 가지 않는다(오너 제보 증상).

   📐 판정: `:has(> .mud-drop-item-preview-start + .mud-drop-item.ob-dragging)`
      = "더미 **바로 다음** 요소(= 그 열의 첫 카드)가 지금 끌고 있는 카드인가".
      `ob-dragging` 은 `MudDropContainer` 의 `ItemDraggingClass` 로, 끌고 있는 아이템에만 붙는다.
   ✅ 특이도 (0,7,0) > 위 규칙 (0,5,0) 이라 확실히 이긴다(`:has()` 는 인자 중 가장 구체적인 것의 특이도를 더한다).
   ✅ **폴백이 안전하다**: `:has()` 미지원 브라우저면 이 규칙만 무시되고 **오너가 "해결되었어"라고 확인한
      직전 상태**로 떨어진다(회귀 상태가 아니다).
   ✅ 첫 카드가 아닌 카드를 끌 때는 이 규칙이 걸리지 않아 **위로 끌어 첫 행 이동은 그대로 동작**한다. */
.ob-col[b-x5libd1jj1]  .ob-zone.ob-zone-dragging:has(> .mud-drop-item-preview-start + .mud-drop-item.ob-dragging) .mud-drop-item-preview-start {
    pointer-events: none;
}

/* 드롭 위치 점선(2026-08-25 오너 지시) — MudBlazor 가 드래그 중에 그리는 자리표시자다.
   실제 클래스는 `border-2 mud-border-primary border-dashed … pa-4 mud-dropitem-placeholder`
   (MudBlazor 9.7.0 어셈블리 실측) — MudBlazor CSS 에 라운드 선언이 없어 **각진 사각형**으로 나온다.
   여기서 카드와 같은 6px 을 준다. 테두리 굵기·색·여백은 건드리지 않는다(`border-2`·`border-dashed` 는
   !important 라 어차피 이길 수 없고, 바꿔야 할 이유도 없다).

   🔴 2026-08-25 오너 지시 — **점선 상자를 끌고 있는 카드와 같은 크기로.**
      원인: 이 자리표시자는 **내용이 없는 한 겹**이라 높이가 `pa-4`(16px×2) + 테두리(2px×2) ≈ **36px 고정**이었다.
            카드는 ≈57px 부터 시작해 내용에 따라 더 커지므로 점선이 항상 카드보다 낮았다.
      해법: 세로만 `min-height` 로 끌어올린다 — 값은 `opsBoard.js` 가 **dragstart 에서 실측한 원본 카드 높이**
            (`--ob-drag-h`, #ob-scroll 에 얹힌다 → DOM 상속으로 여기까지 내려온다).
            드래그 중이 아니면 변수가 없으므로 폴백 **57px**(메모 없는 카드의 실측 기본 높이)을 쓴다.
      · `box-sizing: border-box` 가 필수다 — 없으면 min-height 에 패딩 32 + 테두리 4 가 **더해져** 카드보다 커진다.
      · 폭은 손대지 않는다. 자리표시자는 세로 flex 인 `.ob-zone` 의 자식이라 이미 열 폭을 채우고 있다.
      · 점선 색·굵기·라운드·여백은 그대로다(새로 디자인하지 않았다). */
.ob-col[b-x5libd1jj1]  .mud-dropitem-placeholder {
    box-sizing: border-box;
    min-height: var(--ob-drag-h, 57px);
    border-radius: 6px;
}

/* ⚠️ 예외 — 상단 더미(.mud-drop-item-preview-start) **안**의 자리표시자는 키우지 않는다.
   더미는 `position:absolute; top:0; height:20px` 인 20px 띠라(위 🔧 주석), 안쪽 상자를 57px 로 키우면
   그 밖으로 넘쳐 **첫 카드 위에 점선이 겹쳐 보인다.**
   키울 이유도 없다: 이 화면에서 더미는 `pointer-events:none` 이라 dragenter/dragover 를 받지 못하고,
   따라서 **드롭 대상이 되는 일 자체가 없다**(맨 위 드롭은 첫 카드에 dragenter = index 0 으로 성립).
   → `pointer-events:none` 규칙은 그대로 유효하며, 이 예외 덕분에 더미가 덮는 면적도 20px 그대로다. */
.ob-col[b-x5libd1jj1]  .ob-zone .mud-drop-item-preview-start .mud-dropitem-placeholder {
    /* 더미는 20px 띠라 안쪽 점선 상자를 카드 높이로 키우지 않는다(키우면 첫 카드 위로 넘친다). */
    min-height: 0;
}

/* ── 수동 카드 칩(할 일 · 일정) ─────────────────────────────────────
   2026-08-24 4차(오너 지시 5건) 기준 구조:
     1줄(.ob-t1):   [분류칩] 제목 ………… 시각          ← 체크박스 삭제(1번 지시)
     (.ob-tmemo):   메모 최대 2줄 — 메모가 있을 때만 그린다(5차 6번 지시, 없으면 기본 2줄 유지)
     2줄(.ob-t2):   ……………… [상태 드롭다운][담당자]   ← 둘 다 우측 정렬(4번 지시)
   담당자가 없어도 2줄은 남긴다 — 열 안 카드 높이가 카드마다 달라지지 않게(min-height).
   배경은 --lane(프로그램 색 상속 → 직접 지정색 → 기본 중성색), 글자색 --lane-fg 는 대비 자동 반전. */
.ob-prog.task[b-x5libd1jj1] {
    /* .ob-prog 가 이미 background:var(--lane) / color:var(--lane-fg) 이라 색 선언은 필요 없다.
       .ob-prog 의 가로 flex 를 세로 2줄로 뒤집는다(.two-line 프로그램 라벨과 같은 문법). */
    flex-direction: column;
    align-items: stretch;
    /* 상하 여백(2026-08-24 5차, 오너 지시 5번 "제목·본문·이름 태그가 붙어 답답하다"):
         줄 사이 gap 2 → 5px · 위아래 padding 4 → 7px(좌우 8px 은 그대로).
       ⚖️ 한 열에 보이는 카드 수를 지키려고 폭은 안 건드리고 세로만 늘렸다 —
          메모 없는 카드 기준 ≈45 → ≈57px(+12px).
       🔻 2026-08-25(A-1): 메모 미리보기 줄이 카드에서 빠졌다 → **모든 카드가 1줄+2줄 = 메모 없던 높이(≈57px)로 균일**해졌고,
          메모가 있던 카드는 ≈81 → ≈57px 로 24px 낮아졌다.
       🔺 2026-08-25 오너 지시 "카드 내부 상하 패딩을 조금만 더 넓혀줘": padding 7 → 8px(위아래 각 +1, 카드 +2px).
          gap(5px)은 **줄 사이**라 "상하 패딩"이 아니므로 건드리지 않았다 — 지시 범위를 넘기지 않는다.
       ⛔ 줄이는 방향은 여전히 금지: .ob-zone 의 첫 카드는 MudBlazor 더미(.mud-drop-item-preview-start,
          `position:absolute; top:0; height:20px; z-index:1`)에 덮이는데 그 방어는 pointer-events:none 하나뿐이다.
          패딩이 작아질수록 첫 카드의 1줄이 그 20px 띠 안에 더 깊이 들어간다.
          실측(존 padding-top 4px 기준): 1줄이 띠와 겹치는 양이 7px 일 때 9.2px → 8px 일 때 8.2px 로 **줄었다**
          (키우는 방향은 안전하다). 그래도 겹침이 사라지진 않으므로 **그 규칙을 지운다는 선택지는 없다**
          (위 🔧 주석 참조). */
    gap: 5px;
    padding-top: 8px;
    padding-bottom: 8px;
    cursor: pointer;
}

.ob-prog.task .ob-t1[b-x5libd1jj1],
.ob-prog.task .ob-t2[b-x5libd1jj1] {
    display: flex;
    align-items: center;
    gap: 6px;
    min-width: 0;
}

/* 2줄 = [상태][담당자] **둘 다 우측 정렬**(4단계, 4번 지시 — 이전의 좌/우 분산 배치 폐기).
   담당자가 없어도 높이를 유지한다. 시각(1줄 우측 끝)과 세로로 정렬돼 우측 열이 한 줄로 읽힌다. */
.ob-prog.task .ob-t2[b-x5libd1jj1] {
    justify-content: flex-end;
    min-height: 18px;
}

/* ⛔ `.ob-prog.task .ob-tmemo`(접힌 카드의 메모 2줄 미리보기) 규칙 삭제 — 2026-08-25 오너 지시 A-1.
   같은 메모가 접힌 카드에 2줄, 펼친 확장 패널에 또 한 번 나와 한 카드 안에서 두 번 읽혔다.
   메모의 자리는 이제 두 층뿐이다: **확장 패널 2줄 요약(.ob-exp-note) → `내용 보기` 다이얼로그 전문.**
   부수 효과: 메모가 있는 카드 높이가 약 24px(2줄 × 0.66rem × 1.35 + gap) 줄어 한 열에 더 많이 들어온다. */

/* ── 상태 드롭다운(3단계, 색 4단계) ──────────────────────────────────
   네이티브 <select> 다 — 목록을 OS 가 그리므로 가로 스크롤 컨테이너의 overflow·stacking 을 통과한다
   (이 화면은 MudPopover 계열이 안 열리는 사고를 이미 겪었다. .razor 의 해당 주석 참조).
   색(4단계, 2번 지시): 반투명 먹 단색을 버리고 **상태별 클래스(.st-*)** 로 배경·글자·테두리를 갈랐다.
   매핑은 .razor 의 StatusClass() — 라벨(할일/일정)이 아니라 Status enum 값 기준. */
.ob-stwrap[b-x5libd1jj1] {
    flex: 0 0 auto;
    display: inline-flex;
    min-width: 0;
}

.ob-stsel[b-x5libd1jj1] {
    -webkit-appearance: none;
    appearance: none;
    box-sizing: border-box;
    max-width: 96px;
    height: 17px;
    padding: 0 16px 0 6px;
    border: 1px solid transparent;   /* 상태색 규칙(.st-*)이 색만 채운다 — 폭·높이는 전 상태 동일 */
    /* 🔄 2026-08-25 오너 지시 "예정도 라운드 각도 맞춰줘" — 8px → **--ob-chip-r(= 분류 태그 6px)**.
       ✅ 브라우저 기본 스타일에 덮이지 않는다: 바로 위 `-webkit-appearance:none; appearance:none` 이
          네이티브 select 의 기본 렌더링을 이미 끈 상태라 `border-radius` 가 그대로 적용된다.
       ℹ️ 기록된 크롬 함정은 **`option` 목록**(OS 가 그리는 팝업) 쪽이라 컨트롤 본체의 라운드와 무관하다. */
    border-radius: var(--ob-chip-r);
    /* 드롭다운임을 알리는 캐럿 — 아이콘 폰트·이미지 없이 그린다(외부 자산 0). currentColor 라 상태 글자색을 따라간다. */
    background-image: linear-gradient(45deg, transparent 50%, currentColor 50%), linear-gradient(135deg, currentColor 50%, transparent 50%);
    background-position: calc(100% - 9px) 6px, calc(100% - 6px) 6px;
    background-size: 3px 3px, 3px 3px;
    background-repeat: no-repeat;
    font-size: 0.6rem;
    font-weight: 800;
    line-height: 1;
    cursor: pointer;
}

/* 상태별 색(2번 지시) — 기존 상태 색 관례가 없어(상태 점은 3단계에 폐기·무색이었다) 분류칩 9색과
   **같은 hue 계열의 저채도 파스텔 + 진한 글자**로 새로 잡았다: 카드 면(--lane)보다 튀지 않는 톤.
   진행중=공지 블루(224°) · 완료=행사 그린(163°) · 미확정=투표 바이올렛(263°) 계열, 보류=경고 앰버, 예정=중성. */
.ob-stsel.st-plan[b-x5libd1jj1] { background-color: #e2e8f0; border-color: #cbd5e1; color: #334155; }  /* 예정 */
.ob-stsel.st-prog[b-x5libd1jj1] { background-color: #dbeafe; border-color: #bfdbfe; color: #1d4ed8; }  /* 진행중 */
.ob-stsel.st-done[b-x5libd1jj1] { background-color: #d1fae5; border-color: #a7f3d0; color: #047857; }  /* 완료·종료 */
.ob-stsel.st-hold[b-x5libd1jj1] { background-color: #fef3c7; border-color: #fde68a; color: #92400e; }  /* 보류·취소 */
.ob-stsel.st-tent[b-x5libd1jj1] { background-color: #ede9fe; border-color: #ddd6fe; color: #6d28d9; }  /* 미확정(레거시) */

/* 호버 = 상태색 위에 먹 6%를 한 겹 — 상태마다 호버 규칙을 5벌 만들지 않는다. */
.ob-stsel:hover:not(:disabled)[b-x5libd1jj1] {
    box-shadow: inset 0 0 0 99px rgba(15, 23, 42, 0.06);
}

.ob-stsel:disabled[b-x5libd1jj1] {
    cursor: default;
    opacity: 0.7;
}

/* 상태 select — 카드 안(=임의 배경)에 앉으므로 카드와 같은 이중 링을 쓴다. */
.ob-stsel:focus-visible[b-x5libd1jj1] {
    outline: 2px solid var(--ob-focus);
    outline-offset: 2px;
    box-shadow: 0 0 0 2px var(--ob-focus-halo);
}

/* 목록 자체는 OS 가 그리므로 배경/글자색을 명시해 둔다(카드 색이 상속돼 흰 바탕에 흰 글자가 되지 않게).

   📐 2026-08-25 오너 지시 "닫힌 버튼은 작아도 되는데 열린 목록이 너무 작다".
   ✅ 채택한 방법: **`option` 에만** 크기를 준다. 크롬은 닫힌 트리거의 글자를 `select` 자신의 font-size 로,
      열린 목록을 `option` 의 font-size 로 그린다 → 트리거는 0.6rem(9.6px) 그대로, 목록만 커진다.
      레이아웃에 손대지 않는 유일한 길이라 이걸 1순위로 골랐다.
   📏 값 0.8125rem = **13px** — 새 치수를 만들지 않았다. 이 파일 툴바 규격의 본문 글자와 같은 값이다
      (파일 상단 §툴바 "폰트 13px"). 9.6 → 13px 은 +35%로, 한글 3~4자 라벨이 확실히 읽히는 지점이다.
   🧱 트리거·카드 높이 불변 증명:
      · 높이 — `.ob-stsel` 은 `height:17px` **고정**이다. option 폰트가 무엇이든 닫힌 상자 높이는 17px 이고
        따라서 `.ob-t2`(min-height 18px)도, 카드 높이도 변하지 않는다.
      · 폭 — 만에 하나 크롬이 option 폰트로 트리거의 고유 폭을 계산하더라도 `max-width:96px` 이 상한이다.
        최악(96px)에서도 2줄 폭 계산: 96 + gap 6 + 담당자 최대 161.24(=278×58%) = **263.24px < 278px**
        → 줄바꿈·클리핑 없음(둘 다 우측 정렬이라 남는 공간만 줄어든다).
   ⛔ MudMenu·MudPopover 로 갈아타지 않았고 자체 팝업도 만들지 않았다(개발 규칙 §MudBlazor 금지 항목).
   ℹ️ `padding`/`line-height` 는 Windows 크롬이 option 에 대해 무시할 수 있다 — 무시돼도 손해가 없고
      리눅스·일부 빌드에서는 먹히므로 보험으로 함께 둔다. 크기의 실효 수단은 font-size 하나다. */
.ob-stsel option[b-x5libd1jj1] {
    background: #ffffff;
    color: var(--ob-ink);
    font-weight: 600;
    font-size: 0.8125rem;
    line-height: 1.8;
    padding: 6px 10px;
}

/* 완료 = **취소선만.** 2026-08-25 오너 지시 13으로 `opacity:0.55` 를 걷어냈다.
   흐림은 카드 색(=어느 프로그램인가)과 글자를 동시에 죽여, 끝난 일을 "읽을 수 없는 일"로 만들고 있었다.
   완료를 알리는 신호는 둘 남는다: 제목 취소선 + 상태 드롭다운의 초록칩(.st-done, `완료`/`종료` 글자 포함). */
.ob-prog.task.done .ob-prog-t[b-x5libd1jj1] {
    text-decoration: line-through;
}

/* ⛔ .ob-check(완료 체크박스) 규칙 일괄 삭제 — 4단계(2026-08-24, 1번 지시).
   상태 드롭다운이 같은 값(완료 토글)을 다루는 중복이라 체크박스 자체가 카드에서 빠졌다. */

/* ── ③ 시스템 밴드 / 수동 카드 구분선 ────────────────────────────────
   위아래 **양쪽에 내용이 있을 때만** 그린다(빈 섹션 헤더·안내 문구 없음 — 장식 총량 유지).
   ⚠️ 2단계 용어 정리: 위쪽(②)은 '시스템' 밴드다. `일정`은 수동 카드 타입 이름이므로 이 선을 '일정 구분선'이라 부르지 않는다. */
.ob-div[b-x5libd1jj1] {
    /* 시스템 밴드와 수동 카드 영역을 가르는 선. 열당 **최대 1개**만 그려진다
       (양쪽에 내용이 있을 때만 — `HasTasks(d) && _sysByDay.ContainsKey(d.Date)`).

       ── 이력 ─────────────────────────────────────────────────────────────
       2026-08-25 오너 "조금 더 명확하게, 위아래 간격도 넓게" → 색 #e2e8f0 → #cbd5e1, 여백 8 → 12px.
       2026-08-26 오너 ①"상하 간격을 **살짝만** 더 띄워" ②"조금 더 **눈에 띄게**" → 여백 16px + 2px 실선.
       2026-08-26 오너 "**너무 두꺼워.** 그라데이션이든 뭐든 선 디자인 좀 이쁘게" → **현행: 1px 그라데이션.**
       ⛔ 2px 로 되돌리지 마라 — 굵기로 존재감을 주면 구조선이 카드와 경쟁한다(오너가 물린 방향이다).

       ── 현행 설계 ────────────────────────────────────────────────────────
       📏 여백 **16px**(`--ob-div-gap`) · 좌우 4px(`.ob-sys`/`.ob-zone` 패딩과 끝이 맞는다).
          발자국 33px(16+1+16). 열 높이는 `.ob-zone{flex:1 1 auto}` 가 흡수하므로 **다른 열과 어긋나지 않는다.**
       🎯 **1px + 가로 그라데이션**(가운데 진하고 양끝 투명).
          굵기(면적)로 존재감을 주면 선이 무거워져 카드와 경쟁한다. 가운데만 진하게 하면
          **최대 대비는 올라가고 평균 무게는 내려간다** — 눈에는 더 띄고 화면에는 덜 얹힌다.
          양끝이 사라져 둥근 열 하단 모서리와도 부드럽게 만난다.
       🎨 **새 색 없음** — `--ob-muted`(#475569) 파생 `color-mix` 하나뿐
          (이 파일의 기존 기법: `.ob-cmt` 테두리 `color-mix(currentColor 34%)`).
       📐 대비 실측(가운데 최대치): 흰 열 **2.34:1** · 인접 카드(#f8fafc) 위 **2.26:1**.
          양끝으로 갈수록 0 에 수렴하므로 체감 무게는 이보다 훨씬 낮다.
          직전 2px 실선(1.76:1 균일)보다 **가운데는 진하고 전체는 가볍다.**
       ⚖️ 위계 유지: 글자(`--ob-ink` 17.9:1)·분류칩과 자릿수가 다르고, 1px 이라 면적이 없다.
       ℹ️ `height:0 + border-top` → **`height:1px` + `background`** (그라데이션은 border 로 못 그린다). */
    height: 1px;
    margin: var(--ob-div-gap) 4px;
    background: linear-gradient(90deg,
        transparent 0%,
        color-mix(in srgb, var(--ob-muted) 50%, transparent) 18%,
        color-mix(in srgb, var(--ob-muted) 50%, transparent) 82%,
        transparent 100%);
}

/* ── 상태 · 담당자 · 기간 일정 ──────────────────────────────────────

   2단계 원칙("어느 것도 카드의 폭·높이·정렬을 바꾸지 않는다")은 3단계 오너 지시로 **의도적으로 깨졌다** —
   카드가 기본 2줄이 되면서 상태와 담당자가 1줄의 자리를 다투지 않게 됐기 때문이다.
   그래서 이 구역에서 사라진 것: `.ob-st`(상태 점) · `.pri-high`/`.pri-low`(우선순위 좌측 바). */

/* ⛔ `.ob-prog.task.muted { opacity:0.62 }` 삭제 — 2026-08-25 오너 지시 13(완료 상태에 불투명 처리 금지).
   보류(할 일) · 취소(일정) · 미확정(레거시)의 구분은 이제 **상태 드롭다운의 색·글자 하나**가 전부다
   (.st-hold 앰버 `보류`/`취소`, .st-tent 바이올렛 `미확정`). 취소선은 원래 완료 전용이라 여기엔 없었다.
   ⚠️ 오너 확인 필요: 카드 겉모습만으로는 보류/취소가 예정과 구별되지 않는다(상태칩을 읽어야 안다). */

/* 담당자 태그 — 3단계부터 **풀네임**(2단계는 이니셜 2자였다). 시각 바로 아래(2줄 오른쪽 끝)에 온다.
   이름이 길면 잘린다(전체 이름은 호버 팝업의 담당자 행에 있다).

   색(2026-08-24 5차, 오너 지시 4번 "타입 태그와 같은 칙칙한 색") — **중립 흰 칩 + 잉크 글자 + 얇은 테두리**.
    · 이전 값(반투명 먹 rgba(15,23,42,.16) + 글자색 상속)은 타입 태그와 같은 회색 덩어리로 읽혔다.
    · 새 값은 타입 태그(진한 채도 + 흰 글자)와 **명암이 정확히 반대**라 한 줄 안에서 둘이 절대 안 섞인다.
    · 담당자별로 색을 갈라 무지개를 만들지 않았다 — 개발 규칙 §디자인 관례가 금지하고,
      [[Fandora Manager 개발 규칙]] 의 "중립 흰 칩" 이 이 자리의 기본형이다. 필터 팝업의 이니셜 배지
      (필터 패널의 담당자 배지와 같은 계열이었다 — 그 배지는 2026-08-26 오너 지시로 삭제됐고 이 칩만 남았다).
    · 카드 배경은 파스텔(24색)이 기본이지만 오너가 임의 색을 고르면 어두울 수 있다 — 흰 칩은 **양쪽 모두**에서
      살아남는 유일한 선택지다(어두운 배경 위 흰 칩 = 최대 대비, 밝은 배경 위에서는 테두리가 경계를 만든다). */
.ob-who[b-x5libd1jj1] {
    flex: 0 1 auto;
    box-sizing: border-box;   /* 테두리가 생겼으므로 높이를 상태 드롭다운(17px)과 맞추려면 필수 */
    display: inline-flex;
    align-items: center;
    justify-content: center;
    max-width: 58%;
    height: 17px;
    padding: 0 7px;
    border: 1px solid rgba(15, 23, 42, 0.14);
    border-radius: var(--ob-chip-r);   /* 🔄 2026-08-25 오너 지시 "이름도 라운드 각도 맞춰줘" — 8px → 분류 태그의 6px */
    background: #ffffff;
    color: #1e293b;
    font-size: 0.62rem;
    font-weight: 800;
    line-height: 1;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* 기간 일정 — 열마다 카드를 복제해 그리고, **맞닿는 모서리를 각지게** 만들어 '이어짐'을 보여 준다.
   열 사이에는 12px 간격(--ob-gap)이 있어 실제로 붙지는 않지만, 둥근 쪽/각진 쪽의 차이만으로
   "여기서 시작해서 저기서 끝난다"가 읽힌다 — 연결선을 그리려면 열 경계를 넘는 오버레이 층이 필요한데
   그건 sticky 헤더·드롭존과 겹쳐 위험이 크다(그래서 채택하지 않았다). */
.ob-prog.task.span-start[b-x5libd1jj1] {
    border-top-right-radius: 0;
    border-bottom-right-radius: 0;
}

.ob-prog.task.span-mid[b-x5libd1jj1] {
    border-radius: 0;
}

.ob-prog.task.span-end[b-x5libd1jj1] {
    border-top-left-radius: 0;
    border-bottom-left-radius: 0;
}

/* 첫날이 아닌 복제본은 한 톤 눌러 **원본이 어디인지** 알 수 있게 한다(끌 수 있는 카드도 첫날뿐이다). */
.ob-prog.task.span-mid[b-x5libd1jj1],
.ob-prog.task.span-end[b-x5libd1jj1] {
    /* 2026-08-25 항목 14(색이 우중충하다): 0.86 → 0.92. 복제본을 "한 톤 누른다"는 목적은 유지하되
       파스텔 카드가 뿌옇게 바래던 정도를 절반으로 줄였다. 원본 위치는 모서리 처리(span-start 만 왼쪽이 둥글다)가
       이미 알려 주므로 이 톤은 보조 신호다. ⚠️ 완전히 없앨지는 오너 판단(지시 13은 '완료 상태' 한정이었다). */
    opacity: 0.92;
    cursor: pointer;
}

/* ⛔ 검색 상자(.ob-search / .ob-search-in / .ob-search-x) 규칙 삭제 2026-08-24 5차 — 검색 기능 폐기(오너 지시 1번). */

/* ── 필터 팝오버 섹션 머리글 · 담당자 행 ───────────────────────────── */
.ob-fl-h[b-x5libd1jj1] {
    padding: 6px 8px 2px 8px;
    font-size: 0.68rem;
    font-weight: 800;
    letter-spacing: 0.02em;
    color: var(--ob-muted);
}

/* ⛔ 2026-08-24 5차: 담당자 머리글 위 가로 구분선(.ob-fl-h:not(:first-child)) 제거 —
   두 영역이 좌우로 서면서 구분은 .ob-fl-sec.people 의 **세로선**이 맡는다. */

/* ⛔ `.ob-fl-who`(필터 패널 담당자 이니셜 배지) 규칙 **삭제**(2026-08-26 오너 지시) —
   그리는 마크업이 함께 사라져 죽은 규칙이 됐다. ⛔ 카드의 `.ob-who` 는 **그대로**다. */

.ob-fl-name[b-x5libd1jj1] {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-size: 0.8rem;
    font-weight: 600;
    color: var(--ob-ink);
}

/* ── 빠른 추가 입력줄(열 맨 위) ───────────────────────────────────────
   `+` 를 누른 열에만 나타난다. 열 카드 안쪽이라 폭이 좁으므로 버튼 두 개는 글자만(아이콘 없이) 쓴다. */
.ob-quick[b-x5libd1jj1] {
    display: flex;
    align-items: center;
    gap: 4px;
    margin: 6px 4px 0 4px;
    padding: 4px;
    border: 1px solid var(--ob-ring);
    border-radius: 8px;
    background: #ffffff;
}

.ob-quick-in[b-x5libd1jj1] {
    flex: 1 1 auto;
    min-width: 0;
    height: 24px;
    padding: 0 6px;
    border: none;
    outline: none;
    background: transparent;
    color: var(--ob-ink);
    font-size: 0.76rem;
    font-weight: 600;
}

.ob-quick-in[b-x5libd1jj1]::placeholder {
    color: #94a3b8;
    font-weight: 500;
}

.ob-quick-b[b-x5libd1jj1] {
    flex: 0 0 auto;
    height: 24px;
    padding: 0 6px;
    border: 1px solid #cbd5e1;
    border-radius: 6px;
    background: #ffffff;
    color: #475569;
    font-size: 0.68rem;
    font-weight: 700;
    line-height: 1;
    cursor: pointer;
}

.ob-quick-b:hover[b-x5libd1jj1] {
    background: #f1f5f9;
    border-color: #94a3b8;
    color: var(--ob-ink);
}

.ob-quick-b:disabled[b-x5libd1jj1] {
    opacity: 0.45;
    cursor: default;
}

/* ── 카드 확장 패널 (.ob-exp) — 2026-08-25, 호버 팝업 대체 ─────────────
   설계 원칙 셋:
     ① **칩 안에서 자란다.** 흰 패널을 덧대지 않는다 — 칩 안에 또 하나의 카드를 넣는 꼴이 되고
        (중첩 카드 금지) 프로그램 색이 잘려 어느 프로그램의 카드인지 알 수 없게 된다.
        구분은 색이 아니라 **1px 헤어라인 + 여백**이 한다.
     ② **색을 새로 만들지 않는다.** 글자·테두리는 전부 `currentColor`(= --lane-fg, 배경 휘도로 이미
        자동 반전된 값)에서 알파만 낮춰 파생한다 → 24색 팔레트든 오너가 고른 임의 색이든 대비가 성립한다.
        보조 텍스트를 회색으로 고정하면 어두운 카드에서 즉시 죽는다.
     ③ **in-flow.** position/z-index 를 쓰지 않으므로 stacking context·overflow 클리핑 문제가 없다. */
.ob-exp[b-x5libd1jj1] {
    margin-top: 6px;
    padding-top: 6px;
    border-top: 1px solid currentColor;
    /* 헤어라인은 글자색에서 파생 — 밝은 카드에서 검정 선이 되지 않도록 알파를 낮춘다.
       2026-08-25 항목 14: 18% → 26%. 18% 는 파스텔 카드 위에서 사실상 보이지 않아
       확장 패널이 카드 본문과 한 덩어리로 뭉개졌다(구분이 없으니 "같은 내용이 또 있다"로도 읽힌다). */
    border-top-color: color-mix(in srgb, currentColor 26%, transparent);
    cursor: default;
    text-align: left;
    /* 펼침·접힘 모션 — 0fr ↔ 1fr 로 높이를 애니메이션한다(내용 높이를 몰라도 된다).
       Blazor 가 이 요소를 **새로 삽입**하므로 transition 은 시작 상태가 없어 못 쓴다 → keyframes.
       2026-08-25 오너 지시 12:
         · 펼침 200ms → **260ms**, 곡선도 한 단계 부드럽게(0.16,1,0.3,1 → 0.22,1,0.36,1).
           둘 다 expo-out 계열이지만 뒤쪽이 조금 덜 급격히 멈춰서 열리는 끝맺음이 매끄럽다.
         · 접힘 **180ms**(펼침의 약 0.7배) — 오너가 접힘 애니메이션을 원했고, 나가는 쪽은 들어오는 쪽보다
           빠른 편이 자연스럽다. 곡선은 가속(ease-in)이라 "닫힌다"가 분명하게 읽힌다.
           ⚠️ `forwards` 필수 — 없으면 애니메이션이 끝나는 순간 원래 높이로 튄 뒤 노드가 사라진다.
           ⚠️ 이 180ms 는 .razor 의 `EXP_CLOSE_MS` 와 **반드시 같은 값**이다(한쪽만 바꾸면 어긋난다). */
    display: grid;
    grid-template-rows: 1fr;
    animation: ob-exp-open-b-x5libd1jj1 260ms cubic-bezier(0.22, 1, 0.36, 1);
}

.ob-exp.ob-closing[b-x5libd1jj1] {
    animation: ob-exp-close-b-x5libd1jj1 180ms cubic-bezier(0.4, 0, 1, 1) forwards;
}

/* ⚠️ 0fr → 1fr 은 **첫 번째 트랙**만 움직인다 → 확장 내용은 반드시 **자식 하나**로 묶어야 한다.
   내용을 .ob-exp 의 직계 형제 4개(rows·note·imgs·acts)로 두면 2번째부터는 암시 트랙(auto)이라
   애니메이션에서 빠지고 열이 한 번에 튄다. 이 래퍼가 그 단일 트랙이자 **잘리는 층**이다. */
.ob-exp-in[b-x5libd1jj1] {
    min-width: 0;
    min-height: 0;
    overflow: hidden;
}

/* ℹ️ 정정(2026-08-25 실측): 이 SDK(.NET 10 / Razor 스코프 CSS)는 `@keyframes` 이름도 **스코프한다** —
   생성 번들에서 `@keyframes ob-exp-open-b-x5libd1jj1` 로 나오고 참조도 같이 바뀐다(전역 이름이 아니다).
   그래도 ob- 접두사는 유지한다: 클래스 `.ob-exp-in` 과 구별되고, 번들을 눈으로 훑을 때 출처가 바로 보인다. */
@keyframes ob-exp-open-b-x5libd1jj1 {
    from {
        grid-template-rows: 0fr;
        opacity: 0;
    }

    to {
        grid-template-rows: 1fr;
        opacity: 1;
    }
}

@keyframes ob-exp-close-b-x5libd1jj1 {
    from {
        grid-template-rows: 1fr;
        opacity: 1;
    }

    to {
        grid-template-rows: 0fr;
        opacity: 0;
    }
}

/* 모션 최소화 환경 — 움직임만 없애고 상태 변화(등장·퇴장)는 그대로 보이게 한다.
   접힘도 1ms 로 끝나지만 `forwards` 덕분에 **접힌 모양 그대로** 남아 있다가 노드가 제거된다
   (즉 사용자에겐 즉시 닫힌 것으로 보인다). 호버 아웃라인의 색 전이도 여기서 끈다. */
@media (prefers-reduced-motion: reduce) {
    .ob-exp[b-x5libd1jj1],
    .ob-exp.ob-closing[b-x5libd1jj1] {
        animation-duration: 1ms;
    }

    .ob-prog[b-x5libd1jj1] {
        transition: none;
    }

    /* 2026-08-25 — 부양 호버(확대 + 그림자)는 **모션을 줄인 사용자에게 전부 끈다.**
       신호가 사라지는 것이 아니라 **아웃라인 방식으로 되돌아간다**: .ob-prog:hover 의
       `outline-color` 는 위에서 그대로 살아 있고, 이 블록은 transform/box-shadow/z-index 만 되돌린다.
       (그래서 아웃라인을 걷어내지 않았다 — 걷었다면 여기서 호버 어포던스가 통째로 사라졌을 것이다.) */
    .ob-prog:not(.expanded):hover[b-x5libd1jj1] {
        transform: none;
        box-shadow: none;
        z-index: auto;
    }

    /* 위 규칙이 box-shadow 를 지우면 포커스 헤일로까지 같이 사라지므로 헤일로만 되살린다. */
    .ob-prog:not(.expanded):hover:focus-visible[b-x5libd1jj1] {
        box-shadow: 0 0 0 2px var(--ob-focus-halo);
    }
}

.ob-exp-rows[b-x5libd1jj1] {
    display: flex;
    flex-direction: column;
    gap: 1px;
}

.ob-exp-row[b-x5libd1jj1] {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 10px;
    font-size: 0.68rem;
    line-height: 1.5;
    min-width: 0;
}

/* 라벨은 조용히, 값은 또렷하게 — 위계를 색이 아니라 **투명도·굵기**로 만든다(카드 색과 무관하게 성립). */
.ob-exp-k[b-x5libd1jj1] {
    flex: 0 0 auto;
    font-weight: 700;
    /* 항목 14: 0.7 → 0.82. 위계는 **굵기(700 vs 800)와 정렬**이 이미 만들고 있어서
       투명도까지 크게 낮출 필요가 없었다. 가장 어두운 팔레트 색(#96a0de) 위 잉크 기준
       0.7 → **4.05:1(AA 미달)** / 0.82 → 5.21:1. 라벨은 읽으라고 있는 글자다. */
    opacity: 0.82;
    white-space: nowrap;
}

.ob-exp-v[b-x5libd1jj1] {
    min-width: 0;
    text-align: right;
    font-weight: 800;
    font-variant-numeric: tabular-nums;
    overflow-wrap: anywhere;
}

/* 프로그램 행 — 분류칩(.ob-kind, 기존 스타일 그대로) + 이름. 이름만 말줄임한다. */
.ob-exp-v.prog[b-x5libd1jj1] {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 6px;
}

.ob-exp-pname[b-x5libd1jj1] {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* 상세내용(note) — 확장에서는 **4줄까지**만(2026-08-25 오너 지시 B-2, 2줄 → 4줄). 전문은 `내용 보기`가 연다.
   접힌 카드의 미리보기가 사라졌으므로(A-1) 이제 이 4줄이 보드 위 상세내용의 **유일한** 표시다.

   🔴 **버그 수정(2026-08-25 오너 지시 B-1) — `overflow:hidden` 누락.**
      `-webkit-line-clamp` 는 **`overflow:hidden` 과 짝일 때만** 잘린다. 없으면 요소의 **높이만** N줄로 확정되고
      본문은 그 상자 밖으로 계속 그려진다 → 바로 아래 형제인 `.ob-exp-acts`(내용 보기·메뉴로 이동·수정) 위에
      글자가 겹쳐 찍혀 버튼이 판독 불가가 됐다. 부모 `.ob-exp-in{overflow:hidden}` 은 **확장 패널 바깥**만
      잘라 주므로 패널 **안쪽**에서 벌어지는 이 겹침을 막지 못한다(그래서 증상이 화면에 남았다).
      → 말줄임은 여기서 끝내고, 어떤 길이의 상세내용에서도 액션 줄의 자리는 침범되지 않는다. */
.ob-exp-note[b-x5libd1jj1] {
    margin-top: 6px;
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 4;
    line-clamp: 4;
    /* ⚠️ 이 한 줄이 위 버그의 수정이다 — 클램프의 필수 짝. 지우지 말 것. */
    overflow: hidden;
    font-size: 0.68rem;
    font-weight: 500;
    line-height: 1.45;
    /* 항목 14: 0.82 → 0.92. 가장 어두운 팔레트 색(#96a0de) 위 잉크 기준 5.21:1 → 6.30:1.
       "제목보다 조용하게"는 크기(0.68rem)와 굵기(500)가 이미 충분히 만든다. */
    opacity: 0.92;
    overflow-wrap: anywhere;
}

/* 🔴 2026-08-25 오너 지시 — **구분선은 위에 요약 상자가 실제로 있을 때만 그린다.**
   증상: 프로그램이 없는 카드는 요약 행이 0개인데도 이 선이 그어져, 내용 없는 줄 하나가 카드에 남았다.
   고친 방식: `border-top` 을 기본 규칙에서 떼어 **인접 형제 선택자**로 옮겼다.
     · 마크업 쪽에서 행이 0개면 `.ob-exp-rows` 자체를 렌더하지 않는다(→ .razor `cHasRows`).
     · 그러면 이 선택자가 성립하지 않아 선도 padding 도 붙지 않는다 — **빈 자리가 남지 않는다**
       (`display:none` 으로 덮는 방식이 아니다).
   ⚠️ `.ob-exp-note` 는 수동 카드 확장에서만 쓰이고, 그 안에서 `.ob-exp-rows` 의 **바로 다음 형제**다
      (razor 주석은 요소가 아니라 인접 관계를 깨지 않는다). */
.ob-exp-rows + .ob-exp-note[b-x5libd1jj1] {
    padding-top: 6px;
    border-top: 1px solid color-mix(in srgb, currentColor 22%, transparent);   /* 14% → 22%, 항목 14 */
}

/* ⛔ `.ob-exp-nimg`(상세내용 미리보기 썸네일) **삭제** — 2026-08-25 오너 지시
   "미리보기에서는 이미지를 렌더하지 마라 — 텍스트만". 마크업 쪽 `NoteThumb` 과 함께 걷었다.
   ⚠️ 아래 `.ob-exp-imgs`/`.ob-exp-img` 는 **다른 것**이다 — 시스템 칩(배너·팝업·앱 메인) 미리보기라 그대로 둔다. */

/* 시스템 칩 확장의 이미지 미리보기 — 배너·팝업·앱 메인. **1장만**(2026-08-24 오너 지시 유지). */
.ob-exp-imgs[b-x5libd1jj1] {
    margin-top: 8px;
}

.ob-exp-img[b-x5libd1jj1] {
    margin: 0;
    width: 100%;
}

.ob-exp-img img[b-x5libd1jj1] {
    display: block;
    width: 100%;
    max-width: 100%;
    /* height 고정 — lazy 로딩 중에도 확장 높이가 튀지 않는다(열 전체가 출렁이지 않게). */
    height: 160px;
    object-fit: contain;
    background: #f1f5f9;
    border-radius: 6px;
}

.ob-exp-img figcaption[b-x5libd1jj1] {
    margin-top: 4px;
    text-align: center;
    font-size: 0.62rem;
    font-weight: 700;
    opacity: 0.88;   /* 항목 14 — 0.75 는 흰 시스템 칩 위에서도 흐렸다 */
}

/* ── 액션 버튼 3종 (내용 보기 · 메뉴로 이동 · 수정) ──────────────────────
   툴바 컨트롤 언어(높이 32 · 라운드 8 · 13px)를 **한 단계 줄인** 축소판이다 —
   높이 22 · 라운드 6(카드와 동일) · 11px. 카드 안이라 툴바와 같은 크기면 카드를 잡아먹는다.
   테두리·글자는 전부 currentColor 파생이라 어떤 카드 색 위에서도 성립하고, 호버는 배경 톤만 바뀐다. */
.ob-exp-acts[b-x5libd1jj1] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px;
    /* 줄의 상하 숨통(2026-08-25 오너 지시 "메뉴 이동이나 하단 메뉴 버튼들 상하 여백 좀 늘려줘").
       ⚖️ 버튼 자체(높이 22px · 0.66rem)는 그대로 두고 **줄 바깥 여백만** 늘린다 —
          버튼을 키우면 카드 안에서 액션이 본문보다 무거워진다(위 주석의 "툴바 축소판" 규칙이 깨진다).
       margin-top 8 → 12px: 확장 내용(위치·종류 행, 메모)과 액션 줄이 붙어 한 덩어리로 읽히던 문제.
       margin-bottom 4px 신설: 액션 줄 아래는 카드 padding-bottom 뿐이라
          **액션이 하나뿐인 시스템 칩**(.ob-prog.sys, padding-bottom 4px)에서 특히 바닥에 붙어 있었다.
          이제 시스템 칩 8px · 할 일 카드 12px 로 둘 다 숨통이 생긴다. */
    margin-top: 12px;
    margin-bottom: 4px;
}

.ob-act[b-x5libd1jj1] {
    display: inline-flex;
    align-items: center;
    gap: 4px;               /* 아이콘–텍스트: 툴바 6px 의 축소판 */
    height: 22px;
    padding: 0 8px;
    border-radius: 6px;
    border: 1px solid color-mix(in srgb, currentColor 34%, transparent);   /* 26% → 34%, 항목 14 */
    background: transparent;
    color: inherit;
    font-family: inherit;
    font-size: 0.66rem;
    font-weight: 700;
    line-height: 1;
    white-space: nowrap;
    cursor: pointer;
    transition: background-color 0.15s ease-out, border-color 0.15s ease-out;
}

.ob-act:hover[b-x5libd1jj1] {
    background: color-mix(in srgb, currentColor 12%, transparent);
    border-color: color-mix(in srgb, currentColor 45%, transparent);
}

/* 액션 버튼(내용 보기·메뉴로 이동·수정) — 확장 패널 안이라 역시 카드 색 위에 앉는다. */
.ob-act:focus-visible[b-x5libd1jj1] {
    outline: 2px solid var(--ob-focus);
    outline-offset: 2px;
    box-shadow: 0 0 0 2px var(--ob-focus-halo);
}

.ob-act[b-x5libd1jj1]  .mud-icon-root {
    width: 13px;
    height: 13px;
    font-size: 13px;
}

/* 댓글 수 — `내용 보기` 버튼 **안**의 값이다(2026-08-25 오너 지시 A-6).
   버튼과 다른 색을 쓰지 않는다. 구분은 **얇은 세로 칸막이 하나** — 라벨은 행위, 오른쪽 숫자는 그 행위가 열
   대화의 크기다. 칠한 알약을 넣으면 카드 안에서 이 버튼만 튀어 액션 3종의 균형이 깨진다. */
.ob-act-n[b-x5libd1jj1] {
    margin-left: 2px;
    padding-left: 6px;
    border-left: 1px solid color-mix(in srgb, currentColor 30%, transparent);
    font-weight: 800;
    font-variant-numeric: tabular-nums;
}

/* ── 댓글 수 뱃지 (2026-08-25) ─────────────────────────────────
   자리 = 카드 2줄의 **왼쪽 끝**. 2줄은 [상태][담당자]가 우측 정렬이라 왼쪽이 비어 있던 유일한 지점이고,
   1줄의 분류칩(왼쪽)·시각(오른쪽)과도 세로로 겹치지 않는다.

   ⚠️ 2026-08-25 오너 지적으로 **알약(pill) 화를 되돌렸다.**
      한차례 `background: var(--ob-accent)` + 흰 글자로 칠했다가 오너가 거부했다 —
      지시는 "칩 배경색을 바꾸라"가 아니라 **"아이콘을 바꾸고 아이콘에 색을 입혀라"** 였다.
      ⛔ 이 뱃지에 면(background)을 깔지 말 것. 배경은 **칠하지 않고 윤곽만** 있는 것이 이 뱃지의 정체성이다.

   면·글자색은 예전 그대로다 — `color: inherit`(= --lane-fg, 카드 배경 휘도로 자동 반전된 잉크) +
   currentColor 파생 테두리. 숫자는 옆 칩들과 **같은 잉크**로 읽힌다.
   (2026-08-25 항목 14 이력 유지: `opacity:0.85` 삭제 · 테두리 24% → 34%.
    윤곽만 있는 요소라 테두리가 곳 이 뱃지의 형태다.)

   🔄 2026-08-25 오너 지시 — **라운드 통일. 기준은 `분류 태그`(.ob-kind)다**(5px → 8px → **6px**).
      한 번 틀렸던 자리다: 처음엔 같은 줄의 `.ob-stsel`·`.ob-who`(둘 다 8px)를 기준으로 삼아 8px 로 맞췄는데,
      오너가 지목한 기준은 **분류 태그**였고 *"예정과 이름도 라운드 각도 맞춰줘"* 로 그 둘까지 대상이 됐다.
      → 지금은 셋 다 `--ob-chip-r`(= .ob-kind 실측 6px)을 쓴다.
      ⚠️ 높이(16px)는 건드리지 않는다 — 지시는 라운드이고, 높이를 바꾸면 2줄 행 높이가 움직인다. */
/* 📍 **자리 = 왼쪽 끝. 확정분이다(2026-08-25).** ─────────────────────────────────
   🔁 **왕복 이력 — 다시 옮기지 마라.**
      같은 날 오너 지시로 "댓글 위치는 우측열에 맞춰줘"를 받아 **우측 정렬로 구현했다가**
      ("수동 카드는 상태 왼쪽 / 시스템·프로그램은 우측 끝 시각 아래")
      곧바로 **"댓글숫자 위치는 다시 좌측으로 옮겨줘"** 로 되돌렸다.
      → 지금의 `margin-right: auto` 가 **오너가 실물을 보고 고른 최종값**이다.
      우측 정렬이 더 정돈돼 보인다는 이유로 다시 손대지 말 것. 이미 한 번 왕복한 자리다.
   📐 동작: 우측 정렬 묶음(`.ob-t2 { justify-content: flex-end }`)에서 이 한 요소만 왼쪽 끝으로 밀려나고,
      남는 폭을 전부 먹어 뒤의 `[예정 ▾] [유규호]` 를 오른쪽 끝에 붙인다.
      시스템 칩·프로그램 라벨의 `.ob-prog-2` 에서도 같은 규칙이 그대로 적용된다(별도 규칙 없음).
   ⚖️ 세로 정렬은 **중앙**(`align-items:center`, 두 컨테이너 모두 기존값)이다. baseline 이 아닌 이유:
      셋 다 글자가 아니라 **테두리 있는 알약**이고 높이가 다르다(뱃지 16px · 상태/담당자 17px).
      baseline 으로 세우면 1px 차이가 테두리 아래쪽으로 몰려 어긋나 보인다. 중앙이면 그 1px 이 위아래로 반씩 나뉜다.
   ⛔ 생김새는 확정분 — 아이콘·색·라운드·`99+`·0건 숨김·클릭 없음. 전부 무변경. */
.ob-cmt[b-x5libd1jj1] {
    margin-right: auto;      /* 우측 정렬 묶음에서 혼자 왼쪽으로 밀린다 — 위 §왕복 이력 참조 */
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    gap: 3px;
    height: 16px;
    padding: 0 5px;
    border-radius: var(--ob-chip-r);   /* = 분류 태그(.ob-kind)의 6px */
    border: 1px solid color-mix(in srgb, currentColor 34%, transparent);
    color: inherit;
    font-size: 0.6rem;
    font-weight: 800;
    line-height: 1;
    font-variant-numeric: tabular-nums;
}

/* 아이콘만 색을 갖는다(2026-08-25 오너 지시 "아이콘에 색을 입혀라" → 같은 날 "그냥 검정으로 해줘").
   숫자·테두리는 그대로 --lane-fg 파생이라, 색은 **글리프 하나에만** 들어간다.

   값 = **이 파일에 이미 있던 토큰 `--ob-ink`(#0f172a)**. 새 토큰도, 새 hex 도 만들지 않았다.
     · `--lane-fg` 를 그대로 쓸 수 **없다** — 그 값은 카드 배경 휘도에 따라 검정/흰색으로 뒤집힌다
       (`OpsColor.ForegroundFor`). 어두운 카드에서 흰색이 되므로 "검정으로"라는 지시와 어긋난다.
     · 그래서 **고정 검정**이 필요한데, 이 프로젝트의 검정은 순흑이 아니라 `OpsColor.Ink = #0f172a`
       (그 파일 주석 그대로 "검정 계열")이고, `.ob-root` 의 `--ob-ink` · 두 편집기의 `--ope-ink` 가 모두 같은 값이다.
       → 보드·편집기·상세창이 한 검정을 쓴다.
   📐 대비(보고용. 2026-08-25 오너가 검정으로 확정 — 색 변경 제안 아님):
     · 가장 밝은 팔레트색 #edf1c5 위 **15.3:1** · 기본색 #cbd5e1 위 **12.0:1**
     · 가장 어두운 팔레트색 #96a0de 위 **7.1:1** — 24색 전부 비텍스트 3:1 을 크게 넘는다(글자 기준 AA 도 통과).
     · 오너가 컬러피커로 고른 **아주 어두운 임의 hex** 카드에서는 묻힐 수 있다(고정색의 한계, 보고 완료).

   크기 11px 는 그대로 둔다(높이 16px 상자 안이라 행 높이 무변경). */
/* 🔁 아이콘 **교체 후보**(2026-08-25 오너 "다른 아이콘을 쓸 수는 없어?" 에 대한 목록).
   전부 MudBlazor 9.7.0 `Icons.Material.*` 에 실재하는 이름이다(어셈블리 메타데이터 실측). 새 에셋 0.
   교체는 `.razor` 의 `<MudIcon Icon="@@Icons.Material.___" />` **한 줄**이면 끝난다.
     ① Filled.Forum          ← **현재 적용.** 겹친 말풍선 둘. 바깥 실루엣이 계단형이라 11px 에서도 덩어리로 안 뭉갠다.
                                `내용 보기` 버튼과 같은 글리프라 카드 안에서 댓글 표기가 하나로 통일된다.
     ② Filled.QuestionAnswer   말풍선 둘이 **위아래로 어긋난** 배치. Forum 과 뜻은 같고 실루엣이 더 벌어져 11px 에서 더 또렷하다.
                                다만 '문답'의 뉘앙스가 있어 일반 코멘트에는 조금 좁다.
     ③ Filled.Comment          단색 말풍선 + 안쪽 가로줄 3개. '글이 적혀 있음'이 읽히지만 11px 에서 줄 간격이 1px 미만이라 뭉갤 수 있다.
     ④ Filled.Chat             말풍선 + 점 3개. 점은 줄보다 잘 버텨서 ③보다 11px 생존력이 낫다. 다만 '입력 중' 인상이 섞인다.
     ⑤ Rounded.ChatBubble      직전에 쓰던 글리프의 라운드 변형. 모서리가 더 둥글어 6px 라운드 칩과 문법이 맞는다.
                                오너가 그 실루엣 자체를 물린 것이면 후보에서 빼면 된다.
     ⑥ Outlined.ModeComment    유일한 **윤곽선** 후보. 이 뱃지가 '칠하지 않고 윤곽만' 인 요소라 문법은 가장 잘 맞지만,
                                11px 에서 1px 선이 얇아 굵기가 옆 숫자(800)와 어긋나 보인다.
   ⚠️ 계열은 Filled 를 기본으로 둔다 — 같은 카드·확장의 다른 아이콘(Forum·OpenInNew·Edit)이 전부 Filled 다.
      ⑤·⑥ 을 고르면 그 한 자리만 굵기가 갈린다는 점을 감안할 것. */
.ob-cmt[b-x5libd1jj1]  .mud-icon-root {
    width: 11px;
    height: 11px;
    font-size: 11px;
    color: var(--ob-ink);
}

.ob-cmt b[b-x5libd1jj1] {
    font-weight: 800;
}

/* ── 모바일 ────────────────────────────────────────────────────────── */
@media (max-width: 720px) {
    .ob-root[b-x5libd1jj1] {
        --ob-col: 85vw;
        --ob-gap: 8px;
        --ob-gutter: 8px;
    }

    .ob-toolbar[b-x5libd1jj1] {
        gap: 8px;
    }

    /* 오버플로 메뉴(MudMenu)는 폐지 — 툴바가 컨트롤 4개뿐이라 좁은 화면은 줄바꿈으로 흡수한다. */
    .ob-toolbar[b-x5libd1jj1] {
        flex-wrap: wrap;
    }

    .ob-seg-title[b-x5libd1jj1] {
        font-size: 14px;
        padding: 0 10px;
    }

    /* 필터 팝업 — 좁은 화면에서는 2단을 세로로 접는다(분류 3열은 그대로, 담당자는 1열).
       가로 폭이 없어 억지로 나란히 두면 이름이 전부 잘리기 때문. 세로선도 가로선으로 되돌린다. */
    .ob-filter[b-x5libd1jj1] {
        grid-template-columns: minmax(0, 1fr);
    }

    .ob-fl-sec.people[b-x5libd1jj1] {
        margin-top: 6px;
        padding-top: 8px;
        padding-left: 0;
        border-left: none;
        border-top: 1px solid var(--ob-line);
    }

    .ob-fl-grid.k2[b-x5libd1jj1] {
        grid-template-columns: minmax(0, 1fr);
    }
}

/* ══ 2026-10-02 2차 — 한 달 맞춤 · 카드 줄바꿈 · 열 간격 0 (오너 지시) ══════════════════════
   원문: "셀을 줄여도 한눈에 30일까지 다 화면에 안들어와. 그리고 줄바꿈을 해서 내용을 좀 가득 채워줘" · "Day간 여백도 제거해" */

/* ── 제목 줄 분리 — 제목(.ob-prog-t, order:-1·basis 100%)이 첫 행 전체, 칩·DAY/시각은 아랫줄 ──
   대상 행 3종: 프로그램 라벨·시스템 칩의 1줄 래퍼(.ob-prog-1) · 접힌 1줄 칩(래퍼가 display:contents 라 .ob-prog 자신이 행)
   · 할 일 카드 1줄(.ob-t1). row-gap 만 좁힌다(가로 gap 6px 은 그대로). */
.ob-prog-1[b-x5libd1jj1],
.ob-prog:not(.task):not(.two-line):not(.expanded)[b-x5libd1jj1],
.ob-prog.task .ob-t1[b-x5libd1jj1] {
    flex-wrap: wrap;
    row-gap: 2px;
}

/* 아랫줄 = [분류칩] ……… [DAY/시각] — DAY·시각은 종전처럼 오른쪽 끝(다른 카드의 시각 축과 같은 자리) */
.ob-prog-d[b-x5libd1jj1] {
    margin-left: auto;
}

/* ── 열 사이 경계선 — 간격 0 이 되면서 이웃 열의 1px 테두리가 맞붙어 2px 이 되므로 **왼쪽 테두리를 지운다**.
   둥근 모서리도 보드 바깥 네 귀퉁이만 남긴다(안쪽 모서리가 둥글면 열 사이에 홈이 팬다). */
.ob-head + .ob-head[b-x5libd1jj1] {
    border-left: none;
    border-top-left-radius: 0;
}

.ob-head:not(:last-child)[b-x5libd1jj1] {
    border-top-right-radius: 0;
}

.ob-col + .ob-col[b-x5libd1jj1] {
    border-left: none;
    border-bottom-left-radius: 0;
}

.ob-col:has(+ .ob-col)[b-x5libd1jj1] {
    border-bottom-right-radius: 0;
}

/* ── 좁은 열 모드(.ob-narrow) — opsBoard.js 가 열 폭 < 100px 이면 #ob-scroll 에 붙인다 ──
   열 안쪽 여백을 줄여 한 달 맞춤(약 50px 열)에서도 글자가 들어갈 자리를 만든다.
   ⚠️ 할 일 카드의 **위아래** 패딩은 줄이지 않는다(첫 카드가 MudBlazor 더미 띠에 덮이는 기록된 함정 → .ob-prog.task 주석). 좌우만. */
.ob-scroll.ob-narrow .ob-board[b-x5libd1jj1] {
    padding-left: 4px;
    padding-right: 4px;
}

.ob-scroll.ob-narrow .ob-head[b-x5libd1jj1] {
    flex-direction: column;
    align-items: flex-start;
    justify-content: flex-start;
    gap: 2px;
    padding: 6px 3px 4px 3px;
}

.ob-scroll.ob-narrow .ob-day-n[b-x5libd1jj1] {
    font-size: 0.78rem;     /* "DAY 01" 이 좁으면 DAY / 01 두 줄로 */
}

/* 날짜는 "10월 01일" → "01일"(월은 툴바 제목에 이미 있다) */
.ob-scroll.ob-narrow .ob-day-md b:first-of-type[b-x5libd1jj1],
.ob-scroll.ob-narrow .ob-day-md i:first-of-type[b-x5libd1jj1] {
    display: none;
}

.ob-scroll.ob-narrow .ob-day-md[b-x5libd1jj1],
.ob-scroll.ob-narrow .ob-day-w[b-x5libd1jj1] {
    font-size: 0.72rem;
}

.ob-scroll.ob-narrow .ob-head[b-x5libd1jj1]  .ob-head-add {
    width: 24px;
    height: 24px;
    min-width: 24px;
}

.ob-scroll.ob-narrow .ob-col[b-x5libd1jj1] {
    padding-left: 1px;
    padding-right: 1px;
}

.ob-scroll.ob-narrow .ob-progs[b-x5libd1jj1],
.ob-scroll.ob-narrow .ob-sys[b-x5libd1jj1] {
    padding-left: 2px;
    padding-right: 2px;
}

.ob-scroll.ob-narrow .ob-col[b-x5libd1jj1]  .ob-zone {
    padding-left: 2px;
    padding-right: 2px;
}

.ob-scroll.ob-narrow .ob-prog[b-x5libd1jj1] {
    padding-left: 4px;
    padding-right: 4px;
}

.ob-scroll.ob-narrow .ob-kind[b-x5libd1jj1] {
    padding: 0 3px;
}

.ob-scroll.ob-narrow .ob-prog.task .ob-t2[b-x5libd1jj1] {
    flex-wrap: wrap;
    row-gap: 2px;
}

.ob-scroll.ob-narrow .ob-quick[b-x5libd1jj1] {
    flex-wrap: wrap;
    margin-left: 1px;
    margin-right: 1px;
}

.ob-scroll.ob-narrow .ob-quick-in[b-x5libd1jj1] {
    flex: 1 0 100%;
}
/* /Components/Pages/Manager/Dashboard/OpsColorField.razor.rz.scp.css */
/* 운영 보드 편집기 색 선택 필드 — 스코프 CSS(전역 오염 금지).

   2026-08-25 전면 리뉴얼. 이 파일이 지키는 것:
     1) **치수는 토큰으로만.** 36px 같은 맨 숫자를 다시 심지 않는다(직전 작업에서 걷어낸 부채).
        4의 배수 스케일(--opc-s1..s5) + 컨트롤 높이 1종(--opc-ctl) 만 쓴다.
     2) **세그먼트 컨트롤의 생김새는 편집기 3곳이 동일**하다(카드 타입 · 시간 구분 · 색 모드).
        스코프 CSS 는 파일 간 공유가 불가능하므로 같은 규격을 각 파일에 복제하되,
        값은 전부 토큰으로 두어 한 곳만 보고도 같은 수치임이 확인되게 했다.
     3) **대비 실측치를 주석에 남긴다.** 회색 위 회색이 다시 기어들지 않게.
   레이아웃 원칙: 머리줄(라벨+모드)과 상태줄(색+hex+설명)은 **모드와 무관하게 항상 2줄**이라
   자동↔직접 전환에도 위쪽 격자가 흔들리지 않는다(예전 3열 머리줄이 하던 일을 그대로 이어받았다). */

.opc[b-syerny3eel] {
    /* ── 토큰 ─────────────────────────────────────────────────────────
       색은 운영 보드(.ob-root)의 어휘를 그대로 쓴다 — 보드와 편집기가 한 시스템으로 읽히게. */
    --opc-ink: #0f172a; /* 본문 잉크 · 흰 배경 대비 17.9:1 */
    --opc-ink-2: #475569; /* 비활성 세그먼트 라벨 · 7.57:1 (예전 #94a3b8 = 2.56:1 은 미달이었다) */
    --opc-muted: #64748b; /* 보조 설명 · 4.76:1 */
    --opc-line: #e2e8f0;
    --opc-line-2: #cbd5e1;
    --opc-tint: #f1f5f9;
    --opc-surface: #ffffff;
    /* 채워진 면 위의 흰 글자는 #1e88e5(3.39:1)로는 AA 미달 → 한 스텝 어두운 파랑(5.75:1). */
    --opc-accent: #1565c0;
    --opc-ring: #1e88e5; /* 테두리 강조 전용. ⚠️ 2026-08-25 포커스 링에서 제외 → --opc-focus */
    /* 🎯 포커스 링 = 이중 링. 근거·실측 대비값은 OpsBoard.razor.css 의 --ob-focus 주석 참조.
       ℹ️ 이 파일의 `.opc-sw.on`(선택 스와치)이 이미 "흰 인셋 + 먹 링"으로 같은 원리를 쓰고 있었다 —
          임의 색 위에 얹는 표시는 이중 링이어야 한다는 하우스 선례다. 포커스도 같은 문법으로 통일한다. */
    --opc-focus: #0d47a1;
    --opc-focus-halo: #ffffff;
    --opc-s1: 4px;
    --opc-s2: 8px;
    --opc-s3: 12px;
    --opc-s4: 16px;
    --opc-ctl: 30px; /* 세그먼트·스와치 높이 1종. 24px(WCAG 2.2 SC 2.5.8 최소)보다 6px 여유 */
    --opc-r: 8px;
    --opc-r-sm: 6px;

    display: flex;
    flex-direction: column;
    gap: var(--opc-s2);
    min-width: 0;
}

/* ⛔ `.opc-head` · `.opc-modes` · `.opc-mode*` 규칙 **전부 삭제** — 2026-08-25 오너 지시로
   자동/직접 토글 자체가 사라졌다(마크업에서 라벨은 `.opc-label` 하나로 남았다).
   이 파일에 모드 토글용 셀렉터는 하나도 남아 있지 않다. */
.opc-label[b-syerny3eel] {
    font-size: 0.78rem;
    font-weight: 800;
    letter-spacing: 0.02em;
    color: var(--opc-ink);
    white-space: nowrap;
}

/* ⛔ `.opc-state` · `.opc-now` · `.opc-hex` 규칙 **삭제**(2026-08-25 오너 지시 "현재 지정 색상 표시 줄 제거").
   같은 값을 셋이 말하던 자리다 — 체크된 스와치가 색을, 아래 `.opc-hint` 가 코드를 맡는다. */

/* 색 선택기 옆 **현재 색 코드**. 예전엔 "팔레트 밖 색"이라는 설명이 앉아 있던 자리로,
   2026-08-25 오너 지시로 값 자체가 들어왔다 → 설명체(600)가 아니라 **값의 서체**로 바꾼다:
   자릿수가 흔들리지 않게 tabular-nums, 줄바꿈 금지, 굵기 한 단계 위(700).
   ⚠️ 대비 4.76:1(--opc-muted, AA 통과) — 값이지만 주역은 스와치 그리드라 잉크색까지 올리지 않는다. */
.opc-hint[b-syerny3eel] {
    flex: 0 0 auto;
    min-width: 0;
    font-size: 0.75rem;
    font-weight: 700;
    line-height: 1.45;
    color: var(--opc-muted);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

/* ── 프리셋 스와치 그리드(24색) ─────────────────────────────────────
   🔄 2026-08-25: 칸이 24 → **25개**가 됐다(기본색 1칸 + 프리셋 24칸). 12열이면 12+12+1 로 마지막 줄에
      한 칸만 남아 팔레트가 부러져 보인다 → **13열**로 올려 13+12 = **정확히 2줄**을 유지한다(끝 한 칸만 빈다).
      좁은 폭도 8열(8+8+8+1 = orphan)에서 **9열**(9+9+7)로 바꿔 같은 이유를 피했다.
   정사각(aspect-ratio)이라 폭이 줄면 높이도 함께 줄고, 최소 변은 --opc-ctl 로 눌러 24px 밑으로 안 간다. */
.opc-grid[b-syerny3eel] {
    display: grid;
    grid-template-columns: repeat(13, minmax(0, 1fr));
    gap: var(--opc-s1) 6px;
}

.opc-sw[b-syerny3eel] {
    appearance: none;
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    aspect-ratio: 1 / 1;
    min-height: var(--opc-ctl);
    padding: 0;
    border: 1px solid transparent; /* 실제 색은 인라인 */
    border-radius: var(--opc-r-sm);
    cursor: pointer;
    transition: transform 0.14s cubic-bezier(0.16, 1, 0.3, 1), box-shadow 0.14s ease;
}

.opc-sw:hover[b-syerny3eel] {
    transform: translateY(-1px);
}

/* 🔴 스와치는 **24색 프리셋 위에 얹히는** 표시라 이 파일에서 이중 링이 가장 절실하다. */
.opc-sw:focus-visible[b-syerny3eel] {
    outline: 2px solid var(--opc-focus);
    outline-offset: 2px;
    box-shadow: 0 0 0 2px var(--opc-focus-halo);
}

/* 선택 표시 = 흰 인셋 + 먹 링 + SVG 체크(3중 신호). 링은 box-shadow 라 **크기가 변하지 않는다**
   → 선택이 옮겨 다녀도 그리드가 흔들리지 않는다. */
.opc-sw.on[b-syerny3eel] {
    box-shadow: 0 0 0 2px var(--opc-surface) inset, 0 0 0 2px var(--opc-ink);
}

/* ⚠️ 선택(.on) + 포커스가 겹칠 때. 두 규칙은 특이도가 같아(.opc-sw.on / .opc-sw:focus-visible)
   **소스 순서로 .on 이 이겨** 포커스 헤일로가 통째로 지워진다 → 여기서 두 그림자를 합쳐 둘 다 살린다.
   바깥 먹 링 자리는 포커스 헤일로가 대신하고, 그 바깥을 outline(어두운 링)이 감싼다. */
.opc-sw.on:focus-visible[b-syerny3eel] {
    box-shadow: 0 0 0 2px var(--opc-surface) inset, 0 0 0 2px var(--opc-focus-halo);
}

.opc-k[b-syerny3eel] {
    width: 62%;
    height: 62%;
    pointer-events: none;
}

/* 기본색 칸 — **파선** 테두리로 "고정된 색이 아니라 자동으로 정해진다"를 프리셋 24칸과 구별한다.
   면 색은 인라인(부모가 예정색을 알면 그 색, 모르면 중립 #f1f5f9). 크기·라운드·체크는 프리셋과 동일해
   그리드 리듬이 깨지지 않는다. */
.opc-sw-auto[b-syerny3eel] {
    border-style: dashed;
    border-width: 2px;
}

/* ── 팔레트 밖 색 — 그리드 아래 한 줄로 낮춘다(1순위는 프리셋) ───────── */
.opc-custom[b-syerny3eel] {
    display: flex;
    align-items: center;
    gap: var(--opc-s2);
    min-width: 0;
}

/* Radzen 트리거를 Mud Outlined 입력과 같은 언어로 감싼다(1px 테두리 · 라운드 8 · 흰 바닥) */
.opc-pick[b-syerny3eel] {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    padding: 3px;
    border: 1px solid var(--opc-line-2);
    border-radius: var(--opc-r);
    background: var(--opc-surface);
}

/* ⛔ `.opc-note`(하단 설명) 규칙 **삭제**(2026-08-25 오너 지시 "고른 색을 그대로 씁니다 설명 제거").
   문구가 사라지면서 그 문구만을 위해 두었던 상하 여백 예외도 함께 사라졌다 —
   이제 `.opc` 의 세로 스택 gap(s2) 하나로 라벨·그리드·선택기 세 층이 균일하게 떨어진다. */

@media (max-width: 520px) {
    .opc-grid[b-syerny3eel] {
        grid-template-columns: repeat(9, minmax(0, 1fr));
    }
}

/* 모션은 상태 변화를 설명하는 최소치만 둔다 — 끄면 색·상태는 즉시 바뀌고 움직임만 사라진다. */
@media (prefers-reduced-motion: reduce) {
    .opc-sw[b-syerny3eel] {
        transition: none;
    }

    .opc-sw:hover[b-syerny3eel] {
        transform: none;
    }
}
/* /Components/Pages/Manager/Dashboard/OpsProgramEditor.razor.rz.scp.css */
/* 운영 보드 프로그램 편집 다이얼로그 — 스코프 CSS(2026-08-25 신설, 전역 오염 금지).

   ⚠️ 이 파일은 **새 컴포넌트가 아니다.** `OpsProgramEditor.razor` 의 스코프 스타일일 뿐이라
      `BaseDialogComponent.WindowCode`(= 타입 이름)가 그대로이고, `/AdminMenuAuthorize` 재저장이 필요 없다.

   설계 규칙(할 일 편집기 `OpsTaskEditor.razor.css` 와 **같은 토큰·같은 수치**):
     · 치수는 토큰만 쓴다 — 36px 같은 맨 숫자를 다시 심지 않는다(직전 작업에서 걷어낸 부채).
     · 세그먼트 컨트롤 규격은 편집기 3곳(카드 타입 · 시간 구분 · 색 모드)이 동일하다.
       스코프 CSS 는 파일 간 공유가 불가능하므로 규격을 복제하되 값은 전부 토큰으로 둔다.
     · 대비 실측치를 주석에 남긴다. */

/* ── 토큰 ─────────────────────────────────────────────────────────────────
   ⚠️ 선언 위치가 둘인 이유: `.ope-head` 는 `.dlg-scroll`(그 안에 `.ope-form`)의 **형제**라
      `.ope-form` 에만 선언하면 커스텀 속성이 머리줄까지 상속되지 않는다.
      값은 한 벌이고 선언만 두 뿌리에 건다.
   운영 보드(.ob-root)의 색 어휘를 그대로 쓴다 — 보드와 편집기가 한 시스템으로 읽히게. */
.ope-head[b-0g0latrdf9],
.ope-form[b-0g0latrdf9] {
    --ope-ink: #0f172a; /* 흰 배경 대비 17.9:1 */
    --ope-ink-2: #475569; /* 비활성 세그먼트 라벨 · 7.57:1 */
    --ope-muted: #64748b; /* 보조 설명 · 4.76:1 */
    --ope-line: #e2e8f0;
    --ope-line-2: #cbd5e1;
    --ope-tint: #f1f5f9;
    --ope-surface: #ffffff;
    --ope-accent: #1565c0; /* 채워진 면 + 흰 글자 = 5.75:1 (보드의 #1e88e5 는 3.39:1 이라 텍스트엔 부족) */
    --ope-ring: #1e88e5; /* 테두리·구조선 전용. ⚠️ 2026-08-25 포커스 링에서 제외 → --ope-focus */
    /* 🎯 포커스 링 = 이중 링. 근거·실측 대비값은 OpsBoard.razor.css 의 --ob-focus 주석 참조.
       한 화면 안에서 포커스 표현이 갈리면 안 되므로 보드·할 일 편집기와 같은 방식·같은 색. */
    --ope-focus: #0d47a1;
    --ope-focus-halo: #ffffff;
    --ope-bad: #b91c1c; /* 오류 문구 · 7.0:1 */
    --ope-s1: 4px;
    --ope-s2: 8px;
    --ope-s3: 12px;
    --ope-s4: 16px;
    --ope-s5: 24px;
    --ope-ctl: 30px;
    --ope-r: 8px;
    --ope-r-sm: 6px;
}

/* 📏 여백 한 단계 축소 — **할 일 편집기와 같은 스케일**(2026-08-25 오너 지시 "프로그램 등록도 마찬가지로").
   두 다이얼로그가 어긋나면 안 되므로 `OpsTaskEditor.razor.css` 와 값이 한 글자도 다르지 않다:
     · 섹션 사이   s5(24) → s4(16)   ← 여기
     · 섹션 안 필드 s4(16) → s3(12)   ← .ope-sec
     · 격자 칸 사이 s4(16) → s3(12)   ← .ope-row
     · 라벨–컨트롤 s2(8)  → s1(4)    ← .ope-field
   상단 여백(padding-top s2)도 할 일 편집기와 같게 유지한다 — 미리보기가 빠지며 이미 위가 비었다. */
.ope-form[b-0g0latrdf9] {
    display: flex;
    flex-direction: column;
    gap: var(--ope-s4);
    padding-top: var(--ope-s2);
    min-width: 0;
}

/* ── 타이틀바 ────────────────────────────────────────────────────────────
   증상: 다이얼로그가 좁아지면 X(닫기)가 아랫줄로 내려간다.
   원인: 전역 app.css 의 `.dialog-title{flex-wrap:wrap}` + `@media(max-width:720px){.dialog-title-right{flex-basis:100%}}`.
   전역을 고치면 Manager 의 모든 다이얼로그가 영향을 받으므로 이 화면에서만 무력화한다.
   규칙: 줄바꿈 금지 · 줄어드는 쪽은 제목 · 오른쪽 버튼 묶음은 축소 금지. */
.ope-head[b-0g0latrdf9]  .dialog-title {
    flex-wrap: nowrap;
    column-gap: var(--ope-s2);
}

.ope-head[b-0g0latrdf9]  .dialog-title-left {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    white-space: nowrap;
}

.ope-head[b-0g0latrdf9]  .dialog-title-right {
    flex: 0 0 auto;
    flex-basis: auto;
    flex-wrap: nowrap;
}

.ope-head[b-0g0latrdf9]  .tid-btn {
    max-width: 110px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* ⛔ 보드 표기 미리보기(.ope-pv / -bar / -main / -title / -meta / -tag) **블록 삭제** —
   2026-08-25 오너 지시(할 일 편집기와 양쪽 동시 적용). 마크업·계산 멤버와 함께 걷어냈다.
   이 파일에 .ope-pv* 셀렉터는 하나도 남아 있지 않다. */

/* ── 섹션 ──────────────────────────────────────────────────────────────── */
.ope-sec[b-0g0latrdf9] {
    display: flex;
    flex-direction: column;
    gap: var(--ope-s3); /* 섹션 안 필드 사이 — s4(16) → s3(12), 위 .ope-form 주석 */
    min-width: 0;
}

/* 제목 + 남은 폭을 채우는 실선 한 줄. 점선 hr 한 줄만 있던 예전 구분보다
   "여기부터 무엇" 이 먼저 읽힌다(제목 아래보다 위에 여백이 더 크다 — 그룹은 아래로 붙는다). */
.ope-sec-h[b-0g0latrdf9] {
    display: flex;
    align-items: center;
    gap: var(--ope-s3);
    min-width: 0;
}

.ope-sec-h[b-0g0latrdf9]::after {
    content: "";
    flex: 1 1 auto;
    height: 1px;
    background: var(--ope-line);
}

.ope-sec-t[b-0g0latrdf9] {
    flex: 0 0 auto;
    font-size: 0.76rem;
    font-weight: 800;
    letter-spacing: 0.04em;
    color: var(--ope-ink);
    white-space: nowrap;
}

/* ── 격자 ──────────────────────────────────────────────────────────────── */
.ope-row[b-0g0latrdf9] {
    display: grid;
    gap: var(--ope-s3); /* s4(16) → s3(12) — 섹션 안 필드 사이와 같은 눈금 */
    min-width: 0;
}

.ope-row.full[b-0g0latrdf9] {
    grid-template-columns: 1fr;
}

.ope-row.c2[b-0g0latrdf9] {
    grid-template-columns: repeat(2, minmax(0, 1fr));
}

/* 🔴 전역 지뢰: app.css 의 `.mud-select{flex-grow:0!important}`.
   격자에서는 무의미하지만 Mud 가 내부에서 flex 컨테이너를 만드는 경우가 있어
   **이 컴포넌트의 격자 안에서만** 무력화한다(전역을 건드리면 다른 화면이 깨진다). */
.ope-row[b-0g0latrdf9]  .mud-select {
    flex-grow: 1 !important;
    width: 100%;
}

/* 자체 라벨이 필요한 필드(세그먼트 등) — Mud 부동 라벨과 같은 위계로 읽히게 크기를 맞춘다. */
.ope-field[b-0g0latrdf9] {
    display: flex;
    flex-direction: column;
    gap: var(--ope-s1); /* 라벨–컨트롤 s2(8) → s1(4) */
    min-width: 0;
}

.ope-flabel[b-0g0latrdf9] {
    font-size: 0.78rem;
    font-weight: 800;
    letter-spacing: 0.02em;
    color: var(--ope-ink);
}

/* ── 세그먼트 컨트롤 ─────────────────────────────────────────────────────
   테두리는 바깥에 한 번만, 칸 사이는 1px 세로선(운영 보드 툴바 .ob-seg 와 같은 규칙).
   칸은 균등 분할이라 선택지가 3개든 4개든 줄이 꽉 찬다. */
.ope-seg[b-0g0latrdf9] {
    display: flex;
    align-items: stretch;
    height: var(--ope-ctl);
    border: 1px solid var(--ope-line-2);
    border-radius: var(--ope-r);
    background: var(--ope-surface);
    overflow: hidden;
    min-width: 0;
}

.ope-seg-b[b-0g0latrdf9] {
    appearance: none;
    flex: 1 1 0;
    min-width: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0 var(--ope-s2);
    border: none;
    background: transparent;
    color: var(--ope-ink-2);
    font-family: inherit;
    font-size: 0.8rem;
    font-weight: 700;
    white-space: nowrap;
    cursor: pointer;
    transition: background-color 0.16s ease, color 0.16s ease;
}

.ope-seg-b + .ope-seg-b[b-0g0latrdf9] {
    border-left: 1px solid var(--ope-line-2);
}

.ope-seg-b:hover:not(.on)[b-0g0latrdf9] {
    background: var(--ope-tint);
    color: var(--ope-ink);
}

.ope-seg-b.on[b-0g0latrdf9] {
    background: var(--ope-accent);
    color: var(--ope-surface);
}

/* 이중 링 **인셋판** — 할 일 편집기 .ope-seg-b 와 같은 규격(두 다이얼로그가 어긋나면 안 된다). */
.ope-seg-b:focus-visible[b-0g0latrdf9] {
    outline: 2px solid var(--ope-focus);
    outline-offset: -2px;
    box-shadow: inset 0 0 0 4px var(--ope-focus-halo);
}

/* ── 보조 문구 ──────────────────────────────────────────────────────────
   요약·오류는 **필드 바로 아래**에 둔다. 저장 버튼을 눌러야 스낵바로 알던 것을 앞당긴 자리다. */
.ope-note[b-0g0latrdf9] {
    margin: 0;
    font-size: 0.76rem;
    font-weight: 700;
    line-height: 1.5;
    color: var(--ope-muted);
    font-variant-numeric: tabular-nums;
    overflow-wrap: anywhere;
}

.ope-note.bad[b-0g0latrdf9] {
    color: var(--ope-bad);
}

.ope-hint[b-0g0latrdf9] {
    font-size: 0.75rem;
    font-weight: 600;
    line-height: 1.5;
    color: var(--ope-muted);
    overflow-wrap: anywhere;
}

@media (max-width: 520px) {
    .ope-row.c2[b-0g0latrdf9] {
        grid-template-columns: 1fr;
    }

    .ope-seg-b[b-0g0latrdf9] {
        font-size: 0.76rem;
    }
}

@media (prefers-reduced-motion: reduce) {
    .ope-seg-b[b-0g0latrdf9] {
        transition: none;
    }
}
/* /Components/Pages/Manager/Dashboard/OpsTaskDetail.razor.rz.scp.css */
/* 운영 보드 카드 상세 + 댓글 다이얼로그 — 스코프 CSS(전역 오염 금지: 모든 셀렉터는 이 컴포넌트 마크업 기점).

   2026-08-25 재디자인(오너 지시 15). 방향은 하나다 — **편집기와 같은 창처럼 보이게.**
     · 토큰·치수·색을 `OpsProgramEditor.razor.css` / `OpsTaskEditor.razor.css` 와 **같은 이름·같은 값**으로 맞췄다
       (스코프 CSS 는 파일 간 공유가 불가능하므로 복제하되, 값은 전부 토큰으로 둔다 — 편집기와 같은 규약).
     · 정보·메모·댓글이 각각 **섹션 머리 + 헤어라인**을 갖는다. 예전에는 세 덩어리 사이에 아무 표시가 없었다.
     · 회색을 한 스텝 진하게(#64748b → --ope-ink-2 #475569). 오너 지적 "전체적으로 우중충하다"의 주범이었다:
       흰 배경 4.76:1 → **7.57:1**. 위계는 색이 아니라 크기·굵기가 만든다.
     · 상태는 글자만 두지 않고 **보드·편집기와 같은 상태칩(st-*)** 으로. 세 화면이 같은 색을 쓴다.
   ⛔ 댓글마다 카드를 만들지 않는다(중첩 카드 금지) — 왼쪽 정렬 + 1px 구분선만으로 묶는다.
   ⛔ 새 컴포넌트 파일 없음. 이 파일은 `OpsTaskDetail.razor` 의 스코프 스타일일 뿐이라 `WindowCode` 가 그대로다
      (= `/AdminMenuAuthorize` 재저장이 추가로 필요하지 않다). */

/* ── 토큰 ─────────────────────────────────────────────────────────────────
   선언 위치가 둘인 이유: `.ops-head`(타이틀바)는 `.otd-shell`(본문)의 **형제**라 본문에만 선언하면
   커스텀 속성이 머리줄까지 상속되지 않는다. 값은 한 벌이고 선언만 두 뿌리에 건다.
   ℹ️ 2026-08-25 ⑯: 예전엔 세 뿌리였다(`.otd-body`·`.otd-form`). 액션 줄이 사라지고 컴포저가
      본문 안(우측 패널)으로 들어오면서 `.otd-shell` 하나가 본문 전체를 덮게 됐다. */
.ops-head[b-vy2jjdamk1],
.otd-shell[b-vy2jjdamk1] {
    --ope-ink: #0f172a; /* 흰 배경 17.9:1 */
    --ope-ink-2: #475569; /* 보조 글자 · 7.57:1 (이전 #64748b = 4.76:1) */
    --ope-muted: #64748b; /* 가장 약한 층(플레이스홀더)만 · 4.76:1 */
    --ope-line: #e2e8f0;
    --ope-line-2: #cbd5e1;
    --ope-tint: #f8fafc;
    --ope-surface: #ffffff;
    --ope-accent: #1565c0; /* 채움면 + 흰 글자 = 5.75:1 */
    --ope-ring: #1e88e5; /* 테두리·구조선 전용. ⚠️ 2026-08-25 포커스 링에서 제외 → --ope-focus */
    /* 🎯 포커스 링 = 이중 링. 근거·실측 대비값은 OpsBoard.razor.css 의 --ob-focus 주석 참조.
       한 화면 안에서 포커스 표현이 갈리면 안 되므로 보드·편집기와 같은 방식·같은 색. */
    --ope-focus: #0d47a1;
    --ope-focus-halo: #ffffff;
    --ope-bad: #b91c1c; /* 파괴적 동작 · 7.0:1 */
    --ope-s1: 4px;
    --ope-s2: 8px;
    --ope-s3: 12px;
    --ope-s4: 16px;
    --ope-s5: 24px;
    --ope-r: 8px;
    --ope-r-sm: 6px;
    /* 정보 행의 **라벨 열 고정폭**(2026-08-25 B-4). 계산: 아이콘 16 + 간격 6 + 가장 긴 라벨 `프로그램`
       4자 × 0.8rem(12.8px) ≈ 52 → 74px. 88px 로 두면 라벨과 값 사이에 일정한 홈이 생기고,
       라벨 길이가 달라도 **값의 시작 x 가 모든 행에서 같다**(이 정렬 축이 목록을 표로 읽히게 한다). */
    --otd-key: 88px;
    /* 🔄 2026-08-26 오너 지시 "상세 내용 우측 여백을 좌측 여백만큼 줄이게 코멘트창 넓이를 넓혀줘".
       좌측 열 폭 = **본문이 정확히 들어갈 만큼** = 본문 폭(--ope-doc-w 504) + 좌우 패딩(s4 x2 = 32) = **536px**.
       이전에는 1.5fr(576px)이라 본문 504 뒤에 40px 가 남아 **좌 16 : 우 56** 으로 비대칭이었다.
       ⛔ --ope-doc-w 는 건들이지 않는다 — 편집기와의 폭 통일 기준(19번)이다. **열 폭을 본문에 맞춘다.** */
    --otd-left-w: calc(var(--ope-doc-w) + var(--ope-s4) * 2);   /* = 536px */
    /* 상세내용 본문 아래 꼬리 여백(2026-08-25 오너 지시 "하단 여백은 많이, 여유있게").
       눈금 위의 값이다 — s5(24)의 2배. 하드코딩 px 를 규칙에 흩뿌리지 않으려고 이름을 준다. */
    --otd-note-tail: calc(var(--ope-s5) * 2);   /* = 48px */
    /* ⛔ `--otd-title-fs`/`--otd-title-lh` **삭제**(2026-08-25) — 우측 코멘트 머리를 좌측 제목 줄과
       같은 baseline 에 세우려고 그 타이포를 비추던 값이었다. 오너 지시로 **제목 줄(.otd-top)이 사라져**
       맞출 대상이 없어졌다(→ .razor §제목 줄 삭제 주석). 스트럿(`.otd-sec-t::before`)도 함께 걷었다. */
}

/* ── 타이틀바 — 편집기와 같은 방어(전역 app.css 의 .dialog-title{flex-wrap:wrap} 무력화).
   `::deep` 은 스코프 속성이 붙은 HTML 요소를 기점으로만 걸리므로 감싸는 div(.ops-head)가 반드시 필요하다.
   ⚠️ `.tid-btn` 규칙은 삭제했다 — 이 창은 DialogHeader 에 TID 를 넘기지 않으므로 그 버튼 자체가 없다. */
.ops-head[b-vy2jjdamk1]  .dialog-title {
    flex-wrap: nowrap;
    column-gap: var(--ope-s2);
}

.ops-head[b-vy2jjdamk1]  .dialog-title-left {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    white-space: nowrap;
}

.ops-head[b-vy2jjdamk1]  .dialog-title-right {
    flex: 0 0 auto;
    flex-basis: auto;
    flex-wrap: nowrap;
}

/* ── 껍데기 ────────────────────────────────────────────────────────────────
   app.css 의 `.dlg-scroll` 은 `padding:10px 20px 20px; flex:1 1 auto; min-height:0; overflow:auto` 다.
   이 창은 **자기가 스크롤하지 않는다** — 좌·우 열이 각자 스크롤해야 하므로 여기서 셋을 덮어쓴다:
     ① `overflow:hidden` — 바깥 스크롤러를 없앤다(안 그러면 스크롤바가 둘 겹친다).
     ② `padding:0` — 우측 틴트 패널이 창 오른쪽 끝까지 **면으로** 닿아야 두 열의 경계가 읽힌다.
        각 열이 자기 안쪽 여백을 갖는다(아래 .otd-main / .otd-side).
     ③ 명시적 **높이** — flex 로만 두면 `.dlg-content-flex{max-height:100%}` 아래에서 높이가
        내용 기반(indefinite)이라 **자식의 `overflow:auto` 가 스크롤할 기준을 못 갖는다**(내용만큼 늘어난다).

   📐 높이 정책 = `min(68dvh, 640px)` · 최소 340px. 근거(실측 대신 계산으로 상한을 잡는다):
     · MudBlazor 다이얼로그의 상한은 `max-height: calc(100% - 64px)` 다 → 뷰포트 768px(노트북)에서 704px.
       이 창의 나머지 층은 타이틀바 ≈56px + 제목 줄 ≈52px + 다이얼로그 자체 여백 → 합계 ≈120px.
       68dvh = 522px → 522 + 120 = **642px < 704px** (여유 62px).
     · 1080p(브라우저 크롬 제외 뷰포트 ≈937px)에서는 68dvh = 637px 이 640px 캡에 거의 닿는다 →
       637 + 120 = 757px < 873px. **캡을 둔 이유**는 대형 모니터에서 댓글 열이 1000px 넘게 길어지면
       한 화면에 안 들어와 스크롤 위치를 잃기 때문이다(읽는 창의 편안한 상한).
     · `dvh` 는 모바일 주소창 접힘까지 반영한다(`vh` 는 반영 안 됨).
     · 340px 아래로는 내려가지 않는다 — 그보다 짧으면 말풍선 2개도 못 보여 준다. 뷰포트가 그보다 짧으면
       다이얼로그 자신의 스크롤(`.dlg-content-flex`)이 받아 준다(우아한 열화). */
.dlg-scroll.otd-shell[b-vy2jjdamk1] {
    display: flex;
    flex-direction: column;
    min-width: 0;
    padding: 0;
    overflow: hidden;
    /* 🔴 **우측 흰 띠의 정체가 이것이다**(2026-08-25 오너 지시 "코멘트 우측의 흰색 여백도 코멘트 배경색으로").
       전역 `app.css:122` 의 `.dlg-scroll{scrollbar-gutter:stable}` 은 스크롤바 자리를 **미리 비워 두는** 속성인데,
       `overflow:hidden` 인 요소도 여전히 스크롤 컨테이너라 그 예약이 살아 있다
       → 창 오른쪽 끝에 폭 ≈15px 의 빈 띠가 남고, 그 자리는 이 요소의 배경(--ope-surface = 흰색)으로 칠해진다.
       우측 코멘트 패널(.otd-side)의 틴트는 그 띠 **안쪽**에서 끝나므로 흰 줄로 보였다.
       ⛔ 패딩·마진 문제가 아니었다 — 이 요소의 padding 은 이미 0 이다(위 줄). 그래서 음수 마진으로 덮는 방식이
          아니라 **예약 자체를 끄는 것**이 옳다: 이 창은 스스로 스크롤하지 않으므로(좌·우 열이 각자 스크롤)
          비워 둘 자리가 애초에 필요 없다.
       ✅ 이렇게 하면 `.otd-side` 가 격자 열 끝까지 = 창 끝까지 닿는다. 스레드의 실제 스크롤바는
          `.otd-thread` 안쪽에 그대로 생기므로(그쪽은 overflow:auto) 잘리거나 겹치지 않는다.
       ✅ 다이얼로그 모서리 라운드도 침범하지 않는다 — 배경을 넓힌 것이 아니라 **빈 띠를 없앤** 것이고,
          라운드는 바깥 `.mud-dialog` 가 `overflow` 로 잘라 준다. */
    scrollbar-gutter: auto;
    background: var(--ope-surface);
    /* 🔄 2026-08-25 오너 지시 "다이얼로그 기본 높이를 더 높여라(폭은 유지)".
       **68dvh → 76dvh · 캡 640 → 760px.** 폭(MaxWidth=Medium)과 6:4 분할은 한 글자도 건드리지 않았다.
       실측 계산(위 §높이 정책의 셈을 그대로 이어서 — 이 창의 나머지 층 ≈120px):
         · 768px 노트북 : 76dvh = 584 … 세 번째 항 `calc(100dvh-200px)` = 568 이 이겨 **568px**
                          → 568 + 120 = 688 < 704(MudBlazor `max-height: calc(100% - 64px)`) ✓ 여유 16px
                          (이전 522px → **+46px**)
         · 1080p(≈937px): 76dvh = 712 · calc = 737 · 캡 760 → **712px**
                          → 712 + 120 = 832 < 873 ✓ (이전 637px → **+75px**)
         · 600px 저해상도: calc = 400 → **400px**(min-height 340 위) → 400 + 120 = 520 < 536 ✓
       🔒 **세 번째 항이 넘침 방지의 본체다.** `calc(100dvh - 200px)` 은 위 ≈120px 층에 80px 슬랙을 더한 값이라,
          dvh 비율이나 캡을 나중에 올려도 이 항이 항상 뷰포트 안쪽으로 잘라 준다.
       ℹ️ min-height 340px 은 그대로 — 그보다 짧은 뷰포트에서는 예전처럼 다이얼로그 자신의 스크롤이 받는다.
       ℹ️ ≤860px 에서는 아래 미디어쿼리가 `height:auto; min-height:0; max-height:none` 으로 이 줄을 **통째로 무력화**한다
          (세로로 접히면 바깥 한 개의 스크롤로 돌려주는 기존 규약) → 접힌 화면에 빈 높이가 생기지 않는다. */
    height: min(76dvh, 760px, calc(100dvh - 200px));
    min-height: 340px;
}

/* ⛔ `.otd-top`(제목 줄) 규칙 **삭제**(2026-08-25 오너 지시) — 제목·분류칩이 타이틀바로 올라가
   본문의 그 줄이 중복이 됐다. 격자도 2행 → **1행**으로 줄었다(아래 .otd-split).
   함께 사라진 것: `.otd-title` · `.otd-title.done`(완료 취소선) · 우측 baseline 스트럿. */

/* ── 좌우 분할 ─────────────────────────────────────────────────────────────
   📐 비율 6:4 = `1.5fr : 1fr`. 좌측이 확실히 넓다는 지시를 만족하면서 우측이 대화로 쓸 만한 하한을 지킨다.
      Medium(960px) 기준 실측 계산: 좌 576px / 우 384px. 우측에서 패딩 32px 을 빼면 콘텐츠 352px,
      말풍선 max-width 82% = **289px** → 0.84rem(13.44px) 한글로 한 줄 ≈21자다(두세 글자에서 접히지 않는다).
      7:3 이면 우측 288 → 콘텐츠 256 → 말풍선 210px(≈15자)로 아바타·이름까지 낀 줄이 답답해진다.
   `minmax(0, …)` 필수 — 그리드 자식 기본 `min-width:auto` 때문에 긴 단어 하나가 열을 밀어낸다.

   🔼 2026-08-25 **분할의 시작점이 제목 줄 위로 올라갔다**(오너 지시). 1열 격자 → **2열 × 2행**:
        ┌──────────────┬──────────────┐
        │ 1행 1열      │              │  ← .otd-top (제목 줄, 높이 auto)
        ├──────────────┤  1~2행 2열   │
        │ 2행 1열      │  (.otd-side) │  ← .otd-main (스크롤)
        └──────────────┴──────────────┘
      · 행 = `auto minmax(0, 1fr)` — 1행은 제목 줄 높이만큼, 2행이 남은 높이를 전부 갖는다.
        `minmax(0, 1fr)` 의 0 하한이 **필수**다: 그냥 `1fr` 이면 최소 크기가 내용 기반이라
        긴 코멘트 스레드가 행을 밀어 올려 `.otd-thread` 의 `overflow:auto` 가 스크롤할 기준을 잃는다.
      · `.otd-side` 는 `grid-row: 1 / -1` 로 **두 행을 통째로** 덮는다 → 제목 줄과 같은 y 에서 시작하고
        세로로 제목 줄 높이만큼 길어진다(코멘트 스레드가 그만큼 더 보인다).
      · 배치는 전부 **명시**한다. 자동 배치에 맡기면 `.otd-main` 이 1행 2열로 들어간다.
   ⛔ `display: contents` 로 격자를 한 단계 끌어올리는 방법은 쓰지 않았다 — 접근성 트리에서 상자가
      사라지는 방식이라 얻는 것보다 위험이 크고, 제목 줄을 이 안으로 **옮기는 편**이 DOM 순서와도 맞는다. */
.otd-split[b-vy2jjdamk1] {
    flex: 1 1 auto;
    min-height: 0;
    display: grid;
    /* 🔄 2026-08-26: 비율(1.5fr:1fr = 576/384) → **좌측 고정폭 + 우측이 나머지**.
       960px 기준 **좌 536 / 우 424**(이전 576/384 — 좌측에서 말던 40px 가 그대로 코멘트 열로 갔다).
       • 좌측 `minmax(0, ...)` — 창이 좀아지면 줄어든다(고정 px 로 박지 않는다).
       • 우측 `minmax(340px, 1fr)` — **코멘트 열의 하한을 지킨다.** 고정 좌측 폭만 두면
         마이너스 방향으로 코멘트 열만 계속 줄어 860px 구간 전에 말풍선이 무너진다.
         340 은 ≤860px 분기점의 근거(우측 콘텐츠 300px 하한) + 패딩 32 + 헤어라인 1 에서 나온 값이다.
       📐 배분 순서(그리드 사양): 비유연 트랙(좌)이 먼저 최대 536 까지 차고, 남는 폭을 fr(우)이 가져간다.
          → 960: 좌 536 / 우 424. → 836(좀은 창): 좌 496 / 우 340(하한 유지, 좌측이 양보한다). */
    grid-template-columns: minmax(0, var(--otd-left-w)) minmax(340px, 1fr);
    /* 🔄 2026-08-25: 제목 줄이 사라져 **1행**이 됐다(예전 `auto minmax(0,1fr)` 의 첫 행이 제목 줄이었다).
       `minmax(0, 1fr)` 의 0 하한은 그대로 필수다 — 그냥 `1fr` 이면 최소 크기가 내용 기반이라
       긴 코멘트 스레드가 행을 밀어 올려 `.otd-thread` 의 `overflow:auto` 가 스크롤 기준을 잃는다. */
    grid-template-rows: minmax(0, 1fr);
    min-width: 0;
}

/* ── `solo` = 코멘트 단독 모드(시스템 게시물) ─────────────────────
   2026-08-25 오너 지시 "코멘트인데 투표 내용이 있어" → 좌측 열을 아예 그리지 않는다(마크업에서 제외).
   격자를 **1열**로 줄이고 우측 패널을 그 자리에 앉힌다. 창 폭도 Small 로 내려간다(`OpsBoard.OpenSysDetail`).
   ⚠️ **틴트 배경은 유지한다.** 말풍선 색이 이 틴트(#f8fafc) 위에서 잡혀 있어서 흰 면으로 바꾸면
      회색 말풍선(#f1f5f9)이 배경과 1.04:1 로 **모양 자체가 사라진다**(이 파일 §말풍선 주석의 실측 이력).
      좌측 열이 없다고 틴트를 걷지 말 것. */
.otd-split.solo[b-vy2jjdamk1] {
    grid-template-columns: minmax(0, 1fr);
}

.otd-split.solo .otd-side[b-vy2jjdamk1] {
    grid-column: 1;
    border-left: none;   /* 가를 상대가 없다 */
}

/* 좌측 = 내용. **제목 줄 아래(2행 1열)** 에서 자기 스크롤을 갖는다. */
.otd-main[b-vy2jjdamk1] {
    grid-column: 1;
    grid-row: 1;
    min-width: 0;
    min-height: 0;
    overflow-y: auto;
    overscroll-behavior: contain;
    scrollbar-width: thin;
    display: flex;
    flex-direction: column;
    /* 🔄 2026-08-25 오너 지시 "상세 내용 제목과 내용의 **상단 여백을 줄여**줘".
       s5(24) → **s3(12)**. 이 열의 자식은 `정보` 섹션과 `상세내용` 섹션 **둘뿐**이라
       이 gap 이 곧 **`상세내용` 위 여백**이다 — 다른 자리를 건드리지 않고 그 한 곳만 조인다.
       (상세내용이 비면 자식이 하나라 gap 자체가 생기지 않는다.)
       ℹ️ 같은 날 섹션 제목이 삭제된 뒤에도 값은 그대로다. 이 12px 이 붙는 대상만
          `상세내용 제목` → `상세내용 섹션의 border-top`(구분선)으로 바뀌었다(→ §상세내용 여백).
       ⛔ 우측 코멘트 열(.otd-side)·컴포저는 이 규칙 밖이다. */
    gap: var(--ope-s3);
    padding: var(--ope-s4);
}

/* 우측 = 댓글 전용. **은은한 틴트 + 세로 헤어라인**으로 면을 가른다(제목 하나로 가르지 않는다).
   색은 새로 만들지 않았다 — `--ope-tint`(#f8fafc)는 이 파일이 이미 메모 상자에 쓰는 값이고,
   헤어라인도 섹션 밑줄과 같은 `--ope-line`(#e2e8f0)이다.
   안은 2층: 고정된 머리(.otd-side-top = 제목 + 입력칸) / 스크롤되는 스레드(.otd-thread). */
.otd-side[b-vy2jjdamk1] {
    /* 🔼 2026-08-25: **두 행을 통째로 덮는다.** 제목 줄과 같은 y 에서 시작하고(오너 지시),
       왼쪽 세로 헤어라인도 그만큼 위로 연장돼 두 열의 경계가 다이얼로그 헤더까지 이어진다.
       ⚠️ `min-height: 0` 이 여기서 결정적이다 — 없으면 스레드 내용이 행을 밀어 올려
          `.otd-thread{overflow-y:auto}` 가 스크롤하지 않고 통째로 늘어난다. */
    grid-column: 2;
    grid-row: 1;
    min-width: 0;
    min-height: 0;
    display: flex;
    flex-direction: column;
    background: var(--ope-tint);
    border-left: 1px solid var(--ope-line);
}

/* ── 우측 코멘트 열의 **고정 머리**(스크롤되지 않는다) ─────────────────────
   🔄 2026-08-25 오너 지시 "코멘트 옆으로 뻗는 가로선 말고, **문서 제목처럼 아래에 라인을 깔아라.**
      스크롤도 라인에 맞춰줘."
      → 선을 제목 **옆**(`.otd-sec-h::after` = 남은 폭을 채우던 flex 헤어라인)에서 걷어내고
        머리 블록 전체의 **`border-bottom`** 으로 옮겼다. 세 가지가 함께 따라온다:

     ① **가로 범위 = 우측 열 폭 전체(끝에서 끝).** border 는 이 요소의 *border box* 를 따라 그려지므로
        좌우 padding(16px) 바깥, 즉 틴트 패널의 왼쪽 헤어라인부터 창 오른쪽 끝까지 한 줄로 닿는다.
        ⚠️ **일부러 목록 안쪽(16px)에 맞추지 않았다.** 스레드(`.otd-thread`)는 `overflow-y:auto` 라
           오른쪽에 스크롤바가 서고, 그만큼 콘텐츠 상자가 **가변적으로 줄어든다**(scrollbar-width:thin ≈11px,
           게다가 스크롤이 없는 카드에서는 0). 선을 목록에 맞추면 그 가변분만큼 **매번 어긋난다.**
           끝에서 끝까지 긋는 쪽은 어긋날 대상이 아예 없고, 좌측 제목 줄(`.otd-top`)이 이미 같은 방식이다.
     ② **좌측 제목 줄의 선과 같은 y 에 선다** → 두 열의 머리 밑줄이 창을 가로지르는 한 줄로 이어진다.
        아래 여백 s1(4) → **s3(12)** 로 되돌린 것이 그 계산이다:
          · 좌 `.otd-top`      = 16(pt) + 22.85(`.otd-title` 1.02rem×1.4) + 12(pb) ≈ **50.9px**
          · 우 `.otd-side-top` = 16(pt) + 22.85(아래 ZWSP 스트럿이 만든 같은 line box) + 12(pb) ≈ **50.9px**
        두 상자가 같은 y 에서 시작하므로(`.otd-side` 가 `grid-row:1/-1`) 밑줄도 같은 y 에서 끝난다.
     ③ **선은 머리 안에 있으므로 스크롤되지 않는다**(이 요소는 `flex:0 0 auto` = 스크롤 영역 밖).
        스크롤 포트인 `.otd-thread` 가 이 선 **바로 아래**에서 시작하고, 오버플로 클리핑은 padding box 상단 =
        이 선의 위치에서 일어난다 → 첫 코멘트가 밑줄에 딱 잘린다(→ 아래 .otd-thread 의 padding-top 주석).
   🎨 색은 `--ope-line-2`(#cbd5e1). 틴트(#f8fafc) 위에서 `--ope-line`(#e2e8f0)은 1.16:1 로 사실상 안 보인다
      — 바닥 컴포저의 경계선(`.otd-side-bot`)이 이미 같은 이유로 이 값을 쓴다(새 색 아님). */
.otd-side-top[b-vy2jjdamk1] {
    flex: 0 0 auto;
    display: flex;
    flex-direction: column;
    gap: var(--ope-s3);
    min-width: 0;
    padding: var(--ope-s4) var(--ope-s4) var(--ope-s3);
    border-bottom: 1px solid var(--ope-line-2);
}

/* ⛔ **좌우 baseline 맞추기 장치 삭제**(2026-08-25) — 좌측 제목 줄이 없어져 맞출 대상이 사라졌다.
   걷어낸 것: ZWSP 스트럿 `.otd-side-top .otd-sec-t::before` · `align-items: baseline`.
   지금은 다른 섹션 제목과 같은 규격(`align-items: center`)이고, 이 머리의 **밑줄은 그대로 남는다**
   (오너가 지시한 "문서 제목처럼 아래에 라인"은 계속 유효하다 — 위 §머리 참조). */
.otd-side-top .otd-sec-h[b-vy2jjdamk1] {
    align-items: center;
}

/* ⛔ `.otd-sec-h::after`(제목 옆으로 뻗던 헤어라인) 규칙 **삭제**(2026-08-25) — 세 곳이 함께 사라졌다:
   공통 선언 · 틴트 위 색 보정(`.otd-side .otd-sec-h::after`) · 세로 정렬 예외(`.otd-side-top … {align-self:center}`).
   우측 선은 머리 블록의 `border-bottom` 이 됐고, 좌측 섹션 제목 2개는 같은 날 통째로 삭제됐다
   → 이 파일에 `::after` 헤어라인을 쓰는 자리가 하나도 남지 않았다(죽은 규칙을 남기지 않는다). */

.otd-thread[b-vy2jjdamk1] {
    flex: 1 1 auto;
    min-height: 0;
    min-width: 0;
    overflow-y: auto;
    overscroll-behavior: contain;
    scrollbar-width: thin;
    /* 🔄 2026-08-25 오너 지시 ①"스크롤도 라인에 맞춰줘" → ②"코멘트제목라인과 채팅 내용의 높이 여백을
       추가해줘. **대신 스크롤은 라인까지 올라가게.** 마치 안드로이드의 clip padding 같은 느낌?"
       위 여백 0 → s1(4) → **s4(16)**. 두 지시는 충돌하지 않는다 — 정확히 안드로이드 `clipToPadding=false` 이고,
       CSS 에서는 **스크롤 컨테이너의 `padding-top`** 이 그 성질을 그대로 갖는다:
         · 맨 위에서는 밑줄과 첫 말풍선 사이에 16px 이 **보이고**
         · 스크롤하면 콘텐츠가 그 16px 을 **지나 올라가 밑줄에서 잘린다**(여백이 따라 밀리지 않는다).
       ⛔ `margin-top` 으로 하면 안 된다 — 마진은 스크롤과 **함께 밀려** 콘텐츠가 라인까지 못 올라간다.
       📐 16px 을 고른 이유: 이 파일의 표준 블록 간격(s4)이고 4px 대비 **4배**라 눈에 확실히 띈다.
          s5(24)는 코멘트 패널의 세로를 그만큼 먹어 한 화면에 보이는 말풍선이 줄어든다.
       ℹ️ 스크롤바 트랙은 padding box 전체(= 밑줄 바로 아래)에 걸친다 — clipToPadding 의 정상 거동이라 그대로 둔다.
       (예전 값 s1(4)의 근거였던 "밑줄에 첫 말풍선이 맞닿아 두 선으로 보인다"는 16px 에서 자연히 해소된다.) 스크롤 **영역**의 상단은 여전히 밑줄에 정확히 맞닿아 있다 —
       오버플로 클리핑은 content box 가 아니라 **padding box** 에서 일어나므로, 이 4px 은
       "선과 목록 사이의 틈"이 아니라 **맨 위로 스크롤했을 때만 보이는 첫 말풍선의 숨통**이다.
       스크롤을 내리면 코멘트는 이 4px 을 지나 **밑줄에서 잘린다**(선 위로 새지 않는다).
       0 으로 두지 않은 이유는 예전과 같다: 밑줄에 첫 말풍선의 테두리가 맞닿으면 두 선이 겹쳐 보인다.
       아래 여백이 s4 → s3 로 줄었다(2026-08-25 B-3): 스레드 밑에 컴포저 블록(.otd-side-bot)이
       자기 위쪽 여백 s3 를 갖고 붙으므로, 예전 값을 두면 마지막 말풍선과 입력칸 사이가 28px 로 벌어진다. */
    padding: var(--ope-s4) var(--ope-s4) var(--ope-s3);
}

/* ── 패널 바닥 = 컴포저 고정층 (2026-08-25 B-3, 오너 지시) ────────────────
   자리: ⑯ 의 "스레드 위" → **스레드 아래.** 스레드가 오래된 것 위 · 최신 아래로 흐르므로
   쓰는 자리는 대화가 자라는 쪽 끝에 있어야 손과 눈이 같은 지점에 머문다(메신저 규약).
   경계선은 `--ope-line`(#e2e8f0) 이 아니라 **`--ope-line-2`(#cbd5e1)** 다 — 틴트(#f8fafc) 위에서
   #e2e8f0 은 1.16:1 로 사실상 보이지 않는다(같은 이유로 위쪽 섹션 헤어라인도 이 값으로 덮여 있다). */
.otd-side-bot[b-vy2jjdamk1] {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    min-width: 0;
    padding: var(--ope-s3) var(--ope-s4) var(--ope-s4);
    border-top: 1px solid var(--ope-line-2);
}

/* 🔤 2026-08-25 **줄바꿈 → 말줄임**. 제목 줄이 창 전폭에서 좌측 열(6/10)로 좁아졌기 때문이다:
   줄바꿈을 두면 긴 제목이 이 머리를 2~3줄로 키워 우측 `코멘트 N` 과 첫 줄이 어긋나고,
   좌측 열의 고정 머리 높이가 카드마다 달라진다(두 열의 눈높이가 카드마다 흔들린다).
   ⛔ `overflow-wrap: anywhere` 는 함께 걷어냈다 — `nowrap` 과 같이 두면 아무 일도 하지 않는다.
   ℹ️ 잘린 글자는 사라지지 않는다: .razor 에서 같은 값을 `title` 속성으로 넘겨 네이티브 툴팁으로 읽게 했다.
   ℹ️ 좁은 화면(≤860px)에서는 한 열이 창 전폭이라 사실상 잘릴 일이 없다 — 규칙은 그대로 둔다. */
.otd-title[b-vy2jjdamk1] {
    flex: 1 1 auto;
    min-width: 0;
    margin: 0;
    font-size: 1.02rem;
    font-weight: 800;
    line-height: 1.4;
    color: var(--ope-ink);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* 완료·종료 카드 — 취소선만. ⛔ 색을 회색으로 눌러 흐리게 만들지 않는다
   (보드 카드에서 `opacity` 를 걷어낸 것과 같은 판단: 끝난 일도 읽는 일이다 — 2026-08-25 오너 지시 13). */
.otd-title.done[b-vy2jjdamk1] {
    text-decoration: line-through;
}

/* 보드 분류칩과 같은 규격 — 색은 C# 이 인라인으로 준다(OpsKindChips 단일 출처). */
.otd-kind[b-vy2jjdamk1] {
    flex: 0 0 auto;
    margin-top: 3px;
    padding: 0 var(--ope-s2);
    border-radius: var(--ope-r-sm);
    font-size: 0.62rem;
    font-weight: 800;
    line-height: 1.7;
    white-space: nowrap;
}

/* 타이틀바 아이콘 자리의 분류칩(2026-08-25 오너 지시) — 24px 아이콘이 있던 자리라 한 단계 크게,
   글자와의 간격은 예전 아이콘의 `margin-right:8px` 을 그대로 승계한다(헤더 정렬이 안 흔들리게). */
.otd-kind.hd[b-vy2jjdamk1] {
    margin-top: 0;
    margin-right: var(--ope-s2);
    font-size: 0.68rem;
    line-height: 1.9;
}

.otd-kind.sm[b-vy2jjdamk1] {
    margin-top: 0;
    font-size: 0.58rem;
    line-height: 1.5;
    padding: 0 5px;
}

/* ── 섹션 ───────────────────────────────────────────────────────────────
   🔄 2026-08-25 오너 지시로 **좌측 섹션의 제목줄이 사라졌다**(`정보`·`상세내용`).
      남은 사용처는 **우측 코멘트 머리 하나뿐**이라 `.otd-sec-h`/`.otd-sec-t` 는 그 용도로만 남는다
      (선은 `::after` 헤어라인이 아니라 `.otd-side-top` 의 `border-bottom` — 위 §머리).
   `.otd-sec` 자체는 좌측에서도 계속 쓴다: `.otd-main` 의 gap(12px)이 붙는 층이자,
   `상세내용` 의 구분선·꼬리 여백이 걸리는 상자다(아래 §상세내용 여백). */
.otd-sec[b-vy2jjdamk1] {
    display: flex;
    flex-direction: column;
    gap: var(--ope-s3);
    min-width: 0;
}

.otd-sec-h[b-vy2jjdamk1] {
    display: flex;
    align-items: center;
    gap: var(--ope-s3);
    min-width: 0;
}

.otd-sec-t[b-vy2jjdamk1] {
    flex: 0 0 auto;
    font-size: 0.76rem;
    font-weight: 800;
    letter-spacing: 0.04em;
    color: var(--ope-ink);
    white-space: nowrap;
}

/* 코멘트 수 — 섹션 제목 바로 옆(`코멘트 3`). 칠한 뱃지를 만들지 않는다: 제목 층은 조용해야 하고,
   이 창에서 색을 쓰는 요소는 분류칩·상태칩·아바타뿐이다(장식 총량 유지). */
.otd-n[b-vy2jjdamk1] {
    flex: 0 0 auto;
    margin-left: -4px;   /* 부모 gap(12px)은 제목–선 간격 기준이라 숫자는 제목에 더 붙인다 */
    font-variant-numeric: tabular-nums;
    font-size: 0.76rem;
    font-weight: 800;
    color: var(--ope-ink-2);
}

/* ── 정보 패널(dl) — 2026-08-25 B-4 (오너: "정보 영역이 너무 허전하다") ────────
   무엇이 허전했나(진단):
     ① 목록이 **면을 갖지 않아** 제목 아래 글자 4~5줄이 흰 바탕에 떠 있었다.
     ② `space-between` 우측 정렬이라 라벨과 값 사이에 **행마다 길이가 다른 빈 홈**이 났다 —
        좌측 열 폭이 550px 대라 그 홈이 300px 넘게 벌어졌고, 이것이 '허전함'의 실제 정체다.
     ③ 값의 시작 x 가 행마다 달라(우측 끝 기준) 세로로 훑을 축이 없었다.
   고친 방법(전부 이 창이 이미 쓰는 언어 — 새 색·새 컴포넌트 0):
     ① **면**: 상세내용 상자(.otd-note-b)와 같은 틴트 + 헤어라인 + 라운드. 좌측이 두 덩어리로 읽힌다.
     ② **고정 라벨 열**(--otd-key 88px) + 좌측 정렬 → 홈이 일정해지고 값이 한 축에 선다.
     ③ **아이콘**(.otd-ico)이 라벨 왼쪽에 붙어 세로 방향의 스캔 축을 만든다.
     ④ **담당자 얼굴**(.otd-face) — 우측 코멘트 아바타와 같은 색 규칙(AdminNoticeService).
   행 높이는 4px → **7px** 상하 패딩. 정보 5행 기준 약 30px 만 길어지고(좌측은 스크롤 열이라 여유가 있다)
   대신 행이 서로 붙어 뭉개지지 않는다. 구분선은 `--ope-line`(틴트 위 1.4:1)로 한 단계 진하게 —
   예전 #f1f5f9 는 이제 배경이 틴트라 아예 보이지 않는다. */
.otd-rows[b-vy2jjdamk1] {
    margin: 0;
    display: flex;
    flex-direction: column;
    min-width: 0;
    padding: var(--ope-s1) var(--ope-s3);
    border: 1px solid var(--ope-line);
    border-radius: var(--ope-r);
    background: var(--ope-tint);
}

.otd-row[b-vy2jjdamk1] {
    display: grid;
    grid-template-columns: var(--otd-key) minmax(0, 1fr);
    align-items: center;
    gap: var(--ope-s2);
    padding: 7px 0;
    border-bottom: 1px solid var(--ope-line);
    font-size: 0.8rem;
    min-width: 0;
}

.otd-row:last-child[b-vy2jjdamk1] {
    border-bottom: none;
}

.otd-row dt[b-vy2jjdamk1] {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    min-width: 0;
    font-weight: 700;
    color: var(--ope-ink-2);
    white-space: nowrap;
}

/* 라벨 아이콘 — **글자가 아니라 동반 기호**다. 라벨을 대체하지 않으므로 색은 가장 약한 층(--ope-muted)이면 충분하고
   (틴트 위 4.5:1 — 비텍스트 최소 3:1 을 넉넉히 넘는다), 시선은 여전히 라벨 글자가 가져간다.
   `::deep` 필수 — MudIcon 은 **자식 컴포넌트**라 이 파일의 스코프 속성(b-xxxxx)이 그 svg 에 붙지 않는다
   (같은 이유로 .otd-send 도 ::deep 을 쓴다). */
.otd-ico[b-vy2jjdamk1] {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 16px;
    height: 16px;
    color: var(--ope-muted);
}

.otd-ico[b-vy2jjdamk1]  .mud-icon-root {
    width: 15px;
    height: 15px;
    font-size: 15px;
}

.otd-row dd[b-vy2jjdamk1] {
    margin: 0;
    min-width: 0;
    text-align: left;
    font-weight: 700;
    color: var(--ope-ink);
    font-variant-numeric: tabular-nums;
    overflow-wrap: anywhere;
}

.otd-row dd.prog[b-vy2jjdamk1],
.otd-row dd.who[b-vy2jjdamk1] {
    display: flex;
    align-items: center;
    justify-content: flex-start;
    gap: var(--ope-s2);
}

/* 미지정 — 값이 없다는 사실도 값이다. 다만 **있는 값보다 조용해야** 훑을 때 걸리지 않는다.
   ⛔ 회색 이탤릭·괄호 같은 장식은 쓰지 않는다(이 창에 그런 어휘가 없다) — 굵기와 색 한 단계로만 낮춘다. */
.otd-row dd.none[b-vy2jjdamk1] {
    font-weight: 600;
    color: var(--ope-muted);
}

/* 담당자 얼굴 — 코멘트 아바타(.otd-avatar)의 **작은 판**. 같은 사람은 두 곳에서 같은 색·같은 이니셜이다
   (색표를 복제하지 않고 AdminNoticeService.AvatarColor/Initial 를 .razor 에서 호출한다).
   28px 를 그대로 쓰지 않는 이유: 정보 행 높이(글자 0.8rem + 패딩 14px ≈ 32px)에 28px 원이 들어오면
   행이 아바타 크기에 끌려 커지고, 정보 목록이 프로필 목록처럼 읽힌다. 22px 는 행 높이 안에 들어간다. */
.otd-face[b-vy2jjdamk1] {
    flex: 0 0 auto;
    width: 22px;
    height: 22px;
    border-radius: 50%;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    color: #ffffff;
    font-weight: 800;
    font-size: 0.66rem;
    line-height: 1;
}

.otd-pname[b-vy2jjdamk1] {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* 상태칩 — **보드 카드의 상태 드롭다운(.ob-stsel.st-*)·할 일 편집기의 상태 칩과 같은 색표**다.
   스코프 CSS 는 공유가 안 되므로 값을 복제하되, 색을 새로 고르지는 않는다(한 시스템으로 읽혀야 한다).
   대비 실측: 예정 #334155 on #e2e8f0 = 8.85:1 · 진행중 #1d4ed8 on #dbeafe = 6.94:1 ·
             완료 #047857 on #d1fae5 = 4.78:1 · 보류 #92400e on #fef3c7 = 6.87:1 · 미확정 #6d28d9 on #ede9fe = 6.60:1. */
.otd-st[b-vy2jjdamk1] {
    display: inline-flex;
    align-items: center;
    height: 20px;
    padding: 0 var(--ope-s2);
    border: 1px solid transparent;
    border-radius: var(--ope-r-sm);
    font-size: 0.72rem;
    font-weight: 800;
    line-height: 1;
}

.otd-st.st-plan[b-vy2jjdamk1] { background-color: #e2e8f0; border-color: #cbd5e1; color: #334155; }
.otd-st.st-prog[b-vy2jjdamk1] { background-color: #dbeafe; border-color: #bfdbfe; color: #1d4ed8; }
.otd-st.st-done[b-vy2jjdamk1] { background-color: #d1fae5; border-color: #a7f3d0; color: #047857; }
.otd-st.st-hold[b-vy2jjdamk1] { background-color: #fef3c7; border-color: #fde68a; color: #92400e; }
.otd-st.st-tent[b-vy2jjdamk1] { background-color: #ede9fe; border-color: #ddd6fe; color: #6d28d9; }

/* ── 상세내용 섹션의 상·하 여백(2026-08-25 오너 지시) ──────────────────────
   오너 원문: "상세 내용 제목과 내용의 상단 여백을 줄여주고, 대신 하단 여백은 많이 추가해줘. 여유있게"
   대상은 **좌측 상세 열의 `상세내용` 섹션 하나**다. 우측 코멘트 열·컴포저는 손대지 않았다.
   그래서 `.otd-sec` 공통 규칙을 고치지 않고 이 섹션에만 붙는 `.otd-note` 수식 클래스를 썼다
   (`정보` 섹션과 코멘트 섹션의 리듬은 그대로 유지된다).

   📐 값은 전부 기존 4배수 눈금(--ope-s1..s5) 위에서 골랐다. 새 홀수 px 없음:
     · 제목 위    24px(.otd-main gap s5) → **12px**(s3)                    ← 위 .otd-main
     · 제목–본문  12px(.otd-sec gap s3) + 6px(.otd-note-b 위 패딩) = 18px
                  → **8px**(s2) + **4px**(s1) = **12px**
     · 본문 아래  0 → **48px**(--otd-note-tail) + .otd-main 아래 패딩 16px = **총 64px**
   🎯 하단 48px 의 근거: 눈금의 가장 큰 칸(s5=24)의 **2배**다. "많이·여유있게"를 s5 한 칸(24)으로 주면
      섹션 사이 간격과 같은 값이 되어 '여백'이 아니라 '다음 섹션이 오려다 만 자리'로 읽힌다.
      한 눈금 위(48)로 올려야 본문의 끝이 끝으로 읽힌다. 상단을 12px 로 조였으므로 상:하 = 12 : 64 로 무게가 아래에 실린다.
   ⚠️ 의도된 부작용 — 상세내용이 짧은 카드에서는 이 64px 이 **빈 공간으로 남는다**
      (11번으로 창이 46~75px 더 커진 것과 겹치면 더 두드러진다). 지시가 "여유있게"이므로 그대로 두고 보고한다.
   ℹ️ 상세내용이 없으면 이 섹션 자체가 렌더되지 않으므로(`NoteIsEmpty` 가드) 꼬리 여백도 함께 사라진다.
   ℹ️ ≤860px 세로 접힘에서도 그대로 적용된다 — 그 구간에서는 이 48px 이 상세내용과 아래로 내려온
      코멘트 열 사이의 간격이 되어 오히려 경계가 또렷해진다.

   ── 🔄 2026-08-25 제목 삭제 후(오너 지시) — **상 12 : 하 64 를 그대로 지킨다** ────────────
   제목줄(`.otd-sec-h`)이 사라지면서 이 섹션의 위쪽 기준이 `제목의 헤어라인` → `섹션의 border-top` 으로 바뀌었다.
   위쪽 12px 을 만드는 두 항의 **주인만 바뀌고 합은 같다**:
     · 이전  구분선(제목 옆 헤어라인) → `.otd-sec` gap **8px**(s2) → `.otd-note-b` 위 패딩 **4px**(s1) = **12px**
     · 지금  구분선(`border-top`)     → 이 섹션 `padding-top` **8px**(s2) → `.otd-note-b` 위 패딩 **4px**(s1) = **12px**
   (자식이 `.otd-note-b` 하나뿐이라 `gap` 은 아무 일도 하지 않게 됐다 → `padding-top` 으로 옮겼다.)
   구분선 위 12px 은 여전히 `.otd-main` 의 gap(s3)이고, 아래 64px 은 48(--otd-note-tail) + 16(.otd-main 패딩) 그대로다.
   ⚖️ 결과: **위 12px : 아래 64px** — 오너가 지정한 "위는 조이고 아래는 넉넉히"의 비율이 유지된다.
   🎨 구분선 색은 `--ope-line`(흰 배경 위 1.23:1) — 좌측 열은 흰 면이라 틴트용 `--ope-line-2` 를 쓰지 않는다.
      바로 위 `.otd-top` 의 `border-bottom` 과 같은 색·같은 굵기라 좌측 열의 가로선 두 줄이 한 어휘로 읽힌다. */
.otd-sec.otd-note[b-vy2jjdamk1] {
    padding-top: var(--ope-s2);
    padding-bottom: var(--otd-note-tail);
    border-top: 1px solid var(--ope-line);
}

.otd-sec.otd-note .otd-note-b[b-vy2jjdamk1] {
    padding-top: var(--ope-s1);
}

/* ── 상세내용 전문 ─────────────────────────────────────────────────────────
   🔴 2026-08-25: 내용이 평문에서 **HTML** 로 바뀌었다(웹에디터 전환).
      `white-space: pre-wrap` 을 **제거**했다 — HTML 렌더와 정면으로 충돌한다.
      남겨 두면 소스의 들여쓰기·태그 사이 개행이 전부 여백으로 찍혀 문단마다 빈 줄이 생긴다
      (줄바꿈은 이제 `<br>`·`<p>` 가 만든다 — pre-wrap 이 할 일이 아니다).
   ⚠️ 아래 자식 규칙에 `::deep` 이 붙는 이유: 본문은 `MarkupString` 으로 주입돼
      **이 컴포넌트의 스코프 속성(b-xxxxx)이 그 요소들에 붙지 않는다.** ::deep 없이는 하나도 안 걸린다. */
.otd-note-b[b-vy2jjdamk1] {
    margin: 0;
    /* 🔄 2026-08-25 오너 지시 "상세 내용은 배경색과 아웃라인을 제거해줘. 그냥 흰색 바탕에 내용이 나오게."
       걷어낸 것: `background: var(--ope-tint)` · `border: 1px solid var(--ope-line)` · `border-radius`.
       ⚖️ **정보 카드(.otd-rows)는 그대로 틴트 상자다** — 오너 지시는 상세내용 한정이고,
          둘이 서로 다른 처리가 되는 것이 의도다(위는 '값의 목록', 아래는 '읽는 글'). 층이 갈려 읽힌다.

       📐 **좌우 패딩을 0 으로** 내렸다(10px 12px → 6px 0). 상자가 사라졌으므로 안쪽 여백의 근거도 사라진다:
          이제 본문의 왼쪽 끝은 **섹션 제목(`상세내용`)의 왼쪽 끝과 같은 x** 다. 12px 를 남겨 두면
          제목보다 12px 안으로 들어가 글이 이유 없이 들여쓰기된 것처럼 보인다.
          ℹ️ 정보 카드의 글자와는 12px 어긋나는데, 그쪽은 **상자 안**이라 그 들여쓰기에 근거가 있다.
             기준선은 상자가 없는 쪽이 섹션 라벨을, 있는 쪽이 자기 상자를 따르는 것이 맞다.
       📐 위 여백만 6px 남겼다 — 섹션 제목 헤어라인에 글자가 바로 붙지 않게 하는 최소치다
          (`.otd-sec` 의 gap 12px 위에 얹힌다).
       🎨 결과적으로 **편집기의 본문 면과 같아졌다**: 편집 다이얼로그도 같은 날 `.editor-theme` 의 어두운 면을
          이 화면 한정으로 흰 면(--ope-surface)·잉크색(--ope-ink)으로 덮었다 → 쓰는 화면과 읽는 화면이 같은 종이다. */
    padding: 6px 0 0;
    /* 📐 2026-08-26 오너 지시 "수정에 웹에디터 넓이와 상세내용 보기 상에서 내용의 넓이를 똑같이 맞춰줘".
       **편집기 쪽 폭에 맞춘다**(값·근거는 `app.css` §--ope-doc-w). 넓은 쪽(이 창)이 좁은 쪽으로 내려오는 방향이다 —
       편집기는 `MaxWidth.Small`(600px) 확정값이라 더 넓어질 수 없고, 다이얼로그 폭은 양쪽 다 오너 확정이라
       **내용 폭으로만** 맞출 수 있기 때문이다.
       🖼️ 이미지도 같은 기준으로 스케일된다 — 아래 `::deep img { max-width: 100% }` 의 100% 가
          이 `max-width` 를 따르므로, 편집 중 크기와 저장 후 크기가 같아진다(오너 스크린샷의 차이가 이 지점이었다).
       ℹ️ `max-width` 라 **좁아질 때는 그냥 따라 좁아진다** → ≤860px 세로 접힘·좁은 뷰포트에서는
          열이 이 값보다 좁아지므로 제한이 자연히 풀린다(빈 띠가 남지 않는다). */
    max-width: var(--ope-doc-w);
    font-size: 0.84rem;
    font-weight: 500;
    line-height: 1.65;
    color: var(--ope-ink); /* #334155(9.9:1) → #0f172a(16.4:1 on 틴트). 읽는 층이 가장 진해야 한다 */
    overflow-wrap: anywhere;
}

/* 본문 이미지는 상자를 넘지 않는다. 원본이 커도 폭에 맞춰 줄이고 비율은 유지한다. */
.otd-note-b[b-vy2jjdamk1]  img {
    max-width: 100%;
    height: auto;
    border-radius: var(--ope-r-sm);
}

/* ⛔ `.otd-imgs`/`.otd-img`(시스템 게시물 미리보기 이미지) 규칙 **삭제**(2026-08-25 오너 정정)
   — "시스템은 내용보기 삭제해줘. 코멘트만". 그리는 마크업이 함께 사라져 죽은 규칙이 됐다. */

/* 문단 간격 — 브라우저 기본 1em 은 이 좁은 상자에서 너무 벌어진다.
   마지막 문단의 아래 여백은 지운다(상자 안쪽 아래가 비어 보이지 않게). */
.otd-note-b[b-vy2jjdamk1]  p {
    margin: 0 0 0.5em;
}

.otd-note-b[b-vy2jjdamk1]  p:last-child {
    margin-bottom: 0;
}

/* 목록은 들여쓰기가 없으면 글머리표가 상자 밖으로 나간다. */
.otd-note-b[b-vy2jjdamk1]  ul,
.otd-note-b[b-vy2jjdamk1]  ol {
    margin: 0 0 0.5em;
    padding-left: 1.25em;
}

/* 유튜브 임베드 래퍼(에디터가 붙이는 position:relative div)도 상자를 넘지 않게. */
.otd-note-b[b-vy2jjdamk1]  iframe {
    max-width: 100%;
}

/* ── 댓글 스레드 ───────────────────────────────────────────────────────── */
.otd-empty[b-vy2jjdamk1] {
    margin: 0;
    padding: var(--ope-s4) var(--ope-s3);
    border-radius: var(--ope-r);
    border: 1px dashed var(--ope-line-2);
    font-size: 0.78rem;
    font-weight: 600;
    line-height: 1.6;
    color: var(--ope-ink-2);
}

/* ── 메신저 타임라인 ─────────────────────────────────────────────────────
   📎 출처: `Components/Layout/AdminNoticeTimeline.razor.css`(관리자 공지 실시간 대화, 2026-08-23).
      오너 지시 15: "운영 보드 코멘트 창은 관리자 투표 화면처럼 메신저 형태로."
   ⚠️ **왜 복제인가**: Blazor 스코프 CSS 는 컴포넌트 경계를 넘어 공유되지 않는다(`b-xxxxx` 속성이 다르다).
      원본 파일은 게시 대기 중인 별건이라 손대지 말라는 지시가 있어 공통 클래스로 뽑을 수도 없었다.
      그래서 **말풍선·아바타·이름·시각의 규격만 값을 옮겨 적고, 출처를 여기 남긴다.** 나중에 한쪽을 바꾸면
      다른 쪽도 같이 봐야 한다 — 두 파일이 같은 규격을 공유한다는 사실이 이 주석의 존재 이유다.
   🔁 **색·이니셜은 복제하지 않았다** — `AdminNoticeService.AvatarColor()` / `Initial()`(public static)을
      .razor 에서 그대로 호출한다. 같은 사람은 두 화면에서 같은 색으로 나온다.
   🔀 원본과 다른 점(각각 .razor 주석에 사유 있음): 시각에 날짜 포함 · `column-reverse` 미채택. */
.otd-tl[b-vy2jjdamk1] {
    display: flex;
    flex-direction: column;
    gap: var(--ope-s2); /* 원본 .tl 과 같은 8px */
    min-width: 0;
}

.otd-msg[b-vy2jjdamk1] {
    display: flex;
    max-width: 82%;
    gap: var(--ope-s2);
    min-width: 0;
}

.otd-msg.mine[b-vy2jjdamk1] {
    align-self: flex-end;
    flex-direction: column;
    align-items: flex-end;
}

.otd-msg.theirs[b-vy2jjdamk1] {
    align-self: flex-start;
    align-items: flex-start;
}

.otd-col[b-vy2jjdamk1] {
    display: flex;
    flex-direction: column;
    min-width: 0;
}

/* 말풍선 — 꼬리 쪽 모서리만 각지게(내 글 오른쪽 아래 / 남의 글 왼쪽 위). 원본과 같은 12px / 4px. */
.otd-bubble[b-vy2jjdamk1] {
    padding: 9px var(--ope-s3);
    border-radius: 12px;
    font-size: 0.84rem;
    line-height: 1.55;
    white-space: pre-wrap;
    overflow-wrap: anywhere;
    text-wrap: pretty;
    /* 원본은 #1e293b(14.8:1). 항목 14(색이 우중충하다)에 맞춰 --ope-ink 로 한 단계 진하게 → 흰 배경 17.9:1,
       내 말풍선 틴트 위에서도 16:1 이상. 읽으라고 있는 층이 이 창에서 가장 진해야 한다. */
    color: var(--ope-ink);
    min-width: 0;
}

/* 내 글 = 테마 primary 12% 틴트. **원본과 같은 변수 경로**(--mud-palette-primary-rgb)라 테마를 바꾸면 둘이 같이 따라간다.
   하드코딩 hex 로 옮겨 적으면 그 순간 두 화면이 갈라진다. */
.otd-msg.mine .otd-bubble[b-vy2jjdamk1] {
    background: rgba(var(--mud-palette-primary-rgb), 0.12);
    border-bottom-right-radius: var(--ope-s1);
}

/* 🔀 2026-08-25 ⑯ — 남의 말풍선만 면 색이 바뀌었다: `#f1f5f9` → **흰 면 + 1px 헤어라인.**
   이유는 배치 변경의 **직접적 결과**다: 스레드가 틴트 패널(#f8fafc) 위로 옮겨 갔는데
   #f1f5f9 와 #f8fafc 의 대비는 1.04:1 로 **말풍선 모양 자체가 사라졌다.**
   흰 면 + 헤어라인은 (a) 패널보다 밝아 떠 보이고 (b) 경계가 선으로 확정된다.
   ⛔ 시각 언어의 나머지는 손대지 않았다 — 꼬리 모서리 4px, 아바타 이니셜 원, 이름 줄, 시각 위치,
      내 글(primary 12% 틴트) 규칙은 원본(AdminNoticeTimeline) 그대로다. */
.otd-msg.theirs .otd-bubble[b-vy2jjdamk1] {
    background: var(--ope-surface);
    border: 1px solid var(--ope-line);
    border-top-left-radius: var(--ope-s1);
}

.otd-name[b-vy2jjdamk1] {
    font-size: 0.72rem;
    font-weight: 700;
    color: var(--ope-ink-2); /* 원본 #475569 와 같은 값 — 이 파일에서는 토큰으로 부른다 */
    margin-bottom: 3px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* 말풍선 아래 줄 = 시각 + (본인 글이면) 삭제. 원본의 `.tl-time` 자리를 그대로 쓰되 삭제 버튼이 같은 줄에 붙는다.

   🔄 2026-08-25 오너 지시로 이 줄이 **좌우 대칭**이 됐다 — *날짜가 바깥쪽 끝, 삭제가 안쪽.*
        내 글(오른쪽 정렬) : [삭제] [날짜]   ← 아래 justify-content:flex-end 가 묶음을 오른쪽에 붙인다
        남의 글(왼쪽 정렬) : [날짜] [삭제]   ← 기본값(flex-start) 그대로
      순서를 만드는 것은 **CSS 가 아니라 .razor 의 DOM 순서**다(row-reverse 를 쓰지 않은 이유는 그쪽 주석 참조).
      여기서 하는 일은 "묶음을 어느 쪽 끝에 붙이나" 하나뿐이라, 이 파일은 사실상 손댈 것이 없었다.
   📐 `.otd-foot` 은 `.otd-col`(stretch) 안에서 **말풍선 폭까지 늘어난다** → 양 끝은 말풍선의 모서리와 같은 선이다.
      즉 날짜는 말풍선 바깥 모서리에 정확히 맞고, 삭제는 그 안쪽으로 물러선다. */
.otd-foot[b-vy2jjdamk1] {
    display: flex;
    align-items: center;
    gap: var(--ope-s1);
    margin-top: 3px;
    /* 삭제 버튼이 숨어 있어도 줄 높이가 흔들리지 않게. 가로 흔들림은 `.otd-del{opacity:0}` 이 막는다
       (숨어도 자리를 차지하므로 호버할 때 날짜가 옆으로 밀리지 않는다 — §삭제 참조). */
    min-height: 24px;
}

.otd-msg.mine .otd-foot[b-vy2jjdamk1] {
    justify-content: flex-end;
}

/* 남의 글은 기본값(flex-start)이 곧 정답이다. 규칙을 적어 두는 이유는 **대칭이 의도라는 사실**을
   이 파일만 읽어도 알 수 있게 하기 위해서다 — 위 mine 규칙만 있으면 반대쪽은 우연처럼 보인다. */
.otd-msg.theirs .otd-foot[b-vy2jjdamk1] {
    justify-content: flex-start;
}

.otd-time[b-vy2jjdamk1] {
    flex: 0 0 auto;
    font-size: 0.68rem;
    /* 원본은 #94a3b8(2.56:1). 시각은 **글자**이므로 AA 를 지켜야 한다 → --ope-ink-2 로 7.57:1.
       원본에서 이 값이 통했던 건 그쪽이 흐르는 실시간 로그라 놓쳐도 되는 층이기 때문이고,
       여기서는 "언제 결정됐나"가 며칠 뒤에 읽히는 기록이다(항목 14와 같은 방향). */
    color: var(--ope-ink-2);
    font-variant-numeric: tabular-nums;
}

/* 아바타 — 이니셜 원. 규격은 원본 `.tl-avatar` 와 같다(28px, 원형, 흰 글자 800).
   `margin-top` 은 이름 줄 높이만큼 내려 말풍선과 눈높이를 맞추는 값이다(원본 16px → 이름 폰트가 조금 작아 15px). */
.otd-avatar[b-vy2jjdamk1] {
    flex-shrink: 0;
    width: 28px;
    height: 28px;
    margin-top: 15px;
    border-radius: 50%;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    color: #ffffff;
    font-weight: 800;
    font-size: 0.75rem;
}

/* 삭제 — 본인 글에만, **호버·포커스에서만** 나타난다(파괴적 동작을 상시 노출하지 않는다).
   `visibility` 가 아니라 `opacity` 인 이유: 자리를 계속 차지해야 나타날 때 시각이 옆으로 밀리지 않는다.
   높이 24px = 최소 타깃. */
.otd-del[b-vy2jjdamk1] {
    flex: 0 0 auto;
    height: 24px;
    padding: 0 var(--ope-s2);
    border-radius: var(--ope-r-sm);
    border: 1px solid transparent;
    background: transparent;
    font-family: inherit;
    font-size: 0.68rem;
    font-weight: 700;
    line-height: 1;
    color: var(--ope-ink-2);
    cursor: pointer;
    opacity: 0;
    transition: opacity 140ms ease-out, color 140ms ease-out, background-color 140ms ease-out, border-color 140ms ease-out;
}

.otd-msg:hover .otd-del[b-vy2jjdamk1],
.otd-del:focus-visible[b-vy2jjdamk1] {
    opacity: 1;
}

.otd-del:hover[b-vy2jjdamk1] {
    background: #fef2f2;
    border-color: #fecaca;
    color: var(--ope-bad); /* #b91c1c on #fef2f2 = 6.6:1 */
}

/* 이중 링 아웃셋판 — offset 1 → 2px(헤일로 두께와 맞춰 두 링이 겹치지 않게). */
.otd-del:focus-visible[b-vy2jjdamk1] {
    outline: 2px solid var(--ope-focus);
    outline-offset: 2px;
    box-shadow: 0 0 0 2px var(--ope-focus-halo);
}

.otd-del:disabled[b-vy2jjdamk1] {
    cursor: default;
    color: var(--ope-muted);
}

/* 호버가 없는 기기(터치)에서는 상시 노출 — 숨겨 두면 아예 누를 방법이 없다. */
@media (hover: none) {
    .otd-del[b-vy2jjdamk1] {
        opacity: 1;
    }
}

/* ── 컴포저(우측 코멘트 패널 **최하단** 고정) ──────────────────────────
   📎 배치 출처: `Components/Layout/AdminNoticeProposer.razor.css` 의 `.np-composer` / `.np-input-wrap` / `.np-send`
      — 입력칸은 알약, 전송은 **입력칸 안 오른쪽의 원형 버튼**. 값은 이 파일 토큰으로 다시 적었다(위와 같은 이유).
   자리 이력: 다이얼로그 액션 줄 → ⑯ 코멘트 패널 최상단 → **B-3 코멘트 패널 최하단(스레드 아래)**.
        정렬이 오래된 순으로 돌아가면서 "새 글이 나타나는 곳"과 "쓰는 곳"을 같은 지점에 모았다.
        고정이라는 성질은 세 배치 모두 동일하다 — 스레드만 스크롤한다.
   ⛔ MudTextField(Outlined) 를 쓰지 않는다 — 포커스에 테마 Primary 2px 테두리를 둘러
      오너 지적("보라색 두꺼운 테두리")이 나온 자리다. */
.otd-form[b-vy2jjdamk1] {
    flex: 1 1 auto;   /* .otd-side-bot 안에서 가로를 다 쓴다 */
    display: flex;
    align-items: center;
    width: 100%;
    min-width: 0;
}

.otd-in-wrap[b-vy2jjdamk1] {
    position: relative;
    flex: 1 1 auto;
    display: flex;
    align-items: center;
    min-width: 0;
}

/* 📏 2026-08-25 ⑫ 높이 정상화(오너 지적 "알약 입력칸이 과하게 높고 전송 버튼과 세로 정렬이 안 맞는다").
   진단: 예전 값은 `rows="2"` + `height:56px` 이었다. 글자는 위쪽 padding(10px)부터 **첫 줄에** 놓이는데
        전송 버튼은 상자 **세로 중앙**(top:50%)에 떠 있었다 → 한 줄만 쳤을 때 글자와 버튼이 약 10px 어긋났다.
        "정렬이 안 맞는다"의 원인은 버튼 위치가 아니라 **상자가 두 줄 높이였다는 것**이다.
   해법(수치):
     · 한 줄 계산 — 글자 0.84rem = 13.44px · line-height 1.5 → 줄 상자 **20.16px**.
       위아래 padding 9px + 테두리 1px씩 = 20.16 + 18 + 2 = **40.16px** → `min-height: 40px`.
       라운드는 40px 상자의 정확한 알약값 **20px**(예전과 같은 값이라 생김새가 유지된다).
     · 전송 버튼 36 → **32px**. 40px 상자 안에서 위아래 4px씩 남는다(36px 이면 여백이 0이라 꽉 낀다).
       WCAG 2.2 SC 2.5.8 최소 24px 를 8px 여유로 넘는다. 아이콘은 18px 그대로.
     · 버튼을 `top:50%`(중앙 고정) → **`bottom:4px`(바닥 고정)**. 한 줄일 때는 4 + 32 + 4 = 40 이라
       **정확히 세로 중앙**이고, 여러 줄로 늘어나면 마지막 줄 옆에 남는다(메신저 컴포저의 표준 거동).
     · 오른쪽 padding = 4(여백) + 32(버튼) + 6(글자와의 간격) + 4 = **46px**.
   ⬆️ 여러 줄 확장: `field-sizing: content` (Chrome 123+ / 오너 환경 Chrome on Win11). 미지원 브라우저는
      `rows="1"` + min-height 로 한 줄 높이에 머물고 내부 스크롤된다 — **깨지지 않는 열화**다.
   🧢 상한 **120px** = 5줄(20.16×5 = 100.8 + padding 18 + 테두리 2 = 120.8). 근거: 우측 패널 높이가
      68dvh(노트북 ≈522px) 기준일 때 120px 은 그 23% 다 — 컴포저가 커져도 스레드가 항상 3/4 이상 남는다.
      4줄(100px)은 붙여넣기 한 문단이 바로 잘리고, 6줄(140px)부터는 스레드가 눈에 띄게 좁아졌다. */
.otd-in[b-vy2jjdamk1] {
    flex: 1 1 auto;
    width: 100%;
    min-width: 0;
    box-sizing: border-box;
    field-sizing: content;
    min-height: 40px;
    max-height: 120px;
    padding: 9px 46px 9px var(--ope-s4);
    border: 1px solid var(--ope-line-2);
    border-radius: 20px; /* 원본 `.vp-input` 과 같은 알약 반경 — 40px 상자의 정확한 절반 */
    background: var(--ope-surface); /* ⚠️ 틴트 패널 위에 앉으므로 흰 면이어야 입력칸으로 읽힌다 */
    color: var(--ope-ink);
    font-family: inherit;
    font-size: 0.84rem;
    font-weight: 500;
    line-height: 1.5;
    resize: none;
    overflow: auto;
    overflow-wrap: anywhere;
    transition: border-color 150ms ease-out, background-color 150ms ease-out;
}

.otd-in[b-vy2jjdamk1]::placeholder {
    color: var(--ope-muted);
    font-weight: 500;
}

.otd-in:hover:not(:disabled)[b-vy2jjdamk1] {
    border-color: #94a3b8;
}

/* 포커스 링 = 편집기·보드와 같은 이중 링(오너 지시 15③ "포커스 링도 편집기 토큰과 통일"의 연장).
   ℹ️ 여기만 `:focus` 도 함께 받는다 — **텍스트 입력**은 마우스로 눌러 들어와도 커서 위치를 알려 줘야 하기 때문이다.
      버튼류는 전부 `:focus-visible` 전용이라 마우스 클릭에는 링이 뜨지 않는다(이 차이는 의도적이다). */
.otd-in:focus-visible[b-vy2jjdamk1],
.otd-in:focus[b-vy2jjdamk1] {
    outline: 2px solid var(--ope-focus);
    outline-offset: 2px;
    box-shadow: 0 0 0 2px var(--ope-focus-halo);
    border-color: var(--ope-focus);
    background: var(--ope-surface);
}

.otd-in:disabled[b-vy2jjdamk1] {
    color: var(--ope-ink-2);
    cursor: default;
}

/* 전송 — 원형 채움 버튼. 색은 이 창의 채움면 토큰(--ope-accent #1565c0, 흰 아이콘 5.75:1).
   원본은 테마 primary 를 썼지만 여기서는 편집기 계열의 파랑으로 통일한다(위 포커스 링과 같은 판단). */
.otd-send[b-vy2jjdamk1] {
    position: absolute;
    right: 4px;
    /* 바닥 고정 — 한 줄(40px)일 때 4+32+4 이라 **정확히 세로 중앙**, 여러 줄로 늘면 마지막 줄 옆에 남는다.
       예전 `top:50%; transform:translateY(-50%)` 은 상자가 커질수록 글자와 어긋났다(위 .otd-in 주석 참조). */
    bottom: 4px;
    width: 32px;
    height: 32px;
    padding: 0;
    border: none;
    border-radius: 50%;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: var(--ope-accent);
    color: #ffffff;
    cursor: pointer;
    transition: opacity 150ms ease-out, transform 150ms ease-out, background-color 150ms ease-out;
}

.otd-send[b-vy2jjdamk1]  .mud-icon-root {
    width: 18px;
    height: 18px;
    font-size: 18px;
}

.otd-send:hover:not(:disabled)[b-vy2jjdamk1] {
    background: #0d4f9c;
    transform: scale(1.06);
}

.otd-send:disabled[b-vy2jjdamk1] {
    opacity: 0.35;
    cursor: default;
}

.otd-send:focus-visible[b-vy2jjdamk1] {
    outline: 2px solid var(--ope-focus);
    outline-offset: 2px;
    box-shadow: 0 0 0 2px var(--ope-focus-halo);
}

.otd-noperm[b-vy2jjdamk1] {
    font-size: 0.78rem;
    font-weight: 700;
    color: var(--ope-ink-2);
}

@media (prefers-reduced-motion: reduce) {
    .otd-del[b-vy2jjdamk1],
    .otd-in[b-vy2jjdamk1],
    .otd-send[b-vy2jjdamk1] {
        transition: none;
    }

    .otd-send:hover:not(:disabled)[b-vy2jjdamk1] {
        transform: none;
    }
}

/* ── 좁은 화면: 세로로 접는다(좌 → 우 순) ───────────────────────────────
   📐 분기점 **860px**. 근거: 우측 열은 6:4 의 40% 다 → 우측 콘텐츠 폭 = 0.4×W − 32(패딩) − 1(헤어라인).
      말풍선은 그 82% 이므로, 아바타(28) + gap(8) + 이름 줄까지 낀 남의 글이 답답해지지 않는 하한을
      말풍선 **280px** 로 잡으면 필요한 W = (280/0.82 + 33)/0.4 ≈ **937px**… 는 다이얼로그 폭 기준이 아니라
      뷰포트 기준이라, 다이얼로그가 Medium(960px) 캡에 걸리는 구간(뷰포트 ≥ 992px)에서는 항상 충족된다.
      뷰포트가 좁아져 다이얼로그가 100% 폭으로 줄어들기 시작하는 지점부터가 문제이며,
      그 지점에서 우측 콘텐츠가 300px 밑으로 떨어지는 뷰포트 폭이 **≈860px** 이다
      (0.4×860 − 33 = 311px, 여기서 더 좁아지면 300 미만). 그래서 860px 에서 스택으로 전환한다.
   ⚠️ 접히면 **높이 고정을 푼다** — 두 열이 세로로 이어지므로 각자 스크롤할 이유가 없고,
      바깥 `.dlg-scroll` 한 개의 스크롤로 돌려준다(스크롤러가 셋이 되는 것을 막는다).
   ✅ 컴포저는 여전히 `.otd-side` 안(코멘트 영역 **최하단**)이다 — 마크업이 그대로라 자동으로 지켜진다.
   ℹ️ 이 구간에서는 스레드가 스크롤러가 아니므로 `scrollToBottom('otd-thread')` 는 **아무 일도 하지 않는다**
      (`scrollHeight - clientHeight <= 0` 가드). 문서가 통째로 스크롤되는 화면에서 강제로 바닥까지 끌어내리면
      제목·정보까지 시야 밖으로 밀려 나가므로, 그렇게 하지 않는 편이 옳다. */
@media (max-width: 860px) {
    .dlg-scroll.otd-shell[b-vy2jjdamk1] {
        height: auto;
        min-height: 0;
        max-height: none;
        overflow: auto;
    }

    /* 한 열로 접으면 위의 **명시 배치를 전부 푼다** — 그래야 세 블록이 DOM 순서대로 쌓인다:
       제목 줄 → 정보·상세내용 → 코멘트. (풀지 않으면 `.otd-side` 가 `grid-row:1/-1` 로 제목 줄과
       같은 칸에 겹쳐 앉는다.) */
    .otd-split[b-vy2jjdamk1] {
        grid-template-columns: minmax(0, 1fr);
        grid-template-rows: none;
    }

    .otd-main[b-vy2jjdamk1],
    .otd-side[b-vy2jjdamk1] {
        grid-column: auto;
        grid-row: auto;
    }

    /* 코멘트 단독 모드에는 위에서 내려올 열이 없다 → 경계선도 필요 없다. */
    .otd-split.solo .otd-side[b-vy2jjdamk1] {
        border-top: none;
    }

    .otd-main[b-vy2jjdamk1],
    .otd-thread[b-vy2jjdamk1] {
        overflow: visible;
    }

    /* 세로로 이어지면 왼쪽 헤어라인은 방향이 어긋난다 → 위쪽 경계선으로 돌린다. */
    .otd-side[b-vy2jjdamk1] {
        border-left: none;
        border-top: 1px solid var(--ope-line);
    }

    /* ⛔ 이 구간의 좌우 정렬 되돌리기 규칙 **삭제**(2026-08-25) — base 가 이미 `center` 이고
       스트럿 자체가 사라져 되돌릴 것이 없다. 머리의 밑줄은 이 구간에서도 그대로 유지된다. */
}

@media (max-width: 720px) {
    .otd-msg[b-vy2jjdamk1] {
        max-width: 92%;
    }
}

/* ── 코멘트 스레드의 **날짜**(2026-08-25 오너 지시 "댓글은 날짜별로") ─────────────
   우측 머리 오른쪽 끝에 붙는 작은 날짜. 스레드가 날짜별로 갈리므로 "지금 어느 날의 대화인가"를
   이 한 줄이 책임진다(좌측 열은 게시물 **기간 전체**를 말하기 때문에 대신할 수 없다).
   📐 크기·굵기를 `.otd-n`(코멘트 수)보다 한 단계 낮췄다 — 제목 층은 조용해야 하고,
      이 값은 '읽는 정보'가 아니라 '지금 위치'라 눈에 먼저 들어오면 안 된다.
   ⚠️ font-size 0.7rem × 기본 line-height 로 line box 가 22.85px(스트럿) 안에 들어간다
      → 머리 높이가 변하지 않는다 = 좌·우 밑줄이 같은 y 에 그대로 선다(§머리의 계산 유지).
   ℹ️ `margin-left:auto` 라 `.otd-sec-h` 의 gap 과 무관하게 오른쪽 끝으로 밀린다. */
.otd-day[b-vy2jjdamk1] {
    flex: 0 0 auto;
    margin-left: auto;
    font-variant-numeric: tabular-nums;
    font-size: 0.7rem;
    font-weight: 700;
    letter-spacing: 0.01em;
    color: var(--ope-ink-2);
    white-space: nowrap;
}
/* /Components/Pages/Manager/Dashboard/OpsTaskEditor.razor.rz.scp.css */
/* 운영 보드 수동 카드(할 일·일정) 편집 다이얼로그 — 스코프 CSS(전역 오염 금지).

   2026-08-25 디자인 전면 리뉴얼. 이 파일이 지키는 것:
     1) **치수는 토큰으로만.** 36px 같은 맨 숫자를 다시 심지 않는다(직전 작업에서 걷어낸 부채).
        4의 배수 스케일(--ope-s1..s5) + 컨트롤 높이 1종(--ope-ctl) + 에디터 최소높이 1개(--ope-ed-min) 만 쓴다.
     2) **형제 편집기(`OpsProgramEditor.razor.css`)와 같은 토큰·같은 수치.** 스코프 CSS 는 파일 간 공유가
        불가능하므로 규격을 복제하되 값은 전부 토큰으로 둔다 — 한쪽만 보고도 같은 수치임이 확인된다.
     3) **상태 색은 보드와 같은 이름·같은 값**(st-plan/st-prog/st-done/st-hold/st-tent = OpsBoard 의 .ob-stsel.st-*).
        편집기에서 고른 상태가 보드에서 다른 색으로 보이면 두 화면이 다른 시스템이 된다.
     4) 대비 실측치를 주석에 남긴다 — 회색 위 회색이 다시 기어들지 않게.

   ⚠️ 전역 `app.css` 의 `.mud-input-control-input-container{margin-top:5px!important}` 가 모든 Mud 입력에
      똑같이 걸리므로, **입력을 전부 Mud 로 통일**해야 한 줄 안에서 높이가 어긋나지 않는다.
      (자체 컨트롤은 세그먼트·칩뿐이고, 둘 다 자기 라벨을 따로 세워 Mud 부동 라벨과 섞이지 않는다.)

   2026-08-24 → 2026-08-25 에 버린 것:
     · `.ops-typebar` 의 스위치 + 양옆 라벨 → 세그먼트 1개. 비활성 라벨 #94a3b8(2.56:1, WCAG 미달)이 함께 사라졌다.
     · `.ops-hr` 점선 구분 → 섹션 제목 + 실선.
     · `.dlg-scroll{background:#fff}` → razor 의 `ContentStyle` 회색 인라인과 **한 쌍으로 함께** 제거.
       서로를 상쇄하던 코드였다(전역 `.dialog-background-surface` 가 이미 흰 바닥을 준다). */

/* ── 토큰 ─────────────────────────────────────────────────────────────────
   ⚠️ 선언 위치가 둘인 이유: `.ope-head` 는 `.dlg-scroll`(그 안에 `.ope-form`)의 **형제**라
      `.ope-form` 에만 선언하면 커스텀 속성이 헤더에 상속되지 않는다. 값은 한 벌, 선언만 두 뿌리.
      (2026-08-25 카드 타입 띠 `.ope-typebar` 가 폼 안으로 들어가면서 세 뿌리 → 두 뿌리가 됐다.)
   색 어휘는 운영 보드(.ob-root)와 같다 — 보드와 편집기가 한 시스템으로 읽히게. */
.ope-head[b-mo6ozpnadn],
.dlg-scroll[b-mo6ozpnadn],
.ope-tabs[b-mo6ozpnadn],
.ope-form[b-mo6ozpnadn] {
    --ope-ink: #0f172a; /* 흰 배경 대비 17.9:1 */
    --ope-ink-2: #475569; /* 비활성 세그먼트·칩 라벨 · 7.57:1 */
    --ope-muted: #64748b; /* 보조 설명 · 4.76:1 */
    --ope-line: #e2e8f0;
    --ope-line-2: #cbd5e1;
    --ope-tint: #f1f5f9;
    --ope-surface: #ffffff;
    --ope-accent: #1565c0; /* 채워진 면 + 흰 글자 = 5.75:1 (보드의 #1e88e5 는 3.39:1 이라 텍스트엔 부족) */
    --ope-ring: #1e88e5; /* 테두리·구조선 전용. ⚠️ 2026-08-25 포커스 링에서 제외 → --ope-focus */
    /* 🎯 포커스 링 = 이중 링(밝은 헤일로 + 어두운 링). 근거·실측 대비값은 OpsBoard.razor.css 의 --ob-focus 주석 참조.
       편집기는 배경이 흰 면이라 단색으로도 되지만 **한 화면 안에서 포커스 표현이 갈리면 안 되므로**
       보드(임의 카드색 위)와 같은 방식·같은 색을 쓴다. ⛔ border 로 그리지 말 것(박스가 커진다). */
    --ope-focus: #0d47a1;
    --ope-focus-halo: #ffffff;
    --ope-bad: #b91c1c; /* 오류 문구 · 7.0:1 */
    --ope-s1: 4px;
    --ope-s2: 8px;
    --ope-s3: 12px;
    --ope-s4: 16px;
    --ope-s5: 24px;
    --ope-ctl: 30px;
    --ope-r: 8px;
    --ope-r-sm: 6px;
    /* 상세내용 에디터의 최소 높이 = 공용 래퍼가 인라인으로 주는 값(`min-height:450px`)과 **같은 값**.
       🔄 2026-08-25 오너 지시로 **300 → 450 원복**("이미지 하나만 넣어도 스크롤이 생긴다").
          앞서 450 → 300 으로 내렸던 근거는 "Small 다이얼로그에서 푸터가 밀린다"였으나,
          본문은 `.dlg-scroll{flex:1 1 auto; min-height:0; overflow:auto}` 안에서 스크롤되고
          푸터(DialogActions)는 그 밖이라 밀리지 않는다 — 세로가 길어지면 본문이 스크롤될 뿐이다.
       ⚠️ 다이얼로그 폭(MaxWidth)은 오너 확정값이라 **건드리지 않는다.** 높이만 바뀐다. */
    --ope-ed-min: 450px;

    /* 🔄 2026-08-25 오너 지시 "다이얼로그 기본 높이를 더 높여라(폭은 유지)".

       🔴 **1차 시도 실패 기록 — `min-height` 로는 안 된다(오너: "수정창 높이는 변경이 안되었어").**
          처음엔 `.dlg-scroll { min-height: 510px }` 을 줬다. 선택자는 정확히 맞았고(생성 코드 실측:
          `<div class="dlg-scroll">` 에 `b-mo6ozpnadn` 이 붙고, `.dlg-scroll[b-…]`(0,2,0)가 전역
          `.dlg-scroll`(0,1,0)의 `min-height:0` 을 이긴다) — **그런데도 화면이 그대로였다.**
          이유는 CSS 가 아니라 산수다: `min-height` 는 **바닥값**이라 내용이 그보다 **짧을 때만** 상자를 키운다.
          기본으로 열리는 `정보` 탭은 두 탭 중 **더 긴 쪽**(섹션 3개 + 색 팔레트 2줄)이라 이미 510px 을 넘었고,
          따라서 바닥값은 한 번도 발동하지 않았다 → 정확히 "아무 변화 없음".
       ✅ **`OpsTaskDetail` 과의 차이가 곧 답이었다.** 그쪽은 같은 자리에 `height`(확정값)를 줬고 그래서 먹혔다.
          → 여기도 **확정 높이**로 바꾼다. 내용이 더 길면 예전처럼 이 안에서 스크롤되고(전역 `overflow:auto` 유지),
            짧으면 창이 이 높이를 유지한다 → **탭을 오갈 때 창이 출렁이지 않는다**(이 지시의 실질).

       📐 값 정책은 상세창(`OpsTaskDetail`)과 **같은 형태**로 맞췄다 — 두 창이 한 시스템으로 읽히게.
          다만 빼는 값이 다르다: 이 창에는 **푸터(DialogActions)가 있다.**
            타이틀바 ≈56 + 푸터 ≈80(버튼 48 + pa-4 상하 32) = **136**
            + MudBlazor 다이얼로그 상한 여유 64(`max-height: calc(100% - 64px)`) + 슬랙 16 = **216px**
          실측 계산(창 총높이 = 이 값 + 136):
            · 768px 노트북 : min(583, 760, 552) = **552** → 688 < 704 ✓ (여유 16px)
            · ≈937px(1080p): min(712, 760, 721) = **712** → 848 < 873 ✓
            · 600px 저해상도: min(456, 760, 384) = **384** → 520 < 536 ✓ (스스로 내려간다)
          🔒 `calc(100dvh - 216px)` 항이 넘침 방지의 본체다 — 비율·캡을 올려도 이 항이 뷰포트 안으로 자른다.
       ⚠️ 다이얼로그 폭(MaxWidth)은 오너 확정값이라 **건드리지 않는다.** 높이만 바뀐다. */
    --ope-dlg-h: min(76dvh, 760px, calc(100dvh - 216px));
    /* 아래로는 이만큼까지만 줄어든다(상세창의 `min-height: 340px` 과 같은 관례).
       이보다 짧은 뷰포트에서는 다이얼로그 자신의 스크롤이 받아 준다 — 푸터가 사라지지 않는다. */
    --ope-dlg-floor: 340px;

    /* 탭 띠를 창 폭 끝까지 빼기 위한 상쇄값 = 전역 `app.css` 의 `.dlg-scroll{padding:10px 20px 20px}`.
       ⚠️ 그 전역이 바뀌면 이 두 값도 함께 바뀌어야 한다 — 그래서 맨 숫자를 이름으로 묶어 둔다. */
    --ope-bleed-x: 20px;
    --ope-bleed-t: 10px;

    /* 폼 **꼬리 여백**(2026-08-26 오너 지시 "카드색 하단에 여백이 너무 좁아. 여유있게 하단 여백을 추가해줘").
       📐 48px = s5(24)의 **2배**. 이 창의 섹션 사이 간격이 s4(16)이므로 16·24 로는
          "다음 섹션이 오려다 만 자리"로 읽히고 **끝으로 읽히지 않는다.** 3배(48)라야 꼬리가 된다.
          같은 판단으로 상세 창의 `--otd-note-tail` 도 48px 이다 — 두 창이 같은 어휘를 쓴다.
       ⛔ 새 홀수 px 를 만들지 않았다(기존 눈금의 배수). */
    --ope-form-tail: calc(var(--ope-s5) * 2);   /* = 48px */
}

/* ── 타이틀바 ────────────────────────────────────────────────────────────
   증상: 다이얼로그가 좁아지면 X(닫기)가 아랫줄로 내려간다.
   원인: 전역 app.css 의 `.dialog-title{flex-wrap:wrap}` + `@media(max-width:720px){.dialog-title-right{flex-basis:100%}}`.
   ⛔ 전역을 고치면 Manager 의 **모든 다이얼로그**가 영향을 받으므로 이 화면에서만 무력화한다
      (`::deep` 은 스코프 속성이 붙은 HTML 요소를 기점으로만 걸린다 → 감싸는 div 가 반드시 필요하다).
   규칙: 줄바꿈 금지 · **줄어드는 쪽은 제목**(TID 버튼 포함) · 오른쪽 버튼 묶음은 축소 금지. */
.ope-head[b-mo6ozpnadn]  .dialog-title {
    flex-wrap: nowrap;
    column-gap: var(--ope-s2);
}

.ope-head[b-mo6ozpnadn]  .dialog-title-left {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    white-space: nowrap; /* 제목이 길면 잘린다 — 버튼을 밀어내지 않는 쪽을 택했다 */
}

.ope-head[b-mo6ozpnadn]  .dialog-title-right {
    flex: 0 0 auto; /* @media 의 flex-basis:100% 를 덮는다 = 아랫줄로 안 내려간다 */
    flex-basis: auto;
    flex-wrap: nowrap;
}

/* ⛔ `.ope-head ::deep .tid-btn` 규칙 **삭제**(2026-08-25) — 오너 지시로 헤더에서 ID 복사 버튼을
   걷어내면서(이 화면은 `TID` 를 DialogHeader 에 넘기지 않는다) 그 버튼이 DOM 에 없어졌다.
   ⚠️ 위 `.dialog-title-*` 3규칙은 **그대로 둔다** — 제목이 길 때의 줄바꿈 방어는 ID 버튼과 무관하다. */

/* ⛔ `.ope-typebar` 규칙 **삭제**(2026-08-25 오너 지시) — 카드 타입 선택이 헤더 아래 띠에서
   폼 안 '상태' 바로 위로 내려가면서 그 컨테이너 자체가 사라졌다. 지금은 `.ope-field` 안의
   `.ope-seg.half` 하나뿐이라 배경·경계선을 따로 그릴 이유가 없다(아래 §세그먼트 참조). */

/* ── 탭(정보 / 상세내용) ─────────────────────────────────────────────────
   2026-08-25 신설. **이 다이얼로그에는 가로 버튼 줄이 둘**이다 —
   창을 가르는 탭(정보/상세내용)과, 폼 안에서 값을 고르는 세그먼트(할 일/일정).
   둘이 같은 무게로 보이면 어느 쪽이 상위인지 읽히지 않는다 → 형태를 정반대로 갈랐다:

     · 폭       탭 = 창 폭 전체(스크롤 영역 패딩 밖까지)   / 세그먼트 = 폼 안 50%
     · 경계     탭 = 창을 가로지르는 헤어라인 하나          / 세그먼트 = 사방을 두른 둥근 상자
     · 선택     탭 = 밑줄 2px + 잉크색 + 800                / 세그먼트 = 파란 면 채움
     · 높이     탭 = 44px                                   / 세그먼트 = 30px(--ope-ctl)
     · 글자     탭 = 0.86rem · 자간 0.03em                  / 세그먼트 = 0.8rem · 자간 0
     · 스크롤   탭 = 맨 위에 고정(sticky)                   / 세그먼트 = 본문과 함께 흐른다
   결과: 탭은 **창을 가르는 선**, 세그먼트는 **폼 안의 상자**로 읽힌다.
   면(배경)으로 층을 가르지 않는다 — 2026-08-25 오너 지시 "상단 탭 배경색은 제거해".
   ⚠️ 그래도 배경은 **투명이 아니라 흰색(--ope-surface)** 이어야 한다: 이 띠는 sticky 라
      투명이면 스크롤된 본문이 탭 글자 뒤로 비쳐 지나간다. 흰색 = 다이얼로그 바탕과 같은 색이라
      화면에서는 "배경색이 없는" 것으로 보이고, 겹침만 막힌다.

   ⚠️ `::deep` 필수 — MudTabs 는 자식 컴포넌트라 이 파일의 스코프 속성이 그 DOM 에 붙지 않는다.
      그래서 MudTabs 에 `Class` 를 주는 대신 **내가 그리는 div(.ope-tabs)** 로 감쌌다.
   대비 실측: 비활성 #475569 on #ffffff = 7.57:1 · 활성 #0f172a on #ffffff = 17.9:1 ·
             밑줄 #1565c0 on #ffffff = 5.75:1(비텍스트 최소 3:1 을 넘는다).
   ⚖️ 배경이 사라졌으므로 **선택 표시는 셋이 함께** 진다: 밑줄 2px + 잉크색(7.57 → 17.9:1) + 굵기(700 → 800).
      하나만으로 판정하지 않게 한 것은 색각 이상·저대비 화면에서도 현재 탭이 읽히게 하기 위해서다. */
/* 🔗 2026-08-25 — 아래 세 규칙의 `flex`/`min-height:0` 은 **상세내용 에디터를 바닥까지 늘리기 위한 사슬**이다.
   세로 신축은 조상이 하나라도 끊기면(높이가 내용 기반이 되면) 즉시 죽으므로, `.dlg-scroll`(확정 높이) 부터
   에디터까지 한 줄로 이어 놓는다. 전체 사슬·수치는 §상세내용 에디터 주석 참조.
   ⚖️ `정보` 탭은 영향받지 않는다 — 늘어나는 것은 `.ope-form.ed` 뿐이고, 이 층들은 `정보` 탭에서도
      **컨테이너 높이와 같아질 뿐**이라 내용이 더 길면 예전처럼 `.dlg-scroll` 이 스크롤한다. */
.ope-tabs[b-mo6ozpnadn] {
    min-width: 0;
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
    min-height: 0;
}

/* sticky 는 조상 중 하나라도 overflow 를 자르면 죽는다 → 탭 뿌리는 열어 둔다.
   같은 이유로 razor 에서 `Rounded` 를 켜지 않는다(Mud 가 .mud-tabs-rounded 에 overflow:hidden 을 건다).
   ℹ️ `.mud-tabs` 는 Mud 기본이 이미 `display:flex; flex-direction:column` 이라 방향은 다시 쓰지 않는다. */
.ope-tabs[b-mo6ozpnadn]  .mud-tabs {
    overflow: visible;
    flex: 1 1 auto;
    min-height: 0;
}

.ope-tabs[b-mo6ozpnadn]  .mud-tabs-tabbar {
    position: sticky;
    /* 🔴 `top: 0` 이 아니다. sticky 의 기준 사각형은 스크롤 컨테이너의 **콘텐츠 상자**라
       `0` 으로 두면 `.dlg-scroll` 의 padding-top(10px) 만큼 아래에 붙고, **그 10px 틈으로
       스크롤된 본문이 탭 위를 지나간다**(실측: 상태 칩이 탭 라벨 위에 유령처럼 찍혔다).
       패딩만큼 끌어올려 창의 실제 위 끝에 붙인다 — 아래 margin-top 의 상쇄값과 같은 수치다. */
    top: calc(var(--ope-bleed-t) * -1);
    z-index: 3;
    /* 창 폭 끝까지 — .dlg-scroll 의 패딩을 정확히 상쇄한다(§토큰 --ope-bleed-*).
       ⛔ 좌우 padding 을 주지 않는다: Mud 가 밑줄(.mud-tab-slider) 위치를 탭의 실측 오프셋으로
          계산하므로 안쪽 여백이 생기면 밑줄이 그만큼 어긋난다. */
    margin: calc(var(--ope-bleed-t) * -1) calc(var(--ope-bleed-x) * -1) var(--ope-s2);
    /* 색 면이 아니라 **바탕과 같은 흰색** — 위 주석 참조(sticky 겹침 방지용이지 장식이 아니다).
       Mud 는 `.mud-tabs-tabbar` 에 surface 색을, ApplyEffectsToContainer 로 패널에도 색을 얹으므로
       여기서 명시적으로 되돌린다(생성 CSS 에서 확인함). */
    background: var(--ope-surface);
    border-bottom: 1px solid var(--ope-line);
    border-radius: 0;
    box-shadow: none;
}

.ope-tabs[b-mo6ozpnadn]  .mud-tabs-tabbar-inner {
    min-height: 44px;
}

/* 탭 하나가 창의 **절반**을 갖는다 — 오너 지시 "각 탭 메뉴는 좌우 넓이를 충분히 확보".
   Mud 기본값(min-width:160px · width:100% · flex-shrink:0)을 여기서 전부 되돌린다:
   그대로 두면 두 칸이 창을 넘겨 스크롤 화살표가 붙고 폭이 흔들린다. */
.ope-tabs[b-mo6ozpnadn]  .mud-tab {
    flex: 1 1 0;
    width: auto;
    min-width: 0;
    max-width: none;
    min-height: 44px;
    padding: 0 var(--ope-s4);
    border-radius: 0;
    background-color: transparent;
    color: var(--ope-ink-2);
    font-family: inherit;
    /* 세그먼트(0.8rem/700/자간0)보다 한 눈금 크고 넓다 — 배경을 걷어낸 뒤 층을 지탱하는 것은
       면이 아니라 **활자와 폭**이다. */
    font-size: 0.86rem;
    font-weight: 700;
    letter-spacing: 0.03em;
    text-transform: none; /* Mud 기본 uppercase 해제 */
}

/* 호버는 **글자만** 진해진다 — 면을 칠하면 방금 걷어낸 배경이 호버 때마다 되살아난다. */
.ope-tabs[b-mo6ozpnadn]  .mud-tab:hover:not(.mud-tab-active) {
    background-color: transparent;
    color: var(--ope-ink);
}

/* 활성 탭은 **면을 칠하지 않는다**(오너 지시). 표시는 잉크색 + 굵기 + 아래 밑줄 2px 셋이 함께 진다.
   세그먼트가 '면을 채워' 고른 값을 말하는 것과 정확히 반대다 — 두 컨트롤이 같은 방식으로 말하지 않는다. */
.ope-tabs[b-mo6ozpnadn]  .mud-tab.mud-tab-active {
    background-color: transparent;
    color: var(--ope-ink);
    font-weight: 800;
}

/* Mud 의 `@media(hover:fine)` 규칙(primary-hover)을 이기려면 :hover 까지 같이 눌러야 한다. */
.ope-tabs[b-mo6ozpnadn]  .mud-tab.mud-tab-active:hover {
    background-color: transparent;
}

.ope-tabs[b-mo6ozpnadn]  .mud-tab:focus-visible {
    outline: 2px solid var(--ope-focus);
    outline-offset: -2px;
    box-shadow: inset 0 0 0 4px var(--ope-focus-halo);
}

.ope-tabs[b-mo6ozpnadn]  .mud-tab-slider {
    background: var(--ope-accent);
}

/* 두 칸이 정확히 창을 채우므로 넘칠 일이 없다 — 화살표가 잠깐이라도 나타나면 탭 폭이 흔들린다. */
.ope-tabs[b-mo6ozpnadn]  .mud-tabs-scroll-button {
    display: none;
}

.ope-tabs[b-mo6ozpnadn]  .mud-tabs-panels {
    background: transparent;
}

/* 사슬 계속 — 패널 컨테이너와 **활성 패널**이 남은 높이를 갖는다.
   ⚠️ Mud 는 활성 패널에 `display:contents`(MudBlazor.css: `.mud-tabs-panels>.mud-tab-panel.mud-tab-panel-active
      :not(.mud-tab-panel-hidden){display:contents}`)를 건다. 그 상태로도 자식이 flex 아이템이 되긴 하지만
      **명시적으로 flex 상자로 되돌린다** — `display:contents` 는 상자가 사라지는 값이라 여기에 높이 계산을
      기대면 Mud 가 이 규칙을 바꾸는 날 조용히 깨진다. 우리 쪽 특이도(0,5,0)가 Mud(0,4,0)보다 높아 이긴다.
   ⛔ 비활성 패널은 `display:none` 그대로다(위 선택자에 `.mud-tab-panel-active` 가 들어 있다) —
      `KeepPanelsAlive` 로 살아 있는 반대쪽 탭이 자리를 먹지 않는다. */
.ope-tabs[b-mo6ozpnadn]  .mud-tabs-panels,
.ope-tabs[b-mo6ozpnadn]  .mud-tabs-panels > .mud-tab-panel.mud-tab-panel-active {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
    min-height: 0;
}

/* ── 본문 스크롤 영역의 **확정 높이**(2026-08-25 오너 지시) ─────────────────
   전역 `app.css:116` 의 `.dlg-scroll{padding:10px 20px 20px; flex:1 1 auto; min-height:0; overflow:auto}` 에서
   **높이만** 이 창 한정으로 덮는다. padding·flex·overflow·scrollbar-gutter 는 전역 그대로 둔다.
   · `height` 다 — `min-height` 로는 먹지 않았다(위 토큰 주석의 실패 기록 참조). 확정값이라 항상 적용된다.
   · `min-height` 는 **줄어드는 하한**으로만 남긴다. 전역의 `min-height:0`(= 얼마든지 줄어든다)을 덮어
     낮은 해상도에서 이 요소가 0 까지 눌리는 것을 막는다.
   · flex 관점: 부모(`.dlg-content-flex`)가 세로 flex 이고 이 요소는 `flex:1 1 auto` 다 →
     basis(auto)가 `height` 값을 쓰므로 컨테이너가 그만큼 자란다. 바깥이 상한에 걸리면 shrink 로 줄어들고
     그 하한이 `--ope-dlg-floor` 다. **푸터(DialogActions)가 밖으로 밀리지 않는다.**
   · 내용이 이 높이보다 길면 예전과 똑같이 **여기서 스크롤**된다(상한을 만든 것이 아니다).
     탭바의 `position:sticky` 도 이 요소가 스크롤 포트라서 그대로 작동한다(오히려 더 확실해진다).
   ⛔ 폭은 한 줄도 건드리지 않았다 — `MaxWidth` 는 오너 확정값이다.
   🔗 2026-08-25 `display:flex` 추가 — **높이 자체는 한 글자도 바뀌지 않았다.**
      이 요소는 이미 확정 높이를 갖고 있었지만 자식(`.ope-tabs`)이 그 높이를 **물려받을 방법이 없었다**
      (블록 흐름에서는 높이가 위에서 아래로 전해지지 않는다). 세로 flex 로 바꾸면 자식이 `flex:1 1 auto` 로
      남은 높이를 정확히 받아 간다 → 상세내용 에디터를 바닥까지 늘리는 사슬의 **출발점**이다.
      ⚖️ 두 탭 모두에 걸리지만 `정보` 탭의 화면은 그대로다: `.ope-form`(수식 클래스 없음)은 늘어나지 않고
         `flex-shrink` 도 자동 최소 크기(min-content) 아래로는 못 내려가므로, 내용이 길면 예전처럼 여기서 스크롤된다. */
.dlg-scroll[b-mo6ozpnadn] {
    height: var(--ope-dlg-h);
    min-height: var(--ope-dlg-floor);
    display: flex;
    flex-direction: column;
}

/* ── 본문 ────────────────────────────────────────────────────────────────
   ⚠️ 본문 스크롤은 `.dlg-scroll{flex:1 1 auto; min-height:0; overflow:auto}` +
      `.dlg-content-flex{overflow:hidden}`(app.css)가 이미 잡아 준다 → 여기서 높이를 다시 만들지 않는다. */
/* 📏 여백 한 단계 축소(2026-08-25 오너 지시 "폼들의 상하 여백을 좁혀줘. 너무 벌어져 있어").
   4배수 스케일 위에서 **각 층을 정확히 한 칸씩** 내렸다 — 새 수치를 발명하지 않았다:
     · 섹션 사이   s5(24) → s4(16)   ← 여기
     · 섹션 안 필드 s4(16) → s3(12)   ← .ope-sec
     · 격자 칸 사이 s4(16) → s3(12)   ← .ope-row (필드 사이와 같은 눈금을 유지)
     · 라벨–컨트롤 s2(8)  → s1(4)    ← .ope-field
   ⚖️ 층 간 대비(섹션 > 필드 > 라벨)는 그대로다 — 리듬을 유지한 채 전체만 한 칸 조인 것이다.
   ⚠️ 보드 카드(.ob-prog.task)는 같은 날 **반대로 넓혔다**. 여긴 다이얼로그, 저긴 열 안의 카드다. */
.ope-form[b-mo6ozpnadn] {
    display: flex;
    flex-direction: column;
    gap: var(--ope-s4);
    /* 상단 여백 s2(8px) **유지**. 2026-08-25 에 위쪽 층이 또 두 겹 사라졌다 —
       ①카드 타입 띠(.ope-typebar, 자체 배경·바닥선)가 폼 안으로 내려갔고 ②'내용' 섹션 제목줄이 없어졌다.
       그래서 지금은 DialogHeader 의 <hr> 바로 아래에 제목 입력이 온다(전역 app.css 가 Mud 입력 컨테이너에
       margin-top:5px 를 더하므로 체감 여백은 13px).
       ⚠️ 여기를 s3 로 올리는 것은 오너 지시 범위 밖이라 손대지 않았다 — 같은 날 지시는 전부 '좁히는' 방향이었다.
          실제 화면에서 답답하면 이 한 줄만 s3 로 올리면 된다(새 수치 발명 없이 눈금 하나). */
    padding-top: var(--ope-s2);
    min-width: 0;
}

/* 🔺 폼 바닥 숨통 — 2026-08-26 오너 지시 "카드색 하단에 여백이 너무 좁아. 여유있게".
   증상: `정보` 탭의 마지막 요소(카드색 스와치 그리드 + hex 표시)가 액션 바(삭제·복제·저장하기)에 거의 붙어 있었다
         (`.ope-form` 의 padding-bottom 이 **0** 이었다).

   🎯 대상 특정 — **색 필드가 아니라 폼의 하단 패딩**이다:
      · 색 섹션은 `정보` 탭의 **마지막 요소**이지만 **항상 그런 것은 아니다** — 완료된 카드에서는
        그 아래에 `기록` 섹션(`ClosedLabel: …`)이 하나 더 붙는다. 색 필드에만 여백을 주면 그 경우
        **여백이 문단 중간에 끼어** 버린다. 폼의 꼬리에 주면 마지막이 무엇이든 항상 맞다.

   ⚖️ 적용 범위를 `:not(.ed)` 로 **`정보` 탭에만** 좁혔다:
      · `상세내용` 탭(`.ope-form.ed`)에 같은 패딩을 주면 **에디터 아래에 48px 죽은 띠**가 생겨
        3번(에디터를 바닥까지 채우는 세로 flex 사슬)이 그대로 무너진다.
      · `OpsProgramEditor` 도 `.ope-form` 을 쓰지만 **스코프 CSS 라 영향이 없다**
        (이 파일의 선택자는 `OpsTaskEditor.razor` 의 요소에만 붙는다 — 그쪽은 자기 `.razor.css` 를 갖는다).
        → 이번 변경의 영향 범위는 **이 창의 `정보` 탭 하나뿐**이다.

   📏 창 높이는 **바뀌지 않는다**: `.dlg-scroll` 이 `height: var(--ope-dlg-h)` — `min-height` 가 아니라
      **확정 높이**라 내용이 길어져도 상자가 커지지 않는다 → **탭 전환 시 창이 출렁이지 않는다.**
      내용이 그 높이를 넘으면 예전처럼 `.dlg-scroll` 안에서 스크롤될 뿐이고,
      `scrollbar-gutter: stable`(전역 app.css)이라 스크롤바가 생겨도 **가로 재배치가 없다.** */
.ope-form:not(.ed)[b-mo6ozpnadn] {
    padding-bottom: var(--ope-form-tail);
}

/* ⛔ 보드 카드 미리보기(.ope-pv / -bar / -main / -title / -meta / -when / -st / -who) **블록 삭제** —
   2026-08-25 오너 지시 "할일 등록 상단에 미리보기는 제거해".
   마크업·계산 멤버와 함께 걷어냈다. 이 파일에 .ope-pv* 셀렉터는 하나도 남아 있지 않다. */

/* ── 섹션 ──────────────────────────────────────────────────────────────── */
.ope-sec[b-mo6ozpnadn] {
    display: flex;
    flex-direction: column;
    gap: var(--ope-s3); /* 섹션 안 필드 사이 — s4(16) → s3(12), 위 .ope-form 주석의 한 칸 축소 */
    min-width: 0;
}

/* 제목 + 남은 폭을 채우는 실선 한 줄. 점선 hr 만 있던 예전 구분보다
   "여기부터 무엇" 이 먼저 읽힌다(제목 위 여백이 아래보다 크다 — 그룹은 아래로 붙는다). */
.ope-sec-h[b-mo6ozpnadn] {
    display: flex;
    align-items: center;
    gap: var(--ope-s3);
    min-width: 0;
}

.ope-sec-h[b-mo6ozpnadn]::after {
    content: "";
    flex: 1 1 auto;
    height: 1px;
    background: var(--ope-line);
}

.ope-sec-t[b-mo6ozpnadn] {
    flex: 0 0 auto;
    font-size: 0.76rem;
    font-weight: 800;
    letter-spacing: 0.04em;
    color: var(--ope-ink);
    white-space: nowrap;
}

/* ── 격자 ──────────────────────────────────────────────────────────────── */
.ope-row[b-mo6ozpnadn] {
    display: grid;
    gap: var(--ope-s3); /* s4(16) → s3(12) — 섹션 안 필드 사이와 같은 눈금 */
    min-width: 0;
}

.ope-row.full[b-mo6ozpnadn] {
    grid-template-columns: 1fr;
}

.ope-row.c2[b-mo6ozpnadn] {
    grid-template-columns: repeat(2, minmax(0, 1fr));
}

/* 📏 시작(날짜·시각)과 종료(종료일·종료 시각) 두 격자를 한 묶음으로 — 2026-08-25 오너 지시
   "`날짜`행과 `종료일`행 사이 세로 간격을 좁힌다".
   섹션 기본 간격 s3(12px) 대신 **s2(8px)**. 4배수 스케일의 이웃 값이며 새 수치가 아니다.
   ⚖️ 위계는 그대로다 — 섹션(s4) > 필드(s3) > **같은 개념의 두 줄(s2)** > 라벨–컨트롤(s1). */
.ope-dates[b-mo6ozpnadn] {
    display: flex;
    flex-direction: column;
    gap: var(--ope-s2);
    min-width: 0;
}

/* 🔴 전역 지뢰: `app.css` 의 `.mud-select{flex-grow:0!important}`.
   격자에서는 flex-grow 가 무의미하지만, Mud 가 내부에서 flex 컨테이너를 만드는 경우가 있어
   **이 컴포넌트의 격자 안에서만** 무력화한다(전역을 건드리면 다른 화면이 깨진다). */
.ope-row[b-mo6ozpnadn]  .mud-select {
    flex-grow: 1 !important;
    width: 100%;
}

/* 자체 라벨이 필요한 필드(세그먼트·칩) — Mud 부동 라벨과 같은 위계로 읽히게 크기를 맞춘다. */
.ope-field[b-mo6ozpnadn] {
    display: flex;
    flex-direction: column;
    gap: var(--ope-s1); /* 라벨–컨트롤 s2(8) → s1(4) */
    min-width: 0;
}

.ope-flabel[b-mo6ozpnadn] {
    font-size: 0.78rem;
    font-weight: 800;
    letter-spacing: 0.02em;
    color: var(--ope-ink);
}

/* ── 세그먼트 컨트롤(카드 타입 · 시간 구분) ──────────────────────────────
   테두리는 바깥에 한 번만, 칸 사이는 1px 세로선(운영 보드 툴바 .ob-seg 와 같은 규칙).
   칸은 균등 분할이라 선택지가 2개든 4개든 줄이 꽉 찬다. */
.ope-seg[b-mo6ozpnadn] {
    display: flex;
    align-items: stretch;
    height: var(--ope-ctl);
    border: 1px solid var(--ope-line-2);
    border-radius: var(--ope-r);
    background: var(--ope-surface);
    overflow: hidden;
    min-width: 0;
}

/* 카드 타입 전용 — **시기(4칸)의 절반 = 2칸** 폭으로 좌측 정렬(2026-08-25 오너 지시).
   칸 분할은 건드리지 않는다(`.ope-seg-b{flex:1 1 0}` 그대로) → 그룹 폭이 절반이면 칸도 정확히 절반,
   즉 여기 한 칸과 시기 한 칸이 **같은 폭**이 된다. 값이 2개일 때만 성립하는 규칙이라 클래스로 분리했다.
   ⚠️ `.ope-field` 가 flex 컬럼(align-items:stretch)이므로 명시 폭이 stretch 를 이긴다. */
.ope-seg.half[b-mo6ozpnadn] {
    width: 50%;
    align-self: flex-start;
}

.ope-seg-b[b-mo6ozpnadn] {
    appearance: none;
    flex: 1 1 0;
    min-width: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0 var(--ope-s2);
    border: none;
    background: transparent;
    color: var(--ope-ink-2);
    font-family: inherit;
    font-size: 0.8rem;
    font-weight: 700;
    white-space: nowrap;
    cursor: pointer;
    transition: background-color 0.16s ease, color 0.16s ease;
}

.ope-seg-b + .ope-seg-b[b-mo6ozpnadn] {
    border-left: 1px solid var(--ope-line-2);
}

.ope-seg-b:hover:not(.on)[b-mo6ozpnadn] {
    background: var(--ope-tint);
    color: var(--ope-ink);
}

.ope-seg-b.on[b-mo6ozpnadn] {
    background: var(--ope-accent);
    color: var(--ope-surface);
}

/* 이중 링 **인셋판** — 세그먼트는 그룹 테두리에 붙어 있어 링이 밖으로 나가면 이웃 칸을 덮는다.
   어두운 링이 안쪽 0→2px, 헤일로가 2→4px. */
.ope-seg-b:focus-visible[b-mo6ozpnadn] {
    outline: 2px solid var(--ope-focus);
    outline-offset: -2px;
    box-shadow: inset 0 0 0 4px var(--ope-focus-halo);
}

/* ── 상태 칩 ────────────────────────────────────────────────────────────
   기본은 **중립 흰 칩 + 상태 컬러 도트**(볼트 §디자인 관례: 파스텔 배경 무지개 금지).
   채운 칩은 **선택된 하나뿐**이라 색이 곧 "지금 이 상태"라는 뜻이 된다.
   색 3종(bg/border/fg)은 아래 st-* 변수 한 곳에서 나오고, 미리보기 배지도 같은 변수를 쓴다. */
.st-plan[b-mo6ozpnadn] {
    --st-fg: #334155;
    --st-bg: #e2e8f0;
    --st-bd: #cbd5e1;
}

.st-prog[b-mo6ozpnadn] {
    --st-fg: #1d4ed8;
    --st-bg: #dbeafe;
    --st-bd: #bfdbfe;
}

.st-done[b-mo6ozpnadn] {
    --st-fg: #047857;
    --st-bg: #d1fae5;
    --st-bd: #a7f3d0;
}

.st-hold[b-mo6ozpnadn] {
    --st-fg: #92400e;
    --st-bg: #fef3c7;
    --st-bd: #fde68a;
}

.st-tent[b-mo6ozpnadn] {
    --st-fg: #6d28d9;
    --st-bg: #ede9fe;
    --st-bd: #ddd6fe;
}

.ope-chips[b-mo6ozpnadn] {
    display: flex;
    flex-wrap: wrap;
    gap: var(--ope-s2);
    min-width: 0;
}

.ope-chip[b-mo6ozpnadn] {
    appearance: none;
    display: inline-flex;
    align-items: center;
    gap: var(--ope-s2);
    height: var(--ope-ctl);
    padding: 0 var(--ope-s3);
    border: 1px solid var(--ope-line-2);
    border-radius: var(--ope-r);
    background: var(--ope-surface);
    color: var(--ope-ink-2);
    font-family: inherit;
    font-size: 0.8rem;
    font-weight: 700;
    white-space: nowrap;
    cursor: pointer;
    transition: background-color 0.16s ease, border-color 0.16s ease, color 0.16s ease;
}

.ope-chip:hover:not(.on)[b-mo6ozpnadn] {
    background: var(--ope-tint);
    color: var(--ope-ink);
}

/* 선택 = 틴트 채움 + 같은 계열 테두리 + 먹 링. 색·글자·링 3중 신호라 색만으로 읽지 않아도 된다. */
.ope-chip.on[b-mo6ozpnadn] {
    background: var(--st-bg);
    border-color: var(--st-bd);
    color: var(--st-fg);
    box-shadow: 0 0 0 1px var(--st-fg);
}

/* 이중 링 **아웃셋판** — 헤일로 0→2px, 어두운 링 2→4px. */
.ope-chip:focus-visible[b-mo6ozpnadn] {
    outline: 2px solid var(--ope-focus);
    outline-offset: 2px;
    box-shadow: 0 0 0 2px var(--ope-focus-halo);
}

.ope-dot[b-mo6ozpnadn] {
    flex: 0 0 auto;
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--st-fg);
}

/* ── 보조 문구 ────────────────────────────────────────────────────────── */
.ope-note[b-mo6ozpnadn] {
    margin: 0;
    font-size: 0.76rem;
    font-weight: 700;
    line-height: 1.5;
    color: var(--ope-muted);
    font-variant-numeric: tabular-nums;
    overflow-wrap: anywhere;
}

.ope-note.bad[b-mo6ozpnadn] {
    color: var(--ope-bad);
}

.ope-hint[b-mo6ozpnadn] {
    font-size: 0.75rem;
    font-weight: 600;
    line-height: 1.5;
    color: var(--ope-muted);
    overflow-wrap: anywhere;
}

/* ── 셀렉트 1행(프로그램 · 담당자) ──────────────────────────────────────
   [분류칩] [색 점] 이름 … 기간   /   [이니셜] 이름 … uid */
/* 선택 팝업 한 줄 = [분류칩] [색 스와치] [이름] … [기간].
   📏 2026-08-25 오너 지시 "팝업에 아이콘이랑 태그랑 텍스트가 너무 붙어 있어":
     · 요소 사이 gap s2(8) → s3(12).
     · ⬆️ 같은 날 2차 지시("태그와 색상, 투표 제목의 간격을 넓혀줘")로 **가운데 두 틈만 더 벌렸다**:
       태그↔색칩 24 · 색칩↔제목 16 (아래 `.ope-opt-kind + .ope-opt-dot` 블록 참조).
       기본 gap 은 s3 그대로다 — 담당자 행이 이 기본값을 함께 쓰기 때문에 건드리지 않았다.
     · 오른쪽 끝 기간(.ope-opt-sub)은 이름과 **더 크게** 떨어뜨린다(margin-left: s2 추가) —
       가운데 이름이 말줄임으로 늘어나면 기간과 맞붙어 한 덩어리로 읽혔다.
   ⚖️ 행 높이는 건드리지 않았다(가로 간격만 조정) — 세로로 부풀면 목록에 보이는 항목 수가 줄어든다. */
/* 🔴 **토큰을 여기서 다시 선언하는 이유 — 이 조각은 다이얼로그 밖에서 그려진다.**
   MudSelect 의 드롭다운은 `MainLayout.razor` 최상단의 `<MudPopoverProvider />` 안에 그려진다
   (레이아웃 뿌리의 형제). 이 파일의 토큰은 `.ope-head / .ope-tabs / .ope-form` 세 뿌리에만 선언돼 있는데
   **커스텀 속성은 DOM 상속으로만 전달되므로**, 팝업으로 떠난 이 조각에는 `--ope-*` 가 하나도 닿지 않는다.
   → `gap: var(--ope-s3)` 가 무효값이 되어 **0** 이 되고, 색칩 라운드(`--ope-s1`)·배지 라운드(`--ope-r-sm`)·
     기간 글자색(`--ope-muted`)·기간 앞 여백(`--ope-s2`)도 전부 죽는다.
   ⚠️ 이것이 오너가 "태그·색상·제목이 붙어 있다"고 지적한 **실제 원인**이다. 같은 날 gap 을 s2→s3 로 올렸는데도
      화면이 그대로였던 것은 값이 작아서가 아니라 **애초에 적용된 적이 없었기** 때문이다.
   ✅ 해법: 이 조각이 어디에 떨어지든 자기 치수를 갖도록 **필요한 토큰만 여기에 다시 건다.**
      값은 위 §토큰 블록에서 그대로 가져온 것이라 두 곳이 갈리지 않는다(새 수치 없음).
      스코프 속성(b-xxxxx)은 팝업으로 옮겨 가도 요소에 그대로 붙어 있으므로 선택자 자체는 계속 매치한다 —
      끊기는 것은 **상속뿐**이다.
   ℹ️ 담당자 셀렉트도 이 `.ope-opt` 를 함께 쓰므로 그쪽 행도 **의도했던 치수를 되찾는다**
      (이름↔uid 20px · uid 는 --ope-muted 회색). 디자인 결정을 바꾼 것이 아니라 죽어 있던 규칙이 살아난 것이다. */
.ope-opt[b-mo6ozpnadn] {
    --ope-s1: 4px;
    --ope-s2: 8px;
    --ope-s3: 12px;
    --ope-s4: 16px;
    --ope-s5: 24px;
    --ope-r-sm: 6px;
    --ope-muted: #64748b; /* 기간·uid 보조 글자 · 흰 배경 4.76:1 */

    display: flex;
    align-items: center;
    gap: var(--ope-s3);
    min-width: 0;
    width: 100%;
}

.ope-opt-kind[b-mo6ozpnadn] {
    flex: 0 0 auto;
    font-size: 0.58rem;
    font-weight: 800;
    line-height: 1.5;
    padding: 0 5px;
    border-radius: var(--ope-r-sm);
    white-space: nowrap;
}

.ope-opt-dot[b-mo6ozpnadn] {
    flex: 0 0 auto;
    width: 12px;
    height: 12px;
    border-radius: var(--ope-s1);
    border: 1px solid rgba(15, 23, 42, 0.12);
}

/* 📏 2026-08-25 오너 지시 "프로그램 선택 시 태그와 색상, 투표 제목의 간격을 넓혀줘."
   같은 날 gap 을 s2(8) → s3(12) 로 한 번 올렸는데도 셋이 한 덩어리로 붙어 보인다는 판정이다.
   이번에는 **가운데 두 틈만 따로** 벌린다 — 기본 gap(s3)은 그대로 두고 그 위에 차액만 얹는다:

     [분류칩] ──24px── [색칩] ──16px── 제목 …… 20px …… 기간
        s5(24)                s4(16)              s3+s2

   ⚖️ **왜 두 틈을 다르게 두는가**: 분류칩은 *다른 종류의 정보*(투표/이벤트 같은 계통 라벨)이고,
      색칩은 *그 프로그램의 속성*이라 제목과 한 묶음으로 읽혀야 한다. 그래서
      `태그 ↔ 색칩`(24) > `색칩 ↔ 제목`(16) — 셋이 다 떨어지되 오른쪽 둘의 결속이 더 강하다.
      두 틈을 같게 두면 색칩이 어느 쪽에도 속하지 않는 미아가 되고, 예전처럼 붙여 두면
      색칩이 제목의 머리글자처럼 읽힌다(오너가 지적한 상태).
   📐 값은 전부 기존 4배수 토큰이다(s3/s4/s5). 맨 숫자를 심지 않으려고 **차액을 calc 로** 적었다 —
      `--ope-s3` 을 나중에 바꾸면 총합이 저절로 따라간다.

   🔒 **담당자 셀렉트는 자동으로 제외된다.** 이 두 규칙은 `.ope-opt-kind`/`.ope-opt-dot` 이
      실제로 있을 때만 매치하는데, 담당자 행은 `[이름][uid]` 둘뿐이라 어느 쪽도 없다.
      `(선택 안 함)` 항목도 `.ope-opt` 조각 자체가 없는 맨 텍스트라 영향이 없다(빈 여백이 생기지 않는다).
      → 클래스 추가·마크업 변경 없이 **선택자 구조만으로** 프로그램 행에만 걸린다.
   ⚖️ 세로 정렬은 손대지 않았다 — `.ope-opt{align-items:center}` 가 배지(≈14px)·색칩(12px)·
      글자(≈20px)를 이미 같은 축에 세운다. 가로 간격만 조정했고 행 높이는 그대로다. */
.ope-opt-kind + .ope-opt-dot[b-mo6ozpnadn] {
    margin-left: calc(var(--ope-s5) - var(--ope-s3)); /* 12 + 12 = 24px */
}

.ope-opt-dot + .ope-opt-name[b-mo6ozpnadn] {
    margin-left: calc(var(--ope-s4) - var(--ope-s3)); /* 12 + 4 = 16px */
}

/* 닫힌 칸(선택된 값)은 **목록과 갈랐다** — 한 줄짜리 30px 칸에서 24px 틈은 과하고,
   좁은 칸에서 간격이 커지면 그만큼 제목이 먼저 잘린다. 오늘 값(gap s3 = 12px)으로 되돌린다.
   ℹ️ 이 셀렉트는 `ToStringFunc="@ProgramText"` 로 **이름 문자열만** 닫힌 칸에 넘기므로 실제로는
      이 조각이 거기 그려지지 않을 가능성이 높다. 그래도 규칙을 남기는 이유는 MudBlazor 가
      선택된 항목의 조각을 닫힌 칸에 그대로 넣는 경우가 있기 때문이다(담당자 이니셜 전례, 같은 날 기록).
      그려지지 않으면 이 규칙은 아무것도 매치하지 않는다 — 비용 0. */
.ope-row[b-mo6ozpnadn]  .mud-input .ope-opt-kind + .ope-opt-dot,
.ope-row[b-mo6ozpnadn]  .mud-input .ope-opt-dot + .ope-opt-name {
    margin-left: 0;
}

/* ⛔ `.ope-opt-who`(담당자 이니셜 배지) 규칙 **삭제**(2026-08-25 오너 지시 "이니셜 아바타 마크 제거").
   마크업에서 span 을 걷어내 선택된 값·드롭다운 목록 양쪽에서 사라졌다 — 남은 것은 이름과 uid 뿐이다. */

.ope-opt-name[b-mo6ozpnadn] {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.ope-opt-sub[b-mo6ozpnadn] {
    flex: 0 0 auto;
    margin-left: var(--ope-s2); /* 이름과의 사이만 한 칸 더(위 .ope-opt 주석) — 총 12+8=20px */
    font-size: 0.72rem;
    font-weight: 600;
    color: var(--ope-muted);
    font-variant-numeric: tabular-nums;
}

/* ── 상세내용 에디터 ─────────────────────────────────────────────────────
   2026-08-25 `MudTextField Lines="10"` → 공용 웹에디터(`EditorWithImage`)로 교체.
   ⛔ **공용 래퍼는 한 줄도 고치지 않는다** — 5개 화면이 공유한다. 이 화면만의 치수·색은 전부 여기서 덮는다.
      `!important` 를 쓰는 자리는 셋뿐이고, 셋 다 **덮을 대상이 인라인이거나 이미 !important** 라 다른 수가 없다.

     ① 높이 — 래퍼가 인라인으로 `min-height:450px` 을 준다(인라인은 !important 로만 이긴다).
        `--ope-ed-min` 으로 한 자리에 묶어 두고 소스 편집 textarea 까지 같은 값으로 맞춘다(현재 450px).
     ② 면   — 전역 `app.css` 의 `.editor-theme` 는 **어두운 앱 화면용**이다(본문 #0f0726 · 흰 글자 · 폭 480px 고정).
        운영 보드의 상세내용은 **흰 면**에 그려진다(`OpsTaskDetail` 의 `.otd-note-b`) →
        편집 중에 결과와 다른 것을 보게 되므로 이 다이얼로그 안에서만 밝은 면으로 되돌리고 폭 고정을 푼다.
        ⚠️ 다른 4개 화면은 어두운 채로 그대로다 — 전역을 건드리지 않았다.

   ── 🔄 2026-08-25 오너 지시 "에디터가 다이얼로그 아래쪽 빈 공간을 전부 채우게" ──────────────
   🔴 **빈 여백의 정체는 래퍼가 인라인으로 준 `max-height:600px` 이었다**(`EditorWithImage.razor`:
      `Style="min-height:450px; max-height:600px;"`). 본문 높이(--ope-dlg-h)가 그보다 커도 에디터는 600 에서 멈춘다:
        · 1080p(≈937px) : 본문 712 − 패딩 30 − 탭바 44 − 탭바 아래 8 + 탭바 음수 위 마진 10 − 폼 위 8 = **632px**
          → 600 에서 잘려 **약 32px** 이 남는다(오너 스크린샷의 그 여백).
        · 768px 노트북  : 552 − 30 − 44 − 8 + 10 − 8 = **472px** → 450(min) 로 서서 **약 22px** 이 남는다.
      ⛔ 공용 래퍼는 5개 화면이 공유하므로 고치지 않는다 → 이 화면 한정으로 `max-height:none !important` 로 푼다
         (인라인 스타일은 `!important` 로만 이긴다 — 위 ① 과 같은 사정).
   🔗 그 위에 **세로 flex 사슬**을 얹는다. `.dlg-scroll`(확정 높이) → `.ope-tabs` → `.mud-tabs` →
      `.mud-tabs-panels` → 활성 `.mud-tab-panel` → `.ope-form.ed` → `.ope-note-ed` →
      `.ewi-root` → `.ewi-editor` → (디자인/소스 모드 래퍼 div) → `.rz-html-editor`.
      한 층이라도 빠지면 높이가 다시 내용 기반이 되어 아무 일도 일어나지 않는다.
   ✅ **툴바는 고정, 편집영역만 늘어난다** — Radzen 기본이 이미 그 구조다
      (`.rz-html-editor{display:flex;flex-direction:column}` · `.rz-html-editor-content{flex:1;overflow:auto}`).
      우리가 하는 일은 바깥 상자를 늘려 주는 것뿐이고, **편집영역 안쪽 스크롤은 기존 동작 그대로**다.
   ✅ `--ope-ed-min`(450px)은 **최소 높이로 남는다.** 남는 공간이 그보다 작은 화면에서는 사슬의 중간 층들이
      (min-height:0) 줄어들고 에디터만 450 을 지켜 넘치므로, 예전처럼 `.dlg-scroll` 이 스크롤한다.
   ⛔ 고정 높이(px·calc)로 다시 박지 않았다 — 늘어나는 근거는 전부 `flex: 1 1 auto` 다.
   ⛔ 폭·`MaxWidth` 무변경. */
.ope-note-ed[b-mo6ozpnadn] {
    min-width: 0;
}

/* 사슬의 마지막 구간 — **`.ed` 수식 클래스가 붙은 상세내용 탭에서만** 늘어난다.
   `.ewi-editor > div` 는 공용 래퍼가 그리는 이름 없는 래퍼(디자인 모드 / 소스 모드)다. 클래스를 붙일 수 없어
   자식 선택자로 잡는다.
   ⚠️ 소스 편집 모드에서 숨는 쪽 래퍼는 **인라인 `display:none`** 을 갖는다 → 인라인이 이 규칙을 이기므로
      `display:flex` 를 줘도 되살아나지 않는다(의도적으로 `!important` 를 쓰지 않았다). */
.ope-form.ed[b-mo6ozpnadn],
.ope-form.ed .ope-note-ed[b-mo6ozpnadn] {
    flex: 1 1 auto;
    min-height: 0;
}

.ope-form.ed .ope-note-ed[b-mo6ozpnadn],
.ope-form.ed .ope-note-ed[b-mo6ozpnadn]  .ewi-root,
.ope-form.ed .ope-note-ed[b-mo6ozpnadn]  .ewi-editor,
.ope-form.ed .ope-note-ed[b-mo6ozpnadn]  .ewi-editor > div {
    display: flex;
    flex-direction: column;
}

.ope-form.ed .ope-note-ed[b-mo6ozpnadn]  .ewi-root,
.ope-form.ed .ope-note-ed[b-mo6ozpnadn]  .ewi-editor,
.ope-form.ed .ope-note-ed[b-mo6ozpnadn]  .ewi-editor > div {
    flex: 1 1 auto;
    min-height: 0;
}

.ope-form.ed .ope-note-ed[b-mo6ozpnadn]  .rz-html-editor {
    flex: 1 1 auto;
    max-height: none !important; /* 공용 래퍼의 인라인 max-height:600px 해제 — 위 §빈 여백의 정체 */
}

.ope-note-ed[b-mo6ozpnadn]  .rz-html-editor {
    min-height: var(--ope-ed-min) !important;
    background: var(--ope-surface);
    border: 1px solid var(--ope-line-2);
    border-radius: var(--ope-r);
}

/* 툴바는 **고정**이다 — 세로 flex 안에서 줄지도 늘지도 않게 못 박는다(편집영역만 신축). */
.ope-note-ed[b-mo6ozpnadn]  .rz-html-editor-toolbar {
    flex: 0 0 auto;
    background: var(--ope-tint);
    border-bottom: 1px solid var(--ope-line);
}

.ope-note-ed[b-mo6ozpnadn]  .rz-html-editor-content {
    width: auto !important; /* .editor-theme 의 width:480px!important 해제 */
    margin: 0 !important;
    padding: var(--ope-s3) !important;
    background: var(--ope-surface);
    color: var(--ope-ink);
    font-size: 0.86rem;
    line-height: 1.65;
    /* 📐 2026-08-26 오너 지시 "수정에 웹에디터 넓이와 상세내용 보기 상에서 내용의 넓이를 똑같이 맞춰줘".
       여기는 **폭을 제한하지 않는다** — 대신 이 편집 영역의 폭을 **결정론적으로** 만들어
       상세 창이 그 값(`--ope-doc-w`)에 맞추게 한다(→ `OpsTaskDetail.razor.css` §본문 폭).
       ⛔ 편집 영역에 `max-width` 를 걸면 안 된다: 상자는 543px 인데 글만 좁아져 오른쪽에 **클릭해도 캐럿이
          안 잡히는 죽은 띠**가 생긴다(편집 표면은 상자 전체가 눌려야 한다).
       ✅ 대신 `scrollbar-gutter: stable` 로 **세로 스크롤바 자리를 항상 예약**한다. 두 가지를 동시에 얻는다:
          ① 글이 길어져 스크롤바가 생기는 순간 텍스트가 15px 씩 재배치되던 **떨림이 사라진다**
          ② 폭이 내용량과 무관하게 고정돼 상세 창이 맞출 **기준값이 생긴다**.
       ⚠️ 세로 flex 사슬(§상세내용 에디터)과 무관하다 — 이 두 속성은 가로 축·스크롤바 예약이라
          `flex`/`min-height` 계산에 관여하지 않는다. */
    scrollbar-gutter: stable;
}

/* 본문 이미지는 편집 중에도 상자를 넘지 않는다 — 저장 뒤 상세 창(.otd-note-b)의 규칙과 같다. */
.ope-note-ed[b-mo6ozpnadn]  .rz-html-editor-content img {
    max-width: 100%;
    height: auto;
}

/* 에디터가 만드는 문단 간격 — 브라우저 기본 1em 은 이 좁은 상자에서 너무 벌어진다. */
.ope-note-ed[b-mo6ozpnadn]  .rz-html-editor-content p {
    margin: 0 0 0.5em;
}

/* `HTML 소스 편집` 모드의 textarea 도 같은 인라인 450px 을 갖고 있다.
   🔗 소스 모드 래퍼도 위 사슬로 늘어나므로(그 div 는 인라인으로 이미 세로 flex 다) 이 칸에도 `flex:1 1 auto` 를
      줘서 함께 바닥까지 찬다 — 안 주면 늘어난 래퍼 안에 textarea 아래로 빈 띠가 남는다.
      450px 은 여기서도 **최소값**으로 그대로 남는다. */
.ope-note-ed[b-mo6ozpnadn]  textarea {
    flex: 1 1 auto;
    min-height: var(--ope-ed-min) !important;
}

/* ── 모션 ────────────────────────────────────────────────────────────────
   '할 일'로 전환할 때만 나타나는 종료일 줄. 채워진 상태에서 시작하지 않고 아주 짧게 미끄러져 들어와
   "줄이 하나 늘었다"를 알린다. fill-mode 를 주지 않으므로 끝난 뒤에는 transform 속성 자체가 남지 않는다
   (⛔ 남으면 stacking context 가 생겨 Mud 피커 팝오버가 갇힐 수 있다 — 볼트 §z-index 사고). */
@keyframes ope-in-b-mo6ozpnadn {
    from {
        opacity: 0;
        transform: translateY(-4px);
    }
}

.ope-appear[b-mo6ozpnadn] {
    animation: ope-in-b-mo6ozpnadn 0.18s cubic-bezier(0.16, 1, 0.3, 1);
}

@media (max-width: 520px) {
    .ope-row.c2[b-mo6ozpnadn] {
        grid-template-columns: 1fr;
    }

    .ope-seg-b[b-mo6ozpnadn] {
        font-size: 0.76rem;
    }

    /* 폭이 한 칸으로 접히면 '절반'의 기준(시기 4칸)이 사라진다 → 카드 타입도 줄을 다 쓴다. */
    .ope-seg.half[b-mo6ozpnadn] {
        width: 100%;
    }

    /* 탭은 여전히 두 칸이 창을 반씩 갖는다 — 좁아지는 만큼 라벨 좌우 여백만 줄인다. */
    .ope-tabs[b-mo6ozpnadn]  .mud-tab {
        padding: 0 var(--ope-s2);
        font-size: 0.8rem;
    }
}

/* 움직임만 걷어내고 색·상태 변화는 그대로 둔다(피드백이 사라지면 안 된다). */
@media (prefers-reduced-motion: reduce) {
    .ope-seg-b[b-mo6ozpnadn],
    .ope-chip[b-mo6ozpnadn] {
        transition: none;
    }

    .ope-appear[b-mo6ozpnadn] {
        animation: none;
    }
}
/* /Components/Pages/Manager/FAQ/FAQEditor.razor.rz.scp.css */

.upload-btn .plus[b-4qek2598yl] {
    font-size: 36px;
    line-height: 1;
}

.upload-btn[b-4qek2598yl] {
    border: 1px dashed #ccc;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
}


.image-preview-container[b-4qek2598yl] {
    position: relative;
    border: 1px solid #eee;
    display: flex;
    align-items: center;
    justify-content: center;
}

.image-preview-img[b-4qek2598yl] {
    max-width: 100%;
    max-height: 100%;
    display: block;
}

.image-action[b-4qek2598yl] {
    position: absolute;
    right: 6px;
    top: 6px;
    z-index: 3;
    display: flex;
    gap: 6px;
}


.actions-cell[b-4qek2598yl] {
    display: flex;
    gap: 6px;
    align-items: center;
    justify-content: center;
}
/* /Components/Pages/Manager/FAQ/FAQList.razor.rz.scp.css */
/* /Components/Pages/Manager/Help/HelpEditor.razor.rz.scp.css */

.upload-btn .plus[b-ff27eprv5b] {
    font-size: 36px;
    line-height: 1;
}

.upload-btn[b-ff27eprv5b] {
    border: 1px dashed #ccc;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
}


.image-preview-container[b-ff27eprv5b] {
    position: relative;
    border: 1px solid #eee;
    display: flex;
    align-items: center;
    justify-content: center;
}

.image-preview-img[b-ff27eprv5b] {
    max-width: 100%;
    max-height: 100%;
    display: block;
}

.image-action[b-ff27eprv5b] {
    position: absolute;
    right: 6px;
    top: 6px;
    z-index: 3;
    display: flex;
    gap: 6px;
}


.actions-cell[b-ff27eprv5b] {
    display: flex;
    gap: 6px;
    align-items: center;
    justify-content: center;
}
/* /Components/Pages/Manager/Help/HelpList.razor.rz.scp.css */
/* /Components/Pages/Manager/Logs/AdminAccessLog.razor.rz.scp.css */

body[b-qyopqmkfua] {
    background-color: #fff;
}

/* /Components/Pages/Manager/Logs/AdminAuditLog.razor.rz.scp.css */

body[b-1qgy5pqqg3] {
    background-color: #fff;
}

/* /Components/Pages/Manager/Logs/AdminPolicyLog.razor.rz.scp.css */

body[b-3naifdb1py] {
    background-color: #fff;
}

/* /Components/Pages/Manager/Maintenance/Maintenance.razor.rz.scp.css */

body[b-pna5rtgxji] {
    background-color: #fff;
}


.section[b-pna5rtgxji] {
    width: 200px;
    font-weight: bold;
    vertical-align: central;
    font-size: 14px;
}
.section-title[b-pna5rtgxji] {
    display: flex;
    align-items: center;
    font-size:18px;
    padding-bottom: 5px;
    color: #aaa;
    border-bottom: solid 5px #ccc;
}
/* /Components/Pages/Manager/News/NewsEditor.razor.rz.scp.css */
.image-preview-container[b-x50way9zck] {
    width: 100%;
    height: 100%;
    max-width:200px;
    margin-top:10px;
    display: flex;
    align-items: center;
    justify-content: center;
    background: #eee;
    border-radius: 12px;
    overflow: hidden;
}

.image-preview-img[b-x50way9zck] {
    max-width: 100%;
    max-height: 100%;
    object-fit: contain; /* 비율 유지, 여백 있음 */
    display: block;
}

/* /Components/Pages/Manager/News/NewsList.razor.rz.scp.css */
/* /Components/Pages/Manager/Notice/NoticeEditor.razor.rz.scp.css */

.upload-btn .plus[b-g6cvnb65d6] {
    font-size: 36px;
    line-height: 1;
}

.upload-btn[b-g6cvnb65d6] {
    border: 1px dashed #ccc;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
}


.image-preview-container[b-g6cvnb65d6] {
    position: relative;
    border: 1px solid #eee;
    display: flex;
    align-items: center;
    justify-content: center;
}

.image-preview-img[b-g6cvnb65d6] {
    max-width: 100%;
    max-height: 100%;
    display: block;
}

.image-action[b-g6cvnb65d6] {
    position: absolute;
    right: 6px;
    top: 6px;
    z-index: 3;
    display: flex;
    gap: 6px;
}


.actions-cell[b-g6cvnb65d6] {
    display: flex;
    gap: 6px;
    align-items: center;
    justify-content: center;
}
/* /Components/Pages/Manager/Notice/NoticeList.razor.rz.scp.css */
/* /Components/Pages/Manager/Notification/NotificationEditor.razor.rz.scp.css */

.image-preview-container[b-pt5uaoxjnb] {
    position: relative;
    background: #f4f4f4;
    border: 1px solid #e0e0e0;
    border-radius: 7px;
    display: flex;
    justify-content: center;
    align-items: center;
    overflow: hidden;
}

.image-preview-img[b-pt5uaoxjnb] {
    width: 100%;
    height: 100%;
    object-fit: cover;
    border-radius: 14px;
}

/* /Components/Pages/Manager/Notification/NotificationList.razor.rz.scp.css */
/* /Components/Pages/Manager/OneChallenge/OneChallengeArtistRank.razor.rz.scp.css */
/* /Components/Pages/Manager/OneChallenge/OneChallengeEditor.razor.rz.scp.css */

.upload-btn .plus[b-f6nct18ty8] {
    font-size: 36px;
    line-height: 1;
}

.upload-btn[b-f6nct18ty8] {
    border: 1px dashed #ccc;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
}


.image-preview-container[b-f6nct18ty8] {
    position: relative;
    border: 1px solid #eee;
    display: flex;
    align-items: center;
    justify-content: center;
}

.image-preview-img[b-f6nct18ty8] {
    max-width: 100%;
    max-height: 100%;
    display: block;
}

.image-action[b-f6nct18ty8] {
    position: absolute;
    right: 6px;
    top: 6px;
    z-index: 3;
    display: flex;
    gap: 6px;
}


.actions-cell[b-f6nct18ty8] {
    display: flex;
    gap: 6px;
    align-items: center;
    justify-content: center;
}
/* /Components/Pages/Manager/OneChallenge/OneChallengeFanRank.razor.rz.scp.css */
/* /Components/Pages/Manager/OneChallenge/OneChallengeList.razor.rz.scp.css */
/* /Components/Pages/Manager/PlusStation/PlusStationList.razor.rz.scp.css */

.image-preview-container[b-2w1ck0y38v] {
    position: relative;
    display: inline-block;
    border: 1px dashed #ddd;
    border-radius: 8px;
    overflow: hidden;
    background: #fafafa;
}

.image-preview-img[b-2w1ck0y38v] {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

.upload-btn[b-2w1ck0y38v] {
    display: flex;
    align-items: center;
    justify-content: center;
    flex-direction: column;
    border: 1px dashed #bbb;
    border-radius: 8px;
    color: #777;
    background: #fff;
    position: relative;
}

    .upload-btn .plus[b-2w1ck0y38v] {
        font-size: 42px;
        line-height: 1;
    }

.subtitle[b-2w1ck0y38v] {
    font-size: 18px;
    font-weight: 700;
}
/* /Components/Pages/Manager/PointProducts/PointProductEditor.razor.rz.scp.css */

.upload-btn .plus[b-tl37g2t8ur] {
    font-size: 36px;
    line-height: 1;
}

.upload-btn[b-tl37g2t8ur] {
    border: 1px dashed #ccc;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
}


.image-preview-container[b-tl37g2t8ur] {
    position: relative;
    border: 1px solid #eee;
    display: flex;
    align-items: center;
    justify-content: center;
}

.image-preview-img[b-tl37g2t8ur] {
    max-width: 100%;
    max-height: 100%;
    display: block;
}

.image-action[b-tl37g2t8ur] {
    position: absolute;
    right: 6px;
    top: 6px;
    z-index: 3;
    display: flex;
    gap: 6px;
}


.actions-cell[b-tl37g2t8ur] {
    display: flex;
    gap: 6px;
    align-items: center;
    justify-content: center;
}
/* /Components/Pages/Manager/PointProducts/PointProductList.razor.rz.scp.css */




.event[b-qndkd908ff] {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    justify-content: space-between; /* 버튼을 오른쪽 끝 */
    flex-wrap: wrap; /* 좁으면 줄바꿈 */
    font-weight: bold;
    font-size: 16px;
    padding-bottom: 10px;
    min-height: 40px; /* 기존 높이 보장 */
    margin-top:10px;
    border-bottom: dashed 1px #555;
    gap: 6px; /* 줄바꿈 시 간격 */
}
.event-info[b-qndkd908ff] {
    display: flex;
    align-items: center;
    flex-wrap: wrap; /* 좁을 때 아이콘/텍스트/날짜 줄바꿈 허용 */
    gap: 4px;
    font-size: 18px;
    font-weight: 800;
}
.time[b-qndkd908ff]{
    margin:0 10px 0 10px;
}

.date[b-qndkd908ff] {
    font-size: 12px;
    font-weight: normal;
}

.tilde[b-qndkd908ff] {
    font-size: 13px;
    font-weight: normal;
    margin: 2px;
}
/* /Components/Pages/Manager/PointProducts/PointProductSalesEditor.razor.rz.scp.css */

.upload-btn .plus[b-8nf2kevjun] {
    font-size: 36px;
    line-height: 1;
}

.upload-btn[b-8nf2kevjun] {
    border: 1px dashed #ccc;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
}


.image-preview-container[b-8nf2kevjun] {
    position: relative;
    border: 1px solid #eee;
    display: flex;
    align-items: center;
    justify-content: center;
}

.image-preview-img[b-8nf2kevjun] {
    max-width: 100%;
    max-height: 100%;
    display: block;
}

.image-action[b-8nf2kevjun] {
    position: absolute;
    right: 6px;
    top: 6px;
    z-index: 3;
    display: flex;
    gap: 6px;
}


.actions-cell[b-8nf2kevjun] {
    display: flex;
    gap: 6px;
    align-items: center;
    justify-content: center;
}
/* /Components/Pages/Manager/PointProducts/PointProductSalesList.razor.rz.scp.css */




.event[b-t9n8itigey] {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    justify-content: space-between; /* 버튼을 오른쪽 끝 */
    flex-wrap: wrap; /* 좁으면 줄바꿈 */
    font-weight: bold;
    font-size: 16px;
    padding-bottom: 10px;
    min-height: 40px; /* 기존 높이 보장 */
    margin-top:10px;
    border-bottom: dashed 1px #555;
    gap: 6px; /* 줄바꿈 시 간격 */
}
.event-info[b-t9n8itigey] {
    display: flex;
    align-items: center;
    flex-wrap: wrap; /* 좁을 때 아이콘/텍스트/날짜 줄바꿈 허용 */
    gap: 4px;
    font-size: 18px;
    font-weight: 800;
}
.time[b-t9n8itigey]{
    margin:0 10px 0 10px;
}

.date[b-t9n8itigey] {
    font-size: 12px;
    font-weight: normal;
}

.tilde[b-t9n8itigey] {
    font-size: 13px;
    font-weight: normal;
    margin: 2px;
}
/* /Components/Pages/Manager/Policies/Policies.razor.rz.scp.css */

body[b-9xe2cfc6ug] {
    background-color: #fff;
}


.section[b-9xe2cfc6ug] {
    width: 200px;
    font-weight: bold;
    vertical-align: central;
    font-size: 14px;
}
.section-title[b-9xe2cfc6ug] {
    display: flex;
    align-items: center;
    font-size:18px;
    padding-bottom: 5px;
    color: #aaa;
    border-bottom: solid 5px #ccc;
}
/* /Components/Pages/Manager/Popup/AppPopupEditor.razor.rz.scp.css */

.image-preview-container[b-5n9keu5fq6] {
    position: relative;
    background: #f4f4f4;
    border: 1px solid #e0e0e0;
    border-radius: 7px;
    display: flex;
    justify-content: center;
    align-items: center;
    overflow: hidden;
}

.image-preview-img[b-5n9keu5fq6] {
    width: 100%;
    height: 100%;
    object-fit: contain;
    display: block;
}
/* /Components/Pages/Manager/Popup/AppPopupList.razor.rz.scp.css */

/* /Components/Pages/Manager/Purchase/PurchaseFailures.razor.rz.scp.css */
/* /Components/Pages/Manager/Purchase/PurchaseList.razor.rz.scp.css */
/* /Components/Pages/Manager/Statistics/StatsDeleted.razor.rz.scp.css */

body[b-xbp7t9q8xg] {
    background-color: #fff;
}

/* /Components/Pages/Manager/Statistics/StatsLogin.razor.rz.scp.css */

body[b-fxepa1gcpl] {
    background-color: #fff;
}

/* /Components/Pages/Manager/Statistics/StatsRetention.razor.rz.scp.css */
/* 리텐션 통계 — 페이지 스코프 CSS (2026-08-24: 전체 폭 · 페이지 레벨 스크롤 전환)
   - 이 화면은 MainLayout.FullBleedRoutes("statsretention")로 MudContainer(MaxWidth.Large + px-4)를 건너뛰고
     .fdr-fullbleed 안에서 렌더된다 → 좌우 여백은 .rt-root 가 직접 관리한다.
   - 내부 스크롤 박스(overflow:auto + 고정 높이) 없음. 세로·가로 모두 페이지(뷰포트) 스크롤 = 스크롤바 2중 방지.
   - 카드 overflow 는 hidden 금지(스크롤 컨테이너가 생겨 내부 sticky 가 전부 죽는다) → clip.
   - 100vw 계산 금지(site.css 의 body{width:100vw} + 드로어 개폐에서 깨진다) → width:100% / max-content 만 사용.
   - MudPaper·MudTabs 가 스스로 렌더하는 요소에는 스코프 속성이 안 붙으므로 ::deep 으로 지정. */

.rt-root[b-ovmhid4ky5] {
    /* sticky 기준값 — 조정은 이 두 줄에서만 */
    --rt-stick-top: 56px;   /* 앱바 실측 높이: MainLayout 이 .cross-pattern-appbar .mud-toolbar 를 56px 로 고정한다.
                               MudBlazor 기본 --mud-appbar-height(64px)를 쓰면 헤더 위로 8px 틈이 생긴다 */
    --rt-stick-left: 0px;   /* 문서 가로 스크롤 기준점 = 뷰포트 왼쪽 */

    --rt-line: #e2e8f0;
    --rt-head-bg: #f8fafc;

    width: 100%;
    box-sizing: border-box;
    padding: 0 16px 32px 16px; /* .fdr-fullbleed 는 여백이 0 — 게터는 화면이 소유 */
}

/* ── 카드 ─────────────────────────────────────────────── */
.rt-root[b-ovmhid4ky5]  .rt-card {
    background: #ffffff;
    border: 1px solid #cbd5e1;
    border-radius: 15px;
    box-shadow: 0 2px 3px rgba(0, 0, 0, 0.05);
    overflow: clip; /* hidden 금지 — 내부 sticky 가 죽는다. clip 은 모서리만 잘라낸다 */
}

/* 표 카드는 내용 폭을 따라간다: 표가 넓으면 카드 배경·테두리도 표 끝까지 같이 늘어나고,
   좁으면 min-width 로 화면 폭을 채운다. (상단 필터 카드는 그대로 화면 폭) */
.rt-capture[b-ovmhid4ky5] {
    width: max-content;
    min-width: 100%;
}

.rt-root[b-ovmhid4ky5]  .rt-table-card {
    width: max-content;
    min-width: 100%;
}

/* ── 상단 필터 바 ─────────────────────────────────────── */
.rt-toolbar[b-ovmhid4ky5] {
    background-color: #fcfdfe;
    border-bottom: 1px solid #f1f5f9;
}

/* ── 탭 ───────────────────────────────────────────────── */
.rt-root[b-ovmhid4ky5]  .rt-tabs .mud-tabs-tabbar {
    background-color: transparent;
    justify-content: flex-start;
    border-bottom: 1px solid var(--rt-line);
}

.rt-root[b-ovmhid4ky5]  .rt-tabs .mud-tab {
    font-weight: 700;
    color: #64748b;
    min-width: auto;
    padding: 10px 20px;
    font-size: 0.82rem;
    font-family: 'Pretendard', sans-serif;
}

.rt-root[b-ovmhid4ky5]  .rt-tabs .mud-tab-active {
    color: var(--mud-palette-primary);
}

/* ── 코호트 표 ────────────────────────────────────────── */
.rt-table[b-ovmhid4ky5] {
    width: max-content;
    min-width: 100%;
    border-collapse: separate; /* collapse 면 sticky 셀의 테두리가 따라오지 않는다 */
    border-spacing: 0;
}

/* 열 헤더: 세로 스크롤 시 앱바 바로 아래에 고정. 배경 필수(뒤 행이 비치면 안 됨) */
.rt-table th[b-ovmhid4ky5] {
    position: sticky;
    top: var(--rt-stick-top);
    z-index: 2;
    background-color: var(--rt-head-bg);
    color: #475569;
    font-weight: 800;
    font-size: 0.72rem;
    padding: 8px 6px;
    border-bottom: 1px solid var(--rt-line);
    text-align: center;
    white-space: nowrap;
}

.rt-table td[b-ovmhid4ky5] {
    padding: 6px 3px;
    font-size: 0.75rem;
    color: #334155;
    text-align: center;
    border-bottom: 1px solid #f1f5f9;
    vertical-align: middle;
}

/* 첫 열(코호트): 가로 스크롤 시 왼쪽에 고정. 역시 배경 필수 */
.rt-table th:first-child[b-ovmhid4ky5],
.rt-table td:first-child[b-ovmhid4ky5] {
    position: sticky;
    left: var(--rt-stick-left);
    min-width: 120px;
    text-align: left;
    padding-left: 16px;
    white-space: nowrap;
}

.rt-table th:first-child[b-ovmhid4ky5] {
    z-index: 3; /* 좌상단 코너 — 헤더(2)·첫 열(1) 보다 위 */
}

.rt-table td:first-child[b-ovmhid4ky5] {
    z-index: 1;
    background-color: #ffffff;
    font-family: 'Pretendard', sans-serif;
    font-weight: 800;
    color: #1e293b;
}

/* 칸 폭 고정 — 모드가 바뀌어도 열 간격이 흔들리지 않게.
   ⚠️ .rt-table 접두사 필수: 접두사 없이 쓰면 `.rt-table th` 보다 특이도가 낮아 색이 덮인다 */
.rt-table .rt-col-step[b-ovmhid4ky5] {
    width: 65px;
    min-width: 65px;
    max-width: 65px;
    box-sizing: border-box;
}

.rt-table .rt-col-new[b-ovmhid4ky5] {
    min-width: 70px;
}

.rt-table th.rt-col-today[b-ovmhid4ky5] {
    min-width: 80px;
    color: #e11d48;
}

/* ── 셀 내용 ──────────────────────────────────────────── */
.rt-cohort-size[b-ovmhid4ky5] {
    display: inline-block;
    min-width: 45px;
    padding: 3px 6px;
    border-radius: 4px;
    background-color: #f0f9ff;
    color: #0ea5e9;
    font-weight: 800;
    font-size: 0.75rem;
    font-variant-numeric: tabular-nums;
}

.rt-today-cell[b-ovmhid4ky5] {
    display: inline-flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    min-width: 55px;
    padding: 3px 4px;
    border: 1px solid #fecdd3;
    border-radius: 4px;
    background-color: #fff1f2;
}

.rt-today-cell .rt-count[b-ovmhid4ky5] {
    font-weight: 800;
    color: #e11d48;
    font-size: 0.75rem;
    font-variant-numeric: tabular-nums;
}

.rt-today-cell .rt-rate[b-ovmhid4ky5] {
    font-weight: 600;
    color: #f43f5e;
    font-size: 0.62rem;
    font-variant-numeric: tabular-nums;
}

.rt-heatmap[b-ovmhid4ky5] {
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    width: 100%;
    max-width: 60px;
    margin: 0 auto;
    padding: 4px 2px;
    border-radius: 4px;
    color: #ffffff;
    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.15);
}

.rt-heatmap .rt-count[b-ovmhid4ky5] {
    font-weight: 800;
    font-size: 0.75rem;
    line-height: 1;
    font-variant-numeric: tabular-nums;
}

.rt-heatmap .rt-rate[b-ovmhid4ky5] {
    font-weight: 500;
    font-size: 0.62rem;
    opacity: 0.85;
    margin-top: 1px;
    font-variant-numeric: tabular-nums;
}

.rt-heatmap.rt-empty[b-ovmhid4ky5] {
    background-color: var(--rt-head-bg);
    color: #cbd5e1;
    box-shadow: none;
    border: 1px dashed var(--rt-line);
}
/* /Components/Pages/Manager/Statistics/StatsSales.razor.rz.scp.css */

body[b-q97i9jx8z1] {
    background-color: #fff;
}

/* /Components/Pages/Manager/Statistics/StatsSignup.razor.rz.scp.css */

body[b-3qgu5uf85x] {
    background-color: #fff;
}

/* /Components/Pages/Manager/Users/PickInfo/PickInfo.razor.rz.scp.css */

/* table ----------------------------------------------------------------------------------- */
table-wrapper[b-y0cl5kxsh2] {
    width: 100%;
    overflow-x: auto; /* ���� ��ũ�� ������ ��� */
}

table[b-y0cl5kxsh2] {
    width: 100%;
    overflow-x: auto; /* ���� ��ũ�� ������ ��� */
    border:  0px;
}


table td[b-y0cl5kxsh2] {
    padding: 12px; /* �� ������ ���� ���� */
    text-align: left; /* �ؽ�Ʈ ���� */
    border-bottom: 1px solid #ddd; /* ���� �׵θ� ���� */
    font-size: 14px;
}


/* section ----------------------------------------------------------------------------------- */
.section-title[b-y0cl5kxsh2] {
    display: flex;
    align-items: center;
    font-weight: bold;
    font-size: 16px;
    padding-bottom: 10px;
    border-bottom: solid 5px #999;
}
.section[b-y0cl5kxsh2] {
    width: 120px;
    font-weight: bold;
    vertical-align: top;
    font-size: 13px;
}
/* /Components/Pages/Manager/Users/PickInfo/Popups/PickEditor.razor.rz.scp.css */
/* /Components/Pages/Manager/Users/PickInfo/Popups/PickPointProductSet.razor.rz.scp.css */

.image-preview-container[b-xod0pbayw0] {
    position: relative;
    background: #f4f4f4;
    border: 1px solid #e0e0e0;
    border-radius: 7px;
    display: flex;
    justify-content: center;
    align-items: center;
    overflow: hidden;
}

.image-preview-img[b-xod0pbayw0] {
    width: 100%;
    height: 100%;
    object-fit: contain;
    display: block;
}
/* /Components/Pages/Manager/Users/PickInfo/Popups/PickPointSet.razor.rz.scp.css */
/* /Components/Pages/Manager/Users/PickInfo/Popups/PickPost.razor.rz.scp.css */
/* /Components/Pages/Manager/Users/PickInfo/Popups/UserEditor.razor.rz.scp.css */
/* /Components/Pages/Manager/Users/Picks.razor.rz.scp.css */
/* /Components/Pages/Manager/Users/UserReportList.razor.rz.scp.css */
/* /Components/Pages/Manager/Users/Users.razor.rz.scp.css */
/* /Components/Pages/Manager/Version/Version.razor.rz.scp.css */

body[b-xjv9vx4tl5] {
    background-color: #fff;
}

/* /Components/Pages/Manager/Version/VersionForm.razor.rz.scp.css */

.section[b-t890lflix7] {
    width: 150px;
    font-weight: bold;
    vertical-align: central;
    font-size: 14px;
}
/* /Components/Pages/Manager/Vote/AwardsEditor.razor.rz.scp.css */
/* /Components/Pages/Manager/Vote/AwardsList.razor.rz.scp.css */



body[b-e4dijk5wfi] {
    background-color: #fff;
}

/* /Components/Pages/Manager/Vote/FanChallenge.razor.rz.scp.css */



body[b-oum34nucpq] {
    background-color: #fff;
}
/* /Components/Pages/Manager/Vote/FanChallengeEditor.razor.rz.scp.css */
/* /Components/Pages/Manager/Vote/FanChallengeRank.razor.rz.scp.css */
/* /Components/Pages/Manager/Vote/FanChallengeRankUser.razor.rz.scp.css */
/* /Components/Pages/Manager/Vote/FanChoice.razor.rz.scp.css */



body[b-323tukvch4] {
    background-color: #fff;
}

/* /Components/Pages/Manager/Vote/FanChoiceEditor.razor.rz.scp.css */
/* /Components/Pages/Manager/Vote/FanChoiceRank.razor.rz.scp.css */
/* /Components/Pages/Manager/Vote/FanChoiceRankUser.razor.rz.scp.css */
/* /Components/Pages/Manager/Vote/VoteCandidateEditor.razor.rz.scp.css */


.vote-candidate-dialog .mud-dialog-content[b-8o1s65amig] {
    overflow: hidden;
}

.w44[b-8o1s65amig] {
    width: 44px;
}

.w90[b-8o1s65amig] {
    width: 90px;
}
/* 전체 선택/해제 아이콘 2개용 */

.actions-cell[b-8o1s65amig] {
    display: flex;
    gap: 6px;
    align-items: center;
    justify-content: center;
}

.two-col[b-8o1s65amig] {
    display: flex;
    gap: 16px;
    margin-top: 0;
    align-items: stretch;
    padding: 0 10px;
}

.col[b-8o1s65amig], .right-pane[b-8o1s65amig] {
    flex: 1 1 0;
    width: 50%;
    display: flex;
    flex-direction: column;
}

.topbar[b-8o1s65amig] {
    border-radius: 8px;
    margin-bottom: 8px;
    display: flex;
    align-items: center;
}

.panel[b-8o1s65amig] {
    display: flex;
    flex-direction: column;
    border-radius: 8px;
    margin-top:6px;
}

.table-scroll[b-8o1s65amig] {
    overflow: visible;
}

.panel-footer[b-8o1s65amig] {
    min-height: 46px;
    display: flex;
    align-items: center;
    justify-content: center;
}

.right-pane-body[b-8o1s65amig] {
    overflow: visible;
    max-height: none;
    margin-bottom:20px;
}


.row-selected .actions-cell[b-8o1s65amig] {
    filter: none;
    opacity: 1;
    pointer-events: auto;
}

.compact-table td[b-8o1s65amig], .compact-table th[b-8o1s65amig] {
    padding-top: 10px !important;
    padding-bottom: 10px !important;
}


/* /Components/Pages/Manager/Vote/VoteCandidateList.razor.rz.scp.css */

body[b-4lz3s96shm] {
    background-color: #fff;
}


/* table ----------------------------------------------------------------------------------- */
.table-wrapper[b-4lz3s96shm] {
    width: 100%;
    overflow-x: auto; /* 가로 스크롤 생성을 허용 */
}

table[b-4lz3s96shm] {
    width: 100%;
    border-collapse: collapse; /* 테두리가 겹치지 않도록 설정 */
    /*min-width: 100px; 테이블이 일정 크기 이하로 줄어들지 않도록 설정 */
}

.main-table[b-4lz3s96shm] {
}
.main-table td[b-4lz3s96shm] {
    border: 1px solid #ddd; /* 셀의 테두리 설정 */
    padding: 15px; /* 셀 내부의 여백 설정 */
    text-align: left; /* 텍스트 정렬 */
}


/* ----------------------------------------------------------------------------------- */
.top-menu[b-4lz3s96shm]{

}

.top-menu td[b-4lz3s96shm] {
}

.btn[b-4lz3s96shm] {
    min-width: 100px;
    margin: 0 5px 0 5px;
}

/* ----------------------------------------------------------------------------------- */
.section[b-4lz3s96shm] {
    width: 100px;
    font-weight: bold;
    vertical-align: top;
    font-size: 13px;
}

.section-item[b-4lz3s96shm]{
    text-align:left;
    font-size: 13px;
}

.store[b-4lz3s96shm] {
    margin: 10px 0 5px 0;
    display: flex;
    align-items: center;
    font-size: 14px; /* 아이콘과 텍스트 크기 조정 */
    font-weight: bold;
}

.store .material-icons[b-4lz3s96shm] {
    font-size: 20px; /* 아이콘 크기 */
    margin-right: 5px; /* 아이콘과 텍스트 사이의 간격 조정 */
}


.container[b-4lz3s96shm] {
    text-align: left;
    display: flex;
}

.item[b-4lz3s96shm] {
    margin:2px;
    background-color: #fff;
    padding: 5px;
    font-size: 12px;
    text-align:left;
}
.item:first-child[b-4lz3s96shm] {
    max-width:70px;
   text-align: end;
   width: 60px;
   background-color: #f8f8f8;
}
 
.item:last-child[b-4lz3s96shm] {
}


.custom-th[b-4lz3s96shm] {
    min-width: 50px;
}

/* /Components/Pages/Manager/Vote/VoteStatus.razor.rz.scp.css */

body[b-yjaejfpsrp] {
    background-color: #fff;
}


/* table ----------------------------------------------------------------------------------- */
.table-wrapper[b-yjaejfpsrp] {
    width: 100%;
    overflow-x: auto; /* 가로 스크롤 생성을 허용 */
}

table[b-yjaejfpsrp] {
    width: 100%;
    border-collapse: collapse; /* 테두리가 겹치지 않도록 설정 */
    /*min-width: 100px; 테이블이 일정 크기 이하로 줄어들지 않도록 설정 */
}

.main-table[b-yjaejfpsrp] {
}
.main-table td[b-yjaejfpsrp] {
    border: 1px solid #ddd; /* 셀의 테두리 설정 */
    padding: 15px; /* 셀 내부의 여백 설정 */
    text-align: left; /* 텍스트 정렬 */
}


/* ----------------------------------------------------------------------------------- */
.top-menu[b-yjaejfpsrp]{

}

.top-menu td[b-yjaejfpsrp] {
}

.btn[b-yjaejfpsrp] {
    min-width: 100px;
    margin: 0 5px 0 5px;
}

/* ----------------------------------------------------------------------------------- */
.section[b-yjaejfpsrp] {
    width: 100px;
    font-weight: bold;
    vertical-align: top;
    font-size: 13px;
}

.section-item[b-yjaejfpsrp]{
    text-align:left;
    font-size: 13px;
}

.store[b-yjaejfpsrp] {
    margin: 10px 0 5px 0;
    display: flex;
    align-items: center;
    font-size: 14px; /* 아이콘과 텍스트 크기 조정 */
    font-weight: bold;
}

.store .material-icons[b-yjaejfpsrp] {
    font-size: 20px; /* 아이콘 크기 */
    margin-right: 5px; /* 아이콘과 텍스트 사이의 간격 조정 */
}


.container[b-yjaejfpsrp] {
    text-align: left;
    display: flex;
}

.item[b-yjaejfpsrp] {
    margin:2px;
    background-color: #fff;
    padding: 5px;
    font-size: 12px;
    text-align:left;
}
.item:first-child[b-yjaejfpsrp] {
    max-width:70px;
   text-align: end;
   width: 60px;
   background-color: #f8f8f8;
}
 
.item:last-child[b-yjaejfpsrp] {
}


.custom-th[b-yjaejfpsrp] {
    min-width: 50px;
}

/* /Components/Pages/Manager/Vote/VoteTimeline.razor.rz.scp.css */

body[b-qo61gwhgwm] {
    background-color: #fff;
}



.title[b-qo61gwhgwm] {
    overflow: hidden;
    font-weight: 500;
}

/* 공통 뱃지 */
.chip[b-qo61gwhgwm] {
    display: inline-block;
    padding: 0 8px;
    height: 22px;
    line-height: 22px;
    border-radius: 9999px;
    font-size: 12px;
    font-weight: 600;
    border: 1px solid transparent;
    vertical-align: text-top;
    white-space: nowrap;
}

/* ── 타입: 시작/종료 (Indigo vs Rose) ── */
.chip-start[b-qo61gwhgwm] {
    background: #E0EAFF; /* indigo-100 */
    border-color: #A5B4FC; /* indigo-300 */
    color: #3730A3; /* indigo-800 */
}

.chip-end[b-qo61gwhgwm] {
    background: #FFE4E6; /* rose-100 */
    border-color: #FDA4AF; /* rose-300 */
    color: #9F1239; /* rose-800 */
}

/* ── 상태: Active/Closed (Green vs Slate) ── */
.chip-status-active[b-qo61gwhgwm] {
    background: #DCFCE7; /* green-100 */
    border-color: #86EFAC; /* green-300 */
    color: #166534; /* green-800 */
}

.chip-status-closed[b-qo61gwhgwm] {
    background: #E5E7EB; /* gray/slate-200 */
    border-color: #CBD5E1; /* slate-300 */
    color: #334155; /* slate-700 */
}

/* ── 소스: FanChallenge/FanChoice (Violet vs Amber) ── */
.chip-src-challenge[b-qo61gwhgwm] {
    background: #F3E8FF; /* violet-100 */
    border-color: #C4B5FD; /* violet-300 */
    color: #6D28D9; /* violet-700 */
}

.chip-src-choice[b-qo61gwhgwm] {
    background: #FFFBEB; /* amber-100 */
    border-color: #FDE68A; /* amber-300 */
    color: #92400E; /* amber-700 */
}

/* 행 hover 효과 */
.timeline-table[b-qo61gwhgwm] {
    border-collapse: separate;
    border-spacing: 0 6px; /* 행 간격 */
}

    .timeline-table td[b-qo61gwhgwm] {
        transition: background-color .15s ease, box-shadow .15s ease;
    }
/* /Components/Pages/Manager/Vote/VoteUserRank.razor.rz.scp.css */
/* /Views/Shared/_Layout.cshtml.rz.scp.css */
/* Please see documentation at https://learn.microsoft.com/aspnet/core/client-side/bundling-and-minification
for details on configuring this project to bundle and minify static web assets. */

