/* =====================================================================
   Project Monitoring System - interface styles
   Mobile first. One breakpoint at 900px promotes the nav to a sidebar.
   ===================================================================== */

:root {
  --bg:          #f6f7f9;
  --surface:     #ffffff;
  --surface-2:   #f2f4f7;
  --border:      #e3e6ea;
  --border-firm: #d2d7de;
  --text:        #1b2027;
  --text-soft:   #626c7a;
  --text-faint:  #8b94a1;

  --brand:       #2f6df0;
  --brand-soft:  #eaf1fe;
  --brand-text:  #1d51c4;

  --ok:      #16a34a;  --ok-soft:      #e6f6ec;
  --warn:    #d97706;  --warn-soft:    #fdf1e0;
  --danger:  #dc2626;  --danger-soft:  #fdeaea;
  --neutral: #64748b;  --neutral-soft: #eef1f5;
  --info:    #0891b2;  --info-soft:    #e2f5f9;

  --radius:    10px;
  --radius-sm: 7px;
  --shadow:    0 1px 2px rgba(16,24,40,.06), 0 1px 3px rgba(16,24,40,.05);
  --shadow-lg: 0 10px 30px rgba(16,24,40,.16);

  --header-h: 56px;
  --nav-h:    60px;
  --sidebar-w: 232px;
  --sidebar-collapsed-w: 60px;

  --font: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;

  /* Tells the browser which palette to paint native widgets with: the
     date/time picker, its calendar icon, spinners and scrollbars. */
  color-scheme: light;

  --select-arrow: url("data:image/svg+xml;charset=UTF-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23626c7a' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --bg:        #10131a;
    --surface:   #171b24;
    --surface-2: #1e232e;
    --border:    #262c38;
    --border-firm: #333b4a;
    --text:      #e7eaef;
    --text-soft: #a2acbb;
    --text-faint:#78838f;

    --brand:      #6c9bff;
    --brand-soft: #1b2740;
    --brand-text: #a8c3ff;

    --ok:      #4ade80;  --ok-soft:      #14301f;
    --warn:    #fbbf24;  --warn-soft:    #33270c;
    --danger:  #f87171;  --danger-soft:  #3a1a1a;
    --neutral: #94a3b8;  --neutral-soft: #232936;
    --info:    #38bdf8;  --info-soft:    #102b36;

    --shadow:    0 1px 2px rgba(0,0,0,.4);
    --shadow-lg: 0 12px 32px rgba(0,0,0,.55);

    color-scheme: dark;
    --select-arrow: url("data:image/svg+xml;charset=UTF-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23a2acbb' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
  }
}

:root[data-theme="dark"] {
  --bg:        #10131a;
  --surface:   #171b24;
  --surface-2: #1e232e;
  --border:    #262c38;
  --border-firm: #333b4a;
  --text:      #e7eaef;
  --text-soft: #a2acbb;
  --text-faint:#78838f;
  --brand:      #6c9bff;
  --brand-soft: #1b2740;
  --brand-text: #a8c3ff;
  --ok:      #4ade80;  --ok-soft:      #14301f;
  --warn:    #fbbf24;  --warn-soft:    #33270c;
  --danger:  #f87171;  --danger-soft:  #3a1a1a;
  --neutral: #94a3b8;  --neutral-soft: #232936;
  --info:    #38bdf8;  --info-soft:    #102b36;
  --shadow:    0 1px 2px rgba(0,0,0,.4);
  --shadow-lg: 0 12px 32px rgba(0,0,0,.55);

  color-scheme: dark;
  --select-arrow: url("data:image/svg+xml;charset=UTF-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23a2acbb' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
}

:root[data-theme="light"] { color-scheme: light; }

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font);
  font-size: 15px;
  line-height: 1.5;
  -webkit-text-size-adjust: 100%;
  -webkit-tap-highlight-color: transparent;
}

h1, h2, h3, h4 { margin: 0; font-weight: 600; line-height: 1.3; }
h1 { font-size: 1.35rem; }
h2 { font-size: 1.1rem; }
h3 { font-size: .98rem; }
p  { margin: 0 0 .6rem; }
a  { color: var(--brand); text-decoration: none; }
a:hover { text-decoration: underline; }

[hidden] { display: none !important; }

/* ------------------------------------------------------------ layout */

#app { min-height: 100vh; }

.shell {
  display: grid;
  /* minmax(0, 1fr), never plain 1fr: a 1fr track will not shrink below its
     widest child, so a wide report table or the timeline chart used to push
     the whole page past the window and clip the header buttons. Clamped, the
     table and chart scroll inside their own containers instead. */
  grid-template-columns: minmax(0, 1fr);
  grid-template-rows: var(--header-h) 1fr;
  min-height: 100vh;
}

.appbar {
  position: sticky; top: 0; z-index: 40;
  display: flex; align-items: center; gap: .7rem;
  height: var(--header-h);
  padding: 0 .9rem;
  background: var(--surface);
  border-bottom: 1px solid var(--border);
}

