/* Rooted Shores — farm operations.

   Light, warm and calm. This is read by staff of mixed technical confidence, in a barn, in
   daylight, on a phone, and on a TV across a room — every one of those cases is worse on a dark
   surface, which glares in sun and blooms at distance. Dark follows the OS for evening use.

   The logo's green and cyan are kept as identity but darkened, because the original tones fail
   contrast on white. */

/* The hidden attribute must win over any display we set.
 *
 * The browser's own [hidden] rule is display:none, but ANY author rule with a display beats it —
 * so `.updatebar { display: flex }` left the update notice permanently on screen, on every page,
 * announcing an update that did not exist. A bar that is always on is worse than no bar: it
 * teaches people to ignore the one time it is real. */
[hidden] { display: none !important; }


:root {
  --paper:   #F5F7F2;   /* barely-green off-white: greenhouse linen, not cream */
  --card:    #FFFFFF;
  --card-2:  #FAFBF8;
  --ink:     #211E19;
  --muted:   #6B6357;
  --faint:   #938A7C;
  --line:    #E3E2D8;
  --line-2:  #EFEEE7;

  --sprout:      #3F7A34;
  --sprout-soft: #E8F2E3;
  --water:       #1F6E86;
  --water-soft:  #E2F0F4;
  --sun:         #B4740F;
  --sun-soft:    #FBF0DC;
  --clay:        #A8412A;
  --clay-soft:   #F9E7E2;

  /* Every other row, barely. See the rule down in the tables section for why it is this faint. */
  --stripe: rgba(33,30,25,.028);

  --radius: 12px;
  --r-s: 8px;
  --shadow: 0 1px 2px rgba(33,30,25,.05), 0 6px 20px rgba(33,30,25,.06);
  --shadow-s: 0 1px 2px rgba(33,30,25,.06);

  --font: system-ui, -apple-system, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
  --mono: ui-monospace, 'SF Mono', 'DejaVu Sans Mono', Menlo, Consolas, monospace;
}

@media (prefers-color-scheme: dark) {
  :root {
    --paper: #16150F; --card: #1E1D16; --card-2: #24231B;
    --ink: #F2EFE6; --muted: #A9A192; --faint: #857D6E;
    --line: #322F25; --line-2: #2A281F;
    --sprout: #8CC97A; --sprout-soft: #22301D;
    --water: #63C2DB;  --water-soft: #162B31;
    --sun: #E0A84C;    --sun-soft: #2E2416;
    --clay: #E08363;   --clay-soft: #2F1C16;
    --stripe: rgba(255,255,255,.032);
    --shadow: 0 1px 2px rgba(0,0,0,.3), 0 6px 20px rgba(0,0,0,.35);
  }
}

* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
body {
  background: var(--paper); color: var(--ink);
  font-family: var(--font); line-height: 1.55;
  -webkit-font-smoothing: antialiased; min-height: 100vh;
  font-variant-numeric: tabular-nums;
}
a { color: var(--water); text-decoration: none; }
a:hover { text-decoration: underline; }
:focus-visible { outline: 3px solid var(--water); outline-offset: 2px; border-radius: 4px; }
.muted { color: var(--muted); }

/* ---- shell ------------------------------------------------------------------------------- */

.topbar {
  display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
  padding: 11px 22px; background: var(--card); border-bottom: 1px solid var(--line);
  position: sticky; top: 0; z-index: 30;
}
.topbar .brand { display: flex; align-items: center; gap: 9px; }
/* The BARN, not the whole logo. The full mark has the farm's name drawn into it, so at nav size
   it was an unreadable smudge sitting beside the same name set properly in type two centimetres
   to the right. Trimmed of its own whitespace, so the gap here is the only gap. */
.topbar .brand img { height: 42px; width: auto; display: block; }
.topbar .brand .name { font-weight: 650; letter-spacing: -.01em; line-height: 1.15; }
.topbar .brand .name small {
  display: block; color: var(--faint); font-size: 10px; font-weight: 600;
  letter-spacing: .13em; text-transform: uppercase;
}
.topbar nav { display: flex; gap: 2px; margin-left: auto; align-items: center; flex-wrap: wrap; }
.topbar nav a {
  padding: 7px 13px; border-radius: 999px; color: var(--muted);
  font-size: 14px; font-weight: 550;
}
.topbar nav a:hover { background: var(--line-2); color: var(--ink); text-decoration: none; }
.topbar nav a.active { background: var(--sprout-soft); color: var(--sprout); }
.topbar .who { color: var(--faint); font-size: 13px; padding-left: 8px; }

.wrap { max-width: 1180px; margin: 0 auto; padding: 26px 20px 72px; }

/* ---- type -------------------------------------------------------------------------------- */

h1 { font-size: 27px; font-weight: 680; letter-spacing: -.02em; margin: 0 0 4px; }
h2 { font-size: 18px; font-weight: 650; letter-spacing: -.01em; margin: 0 0 12px; }
h3 { font-size: 15px; font-weight: 620; margin: 0 0 6px; }
.lede { color: var(--muted); margin: 0 0 22px; max-width: 68ch; }

/* Letter-spaced small caps: the section markers of the barn whiteboard this replaces. */
.eyebrow {
  font-size: 11px; font-weight: 700; letter-spacing: .13em; text-transform: uppercase;
  color: var(--faint); margin: 34px 0 12px; display: flex; align-items: center; gap: 10px;
}
.eyebrow::after { content: ""; flex: 1; height: 1px; background: var(--line); }
.page-head { display: flex; align-items: flex-start; gap: 16px; flex-wrap: wrap; margin-bottom: 8px; }
.page-head .actions { margin-left: auto; display: flex; gap: 8px; align-items: center; }
.breadcrumb { color: var(--faint); font-size: 13px; margin-bottom: 8px; }
.breadcrumb a { color: var(--muted); }

/* ---- cards + layout ---------------------------------------------------------------------- */

.card, .panel {
  background: var(--card); border: 1px solid var(--line); border-radius: var(--radius);
  box-shadow: var(--shadow-s);
}
.panel { padding: 20px; }
.panel + .panel { margin-top: 16px; }
.grid { display: grid; gap: 14px; }
.grid.g2 { grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); }
.grid.g3 { grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); }
.grid.g4 { grid-template-columns: repeat(auto-fit, minmax(175px, 1fr)); }

