/* --------------------------------------------------------------------------
   Hero: title, search, primary action
   -------------------------------------------------------------------------- */
/* The sections had no gap between them at all: measured at 1476px, the
   inbox card's bottom edge and the row below it were both at y=480, and that
   row's bottom and "Assigned by me" were both at y=648. Two 1px borders
   touching read as one divider inside a single tall card, which is what made
   the whole thing look like one entangled block. One rhythm here, matching
   the 16px already between the two columns. */
.work-mode { display: flex; flex-direction: column; gap: 16px; }

.wk-hero {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: 16px; flex-wrap: wrap;
}
.wk-hero-text h2 {
  display: flex; align-items: center; gap: 10px;
  font-size: 1.5rem; font-weight: 800; letter-spacing: -0.02em; margin: 0;
}
.wk-hero-text .muted-text { margin: 4px 0 0; font-size: 0.83rem; }
.wk-hero-icon { font-size: 1.25rem; }
.wk-hero-tools { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }

.wk-search {
  position: relative; display: flex; align-items: center;
  min-width: 240px; flex: 1 1 240px;
}
.wk-search-icon {
  position: absolute; left: 13px; font-size: 0.82rem;
  opacity: 0.55; pointer-events: none;
}
.wk-search input {
  width: 100%;
  padding: 10px 34px 10px 36px;
  border-radius: var(--radius-pill);
  border: 1px solid var(--glass-rim, var(--border));
  background: var(--glass-bg-faint, var(--surface));
  -webkit-backdrop-filter: var(--glass-blur-sm);
  backdrop-filter: var(--glass-blur-sm);
  color: var(--text); font: inherit; font-size: 0.84rem;
  transition: border-color var(--t-fast) var(--ease), box-shadow var(--t-fast) var(--ease);
}
.wk-search input::placeholder { color: var(--text-muted); }
.wk-search input:focus {
  outline: none;
  border-color: var(--primary);
  box-shadow: 0 0 0 4px var(--primary-ring);
}
/* The browser's own clear affordance is inconsistent across engines and
   invisible in dark mode, so it is replaced with one that matches. */
.wk-search input::-webkit-search-cancel-button { display: none; }
.wk-search-clear {
  position: absolute; right: 6px;
  width: 26px; height: 26px; border: none; border-radius: 50%;
  background: none; color: var(--text-muted);
  font-size: 0.7rem; cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
}
.wk-search-clear:hover { background: var(--surface-alt); color: var(--text); }

/* --------------------------------------------------------------------------
   Counts, each carrying the seven days behind it
   -------------------------------------------------------------------------- */
/* minmax(0,...) not 1fr: a 1fr track refuses to shrink below its content,
   and the icon, number and sparkline together overflowed the row by 8px
   at 852px -- a phone held sideways. */
.wk-stats { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 14px; }
@media (max-width: 900px) {
  /* The sparkline is the first thing to go: the number it annotates is
     still right beside it. */
  .wk-stats { gap: 10px; }
  .wk-stat { grid-template-columns: auto 1fr; gap: 4px 10px; }
  .wk-stat .wk-spark { display: none; }
}
.wk-stat {
  display: grid;
  grid-template-columns: auto 1fr auto auto;
  grid-template-areas: "icon body spark go" "note note note note";
  align-items: center;
  gap: 4px 13px;
  padding: 16px;
  border-radius: var(--radius-lg);
  background: var(--glass-bg, var(--surface));
  -webkit-backdrop-filter: var(--glass-blur);
  backdrop-filter: var(--glass-blur);
  border: 1px solid var(--glass-rim, var(--border));
  text-align: left;
}
.wk-stat-icon {
  grid-area: icon;
  width: 42px; height: 42px; border-radius: 13px;
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 1.05rem;
  background: var(--tone-soft); color: var(--tone);
  border: 1px solid color-mix(in srgb, var(--tone) 22%, transparent);
}
.wk-stat-body { grid-area: body; min-width: 0; }
/* The number uses --tone-ink, not --tone. The bright tone is a graphic
   colour: correct on the icon tile and the sparkline, but measured at 2.20:1
   against the light background as text. --tone-ink is the same hue darkened
   until it clears 3:1 as large text, verified at the smallest text-size
   setting (0.9 x 1.85rem = 26.6px bold, still large text). */
.wk-stat-n { font-size: 1.85rem; font-weight: 800; color: var(--tone-ink, var(--tone)); line-height: 1.05; }
.wk-stat-l {
  /* 0.68rem was 10.88px. Uppercase with letter-spacing reads smaller still,
     and this is the word that says what the number means. */
  font-size: 0.72rem; color: var(--text-muted); font-weight: 800;
  text-transform: uppercase; letter-spacing: 0.07em; margin-top: 1px;
}
.wk-stat-note {
  grid-area: note;
  font-size: 0.72rem; color: var(--text-muted);
  margin-top: 9px; overflow-wrap: anywhere;
}

/* Per-card tone. The sparkline inherits it through currentColor, so one
   declaration colours the icon, the number and the line together. */