.appbar .brand {
  display: flex; align-items: center; gap: .55rem;
  font-weight: 650; letter-spacing: -.01em; color: var(--text);
}
.appbar .brand .mark {
  width: 28px; height: 28px; border-radius: 8px;
  background: var(--brand); color: #fff;
  display: grid; place-items: center; font-size: .82rem; font-weight: 700;
  flex: none;
}
.appbar .brand .brand-text { font-size: .98rem; }
.appbar .spacer { flex: 1; }

/* The collapse toggle only means something where the sidebar exists; on a
   phone the tab bar is the navigation. Scoped to .appbar so it outranks the
   .btn display rule further down the file. */
.appbar .nav-toggle { display: none; }

.content {
  padding: 1rem .9rem calc(var(--nav-h) + 1.4rem);
  max-width: 1280px; width: 100%; margin: 0 auto;
  min-width: 0;
}

.sidebar { display: none; }

.tabbar {
  position: fixed; bottom: 0; left: 0; right: 0; z-index: 45;
  display: flex; height: var(--nav-h);
  background: var(--surface);
  border-top: 1px solid var(--border);
  padding-bottom: env(safe-area-inset-bottom);
}
.tabbar button {
  flex: 1; border: 0; background: none; cursor: pointer;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 2px;
  color: var(--text-faint); font-size: .68rem; font-family: inherit; padding: 0;
}
.tabbar button svg { width: 21px; height: 21px; }
.tabbar button.active { color: var(--brand); }

@media (min-width: 900px) {
  .shell {
    grid-template-columns: var(--sidebar-w) minmax(0, 1fr);
    grid-template-rows: var(--header-h) 1fr;
    grid-template-areas: "bar bar" "side main";
  }
  .appbar  { grid-area: bar; padding: 0 1.2rem; }
  .sidebar {
    grid-area: side; display: block;
    border-right: 1px solid var(--border);
    background: var(--surface);
    padding: 1rem .6rem;
    position: sticky; top: var(--header-h);
    height: calc(100vh - var(--header-h));
    overflow-y: auto;
  }
  .content { grid-area: main; padding: 1.4rem 1.6rem 3rem; }
  .tabbar  { display: none; }

  /* ---- collapsed to icons -------------------------------------------
     The nav keeps every destination, just without its labels, so the
     project itself gets the width back. */
  /* No transition on grid-template-columns: interpolating between a var()
     width and 1fr leaves the track stuck at the collapsed size in Chrome.
     The switch is instant, which also spares the content a reflow animation. */
  .shell.nav-collapsed { grid-template-columns: var(--sidebar-collapsed-w) minmax(0, 1fr); }

  /* overflow:visible matters - the scroll container the expanded sidebar
     needs would otherwise clip the icon tooltips. The collapsed list is
     short enough that it never has to scroll. */
  .shell.nav-collapsed .sidebar { padding: 1rem .5rem; overflow: visible; }

  .shell.nav-collapsed .nav-item {
    justify-content: center;
    padding-left: 0;
    padding-right: 0;
    gap: 0;
  }
  .shell.nav-collapsed .nav-item > span { display: none; }

  /* The group heading becomes a plain rule - there is no room for a word. */
  .shell.nav-collapsed .nav-group {
    height: 1px;
    margin: .7rem .35rem;
    padding: 0;
    background: var(--border);
    font-size: 0;
    overflow: hidden;
  }

  .appbar .nav-toggle { display: inline-flex; margin-left: -.35rem; }
}

.sidebar .nav-item {
  display: flex; align-items: center; gap: .6rem;
  width: 100%; padding: .55rem .65rem; margin-bottom: 2px;
  border: 0; border-radius: var(--radius-sm); background: none;
  color: var(--text-soft); font: inherit; font-size: .9rem; text-align: left; cursor: pointer;
}
.sidebar .nav-item svg { width: 18px; height: 18px; flex: none; }
.sidebar .nav-item:hover  { background: var(--surface-2); color: var(--text); }
.sidebar .nav-item.active { background: var(--brand-soft); color: var(--brand-text); font-weight: 600; }
.sidebar .nav-group {
  font-size: .68rem; text-transform: uppercase; letter-spacing: .06em;
  color: var(--text-faint); padding: .9rem .65rem .35rem; font-weight: 600;
}

/* ------------------------------------------------------------- pieces */

.page-head {
  display: flex; align-items: flex-start; gap: .8rem;
  flex-wrap: wrap; margin-bottom: 1rem;
}
.page-head .grow { flex: 1; min-width: 200px; }
.page-head .sub { color: var(--text-soft); font-size: .87rem; margin-top: .15rem; }

.card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
}
.card + .card { margin-top: 1rem; }
.card-head {
  display: flex; align-items: center; gap: .6rem; flex-wrap: wrap;
  padding: .8rem 1rem; border-bottom: 1px solid var(--border);
}
.card-head h2, .card-head h3 { flex: 1; min-width: 140px; }
.card-body { padding: 1rem; }
.card-body.tight { padding: .5rem; }

