:root{
  /* ── Surface ─────────────────────────────────────────────── */
  --canvas:#f6f5f1;              /* the page behind everything — a warm light neutral (2026-09-27 UI refinement) */
  --surface-1:#ffffff;           /* panels, cards, rows */
  --surface-2:#faf9f6;           /* a quiet block inside a panel */
  --surface-3:#f1efea;           /* table head, toolbar, selected row (ink-3 on it 4.5:1) */
  --overlay:rgba(16,34,32,.42);  /* behind a dialog */

  /* ── Ink ─────────────────────────────────────────────────── */
  --ink-1:#183c34;               /* headings, primary values (11.1:1 on canvas) */
  --ink-2:#3c5551;               /* body */
  --ink-3:#5c716e;               /* metadata, captions */
  --ink-inverse:#ffffff;

  /* ── Line ────────────────────────────────────────────────── */
  --line-1:#e7e4dd;              /* hairline between rows */
  --line-2:#d6d2c8;              /* component border */
  --line-3:#b8b3a6;              /* emphasis, hover border */

  /* ── Accent and semantics. One accent; semantics only where meaning demands it. */
  --accent:#28584c;              /* primary buttons and links (white on it 8.1:1) */
  --accent-hover:#1f473e;
  --accent-soft:#e7efec;
  --accent-ink:#28584c;
  --bronze-ink:#8a6535;          /* restrained brand emphasis on light ground only (5.3:1 on white); never an error or approval colour */
  --success:#0b5e55;  --success-soft:#e6f2f0;
  --warning:#8a5a00;  --warning-soft:#fff6df;
  --danger:#9b2c2c;   --danger-soft:#fdecec;
  --info:#2f5486;     --info-soft:#e7effa;
  --focus-ring:#28584c40;

  /* ── Navigation rail (both portals). Green identity; the highlight is a line/focus colour, never small text. */
  --nav-bg:#294b44;              /* the rail */
  --nav-hover:#30574e;           /* a hovered item */
  --nav-selected:#355f55;        /* the current item */
  --nav-line:#3f675e;            /* hairline on the rail */
  --nav-text:#f3f6f4;            /* item label (8.8:1 on the rail, 6.6:1 selected) */
  --nav-text-2:#c7d8d2;          /* captions and icons (6.5:1 on the rail) */
  --nav-highlight:#e6c77c;       /* current-item line and keyboard focus on the rail */

  /* ── Type. One family, a 7-step scale, three weights. ───── */
  --font:Inter,"Pretendard","Malgun Gothic",system-ui,sans-serif;
  --font-num:ui-monospace,"SF Mono",Consolas,monospace;
  --text-caption:13px;   /* timestamps, hints. Use sparingly. */
  --text-label:14px;     /* field labels, chips, table metadata */
  --text-body:16px;      /* default reading size in dense views */
  --text-body-lg:16px;   /* forms, dialog body, comfortable reading */
  --text-card:18px;    /* customer/card heading, separate from input sizing */
  --text-title:16px;     /* panel and card titles */
  --text-section:20px;   /* section headings */
  --text-page:26px;      /* one per screen */
  --weight-normal:400;
  --weight-medium:500;   /* labels, table heads, secondary emphasis */
  --weight-bold:600;     /* titles, primary values, buttons */
  --leading-tight:1.25;
  --leading-normal:1.5;

  /* ── Spacing: 4px micro, 8px rhythm. ─────────────────────── */
  --space-1:4px;  --space-2:8px;  --space-3:12px; --space-4:16px;
  --space-5:20px; --space-6:24px; --space-8:32px; --space-10:40px;

  /* ── Radius: three roles, nothing else. ──────────────────── */
  --radius-control:10px;  /* button, input, chip - D-10 (user 2026-09-29): same roundness as a surface, one radius per screen */
  --radius-surface:10px;  /* card, panel, dialog */
  --radius-pill:999px;    /* badges and counts only */

  /* ── Elevation: flat by default; shadow means "floating". ── */
  --shadow-none:none;
  --shadow-raised:0 1px 2px rgba(16,40,36,.05);
  --shadow-overlay:0 12px 32px rgba(16,40,36,.16);

  /* ── Control sizes. ──────────────────────────────────────── */
  --control-sm:32px; --control-md:40px; --control-lg:44px;
  --icon-sm:16px; --icon-md:18px;

  /* ── Motion: fast and purposeful. ────────────────────────── */
  --motion-find:900ms;
  --motion-fast:120ms; --motion-base:180ms; --ease:cubic-bezier(.2,.6,.3,1);

  /* ── Layers. ─────────────────────────────────────────────── */
  --z-sticky:10; --z-dropdown:40; --z-overlay:80; --z-toast:120;

  /* Legacy aliases kept so existing rules resolve to the new scale. */
  --cb-warn:var(--warning); --cb-warn-bg:var(--warning-soft);
  --cb-danger:var(--danger); --cb-danger-bg:var(--danger-soft);
  --cb-ok:var(--success); --cb-ok-bg:var(--success-soft);
  --cb-line:var(--line-2); --cb-muted:var(--ink-3);
}