.wk-stat[data-tone="active"]  { --tone: var(--primary); --tone-soft: var(--primary-soft); --tone-ink: #c56952; }
.wk-stat[data-tone="pending"] { --tone: var(--warning); --tone-soft: var(--warning-soft); --tone-ink: #a77b46; }
.wk-stat[data-tone="done"]    { --tone: var(--success); --tone-soft: var(--success-soft); --tone-ink: #449175; }

/* On a dark ground the bright tone is already the high-contrast choice, so
   the darkened ink would be the wrong direction. */
:root[data-theme="dark"] .wk-stat,
:root[data-theme="dark"] .wk-stat[data-tone] { --tone-ink: var(--tone); }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .wk-stat[data-tone] { --tone-ink: var(--tone); }
}

.wk-spark { grid-area: spark; color: var(--tone); line-height: 0; }
.wk-spark-svg { width: 76px; height: 26px; display: block; }

.wk-columns { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }

/* --------------------------------------------------------------------------
   Card chrome
   -------------------------------------------------------------------------- */
.wk-card { position: relative; overflow: hidden; }
/* A hairline of the card's own colour along the leading edge, so the three
   sections are told apart peripherally rather than by reading the heading. */
.wk-card[data-accent]::before {
  content: ""; position: absolute; inset: 0 auto 0 0; width: 3px;
  background: linear-gradient(180deg, var(--accent), transparent 85%);
  /* Rounded to the card's own corner. A square-ended bar on a rounded card
     pokes past the corner and looks like it belongs to the page, not the
     card. */
  border-radius: var(--radius) 0 0 var(--radius);
}
.wk-card[data-accent="active"] { --accent: var(--primary); }
.wk-card[data-accent="info"]   { --accent: var(--info); }
.wk-card[data-accent="lab"]    { --accent: var(--cat-lab); }

.wk-card-head { display: flex; align-items: center; gap: 11px; margin-bottom: 14px; }
.wk-card-head h3 { margin: 0; font-size: 0.97rem; font-weight: 800; }
.wk-card-titles { flex: 1 1 auto; min-width: 0; }
.wk-card-sub { margin: 3px 0 0; font-size: 0.78rem; color: var(--text-muted); }
.wk-card-icon {
  flex: 0 0 auto;
  width: 36px; height: 36px; border-radius: 11px;
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 0.95rem;
  background: var(--tone-soft); color: var(--tone);
  border: 1px solid color-mix(in srgb, var(--tone) 20%, transparent);
}
.wk-card-icon[data-tone="active"] { --tone: var(--primary); --tone-soft: var(--primary-soft); }
.wk-card-icon[data-tone="info"]   { --tone: var(--info);    --tone-soft: var(--info-soft); }
.wk-card-icon[data-tone="lab"]    { --tone: var(--cat-lab); --tone-soft: var(--cat-lab-soft); }
.wk-card-icon[data-tone="alert"]  { --tone: var(--cat-deadline); --tone-soft: var(--cat-deadline-soft); }

.wk-sort {
  flex: 0 0 auto;
  padding: 7px 11px;
  border-radius: var(--radius-pill);
  border: 1px solid var(--border);
  background: var(--surface-alt);
  color: var(--text-soft);
  font: inherit; font-size: 0.76rem; font-weight: 700;
  cursor: pointer;
}
.wk-sort:focus-visible { outline: none; box-shadow: 0 0 0 3px var(--primary-ring); }

/* The card's footer: one full-width row, so the target is the width of the
   card rather than the width of the words. */
.wk-viewall {
  display: flex; align-items: center; justify-content: space-between;
  width: 100%; margin-top: 6px;
  padding: 12px 13px;
  border: 1px solid var(--border);
  border-radius: 12px;
  background: none;
  color: var(--text-soft);
  font: inherit; font-size: 0.8rem; font-weight: 700;
  cursor: pointer;
  transition: background var(--t-fast) var(--ease), color var(--t-fast) var(--ease);
}
.wk-viewall:hover { background: var(--primary-softer); color: var(--primary); border-color: var(--primary-soft); }
.wk-viewall:focus-visible { outline: none; box-shadow: 0 0 0 3px var(--primary-ring); }
.wk-chev { color: var(--text-muted); font-size: 1.05rem; line-height: 1; flex: 0 0 auto; }
.wk-viewall .wk-chev { transition: transform var(--t) var(--ease); }
.wk-viewall.is-open .wk-chev { transform: rotate(90deg); }

/* --------------------------------------------------------------------------
   Waiting on you
   -------------------------------------------------------------------------- */
.wk-inbox { min-height: 108px; }
/* The illustration is the empty state and nothing more: it sits behind the
   text, is decorative to a screen reader, and disappears the moment a real
   obligation arrives. */
.wk-inbox {
  /* What the illustration claims out of the card head: the glyph itself, the
     distance it sits off the card's edge, and a gap so the caption stops
     short of it rather than touching. Measured, not guessed -- at 1280px the
     glyph is 57px wide sitting 26px in. */
  --inbox-art-reserve: 80px;
}

/* The caption used to run underneath the illustration. Both are inside the
   card and the art is positioned out of flow, so nothing made the text stop:
   at 390px the heading and the caption both ran to x=353 and the glyph sat
   from 307 to 353, straight over the top of them.

   Keyed on whether the art is actually on screen rather than on the card's
   has-items class. The two are toggled together today, but the class says
   "there is something in the inbox" and what the padding needs to know is
   "there is a picture in the corner" -- and those are one refactor away from
   being different questions. */
.wk-inbox:has(.wk-inbox-art:not(.hidden)) .wk-card-titles {
  padding-right: var(--inbox-art-reserve);
}

.wk-inbox-art {
  position: absolute; right: 26px; top: 50%;
  transform: translateY(-50%);
  font-size: 2.6rem;
  opacity: 0.9;
  pointer-events: none;
}
.wk-inbox-art::after {
  content: ""; position: absolute; inset: -34px;
  background: radial-gradient(circle, var(--primary-soft) 0%, transparent 68%);
  opacity: 0.7; z-index: -1;
}
.wk-inbox.has-items .wk-card-head { margin-bottom: 6px; }

/* --------------------------------------------------------------------------
   Requests: the only things here that block someone else
   -------------------------------------------------------------------------- */
.wk-request {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap; row-gap: 8px;
  padding: 12px 0;
  border-bottom: 1px solid var(--border);
}
.wk-request:last-child { border-bottom: none; }
.wk-request-main { flex: 1 1 190px; min-width: 0; }
.wk-request-title { font-weight: 700; font-size: 0.9rem; }
.wk-request-meta { font-size: 0.76rem; color: var(--text-muted); margin-top: 2px; }
.wk-request-actions { display: flex; gap: 7px; margin-left: auto; flex-wrap: wrap; }

.wk-empty { color: var(--text-muted); font-size: 0.85rem; padding: 14px 0; }

/* --------------------------------------------------------------------------
   Tasks
   -------------------------------------------------------------------------- */
.wk-task {
  /* An anchor, so it needs block laying out and the link colours turned off.
     It is a link because it goes somewhere: middle-click, long-press and
     "open in new tab" all work now, and they could not when this was a div
     with a click handler. */
  display: block;
  color: inherit;
  text-decoration: none;
  padding: 12px;
  border-radius: 12px;
  margin-bottom: 9px;
  background: var(--surface-alt);
  border: 1px solid var(--border);
  cursor: pointer;
  transition: transform var(--t) var(--ease), box-shadow var(--t) var(--ease);
}
.wk-task:focus-visible,
.wk-community:focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: 2px;
}
.wk-task:hover { transform: translateY(-1px); box-shadow: var(--shadow); }
.wk-task-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-bottom: 7px; }
.wk-task-row { display: flex; align-items: flex-start; gap: 10px; margin-bottom: 10px; }
.wk-task-main { flex: 1 1 auto; min-width: 0; }
.wk-task-right { display: flex; align-items: center; gap: 8px; flex: 0 0 auto; }
.wk-task-title { font-weight: 700; font-size: 0.87rem; min-width: 0; overflow-wrap: anywhere; }
.wk-task-meta { font-size: 0.74rem; color: var(--text-muted); margin-top: 4px; overflow-wrap: anywhere; }

/* Priority as a colour rather than an emoji: emoji render at wildly different
   sizes and baselines per platform, and this has to line up with a title. */