.grid { display: grid; gap: .8rem; }
.grid.cols-2 { grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); }
.grid.cols-3 { grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); }
.grid.cols-4 { grid-template-columns: repeat(auto-fit, minmax(155px, 1fr)); }

.stat {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius); padding: .8rem .9rem; box-shadow: var(--shadow);
}
.stat .label { font-size: .72rem; text-transform: uppercase; letter-spacing: .05em; color: var(--text-faint); font-weight: 600; }
.stat .value { font-size: 1.5rem; font-weight: 650; letter-spacing: -.02em; margin-top: .15rem; }
.stat .value.danger { color: var(--danger); }
.stat .value.warn   { color: var(--warn); }
.stat .value.ok     { color: var(--ok); }
.stat .hint { font-size: .76rem; color: var(--text-soft); }

/* buttons */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: .4rem;
  padding: .5rem .85rem; min-height: 38px;
  border: 1px solid var(--border-firm); border-radius: var(--radius-sm);
  background: var(--surface); color: var(--text);
  font: inherit; font-size: .88rem; font-weight: 500; cursor: pointer;
  white-space: nowrap;
}
.btn:hover  { background: var(--surface-2); }
.btn:active { transform: translateY(1px); }
.btn:disabled { opacity: .5; cursor: not-allowed; }
.btn svg { width: 16px; height: 16px; }
.btn.primary { background: var(--brand); border-color: var(--brand); color: #fff; }
.btn.primary:hover { filter: brightness(1.07); }
.btn.danger  { background: var(--danger); border-color: var(--danger); color: #fff; }
.btn.ghost   { border-color: transparent; background: transparent; color: var(--text-soft); }
.btn.ghost:hover { background: var(--surface-2); color: var(--text); }
.btn.sm { min-height: 30px; padding: .25rem .55rem; font-size: .8rem; }
.btn.icon { padding: .35rem; min-width: 34px; min-height: 34px; }
.btn.block { width: 100%; }

.btn-row { display: flex; gap: .5rem; flex-wrap: wrap; }

/* form controls */
.field { margin-bottom: .85rem; }
.field label {
  display: block; font-size: .8rem; font-weight: 600;
  color: var(--text-soft); margin-bottom: .3rem;
}
.field .help { font-size: .76rem; color: var(--text-faint); margin-top: .25rem; }
.field .err  { font-size: .78rem; color: var(--danger); margin-top: .25rem; font-weight: 500; }
.field.has-error > label { color: var(--danger); }

input[type="text"], input[type="email"], input[type="password"], input[type="number"],
input[type="search"], input[type="datetime-local"], input[type="date"], select, textarea {
  width: 100%; padding: .55rem .65rem; min-height: 40px;
  border: 1px solid var(--border-firm); border-radius: var(--radius-sm);
  background: var(--surface); color: var(--text);
  font: inherit; font-size: .9rem;
}
textarea { min-height: 92px; resize: vertical; line-height: 1.5; }
input:focus, select:focus, textarea:focus {
  outline: none; border-color: var(--brand);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--brand) 18%, transparent);
}

/* Declared after the focus rule on purpose: the field the form just jumped to
   is focused, and it still has to read as the one that needs attention. */
input.invalid, select.invalid, textarea.invalid,
input.invalid:focus, select.invalid:focus, textarea.invalid:focus {
  border-color: var(--danger);
  background: color-mix(in srgb, var(--danger) 6%, var(--surface));
}
input.invalid:focus, select.invalid:focus, textarea.invalid:focus {
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--danger) 22%, transparent);
}
input:disabled, select:disabled, textarea:disabled { background: var(--surface-2); color: var(--text-faint); }

/* The native arrow is replaced rather than removed - without a chevron a
   select is indistinguishable from a text box and reads as broken. */
select {
  appearance: none;
  -webkit-appearance: none;
  padding-right: 2.1rem;
  background-image: var(--select-arrow);
  background-repeat: no-repeat;
  background-position: right .65rem center;
  background-size: 13px 13px;
  cursor: pointer;
}
select:disabled { cursor: not-allowed; opacity: .7; }

/* Make the calendar button easy to hit; the whole field opens the picker
   (see the click handler in app.js). */
input[type="date"], input[type="datetime-local"] { cursor: pointer; }
input[type="date"]::-webkit-calendar-picker-indicator,
input[type="datetime-local"]::-webkit-calendar-picker-indicator {
  cursor: pointer;
  padding: 4px;
  margin-right: -2px;
  border-radius: 4px;
  opacity: .75;
}
input[type="date"]::-webkit-calendar-picker-indicator:hover,
input[type="datetime-local"]::-webkit-calendar-picker-indicator:hover {
  opacity: 1;
  background: var(--surface-2);
}

.field-row { display: grid; gap: .6rem; grid-template-columns: 1fr; }
@media (min-width: 620px) { .field-row.two { grid-template-columns: 1fr 1fr; } }

