/*
 * NDS Integration service desk — one stylesheet for every module.
 *
 * The palette, type and rules are lifted from the NSHBCCC console so the two
 * read as one system: a technical document, not a dashboard. Barlow Condensed
 * for display, IBM Plex Sans for body, IBM Plex Mono for anything that is a
 * label, a code or a measurement.
 *
 * The layout change from the console is a left rail instead of tabs. Tabs top
 * out at about seven; the intranet has four groups that will keep growing, and
 * a rail makes the shape of the practice visible from any page.
 *
 * Modules must not ship their own CSS. If a module needs a component that is
 * not here, add it here — that is what keeps eight sections looking like one.
 */

:root{
  --film:#E4E9ED; --card:#F3F6F8; --ink:#16212B; --ink60:#5C6E7B;
  --rule:#B4C0C9; --rule2:#D3DBE1;
  --amber:#C8791A; --teal:#1C6A5E; --red:#9E2B25; --blue:#2B4C7E; --grey:#8794A0;
  --disp:'Barlow Condensed',"Arial Narrow",sans-serif;
  --body:'IBM Plex Sans',system-ui,sans-serif;
  --mono:'IBM Plex Mono',ui-monospace,monospace;
  --rail:224px;
}

/* Hiding the rail is one variable. The grid track, the rail itself and the
 * toggle button's `left` all read --rail, so they cannot fall out of step.
 *
 * It snaps rather than slides, and that is a decision, not an omission. Two
 * ways of animating it were built and both failed in the same direction —
 * leaving the layout stuck in a state no CSS rule described, which is far
 * worse than no animation:
 *   `transition:grid-template-columns` on #app — toggling inside the 180ms
 *     left the track pinned at its intermediate value, so the rail stayed 0px
 *     wide with the collapse class already gone.
 *   `@property --rail` + `transition:--rail` on :root — Chrome reported the
 *     transition as permanently `running` and the computed value never left
 *     224px, so nothing moved at all.
 * If someone wants the slide back, animate the rail's own `transform` and
 * leave the track alone — but the content will jump while the rail glides,
 * which is why it was not done that way here. */
.railhid{--rail:0px}
*{box-sizing:border-box}
html,body{margin:0;height:100%}
body{background:var(--film);color:var(--ink);font-family:var(--body);
 font-size:15px;line-height:1.5;-webkit-font-smoothing:antialiased}
:focus-visible{outline:2px solid var(--blue);outline-offset:2px}
button,input,select,textarea{font:inherit;color:inherit}
a{color:var(--blue)}

/* ---------------------------------------------------------------- layout */
/* The grid follows --rail, so there is nothing to collapse here. The state
 * class sits on <html> for two reasons: the toggle button is a sibling
 * *before* #app (it cannot be a grid child), so no combinator from #app can
 * reach it; and <html> exists before the first paint, so an inline script in
 * <head> restores the collapsed state without the rail flashing open —
 * app.js is a module and therefore deferred. */
#app{display:grid;grid-template-columns:var(--rail) 1fr;min-height:100vh}

aside.rail{background:var(--ink);color:var(--film);padding:20px 0 40px;
 position:sticky;top:0;height:100vh;overflow:auto}
/* Collapsing is a zero-width column, not a transform, so both of these earn
 * their place:
 *   min-width:0 — a grid item defaults to `min-width:auto` and refuses to
 *     shrink below its own min-content, so the rail sat at 224px overflowing a
 *     0px track and nothing appeared to happen at all. `main` below has
 *     carried the same override since day one, for the same reason.
 *   overflow:hidden — clips the content the narrowed track no longer fits.
 *     It has to go on the rail rather than on #app because the rail is
 *     `position:sticky`, and sticky inside a clipped ancestor stops sticking. */
.railhid aside.rail{overflow:hidden;min-width:0}
/* The measure widens when the rail goes, otherwise hiding it only shifts the
 * page left and buys nothing. Not unbounded: a spec clause set 1900px wide is
 * unreadable, which is the whole reason there is a max-width at all. */
.railhid main{max-width:1560px}

.railtoggle{position:fixed;top:13px;left:calc(var(--rail) - 31px);z-index:30;
 width:24px;height:24px;padding:0;line-height:1;cursor:pointer;
 background:var(--ink);color:var(--film);border:1px solid rgba(228,233,237,.28);
 font-family:var(--mono);font-size:13px}