.wk-dot {
  flex: 0 0 auto;
  width: 9px; height: 9px; border-radius: 50%;
  margin-top: 5px;
  background: var(--text-muted);
  box-shadow: 0 0 0 3px color-mix(in srgb, currentColor 12%, transparent);
}
.wk-dot[data-p="low"]    { background: var(--success); }
.wk-dot[data-p="medium"] { background: var(--warning); }
.wk-dot[data-p="high"]   { background: #e08a4b; }
.wk-dot[data-p="urgent"] { background: var(--danger); }

.wk-badge {
  padding: 3px 9px; border-radius: var(--radius-pill);
  font-size: 0.68rem; font-weight: 800; white-space: nowrap;
}
.wk-badge.done { background: var(--success-soft); color: var(--success); }
.wk-pct { font-size: 0.78rem; font-weight: 800; color: var(--primary); flex: 0 0 auto; }

.wk-bar {
  height: 7px; border-radius: var(--radius-pill);
  background: var(--border); overflow: hidden;
}
.wk-bar > span {
  display: block; height: 100%;
  border-radius: inherit;
  background: linear-gradient(90deg, var(--primary), var(--primary-hover));
  /* Width, not transform: the bar is a measurement, and a scaled bar would
     also scale a rounded end into an ellipse. */
  transition: width var(--t-slow) var(--ease-out);
}

/* --------------------------------------------------------------------------
   People
   -------------------------------------------------------------------------- */
.wk-people { display: flex; flex-direction: column; gap: 9px; margin-top: 6px; }
.wk-person { display: flex; align-items: center; gap: 10px; font-size: 0.84rem; }
.wk-person-name { font-weight: 600; flex: 0 0 auto; }
.wk-person-bar { flex: 1; min-width: 60px; }
.wk-avatar {
  width: 26px; height: 26px; flex: 0 0 auto;
  border-radius: 50%;
  background: var(--primary-soft); color: var(--primary-hover);
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 0.72rem; font-weight: 800;
}
.wk-chip {
  font-size: 0.7rem; font-weight: 700;
  padding: 3px 9px; border-radius: var(--radius-pill);
  background: var(--bg-tint); color: var(--text-muted);
  white-space: nowrap;
}
.wk-chip.pending { background: var(--warning-soft); color: var(--warning); }
.wk-chip.declined { background: var(--danger-soft); color: var(--danger); }
.wk-chip.role { background: var(--primary-softer); color: var(--primary); text-transform: capitalize; }

.wk-community {
  display: flex; align-items: center; gap: 12px;
  color: inherit; text-decoration: none;
  padding: 11px; margin-bottom: 8px;
  border-radius: 12px;
  background: var(--surface-alt); border: 1px solid var(--border);
  cursor: pointer;
  transition: transform var(--t) var(--ease), background var(--t) var(--ease);
}
.wk-community:hover { transform: translateX(2px); background: var(--primary-softer); }
.wk-community-main { flex: 1 1 auto; min-width: 0; }
.wk-community-icon {
  flex: 0 0 auto;
  width: 38px; height: 38px; border-radius: 12px;
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 1.05rem;
  background: var(--info-soft);
  border: 1px solid color-mix(in srgb, var(--info) 20%, transparent);
}
.wk-community-name { font-weight: 700; font-size: 0.88rem; }

/* Overall progress and the rule behind it */
.wk-overall { padding: 12px; border-radius: 12px; background: var(--surface-alt); margin-bottom: 14px; }
/* Stated in the UI, not just the payload: a number averaged over some members
   and not others is misleading unless the rule is visible. */
.wk-basis { font-size: 0.71rem; color: var(--text-muted); margin-top: 7px; }

.wk-timeline { margin-top: 16px; border-top: 1px solid var(--border); padding-top: 12px; }
.wk-tl-row { display: flex; gap: 10px; font-size: 0.78rem; padding: 5px 0; color: var(--text-soft); }
.wk-tl-when { color: var(--text-muted); flex: 0 0 96px; }

.wk-picker { display: flex; flex-direction: column; gap: 6px; max-height: 190px; overflow-y: auto; }
.wk-pick {
  display: flex; align-items: center; gap: 9px;
  padding: 7px 10px; border-radius: 10px;
  background: var(--surface-alt); cursor: pointer;
  font-size: 0.84rem;
}
.wk-pick:hover { background: var(--primary-softer); }
.wk-pick input { width: auto; }

/* --------------------------------------------------------------------------
   Mobile
   -------------------------------------------------------------------------- */
@media (max-width: 768px) {
  .wk-columns { grid-template-columns: 1fr; }
  .wk-hero { gap: 12px; }
  .wk-hero-text h2 { font-size: 1.3rem; }
  .wk-hero-tools { width: 100%; }
  .wk-search { flex: 1 1 100%; min-width: 0; }
  .wk-hero-tools .btn { width: 100%; }
  .wk-search input { padding-block: 12px; }

  /* Three columns cannot carry an icon, a number and a sparkline at phone
     width -- measured at 360px the number column collapsed to 50px. One card
     per row keeps all three legible and still fits above the fold. */
  .wk-stats { grid-template-columns: 1fr; gap: 10px; }
  .wk-stat {
    grid-template-areas: "icon body spark" "note note note";
    padding: 13px 14px;
  }
  .wk-stat-body { display: flex; align-items: baseline; gap: 9px; flex-wrap: wrap; }
  .wk-stat-n { font-size: 1.5rem; }
  .wk-stat-l { margin-top: 0; }
  .wk-stat-note { margin-top: 7px; }
  .wk-stat-icon { width: 38px; height: 38px; }

  /* 46px of glyph, 16px off the edge, and a gap. */
  .wk-inbox { --inbox-art-reserve: 58px; }
  .wk-inbox-art { font-size: 2.1rem; right: 16px; }
  .wk-card-head { gap: 10px; }
  .wk-viewall { padding: 14px 13px; }
  /* Measured at 360px: padding alone left the select at 35px, under the
     44px touch minimum, because a select sizes from its line box. */
  .wk-sort { padding: 9px 12px; min-height: 44px; }
  .wk-search-clear { width: 40px; height: 40px; right: 4px; }
  .wk-tl-when { flex-basis: 74px; }
}

@media (max-width: 380px) {
  /* The caption is the first thing to go: the count and its trend still say
     what the card is for. */
  .wk-stat { gap: 3px 10px; }
  .wk-spark-svg { width: 58px; }
  .wk-inbox-art { display: none; }
  /* Nothing to reserve for once the picture has gone. */
  .wk-inbox { --inbox-art-reserve: 0px; }
}

/* ==========================================================================
   Work notification centre
   ========================================================================== */
.wn-day {
  position: sticky; top: -9px; z-index: 1;
  padding: 8px 13px 5px;
  font-size: 0.68rem; font-weight: 800; letter-spacing: 0.05em;
  text-transform: uppercase; color: var(--text-muted);
  background: var(--glass-bg-strong, var(--surface));
}
.wn-item {
  display: flex; align-items: flex-start; gap: 10px;
  padding: 11px 13px; border-radius: 11px;
  cursor: pointer;
  transition: background var(--t-fast) var(--ease);
}
.wn-item:hover { background: var(--surface-alt); }
.wn-item.unread { background: var(--primary-softer); }
.wn-ico { font-size: 1rem; line-height: 1.3; flex: 0 0 auto; }
.wn-body { flex: 1; min-width: 0; }
/* Wraps rather than truncating: a notification whose point is cut off is a
   notification that has to be tapped to be understood. */
.wn-title { font-size: 0.83rem; font-weight: 600; overflow-wrap: anywhere; }
.wn-sub { font-size: 0.75rem; color: var(--text-soft); margin-top: 2px; overflow-wrap: anywhere; }
.wn-when { font-size: 0.69rem; color: var(--text-muted); margin-top: 3px; }
.wn-x {
  border: none; background: none; padding: 3px 5px; border-radius: 7px;
  color: var(--text-muted); cursor: pointer; font-size: 0.75rem;
  flex: 0 0 auto; opacity: 0.55;
}
.wn-x:hover { opacity: 1; background: var(--danger-soft); color: var(--danger); }

@media (max-width: 768px) {
  /* Down from the bell it belongs to, not up from the floor.

     It still spans the width rather than being a dropdown pinned to a
     40px icon -- at forty items that dropdown is taller than the screen and
     unreadable -- but it now starts where the bell is, so the panel and the
     control that opened it are the same gesture and the same place. */
  .popover {
    position: fixed;
    top: var(--topbar-h, 65px); right: 0; left: 0; bottom: auto;
    width: auto; max-width: none;
    /* Stops short of the tab bar rather than running under it. */
    max-height: calc(100vh - var(--topbar-h, 65px) - var(--bottom-nav-h, 64px) - 12px);
    border-radius: 0 0 20px 20px;
    padding-bottom: 6px;
    animation: sheetDown 240ms var(--ease-out) both;
    transform-origin: top center;
    /* The gesture moves this element, so nothing above it may capture the
       pan: the browser would otherwise start its own scroll or overscroll
       and fight the drag. */
    overscroll-behavior: contain;
    touch-action: pan-y;
  }

  /* The grab handle. A pseudo-element rather than a node, because the panel's
     contents are replaced wholesale on every refresh and a real element would
     have to be re-inserted each time. Sticky so it stays put while the list
     scrolls under it. */
  .popover::after {
    content: "";
    position: sticky; bottom: 0; z-index: 2;
    display: block; width: 42px; height: 4px;
    margin: 9px auto -1px;
    border-radius: var(--radius-pill);
    background: var(--border-strong);
  }

  /* While a finger is on it: no transition, so the sheet tracks the thumb
     exactly rather than easing behind it. */
  .popover.is-dragging {
    animation: none;
    transition: none;
    will-change: transform;
  }

  /* Let go past the threshold. */
  .popover.is-dismissing {
    animation: none;
    transition: transform 200ms var(--ease), opacity 200ms var(--ease);
    transform: translateY(-100%);
    opacity: 0.6;
  }

  /* Snapping back after a drag that did not go far enough. */
  .popover.is-settling {
    animation: none;
    transition: transform 220ms var(--ease-out);
    transform: none;
  }
}

@media (max-width: 768px) and (prefers-reduced-motion: reduce) {
  /* The drag still tracks the finger -- that is direct manipulation, not
     decoration -- but the release is instant rather than a slide. */
  .popover.is-dismissing { transition: none; }
  .popover.is-settling { transition: none; }
}

@media (max-width: 768px) {
  .wn-item { padding: 13px; }
  /* Comfortable one-handed targets. Measured at 37px with padding alone,
     which is under the ~44px a thumb reliably hits. */
  .wn-x { min-width: 44px; min-height: 44px; font-size: 0.9rem; }
}

/* ==========================================================================
   Mobile: measured fixes
   ========================================================================== */
@media (max-width: 768px) {
  /* Measured at 360px: the switcher tabs were 34px tall, below the ~44px a
     thumb reliably hits. */
  .ps-opt { min-height: 44px; padding: 10px 14px; }

  /* Every action in Work is a decision someone else is waiting on -- accept,
     decline, save progress. None of them should need a second attempt. */
  .wk-request-actions .btn,
  .wk-people .chip-x,
  #wk-save-progress { min-height: 44px; }
  .wk-request-actions .btn { flex: 1 1 auto; justify-content: center; }

  /* Whole card is the target, not just the title. */
  .wk-task { padding: 14px; }
  .wk-community { padding: 14px; }

  /* A range input is the hardest control to hit on a phone; give it room. */
  #wk-my-progress { height: 30px; }

  /* Modals sit above the keyboard rather than behind it: 85vh leaves the
     sheet scrollable when the keyboard takes the bottom half. */
  .modal-card { max-height: 85vh; }
}

/* Very small phones (360px and below) -- the counts row is the first thing
   to break, three numbers side by side with their labels. */
@media (max-width: 380px) {
  .wk-stat { padding: 11px 6px; }
  .wk-stat-n { font-size: 1.2rem; }
  .wk-stat-l { font-size: 0.68rem; letter-spacing: 0.02em; }
  .wk-request-actions { width: 100%; }
  .ps-opt { padding: 10px 10px; font-size: 0.75rem; }
}

/* Each row says which side it came from. The two feeds are merged in one
   inbox, so without a tag "Rahul accepted" and "Lecture in 30 minutes" would
   sit together with nothing to distinguish a colleague's action from your own
   timetable. */
.wn-when { display: flex; align-items: center; gap: 6px; }
.wn-tag {
  font-size: 0.6rem; font-weight: 800; letter-spacing: 0.04em;
  text-transform: uppercase;
  padding: 2px 6px; border-radius: var(--radius-pill);
}
.wn-tag.work { background: var(--primary-soft); color: var(--primary-hover); }
.wn-tag.personal { background: var(--info-soft); color: var(--info); }

/* ==========================================================================
   Identity block: who you are, and which of your two views is open
   ========================================================================== */
.user-block {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 6px;
  min-width: 0;
}
.user-block .user-chip { padding: 0; background: none; border: none; box-shadow: none; }
.user-meta { min-width: 0; }

/* Sits under the name rather than at the far end of the bar. The switcher
   belongs to the account, and the two should read as one block. */
.user-block .profile-switch { margin: 0; }
.user-block .ps-opt { padding: 5px 12px; font-size: 0.74rem; }

/* --------------------------------------------------------------------------
   Phone
   -------------------------------------------------------------------------- */
@media (max-width: 768px) {
  /* One row, not two.
     These rules used to stretch .topbar-actions to the full width so a
     permanent profile switcher could have a row of its own. That switcher
     moved into the account menu, but the rules stayed -- and measured at
     393px they were still pushing the icons onto a second line, leaving the
     hamburger alone on the first and the bar 117px tall before any content.
     Nothing here needs to wrap now: menu, theme, bell and avatar fit in one
     row with room to spare. */
  .topbar { flex-wrap: nowrap; align-items: center; }
  .topbar-actions { flex-wrap: nowrap; width: auto; justify-content: flex-end; }

  /* The caret reads as a stray character once the name beside it is hidden,
     and the avatar is plainly tappable without it. The work count moves onto
     the avatar, where it belongs to something. */
  button.user-chip .user-caret { display: none; }
  button.user-chip .ps-badge { top: -4px; right: -4px; }
}

@media (max-width: 380px) {
  .topbar-actions { gap: 6px; }
  .topbar .ps-opt { font-size: 0.72rem; padding: 8px 6px; }
}

/* ==========================================================================
   Account menu
   The name is the control: one affordance for "who am I" and "which view",
   instead of a permanent switcher competing for a row on a phone.
   ========================================================================== */
.user-block { position: relative; }

button.user-chip {
  display: inline-flex; align-items: center; gap: 9px;
  padding: 5px 10px 5px 5px;
  border-radius: var(--radius-pill);
  border: 1px solid var(--glass-rim, var(--border));
  background: var(--glass-bg-faint, var(--surface));
  -webkit-backdrop-filter: var(--glass-blur-sm);
  backdrop-filter: var(--glass-blur-sm);
  color: var(--text);
  font: inherit; text-align: left;
  cursor: pointer;
  position: relative;
  transition: background var(--t-fast) var(--ease), box-shadow var(--t-fast) var(--ease);
}
button.user-chip:hover { background: var(--glass-bg, var(--surface-alt)); }
button.user-chip:focus-visible { outline: none; box-shadow: 0 0 0 4px var(--primary-ring); }
button.user-chip .user-meta { display: flex; flex-direction: column; line-height: 1.25; min-width: 0; }
.user-caret { color: var(--text-muted); font-size: 0.7rem; margin-left: 2px; }

/* The work count rides the account button, since the switcher that used to
   carry it now lives inside the menu. */
button.user-chip .ps-badge { position: absolute; top: -3px; right: -3px; }

.user-menu {
  position: absolute; top: calc(100% + 8px); right: 0;
  min-width: 232px; z-index: 130;
  padding: 7px;
  border-radius: var(--radius);
  background: var(--glass-bg-strong, var(--surface));
  -webkit-backdrop-filter: var(--glass-blur-lg);
  backdrop-filter: var(--glass-blur-lg);
  border: 1px solid var(--glass-rim, var(--border));
  box-shadow: var(--glass-shadow-lg, var(--shadow-lg));
  animation: scaleIn var(--t) var(--ease-out) both;
  transform-origin: top right;
}
.um-head { padding: 9px 11px 11px; border-bottom: 1px solid var(--border); margin-bottom: 6px; }
.um-name { font-weight: 700; font-size: 0.87rem; }
.um-mail { font-size: 0.73rem; color: var(--text-muted); overflow-wrap: anywhere; }

.um-label {
  padding: 5px 11px 3px;
  font-size: 0.65rem; font-weight: 800; letter-spacing: 0.06em;
  text-transform: uppercase; color: var(--text-muted);
}
.um-item {
  display: flex; align-items: center; gap: 10px;
  width: 100%;
  padding: 10px 11px;
  border: none; background: none;
  border-radius: 10px;
  font: inherit; font-size: 0.84rem; font-weight: 600;
  color: var(--text); text-decoration: none;
  cursor: pointer;
  transition: background var(--t-fast) var(--ease);
}
.um-item:hover { background: var(--surface-alt); }
.um-item.active { background: var(--primary-softer); color: var(--primary); }
/* The tick marks the view you are already in, so the menu answers "which am
   I in" as well as offering the switch. */
.um-tick { margin-left: auto; opacity: 0; color: var(--primary); font-weight: 800; }
.um-item.active .um-tick { opacity: 1; }
.um-count {
  margin-left: auto;
  min-width: 19px; height: 19px; padding: 0 5px;
  border-radius: var(--radius-pill);
  background: var(--danger); color: #fff;
  font-size: 0.65rem; font-weight: 800;
  display: inline-flex; align-items: center; justify-content: center;
}
.um-item.active .um-count { margin-left: auto; }
.um-sep { height: 1px; background: var(--border); margin: 6px 4px; }
.um-danger:hover { background: var(--danger-soft); color: var(--danger); }

/* ==========================================================================
   Leaving a sheet without changing anything
   ========================================================================== */
.sheet-close {
  position: absolute; top: 12px; right: 12px;
  width: 34px; height: 34px;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: 50%;
  border: 1px solid var(--glass-rim, var(--border));
  background: var(--glass-bg-faint, var(--surface-alt));
  color: var(--text-soft);
  font-size: 0.8rem; cursor: pointer;
  z-index: 2;
  transition: background var(--t-fast) var(--ease), color var(--t-fast) var(--ease);
}
.sheet-close:hover { background: var(--danger-soft); color: var(--danger); }
.modal-card { position: relative; }

/* ==========================================================================
   Live progress
   ========================================================================== */

.wk-progress-editor label { display: flex; align-items: center; gap: 8px; }
.wk-progress-editor strong { color: var(--primary); font-size: 0.95rem; }
/* Moving a slider looks like it saved. It has not. */
.wk-dirty {
  font-size: 0.64rem; font-weight: 800; letter-spacing: 0.04em;
  text-transform: uppercase;
  padding: 2px 7px; border-radius: var(--radius-pill);
  background: var(--warning-soft); color: var(--warning);
}
#wk-my-progress { width: 100%; }

@media (max-width: 768px) {
  /* The name is redundant on a phone -- the avatar is the identity anchor and
     the menu repeats the full name at the top anyway. */
  button.user-chip .user-meta { display: none; }
  /* Measured at 32px tall with padding alone. This is the control that opens
     the profile switch, so it is the last thing that should need a second
     tap. */
  button.user-chip { padding: 5px 8px 5px 5px; min-height: 44px; }
  .user-menu { min-width: 236px; }
  /* 39px measured; a menu row is a target like any other. Padding rather
     than min-height, which the flex row was absorbing into its content box. */
  .um-item { padding: 13px 11px; }
  .sheet-close { width: 40px; height: 40px; top: 10px; right: 10px; }
  #wk-my-progress { height: 34px; }
}


/* ==========================================================================
   The same-college directory
   ========================================================================== */
.wk-directory { margin-bottom: 14px; }
.wk-search-inline { min-width: 0; margin-bottom: 10px; }
.wk-dir-scope {
  font-size: 0.72rem; color: var(--text-muted);
  padding: 2px 0 8px; border-bottom: 1px solid var(--border); margin-bottom: 8px;
}
#wk-dir-results { max-height: 260px; overflow-y: auto; }

.wk-dir-person { padding: 7px 0; gap: 11px; }
.wk-dir-main { flex: 1 1 auto; min-width: 0; }
/* Designation and department, not the email. Two colleagues with the same
   name still need telling apart, but a browsable list of addresses is a
   directory to harvest rather than a convenience. */
.wk-dir-meta {
  font-size: 0.72rem; color: var(--text-muted);
  margin-top: 1px; overflow-wrap: anywhere;
}
.wk-dir-person .btn { flex: 0 0 auto; margin-left: auto; }
.wk-dir-person .wk-chip { margin-left: auto; }

/* ==========================================================================
   Deleting a community
   ========================================================================== */
.wk-danger-zone {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  margin-top: 18px; padding: 13px 14px;
  border: 1px solid var(--danger-soft);
  border-radius: 12px;
  background: color-mix(in srgb, var(--danger) 5%, transparent);
}
.wk-danger-text { flex: 1 1 200px; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.wk-danger-text strong { font-size: 0.85rem; }
.wk-danger-text span { font-size: 0.73rem; color: var(--text-muted); }
.wk-danger-zone .btn { flex: 0 0 auto; }

.wk-danger-card h3 { padding-right: 40px; }
.wk-impact {
  list-style: none; margin: 0 0 12px; padding: 12px 14px;
  border-radius: 12px;
  background: var(--surface-alt);
  border: 1px solid var(--border);
  display: grid; gap: 5px;
}
.wk-impact li { font-size: 0.82rem; color: var(--text-soft); }
.wk-impact strong { color: var(--text); font-weight: 800; }

/* The one number that should actually stop someone: work other people
   accepted and have not finished. It is called out rather than listed. */
/* --danger measured 3.28:1 here, and this is 12.5px text -- the one sentence
   in the flow that exists to stop someone destroying a colleague's work has
   to be readable, so it uses a darkened tone that clears 4.5:1. */
.wk-impact-warn {
  margin: 0 0 14px; padding: 10px 13px;
  border-radius: 11px;
  background: var(--danger-soft);
  color: var(--danger-ink, var(--danger));
  font-size: 0.78rem; font-weight: 700;
  border: 1px solid color-mix(in srgb, var(--danger) 22%, transparent);
}
:root { --danger-ink: #aa504b; --danger-solid: #b95752; }
/* On a dark ground the light tone is already the readable one. */
:root[data-theme="dark"] { --danger-ink: var(--danger); --danger-solid: var(--danger); }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) { --danger-ink: var(--danger); --danger-solid: var(--danger); }
}

#wk-del-confirm { width: 100%; }
#wk-del-go:disabled { opacity: 0.45; cursor: not-allowed; }
/* White on --danger measured 3.28:1. The button that performs the deletion
   is not the place to lose a word of its own label. */
#wk-del-go:not(:disabled) {
  background: var(--danger-solid); color: #fff; border-color: var(--danger-solid);
}
#wk-del-go:not(:disabled):hover { background: var(--danger); border-color: var(--danger); }

