/* A Shade Beyond — the shop-floor surface, in Harkhamer Studio's design
 * language (tokens lifted verbatim from studio.harkhamer.com — see the ASB UI
 * spec §1). The CLIENT's identity lives on the Access sign-in page and the
 * home-screen icon; never in this chrome. One product language across the
 * vendor's tools is the shape.
 *
 * MOBILE FIRST, AND NOT AS A SLOGAN. Read one-handed, on a phone, in a shop, in
 * bad light, dusty hands, not going to zoom. One column at every width; type
 * that stays large; targets big enough to hit without looking; contrast that
 * survives sunlight. Zooming is left alone deliberately.
 *
 * COLOUR IS THE STATE MACHINE (§2). Every colour answers one question — should
 * I do something? Blue is the ordinary day; red is the rationed exception;
 * green is finished; the blank (idle) is the absence of a state, not a state.
 * Every card carries the WORD as well as the wash, for sunlight, bad light, and
 * the one man in twelve who will not separate red from green.
 */

/* ── Oswald, self-hosted. One file, one @font-face, no CDN, no build step. The
   route that serves it lives beside /style.css in server.js. ── */
@font-face {
  font-family: "Oswald";
  font-style: normal;
  font-weight: 200 700;
  font-display: swap;
  src: url("/oswald.woff2") format("woff2");
}

:root {
  /* ground + ink — light. Silver-gray ground, white cards, deep-navy ink —
     matched to the ASB board built 2026-08-11 (--bg #C4CED1 / --navy #17283E),
     not Studio's beige. The card SYSTEM is unchanged; only the ground moved. */
  --bg: #c4ced1;   --bg-elev: #ffffff;  --bg-side: #b6c0c4;
  --fg: #17283e;   --fg-muted: #55636e; --rule: #aab5b9;  --brand: #17283e;

  /* the state palette — light */
  --today:  #005cff;   /* ASB brand blue */
  --urgent: #b93426;
  --block:  #8d591c;
  --orphan: #5e7482;
  --done:   #23733a;

  /* the card wash ratios (§2) — tuned for the light ground */
  --fill: 8%;
  --edge: 34%;

  --display: "Oswald", system-ui, sans-serif;
  --read: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;

  /* the interactive accent — the New button, the tab's centre button. Defaults
     to the brand yellow; a person may override it for their own view via
     /me.css. State colours (urgent, waiting, done) are NOT accents and never
     move — meaning must not be a preference. */
  --accent: #eecf06;
}

@media all {  /* forced: ONE dark-navy theme for everyone, not device-driven (Christian 2026-08-13) */
  :root {
    /* deep navy-slate ground, NOT black — matched to the ASB board's dark mode
       (#1b2733 ground / #24323f panels). */
    --bg: #1b2733;   --bg-elev: #24323f;  --bg-side: #17283e;
    --fg: #e8edef;   --fg-muted: #9fb0bb; --rule: #3b4a57;  --brand: #cfd8dd;

    --today:  #4d94ff;   /* brand blue, lifted for the slate ground */
    --urgent: #f0503f;
    --block:  #c8863c;
    --orphan: #93a7b4;
    --done:   #6bd47b;

    /* a blue-slate ground swallows 8% — the tint must read at the same strength */
    --fill: 15%;
    --edge: 46%;
  }
}

* { box-sizing: border-box; }

html {
  font-size: 100%;
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--fg);
  font: 1.0625rem/1.5 var(--read);
  padding: env(safe-area-inset-top) env(safe-area-inset-right)
           env(safe-area-inset-bottom) env(safe-area-inset-left);
}

main {
  max-width: 34rem;   /* 360px floor + air */
  margin: 0 auto;
  padding: 1rem 1rem 4rem;
}

/* ── Navigation — gets NO colour (§2 rule 2). Because blue means ACT, nav is
   --brand slate and the underline carries the affordance. Admin-only links are
   emitted only for admins; staff never see this bar carry more than their
   list, which is the whole proposition. ── */
/* ── The admin app drawer: a bottom tab bar. Fixed to the bottom, icons over
   short labels, the active tab in brand blue, and New as a raised yellow centre
   button. Rendered only for admins/owners; staff get none. ── */
nav.tabbar {
  position: fixed;
  left: 0; right: 0; bottom: 0;
  z-index: 20;
  display: flex;
  background: var(--bg-elev);
  border-top: 1px solid var(--rule);
  padding-bottom: env(safe-area-inset-bottom);
  box-shadow: 0 -1px 10px rgba(23, 40, 62, .07);
}
nav.tabbar a {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: .2rem;
  min-height: 3.25rem;
  padding: .5rem 0 .45rem;
  color: var(--fg-muted);
  text-decoration: none;
  font: 700 .6875rem/1 var(--display);
  letter-spacing: .03em;
  -webkit-tap-highlight-color: transparent;
}
nav.tabbar a .icon { width: 1.5rem; height: 1.5rem; }
nav.tabbar a[aria-current="page"] { color: var(--today); }   /* brand blue */
nav.tabbar a:active { background: var(--bg-side); }

/* New — the raised yellow centre action */
nav.tabbar a.tab-new { color: var(--fg-muted); }
.tab-new-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.6rem; height: 2.6rem;
  margin-top: -.9rem;               /* lift it above the bar, FAB-style */
  border-radius: 50%;
  background: var(--accent);        /* personal accent */
  color: #17283e;                  /* navy + on yellow */
  box-shadow: 0 3px 8px rgba(23, 40, 62, .28);
}
.tab-new-btn .icon { width: 1.55rem; height: 1.55rem; }