/* label.checkbox has to outrank ".field label { display:block }", otherwise a
   checkbox nested in a field stacks its box, avatar and text vertically. */
.checkbox,
.field label.checkbox {
  display: flex;
  align-items: center;
  gap: .5rem;
  margin-bottom: 0;
  font-size: .88rem;
  font-weight: 400;
  color: var(--text);
  cursor: pointer;
}
.checkbox input {
  width: 17px; height: 17px; min-height: 0; flex: none;
  accent-color: var(--brand); cursor: pointer;
}

/* badges */
.badge {
  display: inline-flex; align-items: center; gap: .3rem;
  padding: .12rem .48rem; border-radius: 999px;
  font-size: .72rem; font-weight: 600; white-space: nowrap;
  background: var(--neutral-soft); color: var(--neutral);
}
.badge.ok      { background: var(--ok-soft);     color: var(--ok); }
.badge.warn    { background: var(--warn-soft);   color: var(--warn); }
.badge.danger  { background: var(--danger-soft); color: var(--danger); }
.badge.info    { background: var(--info-soft);   color: var(--info); }
.badge.brand   { background: var(--brand-soft);  color: var(--brand-text); }
.badge .dot { width: 6px; height: 6px; border-radius: 50%; background: currentColor; }

.chip {
  display: inline-flex; align-items: center; gap: .3rem;
  padding: .18rem .5rem; border-radius: 999px;
  background: var(--surface-2); border: 1px solid var(--border);
  font-size: .76rem; color: var(--text-soft);
}
.chip button { border: 0; background: none; color: inherit; cursor: pointer; padding: 0 0 0 .1rem; font-size: .9rem; line-height: 1; }

.avatar {
  width: 26px; height: 26px; border-radius: 50%; flex: none;
  background: var(--brand-soft); color: var(--brand-text);
  display: grid; place-items: center; font-size: .7rem; font-weight: 700;
}
.avatar.sm { width: 21px; height: 21px; font-size: .6rem; }
.avatar-stack { display: flex; }
.avatar-stack .avatar + .avatar { margin-left: -7px; border: 2px solid var(--surface); }

/* progress */
.bar { height: 6px; border-radius: 999px; background: var(--surface-2); overflow: hidden; }
.bar > i { display: block; height: 100%; border-radius: 999px; background: var(--brand); transition: width .25s ease; }
.bar.ok     > i { background: var(--ok); }
.bar.warn   > i { background: var(--warn); }
.bar.danger > i { background: var(--danger); }

.progress-cell { display: flex; align-items: center; gap: .5rem; min-width: 96px; }
.progress-cell .bar { flex: 1; }
.progress-cell .pct { font-size: .76rem; font-variant-numeric: tabular-nums; color: var(--text-soft); width: 34px; text-align: right; }
/* A count needs more room than "45%", and the bar still has to be readable,
   so the cell widens rather than squeezing the bar out of existence. */
.progress-cell .pct.qty { width: auto; white-space: nowrap; color: var(--text); font-weight: 600; }
.progress-cell:has(.pct.qty) { min-width: 170px; }
.progress-cell .bar { min-width: 44px; }

/* tables */
.table-wrap { overflow-x: auto; -webkit-overflow-scrolling: touch; }
table { width: 100%; border-collapse: collapse; font-size: .87rem; }
thead th {
  text-align: left; font-size: .72rem; text-transform: uppercase; letter-spacing: .04em;
  color: var(--text-faint); font-weight: 600; padding: .5rem .7rem;
  border-bottom: 1px solid var(--border); white-space: nowrap;
}
tbody td { padding: .6rem .7rem; border-bottom: 1px solid var(--border); vertical-align: middle; }
tbody tr:last-child td { border-bottom: 0; }
tbody tr.clickable { cursor: pointer; }
tbody tr.clickable:hover { background: var(--surface-2); }
td.num { text-align: right; font-variant-numeric: tabular-nums; }
td.nowrap, th.nowrap { white-space: nowrap; }

/* import preview */
tbody tr.row-bad td { background: color-mix(in srgb, var(--danger) 8%, transparent); }

input[type="file"] {
  width: 100%; padding: .5rem .6rem; font: inherit; font-size: .88rem;
  color: var(--text); background: var(--surface); cursor: pointer;
  border: 1px dashed var(--border-firm); border-radius: var(--radius-sm);
}
input[type="file"]:hover { border-color: var(--brand); }
input[type="file"]::file-selector-button {
  font: inherit; font-size: .82rem; margin-right: .7rem; padding: .3rem .7rem;
  color: var(--text); background: var(--surface-2); cursor: pointer;
  border: 1px solid var(--border-firm); border-radius: var(--radius-sm);
}

/* empty / loading */
.empty { padding: 2.2rem 1rem; text-align: center; color: var(--text-soft); }
.empty .big { font-size: 1.6rem; margin-bottom: .4rem; }
.empty p { margin: .2rem 0; font-size: .9rem; }