@media (max-width: 768px) {
  #wk-dir-results { max-height: 46vh; }
  .wk-dir-person { padding: 9px 0; }
  /* Measured at 360px: both came out 40px from the small-button padding.
     Inviting and deleting are the two actions here, so neither should be
     the one that needs a second tap. */
  .wk-danger-zone .btn, .wk-dir-person .btn { min-height: 44px; }
  .wk-danger-zone { padding: 14px; }
}

/* ==========================================================================
   Organisation: college, department, and people shown by both
   ========================================================================== */
.wk-req { color: var(--danger-ink, var(--danger)); font-weight: 800; }

/* The mandatory panel has no backdrop dismissal and no ✕ on purpose: the
   server refuses the same actions, so letting it be flicked away would only
   produce errors later instead of a choice now. */
.wk-profile-card h3 { margin: 0 0 2px; }
.wk-profile-card select { width: 100%; }

/* Name over department, wherever a person appears. */
.wk-id { flex: 1 1 auto; min-width: 0; }
.wk-id .wk-person-name { font-weight: 700; font-size: 0.86rem; line-height: 1.3; }
.wk-id-dept {
  font-size: 0.72rem; color: var(--text-muted);
  line-height: 1.35; overflow-wrap: anywhere; margin-top: 1px;
}
.wk-person { align-items: flex-start; }
.wk-person .wk-avatar { margin-top: 1px; }
.wk-person .wk-chip, .wk-person .chip-x { flex: 0 1 auto; margin-top: 2px; }