/* make room so the fixed bar never covers content */
body.has-tabbar main { padding-bottom: 5.75rem; }

/* ── Desktop dashboard: an admin's home. On a phone only the Tasks panel shows
   (the tab bar carries the log and people); on a wide screen all three lay out
   as cards side by side. One render, two layouts. ── */
.dash-top { display: none; }   /* mobile: the tab bar handles New + Profile */
.panel-head { display: flex; align-items: center; justify-content: space-between; gap: 1rem; margin: 0 0 .9rem; }
.panel-title { font: 700 1.25rem/1.2 var(--display); letter-spacing: .01em; margin: 0; }
.panel-icon {
  display: inline-flex; align-items: center; justify-content: center;
  width: 2.1rem; height: 2.1rem; border-radius: 8px;
  color: var(--brand); text-decoration: none; flex: none;
}
.panel-icon .icon { width: 1.4rem; height: 1.4rem; }
.panel-icon:active { background: var(--bg-side); }

.dashboard .panel-log, .dashboard .panel-people { display: none; }

@media (min-width: 62rem) {
  /* the bottom tab bar is hidden here; the top bar carries New + Profile */
  nav.tabbar { display: none; }
  body.has-dashboard main { max-width: 90rem; padding-bottom: 2rem; }

  .dash-top { display: flex; align-items: center; justify-content: flex-end; gap: 1rem; margin: 0 0 1.25rem; }
  .btn-new-ask {
    display: inline-flex; align-items: center; gap: .4rem;
    font: 700 .9375rem/1 var(--read);
    background: var(--accent); color: #17283e;
    border-radius: 8px; padding: .62rem 1rem; text-decoration: none;
  }
  .btn-new-ask .icon { width: 1.1rem; height: 1.1rem; }
  .btn-new-ask:active { transform: translateY(1px); }
  .dash-profile { display: inline-flex; }

  .dashboard {
    display: grid;
    grid-template-columns: 1fr 1fr 1fr;
    gap: 1.5rem;
    align-items: start;
  }
  .dashboard .panel-log,
  .dashboard .panel-people { display: block; }

  /* each panel is a card — a darker shade of the page ground, so the white
     inner cards sit inside it; no inner scrollbar, the page scrolls. */
  .dashboard .panel {
    background: var(--bg-side);
    border-radius: 14px;
    padding: 1.15rem 1.15rem 1.35rem;
  }
  /* every panel heading is the same size, at the top, so the cards start flush */
  .dashboard .panel h1,
  .dashboard .panel-title { font: 700 1.25rem/1.2 var(--display); margin: 0; }

  /* People panel: a bigger avatar circle, left-aligned and vertically centred
     with the name (the row's default) — NOT horizontally centred. */
  .panel-people .personcard .avatar { width: 3.4rem; height: 3.4rem; font-size: 1.3rem; }
}

/* ── The board (kanban): stage columns, scrolling horizontally ── */
.board { display: flex; gap: 1rem; overflow-x: auto; padding-bottom: 1rem; -webkit-overflow-scrolling: touch; }
.board-col { flex: 0 0 15rem; background: var(--bg-side); border-radius: 12px; padding: .85rem; }
.board-col-head {
  font: 700 .8125rem/1 var(--display);
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--fg-muted);
  margin: 0 0 .75rem;
  display: flex;
  align-items: center;
  gap: .5rem;
  border-top: 3px solid var(--state, var(--rule));
  padding-top: .6rem;
}
.board-count { margin-left: auto; background: var(--bg); border-radius: 9px; padding: .12rem .5rem; font-size: .75rem; }
.board-empty { text-align: center; color: var(--fg-muted); margin: .5rem 0; }

/* staff: no bar, just a small way out at the foot */
.staff-foot { margin: 2.5rem 0 0; text-align: center; font-size: .875rem; }

/* ── Profile page ── */
.profilecard { --state: var(--brand); }
.profilecard .who { gap: .75rem; margin-bottom: 1rem; }
.profilecard .who-lines { min-width: 0; }
.profilecard .who-lines .pname { font: 700 1.15rem/1.15 var(--display); color: var(--fg); overflow-wrap: anywhere; }
.profilecard .who-lines .ctx { margin-top: .1rem; overflow-wrap: anywhere; }
.chip.static { cursor: default; }
.signout { margin-top: 1.25rem; }
.signout-btn { display: inline-flex; align-items: center; gap: .5rem; }
.signout-btn .icon { width: 1.25rem; height: 1.25rem; }

h1 {
  font: 700 1.5rem/1.2 var(--display);
  letter-spacing: .01em;
  margin: 0 0 1rem;
  overflow-wrap: anywhere;
}

/* ── Grouped list. The order IS the ranking (§5): Needs you, Today, Waiting,
   Done this week. Group headers say the same thing the wash does — someone who
   scrolls past a header still reads it from the colour. ── */
.group { margin: 0 0 1.5rem; }
.group > h2 {
  font: 700 .8125rem/1 var(--display);
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--fg-muted);
  margin: 0 0 .5rem;
}