.spinner {
  width: 20px; height: 20px; border-radius: 50%;
  border: 2px solid var(--border-firm); border-top-color: var(--brand);
  animation: spin .7s linear infinite; display: inline-block;
}
@keyframes spin { to { transform: rotate(360deg); } }
.loading { display: flex; align-items: center; justify-content: center; gap: .6rem; padding: 2.5rem; color: var(--text-soft); }

/* ------------------------------------------------------ activity tree */

.tree { padding: .25rem; }

.node {
  display: flex; align-items: flex-start; gap: .5rem;
  padding: .5rem .5rem .5rem 0;
  border-bottom: 1px solid var(--border);
  position: relative;
}
.node:last-child { border-bottom: 0; }
.node.dragging { opacity: .4; }
.node.drop-into  { background: var(--brand-soft); border-radius: var(--radius-sm); }
.node.drop-above { box-shadow: inset 0 2px 0 var(--brand); }
.node.drop-below { box-shadow: inset 0 -2px 0 var(--brand); }

.node .indent { flex: none; align-self: stretch; }
.node .twist {
  flex: none; width: 22px; height: 22px; margin-top: 1px;
  border: 0; background: none; color: var(--text-faint);
  cursor: pointer; display: grid; place-items: center; padding: 0;
}
.node .twist svg { width: 13px; height: 13px; transition: transform .15s; }
.node.collapsed .twist svg { transform: rotate(-90deg); }
.node .twist.leaf { visibility: hidden; }

.node .body { flex: 1; min-width: 0; }
.node .title-row { display: flex; align-items: center; gap: .4rem; flex-wrap: wrap; }
.node .wbs {
  font-size: .72rem; color: var(--text-faint); font-variant-numeric: tabular-nums;
  min-width: 26px; font-weight: 600;
}
.node .name { font-weight: 550; font-size: .92rem; overflow-wrap: anywhere; }
.node.done .name { color: var(--text-soft); }
.node .meta {
  display: flex; align-items: center; gap: .45rem .8rem; flex-wrap: wrap;
  margin-top: .3rem; font-size: .76rem; color: var(--text-soft);
}
.node .meta .item { display: inline-flex; align-items: center; gap: .25rem; }
.node .meta svg { width: 13px; height: 13px; opacity: .75; }
.node .remark {
  margin-top: .35rem; font-size: .8rem; color: var(--text-soft);
  background: var(--surface-2); border-radius: var(--radius-sm);
  padding: .3rem .5rem; border-left: 2px solid var(--border-firm);
  overflow-wrap: anywhere;
}
.node .actions { display: flex; gap: .15rem; align-items: center; flex: none; align-self: flex-start; }

/* On a phone the four nudge buttons would crowd the title out, so only the
   row menu stays - it carries the same moves plus "Move to". */
@media (max-width: 760px) {
  .node .actions [data-move-up],
  .node .actions [data-move-down],
  .node .actions [data-indent],
  .node .actions [data-outdent] { display: none; }
}
.node .grip {
  cursor: grab; color: var(--text-faint); padding: .3rem .15rem;
  display: none; touch-action: none;
}
.node .grip svg { width: 14px; height: 14px; }
@media (min-width: 900px) { .node .grip { display: block; } }

.node .side { display: flex; align-items: center; gap: .55rem; flex: none; }
@media (max-width: 620px) {
  .node .side { display: none; }
  .node .progress-inline { display: flex; }
}
.progress-inline { display: none; margin-top: .4rem; }

.level-tint-1 { border-left: 3px solid var(--brand); }
.level-tint-2 { border-left: 3px solid var(--info); }
.level-tint-3 { border-left: 3px solid var(--neutral); }
.level-tint-4 { border-left: 3px solid var(--border-firm); }

/* ------------------------------------------------------------ tooltips */

/* Icon-only buttons say what they do on hover. Pointer devices only -
   on touch there is no hover and :hover would stick after a tap. */
@media (hover: hover) and (pointer: fine) {
  [data-tip] { position: relative; }
  [data-tip]::after {
    content: attr(data-tip);
    position: absolute;
    bottom: calc(100% + 6px);
    left: 50%;
    transform: translateX(-50%) translateY(3px);
    padding: .24rem .48rem;
    border-radius: 5px;
    background: var(--text);
    color: var(--bg);
    font-size: .72rem;
    font-weight: 600;
    line-height: 1.3;
    white-space: nowrap;
    box-shadow: var(--shadow-lg);
    opacity: 0;
    pointer-events: none;
    transition: opacity .12s ease, transform .12s ease;
    z-index: 60;
  }
  [data-tip]:hover::after,
  [data-tip]:focus-visible::after { opacity: 1; transform: translateX(-50%) translateY(0); }

  /* Row buttons sit at the right edge, so their labels open leftwards
     rather than pushing the page sideways. */
  .node .actions [data-tip]::after { left: auto; right: 0; transform: translateY(3px); }
  .node .actions [data-tip]:hover::after,
  .node .actions [data-tip]:focus-visible::after { transform: translateY(0); }

  /* Sidebar labels are already on screen when the nav is expanded, so the
     tooltip only earns its place once it has collapsed to icons - and it
     opens sideways, out of the narrow column. */
  .sidebar [data-tip]::after { content: none; }
  .shell.nav-collapsed .sidebar [data-tip]::after {
    content: attr(data-tip);
    left: calc(100% + 10px);
    right: auto;
    bottom: auto;
    top: 50%;
    transform: translateY(-50%) translateX(-3px);
  }
  .shell.nav-collapsed .sidebar [data-tip]:hover::after,
  .shell.nav-collapsed .sidebar [data-tip]:focus-visible::after {
    transform: translateY(-50%) translateX(0);
  }
}