/* ---- stats ------------------------------------------------------------------------------- */

.stat { background: var(--card); border: 1px solid var(--line); border-radius: var(--radius); padding: 16px 18px; }
.stat .k { font-size: 11px; font-weight: 700; letter-spacing: .1em; text-transform: uppercase; color: var(--faint); }
.stat .v { font-size: 30px; font-weight: 640; letter-spacing: -.02em; margin-top: 4px; line-height: 1.1; }
.stat .u { font-size: 12px; color: var(--muted); margin-top: 2px; }
.stat.good .v { color: var(--sprout); }
.stat.warn .v { color: var(--clay); }

/* ---- progress: one visual language for "how far along" ----------------------------------- */

.bar { height: 8px; border-radius: 999px; background: var(--line-2); overflow: hidden; }
.bar > span { display: block; height: 100%; background: var(--sprout); border-radius: 999px; transition: width .5s ease; }
.bar.water > span { background: var(--water); }
.bar.sun > span { background: var(--sun); }
.bar-row { display: flex; align-items: center; gap: 12px; }
.bar-row .bar { flex: 1; }
.bar-row .pct { font-size: 13px; font-weight: 640; color: var(--muted); min-width: 44px; text-align: right; }

.split { display: flex; height: 12px; border-radius: 999px; overflow: hidden; background: var(--line-2); }
.split > span { display: block; }
.legend { display: flex; flex-wrap: wrap; gap: 6px 16px; margin-top: 10px; font-size: 13px; color: var(--muted); }
.legend i { width: 9px; height: 9px; border-radius: 3px; display: inline-block; margin-right: 6px; }

/* ---- pills ------------------------------------------------------------------------------- */

.pill {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 12px; font-weight: 620; padding: 3px 10px; border-radius: 999px;
  background: var(--line-2); color: var(--muted); white-space: nowrap;
}
.pill.green { background: var(--sprout-soft); color: var(--sprout); }
.pill.blue  { background: var(--water-soft);  color: var(--water); }
.pill.amber { background: var(--sun-soft);    color: var(--sun); }
.pill.red   { background: var(--clay-soft);   color: var(--clay); }

/* Goal -> project -> task lineage. Shown, not merely stored: people work better when they can see
   what their work is for, and it costs one join. */