/* the cards column — Studio's .col-cards rhythm exactly. The 8px gap is
   structural: a thumb cannot land between two cards and hit neither. */
.cards { display: flex; flex-direction: column; gap: 8px; }

/* ── The card. The whole card is the tap target. Titles wrap, never truncate —
   a half-read instruction is worse than a long one. ── */
.card {
  position: relative;
  display: block;
  min-height: 3rem;              /* a thumb-sized tap target, even for a short title */
  padding: .7rem .85rem;
  border-radius: 8px;
  border: 1px solid color-mix(in srgb, var(--state) var(--edge), var(--rule));
  border-left: 4px solid var(--state);            /* the stripe, full saturation */
  background: color-mix(in srgb, var(--state) var(--fill), var(--bg-elev));
  box-shadow: 0 1px 2px rgba(23, 40, 62, .06), 0 2px 8px rgba(23, 40, 62, .04);
  color: var(--fg);
  text-decoration: none;
  -webkit-tap-highlight-color: transparent;
  transition: box-shadow .12s ease, transform .12s ease;
}
.card:active { transform: translateY(1px); box-shadow: 0 1px 2px rgba(23, 40, 62, .06); }
@media all {  /* forced: ONE dark-navy theme for everyone, not device-driven (Christian 2026-08-13) */
  .card { box-shadow: 0 1px 2px rgba(0, 0, 0, .25); }
}

/* the state tag row: TAG left (semantic colour), age right — age ONLY on red */
.card .tagline {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: .5rem;
  margin-bottom: .15rem;
}
.card .tag {
  font: 700 .75rem/1 var(--display);
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--state);
}
.card .age {
  font: 700 .75rem/1 var(--display);
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--state);
  white-space: nowrap;
}
.card .title {
  font: 500 1.0625rem/1.3 var(--read);
  color: var(--fg);
  overflow-wrap: anywhere;
}
.card .ctx {
  margin-top: .15rem;
  font: .8125rem/1.35 var(--read);
  color: var(--fg-muted);
  overflow-wrap: anywhere;
}

/* the five states carry a --state; the sixth (idle) is the deliberate blank */
.is-today  { --state: var(--today); }
.is-urgent { --state: var(--urgent); }
.is-block  { --state: var(--block); }
.is-orphan { --state: var(--orphan); }
.is-done   { --state: var(--done); }

/* WAITING gets no wash and no coloured edge — plain --bg-elev on --rule, stripe
   in --rule. Waiting is the absence of a state, and it must visibly sit beneath
   every coloured card (§2). */
.is-idle {
  --state: var(--rule);
  background: var(--bg-elev);
}
.is-idle .tag { color: var(--fg-muted); }

/* an empty group message, and the reassuring "nothing here" */
.empty { color: var(--fg-muted); font-style: italic; margin: .25rem 0 0; }

/* ── One request, and its thread ── */
.back { margin: 0 0 1rem; }
.back a, a.link {
  color: var(--brand);
  text-decoration: underline;
  text-underline-offset: 3px;
  font-weight: 500;
}
.ask { font-size: 1.0625rem; margin: 0 0 .75rem; overflow-wrap: anywhere; }
.when { color: var(--fg-muted); font-size: .875rem; margin: 0 0 1rem; }
.when .state {
  font: 700 .75rem/1 var(--display);
  letter-spacing: .1em; text-transform: uppercase; color: var(--fg-muted);
}
.thread { list-style: none; margin: 1rem 0; padding: 0; display: flex; flex-direction: column; gap: .75rem; }
.thread li { border-left: 3px solid var(--rule); padding: .25rem 0 .25rem .75rem; }
.thread .who { font: 700 .8125rem/1 var(--display); letter-spacing: .06em; text-transform: uppercase; color: var(--fg-muted); margin: 0 0 .25rem; }
.thread .said { margin: 0; overflow-wrap: anywhere; }
.files { padding-left: 1.1rem; margin: 1rem 0; }
.finished { color: var(--fg-muted); font-weight: 500; }

/* ── The single request, AS A CARD that opens up ── */
.btn-back {
  display: inline-flex;
  align-items: center;
  gap: .35rem;
  font: 600 .9375rem/1 var(--read);
  color: var(--brand);
  background: var(--bg-elev);
  border: 1px solid var(--rule);
  border-radius: 8px;
  padding: .55rem .95rem;
  text-decoration: none;
  margin: 0 0 1rem;
  -webkit-tap-highlight-color: transparent;
}
.btn-back:active { transform: translateY(1px); }