/* The declined chip is the only one holding text a person typed, so it is the
   only one that cannot behave like a status pill.

   As nowrap and flex: 0 0 auto it refused to shrink and refused to wrap, so a
   reason of any length took the whole row and crushed .wk-id -- which has
   min-width: 0 -- to nothing. Measured at 393px with a six-word reason: the
   name block was 0px wide and the department rendered 575px tall, one letter
   per line, in a row 612px deep.

   Wrapping is right rather than truncating: the reason is why the work came
   back, which is the one thing the person who assigned it needs to read. */
.wk-chip.declined {
  white-space: normal;
  overflow-wrap: anywhere;
  text-align: left;
  min-width: 0;
}

/* The bar and its percentage move as one thing. As separate children of a
   wrapping row they could be split across two lines, leaving a number under a
   bar it no longer sits beside. */
.wk-person-progress {
  display: flex; align-items: center; gap: 8px;
  flex: 1 1 auto; min-width: 90px;
}
.wk-person-progress .wk-person-bar { flex: 1 1 auto; }

.wk-dir-role { opacity: 0.85; }

/* Search and department filter, side by side. */
.wk-filter-row { display: flex; gap: 8px; align-items: center; margin-bottom: 10px; }
.wk-filter-row .wk-search { flex: 1 1 auto; }
.wk-filter-row > input[type="search"] {
  flex: 1 1 auto; min-width: 0;
  padding: 10px 13px;
  border-radius: var(--radius-pill);
  border: 1px solid var(--glass-rim, var(--border));
  background: var(--glass-bg-faint, var(--surface));
  color: var(--text); font: inherit; font-size: 0.84rem;
}
.wk-filter-row > input[type="search"]:focus {
  outline: none; border-color: var(--primary); box-shadow: 0 0 0 4px var(--primary-ring);
}
.wk-filter-row select {
  flex: 0 0 auto; max-width: 46%;
  padding: 9px 11px;
  border-radius: var(--radius-pill);
  border: 1px solid var(--border);
  background: var(--surface-alt);
  color: var(--text-soft);
  font: inherit; font-size: 0.78rem; font-weight: 700;
  cursor: pointer;
}
.wk-filter-row select:focus-visible { outline: none; box-shadow: 0 0 0 3px var(--primary-ring); }