/* ------------------------------------------------------ timeline chart */

:root { --planned-bar: #9aa6b8; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) { --planned-bar: #55627a; }
}
:root[data-theme="dark"] { --planned-bar: #55627a; }

.gantt { display: flex; align-items: flex-start; border-bottom: 1px solid var(--border); }

.gantt-labels {
  border-right: 1px solid var(--border);
  background: var(--surface);
  min-width: 0;
}
.gantt-head {
  display: flex; align-items: center;
  padding: 0 .7rem;
  background: var(--surface-2);
  border-bottom: 1px solid var(--border);
  font-size: .72rem; font-weight: 600; letter-spacing: .04em;
  text-transform: uppercase; color: var(--text-faint);
}
.gantt-row {
  display: flex; align-items: center; gap: .45rem;
  padding: 0 .7rem;
  font-size: .82rem;
  border-bottom: 1px solid transparent;
}
.gantt-row:nth-child(even) { background: color-mix(in srgb, var(--surface-2) 45%, transparent); }
.gantt-row.is-project { font-weight: 650; border-bottom: 1px solid var(--border-firm); }
.gantt-wbs { flex: none; width: 34px; font-size: .7rem; color: var(--text-faint); font-variant-numeric: tabular-nums; }
.gantt-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* Only the bars scroll sideways; the names stay put. */
.gantt-scroll { flex: 1; overflow-x: auto; -webkit-overflow-scrolling: touch; }
.gantt-scroll svg { display: block; }

.gantt-key { width: 14px; height: 6px; border-radius: 3px; display: inline-block; }
.gantt-key.planned { background: var(--planned-bar); }
.gantt-key.actual  { background: var(--ok); }
.gantt-key.late    { background: var(--danger); }
.gantt-key.today   { width: 2px; height: 12px; border-radius: 0; background: var(--danger); }

td.late { color: var(--danger); font-weight: 600; }

@media (max-width: 700px) {
  .gantt-labels { flex-basis: 150px !important; }
  .gantt-wbs { display: none; }
}

/* ---------------------------------------------------- move confirmation */

.move-summary {
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  padding: .7rem .8rem;
}
.move-line { display: flex; gap: .6rem; align-items: flex-start; font-size: .87rem; }
.move-tag {
  flex: none; width: 44px;
  font-size: .68rem; font-weight: 700; text-transform: uppercase; letter-spacing: .05em;
  padding-top: .12rem;
}
.move-tag.from { color: var(--text-faint); }
.move-tag.to   { color: var(--brand-text); }
.move-arrow { color: var(--text-faint); margin: .25rem 0 .25rem 12px; }
.move-arrow svg { width: 15px; height: 15px; }

/* --------------------------------------------------------- modal/sheet */

.overlay {
  position: fixed; inset: 0; z-index: 90;
  background: rgba(16,20,28,.5);
  display: flex; align-items: flex-end; justify-content: center;
  animation: fade .15s ease;
}
@keyframes fade { from { opacity: 0; } }

.sheet {
  background: var(--surface);
  width: 100%; max-width: 620px;
  max-height: 92vh; display: flex; flex-direction: column;
  border-radius: 16px 16px 0 0;
  box-shadow: var(--shadow-lg);
  animation: rise .2s cubic-bezier(.2,.8,.3,1);
}
@keyframes rise { from { transform: translateY(26px); } }
.sheet.wide { max-width: 880px; }

@media (min-width: 700px) {
  .overlay { align-items: center; padding: 1.5rem; }
  .sheet { border-radius: var(--radius); max-height: 88vh; }
}

.sheet-head {
  display: flex; align-items: center; gap: .6rem;
  padding: .9rem 1rem; border-bottom: 1px solid var(--border); flex: none;
}
.sheet-head h2 { flex: 1; font-size: 1rem; }
.sheet-body { padding: 1rem; overflow-y: auto; flex: 1; }
.sheet-foot {
  display: flex; gap: .5rem; justify-content: flex-end;
  padding: .8rem 1rem; border-top: 1px solid var(--border); flex: none;
  padding-bottom: calc(.8rem + env(safe-area-inset-bottom));
}
.sheet-foot .btn { flex: 1; }
@media (min-width: 700px) { .sheet-foot .btn { flex: none; } }

/* ------------------------------------------------------------- toast */

.toasts {
  position: fixed; left: 50%; transform: translateX(-50%);
  bottom: calc(var(--nav-h) + 14px); z-index: 120;
  display: flex; flex-direction: column; gap: .4rem; align-items: center;
  width: min(440px, calc(100% - 24px)); pointer-events: none;
}
@media (min-width: 900px) { .toasts { bottom: 20px; } }
.toast {
  background: var(--text); color: var(--bg);
  padding: .6rem .9rem; border-radius: var(--radius-sm);
  font-size: .86rem; box-shadow: var(--shadow-lg);
  animation: rise .18s ease; width: 100%;
}
.toast.error { background: var(--danger); color: #fff; }
.toast.ok    { background: var(--ok); color: #fff; }

/* --------------------------------------------------------------- mic */

.mic-row { display: flex; gap: .5rem; align-items: flex-start; }
.mic-row textarea { flex: 1; }
.mic-btn {
  flex: none; width: 42px; height: 42px; border-radius: 50%;
  border: 1px solid var(--border-firm); background: var(--surface);
  color: var(--text-soft); cursor: pointer; display: grid; place-items: center;
}
.mic-btn svg { width: 18px; height: 18px; }
.mic-btn.listening {
  background: var(--danger); border-color: var(--danger); color: #fff;
  animation: pulse 1.3s ease-in-out infinite;
}
@keyframes pulse {
  0%,100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--danger) 55%, transparent); }
  50%     { box-shadow: 0 0 0 8px transparent; }
}
.mic-status { font-size: .76rem; color: var(--text-faint); margin-top: .35rem; min-height: 1em; line-height: 1.45; }
.mic-status.live { color: var(--danger); font-weight: 600; }
/* Failures have to be readable, not a faint grey aside. */
.mic-status.error {
  color: var(--danger);
  background: var(--danger-soft);
  border-radius: var(--radius-sm);
  padding: .35rem .5rem;
}