/* the detail is the same card the list showed, opening in place */
.detailcard {
  min-height: 0;
  padding: 1.1rem 1.15rem;
  animation: card-open .24s cubic-bezier(.2, .7, .3, 1);
  transform-origin: top center;
}
.detailcard:active { transform: none; }   /* it is not a tap target itself */
.detailcard.by-person { --state: var(--person, var(--brand)); }   /* admin detail: person colour */
.detailcard .row1 { margin-bottom: .6rem; }
.detailcard .detail-title { font: 700 1.4rem/1.2 var(--display); margin: .15rem 0 .5rem; overflow-wrap: anywhere; }
.detailcard .ask { font-size: 1.0625rem; }
.detailcard form { margin: 1.1rem 0 0; }
@keyframes card-open {
  from { opacity: 0; transform: translateY(10px) scale(.985); }
  to   { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) { .detailcard { animation: none; } }

/* attach: a photo (camera) or a file. The real input is hidden behind a styled
   label so the two affordances read as buttons. */
.attach { display: flex; flex-wrap: wrap; gap: .75rem; align-items: center; margin: 1.1rem 0 0; }
.attach form { display: inline-flex; align-items: center; gap: .5rem; margin: 0; }

/* Send inline with the attach icons, pushed right */
.action-row { display: flex; align-items: center; justify-content: space-between; gap: 1rem; margin: .35rem 0 0; }
/* pull Send + the photo/file buttons up close to the reply box */
#reply-form textarea { margin-bottom: .35rem; }
.progress-actions:empty { display: none; }
.action-row .attach { margin: 0; }
.action-row > button { margin: 0; }
.filebtn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 2.9rem;
  min-height: 2.9rem;
  color: var(--brand);
  background: transparent;
  border: 1px solid var(--brand);
  border-radius: 8px;
  padding: .6rem;
  cursor: pointer;
  margin: 0;
}
.filebtn .icon { width: 1.5rem; height: 1.5rem; display: block; }
.filebtn input { position: absolute; width: 1px; height: 1px; opacity: 0; overflow: hidden; }
.filebtn:active { transform: translateY(1px); }
.filebtn:focus-within { outline: 2px solid var(--brand); outline-offset: 1px; }

/* ── Forms — new ask, reply, the transitions ── */
form { margin: 1.25rem 0; }
label { display: block; font-weight: 600; margin: 0 0 .35rem; }
input[type="text"], textarea, select {
  width: 100%;
  font: 1.0625rem/1.4 var(--read);
  color: var(--fg);
  background: var(--bg-elev);
  border: 1px solid var(--rule);
  border-radius: 5px;
  padding: .6rem .7rem;
  margin: 0 0 1rem;
}
textarea { resize: vertical; }
input:focus, textarea:focus, select:focus {
  outline: 2px solid var(--brand);
  outline-offset: 1px;
}

/* the three-way segmented control — "When do you need it?" (§3). The input is
   hidden; the label is the segment; :has lights the chosen one. */
.segmented { border: 0; padding: 0; margin: 0 0 .5rem; }
.segmented legend { font-weight: 600; padding: 0; margin: 0 0 .35rem; }
.segments { display: flex; border: 1px solid var(--rule); border-radius: 5px; overflow: hidden; }
.segments label {
  flex: 1;
  margin: 0;
  text-align: center;
  padding: .55rem .4rem;
  font-weight: 600;
  color: var(--fg);
  background: var(--bg-elev);
  border-left: 1px solid var(--rule);
  cursor: pointer;
}
.segments label:first-child { border-left: 0; }
.segments input { position: absolute; opacity: 0; pointer-events: none; }
.segments label:has(input:checked) { background: var(--brand); color: var(--bg-elev); }

/* buttons: .done is the one that finishes something; .secondary is everything
   else. Neither borrows a state colour it does not own. */
button {
  font: 600 1rem/1 var(--read);
  border-radius: 8px;
  padding: .7rem 1.1rem;
  border: 1px solid var(--brand);
  background: var(--brand);
  color: var(--bg-elev);
  cursor: pointer;
}
button.secondary { background: transparent; color: var(--brand); }
button.done, summary.done {
  background: #eecf06;           /* ASB brand yellow — FIXED, not the personal accent */
  border-color: #eecf06;
  color: #17283e;                /* navy ink — legible on yellow */
  font-weight: 700;
  font-size: 1.0625rem;
  padding: .85rem 1.2rem;
  width: 100%;
}

h2 {
  font: 700 1.1rem/1.2 var(--display);
  letter-spacing: .02em;
  margin: 2rem 0 1rem;
}

/* ── The admin log (admin/owner only) — cards, not a table ── */
.filters { display: flex; gap: 1.25rem; margin: 0 0 1rem; }
.filters a {
  font: 700 .8125rem/1 var(--display);
  letter-spacing: .08em; text-transform: uppercase;
  color: var(--brand); text-decoration: underline; text-underline-offset: 3px;
}
.filters a.on { text-decoration: none; color: var(--fg); }

/* the compact row shared by log + people cards: title left, tag right */
.card .row1 {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: .5rem;
}
.card .row1 .title { font: 600 1.0625rem/1.3 var(--read); overflow-wrap: anywhere; }
.logcard { --state: var(--person, var(--brand)); min-height: 0; }
.logcard .who { align-items: center; }
/* the TASK leads (name removed): the title sits where the name was */
.logcard .log-title { font: 600 1rem/1.25 var(--read); color: var(--fg); overflow-wrap: anywhere; }
.logcard .ctx { margin-top: .3rem; }

/* ── Per-person colour — the rainbow. Each person gets a stable hue (assigned
   by a hash of their id in the template, class person-0..9), used on the log
   and here on the people page so a person reads as the same colour everywhere.
   Every value is legible as bold text on a white card and bright enough on the
   dark slate. ── */