.lineage { font-size: 12px; color: var(--faint); display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.lineage a { color: var(--muted); }
.lineage .sep { color: var(--line); }

/* ---- forms ------------------------------------------------------------------------------- */

label { display: block; font-size: 12px; font-weight: 650; color: var(--muted); margin-bottom: 5px; }
input, select, textarea {
  width: 100%; padding: 9px 11px; border: 1px solid var(--line); border-radius: var(--r-s);
  background: var(--card); color: var(--ink); font-family: var(--font); font-size: 14px;
}
/* Not everything with a border is a text field. The blanket width:100% above stretched every
   checkbox across its row, which pushed the name beside it onto the next line — the people
   picker on a project read as a column of empty boxes with names underneath them. */
input[type="checkbox"], input[type="radio"] {
  width: auto; padding: 0; margin: 0; vertical-align: middle;
}
textarea { min-height: 70px; resize: vertical; }

/* Tick-as-many-as-you-need lists: chips that wrap, not a stack of full-width rows. */
.peoplepick { display: flex; flex-wrap: wrap; gap: 8px 16px; margin: 4px 0 0; }
.peoplepick .pick {
  display: inline-flex; align-items: center; gap: 7px; margin: 0;
  font-size: 13.5px; font-weight: 500; color: var(--ink); cursor: pointer;
}
/* Names you turn on and off, one click each.
 *
 * For any question of the shape "who is on this" — a project's people, and anywhere else the same
 * question comes up. One list of everybody, each name its own little form, and the click is the
 * save: no Save button, and no second list of the people who are not on it. The face and the tick
 * are what say which way it is set, because a colour alone is not an answer on a bright day.
 *
 * Whoever holds the list decides what a press means; this only draws it. */
.peopletoggle { display: flex; flex-wrap: wrap; gap: 8px; margin: 4px 0 0; }
.peopletoggle form { margin: 0; }
.peopletoggle button {
  display: inline-flex; align-items: center; gap: 9px; padding: 6px 14px 6px 6px;
  border: 1px solid var(--line); border-radius: 999px; background: var(--card);
  font-size: 14px; font-weight: 550; color: var(--muted); cursor: pointer;
}
.peopletoggle button:hover { background: var(--line-2); }
.peopletoggle .avatar { width: 30px; height: 30px; font-size: 12px; opacity: .45; }
.peopletoggle .nm { line-height: 1; }
/* The tick holds its width whether it is shown or not, so a name does not shuffle sideways as it
   goes on and off — a list that moves under the finger is a list you mis-tap. */
.peopletoggle .tick { width: 12px; color: var(--sprout); font-weight: 700; visibility: hidden; }
.peopletoggle button.on {
  background: var(--sprout-soft); border-color: var(--sprout); color: var(--ink);
}
.peopletoggle button.on .avatar { opacity: 1; }
.peopletoggle button.on .tick { visibility: visible; }
.peopletoggle button:focus-visible { outline: 2px solid var(--water); outline-offset: 2px; }

input:focus, select:focus, textarea:focus { outline: none; border-color: var(--water); box-shadow: 0 0 0 3px var(--water-soft); }
.field { margin-bottom: 12px; }
.field label { margin-bottom: 5px; }
.row { display: flex; gap: 12px; flex-wrap: wrap; align-items: flex-end; }
.row > * { flex: 1; min-width: 140px; }
.row > .shrink { flex: 0 0 auto; min-width: 0; }
/* A .field carries 12px under it for stacked forms. Inside a .row the items are bottom-aligned, so
   that margin lifted the control 12px clear of the button beside it and the pair read as two rows
   that had wrapped rather than one control with its button. */
.row > .field { margin-bottom: 0; }

/* A form is a block element, so two of them in one table cell put Save on its own line and the
   × underneath it — which is what the routines page had been doing since it was written. The
   class was on the markup in five templates and had never existed in here.

   nowrap on purpose: these are two or three controls that together mean one thing, and a Save
   that wraps away from the field it saves is a Save nobody presses. The CELL decides whether the
   group as a whole moves; the group never comes apart. */
form.inline, .inline {
  display: inline-flex; align-items: center; gap: 6px; flex-wrap: nowrap;
  vertical-align: middle; margin: 0;
}
form.inline + form.inline, .inline + .inline { margin-left: 6px; }
form.inline .field, .inline .field { margin-bottom: 0; }
/* Controls keep their own size rather than being stretched by the flex row they now sit in. */
form.inline > *, .inline > * { flex: 0 0 auto; width: auto; }
form.inline select, .inline select, form.inline input, .inline input { width: auto; min-width: 0; }
form.inline input[type="text"], .inline input[type="text"] { min-width: 90px; }
/* Where several of these share a cell, they line up right and stay on one line. */
td.actions, th.actions { text-align: right; white-space: nowrap; padding-right: 0; }
td.num .inline, td.actions .inline { white-space: nowrap; }

/* Saving in the background is faster than a page load, which is the problem: without a mark it
   is indistinguishable from a button that did nothing. Half a second of dimming is enough to
   read as "that went". */
form.htmx-request { opacity: .5; transition: opacity .1s; }
form.htmx-request button { pointer-events: none; }

button, .btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 7px;
  font-family: var(--font); font-size: 14px; font-weight: 620; padding: 9px 16px;
  border-radius: var(--r-s); border: 1px solid var(--line);
  background: var(--card); color: var(--ink); cursor: pointer; text-decoration: none;
  transition: background .15s, filter .15s;
}
button:hover, .btn:hover { background: var(--line-2); text-decoration: none; }
button.primary, .btn.primary { background: var(--sprout); border-color: var(--sprout); color: #fff; }
button.primary:hover, .btn.primary:hover { filter: brightness(1.08); background: var(--sprout); }
button.ghost, .btn.ghost { background: transparent; color: var(--muted); }
button.ghost:hover { background: var(--line-2); color: var(--ink); }
button.quiet { border-color: transparent; background: transparent; color: var(--muted); }
button.quiet:hover { background: var(--line-2); }
button.danger { color: var(--clay); border-color: var(--clay-soft); background: transparent; }
button.danger:hover { background: var(--clay-soft); }
button.small, .btn.small { padding: 5px 11px; font-size: 13px; }
.num-control { display: flex; gap: 8px; align-items: center; }
.num-control input { width: 100px; }

details.adder > summary {
  cursor: pointer; font-size: 14px; font-weight: 620; color: var(--water);
  padding: 8px 0; list-style: none;
}
details.adder > summary::-webkit-details-marker { display: none; }
details.adder > summary::before { content: "+ "; font-weight: 700; }
details.adder[open] > summary::before { content: "− "; }

/* ---- tables ------------------------------------------------------------------------------ */

table { width: 100%; border-collapse: collapse; font-size: 14px; }
th {
  text-align: left; font-size: 11px; font-weight: 700; letter-spacing: .09em;
  text-transform: uppercase; color: var(--faint); padding: 0 12px 9px 0;
  border-bottom: 1px solid var(--line);
}
td { padding: 11px 12px 11px 0; border-bottom: 1px solid var(--line-2); vertical-align: top; }
tr:last-child td { border-bottom: none; }

/* Alternating rows, on every table on the office side.
 *
 * Barely there on purpose. A wide row — a task with a name, two people, an estimate, an amount —
 * is read across, and the eye needs something to hold the line; a stripe you notice is a stripe
 * that says these rows are two different kinds of thing, which they are not. If it reads as a
 * colour on a barn screen in daylight it is too strong.
 *
 * On the cells rather than the row, because a row's background sits behind its cells and loses to
 * anything a page paints on a td. The week grid is left out: its cells carry their own colours,
 * and Tuesday is not a stripe. */
tbody tr:nth-child(even) > td { background: var(--stripe); }
/* A row that is drawn for a REASON keeps its own colour: the egg report hatches the gap
   between one week and the next, and a stripe on top of it made the hatching disappear on
   every other one. Anything with a meaning of its own opts out here. */
tbody tr.gapline > td, tbody tr.struckrow > td { background: revert; }
.weekgrid tbody tr:nth-child(even) > td { background: none; }
td.num, th.num { text-align: right; padding-right: 0; }
td .state { font-size: 11px; padding: 2px 9px; border-radius: 999px; background: var(--line-2); color: var(--muted); }
.state.acked { background: var(--sprout-soft); color: var(--sprout); }
.state.failed { background: var(--clay-soft); color: var(--clay); }
.state.pending, .state.sent { background: var(--sun-soft); color: var(--sun); }

/* ---- empty states: an invitation to act, never a shrug ----------------------------------- */

.empty {
  padding: 30px 22px; text-align: center; color: var(--muted);
  border: 1px dashed var(--line); border-radius: var(--radius); background: var(--card-2);
}
.empty strong { display: block; color: var(--ink); font-weight: 620; margin-bottom: 4px; }

.note { font-size: 13px; color: var(--muted); line-height: 1.5; }
/* A note that has to say something went wrong. Same size, different colour: it is still a note,
   not an alarm. */
.note.bad { color: var(--clay); font-weight: 600; }
/* WHAT WAS TYPED, IN THE SHAPE IT WAS TYPED. A description written as three lines — where the
   crate is, which gate, who to ask — renders as one paragraph in HTML, so the shape somebody put
   into it is thrown away between the box and the page. Applied by hand rather than to `.note`
   generally: a note whose SOURCE spans several lines would then break where the template happens
   to wrap, which is a different thing entirely. */
.lines { white-space: pre-line; }
.err { color: var(--clay); font-size: 13px; margin: 8px 0 0; }
.flash { padding: 11px 14px; border-radius: var(--r-s); font-size: 14px; margin-bottom: 16px; }
.flash.ok  { background: var(--sprout-soft); color: var(--sprout); }
.flash.bad { background: var(--clay-soft); color: var(--clay); }

/* ---- reconciliation: neutral by design --------------------------------------------------- */

.recon {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(148px, 1fr)); gap: 1px;
  background: var(--line); border: 1px solid var(--line); border-radius: var(--radius); overflow: hidden;
}
.recon .cell { background: var(--card); padding: 14px 16px; }
.recon .cell.result { background: var(--card-2); }
.recon .cell.flagged { background: var(--clay-soft); }
.recon .k { font-size: 11px; font-weight: 700; letter-spacing: .09em; text-transform: uppercase; color: var(--faint); }
.recon .v { font-size: 22px; font-weight: 640; margin-top: 3px; }
.recon .cell.flagged .v { color: var(--clay); }