/* The assign picker now carries two lines per person. */
.wk-pick { display: flex; align-items: flex-start; gap: 10px; padding: 9px 4px; }
.wk-pick input[type="checkbox"] { margin-top: 4px; flex: 0 0 auto; }
.wk-pick[hidden] { display: none; }

/* ==========================================================================
   Admin: colleges and departments
   ========================================================================== */
.ad-college, .ad-dept {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap; row-gap: 8px;
  padding: 13px 0;
  border-bottom: 1px solid var(--border);
}
.ad-college:last-child, .ad-dept:last-child { border-bottom: none; }
.ad-college-main, .ad-dept-main { flex: 1 1 210px; min-width: 0; }
.ad-college-name { font-weight: 700; font-size: 0.9rem; display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.ad-college-meta { font-size: 0.75rem; color: var(--text-muted); margin-top: 3px; }
.ad-college-actions, .ad-dept-actions { display: flex; gap: 7px; margin-left: auto; flex-wrap: wrap; }
.ad-dept-main { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.ad-dept-name { font-weight: 700; font-size: 0.86rem; }
.ad-dept-meta { font-size: 0.73rem; color: var(--text-muted); }
/* Archived rows stay visible and legible -- they still hold members and
   history, and hiding them would make the count above unexplainable. */
.is-archived .ad-college-name, .is-archived .ad-dept-name { opacity: 0.62; }

/* --- Members of a college or a department ------------------------------- */
.ad-member {
  display: flex; align-items: center; gap: 11px;
  padding: 10px 0;
  border-bottom: 1px solid var(--border);
}
.ad-member:last-of-type { border-bottom: none; }
.ad-member-avatar {
  flex: 0 0 auto;
  width: 32px; height: 32px; border-radius: 50%;
  display: grid; place-items: center;
  background: var(--primary-soft); color: var(--primary-hover);
  font-weight: 800; font-size: 0.82rem;
}
.ad-member-main { min-width: 0; }
.ad-member-name { font-weight: 700; font-size: 0.87rem; }
/* Department first, designation after: the list is usually being read to
   answer "who is in this department", so that is the line that has to scan. */
.ad-member-meta { font-size: 0.74rem; color: var(--text-muted); margin-top: 2px; }
.ad-member-count {
  margin-top: 12px; padding-top: 10px;
  border-top: 1px dashed var(--border);
  font-size: 0.75rem; color: var(--text-muted);
}

@media (max-width: 768px) {
  .wk-filter-row { flex-wrap: wrap; }
  .wk-filter-row select { max-width: none; width: 100%; min-height: 44px; }
  .wk-filter-row > input[type="search"] { min-height: 44px; }
  .wk-profile-card select { min-height: 44px; }
  #wk-p-college, #wk-p-department { min-height: 44px; }
  /* Measured at 360px: these came out 40px from the small-button padding.
     Archive and delete are the consequential ones here. */
  .ad-college-actions .btn, .ad-dept-actions .chip-x { min-height: 44px; min-width: 44px; }
  #ad-dept-new, #ad-college-name, #ad-college-loc { min-height: 44px; }
  .ad-college, .ad-dept { padding: 14px 0; }
  .wk-pick { padding: 11px 4px; }
}

/* ==========================================================================
   Managing a task: roster and details
   ========================================================================== */
/* The per-person controls sit at the end of the row and stay out of the way
   until there is room; on a narrow sheet they wrap under rather than
   squeezing the name. */
.wk-person-actions { display: flex; gap: 4px; flex: 0 0 auto; margin-left: auto; }
.wk-person-actions .chip-x { opacity: 0.55; }
.wk-person-actions .chip-x:hover { opacity: 1; }
.wk-person-actions [data-unassign]:hover { background: var(--danger-soft); color: var(--danger-ink, var(--danger)); }

/* Folded away by default. Editing a task is the rarer thing to want when
   opening it -- reading who is where is the common one. */
.wk-manage { margin-top: 16px; }
.wk-manage-toggle {
  display: flex; align-items: center; justify-content: space-between;
  width: 100%; padding: 11px 13px;
  border: 1px solid var(--border); border-radius: 12px;
  background: none; color: var(--text-soft);
  font: inherit; font-size: 0.82rem; font-weight: 700;
  cursor: pointer;
  transition: background var(--t-fast) var(--ease), color var(--t-fast) var(--ease);
}
.wk-manage-toggle:hover { background: var(--primary-softer); color: var(--primary); }
.wk-manage-toggle:focus-visible { outline: none; box-shadow: 0 0 0 3px var(--primary-ring); }
.wk-manage-toggle .wk-chev { transition: transform var(--t) var(--ease); }
.wk-manage-toggle.is-open .wk-chev { transform: rotate(90deg); }

.wk-manage-panel {
  margin-top: 10px; padding: 14px;
  border: 1px solid var(--border); border-radius: 12px;
  background: var(--surface-alt);
  animation: scaleIn var(--t) var(--ease-out) both;
  transform-origin: top center;
}
.wk-manage-sep { height: 1px; background: var(--border); margin: 14px 0; }
.wk-manage-panel .form-hint { display: block; margin-top: 6px; }
#wk-add-member { flex: 1; min-width: 0; }

@media (max-width: 768px) {
  /* One line cannot hold an avatar, a name, a department, a status and two
     buttons at 393px. Rather than shrinking all of them until each is
     unreadable, the row becomes two: who it is, then how it is going.

     order moves the buttons up beside the name; without it they would land
     below the status, on a third line, because flex wraps in DOM order. */
  .wk-person { flex-wrap: wrap; row-gap: 6px; }
  .wk-person > .wk-person-actions { order: 1; margin-left: auto; }

  /* flex-basis: 0, and it has to be 0.

     A flex line is packed from hypothetical sizes and only shrunk afterwards,
     so with basis auto the identity block was measured at its full text width
     first -- filling the line on its own and pushing the buttons onto a line
     of their own, before any shrinking got a chance to run. At 0 it takes no
     part in that decision, then grows into whatever the buttons leave. */
  .wk-person > .wk-id { flex: 1 1 0; }

  .wk-person > .wk-chip,
  .wk-person > .wk-person-progress {
    order: 2;
    /* The indent is subtracted from the basis. A full 100% plus a margin is
       wider than the row, which is an overflow rather than a second line. */
    flex: 1 0 calc(100% - 36px);
    /* Indented past the avatar so the second line still reads as part of
       this person and not as a new one. */
    margin-left: 36px;
  }

  .wk-person-actions { margin-left: 0; }
  .wk-person-actions .chip-x { min-width: 44px; min-height: 44px; }
  .wk-manage-toggle { min-height: 44px; }
  /* The panel's own controls already reach 44px from the generic rule --
     they measure 42 only while the entry animation is mid-scale. */
  .sheet-close { width: 44px; height: 44px; }
}


/* --------------------------------------------------------------------------
   Detail pages

   A task and a community each have their own page. What used to be a dialog
   body is now the content of a card, so the renderer did not change -- only
   what it is rendering into.
   -------------------------------------------------------------------------- */
.wk-detail-bar {
  display: flex;
  align-items: center;
  margin-bottom: 14px;
}

.wk-back {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  /* 44px tall: this is the control every route out of the page goes through,
     and on a phone it is reached with a thumb. */
  min-height: 44px;
  padding: 0 14px 0 10px;
  border-radius: 999px;
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--text);
  font: inherit;
  font-size: 0.86rem;
  font-weight: 650;
  cursor: pointer;
  transition: background var(--t) var(--ease), transform var(--t) var(--ease);
}
.wk-back:hover { background: var(--primary-softer); transform: translateX(-2px); }
.wk-back:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }
.wk-back-chev { font-size: 1.3em; line-height: 1; margin-top: -2px; }