.person-0 { --person: #3973e6; }  /* blue   */
.person-1 { --person: #e65a4f; }  /* red    */
.person-2 { --person: #2fa66a; }  /* green  */
.person-3 { --person: #e5a52b; }  /* amber  */
.person-4 { --person: #805ad5; }  /* purple */
.person-5 { --person: #259c9c; }  /* teal   */
.person-6 { --person: #d94f87; }  /* pink   */
.person-7 { --person: #d97835; }  /* orange */
.person-8 { --person: #5368c7; }  /* indigo */
.person-9 { --person: #79a83b; }  /* olive  */
/* dark mode: lift each toward white so names/avatars read on the slate ground */
@media all {  /* forced: ONE dark-navy theme for everyone, not device-driven (Christian 2026-08-13) */
  .person-0 { --person: color-mix(in srgb, #3973e6 68%, #fff); }
  .person-1 { --person: color-mix(in srgb, #e65a4f 68%, #fff); }
  .person-2 { --person: color-mix(in srgb, #2fa66a 68%, #fff); }
  .person-3 { --person: color-mix(in srgb, #e5a52b 68%, #fff); }
  .person-4 { --person: color-mix(in srgb, #805ad5 68%, #fff); }
  .person-5 { --person: color-mix(in srgb, #259c9c 68%, #fff); }
  .person-6 { --person: color-mix(in srgb, #d94f87 68%, #fff); }
  .person-7 { --person: color-mix(in srgb, #d97835 68%, #fff); }
  .person-8 { --person: color-mix(in srgb, #5368c7 68%, #fff); }
  .person-9 { --person: color-mix(in srgb, #79a83b 68%, #fff); }
}

/* the person, as an avatar — the identifier is the face, not the name. A real
   headshot (img.avatar-img) drops in when one exists; until then a circle in the
   person's colour carries their initials. The name rides along, smaller. */
.who { display: flex; align-items: center; gap: .6rem; min-width: 0; }
.avatar {
  flex: none;
  width: 2.75rem; height: 2.75rem;
  border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  background: var(--person, var(--brand));
  color: #fff;
  font: 700 1rem/1 var(--display);
  letter-spacing: .04em;
  box-shadow: 0 0 0 2px var(--bg-elev), 0 0 0 3px color-mix(in srgb, var(--person, var(--brand)) 55%, transparent);
  overflow: hidden;
}
.avatar-img { object-fit: cover; }
.pname {
  font: 700 1.05rem/1.15 var(--display);
  letter-spacing: .01em;
  color: var(--person, var(--fg));
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* the days-sitting callout — a traffic light on the right. Fresh is calm, and a
   request left sitting turns amber then red, so "how long has this been out"
   answers itself from across the room. */
.days {
  font: 700 .8125rem/1 var(--display);
  letter-spacing: .05em; text-transform: uppercase;
  white-space: nowrap;
  padding: .3rem .55rem;
  border-radius: 9px;
  color: #fff;
}
.days.d-fresh { background: #2e7d32; }
.days.d-warn  { background: #b8860b; }
.days.d-late  { background: #c0392b; }
@media all {  /* forced: ONE dark-navy theme for everyone, not device-driven (Christian 2026-08-13) */
  .days { color: #10202b; }
  .days.d-fresh { background: #7bd486; }
  .days.d-warn  { background: #e6c34a; }
  .days.d-late  { background: #ff7a6b; }
}

/* ── People cards — compact long rectangles: avatar, name, role badge flush
   right, and everything editable hidden behind the bottom-right edit pencil. ── */
.personcard { --state: var(--person, var(--brand)); }
/* compact cards — the SAME size for people, the log, and any list card that
   asks for it (§ Christian: log cards match the people/task cards). */
.card.compact { padding: .5rem .7rem; }
.card.compact .avatar { width: 2.25rem; height: 2.25rem; font: 700 .85rem/1 var(--display); }
.personcard .row1 { align-items: center; }
.personcard.is-off { --state: var(--rule); opacity: .6; }
.tag.off { color: var(--fg-muted); }

/* the role badge — a dark rounded rectangle, flush right, opposite the name */
.roles-badges { display: flex; gap: .35rem; align-items: center; flex-wrap: wrap; justify-content: flex-end; }
.role-badge {
  font: 700 .6875rem/1 var(--display);
  letter-spacing: .06em;
  text-transform: uppercase;
  background: #17283e;
  color: #fff;
  padding: .32rem .5rem;
  border-radius: 6px;
  white-space: nowrap;
}
.role-badge.off { background: var(--fg-muted); }

/* the edit accordion — native <details>, the pencil in the bottom-right */
.person-edit > summary.edit-toggle {
  list-style: none;
  display: flex;
  justify-content: flex-end;
  align-items: center;
  min-height: 1.6rem;
  margin-top: .3rem;
  color: var(--fg-muted);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
.person-edit > summary.edit-toggle::-webkit-details-marker { display: none; }
.person-edit > summary.edit-toggle .icon { width: 1.2rem; height: 1.2rem; }
.person-edit[open] > summary.edit-toggle { color: var(--today); }
.edit-body { margin-top: .55rem; padding-top: .75rem; border-top: 1px solid var(--rule); }
.edit-email { color: var(--fg-muted); font-size: .875rem; margin: 0 0 .85rem; overflow-wrap: anywhere; }
.edit-field { margin: 0 0 1rem; }
.edit-field:last-child { margin-bottom: 0; }
.edit-label {
  display: block;
  font: 700 .75rem/1 var(--display);
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--fg-muted);
  margin: 0 0 .45rem;
}

.chips { display: flex; flex-wrap: wrap; gap: .4rem; align-items: center; margin-top: .6rem; }
.edit-field .chips, .edit-field .personact { margin-top: 0; }
.chips .inline { margin: 0; }
.chip {
  font: 700 .75rem/1 var(--display);
  letter-spacing: .06em; text-transform: uppercase;
  padding: .35rem .6rem;
  border-radius: 9px;
  border: 1px solid var(--rule);
  background: var(--bg);
  color: var(--fg);
  cursor: pointer;
}
.chip.add { background: var(--brand); color: var(--bg-elev); border-color: var(--brand); }
.chip-add { display: inline-flex; gap: .3rem; align-items: center; }
.chip-add select { width: auto; margin: 0; padding: .3rem .5rem; font-size: .875rem; }
.personact { margin-top: .75rem; }
.personact button { padding: .5rem .9rem; font-size: .9375rem; }

/* the add-someone checkboxes */
.checks { display: flex; gap: 1rem; margin: 0 0 1rem; }
.check { display: inline-flex; align-items: center; gap: .35rem; font-weight: 500; }
.check input { width: auto; margin: 0; }

/* the transitions on the admin request view sit apart, one action per row */
.admin-actions { margin-top: 1.5rem; padding-top: 1rem; border-top: 1px solid var(--rule); }
.admin-actions form { margin: 0 0 1rem; }

/* ── PROGRESS ─────────────────────────────────────────────────────────────
   A self-reported light: green = the assignee started it, yellow = blocked.
   The dot sits top-right of a card; the buttons that set it live on the
   request itself (views/request.ejs). Blocked cards are grouped into "Waiting
   on someone else" by the partials, so the yellow dot appears there. */
.card .light {
  position: absolute;
  top: .55rem;
  right: .6rem;
  width: .8rem;
  height: .8rem;
  border-radius: 50%;
  z-index: 1;
}
.light-green  { background: #22c55e; box-shadow: 0 0 0 2px var(--bg-elev), 0 0 7px rgba(34, 197, 94, .75); }
.light-yellow { background: #eab308; box-shadow: 0 0 0 2px var(--bg-elev), 0 0 7px rgba(234, 179, 8, .85); }
.light-red    { background: #ef4444; box-shadow: 0 0 0 2px var(--bg-elev), 0 0 7px rgba(239, 68, 68, .8); }
/* not started: the card's own state colour, so the dot matches the tag (blue for Today, red for Urgent) */
.light-state  { background: var(--state); box-shadow: 0 0 0 2px var(--bg-elev); }
/* reserve the corner so a light never sits on top of the age badge */
.card:has(.light) .tagline { padding-right: 1.05rem; }

/* ── ALL TASKS: one giant list, washed by STATE, person on the avatar ──────
   The whole card is NOT tinted to the person (that is what .logcard did) — it
   carries its stage colour like a staff card, and the avatar alone says who. */
.card.alltask { padding: .6rem .8rem .6rem .75rem; }
.card.alltask .at-row { display: flex; align-items: center; gap: .65rem; }
.card.alltask .avatar { width: 2.6rem; height: 2.6rem; font: 700 .95rem/1 var(--display); flex: 0 0 auto; }
.card.alltask .at-main { flex: 1; min-width: 0; }
.card.alltask .tagline { margin-bottom: .1rem; }
.card.alltask .title { font: 600 1rem/1.25 var(--read); color: var(--fg); overflow-wrap: anywhere; }
.card.alltask .ctx { margin-top: .12rem; }
.alltasks-page { max-width: 40rem; }

/* ── PROGRESS BUTTONS on a request ────────────────────────────────────────*/
.progress-row { display: flex; align-items: center; flex-wrap: wrap; gap: .5rem; margin: 0 0 1.1rem; }
.progress-row .light { position: static; }
.progress-now { font: 600 .9rem/1.2 var(--read); color: var(--fg-muted); margin-right: .15rem; }
.progress-btn {
  border: 0;
  border-radius: 9px;
  padding: .5rem .95rem;
  font: 600 .9rem/1 var(--read);
  cursor: pointer;
}
.progress-btn.is-started { background: #22c55e; color: #06210f; }
.progress-btn.is-blocked { background: #eab308; color: #241c00; }
.progress-btn.ghost { background: transparent; color: var(--fg-muted); box-shadow: inset 0 0 0 1.5px var(--rule); }
.progress-btn:active { transform: translateY(1px); }

/* ── PROFILE: the personal skin form ─────────────────────────────────────── */
.skin-head { font: 700 1.25rem/1.2 var(--display); letter-spacing: .01em; margin: 1.75rem 0 .75rem; }
.skin-form { display: flex; flex-direction: column; gap: 1rem; }
.skin-row { display: flex; align-items: center; gap: .75rem; flex-wrap: wrap; }
.skin-label { flex: 1 1 8rem; font: 600 1rem/1.3 var(--read); color: var(--fg); }
.skin-form input[type="color"] {
  -webkit-appearance: none; appearance: none;
  width: 3rem; height: 2.1rem; padding: 0;
  border: 1px solid var(--rule); border-radius: 8px; background: none; cursor: pointer;
}
.skin-form input[type="color"]::-webkit-color-swatch-wrapper { padding: 3px; }
.skin-form input[type="color"]::-webkit-color-swatch { border: none; border-radius: 5px; }
.skin-form select {
  font: 600 1rem/1.2 var(--read); color: var(--fg);
  background: var(--bg-side); border: 1px solid var(--rule); border-radius: 8px;
  padding: .55rem .7rem; min-width: 9rem;
}
.skin-reset { display: inline-flex; align-items: center; gap: .35rem; font: .85rem/1 var(--read); color: var(--fg-muted); }
.skin-reset input { width: auto; margin: 0; }
.skin-save { align-self: flex-start; margin-top: .25rem; }

/* the photo picker on the profile card — a full-width tap target */
.photo-form { margin-top: 1rem; }
.filebtn.wide {
  display: inline-flex; align-items: center; gap: .5rem;
  padding: .6rem .9rem; border: 1px solid var(--rule); border-radius: 10px;
  color: var(--brand); cursor: pointer; font: 600 .95rem/1 var(--read);
}
.filebtn.wide .icon { width: 1.2rem; height: 1.2rem; }
.filebtn.wide input[type="file"] { position: absolute; width: 1px; height: 1px; opacity: 0; overflow: hidden; }

/* ── The New request dialog: the "Today" blue look, border turned up so the
   whole dialog reads as one bright-blue card with a transparent blue fill. ── */
.newask { border-width: 2px; border-color: color-mix(in srgb, var(--today) 58%, var(--rule)); }
.newask h1 { margin-top: 0; }

/* ── Team: the add-member accordion — a gray button (white stroke + lettering)
   that drops the add form open. ── */
.add-member { margin-top: 1.5rem; }
.add-member-btn {
  list-style: none;
  display: block;
  cursor: pointer;
  text-align: center;
  background: #4b5866;
  color: #fff;
  border: 1.5px solid #fff;
  border-radius: 10px;
  padding: .85rem 1rem;
  font: 700 .95rem/1 var(--display);
  letter-spacing: .07em;
  text-transform: uppercase;
}
.add-member-btn::-webkit-details-marker { display: none; }
.add-member-btn:active { transform: translateY(1px); }
.add-member[open] > .add-member-btn { margin-bottom: 1.1rem; }

/* ── MOBILE: bigger, more legible type (Christian: hard to read on a phone). The
   desktop layout (>= 62rem) keeps its own sizes. ── */
@media (max-width: 61.99rem) {
  body { font-size: 1.15rem; }                                   /* all text a little bigger */
  .panel-title { font: 700 1.5rem/1.2 var(--display); }          /* "Your tasks" == "All Tasks" */
  .card .title, .card.alltask .title, .logcard .log-title { font-size: 1.2rem; }
  .card .ctx, .card.alltask .ctx { font-size: .95rem; }
  .card .tag, .card .age { font-size: .82rem; }
  /* Team cards: avatar circles twice as big, names larger */
  .personcard.compact .avatar { width: 4.5rem; height: 4.5rem; font: 700 1.6rem/1 var(--display); }
  .personcard .pname { font-size: 1.4rem; }
}

/* ── Blocker relationship lines + the Pause / Confirm inline dialogs ─────── */
.blockrel { font: 600 .82rem/1.3 var(--read); color: var(--urgent); margin: .12rem 0 0; overflow-wrap: anywhere; }
.blockrel.banner {
  margin: .55rem 0 .3rem;
  padding: .55rem .7rem;
  border-radius: 9px;
  background: color-mix(in srgb, var(--urgent) 14%, var(--bg-elev));
  border: 1px solid color-mix(in srgb, var(--urgent) 38%, var(--rule));
  color: var(--fg);
  font-weight: 500;
  font-size: .95rem;
}
.blockrel.banner strong { color: var(--urgent); }

.progress-actions { display: flex; flex-wrap: wrap; align-items: center; gap: .6rem; margin: 1rem 0; }

/* a <details> whose <summary> IS the button; opening expands a form inline —
   no JS, no modal, CSP-safe (same pattern as the add-team-member accordion). */
.pausebox { margin: 0; }
/* when the Pause form is open, break it out to the full row so the reason +
   person fields are full width, not squeezed into the button row's leftover */
.pausebox[open] { flex-basis: 100%; }
.pause-form { width: 100%; }
.confirmbox { display: block; margin-top: .3rem; }
.pausebox > summary, .confirmbox > summary { list-style: none; cursor: pointer; display: inline-block; }
.pausebox > summary::-webkit-details-marker,
.confirmbox > summary::-webkit-details-marker { display: none; }
.confirmbox > summary.done { display: block; width: 100%; text-align: center; border-radius: 8px; border: 1px solid #eecf06; }

.pause-form, .confirmbox form {
  display: flex; flex-direction: column; gap: .55rem;
  margin-top: .8rem; padding: .85rem;
  border-radius: 10px; background: var(--bg-side); border: 1px solid var(--rule);
}
.confirmbox form { border-color: color-mix(in srgb, #eecf06 45%, var(--rule)); }
.pause-form button, .confirmbox form button { align-self: flex-start; margin-top: .3rem; }
.confirm-q { margin: 0; font: 600 1rem/1.35 var(--read); }

/* profile: notifications opt-in */
.push-note { color: var(--fg-muted); font-size: .95rem; margin: 0 0 .75rem; }
#enable-push { margin-bottom: 1.25rem; }

/* ── Jobs board + job detail ─────────────────────────────────────────────── */
.btn-newjob {
  display: inline-block; margin: 0 0 1rem;
  background: var(--accent); color: #17283e;
  border-radius: 8px; padding: .55rem .9rem;
  font: 700 .9rem/1 var(--read); text-decoration: none;
}
.jobinfo { margin: .35rem 0 .85rem; }
.jobcustomer { font: 700 1.2rem/1.2 var(--display); margin: 0 0 .15rem; overflow-wrap: anywhere; }
.jobcustomer .jobtype { font: 600 1rem/1.2 var(--read); color: var(--fg-muted); }
.jobaddr {
  display: flex; align-items: center; gap: .5rem; flex-wrap: wrap;
  margin: .5rem 0 0; font: .98rem/1.3 var(--read); overflow-wrap: anywhere;
}
.jobaddr .icon { width: 1.15rem; height: 1.15rem; color: var(--today); flex: none; }
.jobaddr span { flex: 1; min-width: 8rem; }
.navbtn {
  background: var(--today); color: #fff;
  border-radius: 8px; padding: .45rem .85rem;
  font: 700 .85rem/1 var(--read); text-decoration: none; white-space: nowrap;
}

/* ── Jobs — the primary tab, a raised blue circle (installers live here) ──── */
nav.tabbar a.tab-jobs { color: var(--fg-muted); }
.tab-jobs-btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 2.6rem; height: 2.6rem; margin-top: -.9rem;
  border-radius: 50%;
  background: var(--today); color: #fff;
  box-shadow: 0 3px 8px rgba(23, 40, 62, .28);
}
.tab-jobs-btn .icon { width: 1.55rem; height: 1.55rem; }

/* ── Inbox "+" (staff can request a task) + pending-approval flag ─────────── */
.btn-request {
  display: inline-flex; align-items: center; gap: .35rem; margin: 0 0 1rem;
  background: var(--today); color: #fff;
  border-radius: 8px; padding: .55rem .9rem;
  font: 700 .9rem/1 var(--read); text-decoration: none;
}
.pending-flag { color: var(--block); font-weight: 700; }
.btn-request .icon { width: 1rem; height: 1rem; }
.field-note { color: var(--fg-muted); font: .9rem/1.35 var(--read); margin: .35rem 0 .5rem; }

/* ── Job field-flow (slice 2): locked address, kit checklist, photo gate ───── */
.addr-locked { color: var(--fg-muted); }
.addr-locked .icon { color: var(--fg-muted); }

.kit-form { display: flex; flex-direction: column; gap: .5rem; margin: .3rem 0; }
.kit-head { font: 700 1rem/1.3 var(--read); margin: 0; }
.kit { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: .1rem; }
.kit-item label {
  display: flex; align-items: center; gap: .7rem;
  min-height: 3rem; padding: .35rem .2rem;
  font: 1.05rem/1.3 var(--read); overflow-wrap: anywhere; cursor: pointer;
}
.kit-item input[type="checkbox"] { width: 1.5rem; height: 1.5rem; flex: none; accent-color: var(--today); }

.photo-gate {
  margin: .6rem 0 0; padding: .7rem .9rem;
  border-radius: 10px; border: 1px solid color-mix(in srgb, var(--today) 40%, var(--rule));
  background: color-mix(in srgb, var(--today) 10%, transparent);
  color: var(--fg); font: 600 1rem/1.35 var(--read);
}

/* ── Swipe strip: where this card sits, and tap-or-swipe to the next ───────── */
.cardswipe {
  display: flex; align-items: center; justify-content: space-between; gap: .5rem;
  margin: 0 0 .7rem; padding: .15rem .3rem;
}
.swipe-pos { font: 700 .95rem/1 var(--read); color: var(--fg-muted); letter-spacing: .02em; }
.swipe-arrow {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 3rem; min-height: 3rem; border-radius: 10px;
  font: 700 1.6rem/1 var(--read); text-decoration: none;
  color: #fff; background: var(--today);
}
.swipe-arrow.is-edge { color: var(--fg-muted); background: transparent; box-shadow: inset 0 0 0 1.5px var(--rule); }

/* ── Design-review mode: banner + persona switcher (never shown in production) ─ */
.review-banner {
  position: sticky; top: 0; z-index: 50;
  background: #b45309; color: #fff;
  font: 700 .85rem/1.3 var(--read); text-align: center;
  padding: .5rem .8rem; letter-spacing: .01em;
}
.review-banner a { color: #fff; text-decoration: underline; }
.rv-page main { max-width: 44rem; margin: 0 auto; padding: 1rem; }
.rv-page h1 { font: 700 1.5rem/1.15 var(--display); margin: 1rem 0 .5rem; }
.rv-help { color: var(--fg-muted); font: 1rem/1.45 var(--read); margin: .5rem 0; }
.rv-help code { font-family: var(--mono, monospace); }
.rv-personas { list-style: none; padding: 0; margin: 1rem 0; display: flex; flex-direction: column; gap: .7rem; }
.rv-persona a {
  display: block; padding: .9rem 1rem; border-radius: 12px;
  background: var(--card); box-shadow: inset 0 0 0 1.5px var(--rule);
  text-decoration: none; color: var(--fg);
}
.rv-persona.is-on a { box-shadow: inset 0 0 0 2px var(--today); }
.rv-name { display: block; font: 700 1.1rem/1.25 var(--read); }
.rv-blurb { display: block; margin-top: .25rem; color: var(--fg-muted); font: .95rem/1.4 var(--read); }