/* ---- device panel (existing components, restyled) ---------------------------------------- */

.devices { display: grid; grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); gap: 16px; }
.card { overflow: hidden; }
.card-head { display: flex; align-items: center; gap: 10px; padding: 14px 16px; border-bottom: 1px solid var(--line); }
.card-head .title { font-weight: 640; }
.card-head .kind { color: var(--faint); font-size: 11px; text-transform: uppercase; letter-spacing: .1em; }
.card-head a.title { color: var(--ink); }
.card-head a.title:hover { color: var(--water); }

.status { display: inline-flex; align-items: center; gap: 6px; margin-left: auto; font-size: 12px; color: var(--muted); }
.dot { width: 9px; height: 9px; border-radius: 50%; background: var(--faint); }
.dot.online { background: var(--sprout); box-shadow: 0 0 0 3px var(--sprout-soft); }
.dot.no_stream, .dot.stale_data { background: var(--sun); box-shadow: 0 0 0 3px var(--sun-soft); }
.dot.offline, .dot.never { background: var(--faint); }

.tiles { display: grid; grid-template-columns: repeat(2, 1fr); gap: 1px; background: var(--line); }
.tile { background: var(--card); padding: 14px 16px; min-height: 78px; }
.tile .k { color: var(--faint); font-size: 11px; font-weight: 650; letter-spacing: .06em; }
.tile .v { font-size: 26px; font-weight: 640; margin-top: 4px; letter-spacing: -.02em; }
.tile .v .u { font-size: 14px; color: var(--muted); font-weight: 550; margin-left: 4px; }
.tile.bool .v.on { color: var(--sprout); }
.tile.bool .v.off { color: var(--faint); }

.controls { padding: 12px 16px 16px; border-top: 1px solid var(--line); display: grid; gap: 10px; background: var(--card-2); }
.control { display: flex; align-items: center; gap: 12px; }
.control .lbl { font-size: 14px; flex: 1; }
.control .pending { font-size: 11px; color: var(--sun); }

.switch { position: relative; width: 52px; height: 30px; flex: 0 0 auto; }
.switch input { opacity: 0; width: 0; height: 0; }
.slider { position: absolute; inset: 0; background: var(--line); border: 1px solid var(--line); border-radius: 999px; cursor: pointer; transition: .18s; }
.slider::before { content: ""; position: absolute; height: 22px; width: 22px; left: 3px; top: 3px; background: #fff; border-radius: 50%; transition: .18s; box-shadow: var(--shadow-s); }
.switch input:checked + .slider { background: var(--sprout); border-color: var(--sprout); }
.switch input:checked + .slider::before { transform: translateX(22px); }
.switch.busy .slider { opacity: .5; }

.enroll-card { background: var(--water-soft); border: 1px dashed var(--water); border-radius: var(--radius); padding: 16px; margin-top: 14px; }
.enroll-card code { font-family: var(--mono); color: var(--water); font-size: 13px; word-break: break-all; }
.enroll-card pre { background: var(--card); border: 1px solid var(--line); border-radius: var(--r-s); padding: 12px; overflow-x: auto; font-family: var(--mono); font-size: 12.5px; }
.code-pill { display: inline-block; font-family: var(--mono); font-size: 20px; letter-spacing: 1px; color: var(--sprout); background: var(--card); border: 1px solid var(--line); padding: 8px 14px; border-radius: var(--r-s); font-weight: 650; }

.sparkline { display: block; width: 100%; height: 40px; margin-top: 8px; }

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

.login-wrap { min-height: 100vh; display: grid; place-items: center; padding: 24px; }
.login-card { width: 100%; max-width: 380px; text-align: center; }
.login-card img { height: 80px; margin-bottom: 6px; }
.login-card .panel { text-align: left; margin-top: 18px; }

/* ---- staff kiosk: big targets, muddy hands, one shared tablet ---------------------------- */

.kiosk { max-width: 900px; margin: 0 auto; padding: 26px 18px 60px; }
.people { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 14px; }
.person {
  display: flex; flex-direction: column; align-items: center; gap: 10px;
  padding: 22px 12px; background: var(--card); border: 1px solid var(--line);
  border-radius: var(--radius); cursor: pointer; text-decoration: none; color: var(--ink);
  box-shadow: var(--shadow-s); transition: transform .12s, box-shadow .12s;
}
.person:hover { transform: translateY(-2px); box-shadow: var(--shadow); text-decoration: none; }
.avatar {
  width: 58px; height: 58px; border-radius: 50%; display: grid; place-items: center;
  color: #fff; font-weight: 700; font-size: 21px; letter-spacing: -.02em;
}
.person .nm { font-weight: 620; font-size: 15px; text-align: center; }
.person .rl { font-size: 12px; color: var(--faint); }
.person.on { border-color: var(--sprout); box-shadow: 0 0 0 3px var(--sprout-soft); }

.pinpad { display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px; max-width: 300px; margin: 20px auto 0; }
.pinpad button { font-size: 24px; font-weight: 620; padding: 18px 0; }
.pindots { display: flex; gap: 12px; justify-content: center; margin: 18px 0 4px; }
.pindots i { width: 14px; height: 14px; border-radius: 50%; background: var(--line); display: block; }
.pindots i.on { background: var(--sprout); }

.activity-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(160px, 1fr)); gap: 12px; }
.activity {
  padding: 20px 16px; border-radius: var(--radius); border: 2px solid var(--line);
  background: var(--card); font-weight: 620; font-size: 16px; cursor: pointer; text-align: left;
}
.activity:hover { background: var(--line-2); }
.activity.current { border-color: var(--sprout); background: var(--sprout-soft); color: var(--sprout); }
.activity .sub { display: block; font-size: 12px; font-weight: 550; color: var(--faint); margin-top: 3px; }