.wk-detail-card { padding: 18px; }

/* The dialog put its actions in a row at the bottom; on a page that row is
   just a row of buttons, and the dialog's top margin would leave it floating. */
.wk-detail-card .modal-actions { margin-top: 14px; }

.wk-detail-error {
  text-align: center;
  padding: 34px 16px;
}
.wk-detail-error-art { font-size: 2.4rem; margin-bottom: 10px; opacity: 0.7; }
.wk-detail-error p { color: var(--text-muted); margin: 0 0 16px; }


/* ==========================================================================
   Attachments

   Directly under the progress bar, because that is where the evidence for a
   number belongs: a percentage and the report justifying it should be read in
   one glance, not one above the fold and the other below it.
   ========================================================================== */
.wk-atts {
  margin: 12px 0 4px;
  padding: 12px;
  border: 1px solid var(--border);
  border-radius: 12px;
  background: var(--surface-alt);
}
.wk-atts-head {
  display: flex; align-items: center; gap: 8px;
  font-size: 0.82rem; margin-bottom: 8px;
}
.wk-atts-count {
  font-size: 0.7rem; font-weight: 800;
  background: var(--bg-tint); color: var(--text-muted);
  padding: 1px 7px; border-radius: var(--radius-pill);
}
.wk-atts-empty { font-size: 0.78rem; color: var(--text-muted); margin: 0; }

.wk-att {
  display: flex; align-items: center; gap: 10px;
  padding: 8px; border-radius: 10px;
  background: var(--surface);
  border: 1px solid var(--border);
  margin-bottom: 6px;
}
.wk-att-icon { font-size: 1.15rem; flex: 0 0 auto; }
/* min-width: 0 so a long filename truncates instead of pushing the actions off
   the row -- the same collapse the person rows had. */
.wk-att-main { flex: 1 1 auto; min-width: 0; }
.wk-att-name {
  font-weight: 650; font-size: 0.82rem;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.wk-att-meta { font-size: 0.72rem; color: var(--text-muted); margin-top: 1px; }
.wk-att-actions { display: flex; align-items: center; gap: 8px; flex: 0 0 auto; }
.wk-att-act {
  font-size: 0.75rem; font-weight: 700;
  color: var(--primary); text-decoration: none;
}
/* The underline on hover is now drawn by .lnk-wipe / .lnk-arrow, which animate
   it. Leaving text-decoration here as well would draw a second, static line
   under the first. */

.wk-atts-more {
  display: block; width: 100%;
  margin-top: 4px; padding: 7px;
  border: none; background: transparent;
  color: var(--primary); font: inherit; font-size: 0.78rem; font-weight: 700;
  cursor: pointer; border-radius: 8px;
}
.wk-atts-more:hover { background: var(--primary-softer); }

.wk-att-add {
  display: inline-flex; align-items: center; gap: 6px;
  margin-top: 8px; padding: 8px 14px;
  border: 1px dashed var(--border-strong);
  border-radius: var(--radius-pill);
  font-size: 0.78rem; font-weight: 700;
  color: var(--text-soft); cursor: pointer;
  transition: background var(--t) var(--ease), border-color var(--t) var(--ease);
}
.wk-att-add:hover { background: var(--primary-softer); border-color: var(--primary); color: var(--primary); }

.wk-att-progress { display: flex; align-items: center; gap: 10px; margin-top: 10px; }
.wk-att-progress .wk-bar { flex: 1 1 auto; }
.wk-att-progress-label { font-size: 0.72rem; color: var(--text-muted); flex: 0 0 auto; }

/* ==========================================================================
   Work board
   ========================================================================== */
.wk-metrics {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
  gap: 10px;
}
.wk-metric {
  padding: 12px;
  border-radius: 12px;
  background: var(--surface-alt);
  border: 1px solid var(--border);
  text-align: center;
}
.wk-metric-n { font-size: 1.6rem; font-weight: 800; line-height: 1.05; color: var(--text); }
.wk-metric-l {
  font-size: 0.72rem; font-weight: 800; color: var(--text-muted);
  text-transform: uppercase; letter-spacing: 0.06em; margin-top: 3px;
}
.wk-metric[data-tone="alert"] .wk-metric-n { color: var(--danger); }
.wk-metric[data-tone="done"] .wk-metric-n { color: var(--primary); }

.wk-board-search { display: flex; gap: 8px; align-items: center; margin-bottom: 10px; }
.wk-board-search input {
  flex: 1 1 auto; min-width: 0;
  padding: 10px 14px; border-radius: var(--radius-pill);
  border: 1px solid var(--border); background: var(--surface-alt);
  font: inherit; font-size: 0.85rem; color: var(--text);
}

.wk-filters { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 12px; }
.wk-filters select, .wk-range input {
  padding: 8px 12px; border-radius: 10px;
  border: 1px solid var(--border); background: var(--surface);
  font: inherit; font-size: 0.8rem; color: var(--text);
}
.wk-range { display: flex; gap: 8px; }

/* --- The performance table --- */
.wk-table-wrap { overflow-x: auto; }
.wk-table { width: 100%; border-collapse: collapse; font-size: 0.82rem; }
.wk-table th, .wk-table td {
  padding: 10px 8px; text-align: left; vertical-align: middle;
  border-bottom: 1px solid var(--border);
}
.wk-table th {
  font-size: 0.7rem; font-weight: 800; color: var(--text-muted);
  text-transform: uppercase; letter-spacing: 0.05em;
}
.wk-table .num { text-align: right; font-variant-numeric: tabular-nums; }
.wk-table tbody tr { cursor: pointer; transition: background var(--t-fast) var(--ease); }
.wk-table tbody tr:hover { background: var(--primary-softer); }
.wk-table tbody tr:focus-visible { outline: 2px solid var(--primary); outline-offset: -2px; }
.wk-late { color: var(--danger); font-weight: 800; }

.wk-inline-bar { display: flex; align-items: center; gap: 8px; min-width: 120px; }
.wk-inline-bar .wk-bar { flex: 1 1 auto; }

/* --- One task in a member's history --- */
.wk-track {
  display: block; color: inherit; text-decoration: none;
  padding: 11px; margin-bottom: 8px;
  border-radius: 12px;
  background: var(--surface-alt); border: 1px solid var(--border);
  transition: transform var(--t) var(--ease), box-shadow var(--t) var(--ease);
}
.wk-track:hover { transform: translateY(-1px); box-shadow: var(--shadow); }
.wk-track:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }
.wk-track-head { display: flex; align-items: flex-start; gap: 9px; margin-bottom: 9px; }
.wk-track-main { flex: 1 1 auto; min-width: 0; }
.wk-track-atts { font-size: 0.72rem; color: var(--text-muted); margin-top: 7px; }
.wk-track-note { font-size: 0.72rem; color: var(--danger); margin-top: 6px; }

.wk-badge.pending { background: var(--bg-tint); color: var(--text-muted); }
.wk-badge.in_progress { background: var(--primary-softer); color: var(--primary); }
.wk-badge.completed { background: var(--primary-softer); color: var(--primary); }
.wk-badge.incomplete { background: var(--bg-tint); color: var(--text-muted); }
.wk-badge.overdue { background: var(--danger-soft); color: var(--danger); }
.wk-bar.late span { background: var(--danger); }

/* Why a colleague's list is shorter than the numbers above it. */
.wk-scope-note {
  margin: 0 0 10px;
  padding: 9px 11px;
  border-radius: 10px;
  background: var(--bg-tint);
  color: var(--text-muted);
  font-size: 0.76rem;
  line-height: 1.45;
}