.railtoggle:hover{background:#22303c;border-color:rgba(228,233,237,.5)}
/* Open, it rides just inside the rail's right edge. Collapsed, --rail is 0 and
 * `calc(0px - 31px)` would park it off the left of the screen — so it comes
 * back to the margin as a plain burger on the film background. */
.railhid .railtoggle{left:10px}
.brand{padding:0 18px 18px;border-bottom:1px solid rgba(228,233,237,.18)}
/* The NDS mark, as supplied: white letters on the NDS blue square. Never
 * recoloured or redrawn; the file is the brand. */
.brand .logo{width:56px;height:56px;display:block;margin-bottom:12px}
.brand .n{font-family:var(--disp);font-size:26px;font-weight:700;line-height:.95;
 text-transform:uppercase;letter-spacing:-.01em}
.brand .s{font-family:var(--mono);font-size:9px;letter-spacing:.18em;
 text-transform:uppercase;color:#93A6B3;margin-top:6px}
/* Who is signed in, at the foot of the rail, with Sign out */
.rail .who{margin:24px 18px 0;padding-top:14px;border-top:1px solid rgba(228,233,237,.18)}
.rail .who .n{font-size:14px;color:var(--film)}
.rail .who .s{font-family:var(--mono);font-size:9px;letter-spacing:.16em;text-transform:uppercase;
 color:#93A6B3;margin:3px 0 10px}
.rail .who .btn.ghost{color:var(--film);border-color:rgba(228,233,237,.35)}
/* The sign-in page: the shell with nothing in it but the form */
.signin .rail #nav{display:none}
.signin-box{max-width:420px;margin:12vh auto 0;background:var(--card);border:1px solid var(--rule);padding:28px 32px}
.signin-box h1{margin-top:0}
.signin-box form{display:grid;gap:12px}
.railgroup{margin-top:20px}
.railgroup>h3{font-family:var(--mono);font-size:9px;letter-spacing:.16em;
 text-transform:uppercase;color:#8398A6;font-weight:400;margin:0 0 6px;padding:0 18px}
.railgroup a{display:flex;align-items:baseline;gap:9px;padding:8px 18px;
 text-decoration:none;color:var(--film);font-size:14px;border-left:3px solid transparent}
.railgroup a:hover{background:rgba(228,233,237,.07)}
.railgroup a[aria-current=page]{background:rgba(228,233,237,.12);border-left-color:var(--amber)}
.railgroup a .ic{font-family:var(--mono);font-size:11px;color:#93A6B3;width:12px}
.railgroup a .cl{display:block;font-family:var(--mono);font-size:9px;
 letter-spacing:.09em;text-transform:uppercase;color:#8398A6;margin-top:2px}
/* Reordering the rail. The grip is the only thing that carries
   `touch-action:none`, so a finger dragged anywhere else in the rail still
   scrolls it — on a phone that matters more than a larger drag target. It sits
   in the padding the row already has, so appearing on hover shifts nothing. */
.railgroup a{position:relative}
.railgroup a .grip{position:absolute;left:2px;top:50%;transform:translateY(-50%);
 font-family:var(--mono);font-size:11px;line-height:1;color:#93A6B3;opacity:0;
 padding:3px 2px;cursor:grab;touch-action:none}
.railgroup a:hover .grip{opacity:.65}
.railgroup>h3{cursor:grab;touch-action:none}
/* Nothing to hover with, so the grips stay visible. */
@media (hover:none){.railgroup a .grip{opacity:.5}}
/* The dragged row rides above its neighbours and follows the pointer; the list
   below it reflows as it passes each midpoint. */
.rail .dragging{position:relative;z-index:5;cursor:grabbing;
 background:rgba(228,233,237,.14);box-shadow:0 6px 18px rgba(0,0,0,.35)}
.rail .dragging.railgroup{background:rgba(228,233,237,.07);border-radius:2px}
/* The dragged row is offset by a transform, which would otherwise grow the
   rail's scrollable area and flash a scrollbar mid-drag. */
.rail:has(.dragging){overflow:hidden}
.railreset{display:block;margin:22px 18px 0;padding:0;border:0;background:none;
 font-family:var(--mono);font-size:9px;letter-spacing:.14em;text-transform:uppercase;
 color:#8398A6;cursor:pointer}
.railreset:hover{color:var(--film)}
/* Two of them now, stacked at the foot of the rail. The published one reads as
   the primary of the pair — it is the one that changes something beyond this
   browser — so it carries the amber the rail uses for the current section. */
.railreset.save{margin-top:24px;margin-bottom:2px;color:var(--amber)}
.railreset.save:hover{color:#fff}
.railreset.save[disabled]{opacity:.65;cursor:default}
.railreset.save+.railreset{margin-top:0}
/* Destructive of a shared thing, so it reads as the quietest of the three
   rather than the loudest — it should be findable, not inviting. */
.railreset.clear{margin-top:0;color:#7A8C99}
.railreset.clear:hover{color:var(--red,#C4614F)}
.railreset.clear[disabled]{opacity:.65;cursor:default}
/* Author rules beat the UA's [hidden] rule: an element with its own display
 * (a grid, a flex row, an inline style) stays visible when hidden unless this
 * is restated. It was, once, on a form whose fields showed while unselected,
 * so a Customer was filled in that was never going to be saved. */
[hidden]{display:none!important}

.dot{width:6px;height:6px;border-radius:50%;margin-left:auto;flex:0 0 auto;align-self:center}
.dot.live{background:#4FB79E}.dot.partial{background:var(--amber)}.dot.stub{background:#5E7383}

main{padding:26px 30px 90px;max-width:1320px;min-width:0}

/* -------------------------------------------------------------- masthead */
.mast{border-top:3px solid var(--ink);padding-top:12px;margin-bottom:22px}
.eyebrow{font-family:var(--mono);font-size:10.5px;letter-spacing:.15em;
 text-transform:uppercase;color:var(--ink60);display:flex;flex-wrap:wrap;gap:16px;align-items:center}
.eyebrow b{color:var(--ink);font-weight:500}
h1{font-family:var(--disp);font-weight:700;font-size:clamp(30px,4.4vw,48px);
 line-height:.95;letter-spacing:-.015em;margin:8px 0 0;text-transform:uppercase}
h1 span{color:var(--ink60);font-weight:400}
.lede{font-size:14px;color:var(--ink60);margin:9px 0 0;max-width:78ch}

h2{font-family:var(--disp);text-transform:uppercase;font-size:22px;
 letter-spacing:.04em;font-weight:600;margin:34px 0 6px;display:flex;align-items:baseline;gap:12px}
h2::after{content:"";flex:1;height:1px;background:var(--rule)}
h2:first-child{margin-top:0}
.note{font-size:13.5px;color:var(--ink60);margin:0 0 16px;max-width:80ch}
.mono{font-family:var(--mono)}
.hidden{display:none!important}

/* -------------------------------------------------------------- controls */
.bar{border:1px solid var(--rule);background:var(--card);padding:14px 16px;
 display:flex;flex-wrap:wrap;gap:13px;align-items:center;margin-bottom:18px}
/* A note that sits in a bar is one of its items, not a paragraph under it. */
.bar .note{margin:0}
td .note{margin:2px 0 0;font-size:12px}
/* The schematic canvas, framed. Fixed height because the Angular app fills
 * whatever it is given and the page under it still has a list to show. */
iframe.canvas{width:100%;height:620px;border:1px solid var(--rule);background:#fff;display:block}
input[type=search],input[type=text],input[type=number],input[type=date],select,textarea{
 font-family:var(--body);font-size:14.5px;padding:8px 10px;border:1px solid var(--rule);
 background:#fff;min-width:0}
input[type=search]{flex:1;min-width:220px}
textarea{width:100%;resize:vertical}
.seg{display:flex;border:1px solid var(--ink)}
.seg button{font-family:var(--mono);font-size:10.5px;letter-spacing:.1em;
 text-transform:uppercase;padding:8px 13px;border:0;background:transparent;cursor:pointer}
.seg button+button{border-left:1px solid var(--ink)}
.seg button[aria-pressed=true]{background:var(--ink);color:var(--film)}
.btn{font-family:var(--mono);font-size:10.5px;letter-spacing:.1em;text-transform:uppercase;
 padding:9px 15px;border:1px solid var(--ink);background:var(--ink);color:var(--film);cursor:pointer}
/* A link styled as a button reads as one: no underline, same box. */
a.btn{text-decoration:none;display:inline-block}
.btn.ghost{background:transparent;color:var(--ink)}
.btn.danger{background:var(--red);border-color:var(--red);color:#fff}
/* Available, not offered. For an action that is occasionally necessary and
 * usually not what you want — it should not read as a peer of the buttons
 * beside it, and it should cost a deliberate look to find. */
.btn.quiet{background:transparent;border-color:transparent;color:var(--ink60);
 padding-left:0;padding-right:0;text-decoration:underline;
 text-decoration-color:var(--rule);text-underline-offset:3px}
.btn.quiet:hover{color:var(--red);text-decoration-color:var(--red)}
.btn:disabled{opacity:.4;cursor:default}
label.fld{display:flex;flex-direction:column;gap:5px;font-family:var(--mono);
 font-size:9.5px;letter-spacing:.09em;text-transform:uppercase;color:var(--ink60)}

/* the pricing picker's selection tray — a working set being assembled, so it
   is bordered in ink to sit above the search results rather than beside them */
.picked{border:1px solid var(--ink);background:var(--card);margin-bottom:18px}
.picked>.bar{border:0;border-top:1px solid var(--rule2);margin:0}
.picked>.bar input[type=text]{flex:1;min-width:240px}
.pickhead{display:flex;flex-wrap:wrap;gap:6px 18px;align-items:baseline;
 padding:13px 16px 11px;border-bottom:1px solid var(--rule2)}
.pickhead h3{font-family:var(--disp);font-size:20px;text-transform:uppercase;
 letter-spacing:.02em;margin:0}
.pickhead .note{max-width:none}
/* Sets an action apart from the group it would otherwise read as part of. */
.pickhead .pushright{margin-left:auto}
.pickhead b{color:var(--amber);font-weight:600}
.picked .wrapx{padding:0 4px}
input.qty{width:64px;padding:5px 7px;text-align:right}
/* A percentage the budget is built on — margin, PM, freight, contingency.
   Labelled inline rather than in a column header, because these four sit in a
   bar together and a bare number box beside three others says nothing. */
label.pct{display:inline-flex;align-items:center;gap:7px;font-family:var(--mono);
 font-size:10.5px;letter-spacing:.09em;text-transform:uppercase;color:var(--ink60)}
label.pct input.qty{width:58px}
/* The budget sits inside the selection tray, so its sub-headings step down
   from the tray's own title rather than competing with it. */
.picked>h3{font-family:var(--disp);font-size:15px;text-transform:uppercase;
 letter-spacing:.05em;color:var(--ink60);margin:16px 0 0;padding:0 16px}
/* The select column is a checkbox, not data — keep it out of the eye line. */
.t td:has(>input[type=checkbox]),.t th:first-child:empty{width:28px}

/* sliders — the sightlines tool leans on these */
.slider{display:grid;grid-template-columns:1fr auto;gap:4px 12px;align-items:center;
 margin-bottom:14px}
.slider .lab{font-family:var(--mono);font-size:9.5px;letter-spacing:.09em;
 text-transform:uppercase;color:var(--ink60)}
.slider .val{font-family:var(--mono);font-size:13px;text-align:right;white-space:nowrap}
.slider input[type=range]{grid-column:1/-1;width:100%;accent-color:var(--blue);margin:0}

/* ------------------------------------------------------------------ kpis */
.kpis{display:grid;grid-template-columns:repeat(auto-fit,minmax(140px,1fr));gap:1px;
 background:var(--rule);border:1px solid var(--rule);margin:0 0 22px}
.kpi{background:var(--card);padding:13px 14px 11px}
.kpi .v{font-family:var(--disp);font-size:36px;font-weight:600;line-height:1}
.kpi .v small{font-size:16px;font-weight:400;color:var(--ink60)}
.kpi .l{font-family:var(--mono);font-size:9.5px;letter-spacing:.1em;
 text-transform:uppercase;color:var(--ink60);margin-top:5px;line-height:1.5}
.kpi.hot .v{color:var(--amber)}.kpi.bad .v{color:var(--red)}.kpi.ok .v{color:var(--teal)}

/* ---------------------------------------------------------------- tables */
table.t{width:100%;border-collapse:collapse}
table.t th{text-align:left;font-family:var(--mono);font-size:9.5px;letter-spacing:.11em;
 text-transform:uppercase;color:var(--ink60);font-weight:400;padding:0 10px 7px 0;
 border-bottom:1px solid var(--rule);white-space:nowrap}
table.t td{padding:9px 10px 9px 0;border-bottom:1px solid var(--rule2);
 font-size:13.5px;vertical-align:top}
table.t tr.click{cursor:pointer}
table.t tr.click:hover td{background:rgba(43,76,126,.06)}
/* A quote's document section: its include tick on the left, outside the fold */
.qsec{display:flex;gap:10px;align-items:flex-start;border-bottom:1px solid var(--rule);padding:8px 0}
.qsec>input[type=checkbox]{margin:3px 0 0;flex:none;width:16px;height:16px;cursor:pointer}
.qsec>details{flex:1;min-width:0}
.qsec>details>summary{cursor:pointer}
/* A row being edited, and the form opened directly beneath it */
table.t tr.editing td{background:rgba(43,76,126,.12)}
table.t tr.editing td:first-child{box-shadow:inset 3px 0 0 var(--blue)}
table.t tr.editrow>td{padding:0;box-shadow:inset 3px 0 0 var(--blue)}
table.t tr.editrow .panel{margin:0}
td.num,th.num{font-family:var(--mono);font-size:12.5px;text-align:right;white-space:nowrap}
/* `table.t th` above sets text-align:left and is *more specific* — (0,1,2)
 * against `th.num`'s (0,1,1) — so it won regardless of source order, and every
 * numeric column header in the intranet sat hard left while its figures sat
 * hard right. On a wide table that reads as the header belonging to a
 * different column: three narrow PO columns side by side on the FHA day strip
 * is where it finally became obvious, but it was true of every `num: true`
 * column `ui.js` has ever drawn. Raising the selector rather than reordering,
 * because reordering would leave the next person to rediscover the same trap. */
table.t th.num{text-align:right}
.wrapx{overflow-x:auto}

/* A roll-up row that opens onto its own detail table — used where a summary is
   the answer and the full inventory behind it is only occasionally wanted. */
.rolls{margin:14px 0 16px;border:1px solid var(--rule);background:var(--card)}
.roll+.roll{border-top:1px solid var(--rule)}
.roll>summary{font-family:var(--mono);font-size:10.5px;letter-spacing:.1em;
 text-transform:uppercase;padding:11px 16px;cursor:pointer;color:var(--ink60)}
.roll>summary:hover{color:var(--ink);background:rgba(43,76,126,.06)}
.roll[open]>summary{color:var(--ink);border-bottom:1px solid var(--rule2)}
.roll>.wrapx{padding:0 16px 14px}

/* A quote's blended margin: big, and coloured by the band _quote.py gives it
   (config.json quoting.margin_bands). No band: grey, and the note says why. */
.mbadge{border:1px solid var(--rule);background:#fff;padding:14px 16px 12px;margin:2px 0 16px;text-align:center}
.mbadge .v{font-family:var(--disp);font-size:52px;font-weight:700;line-height:1;color:var(--grey)}
.mbadge .l{font-family:var(--mono);font-size:10px;letter-spacing:.12em;text-transform:uppercase;margin-top:6px;color:var(--ink60)}
.mbadge .n{font-size:11.5px;color:var(--ink60);margin-top:4px}
.mbadge.good{background:#1E7B4F;border-color:#1E7B4F}
.mbadge.fair{background:#F2C230;border-color:#D9A800}
.mbadge.low{background:#B3261E;border-color:#B3261E}
.mbadge.good .v,.mbadge.low .v,.mbadge.good .l,.mbadge.low .l,.mbadge.good .n,.mbadge.low .n{color:#fff}
.mbadge.fair .v,.mbadge.fair .l,.mbadge.fair .n{color:#3A2E00}

.btn.small{padding:3px 8px;font-size:9.5px}

/* The pipeline board (wireframe: Pipeline). A column per stage, cards that drag
   between them; amber for a deal with no next action or gone quiet. */
.pboard{display:grid;grid-auto-flow:column;grid-auto-columns:minmax(230px,1fr);gap:12px;padding-bottom:6px;min-width:min-content}
.pcol{background:var(--card);border:1px solid var(--rule);padding:10px;display:flex;flex-direction:column;gap:8px;min-width:0}
.pcol.over{outline:2px dashed var(--blue);outline-offset:-4px}
.pcol>h4{margin:0;font-family:var(--mono);font-size:10px;letter-spacing:.12em;text-transform:uppercase;color:var(--ink60);
 font-weight:400;display:flex;justify-content:space-between}
.pcol>.tot{font-family:var(--mono);font-size:11.5px;color:var(--ink);margin:-4px 0 2px}
.pcard{background:#fff;border:1px solid var(--rule);padding:10px 11px;font-size:13px;display:flex;flex-direction:column;gap:5px}
.pcard.move{cursor:grab}.pcard.dragging{opacity:.5}
.pcard.ro{background:var(--card);border-style:dashed;cursor:not-allowed}   /* Jetbuilt's: read-only here */
.pcard.stale{border-color:var(--amber)}
.pcard .t1{font-weight:600;line-height:1.3}
.pcard .t2{color:var(--ink60);font-size:12px}
.pcard .row{display:flex;flex-wrap:wrap;gap:6px;align-items:center}
.pcard .mono{font-family:var(--mono);font-size:12px}
.pcard .na{border-top:1px dashed var(--rule);padding-top:6px;font-size:12px}
.pcard .na b{font-family:var(--mono);font-size:9px;letter-spacing:.1em;text-transform:uppercase;color:var(--ink60);font-weight:400;display:block}
.pcard .na .none{color:var(--red)}

/* Quote defaults: Parts and Shipping read as a sentence, labour as a small
   table of rate and cost per hour under each currency. */
.qdef>summary .sum{text-transform:none;letter-spacing:0;font-family:var(--body);font-size:13px}
.qdef>.body{padding:4px 16px 14px}
.qdef h4{font-family:var(--mono);font-size:9.5px;letter-spacing:.11em;text-transform:uppercase;
 color:var(--ink60);font-weight:400;margin:14px 0 8px}
.qdef .factors{display:flex;flex-wrap:wrap;gap:10px 36px}
.qdef .factor{display:flex;align-items:center;gap:8px;font-size:14px}
.qdef .factor b{min-width:64px}
.qdef .factor input{width:76px;text-align:right}
.qdef table.t{width:auto;min-width:min(100%,560px)}
.qdef table.t th.cur{text-align:center;padding-right:0}
.qdef table.t td{vertical-align:middle;padding:5px 12px 5px 0}
.qdef table.t td.num input{width:100px;text-align:right;padding:5px 8px}
.qdef table.t td:first-child{padding-right:24px}
.qdef .unset{color:var(--grey)}
.qdef .bar,.qdef>.body>p.note{margin-top:12px}

.tag{font-family:var(--mono);font-size:9.5px;letter-spacing:.09em;text-transform:uppercase;
 border:1px solid var(--rule);padding:2px 6px;white-space:nowrap;color:var(--ink60);display:inline-block}
.tag.on{border-color:var(--teal);color:var(--teal)}
.tag.off{border-color:var(--rule);color:var(--grey)}
.tag.warn{border-color:var(--amber);color:var(--amber)}
.tag.bad{border-color:var(--red);color:var(--red)}

/* ---------------------------------------------------------------- panels */
.panel{border:1px solid var(--rule);background:var(--card);padding:16px 18px;margin-bottom:16px}
.panel.warn{border-left:3px solid var(--amber)}
.panel.bad{border-left:3px solid var(--red)}
.panel.ok{border-left:3px solid var(--teal)}
.panel h3{font-family:var(--disp);font-size:20px;text-transform:uppercase;
 letter-spacing:.03em;margin:0 0 8px}
.panel p{margin:0 0 10px;font-size:13.5px}
.panel p:last-child,.panel ul:last-child{margin-bottom:0}
.panel ul{margin:0 0 10px;padding-left:20px;font-size:13.5px}
.panel li{margin-bottom:5px}
pre.cmd{font-family:var(--mono);font-size:12px;background:var(--ink);color:var(--film);
 padding:11px 13px;margin:0 0 10px;overflow-x:auto}

/* A composed email, shown as it will read. Body type rather than mono and
 * wrapped rather than scrolled: it is prose to be checked before it is sent,
 * not a command to be copied exactly, and mono makes an email look like
 * output. `white-space:pre-wrap` keeps the paragraphing it was written with. */
pre.draft{font:inherit;font-size:13px;line-height:1.5;background:var(--card);
 border:1px solid var(--rule2);border-left:3px solid var(--ink60);
 padding:12px 14px;margin:10px 0 0;white-space:pre-wrap;word-break:break-word}

dl.kv{margin:0;display:grid;grid-template-columns:minmax(110px,auto) 1fr;gap:5px 14px;font-size:13px}
dl.kv dt{font-family:var(--mono);font-size:9.5px;letter-spacing:.09em;
 text-transform:uppercase;color:var(--ink60);padding-top:3px}
dl.kv dd{margin:0;word-break:break-word}

/* ----------------------------------------------------------------- tiles */
.tiles{display:grid;grid-template-columns:repeat(auto-fill,minmax(230px,1fr));gap:1px;
 background:var(--rule);border:1px solid var(--rule)}
.tile{background:var(--card);padding:15px 16px 14px;text-decoration:none;color:inherit;display:block}
.tile:hover{background:#fff}
.tile .g{font-family:var(--mono);font-size:9px;letter-spacing:.14em;
 text-transform:uppercase;color:var(--ink60)}
.tile .n{font-family:var(--disp);font-size:24px;text-transform:uppercase;
 letter-spacing:.02em;margin:5px 0 4px;line-height:1}
.tile .b{font-size:12.5px;color:var(--ink60);line-height:1.45}
.tile .st{margin-top:9px}

/* --------------------------------------------------------------- meters */
.meter{height:9px;background:#fff;border:1px solid var(--rule);position:relative;margin:6px 0 4px}
.meter i{display:block;height:100%;background:var(--teal)}
.meter.over i{background:var(--red)}
.meter b{position:absolute;top:-3px;bottom:-3px;width:1px;background:var(--ink)}

/* -------------------------------------------------------- column charts */
/* Months against an agreed ceiling. Thin marks and a hairline baseline, in
   keeping with everything else here: the only saturated colour is a month that
   needs an answer, so that is what the eye should land on first. */
.bars{margin:2px 0 4px}
.bars .plot{position:relative;height:170px;border-bottom:1px solid var(--rule)}
.bars .cols{position:absolute;inset:0;display:flex;gap:2px;align-items:flex-end}
.bars .col{flex:1 1 0;min-width:0;height:100%;display:flex;flex-direction:column;
 justify-content:flex-end;align-items:center}
.bars .f{width:58%;max-width:34px;background:var(--grey);border-radius:4px 4px 0 0}
.bars .f.ok{background:var(--teal)}
.bars .f.warn{background:var(--amber)}
.bars .f.bad{background:var(--red)}
/* The month in progress is hatched. A half-height bar for a month that is only
   half over must not read as a finished quiet month. */
.bars .f.part{background-image:repeating-linear-gradient(45deg,
 rgba(243,246,248,.60) 0 3px,transparent 3px 6px)}
.bars .n{font-family:var(--mono);font-size:10px;line-height:1;color:var(--ink60);
 margin-bottom:3px;white-space:nowrap}
.bars .col:hover .n{color:var(--ink)}
.bars .n.un{color:var(--rule)}
/* The one dashed rule in the stylesheet, because this one really is a
   threshold. Gridlines elsewhere stay solid so they never read as one. */
.bars .ceil{position:absolute;left:0;right:0;border-top:1px dashed var(--ink);
 pointer-events:none}
.bars .ceil span{position:absolute;right:0;top:-14px;padding:0 4px;
 background:var(--card);font-family:var(--mono);font-size:9px;
 letter-spacing:.09em;text-transform:uppercase;color:var(--ink)}
/* Where the terms changed: the first month the ceiling actually applies to. */
.bars .col.starts{box-shadow:inset 1px 0 0 var(--rule)}
.bars .axis{display:flex;gap:2px;margin-top:5px}
.bars .axis span{flex:1 1 0;min-width:0;overflow:hidden;text-align:center;
 font-family:var(--mono);font-size:9px;letter-spacing:.06em;text-transform:uppercase;
 color:var(--ink60);white-space:nowrap}

/* ------------------------------------------------------------- room view */
.roomview{background:#fff;border:1px solid var(--rule);display:block;width:100%;height:auto}
.roomview .wall{fill:none;stroke:var(--ink);stroke-width:2}
.roomview .screen{fill:var(--ink)}
.roomview .cone{fill:rgba(43,76,126,.10);stroke:none}
.roomview .seat{fill:var(--card);stroke:var(--ink60)}
.roomview .dim{stroke:var(--rule);stroke-width:1;stroke-dasharray:3 3}
.roomview text{font-family:var(--mono);font-size:9px;fill:var(--ink60)}
.roomview text.ok{fill:var(--teal)}
.roomview text.bad{fill:var(--red)}

/* ------------------------------------------------------------ misc state */
.loading,.empty{font-family:var(--mono);font-size:11px;letter-spacing:.12em;
 text-transform:uppercase;color:var(--ink60);padding:26px 0}
.err{border:1px solid var(--red);border-left:3px solid var(--red);background:#fff;
 padding:14px 16px;margin-bottom:16px;font-size:13.5px}
.err b{font-family:var(--mono);font-size:10px;letter-spacing:.1em;
 text-transform:uppercase;display:block;margin-bottom:5px;color:var(--red)}
.grid2{display:grid;grid-template-columns:1fr 1fr;gap:20px;align-items:start}
.grid-side{display:grid;grid-template-columns:1fr 320px;gap:22px;align-items:start}

@media (max-width:960px){
  #app{grid-template-columns:1fr}
  aside.rail{position:static;height:auto}
  /* Stacked above the content rather than beside it, so "hidden" has to mean
     gone — a zero-width column does nothing to a single-column grid. */
  .railhid aside.rail{display:none}
  .railtoggle,.railhid .railtoggle{left:auto;right:12px;top:12px}
  main{padding:20px 18px 70px}
  .grid2,.grid-side{grid-template-columns:1fr}
}

/* ------------------------------------------------- Division 27 authoring
 * The spec editor and its history. A specification is
 * read by number, so the number is what the layout gives room to: a fixed
 * label gutter that every level shares, with the text block stepping in
 * beside it. That is the geometry of a printed spec page and it is the whole
 * reason a clause is scannable.                                            */
.spec{border:1px solid var(--rule);background:#fff}
.spec .cl{display:grid;grid-template-columns:88px 1fr auto;gap:10px;
 padding:5px 12px;border-bottom:1px solid var(--rule2);align-items:start}
.spec .cl:hover{background:rgba(43,76,126,.04)}
.spec .cl.l1{background:var(--ink);color:var(--film);border-bottom:0;margin-top:2px}
.spec .cl.l1 .n,.spec .cl.l1 .tx{font-family:var(--disp);font-size:17px;
 text-transform:uppercase;letter-spacing:.02em}
.spec .cl.l2{background:var(--card)}
.spec .cl.l2 .tx{font-weight:600}
.spec .n{font-family:var(--mono);font-size:11px;color:var(--ink60);padding-top:3px;
 white-space:nowrap}
.spec .cl.l1 .n{color:#93A6B3}
.spec .tx{font-size:13.5px;line-height:1.5;min-height:20px;white-space:pre-wrap;
 border:1px solid transparent;padding:2px 4px;margin:-2px -4px;border-radius:2px}
.spec .tx:focus{outline:0;border-color:var(--blue);background:#fff}
.spec .tx:empty::before{content:'—';color:var(--rule)}
.spec .cl[data-lvl="3"] .tx{margin-left:0}
.spec .cl[data-lvl="4"]{padding-left:30px}
.spec .cl[data-lvl="5"]{padding-left:52px}
.spec .cl[data-lvl="6"]{padding-left:74px}
.spec .cl[data-lvl="7"]{padding-left:96px}
.spec .ops{display:flex;gap:3px;opacity:0;transition:opacity .1s}
.spec .cl:hover .ops,.spec .cl:focus-within .ops{opacity:1}
.spec .ops button{font-family:var(--mono);font-size:10px;line-height:1;padding:3px 5px;
 background:transparent;border:1px solid var(--rule);color:var(--ink60);cursor:pointer}
.spec .ops button:hover{background:var(--ink);color:var(--film);border-color:var(--ink)}

/* History and diffs. Additions and removals are never colour alone — the sign
 * in the gutter carries the meaning for anyone who cannot separate the two. */
.hist{font-family:var(--mono);font-size:10.5px}
.hist .r{display:flex;gap:9px;padding:5px 0;border-bottom:1px solid var(--rule2);
 align-items:baseline;cursor:pointer}
.hist .r:hover{background:rgba(43,76,126,.05)}
.hist .who{text-transform:uppercase;letter-spacing:.08em;flex:0 0 62px}
.hist .who.assistant{color:var(--amber)}
.hist .who.import{color:var(--blue)}
.hist .when{color:var(--ink60);margin-left:auto;white-space:nowrap}
.dif .d{border-left:3px solid var(--rule);padding:6px 10px;margin:6px 0;background:var(--card)}
.dif .d.added{border-left-color:var(--teal)}
.dif .d.removed{border-left-color:var(--red)}
.dif .d.changed{border-left-color:var(--amber)}
.dif .lab{font-family:var(--mono);font-size:10px;letter-spacing:.08em;
 text-transform:uppercase;color:var(--ink60)}
.dif .was{color:var(--red);text-decoration:line-through;font-size:12.5px}
.dif .now{color:var(--teal);font-size:12.5px}
.dif .was::before{content:'− '}
.dif .now::before{content:'+ '}

/* Cross-check findings. Severity is a word, not just a colour. */
.find{border:1px solid var(--rule);background:#fff}
.find .f{display:grid;grid-template-columns:96px 118px 1fr;gap:12px;padding:8px 12px;
 border-bottom:1px solid var(--rule2);font-size:13px;align-items:baseline}
.find .f:last-child{border-bottom:0}
.find .sv{font-family:var(--mono);font-size:9.5px;letter-spacing:.11em;
 text-transform:uppercase}
.find .sv.conflict{color:var(--red)}
.find .sv.gap{color:var(--amber)}
.find .sv.note{color:var(--ink60)}
.find .rf{font-family:var(--mono);font-size:11.5px}

/* The similarity report. Ours above theirs, always in that order — the
 * question is what our clause borrowed, not how alike two documents are. */
.sim .h{border:1px solid var(--rule);background:#fff;margin-bottom:10px}
.sim .sc{display:flex;gap:12px;align-items:baseline;padding:7px 12px;
 background:var(--card);border-bottom:1px solid var(--rule2);
 font-family:var(--mono);font-size:10.5px;letter-spacing:.06em;text-transform:uppercase}
.sim .sc b{font-size:14px;letter-spacing:0}
.sim .sc.hot b{color:var(--red)}
.sim .p{padding:8px 12px;font-size:13px;line-height:1.5}
.sim .p+.p{border-top:1px dashed var(--rule2);color:var(--ink60)}
.sim .p .lab{font-family:var(--mono);font-size:9.5px;letter-spacing:.12em;
 text-transform:uppercase;color:var(--ink60);display:block;margin-bottom:3px}

/* A clause still carrying the precedent's own words. Marked in the gutter, not
 * by colour alone — the amber rule is the signal for anyone who cannot separate
 * it from the ink. The badge beside the number is the label it had in their
 * document, which is what makes a side-by-side read possible. */
/* Review state. A different axis from `.borrowed`: that asks whose words these
 * are, this asks whether anyone has read them here yet. Only real clauses get
 * it — a PART or an article heading is furniture and colouring it would swamp
 * the page. The left border differs in weight as well as hue, and the legend
 * above the list names each state, so the three are never colour alone.
 * `.borrowed` is declared after these and wins, because somebody else's
 * sentence still sitting in the document is the more serious fact. */
.spec .cl.l3.rv-asis{border-left:3px solid var(--amber);background:rgba(200,121,26,.05)}
.spec .cl.l3.rv-asis .n{color:var(--amber)}
/* Read and kept, versus read and changed. Both are done, so both are teal;
 * the dashed edge says the words are still the imported ones, which matters
 * when you come back and want to know whether you wrote that sentence. */
.spec .cl.l3.rv-accepted{border-left:3px dashed var(--teal)}
.spec .cl.l3.rv-accepted .n{color:var(--teal)}
.spec .cl.l3.rv-edited{border-left:3px solid var(--teal)}
.spec .cl.l3.rv-edited .n{color:var(--teal)}
.spec .cl.l3.rv-new{border-left:3px dotted var(--blue)}
.spec .cl.l3.rv-new .n{color:var(--blue)}

/* Unsaved. The row keeps its review colour and gains a rule down the right,
 * so "not written down yet" reads separately from "not reviewed yet". */
.spec .cl.dirty{box-shadow:inset -3px 0 0 var(--red);background:rgba(158,43,37,.04)}
.spec .cl.justsaved{background:rgba(28,106,94,.10);transition:background .5s}

.spec .ops .save{display:none;font-family:var(--mono);font-size:10px;
 letter-spacing:.06em;white-space:nowrap;border-color:var(--rule)}
.spec .cl:hover .ops .save,
.spec .cl:focus-within .ops .save{display:inline-block}
/* "Keep as-is" is an ordinary, frequent act, so it stays quiet. */
.spec .cl .ops .save.accept{color:var(--teal);border-color:var(--rule)}
.spec .cl .ops .save.accept:hover{background:var(--teal);color:var(--film);
 border-color:var(--teal)}
/* Unsaved text is the one state that should nag. */
.spec .cl.dirty .ops{opacity:1}
.spec .cl.dirty .ops .save{display:inline-block;border-color:var(--red);
 color:var(--red);font-weight:600}
.spec .cl.dirty .ops .save:hover{background:var(--red);color:var(--film);
 border-color:var(--red)}
/* A clause that is already done needs no accept button. */
.spec .cl.rv-accepted .ops .save.accept,
.spec .cl.rv-edited .ops .save.accept,
.spec .cl.rv-new .ops .save.accept{display:none}

/* Register column: how much of a section is still untouched. */
.warnnum{color:var(--amber);font-weight:600}
.oknum{color:var(--teal)}

/* The legend and progress above the clause list. */
.rvbar{border:1px solid var(--rule);border-left:3px solid var(--amber);
 background:var(--card);padding:10px 13px;margin:10px 0 2px}
.rvbar .rvsum{font-size:12.5px;margin-bottom:7px}
.rvlegend{display:flex;flex-wrap:wrap;gap:16px;margin-top:8px;
 font-family:var(--mono);font-size:9.5px;letter-spacing:.08em;
 text-transform:uppercase;color:var(--ink60)}
.rvkey{display:inline-flex;align-items:center;gap:6px}
.rvkey i{width:11px;height:11px;border-left:3px solid var(--rule);
 background:var(--paper);display:inline-block}
.rvkey.rv-asis i{border-left-color:var(--amber);background:rgba(200,121,26,.10)}
.rvkey.rv-accepted i{border-left:3px dashed var(--teal)}
.rvkey.rv-edited i{border-left-color:var(--teal)}
.rvkey.rv-new i{border-left:3px dotted var(--blue)}

.spec .cl.borrowed{border-left:3px solid var(--amber);background:rgba(200,121,26,.045)}
.spec .cl.borrowed .n{color:var(--amber)}
.spec .n .was{display:block;font-size:9px;letter-spacing:.06em;color:var(--ink60);
 opacity:.75;margin-top:2px}

/* The chamber camera. A dark ground because the picture is a dimly lit box and
 * a pale card around it reads as a blown-out image, and a fixed aspect so the
 * frame does not jump between the placeholder, the picture and the offline
 * notice — three states one panel cycles through while you watch it. */
.cam{border:1px solid var(--rule);background:#16212B;aspect-ratio:16/10;
 display:flex;align-items:center;justify-content:center;overflow:hidden}
.cam img{width:100%;height:100%;object-fit:contain;display:block}
.cam .wait{font-family:var(--mono);font-size:10.5px;letter-spacing:.1em;
 text-transform:uppercase;color:#93A6B3}
.cam .panel{background:var(--card);margin:0;max-width:520px}

/* A wall of cameras. Tiles are wide rather than tall because that is the shape
 * a camera sees in, and the grid is auto-fill so three cameras fill the row and
 * eight wrap without anyone choosing a breakpoint. */
.camwall{display:grid;grid-template-columns:repeat(auto-fill,minmax(320px,1fr));
 gap:14px;margin-bottom:16px}
.camtile{border:1px solid var(--rule);background:var(--card)}
.camtile .h{display:flex;gap:10px;align-items:baseline;flex-wrap:wrap;
 padding:9px 12px;border-bottom:1px solid var(--rule2)}
.camtile .h b{font-family:var(--disp);font-size:17px;text-transform:uppercase;
 letter-spacing:.01em}
.camtile .cam{border:0;aspect-ratio:16/9}

/* Lighting. One row per load: name and state on the left, the level, then the
 * control. The level sits in its own column so a column of them lines up and
 * the room can be read down the page without chasing numbers across rows. */
.lights{border:1px solid var(--rule);background:var(--card);margin-bottom:18px}
.light{display:grid;grid-template-columns:1fr auto minmax(140px,240px);
 gap:10px 16px;align-items:center;padding:10px 14px}
.light+.light{border-top:1px solid var(--rule2)}
.light .n{display:flex;gap:10px;align-items:baseline;flex-wrap:wrap;min-width:0}
.light .n b{font-family:var(--disp);font-size:18px;text-transform:uppercase}
.light .lv{font-family:var(--mono);font-size:13px;color:var(--ink60);
 text-align:right;min-width:44px}
.light .dim input[type=range]{width:100%;accent-color:var(--amber);margin:0;
 display:block}
.light .seg{justify-self:end}
@media (max-width:640px){
  .light{grid-template-columns:1fr auto}
  .light .dim,.light .seg{grid-column:1/-1;justify-self:stretch}
}

/* The player. Cover on the left at a fixed square, everything else in a column
 * beside it — the layout every music player has converged on, because the cover
 * is the thing you recognise from across the room. */
.player{display:grid;grid-template-columns:minmax(180px,300px) 1fr;gap:22px;
 border:1px solid var(--rule);background:var(--card);padding:18px}
.player .art{aspect-ratio:1;background:#16212B;overflow:hidden}
.player .cover{width:100%;height:100%;object-fit:cover;display:block}
.player .noart{width:100%;height:100%;display:flex;align-items:center;
 justify-content:center;font-size:52px;color:#3D5163}
.player .now{min-width:0;display:flex;flex-direction:column;gap:12px}
.player .meta h2{font-family:var(--disp);font-size:32px;line-height:1.05;
 text-transform:uppercase;margin:0}
.player .artist{font-size:16px;color:var(--ink);margin-top:4px}
.player .album{font-size:13.5px;color:var(--ink60);margin-top:2px}
.player .times{display:grid;grid-template-columns:auto 1fr auto;gap:10px;
 align-items:center;font-size:11.5px;color:var(--ink60)}
.player .pbar{height:4px;background:var(--rule2);position:relative}
.player .pbar i{display:block;height:100%;background:var(--amber);width:0}
.player .transport{display:flex;gap:8px;flex-wrap:wrap}
.player .transport .btn{min-width:64px}
.player .slider{margin:0}
@media (max-width:700px){ .player{grid-template-columns:1fr} }

/* RCH PH3 — the three-state scope control. It sits in a table cell on 900 rows,
   so it is the segmented control at the size a cell can carry rather than a new
   widget: the same shape means the same thing everywhere in the section. */
.t .seg{display:inline-flex;white-space:nowrap}
.t .seg button{padding:3px 8px;font-size:9px;letter-spacing:.06em}
/* Filters wrap onto their own line above a long table; the labels are the
   same .fld as everywhere else, only laid out across instead of down. */
.pickhead label.fld{flex-direction:row;align-items:center;gap:7px}
.pickhead label.fld select,.pickhead label.fld input{margin:0}

/* A cell that opens a record. Not a <a href> — there is no URL to go to, the
   panel opens in place — so it carries the affordance without the navigation. */
a.lnk{color:var(--blue);cursor:pointer;text-decoration:underline;
 text-underline-offset:2px;text-decoration-thickness:1px}
a.lnk:hover{color:var(--ink)}
/* The opened record sits above the table it came from, bordered in ink so it
   reads as the thing in focus rather than as another row. */
.rec{border:1px solid var(--ink);background:var(--card);margin:0 0 18px}
.rec>.pickhead{border-bottom:1px solid var(--rule2)}
.rec .bodytext{white-space:pre-wrap;font-size:13.5px;padding:2px 16px 14px;
 max-width:90ch}
.rec .thread{padding:0 16px 14px}
.rec .thread .c{border-top:1px solid var(--rule2);padding:9px 0}
.rec .thread .c:first-child{border-top:0}
.rec .thread .by{font-family:var(--mono);font-size:9.5px;letter-spacing:.09em;
 text-transform:uppercase;color:var(--ink60);margin-bottom:4px}
.rec .thread .tx{font-size:13px;white-space:pre-wrap}

/* ------------------------------------------------------------- calendar
 * Three overlaid calendars, the family's standing jobs, and what to do next.
 *
 * The colour of an event is the only thing on this page allowed to be
 * decorative, and it is not really decorative either: it is which of the three
 * mailboxes the event came from, which is the whole question the section
 * exists to answer. Each source names a palette variable in config.json rather
 * than a hex value, so the calendar cannot drift away from the rest of the
 * intranet — .c-teal, .c-blue, .c-amber, .c-red, .c-grey are the whole range,
 * and a fourth calendar picks up the next one automatically.
 *
 * Events are drawn as tinted blocks with a saturated left edge rather than
 * solid fills. A week with forty solid colour blocks is unreadable, and this
 * keeps the page a document with marks on it, like everything else here. */
.c-teal{--cc:var(--teal)} .c-blue{--cc:var(--blue)} .c-amber{--cc:var(--amber)}
.c-red{--cc:var(--red)} .c-grey{--cc:var(--grey)}

.calbar{display:flex;flex-wrap:wrap;gap:12px 18px;align-items:center;
 justify-content:space-between;margin-bottom:12px}
.calnav{display:flex;gap:8px;align-items:center}
.calnav .btn{padding:8px 12px}
.calnav h2{font-family:var(--disp);font-size:26px;text-transform:uppercase;
 letter-spacing:.02em;margin:0 0 0 8px;line-height:1}
.calacts{display:flex;gap:10px;align-items:center;flex-wrap:wrap}
.calacts .btn[aria-pressed=true]{background:var(--ink);color:var(--film)}

.callegend{display:flex;flex-wrap:wrap;gap:8px 14px;align-items:center;
 margin-bottom:14px;padding-bottom:12px;border-bottom:1px solid var(--rule2)}
.calchip{display:inline-flex;gap:7px;align-items:center;cursor:pointer;
 background:transparent;border:1px solid var(--rule);padding:5px 10px;
 font-family:var(--mono);font-size:10.5px;letter-spacing:.06em;
 text-transform:uppercase;opacity:.45}
.calchip.on{opacity:1;border-color:var(--ink)}
.calchip i{width:11px;height:11px;background:var(--cc);flex:none}
.calchip em{font-style:normal;color:var(--ink60)}
.calchip em.bad{color:var(--red)}
.calstat{font-family:var(--mono);font-size:10px;letter-spacing:.05em;
 color:var(--ink60);text-transform:uppercase}

.calwrap{min-width:0;overflow-x:auto}
.grid-side.notasks{grid-template-columns:1fr}
/* Calendar put away: the rail takes the width and its two panels — the
 * family list and the tasks — sit side by side instead of stacked. */
.grid-side.nogrid{grid-template-columns:1fr}
.grid-side.nogrid .calrail{display:grid;grid-template-columns:1fr 1fr;gap:22px;
 align-items:start}
@media (max-width:960px){.grid-side.nogrid .calrail{grid-template-columns:1fr}}

/* ------------------------------------------------------------ month view */
.calmonth{border:1px solid var(--rule);background:var(--card);min-width:660px}
.calmonthhead{display:grid;grid-template-columns:repeat(7,1fr);
 border-bottom:1px solid var(--rule)}
.calmonthhead .dh{font-family:var(--mono);font-size:9.5px;letter-spacing:.12em;
 text-transform:uppercase;color:var(--ink60);padding:7px 8px;text-align:center}
.calmonthbody{display:grid;grid-template-columns:repeat(7,1fr);
 grid-auto-rows:minmax(96px,1fr);gap:1px;background:var(--rule2)}
.calmonth .cell{background:#fff;padding:5px 6px 7px;display:flex;
 flex-direction:column;gap:3px;cursor:pointer;min-width:0}
.calmonth .cell:hover{background:#FAFCFD}
.calmonth .cell.out{background:var(--card);color:var(--ink60)}
.calmonth .cell.hol{background:rgba(200,121,26,.07)}
.calmonth .cell.today{box-shadow:inset 0 0 0 2px var(--ink)}
.calmonth .dn{display:flex;gap:6px;align-items:baseline;
 font-family:var(--mono);font-size:11px;color:var(--ink60)}
.calmonth .cell.today .dn{color:var(--ink);font-weight:600}
.calmonth .holname{font-size:9px;letter-spacing:.06em;text-transform:uppercase;
 color:var(--amber);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.calmonth .more{font-family:var(--mono);font-size:9.5px;color:var(--ink60)}

/* An event as a one-line chip. Used in month cells and in the all-day strip. */
.calev{display:flex;gap:5px;align-items:baseline;font-size:11.5px;
 line-height:1.3;padding:2px 5px;background:color-mix(in srgb,var(--cc) 12%,#fff);
 border-left:3px solid var(--cc);overflow:hidden;white-space:nowrap;
 text-overflow:ellipsis;cursor:default}
.calev b{font-family:var(--mono);font-size:9.5px;color:var(--cc);flex:none}
.calev span{overflow:hidden;text-overflow:ellipsis}
.calev em{font-style:normal;color:var(--ink60);font-size:10px}
.calev.free{background:transparent;border-left-style:dotted}
/* A family task on the day it is owed. Dashed rather than solid, and in ink
 * rather than a calendar colour, because it is not an appointment: it came
 * from the rail, not from a mailbox. Overdue ones sit on today, in red. */
.calev.task{--cc:var(--ink);border-left-style:dashed;background:var(--card);
 align-items:center}
.calev.task.overdue{--cc:var(--red)}
.calev.task.ticked{opacity:.5}
.calev.task.ticked span{text-decoration:line-through}
.calev.task .tick{width:14px;height:14px;flex:none;border:1px solid var(--ink60);
 background:#fff;cursor:pointer;font-size:9px;line-height:1;padding:0}
.calev.task.ticked .tick{background:var(--teal);color:#fff;border-color:var(--teal)}

/* -------------------------------------------------------- week/day grid */
.calgrid{display:grid;grid-template-columns:56px 1fr;border:1px solid var(--rule);
 background:var(--card);min-width:660px}
.calgrid .hours{padding-top:58px;border-right:1px solid var(--rule2)}
.calgrid .hr{font-family:var(--mono);font-size:9.5px;color:var(--ink60);
 text-align:right;padding:2px 7px 0 0;border-top:1px solid var(--rule2)}
.calgrid .cols{display:grid;grid-auto-flow:column;grid-auto-columns:1fr;
 gap:1px;background:var(--rule2);min-width:0}
.calgrid .col{background:#fff;min-width:0;display:flex;flex-direction:column}
.calgrid .col.hol{background:rgba(200,121,26,.06)}
.calgrid .col.today{background:#FAFCFD;box-shadow:inset 0 0 0 2px var(--ink)}
.calgrid .colhead{padding:6px 8px 4px;border-bottom:1px solid var(--rule2);
 display:flex;flex-direction:column;gap:1px;min-height:34px}
.calgrid .colhead b{font-family:var(--mono);font-size:11px;letter-spacing:.06em;
 text-transform:uppercase}
.calgrid .colhead .holname{font-size:9px;letter-spacing:.05em;
 text-transform:uppercase;color:var(--amber);overflow:hidden;
 text-overflow:ellipsis;white-space:nowrap}
.calgrid .allday{display:flex;flex-direction:column;gap:2px;padding:3px 4px;
 border-bottom:1px solid var(--rule2);min-height:24px}
.calgrid .slots{position:relative}
.calgrid .slot{position:absolute;left:0;right:0;border-top:1px solid var(--rule2)}
.calgrid .now{position:absolute;left:0;right:0;height:2px;background:var(--red);
 z-index:3}
/* A block in the time grid. Absolute so overlapping events can share the
 * column width, which is what `lanes()` in calendar.js computes. */
.calevb{position:absolute;overflow:hidden;padding:2px 5px;z-index:2;
 background:color-mix(in srgb,var(--cc) 14%,#fff);
 border-left:3px solid var(--cc);border-top:1px solid #fff;
 font-size:11.5px;line-height:1.25;cursor:default}
.calevb b{display:block;font-weight:600;overflow:hidden;text-overflow:ellipsis}
.calevb i{display:block;font-style:normal;font-size:10px;color:var(--ink60);
 overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.calevb.free{background:transparent;border-left-style:dotted}
.calevb.tent{background:repeating-linear-gradient(135deg,
 color-mix(in srgb,var(--cc) 16%,#fff) 0 6px,transparent 6px 12px)}

/* ------------------------------------------------------------- day list
 * The family calendar's entries for one day, sorted into calls, online jobs
 * and places to be. Rows keep the calendar's colour bar so they read as the
 * same entries the grid draws, ticked or not. */
.calrail{display:flex;flex-direction:column;gap:18px;min-width:0}
.calrail>.panel{margin:0}
.dlhead{margin-bottom:4px}
.daylist h4{font-family:var(--mono);font-size:9.5px;letter-spacing:.12em;
 text-transform:uppercase;color:var(--ink60);margin:14px 0 6px}
.daylist h4:first-child{margin-top:8px}
.dl{display:grid;grid-template-columns:auto 58px 1fr auto;gap:9px;align-items:start;
 padding:6px 0 6px 7px;border-top:1px solid var(--rule2);border-left:3px solid var(--cc)}
/* Promote an entry to a family task. Quiet until the row is hovered: most
 * entries never need it, and a loud button on every row reads as a demand. */
.dl .totask{font-family:var(--mono);font-size:9px;letter-spacing:.08em;
 text-transform:uppercase;padding:4px 7px;border:1px solid var(--rule);
 background:#fff;color:var(--ink60);cursor:pointer;opacity:.55;white-space:nowrap}
.dl:hover .totask,.dl .totask:focus{opacity:1;color:var(--ink);border-color:var(--ink)}
.dl.done{opacity:.5}
.dl.done .dlb span{text-decoration:line-through}
.dl .tick{width:22px;height:22px;flex:none;border:1px solid var(--rule);
 background:#fff;cursor:pointer;font-size:12px;line-height:1;padding:0}
.dl.done .tick{background:var(--teal);color:#fff;border-color:var(--teal)}
.dl b{font-family:var(--mono);font-size:10px;color:var(--cc);padding-top:4px}
.dl .dlb{min-width:0}
.dl .dlb span{display:block;font-size:13px;line-height:1.35}
.dl .dlb em{display:block;font-style:normal;font-family:var(--mono);font-size:9.5px;
 letter-spacing:.04em;color:var(--ink60);margin-top:2px;overflow:hidden;
 text-overflow:ellipsis;white-space:nowrap}

/* ----------------------------------------------------------------- tasks */
.tasks h4{font-family:var(--mono);font-size:9.5px;letter-spacing:.12em;
 text-transform:uppercase;color:var(--ink60);margin:14px 0 6px}
.tasks h4:first-child{margin-top:8px}
.task{display:grid;grid-template-columns:auto 1fr auto;gap:9px;
 align-items:start;padding:7px 0;border-top:1px solid var(--rule2)}
.task.done{opacity:.5}
.task .tick{width:22px;height:22px;flex:none;border:1px solid var(--rule);
 background:#fff;cursor:pointer;font-size:12px;line-height:1;padding:0}
.task.done .tick{background:var(--teal);color:#fff;border-color:var(--teal)}
.task .tbody b{display:block;font-size:13.5px;font-weight:600;cursor:pointer}
.task .tbody b:hover{color:var(--blue)}
.task .tmeta{display:flex;flex-wrap:wrap;gap:4px 9px;align-items:baseline;
 font-family:var(--mono);font-size:9.5px;letter-spacing:.04em;
 text-transform:uppercase;color:var(--ink60);margin-top:3px}
.task .tdue{font-family:var(--mono);font-size:10px;color:var(--ink60);
 text-align:right;white-space:nowrap}
.task.overdue .tdue{color:var(--red)}
.task.today .tdue{color:var(--ink)}
.task .tfit{color:var(--teal)}
.task .tnotes{font-size:11.5px;color:var(--ink60);margin-top:2px}
/* Finished one-offs, folded away. They stay a month so a tick can be undone. */
.tasks details{margin-top:14px}
.tasks summary{font-family:var(--mono);font-size:9.5px;letter-spacing:.12em;
 text-transform:uppercase;color:var(--ink60);cursor:pointer;margin-bottom:6px}
.taskform textarea{border:1px solid var(--rule);background:#fff;padding:6px 8px;
 font-size:13px;min-height:52px}
.taskform input[type=date]{border:1px solid var(--rule);background:#fff;
 padding:5px 8px;font-size:13px;width:100%}
.taskform{border:1px solid var(--ink);background:#fff;padding:12px;margin:8px 0}
.taskform .row{display:flex;flex-wrap:wrap;gap:10px;align-items:flex-end;
 margin-top:9px}
.taskform label.fld{flex:1;min-width:88px}
.taskform input[type=text],.taskform input[type=number],.taskform select{
 border:1px solid var(--rule);background:#fff;padding:6px 8px;font-size:13px;width:100%}
.taskform input[type=checkbox]{width:auto}
.calhint{font-size:11.5px;color:var(--ink60);margin:9px 0 0;line-height:1.45}

/* --------------------------------------------------------------- collisions */
.calbottom{margin-top:20px}
.clash{border-top:1px solid var(--rule2);padding:9px 0}
.clash .ch{display:flex;gap:9px;align-items:baseline;flex-wrap:wrap;
 margin-bottom:5px}
.clash .ch b{font-family:var(--mono);font-size:10.5px;letter-spacing:.05em}
.clash .cx{display:flex;gap:8px;align-items:baseline;font-size:12.5px;
 padding:3px 7px;border-left:3px solid var(--cc);
 background:color-mix(in srgb,var(--cc) 9%,#fff);margin-bottom:2px}
.clash .cx b{font-family:var(--mono);font-size:10px;color:var(--cc);flex:none}
.clash .cx span{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.clash .cx em{font-style:normal;font-size:10px;color:var(--ink60);flex:none}

@media (max-width:960px){
  .calmonth,.calgrid{min-width:560px}
}

/* --------------------------------------------------------- calendar search
 * One box, and it narrows everything on the page at once: the grid dims what
 * does not match, the task rail filters, and a result list appears covering
 * the whole cached span rather than the visible week.
 *
 * Dimming rather than hiding is the decision worth recording. Removing the
 * non-matches would leave a Tuesday that looks empty, which is a claim about
 * Tuesday; fading them keeps the shape of the week intact and says only that
 * these are not what you asked for. */
.calfind{display:flex;gap:9px;align-items:center;flex-wrap:wrap;margin-bottom:12px}
.calq{flex:1;min-width:220px;max-width:440px;border:1px solid var(--rule);
 background:#fff;padding:8px 11px;font-size:13.5px}
.calq:focus{border-color:var(--ink);outline:none}
.calq::-webkit-search-cancel-button{display:none}

.calevb.dim,.calev.dim{opacity:.2}
.calevb.dim{z-index:1 !important}

.calfound .panel{margin-bottom:16px}
.calhits{display:flex;flex-direction:column;gap:2px;margin-top:8px}
.calhitday{font-family:var(--mono);font-size:9.5px;letter-spacing:.12em;
 text-transform:uppercase;color:var(--ink60);margin:9px 0 3px}
.calhit{display:flex;gap:9px;align-items:baseline;font-size:12.5px;
 padding:4px 8px;cursor:pointer;border-left:3px solid var(--cc);
 background:color-mix(in srgb,var(--cc) 9%,#fff)}
.calhit:hover{background:color-mix(in srgb,var(--cc) 18%,#fff)}
.calhit b{font-family:var(--mono);font-size:10px;color:var(--cc);flex:none;
 min-width:52px}
.calhit span{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.calhit em{font-style:normal;font-size:10px;color:var(--ink60);flex:none}
.calhit.task{--cc:var(--ink);cursor:default;background:var(--card)}
.calhit.task:hover{background:var(--card)}

.clash .cx{cursor:pointer}
.clash .cx:hover{background:color-mix(in srgb,var(--cc) 18%,#fff)}
.clash .during{font-family:var(--mono);font-size:9.5px;letter-spacing:.05em;
 text-transform:uppercase;color:var(--ink60);margin-top:4px}
.clash .during b{color:var(--ink);font-weight:600}
.clash .during b+b:before{content:', '}
/* Cap the result list so the grid stays on screen behind it. Searching is
 * meant to narrow the calendar you are looking at, not replace it — with an
 * uncapped list a common word pushes the week a thousand pixels down and the
 * dimming it applies to that week is never seen. */
.calhits{max-height:320px;overflow-y:auto}

/* A compact list inside a panel — the rescan's new candidates, one room a line. */
ul.tight{margin:4px 0 8px;padding-left:18px}
ul.tight li{margin:2px 0;line-height:1.45}

/* End Use Device team: scope, but another team's — blue, apart from AV teal and No grey. */
.tag.eud{border-color:var(--blue);color:var(--blue)}