@media (max-width: 640px) {
  .wrap { padding: 18px 14px 60px; }
  h1 { font-size: 23px; }
  .topbar { padding: 10px 14px; }
  .topbar nav a { padding: 6px 10px; font-size: 13px; }
}

/* ---- plot map: beds drawn as the strips they actually are -------------------------------- */

.plotmap { display: flex; gap: 5px; align-items: stretch; overflow-x: auto; padding-bottom: 4px; }
.bed {
  flex: 1 1 0; min-width: 62px; min-height: 120px; text-decoration: none; color: var(--ink);
  border: 1.5px solid var(--line); border-radius: 7px; background: var(--card-2);
  padding: 9px 7px; display: flex; flex-direction: column; gap: 3px; align-items: center;
  text-align: center; transition: transform .1s, box-shadow .1s;
}
.bed:hover { transform: translateY(-2px); box-shadow: var(--shadow); text-decoration: none; }
.bed .bnum { font-size: 11px; font-weight: 700; color: var(--faint); }
.bed .bcrop { font-size: 13px; font-weight: 620; line-height: 1.2; }
.bed .bwhen { font-size: 11px; color: var(--muted); margin-top: auto; }
.bed .bempty { font-size: 12px; color: var(--faint); font-style: italic; margin-top: auto; }


/* ---- update notice ------------------------------------------------------------------------- */
.updatebar {
  position: fixed; left: 50%; bottom: 22px; transform: translateX(-50%);
  display: flex; align-items: center; gap: 12px; z-index: 80;
  background: var(--ink); color: var(--paper);
  padding: 11px 12px 11px 18px; border-radius: 999px; font-size: 14px;
  box-shadow: 0 8px 28px rgba(0,0,0,.28);
}
.updatebar button {
  background: var(--sprout); color: #fff; border: none; font: inherit; font-weight: 650;
  padding: 7px 15px; border-radius: 999px; cursor: pointer; width: auto;
}
.updatebar button.dismiss {
  background: transparent; color: var(--paper); opacity: .6; padding: 4px 9px; font-size: 19px;
  line-height: 1;
}
.updatebar button.dismiss:hover { opacity: 1; }
@media (max-width: 520px) { .updatebar { left: 12px; right: 12px; transform: none; border-radius: 14px; } }


/* ---- board: it updates itself, and says so when it cannot ----------------------------------- */
.boardstale {
  position: fixed; right: 16px; top: 16px; z-index: 90;
  background: var(--clay); color: #fff; padding: 8px 14px; border-radius: 999px;
  font-size: 14px; font-weight: 650;
}


/* ---- pinning a project to the barn board ---------------------------------------------------
   A star in the corner rather than a button in the row: the button wrapped the pill line onto two
   lines on every card, and the state it shows is binary, so a control the size of a word was doing
   the job of a control the size of a glyph. */
.pcard { position: relative; }

/* ---- the three lists on /projects ----------------------------------------------------------
   The page is about live work. What is waiting to be reviewed sits above it because it is a short
   queue somebody has to clear; what has been reviewed sits behind a summary, because the reward
   for finishing a project should not be another card to scroll past for ever. */
.secthead { display: flex; align-items: baseline; gap: 9px; margin: 26px 0 4px; }
.secthead .ct {
  font-size: 12px; font-weight: 700; color: var(--paper); background: var(--clay);
  border-radius: 999px; padding: 1px 8px; letter-spacing: .02em;
}
details.finished { margin-top: 30px; border-top: 1px solid var(--line); padding-top: 12px; }
details.finished > summary {
  cursor: pointer; font-size: 14px; font-weight: 620; color: var(--muted);
  padding: 6px 0; list-style: none;
}
details.finished > summary::-webkit-details-marker { display: none; }
details.finished > summary::before { content: "\25b8  "; }
details.finished[open] > summary::before { content: "\25be  "; }
/* Reviewed cards are quiet but still legible — greying them right out would defeat the one thing
   the drawer is for, which is going back to look something up. */
.pcard.done { opacity: .72; }
.pcard.done:hover, .pcard.done:focus-within { opacity: 1; }