/* ==========================================================================
   Adaptive slider

   The progress control on a task: a pill track with a gradient fill that
   changes colour as the value climbs, and a white thumb that springs into
   place when released.

   One number drives all of it. --pct is set once on the wrapper and the fill
   width, the thumb position and the colour all read it, so they cannot drift
   apart mid-drag the way three separately-updated properties would.

   The real <input type="range"> is still here, transparent, on top. Everything
   visible is paint. Rebuilding a slider out of divs and pointer maths costs
   the keyboard, the screen reader, the touch behaviour and the step snapping
   that the browser already gets right -- and this control is how somebody
   records that their work is finished, which is not a place to lose any of it.
   ========================================================================== */
.aslider {
  --pct: 0;
  --aslider-h: 52px;
  --thumb: 44px;
  position: relative;
  margin: 10px 0 4px;
  touch-action: none;          /* the drag is the control, not a page scroll */
}

.aslider-track {
  position: relative;
  height: var(--aslider-h);
  border-radius: 999px;
  background: var(--surface-alt);
  border: 1px solid var(--border);
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: space-evenly;
}

/* Six dots along the track. They are what stops an empty slider reading as a
   disabled input: something is clearly there to be moved. */
.aslider-track > i {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--border-strong);
  opacity: 0.7;
  flex: 0 0 auto;
}

.aslider-fill {
  position: absolute;
  inset: 0 auto 0 0;
  width: calc(var(--pct) * 1%);
  border-radius: 999px;
  /* The colour carries the meaning, so the stops are the app's own rather
     than the source component's orange/pink/purple: amber while it is early,
     the brand orange in the middle, green once the work is essentially done.
     Purple at 100% would be decoration; green is a claim about the state. */
  background: linear-gradient(90deg, #FEB101, #FE7C09);
  transition: width 420ms var(--ease-spring, cubic-bezier(0.34, 1.4, 0.64, 1)),
              background 300ms var(--ease);
}
/* Above half, the brand colour. Above nine tenths, done. Driven from a class
   rather than from CSS comparisons, which cannot compare a custom property. */
.aslider.is-mid .aslider-fill { background: linear-gradient(90deg, #FE9F2E, #E0785D); }
.aslider.is-high .aslider-fill { background: linear-gradient(90deg, #4CAF7D, #2E9E63); }

.aslider-thumb {
  position: absolute;
  top: 50%;
  width: var(--thumb);
  height: var(--thumb);
  border-radius: 50%;
  background: #fff;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.22);
  /* Inset by half a thumb at each end so it never hangs over the edge of the
     track: at 0% its left edge sits on the track's left edge, at 100% its
     right edge on the right. */
  left: calc(var(--thumb) / 2 + (100% - var(--thumb)) * var(--pct) / 100);
  translate: -50% -50%;
  transition: left 420ms var(--ease-spring, cubic-bezier(0.34, 1.4, 0.64, 1));
  pointer-events: none;
}

/* While the pointer is down the thumb tracks it exactly. A spring during the
   drag puts the thumb behind the finger, which reads as lag, not as bounce. */
.aslider.is-dragging .aslider-fill,
.aslider.is-dragging .aslider-thumb { transition: none; }

/* The control itself: full size, on top, invisible. */
.aslider input[type="range"] {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  margin: 0;
  opacity: 0;
  cursor: grab;
  -webkit-appearance: none;
  appearance: none;
  background: transparent;
}
.aslider input[type="range"]:active { cursor: grabbing; }

/* The invisible thumb still needs a size, or the browser gives it a default
   hit area that does not match the one being drawn. */
.aslider input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none;
  width: var(--thumb);
  height: var(--thumb);
  border-radius: 50%;
}
.aslider input[type="range"]::-moz-range-thumb {
  width: var(--thumb);
  height: var(--thumb);
  border: 0;
  border-radius: 50%;
}

/* Focus lands on the input, which is invisible, so the ring has to be drawn
   on the track instead -- otherwise a keyboard user gets no focus indicator
   at all. */
.aslider:focus-within .aslider-track {
  outline: 2px solid var(--primary);
  outline-offset: 2px;
}

@media (prefers-reduced-motion: reduce) {
  .aslider-fill, .aslider-thumb { transition: none; }
}


/* --------------------------------------------------------------------------
   Community and task rows arriving as you reach them

   The same reveal as the dashboard's cards, defined in style.css. A shorter
   rise, because these are rows: a card can afford to travel further than the
   thing it is a row of.

   These lists are built by work.js after the page loads, which needs no
   handling -- a view() timeline applies to an element whenever it comes to
   exist, and one inserted already on screen is simply past the end of its own
   range and therefore fully visible.
   -------------------------------------------------------------------------- */
@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    .wk-community,
    .wk-task {
      --reveal-rise: 14px;
      animation: revealUp linear both;
      animation-timeline: view();
      animation-range: entry 4% cover 40%;
    }
  }
}


/* --------------------------------------------------------------------------
   A count you can open

   The three tiles are links now, so they take a link's colour off and get a
   press of their own. The chevron is what says so before it is pressed -- a
   card that happens to be clickable and looks exactly like one that is not
   only announces itself to whoever tries.
   -------------------------------------------------------------------------- */
a.wk-stat {
  color: inherit;
  text-decoration: none;
  transition: transform var(--t) var(--ease), box-shadow var(--t) var(--ease);
}
a.wk-stat:hover { transform: translateY(-2px); box-shadow: var(--shadow-md); }
a.wk-stat:active { transform: translateY(0); }
a.wk-stat:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }

.wk-stat-go {
  grid-area: go;
  font-size: 1.15rem;
  color: var(--text-muted);
  transition: transform var(--t) var(--ease);
}
a.wk-stat:hover .wk-stat-go { transform: translateX(3px); }

/* --------------------------------------------------------------------------
   The history behind a count
   -------------------------------------------------------------------------- */
.wk-hrow {
  display: flex; align-items: flex-start; gap: 12px;
  padding: 13px 2px;
  border-bottom: 1px solid var(--border);
  color: inherit; text-decoration: none;
  transition: background var(--t-fast) var(--ease);
}
.wk-hrow:last-child { border-bottom: none; }
.wk-hrow:hover { background: var(--primary-softer); }
.wk-hrow:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; border-radius: 10px; }
.wk-hrow-main { flex: 1 1 auto; min-width: 0; }
.wk-hrow-title { font-weight: 700; font-size: 0.9rem; overflow-wrap: anywhere; }
.wk-hrow-meta { font-size: 0.76rem; color: var(--text-muted); margin-top: 3px; overflow-wrap: anywhere; }

/* The dates, laid out as a row of small facts rather than a table: there are
   at most three of them and they wrap on a phone. */
.wk-htrail { display: flex; flex-wrap: wrap; gap: 6px 12px; margin-top: 8px; }
.wk-hstep {
  font-size: 0.72rem; color: var(--text-soft);
  background: var(--bg-tint);
  padding: 3px 9px; border-radius: var(--radius-pill, 999px);
}
.wk-hstep b { font-weight: 700; color: var(--text); }

.wk-hdue {
  font-size: 0.72rem; font-weight: 700;
  color: var(--text-soft);
  background: var(--bg-tint);
  padding: 3px 9px; border-radius: var(--radius-pill, 999px);
}
/* Only ever set on work that is still outstanding: a task finished after its
   date was late, not overdue, and the row already says when it finished. */
.wk-hdue.is-late { color: var(--danger); background: var(--danger-soft); }

.wk-hrow-right { display: flex; align-items: center; gap: 8px; flex: 0 0 auto; }
.wk-hpct { font-weight: 800; font-size: 0.85rem; color: var(--primary); font-variant-numeric: tabular-nums; }

@media (max-width: 768px) {
  .wk-hrow { padding: 14px 2px; }
  .wk-hrow-right { flex-direction: column; align-items: flex-end; gap: 4px; }
}