@media (prefers-reduced-motion:reduce){:root{--motion-fast:0ms;--motion-base:0ms}}

/* Shared workflow components. Portal styles may refine layout, not token values. */
.cb-inbox{display:grid;gap:var(--space-2);margin:0 0 var(--space-5);padding:0;list-style:none}
.cb-inbox-item{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:var(--space-1) var(--space-3);align-items:center;padding:var(--space-3) var(--space-4);border-bottom:1px solid var(--line-1);border-left:var(--space-1) solid var(--accent);background:var(--surface-1)}
.cb-inbox-item.urgent{border-left-color:var(--danger)}
.cb-inbox-title{font-size:var(--text-body-lg);font-weight:var(--weight-bold);color:var(--ink-1)}
.cb-inbox-meta{grid-column:1;font-size:var(--text-body);color:var(--ink-3)}
.cb-inbox-item>button,.cb-inbox-item>a.button{grid-row:1/3;grid-column:2;min-height:var(--control-lg)}
.cb-inbox-empty{padding:var(--space-4);border:1px dashed var(--line-2);border-radius:var(--radius-surface);color:var(--ink-3);font-size:var(--text-body-lg)}
/* A plain count is neutral-green; only a count the screen knows holds critical work (server severity) is red, and
   it also carries a "!" in its text — never colour alone. */
.cb-count{display:inline-block;min-width:var(--space-6);padding:0 var(--space-2);border-radius:var(--radius-pill);background:var(--accent-soft);color:var(--accent);font-size:var(--text-label);font-weight:var(--weight-bold);text-align:center;overflow-wrap:normal}
.cb-count.critical{background:var(--danger);color:var(--ink-inverse)}
/* D-08-A (C, user iPhone): no double-tap-to-zoom wait on anything tapped - pinch zoom and scrolling still work */
button,a,summary,label,[role=button]{touch-action:manipulation}
/* W2-3A link rule (C decision): a name link inside a list, table or row has no underline - colour and weight set it
   apart, and hover/focus underline it; a link inside running text is always underlined. Row links: .cb-row-link
   or .cb-inbox-title a. Text links: an unclassed a inside p/dd/.help/.note/.cb-banner, or .cb-flow-link anywhere. */
.cb-row-link,.cb-inbox-title a{color:var(--accent-ink);font-weight:var(--weight-bold);text-decoration:none}
.cb-row-link:hover,.cb-row-link:focus-visible,.cb-inbox-title a:hover,.cb-inbox-title a:focus-visible{text-decoration:underline;text-underline-offset:3px}
:where(p,dd,.help,.note,.cb-banner)>a:not([class]),.cb-flow-link{text-decoration:underline;text-underline-offset:3px}
/* W2-2A field errors (shared class contract): .cb-field-error under the field = '!' mark (.cb-field-error-mark) + words,
   and the field itself [aria-invalid=true] gets a danger border - never colour alone. */
.cb-field-error{display:flex;align-items:flex-start;gap:var(--space-2);margin:var(--space-1) 0 var(--space-3);font-size:var(--text-body);font-weight:var(--weight-medium);line-height:var(--leading-normal);color:var(--danger)}
.cb-field-error-mark{flex:none;display:inline-flex;align-items:center;justify-content:center;width:1.5em;height:1.5em;border-radius:var(--radius-pill);background:var(--danger);color:var(--ink-inverse);font-weight:var(--weight-bold)}
input[aria-invalid=true],select[aria-invalid=true],textarea[aria-invalid=true]{border-color:var(--danger);box-shadow:0 0 0 1px var(--danger)}
/* W3-1A detail header (both portals): the status chips and the action buttons are two groups, not one mixed row.
   <div class="cb-detail-side"><div class="cb-detail-status" data-detail-status>chips</div>
   <div class="row cb-detail-actions" data-detail-actions>buttons</div></div> - chips above, buttons below; on a phone
   the side takes the full width, chips start at the left and the buttons split the row evenly. */
.cb-detail-side{display:flex;flex:none;flex-direction:column;align-items:flex-end;gap:var(--space-3)}
/* W3-1A2: when the name and the side do not both fit (long name, enlarged text, a tablet beside the sidebar) the
   side moves under the name instead of squeezing it; the name block asks for 20em before that happens */