.pinstar { position: absolute; top: 10px; right: 12px; margin: 0; }
.pinstar button {
  background: none; border: none; padding: 2px 4px; width: auto;
  font-size: 22px; line-height: 1; cursor: pointer; color: var(--line-2);
  transition: color .12s;
}
.pinstar button:hover { color: var(--faint); }
.pinstar button.on { color: #E0A33C; }

/* ---- the settings menu -------------------------------------------------------------------
   A <details> rather than a scripted dropdown: it opens with a click and closes with Escape on
   its own, keyboard included, and it still works if the JavaScript on a page has thrown. */
.topbar nav details.menu { position: relative; display: inline-block; }
.topbar nav details.menu > summary {
  list-style: none; cursor: pointer; padding: 6px 10px; border-radius: 7px;
  color: var(--muted); font-size: 14px; white-space: nowrap;
}
.topbar nav details.menu > summary::-webkit-details-marker { display: none; }
.topbar nav details.menu > summary::after { content: " ▾"; opacity: .55; }
.topbar nav details.menu > summary:hover { color: var(--ink); background: var(--card-2); }
.topbar nav details.menu > summary.active { color: var(--sprout); font-weight: 650; }
.topbar nav .menupop {
  position: absolute; right: 0; top: calc(100% + 6px); z-index: 40; min-width: 170px;
  display: flex; flex-direction: column; padding: 6px;
  background: var(--card); border: 1px solid var(--line); border-radius: 10px;
  box-shadow: 0 10px 26px rgba(0,0,0,.16);
}
.topbar nav .menupop a { padding: 8px 10px; border-radius: 6px; }

/* ---- Work: a word and a caret ---------------------------------------------------------------
   The label is a link to the crew board and the caret opens the rest, so the page behind the word
   is one click and the planning screens are two — on a phone as well, where there is no hover to
   open anything with. The caret needs a target of its own, hence the padding on the summary and
   the anchor stopping short of it. */
.topbar nav details.work { margin-right: 2px; }
.topbar nav details.work > summary { padding-right: 6px; }
.topbar nav details.work > summary > a {
  color: inherit; text-decoration: none; padding: 6px 2px 6px 0; margin: -6px 0;
}
.topbar nav details.work > summary::after { content: " ▾"; padding: 0 4px; }
.topbar nav details.work .menupop { right: auto; left: 0; }

/* ---- handing work out ------------------------------------------------------------------------ */

/* The bar above the task table. Deliberately plain: it is a control, not a feature. */
.handout { display: grid; gap: 10px; }
.handout .row { align-items: baseline; }
.handout .row > * { flex: 0 0 auto; min-width: 0; }
.handout .row .note { flex: 1 1 260px; }
.handout .peoplepick { gap: 8px; }
.handout .peoplepick .chip {
  display: inline-flex; align-items: center; gap: 7px; margin: 0; cursor: pointer;
  padding: 7px 12px; border-radius: 999px; border: 1px solid var(--line);
  background: var(--card); font-size: 13.5px; font-weight: 550;
}
.handout .peoplepick .chip:has(input:checked) {
  background: var(--sprout-soft); border-color: var(--sprout); color: var(--sprout);
}
.handout .peoplepick .chip input { width: auto; margin: 0; }
.tasktable td.pickbox { text-align: center; vertical-align: top; padding-top: 14px; }
.tasktable td.pickbox input { width: auto; }

/* The task table's own column widths live in project.html, beside the markup they count. */

/* ---- the week --------------------------------------------------------------------------------- */

.weekwrap { overflow-x: auto; }
.weekgrid { width: 100%; border-collapse: collapse; min-width: 900px; }
.weekgrid th, .weekgrid td {
  border: 1px solid var(--line); padding: 8px 9px; vertical-align: top; text-align: left;
}
.weekgrid thead th { background: var(--card-2); font-size: 12.5px; }
.weekgrid thead th .dn { display: block; font-weight: 700; }
.weekgrid thead th .dd { display: block; color: var(--muted); font-weight: 500; }
.weekgrid th.who { width: 140px; font-size: 14px; font-weight: 650; background: var(--card-2); }
.weekgrid td { width: 12.2%; }
/* A day nobody is scheduled is a day that cannot take work, and it should look like one. */
.weekgrid td.off { background: repeating-linear-gradient(135deg,
  transparent 0 6px, rgba(0,0,0,.025) 6px 12px); }
.weekgrid .is-today { box-shadow: inset 0 3px 0 var(--sprout); }
.weekgrid .hrs { display: block; font-size: 11.5px; color: var(--muted); margin-bottom: 6px; }
/* Scoped to .daylist rather than to .weekgrid: the day board draws the same chip, and `.on` on
   its own is a class four other things on this site already use. */
.daylist .on {
  display: flex; align-items: center; gap: 5px; margin-bottom: 5px;
  background: var(--sprout-soft); border-radius: 8px; padding: 4px 6px;
  font-size: 12.5px; font-weight: 600; line-height: 1.25;
}
.daylist .on .em { font-size: 14px; }
.daylist .on form { margin-left: auto; }
.daylist .on form + form { margin-left: 0; }
.daylist .on .x {
  background: none; border: 0; padding: 0 3px; color: var(--muted); font-size: 14px;
  cursor: pointer; min-height: 0;
}
.daylist .on .x.rest { color: var(--sprout); }
.weekgrid select.mini, .daycol select.mini { width: 100%; font-size: 12px; padding: 5px 6px; }

/* ---- what a chip is doing --------------------------------------------------------------------
   Two marks, and they have to survive being read at arm's length across seven columns.

   LIVE is an outline: a ring in the sprout green over a white fill, so the chip lifts off the
   others rather than merely changing shade. Somebody is stood in a field doing this right now.
   DONE is struck through and drained — the same treatment the crew's own screen gives a finished
   row, so the two screens say the same thing the same way. Finished work stays on the grid: a
   list that empties as it is worked reads as though the work was never there. */
/* The name is wrapped in a span only so the strike-through lands on it and not on the buttons
   beside it. It is deliberately given NO width behaviour: as a flex item free to shrink it wraps
   a character per line in a column a seventh of the screen wide, which is what it did for one
   round of this. */
.daylist .on.live { box-shadow: 0 0 0 2px var(--sprout); background: #fff; }
.daylist .on .nowdot {
  width: 7px; height: 7px; border-radius: 50%; background: var(--sprout); flex: 0 0 auto;
  box-shadow: 0 0 0 3px var(--sprout-soft);
}
.daylist .on .nowtag, .daylist .on .donetag {
  font-size: 10.5px; font-weight: 700; letter-spacing: .03em; text-transform: uppercase;
  flex: 0 0 auto;
}
.daylist .on .nowtag { color: var(--sprout); }
.daylist .on .donetag { color: var(--faint); }
.daylist .on.done { background: var(--card-2); color: var(--faint); box-shadow: none; }
.daylist .on.done .what { text-decoration: line-through; }
.daylist .on.done .em { filter: grayscale(.75); opacity: .55; }
.daylist .on.done .grip { opacity: .4; }

/* The routines table below the grid, marked the same way. */
tr.struckrow .what { text-decoration: line-through; }
tr.struckrow td, tr.struckrow .what { color: var(--faint); }

/* ---- week or day ------------------------------------------------------------------------------ */

.planhead { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; margin: 22px 0 8px; }
.planhead .stepper { display: flex; align-items: center; gap: 8px; font-size: 14px; }
.planhead .stepper strong { min-width: 13ch; text-align: center; }
.planhead .viewtoggle { margin-left: auto; display: flex; border: 1px solid var(--line);
  border-radius: 9px; overflow: hidden; background: var(--card); }
.planhead .seg {
  padding: 6px 14px; font-size: 13px; font-weight: 650; color: var(--muted);
  text-decoration: none;
}
.planhead .seg.is-on { background: var(--sprout); color: #fff; }
.planhead .seg:not(.is-on):hover { background: var(--card-2); }

/* One day, one column per person. Columns hold a floor width and the wrapper scrolls: squeezing a
   ninth person in is how the day board turns back into the thing it was built to replace. */
.dayboard { display: flex; gap: 10px; align-items: flex-start; }
.daycol {
  flex: 1 1 220px; min-width: 210px; border: 1px solid var(--line); border-radius: 10px;
  padding: 9px 10px; background: var(--card);
}
/* Narrower, because the board now carries a column for EVERY person whether they are in or not —
   work is handed out by dragging it onto somebody, and a person with no column is a person you
   cannot hand anything to. They are drop targets rather than plans, so they take the space of one
   and leave the width to the people who are actually on today. */
.daycol.off { background: repeating-linear-gradient(135deg,
  transparent 0 6px, rgba(0,0,0,.025) 6px 12px);
  flex: 0 1 160px; min-width: 150px; }
.daycol .dayhead { margin-bottom: 8px; }
.daycol .dayhead strong { display: block; font-size: 14.5px; }
.daycol .hrs { font-size: 11.5px; color: var(--muted); }
.daycol .daylist { min-height: 10px; }
.daycol .daylist .on { margin-bottom: 6px; font-size: 13px; padding: 6px 8px; }
/* The rule between the people who are on today and the people who are not. Vertical, because
   the board is columns, and labelled, because an unexplained line is just a gap. */
.dayrule {
  flex: 0 0 auto; align-self: stretch; width: 1px; background: var(--line);
  position: relative; margin: 0 12px;
}
.dayrule span {
  position: absolute; top: 8px; left: 50%; transform: translateX(-50%) rotate(180deg);
  writing-mode: vertical-rl; font-size: 10.5px; letter-spacing: .08em; text-transform: uppercase;
  color: var(--muted); background: var(--bg, #fff); padding: 6px 1px;
}
/* One dialog serves every column: the button fills in whose it is. */
.assignbox { border: 1px solid var(--line); border-radius: 12px; padding: 0; max-width: 640px;
  width: calc(100% - 32px); }
.assignbox::backdrop { background: rgba(20,18,15,.42); }
.assignbox .abhead { padding: 14px 16px 10px; border-bottom: 1px solid var(--line); }
.assignbox .abhead h3 { margin: 0; font-size: 16px; }
.assignbox .abbody { padding: 8px 16px; max-height: 52vh; overflow: auto; }
.assignbox .abfoot { padding: 12px 16px; border-top: 1px solid var(--line); display: flex;
  justify-content: space-between; align-items: center; gap: 10px; }
.assignbox .abproj { font-size: 11.5px; letter-spacing: .08em; text-transform: uppercase;
  color: var(--muted); margin: 12px 0 4px; }
.assignbox label.abtask { display: flex; gap: 9px; align-items: baseline; padding: 5px 2px;
  border-bottom: 1px solid var(--line); cursor: pointer;
  /* Shift-clicking a range would otherwise drag a blue selection across the list. */
  -webkit-user-select: none; user-select: none; }
.assignbox label.abtask:last-child { border-bottom: 0; }
.assignbox label.abtask .who { margin-left: auto; font-size: 11.5px; color: var(--muted); }
.spareday { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; margin-top: 12px; }
.spareday .spare { font-size: 12.5px; }

/* ---- what is behind a chip ---------------------------------------------------------------------
   The name is a button because it opens something. It must not look like one: a chip full of
   buttons reads as a toolbar, and this is a label you can press. */
.daylist .on .what.open {
  background: none; border: 0; padding: 0; margin: 0; min-height: 0; font: inherit; color: inherit;
  text-align: left; cursor: pointer;
}
.daylist .on .what.open:hover { text-decoration: underline; }
.daylist .on.done .what.open { text-decoration: line-through; }

/* How much of a project has this person's name on it. "no tasks" is the whole point of it being
   here, so it is the one that is coloured. */
.daylist .on .tally {
  font-size: 10.5px; font-weight: 700; color: var(--muted); flex: 0 0 auto;
  font-variant-numeric: tabular-nums;
}
.daylist .on .tally.none {
  color: #8A6A1F; background: var(--sun-soft); border-radius: 5px; padding: 0 4px;
  text-transform: uppercase; letter-spacing: .02em;
}

.chippanel {
  width: min(720px, 94vw); max-height: 88vh; border: 1px solid var(--line); border-radius: 14px;
  padding: 20px 22px; background: var(--card); color: var(--ink); overflow: auto;
}
.chippanel::backdrop { background: rgba(24,28,20,.42); }
.chiptitle { margin: 0 0 2px; font-size: 20px; }
.chipsub { margin: 0 0 14px; color: var(--muted); font-size: 13.5px; }
.chipdetail { margin: 0 0 14px; }
.chipwarn {
  margin: 0 0 14px; padding: 10px 12px; border-radius: 10px; background: var(--sun-soft);
  font-size: 13.5px;
}
/* ---- the wording, edited where it is read ----------------------------------------------------
   The name and the description ARE the boxes. They are meant to look like the heading and the
   paragraph they replaced until you put a cursor in one — an editor that announces itself with
   framed inputs at the top of a panel turns "read this job" into "fill this form in". */
.chipwords { margin: 0 0 4px; }
.chipwords .wordshead { display: flex; align-items: baseline; gap: 8px; }
.chipwords input, .chipwords textarea {
  font: inherit; color: inherit; background: transparent; border: 1px solid transparent;
  border-radius: 8px; padding: 4px 6px; width: 100%;
}
.chipwords input:hover, .chipwords textarea:hover { border-color: var(--line); }
.chipwords input:focus, .chipwords textarea:focus {
  border-color: var(--sprout); background: var(--card); outline: none;
}
.chipwords .chipemoji { width: 2.4em; flex: 0 0 auto; text-align: center; font-size: 20px; }
.chipwords .chiptitlebox { font-size: 20px; font-weight: 650; }
.chipwords .chipdetailbox { resize: vertical; line-height: 1.5; }
/* Save is for a keyboard and for a browser with no script. Quiet, because leaving a field has
   already saved. */
.chipwords .wordsrow { margin-top: 2px; }
.chipwords .wordsaid, .chipwho .wordsaid { font-size: 12.5px; color: var(--muted);
  font-weight: 500; letter-spacing: 0; text-transform: none; margin-left: 6px; }
.chipwords .chipaskbox { font-size: 14px; color: var(--muted); margin-top: 2px; }
.chipwords .chipaskbox:focus { color: var(--ink); }
/* What came back: the answer to the question, and any photographs. Drawn only when there is
   something to draw — an empty "Photo: 0 in" row is a line about nothing. */
.chipback { margin: 0 0 16px; padding: 10px 12px; border-radius: 10px; background: var(--card-2); }
.chipback .chipanswer { margin: 0; font-size: 14px; }
.chipback .shots { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 8px; }
.chipback .shots img { width: 88px; height: 88px; object-fit: cover; border-radius: 8px; }
.chipagain { margin: 0 0 16px; }

.chipform { margin: 0 0 18px; }
.chiprow { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; margin-top: 10px; }
.chiprow.end { justify-content: flex-end; border-top: 1px solid var(--line); padding-top: 14px; }
.chiptasks { width: 100%; border-collapse: collapse; font-size: 13.5px; }
.chiptasks td { border-top: 1px solid var(--line); padding: 7px 8px; vertical-align: top; }
.chiptasks td.pick { width: 26px; }
.chiptasks td.who, .chiptasks td.when { width: 92px; color: var(--muted); font-size: 12.5px; }
.chiptasks tr.isdone .what { text-decoration: line-through; color: var(--faint); }
.chiptasks .tag { font-weight: 650; }
.chiptasks .tag.is-mine { color: var(--sprout); }
.chiptasks .tag.none { color: var(--faint); font-weight: 500; }
.chiptasks .note { color: var(--muted); font-size: 12px; margin-top: 2px; }

/* Names as pressable chips rather than a multi-select: a list box that needs ctrl-click to add a
   second name is a control people use wrong once and then avoid. */
.pickpeople { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }
.pickpeople .person {
  display: inline-flex; align-items: center; gap: 6px; cursor: pointer;
  border: 1px solid var(--line); border-radius: 999px; padding: 5px 12px; font-size: 13px;
}
.pickpeople .person input { margin: 0; }
.pickpeople .person.is-on { border-color: var(--sprout); background: var(--sprout-soft); }
.chipfeed .upd { border-top: 1px solid var(--line); padding: 9px 0; font-size: 13.5px; }
.chipfeed .meta { color: var(--muted); font-size: 12px; margin-bottom: 3px; }
.chipfeed .shots { display: flex; gap: 6px; flex-wrap: wrap; margin-top: 6px; }
.chipfeed .shots img { width: 84px; height: 84px; object-fit: cover; border-radius: 8px; }
.chipfacts { display: grid; gap: 10px; margin-bottom: 16px; font-size: 13.5px; }
.chipfacts .k {
  display: block; font-size: 11px; text-transform: uppercase; letter-spacing: .05em;
  color: var(--muted); font-weight: 700;
}

/* The Connecteam sync being down, said on the roster page. Warm rather than red: nothing is
   broken or lost, the numbers below have simply stopped moving, and an alarm colour for "this is
   a snapshot" is the kind of thing people learn to scroll past. */
.ctdown {
  border: 1px solid #E4C48A; background: #FDF6E7; border-radius: 12px;
  padding: 20px 22px; margin: 0 0 22px;
}
.ctdown h2 { margin: 0 0 8px; font-size: 18px; line-height: 1.35; }
.ctdown p { margin: 0 0 10px; max-width: 68ch; }
.ctdown .when { color: #7A6A4A; font-size: 14px; }
.ctdown ol { margin: 14px 0 0; padding-left: 22px; display: grid; gap: 11px; }
.ctdown li b { display: block; }
.ctdown li span { display: block; color: #5E5647; font-size: 14.5px; line-height: 1.55; max-width: 66ch; }

/* A save that landed. The whole <main> is redrawn on every action, so without a mark the only
   evidence a tick took is that a number somewhere changed — which is why saving twice by accident
   was so easy. The row it happened to lights briefly and settles. Colour rather than movement:
   these lists are forty rows long and a row that slides pushes the next one under the cursor. */
@keyframes just-saved-fade {
  0%   { background: var(--sprout-soft); }
  70%  { background: var(--sprout-soft); }
  100% { background: transparent; }
}
.just-saved, .just-saved > td {
  animation: just-saved-fade 1.4s ease-out 1;
}
@media (prefers-reduced-motion: reduce) {
  .just-saved, .just-saved > td { animation-duration: 0.01s; background: transparent; }
}

/* Who is packing today, on the pack pages.
   It sits in the page head where the lede was, so it reads as a fact about the day rather than as
   a setting buried in a form — it is the name that goes on every one of forty labels. */
.packer { display: flex; align-items: center; gap: 8px; margin: 6px 0 0; flex-wrap: wrap; }
.packer label { font-size: 13px; color: var(--muted); font-weight: 600; }
.packer select { font-size: 14px; padding: 6px 10px; min-width: 170px; }
.packer .on { font-size: 12.5px; color: var(--faint); }

/* ---- "see their app" ------------------------------------------------------------------------
   An eye beside a person's name, quiet until it is wanted: it is a way of checking something, not
   an action anybody takes as part of planning a day, so it sits at the weight of a caption and
   comes up to full strength under the pointer. */
.aseye { display: inline-flex; vertical-align: middle; margin-left: 6px; }
.aseye .eye {
  display: inline-flex; align-items: center; justify-content: center;
  width: 26px; height: 26px; padding: 0; border: 0; border-radius: 7px;
  background: transparent; color: var(--faint); cursor: pointer;
}
.aseye .eye svg { width: 17px; height: 17px; fill: none; stroke: currentColor; stroke-width: 1.7;
  stroke-linecap: round; stroke-linejoin: round; }
.aseye .eye:hover, .aseye .eye:focus-visible { color: var(--sprout); background: var(--card-2); }

/* ---- flagged as stuck --------------------------------------------------------------------------
   Somebody in a field pressed "I am stuck". Amber, above the board: it is not an error and not a
   success, it is a thing waiting on a decision. */
.stalledlist { border-color: var(--sun); }
.stalledrow {
  display: flex; gap: 14px; align-items: flex-start; flex-wrap: wrap;
  padding: 10px 0; border-top: 1px solid var(--line);
}
.stalledlist .stalledrow:first-of-type { border-top: 0; }
.stalledrow > div:first-child { flex: 1; min-width: 220px; }
.stalledrow .note { display: block; }
.stalledrow .actions { display: flex; gap: 8px; align-items: center; }
