:root{
  --kptu-bg:#f5f6f7;
  --kptu-surface:#fff;
  --kptu-surface-subtle:#fafbfc;
  --kptu-ink:#1f2933;
  --kptu-muted:#66727f;
  --kptu-faint:#8a949e;
  --kptu-border:#dfe4e8;
  --kptu-border-strong:#cfd6dc;
  --kptu-primary:#263f5f;
  --kptu-primary-hover:#1f354f;
  --kptu-primary-soft:#eef2f6;
  --kptu-link:#355f86;
  --kptu-success:#2f6b4f;
  --kptu-success-soft:#eef6f1;
  --kptu-warning:#8a6218;
  --kptu-warning-soft:#faf4e7;
  --kptu-danger:#9a4048;
  --kptu-danger-soft:#faeeee;
  --kptu-info:#496b8c;
  --kptu-info-soft:#eef4f8;
  --kptu-accent:#66508c;
  --kptu-space-1:4px;
  --kptu-space-2:8px;
  --kptu-space-3:12px;
  --kptu-space-4:16px;
  --kptu-space-5:24px;
  --kptu-space-6:32px;
  --kptu-radius-sm:6px;
  --kptu-radius-md:8px;
  --kptu-radius-lg:12px;
  --kptu-radius-pill:999px;
  --kptu-shadow-float:0 8px 24px rgba(20,33,48,.08);
  --kptu-shadow-modal:0 24px 64px rgba(20,33,48,.16);
  --kptu-control-height:36px;
  --kptu-action-compact-height:32px;
  --bg:var(--kptu-bg);
  --paper:var(--kptu-surface);
  --ink:var(--kptu-ink);
  --muted:var(--kptu-muted);
  --line:var(--kptu-border);
  --navy:var(--kptu-primary);
  --blue:var(--kptu-link);
  --soft:var(--kptu-primary-soft);
  --green:var(--kptu-success);
  --amber:var(--kptu-warning);
  --red:var(--kptu-danger);
  --purple:var(--kptu-accent);
}
*{box-sizing:border-box}
html,body{margin:0;min-height:100%;background:var(--kptu-bg);color:var(--kptu-ink);font-family:-apple-system,BlinkMacSystemFont,"Noto Sans KR","Apple SD Gothic Neo",sans-serif}
body{line-height:1.55}
button,input,select,textarea{font:inherit}
button{cursor:pointer}
.hidden{display:none!important}
#authView{display:none!important}
#appView:not(.kptu-ui-ready):not(.kptu-shell-ready){visibility:hidden!important;pointer-events:none!important}
.shell{min-height:100vh;min-height:100dvh}
.topbar{height:62px;padding:0 max(18px,env(safe-area-inset-left));display:flex;align-items:center;justify-content:space-between;background:var(--kptu-surface);border-bottom:1px solid var(--kptu-border);position:sticky;top:0;z-index:20}
.brand{display:flex;align-items:center;gap:var(--kptu-space-2);color:var(--kptu-ink);text-decoration:none;font-weight:800;white-space:nowrap;flex:0 0 auto}
.brand .leaf{width:28px;height:28px;border-radius:var(--kptu-radius-md);background:var(--kptu-success);color:var(--kptu-on-primary);display:grid;place-items:center;font-size:20px}
.brand-icon{width:34px;height:34px;display:block;object-fit:cover;border-radius:9px;flex:0 0 auto}
.brand b{font-size:11px;color:var(--kptu-link);background:var(--kptu-primary-soft);padding:3px 7px;border-radius:var(--kptu-radius-pill)}
.top-actions{display:flex;gap:var(--kptu-space-2);align-items:center}
.user-badge{border:0;background:transparent;padding:6px 8px;border-radius:var(--kptu-radius-md);font-size:12px;color:var(--kptu-muted);max-width:190px;white-space:normal;overflow-wrap:anywhere;text-align:left;line-height:1.3;cursor:pointer}
.user-badge:hover,.user-badge:focus-visible{background:var(--kptu-primary-soft);color:var(--kptu-ink)}
main{max-width:1120px;margin:0 auto;padding:34px 20px 80px}
.eyebrow{font-size:11px;letter-spacing:.12em;font-weight:800;color:var(--kptu-link);margin-bottom:var(--kptu-space-2)}
.auth-wrap{min-height:calc(100vh - 140px);display:grid;place-items:center}
.auth-card,.center-card{width:min(100%,470px);background:var(--kptu-surface);border:1px solid var(--kptu-border);border-radius:var(--kptu-radius-lg);padding:var(--kptu-space-6);box-shadow:var(--kptu-shadow-float)}
.auth-card h1{font-size:28px;line-height:1.25;letter-spacing:-.8px;margin:0 0 var(--kptu-space-3);font-weight:800}
.auth-card>p,.center-card>p{color:var(--kptu-muted);font-size:14px;margin:0 0 var(--kptu-space-5)}
.auth-tabs{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);background:var(--kptu-primary-soft);border-radius:var(--kptu-radius-md);padding:var(--kptu-space-1);margin-bottom:var(--kptu-space-4)}
.tab{border:0;background:transparent;min-height:var(--kptu-control-height);padding:0 var(--kptu-space-3);border-radius:var(--kptu-radius-sm);font-weight:700;color:var(--kptu-muted)}
.tab.active{background:var(--kptu-surface);color:var(--kptu-primary-text);box-shadow:0 1px 4px rgba(20,33,48,.07)}
label{display:flex;flex-direction:column;gap:var(--kptu-space-2);font-size:12px;font-weight:700;color:var(--kptu-muted);margin:var(--kptu-space-3) 0}
input,select,textarea{width:100%;min-height:var(--kptu-control-height);border:1px solid var(--kptu-border-strong);border-radius:var(--kptu-radius-md);background:var(--kptu-surface);color:var(--kptu-ink);padding:8px var(--kptu-space-3);outline:none}
input:focus,select:focus,textarea:focus{border-color:var(--kptu-primary-ink);box-shadow:0 0 0 3px var(--kptu-primary-soft)}
textarea{resize:vertical}
.primary,.secondary,.ghost,.danger,.mini{min-height:var(--kptu-control-height);border:1px solid transparent;border-radius:var(--kptu-radius-md);padding:0 var(--kptu-space-3);display:inline-flex;align-items:center;justify-content:center;gap:var(--kptu-space-1);font-size:var(--ds-text-button,13px);font-weight:var(--ds-weight-medium,500);line-height:1;white-space:nowrap;text-decoration:none}
.mini{min-height:var(--kptu-action-compact-height);font-size:11px;padding:0 var(--kptu-space-2);background:var(--kptu-surface);color:var(--kptu-muted);border-color:var(--kptu-border)}
.primary{background:var(--kptu-primary);color:var(--kptu-on-primary)}
.primary:hover{background:var(--kptu-primary-hover)}
.secondary{background:var(--kptu-surface);color:var(--kptu-ink);border-color:var(--kptu-border-strong)}
.secondary:hover,.mini:hover{background:var(--kptu-surface-subtle);border-color:var(--kptu-border-strong)}
.ghost{background:transparent;color:var(--kptu-muted)}
.ghost:hover{background:var(--kptu-primary-soft);color:var(--kptu-ink)}
.danger{background:var(--kptu-danger);color:var(--kptu-on-primary)}
.primary:focus-visible,.secondary:focus-visible,.ghost:focus-visible,.danger:focus-visible,.mini:focus-visible,.icon-btn:focus-visible{outline:2px solid var(--kptu-info);outline-offset:2px}
button:disabled,[aria-disabled="true"]{opacity:.5;cursor:not-allowed}
.wide{width:100%;margin-top:var(--kptu-space-2)}
.status{font-size:12px;color:var(--kptu-muted);min-height:18px;margin-top:var(--kptu-space-2)}
.status.error{color:var(--kptu-danger)}
.status.ok{color:var(--kptu-success)}
.notice{padding:10px var(--kptu-space-3);background:var(--kptu-success-soft);color:var(--kptu-success);border-radius:var(--kptu-radius-md);font-size:12px;margin:var(--kptu-space-3) 0}
.center-card{margin:11vh auto}
/* APP-다시열림: 새로고침·복원으로 다시 여는 중에는 큰 카드 대신 맨 위 가는 줄 하나(문구는 화면 읽기용으로만 남김). */
#bootView.boot-quiet{position:fixed;top:0;left:0;right:0;z-index:20;width:auto;height:3px;margin:0;padding:0;border:0;border-radius:0;box-shadow:none;background:transparent;overflow:hidden}
#bootView.boot-quiet>*{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}
#bootView.boot-quiet::before{content:"";display:block;width:40%;height:3px;background:var(--kptu-accent);opacity:.7;animation:kptu-boot-quiet 1.1s ease-in-out infinite}
@keyframes kptu-boot-quiet{from{transform:translateX(-100%)}to{transform:translateX(250%)}}
@media (prefers-reduced-motion:reduce){#bootView.boot-quiet::before{width:100%;opacity:.4;animation:none}}
.head-actions{display:flex;gap:var(--kptu-space-2);align-items:center;flex-wrap:wrap}
.view-tabs{display:flex;gap:var(--kptu-space-5);border-bottom:1px solid var(--kptu-border);margin-bottom:var(--kptu-space-4)}
.view-tab{border:0;background:transparent;padding:10px 2px;border-bottom:2px solid transparent;color:var(--kptu-muted);font-weight:700}
.view-tab.active{color:var(--kptu-primary-text);border-bottom-color:var(--kptu-primary)}
.toolbar{display:flex;align-items:center;gap:var(--kptu-space-2);margin-bottom:var(--kptu-space-4)}
.search{flex:1}
.toolbar select{width:150px}
.page-list{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--kptu-space-3)}
.page-card,.group-card,.panel,.project-card{background:var(--kptu-surface);border:1px solid var(--kptu-border);border-radius:var(--kptu-radius-lg);box-shadow:none}
.page-card{padding:var(--kptu-space-4);display:flex;flex-direction:column;gap:var(--kptu-space-3)}
.page-card:hover{border-color:var(--kptu-border-strong);box-shadow:none}
.page-meta{display:flex;justify-content:space-between;align-items:center;gap:var(--kptu-space-2)}
.badges{display:flex;gap:var(--kptu-space-1);flex-wrap:wrap}
.badge{font-size:11px;font-weight:700;padding:3px 8px;border-radius:var(--kptu-radius-pill);background:var(--kptu-primary-soft);color:var(--kptu-muted)}
.badge.published{background:var(--kptu-success-soft);color:var(--kptu-success)}
.badge.review{background:var(--kptu-warning-soft);color:var(--kptu-warning)}
.badge.draft,.badge.archived{background:var(--kptu-primary-soft);color:var(--kptu-muted)}
.badge.public{background:var(--kptu-info-soft);color:var(--kptu-info)}
.badge.groups,.badge.workspace{background:#f3f0f7;color:var(--kptu-accent)}
.badge.private{background:var(--kptu-danger-soft);color:var(--kptu-danger)}
.page-card h3{font-size:15px;line-height:1.4;margin:0;font-weight:700}
.page-card p{color:var(--kptu-muted);font-size:13px;margin:0;min-height:38px}
.page-card-foot{display:flex;align-items:center;justify-content:space-between;gap:var(--kptu-space-2);margin-top:auto}
.updated{font-size:11px;color:var(--kptu-faint)}
.card-actions{display:flex;gap:var(--kptu-space-2);align-items:center;flex-wrap:wrap}
.empty,.state-empty,.state-error,.state-loading{padding:var(--kptu-space-6);border:1px dashed var(--kptu-border-strong);border-radius:var(--kptu-radius-lg);text-align:center;color:var(--kptu-muted);background:var(--kptu-surface)}
.state-error{color:var(--kptu-danger);background:var(--kptu-danger-soft)}
.section-head,.panel-head{display:flex;justify-content:space-between;align-items:center;gap:var(--kptu-space-3);margin-bottom:var(--kptu-space-4)}
.section-head.actions-only{justify-content:flex-end;margin-bottom:var(--kptu-space-3)}
.section-head h2,.panel-head h2{margin:0;font-size:20px;line-height:1.35;font-weight:800}
.section-head h3,.panel-head h3{margin:0;font-size:15px;line-height:1.4;font-weight:700}
.section-head p,.panel-head p{margin:var(--kptu-space-1) 0 0;color:var(--kptu-muted);font-size:13px}
.group-list{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:var(--kptu-space-3)}
.group-card{padding:var(--kptu-space-4)}
.group-card b{display:block;margin-bottom:var(--kptu-space-1)}
.group-card span{font-size:12px;color:var(--kptu-muted)}
.modal{position:fixed;inset:0;background:rgba(18,26,35,.46);z-index:50;display:grid;place-items:center;padding:var(--kptu-space-5)}
.modal-card{background:var(--kptu-surface);border:1px solid var(--kptu-border);border-radius:var(--kptu-radius-lg);width:min(100%,1040px);max-height:94vh;overflow:auto;box-shadow:var(--kptu-shadow-modal)}
.small-card{width:min(100%,460px);padding:var(--kptu-space-5)}
.editor-card{padding:var(--kptu-space-5)}
.modal-head{display:flex;align-items:flex-start;justify-content:space-between;gap:var(--kptu-space-3);margin-bottom:var(--kptu-space-3)}
.modal-head h2{margin:0;font-size:20px;line-height:1.35;font-weight:800}
.icon-btn{border:1px solid var(--kptu-border);background:var(--kptu-surface-subtle);color:var(--kptu-muted);width:32px;height:32px;border-radius:var(--kptu-radius-md);font-size:20px;line-height:1;display:grid;place-items:center;padding:0}
.editor-grid{display:grid;grid-template-columns:minmax(0,1fr) 280px;gap:var(--kptu-space-5)}
.body-editor{min-height:430px;line-height:1.7;font-family:inherit}
.editor-side{border-left:1px solid var(--kptu-border);padding-left:var(--kptu-space-4)}
.permission-box,.revision-box{border-top:1px solid var(--kptu-border);padding-top:var(--kptu-space-4);margin-top:var(--kptu-space-4);font-size:12px}
.permission-box>b,.revision-box>b{display:block;margin-bottom:var(--kptu-space-2)}
.group-check{display:flex;align-items:center;gap:var(--kptu-space-2);margin:var(--kptu-space-2) 0;font-weight:600}
.side-actions{display:flex;flex-direction:column;gap:var(--kptu-space-2);margin-top:var(--kptu-space-4)}
.link-button{text-align:center;text-decoration:none;font-size:13px}
.revision-list{color:var(--kptu-muted);font-size:11px;display:flex;flex-direction:column;gap:var(--kptu-space-1)}
.modal-foot{display:flex;align-items:center;justify-content:space-between;gap:var(--kptu-space-3);border-top:1px solid var(--kptu-border);margin-top:var(--kptu-space-4);padding-top:var(--kptu-space-4)}
.modal-foot>div:last-child{display:flex;gap:var(--kptu-space-2)}
.result-box{margin-top:var(--kptu-space-3);background:var(--kptu-surface-subtle);border:1px solid var(--kptu-border);border-radius:var(--kptu-radius-md);padding:var(--kptu-space-3);font-size:12px;word-break:break-all}
.result-box a{color:var(--kptu-link)}
/* UI-작은알림자리(2026-10-28 명진 결정 10:52): 작은 알림(#toast·.kptu-undo-notice·.kptu-notice)은 모두 화면 위쪽 가운데,
   맨 위 줄(폰 머리줄·PC 상단 줄) 바로 아래·목록 위에 뜬다. 폰 하단바·손가락에 가리지 않게. 맨 위 알림 줄(notice-bar.js, 새 버전 안내 등)이 떠 있으면 그 아래로.
   자리는 --kptu-notice-top 하나로 정하고, 화면마다 bottom을 따로 올리던 덮어쓰기는 없앴다(docs/design-decisions.md '작은 알림 자리'). */
:root{--kptu-notice-top:calc(env(safe-area-inset-top,0px) + 56px)}
body.kptu-notice-bar-open{--kptu-notice-top:calc(env(safe-area-inset-top,0px) + 56px + var(--kptu-notice-bar-height,33px))}
/* 되돌리기 알림이 떠 있는 동안 뒤에 뜬 작은 알림·#toast는 한 줄 아래로(겹쳐 [되돌리기]를 가리지 않게). */
body:has(.kptu-undo-notice) :is(.toast,.kptu-notice){top:calc(var(--kptu-notice-top) + 44px)}
/* 위쪽 알림 글 부분은 아래 목록(거르기 칩 등) 누르기를 막지 않는다. [되돌리기]·✕만 눌린다. */
.kptu-undo-notice,.kptu-notice{pointer-events:none}
.kptu-undo-notice button,.kptu-notice button{pointer-events:auto}
.toast{position:fixed;left:50%;top:var(--kptu-notice-top);bottom:auto;transform:translateX(-50%);max-width:min(92vw,520px);box-sizing:border-box;background:var(--kptu-ink);color:var(--kptu-surface);padding:7px var(--kptu-space-3);border-radius:var(--kptu-radius-md);font-size:12px;z-index:100;box-shadow:var(--kptu-shadow-float)}
/* BUG-바구니연결해제·UI-작은알림자리: one 2-second undo notice (basket-record-delete.js offerUndoNotice), at the top like every small notice. */
.kptu-undo-notice{position:fixed;left:50%;top:var(--kptu-notice-top);bottom:auto;transform:translateX(-50%);z-index:110;display:flex;align-items:center;gap:var(--kptu-space-2);width:max-content;max-width:calc(100vw - 32px);box-sizing:border-box;padding:4px 4px 4px var(--kptu-space-3);background:var(--kptu-ink);color:var(--kptu-surface);border-radius:var(--kptu-radius-md);box-shadow:var(--kptu-shadow-float);font-size:13px;line-height:1.4}
.kptu-undo-notice[data-overlap-notice]{flex-wrap:wrap;justify-content:flex-end}
.kptu-undo-notice [data-undo-text]{min-width:0;overflow-wrap:anywhere}
.kptu-undo-notice [data-undo-action]{position:relative;flex:0 0 auto;min-height:28px;min-width:44px;padding:0 10px;border:0;border-radius:var(--kptu-radius-md);background:transparent;color:inherit;font:inherit;font-weight:700;text-decoration:underline;text-underline-offset:3px;cursor:pointer}
.kptu-undo-notice [data-undo-action]::after{content:"";position:absolute;left:0;right:0;top:calc(50% - var(--kptu-touch-target,44px) / 2);height:var(--kptu-touch-target,44px)}
.kptu-undo-notice [data-undo-action]:focus-visible{outline:2px solid currentColor;outline-offset:-4px}
@media(max-width:760px){
  main{padding:22px 12px 60px}
  .topbar{height:56px;padding:0 12px}
  .brand b{display:none}
  .user-badge{display:none}
  .auth-card,.center-card{padding:var(--kptu-space-5)}
  .auth-card h1{font-size:24px}
  .head-actions{width:100%}
  .page-list,.group-list{grid-template-columns:minmax(0,1fr)}
  .toolbar{flex-direction:column;align-items:stretch}
  .toolbar select{width:100%}
  .modal{padding:0;align-items:end}
  .modal-card{border-radius:var(--kptu-radius-lg) var(--kptu-radius-lg) 0 0;max-height:96vh;width:100%;padding:var(--kptu-space-4)}
  .editor-grid{grid-template-columns:minmax(0,1fr)}
  .editor-side{border-left:0;border-top:1px solid var(--kptu-border);padding-left:0;padding-top:var(--kptu-space-3)}
  .body-editor{min-height:300px}
  .modal-foot{position:sticky;bottom:0;background:var(--kptu-surface);padding-bottom:calc(4px + env(safe-area-inset-bottom))}
}

/* Keep painted bounds unchanged; the transparent pseudo-element belongs to the button. */
:where(button.primary,button.secondary,button.ghost,button.danger,button.mini,button.icon-btn,button.ci-delete,.gt-undo-item button){position:relative;scroll-margin:6px}
:where(button.primary,button.secondary,button.ghost,button.danger,button.mini,button.icon-btn,button.ci-delete,.gt-undo-item button)::after{content:"";position:absolute;inset:min(0px,calc((100% - 44px)/2));min-width:44px;min-height:44px}
/* Compact adjacent actions cannot safely share a 44px target without moving layout. */
:where(.card-actions,.head-actions,.page-card-foot,.side-actions,.auth-tabs,.compact-entry-actions,.ps3-row-actions,.ps3-page-actions,.meeting-file-actions,.mrd-task-actions,.ps3-pg-quick) :is(.mini,.icon-btn)::after{content:none}
/* Calendar cells have their own interaction contract. */
.calendar-grid button::after,.cmv-grid button::after{content:none}

/* The connection button sits directly below the calendar disclosure. */
#googleConnectBtn::after{content:none}

/* List role typography. Text action buttons share the task-tab size ceiling. */
:is(#projectsView,#meetingsView,#pagesView,#teamView) button:is(.primary,.secondary):not(.mini){font-size:var(--kptu-text-meta)}
:is(#projectsView,#meetingsView,#pagesView,#teamView) button.mini{font-size:var(--kptu-text-meta)}
:is(#projectsView,#meetingsView,#pagesView,#teamView) :is(.updated,.muted,.empty.compact){font-size:var(--kptu-text-meta)}
:is(#projectsView,#meetingsView,#pagesView,#teamView) .empty:not(.compact){font-size:var(--kptu-text-body)}
/* UI-팝업머리고정: one rule for every popup (.modal-card) on phone and PC. The title line with its close (×) stays at the top
   while the body scrolls under it. The shadow is the card colour and covers the card's top padding above the stuck line, so
   scrolled text never shows there; it is clipped by the card. :where keeps this at one class so a popup's own head rule
   (project detail .ps3-modal-head, the PC task pane #gtDetailPane) still sets its own offset. Save stays where it is: in the
   bottom row (.modal-action-footer) for popups, in the title line only for the PC task pane. */
:where(.modal-card)>.modal-head{position:sticky;top:0;z-index:3;background:var(--kptu-surface);box-shadow:0 -24px 0 24px var(--kptu-surface)}
#pagesView .badge{font-size:var(--kptu-text-meta)}


/* CAL-버튼고정: reserve the footer height in flow; cover the shared 24px card bottom padding. */
.modal-action-footer{position:sticky;bottom:calc(-1 * var(--kptu-space-5));z-index:2;background:var(--kptu-surface);border-top:1px solid var(--kptu-border);margin-top:var(--kptu-space-3);margin-bottom:calc(-1 * var(--kptu-space-5));padding:var(--kptu-space-2) 0 calc(var(--kptu-space-5) + var(--kptu-space-1) + env(safe-area-inset-bottom))}
/* UI-저장자리(2026-10-27 명진 요청): 팝업 아래 줄은 버튼이 오른쪽 아래([취소] 왼쪽, [저장] 맨 오른쪽). 상태 글은 버튼 줄 위 한 줄. 줄 모양은 ui-standard.css의 .save-row 규칙과 같다. */
.modal-action-footer{display:flex;flex-wrap:wrap;align-items:center;justify-content:flex-end;gap:var(--kptu-space-2)}
.modal-action-footer>.status{flex:1 1 100%;margin:0;overflow-wrap:anywhere}
.modal-action-footer>div:not(.status){flex:1 1 100%;min-width:0}
.modal-action-footer>.status:empty{display:none}
.modal-action-footer .wide{width:auto;margin:0}
/* 할 일 창: [완료][삭제]는 줄 왼쪽, [저장]은 같은 줄 오른쪽 끝. */
.modal-action-footer>.tl-detail-actions{flex:1 1 0;margin:0}
.modal-action-footer .tl-detail-actions .tl-danger{margin-left:0}
.modal-action-footer[data-keyboard-open]{position:static}

/* UI-더보기제목줄: 상세의 ⋯는 혼자 한 줄을 차지하지 않고 제목(없으면 첫 줄) 오른쪽 끝에 둔다. 공용 규칙 하나:
   <div class="kptu-title-line"><제목 또는 첫 줄 글자/><⋯ 버튼/></div>. 글자는 ⋯ 옆으로 비켜 줄바꿈하고, ⋯는 줄 위쪽에 붙는다. 색·크기는 각 화면의 ⋯ 버튼 규칙을 그대로 쓴다. */
.kptu-title-line{display:flex;align-items:flex-start;gap:var(--kptu-space-2);min-width:0;margin:0 0 6px}
.kptu-title-line>:first-child{flex:1 1 auto;min-width:0;margin:0;overflow-wrap:anywhere}
.kptu-title-line>:not(:first-child){flex:none;margin-top:-4px}

/* PRJ-화면다듬기: one 4-line text clamp (text-clamp.js). Open = .is-open; the organization record list adds a [더보기]/[접기] button under the text. */
.kptu-clamp{display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:4;line-clamp:4;overflow:hidden}
.kptu-clamp.is-open{display:block;-webkit-line-clamp:unset;line-clamp:unset;overflow:visible}
.kptu-clamp-more{display:inline-flex;align-items:center;min-height:44px;margin:0;padding:0 4px;border:0;background:transparent;color:var(--kptu-muted);font:inherit;font-size:var(--ds-text-meta,12px);cursor:pointer}
.kptu-clamp-more:focus-visible{outline:2px solid var(--kptu-info);outline-offset:-2px;border-radius:var(--kptu-radius-md)}
/* CAL-저장본먼저: one small line on screens that show this device's saved copy first (data-freshness.js draws it):
   새로 불러오는 중 / 최신 아님 · 마지막 확인 HH:MM [다시 시도]. Muted while refreshing, danger ink when not the latest. */
.data-freshness{display:flex;align-items:center;flex-wrap:wrap;gap:6px;margin:4px 0;font-size:var(--ds-text-meta,13px);color:var(--kptu-muted)}
.data-freshness[hidden]{display:none}
.data-freshness.data-freshness-warn{color:var(--kptu-danger)}
.data-freshness .data-freshness-retry{min-height:28px}
/* JOURNAL-하루개편 ⑥: 업무일지에서 누른 기록이 조직·프로젝트 화면에서 열리면 그 기록을 잠깐(1.6초) 강조한다. journal.js가 붙였다 뗀다. */
[data-journal-flash]{ animation:kptu-journal-flash 1.6s ease-out 1; border-radius:var(--kptu-radius-md); }
@keyframes kptu-journal-flash{ 0%,35%{ background-color:var(--ds-kind-journal-soft); box-shadow:0 0 0 2px var(--ds-kind-journal-ink); } 100%{ background-color:transparent; box-shadow:0 0 0 0 transparent; } }
@media(prefers-reduced-motion:reduce){ [data-journal-flash]{ animation-timing-function:steps(1,end); } }

/* 공용: 작은 [복사] 아이콘(summary-copy.js)과 상세 화면의 '‹ 목록' 돌아가기 글자(UI-돌아가기글자). 버튼처럼 크지 않게, 누르는 자리만 넓힌다. */
.copy-mini{position:relative;flex:none;display:inline-flex;align-items:center;justify-content:center;width:24px;height:24px;min-height:0;margin:0;padding:0;border:0;border-radius:var(--ds-radius-control,6px);background:transparent;color:var(--kptu-muted);cursor:pointer}
.copy-mini::after{content:"";position:absolute;inset:-10px}
.copy-mini:hover{background:var(--kptu-surface-subtle)}
.copy-mini:focus-visible{outline:2px solid var(--kptu-info);outline-offset:-2px}
button.back-text{position:relative;display:inline-flex;align-items:center;height:32px;min-height:0;margin:0 0 0 -8px;padding:0 8px;border:0;border-radius:0;background:transparent;color:var(--kptu-link);font:inherit;font-size:var(--kptu-text-body);cursor:pointer;white-space:nowrap}
button.back-text::after{content:"";position:absolute;inset:-8px -6px}
button.back-text:focus-visible{outline:2px solid var(--kptu-info);outline-offset:-2px}
/* UI-모바일고르기칸 (select-menu.js): 고르기 칸(select)을 누르면 휴대폰 기본 창 대신 칸 바로 아래에 펼쳐지는 작은 목록. 칸과 같은 폭, 뒤 화면은 어둡게 하지 않음. */
.kptu-select-inset{position:fixed;left:0;bottom:0;width:0;height:calc(var(--kptu-mobile-tab-height,0px) + var(--kptu-switch-dock,0px) + env(safe-area-inset-bottom,0px));visibility:hidden;pointer-events:none}
.kptu-select-menu{position:fixed;inset:auto;margin:0;box-sizing:border-box;padding:2px;overflow-y:auto;overscroll-behavior:contain;border:var(--ds-line-width,1px) solid var(--ds-line,var(--kptu-border-strong));border-radius:var(--ds-radius-control,8px);background:var(--kptu-surface);color:var(--kptu-ink);box-shadow:var(--kptu-shadow-float);z-index:1700;outline:0}
.kptu-select-menu[hidden]{display:none}
.kptu-select-opt{display:flex;align-items:center;justify-content:space-between;gap:8px;box-sizing:border-box;min-height:32px;padding:0 8px;border-radius:calc(var(--ds-radius-control,8px) - 2px);font-size:14px;line-height:1.3;cursor:pointer;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.kptu-select-opt.is-active{background:var(--kptu-primary-soft)}
.kptu-select-opt[aria-selected="true"]{font-weight:700;color:var(--kptu-primary-ink,var(--kptu-ink))}
.kptu-select-opt[aria-selected="true"]::after{content:"✓";flex:0 0 auto;font-weight:700}
.kptu-select-opt[aria-disabled="true"]{color:var(--kptu-muted);cursor:default}
.kptu-select-group{padding:6px 8px 2px;font-size:12px;color:var(--kptu-muted)}
/* UI-작은알림 (2026-10-28): 브라우저 기본 알림창 대신 쓰는 공용 작은 알림(small-notice.js notify)·작은 확인창(askConfirm). 하단바 위, 톤다운. */
.kptu-notice{position:fixed;z-index:110;left:50%;transform:translateX(-50%);top:var(--kptu-notice-top);bottom:auto;box-sizing:border-box;width:max-content;max-width:min(calc(100vw - 32px),520px);display:flex;align-items:center;flex-wrap:nowrap;gap:4px 10px;padding:7px 8px 7px 12px;border-radius:var(--kptu-radius-md);background:var(--kptu-ink);color:var(--kptu-surface);font-size:12px;line-height:1.4;box-shadow:var(--kptu-shadow-float)}
.kptu-notice[hidden]{display:none}
.kptu-notice.error{background:var(--kptu-danger)}
/* S48-52(요청함 11/03 07:43·07:44 ①): 글과 버튼·[✕]는 한 줄(글 왼쪽, 버튼 오른쪽). 글이 길면 글 칸 안에서 낱말 단위로 줄바꿈(한글 keep-all).
   작은 설명(note)·입력칸이 있는 알림만 다음 줄로 내린다. 폭은 폰 양쪽 16px까지. */
.kptu-notice:has(.kptu-notice-note,.kptu-notice-input){flex-wrap:wrap}
.kptu-notice-text{flex:1 1 auto;min-width:0;word-break:keep-all;overflow-wrap:anywhere}
.kptu-notice>button{flex:0 0 auto;white-space:nowrap}
.kptu-notice-undo,.kptu-notice-close{border:0;background:transparent;color:inherit;font:inherit;font-weight:700;padding:2px 4px;min-height:24px;cursor:pointer}
.kptu-notice-undo{text-decoration:underline;text-underline-offset:2px}
.kptu-notice-close{opacity:.7;font-weight:400}
/* UI-고르기줄 (S48-54, 요청함 11/03 07:43·07:44): 여러 개 고르기 줄·크게 보기 아래 줄의 공용 부품(app/action-bar.mjs). 이 화면들은 이 규칙 하나를 쓴다:
   사진 여러 장 고르기·휴지통 고르기(.photos-act), 크게 보기(.diary-viewer-actions, 사진·일기), 노트 고르기(.nx-select-bar), 자료실 고르기(.lu-select-bar).
   ① 버튼(.kptu-act)은 줄 폭을 같은 너비 칸으로 나눠 쓰고 칸 사이 간격이 같다. 넓은 화면(폴드 펼침·PC)은 칸 최대 120px이라 너무 벌어지지 않는다.
   ② 칸은 가장 긴 낱말보다 좁아지지 않는다(낱말 단위 줄바꿈 keep-all) — 폴드 접음 폭에서도 글자가 잘리지 않고, 모자라면 다음 줄(위쪽 글자 줄만).
   ③ 아이콘 줄(-icon, 한 줄): 폰은 아이콘 위·글자 아래, 761px~는 한 줄 나란히. 아이콘은 글자와 같은 색의 글자 모양·선 아이콘.
     글자 줄(-text, 위쪽 고르기 줄 안의 버튼 묶음): 테두리 없는 작은 글자, 같은 너비 칸(최소 56px)으로 나누고 모자라면 다음 줄도 같은 칸.
   ④ 지우기(.kptu-act-danger)도 다른 버튼과 같은 색·같은 선 아이콘(S49-5: 빨강은 되돌릴 수 없는 마지막 확인 버튼에만). 누르는 범위는 늘 44px(::after). 줄의 자리(아래 붙기·위 붙기)·바탕은 화면 CSS가 맡는다. */
.kptu-actbar{display:flex;align-items:center;justify-content:space-evenly;min-width:0}
#appView .kptu-actbar>button.kptu-act{position:relative;box-sizing:border-box;flex:1 1 0;min-width:min-content;max-width:120px;justify-content:center;margin:0;border:0;border-radius:var(--ds-radius-control,6px);background:transparent;box-shadow:none;font-weight:400;text-align:center;white-space:normal;word-break:keep-all;-webkit-tap-highlight-color:transparent}
#appView .kptu-actbar>button.kptu-act::after{content:"";position:absolute;left:0;right:0;top:calc(50% - var(--kptu-touch-target,44px) / 2);height:var(--kptu-touch-target,44px)}
#appView .kptu-actbar>button.kptu-act[hidden]{display:none}
#appView .kptu-actbar>button.kptu-act:disabled{opacity:.45;cursor:default}
#appView .kptu-actbar>button.kptu-act:focus-visible{outline:2px solid currentColor;outline-offset:-2px}
#appView .kptu-actbar-icon>button.kptu-act{display:flex;flex-direction:column;align-items:center;gap:1px;height:auto;min-height:40px;padding:2px;color:inherit;font-size:11px;line-height:1.2}
#appView .kptu-actbar-icon .kptu-act-ic{display:inline-flex;align-items:center;justify-content:center;width:18px;height:18px;font-size:16px;line-height:1}
#appView .kptu-actbar-icon .kptu-act-ic svg{display:block;width:16px;height:16px}
/* PHOTO-아래줄정돈(S49-34): [공유 ▾]·[편집 ▾] 글자 옆 작은 ▾ */
#appView .kptu-actbar-icon .kptu-act-caret{font-size:9px;margin-left:2px;opacity:.7}
.kptu-actbar-text{display:grid;grid-template-columns:repeat(auto-fit,minmax(var(--kptu-act-min,56px),1fr));justify-items:center;align-items:center;flex:1 1 auto;min-width:0}
#appView .kptu-actbar-text>button.kptu-act{display:inline-flex;align-items:center;width:100%;height:auto;min-height:var(--ds-compact-height-sm,28px);padding:2px;color:var(--kptu-ink);font-size:var(--ds-compact-text,13px);line-height:1.25}
@media(min-width:761px){#appView .kptu-actbar-icon>button.kptu-act{flex-direction:row;gap:4px;min-height:var(--ds-compact-height,32px);padding:0 4px;font-size:var(--ds-compact-text,13px)}}
.kptu-notice-note{flex:1 0 100%;order:5;font-size:11px;opacity:.75}
/* SHARE-바로넣기: 알림 안 한 줄 입력칸([메모 달기]). 알림 글처럼 촘촘하게, 눌러서 쓸 수 있게(바탕 알림은 누르기를 통과시킴). */
.kptu-notice input.kptu-notice-input{pointer-events:auto;flex:1 1 160px;min-width:0;height:28px;box-sizing:border-box;margin:0;padding:0 8px;font:inherit;font-size:13px;color:var(--kptu-ink);background:var(--kptu-surface);border:0;border-radius:var(--kptu-radius-sm,6px)}
.kptu-ask{position:fixed;z-index:61;box-sizing:border-box;padding:10px 12px;border:1px solid var(--kptu-border-strong);border-radius:var(--kptu-radius-md);background:var(--kptu-surface);color:var(--kptu-ink);box-shadow:var(--kptu-shadow-float);font-size:13px;overflow:auto}
.kptu-ask.kptu-ask-center{left:50%;transform:translateX(-50%);width:min(92vw,300px);bottom:calc(var(--kptu-mobile-tab-height,0px) + var(--kptu-switch-dock,0px) + env(safe-area-inset-bottom,0px) + 12px)}
.kptu-ask-text{margin:0 0 4px;line-height:1.45;white-space:pre-line}
.kptu-ask-note{display:block;margin:0 0 6px;font-size:11px;color:var(--kptu-muted)}
.kptu-ask-actions{display:flex;justify-content:flex-end;gap:6px;margin-top:6px}
.kptu-ask-actions button{min-height:var(--kptu-action-compact-height)}
/* S48-17 작은 고르기창(askChoice): 줄마다 [아이콘 | 굵은 글 + 작은 설명]. 위험한 줄은 빨간 글자. 맨 아래 흐린 글자 한 줄. */
.kptu-ask.kptu-ask-choice{padding:6px}
.kptu-ask-pick{display:flex;align-items:flex-start;gap:8px;width:100%;margin:0;padding:6px;border:0;border-radius:var(--kptu-radius-sm,6px);background:none;color:var(--kptu-ink);font:inherit;text-align:left;cursor:pointer}
.kptu-ask-pick:hover:not(:disabled),.kptu-ask-pick:focus-visible{background:var(--kptu-surface-subtle)}
.kptu-ask-pick:disabled{opacity:.45;cursor:default}
.kptu-ask-pick-ic{flex:0 0 18px;display:grid;place-items:center;height:18px;color:var(--kptu-primary-text)}
.kptu-ask-pick.is-danger,.kptu-ask-pick.is-danger .kptu-ask-pick-ic{color:var(--kptu-danger)}
.kptu-ask-pick-t{display:flex;flex-direction:column;gap:1px;min-width:0}
.kptu-ask-pick-t b{font-weight:600;font-size:13px}
.kptu-ask-pick-t small{font-size:11px;line-height:1.35;color:var(--kptu-muted)}
.kptu-ask-foot{margin:4px 6px 2px}
.kptu-ask-field{display:block;box-sizing:border-box;width:100%;min-height:var(--kptu-action-compact-height);margin:4px 0 0;font:inherit}
/* 폴더 위치 줄 공용 모양(NOTE-탐색기 후속 ⑧): 자료실 '자료실 › … '·노트 '노트 › … ' 들어가기 위 한 줄. 작고 낮게, 길면 가로로 넘김(folder-path.mjs). */
.fp-path{display:flex;align-items:center;gap:2px;margin:2px 0 4px;overflow-x:auto;white-space:nowrap;font-size:var(--ds-text-meta,12px);color:var(--kptu-muted);scrollbar-width:none}
.fp-path[hidden]{display:none}
.fp-path .fp-step{min-height:32px;padding:0 6px;border:0;border-radius:var(--kptu-radius-sm,6px);background:transparent;color:var(--kptu-primary-ink);font:inherit;cursor:pointer}
.fp-path .fp-step:hover,.fp-path .fp-step:focus-visible{background:var(--kptu-surface-subtle)}
.fp-path .fp-here{padding:0 6px;color:var(--kptu-ink);font-weight:600}
.fp-path .fp-sep{color:var(--kptu-muted)}
/* IMG-빈칸(PHOTO-못받은사진 2026-10-29): 그림 칸 하나의 표시(공용 img-slot.js). 받는 중 = 글자 없는 연한 회색 칸, 못 받음 = 같은 칸 가운데 작은 ↻.
   <img>는 다 받은 뒤에만 보인다. 받기에 실패한 그림(data-img-broken)은 어디서든 감춘다(깨진 그림 표시·대체 글자 금지). */
html .img-slot:not([data-img-state="shown"]){background:color-mix(in srgb,var(--kptu-border) 55%,transparent)}
.img-slot:not([data-img-state="shown"]) img,img[data-img-broken],img:not([src]),img[src=""]{visibility:hidden}
.img-slot{position:relative}
.img-slot-preview{position:absolute;inset:0;width:100%;height:100%;object-fit:contain;pointer-events:none}
.img-slot:not([data-img-state="shown"]) img.img-slot-preview[src]{visibility:visible}
html .img-slot[data-img-preview="shown"]:not([data-img-state="shown"]){background:transparent}
.img-slot[data-img-preview] > img:not(.img-slot-preview){position:relative}
.img-slot[data-img-preview="fading"][data-img-state="shown"] > img:not(.img-slot-preview){animation:img-slot-in .24s ease-out}
@keyframes img-slot-in{from{opacity:0}to{opacity:1}}
@media (prefers-reduced-motion:reduce){.img-slot[data-img-preview="fading"][data-img-state="shown"] > img:not(.img-slot-preview){animation:none}}
.img-slot-retry{position:absolute;left:50%;top:50%;z-index:1;transform:translate(-50%,-50%);display:grid;place-items:center;width:20px;height:20px;font-size:13px;line-height:1;color:var(--kptu-muted);cursor:pointer;user-select:none}
.img-slot-retry::after{content:"";position:absolute;inset:-6px}
.img-slot-retry.is-passive{pointer-events:none;cursor:inherit}
.img-slot-retry:focus-visible{outline:2px solid var(--kptu-primary);outline-offset:1px;border-radius:50%}
.img-slot .diary-photo-link{position:absolute;left:0;right:0;bottom:8px;z-index:1;text-align:center}
.act-photo-thumb.img-slot::before{content:none}
/* UI-기다림표시통일(2026-10-29 명진 A안): 기다림·실패·없음 공용 부품(wait-state.js) 하나. 기다림 = 위쪽 가는 줄 + 실제 줄 높이 회색 빈 줄, 글자 없음.
   0.4초 안에 끝나면 아무것도 보이지 않는다(늦은 표시). 회색 빈 줄은 그림 칸(.img-slot 받는 중)과 같은 색. 민트(.notice)는 완료 알림에만. */
.wait{display:grid;gap:6px;padding:4px 0;animation:wait-show 0s linear .4s both}
/* UI-로딩맨위: 칸 안에는 회색 빈 줄만(막대 없음). 칸 폭 가득, 글줄 안 한 칸(.wait-inline)만 예외. */
.wait:not(.wait-inline){box-sizing:border-box;width:100%;align-self:stretch;justify-self:stretch;margin:0}
@keyframes wait-show{from{visibility:hidden}to{visibility:visible}}
.wait-only-bar{display:block}
/* UI-로딩맨위(2026-11-04 명진 결정): 움직이는 로딩 막대는 화면 맨 위 끝 한 곳뿐(wait-state.js 공용 카운터). 아래로 내려도 보이게 fixed, 눌림은 막지 않는다. */
.top-wait{position:fixed;top:0;left:0;right:0;height:3px;z-index:120;overflow:hidden;pointer-events:none;animation:wait-show 0s linear .4s both}
.top-wait-run{position:absolute;top:0;bottom:0;left:0;width:30%;background:var(--kptu-muted);opacity:.75;animation:wait-run 1.2s ease-in-out infinite}
@keyframes wait-run{from{transform:translateX(-100%)}to{transform:translateX(340%)}}
.wait-row{display:block;height:var(--wait-h,20px);border-radius:4px;background:color-mix(in srgb,var(--kptu-border) 55%,transparent)}
.wait-row:nth-child(3n+3){width:72%}
.wait.wait-inline{display:inline;padding:0;color:var(--kptu-muted)}
.wait.wait-inline::after{content:"…"}
.wait.wait-only-bar{padding:0;gap:0;display:block;height:0}
.wait-fail{margin:4px 0;font-size:var(--kptu-text-meta,12px);color:var(--kptu-danger);display:flex;align-items:center;gap:6px;flex-wrap:wrap}
.wait-fail .wait-retry{min-height:24px;padding:0 8px;border:1px solid var(--kptu-border);border-radius:var(--kptu-radius-sm,6px);background:transparent;color:var(--kptu-ink);font-size:var(--kptu-text-meta,12px);font-weight:400;cursor:pointer}
.wait-fail .wait-retry:hover{background:var(--kptu-surface-subtle)}
.wait-fail .wait-retry:focus-visible{outline:2px solid var(--kptu-info);outline-offset:1px}
.wait-empty{margin:4px 0;font-size:var(--kptu-text-meta,12px);color:var(--kptu-muted)}
.wait-empty[hidden]{display:none}
@media (prefers-reduced-motion:reduce){.top-wait-run{animation:none;width:100%;opacity:.25}}
/* UI-창잘림·끌어옮기기: 넓은 화면(761px~)에서 버튼 옆에 뜬 작은 창(data-anchor-side, anchored-popup.js)은 제목 줄을 잡고 끌어 옮긴다.
   제목 왼쪽 작은 손잡이(∷)와 손 모양 커서. 폰 아래 창에는 data-anchor-side가 없어 보이지 않는다. 제목 없는 ⋯ 메뉴 판은 손잡이 없음. */
@media (min-width:761px){
  [data-anchor-side] .anchored-drag-title{cursor:grab;user-select:none;-webkit-user-select:none;touch-action:none}
  [data-anchor-side].anchored-dragging .anchored-drag-title{cursor:grabbing}
  [data-anchor-side] .anchored-drag-title>:first-child::before{content:"∷";display:inline-block;margin-right:6px;font-weight:400;font-size:12px;line-height:1;color:var(--kptu-faint,var(--kptu-muted));vertical-align:1px}
}
/* UI-메뉴잘림(2026-10-30): ⋯·우클릭 메뉴와 버튼 옆 작은 창은 항목을 끝까지 다 보인다. 창보다 정말 길 때만 안쪽 스크롤이 생기고, 그때 아래 끝을 흐리게 해
   '더 있음'을 보인다(anchored-popup.js markScrollMore가 data-scroll-below를 단다. 끝까지 내리면 사라짐). 지우기 같은 위험 항목은 메뉴 맨 끝에 두고 위에 가는 선으로 나눈다. */
[data-scroll-below]{-webkit-mask-image:linear-gradient(to bottom,currentColor calc(100% - 28px),transparent);mask-image:linear-gradient(to bottom,currentColor calc(100% - 28px),transparent)}
[role="group"]>button:is(.basket-menu-danger,.feed-menu-danger,.gt-menu-danger,.lu-menu-danger,.rb-menu-danger,.diary-menu-danger,.ql-menu-danger,.ci-menu-danger,.task-inline-danger,.ps3-record-danger,.od-link-danger,.basket-link-danger):last-child:not(:first-child){box-shadow:inset 0 var(--ds-line-width,1px) 0 var(--ds-line,var(--kptu-border))}
/* APP-공유노트할일: 폰 공유 '웹2 노트'·'웹2 할 일' 작은 창(share-target.js). 한 줄 업데이트 창과 같은 모양(위쪽에 뜸, 하단바에 안 가림), 기한은 낮은 칩 한 줄. */
.share-target-dialog{width:min(520px,calc(100vw - 16px));padding:0;border:1px solid var(--kptu-border);border-radius:var(--kptu-radius-md);background:var(--kptu-surface-subtle);color:var(--kptu-ink)}
.share-target-dialog::backdrop{background:color-mix(in srgb,var(--kptu-ink) 46%,transparent)}
.share-target-head,.share-target-foot{display:flex;align-items:center;gap:var(--kptu-space-2);padding:6px var(--kptu-space-3)}
.share-target-head h2{margin:0;font-size:15px;flex:1}
.share-target-body{display:grid;gap:var(--kptu-space-2);padding:0 var(--kptu-space-3) var(--kptu-space-2)}
.share-target-foot{justify-content:space-between;border-top:1px solid var(--kptu-border)}
.share-target-foot .status{margin:0;font-size:12px;flex:1;min-width:0}
.share-target-dialog input[type="text"],.share-target-dialog select{width:100%;box-sizing:border-box;font-size:14px}
.share-target-dues{display:flex;flex-wrap:wrap;gap:4px}
.share-target-dialog [hidden]{display:none}
.share-target-dues button[aria-pressed="true"]{background:var(--kptu-primary-soft);color:var(--kptu-primary-ink);font-weight:700}
.share-target-what{margin:0;font-size:12px;color:var(--kptu-muted);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
@media (max-width:760px){.share-target-dialog{margin:12px auto auto}}