.detail-title:has(>.cb-detail-side){flex-wrap:wrap}
.detail-title:has(>.cb-detail-side)>:first-child{flex:1 1 20em;min-width:0}
.detail-title>.cb-detail-side{margin-left:auto}
.cb-detail-status{display:flex;flex-wrap:wrap;justify-content:flex-end;align-items:center;gap:var(--space-2)}
/* the buttons sit side by side in equal columns (the widest label sets both), never stacked by a narrow side */
.row.cb-detail-actions{display:grid;grid-auto-flow:column;grid-auto-columns:1fr;justify-content:end}
/* phone: two buttons share the row; when enlarged text no longer fits two, each takes its own line (auto-fit) */
@media (max-width:760px){.cb-detail-side{align-items:stretch;width:100%}.cb-detail-status{justify-content:flex-start}
  .row.cb-detail-actions{grid-auto-flow:row;grid-template-columns:repeat(auto-fit,minmax(min(100%,9em),1fr))}}
button.link.back{display:inline-flex;align-items:center;min-height:var(--control-lg);line-height:var(--leading-normal);padding:var(--space-2) var(--space-4);margin:0 0 var(--space-5);border:1px solid var(--line-2);border-radius:var(--radius-control);background:var(--surface-1);color:var(--ink-1);font-size:var(--text-body-lg);font-weight:var(--weight-medium);text-decoration:none;box-shadow:none}
button.link.back:hover,button.link.back:focus-visible{background:var(--accent-soft);border-color:var(--accent)}
/* Korean words stay whole when a line breaks; only a word longer than its line breaks inside (AGENTS 반응형 문장 배치).
   Table cells keep numbers and long values whole for their column's minimum width. */
body{word-break:keep-all;overflow-wrap:anywhere}
td,th{overflow-wrap:break-word}
/* time zone legend: one row per meaning; the value drops under its label when narrow */
.cb-time-legend{margin:0 0 var(--space-3);font-size:var(--text-body);line-height:var(--leading-normal);color:var(--ink-2)}
.cb-time-legend.banner{padding:var(--space-3);border-radius:var(--radius-control);background:var(--success-soft);color:var(--success)}
.cb-time-legend dl{display:grid;gap:var(--space-1);margin:0}
.cb-time-legend dl>div{display:flex;flex-wrap:wrap;align-items:baseline;gap:0 var(--space-2)}
.cb-time-legend dt{font-size:var(--text-label);font-weight:var(--weight-medium)}   /* W5-2A: a label is 12/500 */
.cb-time-legend dd{margin:0;min-width:0}
.cb-zone{overflow-wrap:anywhere;word-break:normal}
.cb-time-legend p{margin:var(--space-2) 0 0}
.cb-banner{margin:0 0 var(--space-3);padding:var(--space-3);border-radius:var(--radius-control);font-size:var(--text-body-lg);line-height:var(--leading-normal);background:var(--success-soft);color:var(--success)}
.cb-banner.warn{background:var(--warning-soft);color:var(--warning)}
.cb-banner.danger{background:var(--danger-soft);color:var(--danger)}
.cb-chip{display:inline-block;padding:var(--space-1) var(--space-2);border-radius:var(--radius-control);font-size:var(--text-label);font-weight:var(--weight-medium);background:var(--success-soft);color:var(--success)}
.cb-chip.warn{background:var(--warning-soft);color:var(--warning)}
.cb-chip.danger{background:var(--danger-soft);color:var(--danger)}
.cb-chip.muted{background:var(--surface-3);color:var(--ink-3)}
/* W4-3A: '기한 D-11' - the word is a label, the count is the value (both portals' due chips) */
/* a due with a time is a small outlined label chip ('기한 D-11', '3시간 남음'); '기한 없음' stays quiet text */
/* W5-4A: a due date is a state - a filled chip (outlines are for owners: '병원' / '에이전시', the assignee); past due
   is the danger fill, and '기한 없음' stays plain text */