/* -------------------------------------------------------------- login */

.auth-wrap {
  min-height: 100vh; display: grid; place-items: center;
  padding: 1.2rem; background: var(--bg);
}
.auth-card {
  width: 100%; max-width: 400px; background: var(--surface);
  border: 1px solid var(--border); border-radius: 14px;
  box-shadow: var(--shadow-lg); padding: 1.6rem 1.4rem;
}
.auth-card .logo {
  width: 44px; height: 44px; border-radius: 12px; background: var(--brand);
  color: #fff; display: grid; place-items: center; font-weight: 700;
  margin-bottom: .9rem;
}
.auth-card h1 { font-size: 1.25rem; margin-bottom: .2rem; }
.auth-card .sub { color: var(--text-soft); font-size: .88rem; margin-bottom: 1.2rem; }
.auth-error {
  background: var(--danger-soft); color: var(--danger);
  padding: .55rem .7rem; border-radius: var(--radius-sm);
  font-size: .84rem; margin-bottom: .8rem;
}
.auth-hint {
  margin-top: 1.1rem; padding-top: .9rem; border-top: 1px solid var(--border);
  font-size: .78rem; color: var(--text-faint); line-height: 1.6;
}

/* ------------------------------------------------------------ helpers */

.row      { display: flex; align-items: center; gap: .5rem; }
.row.wrap { flex-wrap: wrap; }
.row.between { justify-content: space-between; }
.grow  { flex: 1; min-width: 0; }
.muted { color: var(--text-soft); }
.faint { color: var(--text-faint); }
.small { font-size: .8rem; }
.xs    { font-size: .74rem; }
.strong{ font-weight: 600; }
.mt    { margin-top: .8rem; }
.mb    { margin-bottom: .8rem; }
.truncate { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tabular { font-variant-numeric: tabular-nums; }
.sep { height: 1px; background: var(--border); margin: .8rem 0; }

.seg {
  display: inline-flex; background: var(--surface-2);
  border: 1px solid var(--border); border-radius: var(--radius-sm); padding: 2px; gap: 2px;
}
.seg button {
  border: 0; background: none; color: var(--text-soft);
  padding: .3rem .6rem; border-radius: 5px; font: inherit; font-size: .82rem; cursor: pointer;
}
.seg button.active { background: var(--surface); color: var(--text); font-weight: 600; box-shadow: var(--shadow); }

.toolbar {
  display: flex; gap: .5rem; align-items: center; flex-wrap: wrap;
  margin-bottom: .8rem;
}
.toolbar .grow { min-width: 160px; }
.toolbar select, .toolbar input { min-height: 36px; font-size: .85rem; }
@media (max-width: 620px) {
  .toolbar > select, .toolbar > input { flex: 1 1 100%; }
}

.scroll-x { display: flex; gap: .5rem; overflow-x: auto; padding-bottom: .3rem; -webkit-overflow-scrolling: touch; }
.scroll-x::-webkit-scrollbar { height: 0; }

.list-item {
  display: flex; align-items: center; gap: .7rem;
  padding: .7rem 1rem; border-bottom: 1px solid var(--border); cursor: pointer;
}
.list-item:last-child { border-bottom: 0; }
.list-item:hover { background: var(--surface-2); }
.list-item .grow { min-width: 0; }

.kv { display: grid; grid-template-columns: minmax(90px, auto) 1fr; gap: .35rem .8rem; font-size: .86rem; }
.kv dt { color: var(--text-soft); }
.kv dd { margin: 0; }

@media print {
  .appbar, .sidebar, .tabbar, .toolbar, .btn, .toasts { display: none !important; }
  .content { padding: 0; max-width: none; }
  .card { box-shadow: none; border-color: #ccc; break-inside: avoid; }
  body { background: #fff; }
}

/* ---------------------------------------------------------------- critical path */
/* The chain reads as a sequence, so it is numbered and joined by a rule. */
.chain { list-style: none; margin: .75rem 0 0; padding: 0; }
.chain li { display: flex; gap: .7rem; align-items: flex-start; padding: .5rem 0; position: relative; }
.chain li + li { border-top: 1px solid var(--border); }
.chain-step {
  flex: none; width: 22px; height: 22px; border-radius: 50%;
  display: grid; place-items: center;
  background: var(--danger-soft, var(--surface-2)); color: var(--danger);
  font-size: .7rem; font-weight: 700; font-variant-numeric: tabular-nums;
}
tr.row-critical td { background: var(--danger-soft, transparent); }
tr.row-critical td:first-child { box-shadow: inset 3px 0 0 var(--danger); }
.warn-text { color: var(--warn); }
.badge.sm { font-size: .62rem; padding: .05rem .3rem; margin-left: .3rem; }

/* -------------------------------------------------------- minutes of meeting */
/* A day heading rather than a card, so the eye groups by date first. */
.day-group { margin-bottom: 1.4rem; }
.day-head {
  display: flex; align-items: center; gap: .5rem;
  padding: .35rem 0 .5rem;
  border-bottom: 2px solid var(--border-firm);
  margin-bottom: .7rem;
  font-size: .92rem;
}

/* An action is a checkbox and a line of context; the whole row is the label
   so the tap target is the full width on a phone. */
.action-line {
  display: flex; align-items: flex-start; gap: .6rem;
  padding: .45rem 0;
  border-bottom: 1px solid var(--border);
  cursor: pointer;
}
.action-line:last-child { border-bottom: 0; }
.action-line input[type="checkbox"] { margin-top: .2rem; flex: none; }
.action-line .block { display: block; }
.action-line.overdue .strong { color: var(--danger); }
.action-line.closed { opacity: .62; }
.struck { text-decoration: line-through; }

.action-row { padding: .5rem 0; border-bottom: 1px solid var(--border); }
.action-row:last-of-type { border-bottom: 0; }
.action-row > input[type="text"] { width: 100%; }

/* Minutes are typed with line breaks that carry meaning. */
.pre-wrap { white-space: pre-wrap; overflow-wrap: anywhere; }

/* ----------------------------------------------------- completed projects */
/* A row in a record rather than a card to scan: finished work is read, not
   triaged, so it gets less weight than the live projects above it. */
.done-row {
  padding: .55rem .1rem;
  border-bottom: 1px solid var(--border);
}
.done-row:last-child { border-bottom: 0; }
.done-row:hover { background: var(--surface-2); }
.done-head { display: flex; align-items: center; gap: .45rem; flex-wrap: wrap; }
.done-meta {
  display: flex; flex-wrap: wrap; gap: .8rem;
  margin-top: .25rem;
  font-size: .76rem;
  color: var(--text-soft);
}
.done-meta span { display: inline-flex; align-items: center; gap: .25rem; }
.done-meta svg { width: 12px; height: 12px; opacity: .75; }

/* A project with nothing left to do that nobody has closed. Sits inside the
   card so the prompt is attached to the thing it is about. */
.close-prompt {
  display: flex; align-items: center; gap: .6rem; flex-wrap: wrap;
  margin-top: .6rem; padding: .5rem .6rem;
  background: var(--ok-soft);
  border-radius: var(--radius-sm);
  color: var(--text-soft);
}

/* Briefly ring a card that was jumped to, so the eye lands on the right one. */
@keyframes flash-ring {
  from { box-shadow: 0 0 0 3px var(--ok); }
  to   { box-shadow: 0 0 0 3px transparent; }
}
.card.flash { animation: flash-ring 1.6s ease-out; }
@media (prefers-reduced-motion: reduce) {
  .card.flash { animation: none; box-shadow: 0 0 0 3px var(--ok); }
}

/* ------------------------------------------------- project group headings */
/* A rule rather than a card, so the heading reads as a divider between
   stages and not as another thing to click. */
.group-head {
  display: flex; align-items: baseline; gap: .5rem; flex-wrap: wrap;
  padding: .3rem 0 .55rem;
  margin: 1.3rem 0 .75rem;
  border-bottom: 2px solid var(--border-firm);
}
.group-head:first-of-type { margin-top: .4rem; }
.group-head h2 { font-size: 1.02rem; }