.cb-chip[data-due-chip]:not([data-due-chip=""]){padding:var(--space-1) var(--space-2);border:0;background:var(--surface-3);color:var(--ink-2);font-weight:var(--weight-bold)}
.cb-chip.danger[data-due-chip]:not([data-due-chip=""]){background:var(--danger-soft);color:var(--danger)}
.cb-due-label{font-weight:var(--weight-normal)}
.cb-struck{text-decoration:line-through;color:var(--ink-3)}
.cb-slot-day{display:flex;gap:var(--space-2);align-items:center;flex-wrap:wrap;margin:0 0 var(--space-3)}
.cb-slot-day input[type=date]{min-height:var(--control-lg);font-size:var(--text-title)}
.cb-slots{display:grid;grid-template-columns:repeat(auto-fill,minmax(150px,1fr));gap:var(--space-2);margin:0 0 var(--space-3)}
.cb-slot{min-height:var(--control-lg);padding:var(--space-2);border:1px solid var(--line-2);border-radius:var(--radius-control);background:var(--surface-1);font-size:var(--text-body-lg);line-height:var(--leading-normal);text-align:center;cursor:pointer}
.cb-slot[aria-pressed=true]{border-color:var(--accent);background:var(--accent);color:var(--ink-inverse);font-weight:var(--weight-bold)}
.cb-slot:disabled{background:var(--surface-3);color:var(--ink-3);cursor:not-allowed;text-decoration:line-through}
.cb-picked{display:grid;gap:var(--space-2);margin:0 0 var(--space-3);padding:0;list-style:none}
.cb-picked li{display:flex;justify-content:space-between;gap:var(--space-2);align-items:center;padding:var(--space-2) var(--space-3);border-radius:var(--radius-control);background:var(--success-soft);font-size:var(--text-body-lg)}
/* B T-07: a clock line may wrap — between its date and time, after " · ", inside a long zone name; its own units
   (9/27(일), 09:00 KST) are kept whole by CB.dual and common.js, so nowrap only pushed a long zone off the screen */
.cb-time{font-variant-numeric:tabular-nums}
/* W2-5A: '예약'/'알림' before a time when a row shows two (label and time joined by a no-break space) */
.cb-when-label{font-weight:var(--weight-medium);color:var(--ink-2)}
/* AP-1A5: an amount ('USD 300') moves to the next line whole; only one wider than the line breaks, at its space
   (common.js wraps it). A link's underline is drawn on it too (decorations do not reach an inline-block). */
.cb-amount{display:inline-block;max-width:100%;text-decoration:inherit}
.cb-time-local{display:block;font-size:var(--text-label);color:var(--ink-3)}
.cb-money{margin:0 0 var(--space-3);padding:var(--space-3);border:1px solid var(--line-2);border-radius:var(--radius-surface);font-size:var(--text-body-lg);line-height:var(--leading-normal)}
.cb-money strong{font-size:var(--text-title)}
.cb-fresh{display:inline-flex;gap:var(--space-2);align-items:center;font-size:var(--text-label);color:var(--ink-3)}
.cb-fresh button{min-height:var(--control-sm);padding:var(--space-1) var(--space-3);font-size:var(--text-label)}
.cb-offline{position:sticky;top:0;z-index:var(--z-sticky);padding:var(--space-2) var(--space-3);background:var(--danger);color:var(--ink-inverse);font-size:var(--text-body-lg);text-align:center}
/* Trial mode has a persistent viewport notice above login and both portal shells. */
.cb-trial-banner{position:fixed;inset:0 0 auto;z-index:var(--z-overlay);box-sizing:border-box;min-height:var(--control-lg);display:flex;align-items:center;justify-content:center;padding:var(--space-2) var(--space-3);background:var(--warning-soft);color:var(--warning);border-bottom:1px solid var(--warning);font-size:var(--text-body-lg);font-weight:var(--weight-bold);line-height:var(--leading-normal);text-align:center;word-break:keep-all}
body.cb-trial-mode{padding-top:var(--control-lg)}
.cb-trial-mode .sidebar,.cb-trial-mode .cb-offline,.cb-trial-mode .doc-bulk,.cb-trial-mode .cb-detail-nav{top:var(--control-lg)}
.cb-trial-input-warning{flex:none;margin:0 0 var(--space-4);padding:var(--space-3);border:1px solid var(--warning);border-radius:var(--radius-control);background:var(--warning-soft);color:var(--warning);font-size:var(--text-body-lg);font-weight:var(--weight-bold);line-height:var(--leading-normal);word-break:keep-all}
dialog .cb-trial-input-warning{position:sticky;top:0;z-index:var(--z-dropdown)}
.cb-access-log-notice{margin-top:var(--space-5);padding:var(--space-3) var(--space-4);color:var(--ink-3);font-size:var(--text-label);font-weight:var(--weight-normal);line-height:var(--leading-normal);text-align:center;word-break:keep-all}
@media(max-width:760px){.main>.cb-access-log-notice{padding-bottom:calc(var(--control-lg) + var(--space-8))}}
@media(max-width:640px){
 .cb-inbox-item{grid-template-columns:1fr}
 .cb-inbox-item>button,.cb-inbox-item>a.button{grid-row:auto;grid-column:1;width:100%}
 .cb-slots{grid-template-columns:repeat(2,minmax(0,1fr))}
}
