:root{
  --bg:#f6f7f9; --card:#fff; --ink:#1b2230; --muted:#6b7787; --line:#e2e6ec;

  /* Brand accent. --accent is the exact brand blue and is used wherever the
     colour is a SHAPE - button fills, borders, focus rings, chart strokes.
     It is not used for small text: #30A9DD on white measures 2.68:1, well under
     the 4.5:1 needed to read comfortably, and this is software people stare at
     all day. --accent-ink is the same hue darkened to 4.66:1 and carries every
     bit of coloured TEXT - links, outline-button labels, pill text. */
  --accent:#30A9DD;
  --accent-ink:#1F7CA8;
  --accent-hover:#2A97C6;
  --accent-soft:#E6F4FB;
  --accent-hint:#F2FAFD;   /* accent-soft taken 50% toward white; row hover */
  /* For SMALL blue text on --accent-soft. --accent-ink measures 4.15:1 there,
     which passes for the 15px bold date and fails for an 11px count - AA wants
     4.5:1 and only counts 14px bold as large. This is 5.0:1. */
  --accent-deep:#1B6E95;

  --warn:#b4690e; --warn-soft:#fdf3e3;
  --bad:#c0392b; --good:#1e7f52; --good-soft:#e7f5ee;

  /* Control heights, declared once because they cannot be derived. A native
     date input measures 41px, a time 41px, a number 40.25px and a plain text
     input 38.25px from identical padding - the picker sets its own intrinsic
     height - and buttons come out at 34.89px from line-height. Side by side on
     a toolbar that reads as five slightly broken controls. Set the box and
     stop guessing.
     There is ONE size. The day bar used to run a 30px scale of its own, which
     meant the same kind of control was a different height depending on which
     page you were looking at. --ctl is it; the offsets below exist only where a
     wrapper adds a border, so the OUTER box still lands on 38. */
  --ctl:38px;
}
*{box-sizing:border-box}
body{margin:0;background:var(--bg);color:var(--ink);
  font:14px/1.5 -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif}
.wrap{max-width:1180px;margin:0 auto;padding:0 22px}
main.wrap{padding-bottom:36px}   /* the footer used to provide this */
a{color:var(--accent-ink);text-decoration:none}
a:hover{text-decoration:underline}

/* Sticky, not fixed: it keeps its place in the flow, so nothing below needs a
   compensating top margin and the mobile nav panel still anchors to it (sticky
   is a positioned element, so it remains the containing block for the
   position:absolute panel hanging off its bottom edge).
   z-index clears the filter dropdown panels at 30 - they open downward, so an
   open one scrolled up to the header must pass under it, not through it. */
/* The environment bar and the header stick together as one block. Making them
   separately sticky would mean the header hardcoding the bar's height, which
   stops being true the moment the text wraps on a narrow screen. */
.stickytop{position:sticky;top:0;z-index:50;margin-bottom:26px}

/* Always present, coloured by which database is on screen. Blue for invented
   data, red for real: test mode is information, not a warning, and reserving
   alarm colours for the state that actually costs something keeps them
   meaningful. Text left, control right, on the same .wrap as the header so all
   three edges line up.

   --accent-ink, never --accent: white on the bright brand blue measures 2.68:1
   and this text is 9px, which needs 4.5:1. The darkened hue gives 4.66:1 and is
   the variable this stylesheet already reserves for anything text sits on. As a
   bonus it beats the amber it replaced, which was 4.23:1 and failing. */
.envbar{color:#fff;font-size:9px;font-weight:600;letter-spacing:.4px}
.envbar .wrap{display:flex;align-items:center;justify-content:space-between;
  gap:16px;min-height:26px;padding-top:4px;padding-bottom:4px}
.envbar.test{background:var(--accent-ink)}
.envbar.production{background:var(--bad)}
.envbar.unknown{background:var(--ink)}
.envtext{text-transform:uppercase;letter-spacing:.6px}

/* Not sticky itself - .stickytop above pins the bar and this together. A
   nested sticky would stick within its parent's box, which is a no-op here at
   best and a jump at worst. The margin moves to the wrapper so the two stay
   flush against each other. */
.topbar{background:#fff;border-bottom:1px solid var(--line);
  position:relative}
.topbar .wrap{display:flex;align-items:center;gap:22px;height:60px}
.brand{display:flex;align-items:center;flex:none}
/* The wordmark is part of the image, so height drives it and width follows the
   intrinsic 510x128 ratio. The width/height attrs on the <img> reserve the box
   so the topbar doesn't reflow while the logo loads. */
.brand img{height:32px;width:auto;display:block}

/* Nav items sit on a tinted pill when active, with a bar under the current
   section so the active item reads even at a glance. */
.topbar nav{display:flex;gap:2px;flex:1;align-items:center}
.topbar nav a{position:relative;color:var(--muted);font-weight:500;font-size:14px;
  padding:8px 12px;border-radius:4px;white-space:nowrap}
.topbar nav a:hover{color:var(--ink);background:var(--accent-hint);text-decoration:none}
.topbar nav a.on{color:var(--accent-ink);background:var(--accent-soft);font-weight:600}

/* Page-level actions live here. Order in the markup is secondary -> primary,
   so the primary always lands on the right. */
.topcta{display:flex;gap:8px;align-items:center;flex:none}

/* Database toggle. Development only. A switch, not links: it changes state
   rather than navigating. It sits on the coloured bar, so the inactive side is
   a translucent well and the active side is solid white - readable on amber and
   on red without needing a rule per background. */
.dbtoggle{display:flex;flex:none;border-radius:4px;overflow:hidden;
  background:rgba(0,0,0,.18)}
.dbtoggle button{font:inherit;font-size:8.25px;font-weight:700;letter-spacing:.6px;
  text-transform:uppercase;padding:4px 11px;border:0;background:transparent;
  color:rgba(255,255,255,.75);cursor:pointer;line-height:1.5}
.dbtoggle button:hover{color:#fff;background:rgba(255,255,255,.14)}
.dbtoggle button.on{background:#fff;color:var(--ink)}
.dbtoggle button.on:hover{background:#fff}

.navtoggle{display:none;align-items:center;justify-content:center;width:38px;height:38px;
  padding:0;border:1px solid var(--line);border-radius:4px;background:#fff;
  color:var(--ink);cursor:pointer;flex:none}
.navtoggle:hover{border-color:var(--accent)}

/* Every page title clears its content by 20px, whether or not a .sub line
   follows. When one does, the h1 tucks up against it and the .sub carries the
   gap instead - otherwise the two would stack and the title would float. */
h1{font-size:23px;margin:0 0 20px;letter-spacing:-.3px}
h1:has(+ .sub){margin-bottom:4px}
h1 .pill{vertical-align:middle;margin-left:10px;position:relative;top:-2px}
h2{font-size:15px;margin:0 0 12px;text-transform:uppercase;letter-spacing:.7px;color:var(--muted)}
h3{font-size:14px;margin:18px 0 8px}
.sub{color:var(--muted);margin:0 0 20px}

.card{background:var(--card);border:1px solid var(--line);border-radius:4px;
  padding:12px;margin-bottom:18px}

/* A card heading that's prose rather than a section label - the generated
   report title on Analytics. Drops the uppercase-muted treatment. */
.card .title{font-size:20px;text-transform:none;letter-spacing:-.3px;
  color:var(--ink);font-weight:700;margin:0 0 10px}
.q{color:var(--muted)}                 /* inline qualifier, not a label */
.grid{display:grid;gap:16px}
.g2{grid-template-columns:repeat(2,1fr)}
.g3{grid-template-columns:repeat(3,1fr)}
.g4{grid-template-columns:repeat(4,1fr)}
.g5{grid-template-columns:repeat(5,1fr)}
.g6{grid-template-columns:repeat(6,1fr)}
@media(max-width:860px){.g2,.g3,.g4,.g5,.g6{grid-template-columns:1fr 1fr}}

.kpi{background:#fff;border:1px solid var(--line);border-radius:4px;padding:15px 17px}
.kpi .n{font-size:25px;font-weight:700;letter-spacing:-.6px}
.kpi .l{color:var(--muted);font-size:12px;text-transform:uppercase;letter-spacing:.6px}
.kpi.warn .n{color:var(--warn)}

table{width:100%;border-collapse:collapse;font-size:13.5px}
th{text-align:left;font-size:11px;text-transform:uppercase;letter-spacing:.6px;
  color:var(--muted);border-bottom:1px solid var(--line);padding:12px;font-weight:600}
/* Horizontal padding matches the th so columns line up; vertical stays tighter
   because these tables run to thousands of rows. */
td{padding:8px 12px;border-bottom:1px solid #f0f2f5;vertical-align:top}
/* The card edge already closes the table - a rule under the last row doubles it. */
tbody tr:last-child td{border-bottom:0}
tbody tr:hover{background:#fafbfc}
tbody tr[data-href]{cursor:pointer}
tbody tr[data-href]:hover{background:var(--accent-hint)}
td.num,th.num{text-align:right;font-variant-numeric:tabular-nums}
.mono{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12.5px}

/* Primary: solid brand fill, white label - Justin's call, made knowing the
   numbers. White on #30A9DD is 2.68:1 (WCAG AA wants 4.5:1 for text this size).
   If it ever reads as washed out on a bright screen, darkening the fill to
   var(--accent-ink) takes the same white label to 4.66:1 and is a one-line
   change here; the brand hue is unchanged either way. */
.btn{display:inline-flex;align-items:center;justify-content:center;
  height:var(--ctl);background:var(--accent);color:#fff;
  border:1px solid var(--accent);border-radius:4px;
  padding:8px 14px;font-size:13px;font-weight:600;cursor:pointer;line-height:1.3}
.btn:hover{background:var(--accent-hover);border-color:var(--accent-hover);
  text-decoration:none;color:#fff}

/* Secondary: outline variation of the same accent. */
.btn.sec{background:transparent;color:var(--accent-ink);border:1px solid var(--accent)}
.btn.sec:hover{background:var(--accent-soft);color:var(--accent-ink)}
.btn.danger{background:#fff;color:var(--bad);border:1px solid #f0c8c3}
.btn.danger:hover{background:#fdecea;color:var(--bad)}
/* .sm is now only a narrower, smaller-lettered button - not a shorter one.
   A row of controls where one is 8px stubbier reads as a mistake. */
.btn.sm{height:var(--ctl);padding:0 12px;font-size:12.5px}
.actions{display:flex;gap:8px;flex-wrap:wrap;align-items:center}
.tick{display:inline-flex;align-items:center;gap:7px;margin:0;font:inherit;
  text-transform:none;letter-spacing:0;font-weight:400;color:var(--ink);cursor:pointer}
.tick input{width:auto;margin:0}

label{display:block;font-size:11.5px;text-transform:uppercase;letter-spacing:.5px;
  color:var(--muted);font-weight:600;margin-bottom:4px}
input[type=text],input[type=date],input[type=time],input[type=number],
input[type=email],input[type=url],select,textarea{
  width:100%;padding:8px 10px;border:1px solid var(--line);border-radius:4px;
  background:#fff;font:inherit;color:var(--ink)}
input[type=text],input[type=date],input[type=time],input[type=number],
input[type=email],input[type=url],select{height:var(--ctl)}
input:focus,select:focus,textarea:focus{outline:2px solid var(--accent);outline-offset:0;
  border-color:var(--accent)}
/* The native select arrow is drawn by the OS hard against the border and
   ignores padding-right. Suppress it and paint the same chevron the filter
   dropdowns use, inset properly. */
/* One rule, two controls. An <input list> also drops a list down, so it should
   carry the same chevron with the same inset - and sharing the declaration is
   what stops the two drifting apart the next time one is adjusted. */
select,
input[type=text][list],
input[type=number][list]{
  appearance:none;-webkit-appearance:none;
  padding-right:32px;
  background-image:url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2016%2016%22%20fill%3D%22none%22%20stroke%3D%22%236b7787%22%20stroke-width%3D%221.8%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%3E%3Cpath%20d%3D%22M4%206l4%204%204-4%22%2F%3E%3C%2Fsvg%3E");
  background-repeat:no-repeat;
  background-position:right 11px center;
  background-size:14px 14px;
}
/* Chrome draws its own tiny arrow for a datalist input, which would sit next to
   ours. Scoped to text inputs on purpose: on a date or time field that same
   pseudo-element IS the calendar or clock button, and hiding it takes away the
   only way to open the picker. */
input[type=text][list]::-webkit-calendar-picker-indicator,
input[type=number][list]::-webkit-calendar-picker-indicator{display:none!important}
/* The spinner sits where the chevron now is, and stepping by 1 through a dose
   is not how anyone enters 12.5 anyway. The list and the keyboard are both
   better than the arrows. */
input[type=number][list]::-webkit-inner-spin-button,
input[type=number][list]::-webkit-outer-spin-button{-webkit-appearance:none;margin:0}
select:disabled{opacity:.6}

textarea{min-height:78px;resize:vertical}
.field{margin-bottom:14px}
/* align-items:stretch, not centre: the button then takes the row's height
   whatever that turns out to be. Deriving it from font metrics does not work
   here - input[type=time] measures 41px and input[type=number] 40.25px against
   a plain text input's 38.25px, because the native picker sets its own
   intrinsic height. Let the box do it. */
.withbtn{display:flex;gap:6px;align-items:stretch}
.withbtn input{flex:1;min-width:0}
.withbtn .btn{font:inherit;font-weight:600;padding:0 12px;flex:none;
  display:inline-flex;align-items:center;
  /* height:auto so align-items:stretch wins - it takes the field's height,
     which is the point of the wrapper. A fixed height would override it. */
  height:auto}
fieldset{border:1px solid var(--line);border-radius:4px;padding:14px 16px;margin:0 0 18px}
legend{font-size:11px;text-transform:uppercase;letter-spacing:.7px;color:var(--muted);
  font-weight:700;padding:0 6px}
/* Remove-row button on repeating form sections. A narrow trailing column so
   the × sits at a predictable place on every row rather than after however
   wide the last field happens to be. */
/* height:1px seeds the percentage on .rowrm below. A table cell's height is
   auto, so a child's height:100% has nothing to resolve against and collapses
   to its line box; a definite value gives it one, and the row still expands to
   whatever the tallest cell needs, so 1px is never the used height. */
.rmcol{width:36px;height:1px;padding-left:0;padding-right:6px;text-align:right}
/* Same box as the input beside it, built the same way: font:inherit, 8px
   vertical padding, 1px border. Setting line-height by hand instead got within
   0.75px, because an input's content box resolves to 20.25px rather than the
   21px that 14px x 1.5 suggests. Weight rather than size carries the glyph, so
   the x stays visible without growing the button. */
.rowrm{width:30px;height:100%;font:inherit;font-weight:600;padding:0;
  border:1px solid transparent;border-radius:4px;background:transparent;
  color:var(--muted);cursor:pointer}
.rowrm:hover{border-color:#f0c8c3;background:#fdecea;color:var(--bad)}
th.rmcol{padding-right:6px}

/* A value a form shows but will not post - sits where an input would, without
   pretending to be one. */
.readonly{margin:0;padding:8px 0;font-size:13.5px;line-height:21px}

/* A note under a form section - how the section behaves, not what to type. */
.hint{color:var(--muted);font-size:12px;margin:10px 0 0}

.pill{display:inline-block;padding:2px 8px;border-radius:4px;font-size:11px;font-weight:600}
.pill.blue{background:var(--accent-soft);color:var(--accent-ink)}
.pill.grey{background:#eef0f3;color:var(--muted)}
.pill.warn{background:var(--warn-soft);color:var(--warn)}
.pill.good{background:var(--good-soft);color:var(--good)}
.pill.bad{background:#fdecea;color:var(--bad)}

.conf{display:inline-block;min-width:22px;text-align:center;padding:2px 6px;border-radius:4px;
  font-size:11px;font-weight:700;font-variant-numeric:tabular-nums}
.conf.lo{background:#fdecea;color:var(--bad)}
.conf.mid{background:var(--warn-soft);color:var(--warn)}
.conf.hi{background:var(--good-soft);color:var(--good)}

/* Page heading left, search + filters right. */
.pagehead{display:flex;justify-content:space-between;align-items:center;
  gap:16px;flex-wrap:wrap;margin-bottom:20px}
.pagehead h1{margin:0}
.pagehead .sub{margin:3px 0 0}
.count{color:var(--muted);font-size:16px;font-weight:400;letter-spacing:0}

/* In-page tabs. Distinct from the top-bar nav (which moves between sections)
   and from the CTAs beside it (which act on the record): these switch which
   part of one record you are looking at, so they read as a segmented control
   rather than as buttons. */
.tabs{display:flex;gap:2px;flex:none;background:var(--bg);border:1px solid var(--line);
  border-radius:4px;padding:2px}
/* The segmented controls - these and the site picker. -6px because the wrapper
   adds 2px of padding each side and a 1px border, and it is the OUTER box that
   has to line up with the buttons beside it. */
.tabs a,.tabs button{display:flex;align-items:center;gap:7px;
  height:calc(var(--ctl) - 6px);padding:0 13px;
  border-radius:3px;font:inherit;font-size:13px;font-weight:600;color:var(--muted);
  white-space:nowrap;border:0;background:transparent;cursor:pointer;
  text-transform:none;letter-spacing:0;margin:0}
.tabs a:hover,.tabs button:hover{color:var(--ink);text-decoration:none}
.tabs a.on,.tabs button.on{background:#fff;color:var(--accent-ink);
  box-shadow:0 1px 2px rgba(27,34,48,.10)}
.tabn{font-size:11.5px;font-weight:600;color:var(--muted);
  background:var(--line);border-radius:3px;padding:1px 6px;font-variant-numeric:tabular-nums}
.tabs a.on .tabn{background:var(--accent-soft);color:var(--accent-ink)}

/* Search: the submit button is the magnifier, sitting inside the field. */
.search{position:relative;display:inline-block}
.search input[type=text]{width:250px;max-width:none;padding-right:34px}
.searchbtn{position:absolute;right:1px;top:1px;bottom:1px;width:32px;padding:0;
  border:0;background:transparent;color:var(--muted);cursor:pointer;
  display:inline-flex;align-items:center;justify-content:center}
.searchbtn:hover{color:var(--accent-ink)}
.searchbtn svg{width:16px;height:16px;display:block}

/* Filter row: dropdowns + search, all on the heading line. */
.controls{display:flex;align-items:center;gap:8px;flex-wrap:wrap}

/* Multi-select dropdown. The caret and the X occupy the same slot on the right
   of the trigger; the caret is decorative (clicks fall through and open the
   panel) while the X is a real link that clears the facet. */
.dd{position:relative;display:inline-block}
.dd-trigger{display:inline-flex;align-items:center;gap:6px;font:inherit;font-size:13px;
  height:var(--ctl);padding:0 32px 0 11px;border:1px solid var(--line);border-radius:4px;
  background:#fff;color:var(--ink);cursor:pointer;line-height:1.3;white-space:nowrap}
.dd-trigger:hover,.dd.open .dd-trigger{border-color:var(--accent)}
.dd-n{display:inline-flex;align-items:center;justify-content:center;min-width:17px;
  height:17px;padding:0 4px;background:var(--accent);color:#fff;border-radius:4px;
  font-size:11px;font-weight:700;line-height:1}
.dd-caret,.dd-x{position:absolute;right:1px;top:1px;bottom:1px;width:30px;
  display:inline-flex;align-items:center;justify-content:center;color:var(--muted)}
.dd-caret{pointer-events:none}
.dd-x:hover{color:var(--bad);text-decoration:none}
.dd-caret svg,.dd-x svg{width:14px;height:14px;display:block}
.dd-panel{display:none;position:absolute;z-index:30;top:calc(100% + 4px);left:0;
  min-width:100%;white-space:nowrap;background:#fff;border:1px solid var(--line);
  border-radius:4px;box-shadow:0 6px 20px rgba(27,34,48,.14);padding:5px}
.dd.open .dd-panel{display:block}
.dd-opt{display:flex;align-items:center;gap:8px;margin:0;padding:6px 9px;
  border-radius:4px;color:var(--ink);font-size:13px;font-weight:400;
  text-transform:none;letter-spacing:0;cursor:pointer}
.dd-opt:hover{background:var(--accent-hint)}
.dd-opt input{width:auto;margin:0;accent-color:var(--accent)}
a.dd-opt{text-decoration:none}
a.dd-opt.on{background:var(--accent-soft);color:var(--accent-ink);font-weight:600}
.dd-trigger.on{border-color:var(--accent);color:var(--accent-ink)}
.dd-panel.wide{min-width:250px}
.dd-sep{height:1px;background:var(--line);margin:5px 0}
.dd-range{display:grid;grid-template-columns:auto 1fr;gap:6px 8px;
  align-items:center;padding:4px 9px 6px}
.dd-range label{margin:0;font-size:11px}
.dd-range input[type=date]{width:100%;height:var(--ctl);padding:0 9px;font-size:13px}

/* Sortable headers. The arrow points down for descending and is flipped for
   ascending, so one glyph covers both. */
th a.sort{display:inline-flex;align-items:center;gap:4px;color:var(--muted)}
th a.sort:hover{color:var(--accent-ink);text-decoration:none}
th a.sort.on{color:var(--accent-ink)}
th.num a.sort{flex-direction:row-reverse}
.sarrow{width:12px;height:12px;display:block;flex:none}
.sarrow.asc{transform:rotate(180deg)}
.pager{display:flex;gap:6px;align-items:center;margin-top:14px;color:var(--muted);font-size:13px}
.pager a{padding:5px 10px;border:1px solid var(--line);border-radius:4px;background:#fff}

.dl{display:grid;grid-template-columns:150px 1fr;gap:6px 14px;font-size:13.5px}
.dl dt{color:var(--muted);font-size:12px;text-transform:uppercase;letter-spacing:.4px}
.dl dd{margin:0}
.empty{color:var(--muted);font-style:italic;padding:14px 0}
.flex{display:flex;justify-content:space-between;align-items:flex-start;gap:16px;flex-wrap:wrap}
.spark{display:block}

/* ------------------------------------------------------------- trajectories
   Scaled uniformly: the viewBox is in the same proportion the card renders at,
   so a rise on the y axis is not stretched by whatever width the card happens
   to be. width:100% with height:auto keeps that true at every breakpoint. */
.traj{display:block;width:100%;height:auto}
.traj .gl{stroke:var(--line);stroke-width:1}
.traj .gt{fill:var(--muted);font-size:11px}
.traj .thr{stroke:var(--good);stroke-width:1;stroke-dasharray:5 4;opacity:.7}
.traj .tline{stroke-width:2;stroke-linejoin:round;stroke-linecap:round}
.traj .tdot{pointer-events:none;transition:r .08s ease-out}
/* The hit target is transparent, not invisible: fill:none would let the pointer
   fall straight through it. */
.traj .thit{fill:transparent;cursor:pointer}
/* Scoped to the point's own group. `.thit:hover ~ .tdot` looked right and was
   wrong: `~` matches every LATER sibling, so hovering one point grew every dot
   after it. */
.traj .tpt:hover .tdot{r:5.5}
/* Vitals: the hover target is a full-height column, and a vertical guide marks
   it. Scoped inside the column group for the same reason as the dot above. */
.traj .tguide{stroke:var(--ink);stroke-width:1;opacity:0}
.traj .tcol:hover .tguide{opacity:.22}
.traj .bar{fill:var(--accent);cursor:pointer}
.traj .bar:hover{fill:var(--accent-ink)}
.swatch{display:inline-block;width:9px;height:9px;border-radius:2px;
  vertical-align:-1px;margin-right:5px;margin-left:2px}
/* Label left, value right, on every row. The label takes the slack; the value
   never does. Keyed on explicit classes rather than on the element - the bold
   measured value is a <b> and the estimates are <span>s, and a rule matching
   the element gave the estimates an equal share of the width, so they sat in
   the middle of a column the measured value had aligned to the right. */
.tiprow{display:flex;align-items:center;gap:14px;margin-top:3px}
.tiprow i{width:8px;height:8px;border-radius:2px;flex:none}
.tiprow .tipk{flex:1;text-align:left;color:#c6ccd6}
.tiprow .tipv{flex:none;margin-left:auto;text-align:right;
  font-variant-numeric:tabular-nums}
.h2sub{text-transform:none;letter-spacing:0;font-weight:400}
.chartnote{color:var(--muted);font-size:12px;margin:6px 0 0}

/* Follows the cursor; positioned from JS, so it starts off-screen rather than
   flashing at 0,0 on first paint. */
.tip{position:fixed;left:-9999px;top:0;z-index:60;pointer-events:none;
  background:var(--ink);color:#fff;border-radius:4px;padding:6px 9px;
  font-size:12px;line-height:1.45;white-space:nowrap;
  box-shadow:0 2px 10px rgba(27,34,48,.25)}
.tip b{font-size:13px}
.tip span{color:#c6ccd6}

/* A document icon standing in for the word "paper". */
.paperico{width:13px;height:13px;vertical-align:-2px;color:var(--muted);
  margin-left:2px}

/* Per-patient consent management. One card per kind: state and controls on the
   head row, the paper-entry line under it, history below that. */
.conhead{display:flex;align-items:flex-start;justify-content:space-between;
  gap:16px;flex-wrap:wrap}
.paperrow{display:flex;align-items:center;gap:10px;flex-wrap:wrap;
  margin:12px 0 0;padding:10px 12px;background:var(--bg);
  border:1px solid var(--line);border-radius:4px}
.paperrow label{margin:0;flex:none}
.paperrow input[type=date]{width:auto;flex:none}
.paperrow .q{font-size:12px}
.note{white-space:pre-wrap;background:#fafbfc;border-left:3px solid var(--line);
  padding:9px 12px;border-radius:0 4px 4px 0;color:#3a4453}
.inline{display:inline}

/* ------------------------------------------------------------------ mobile
   Columns drop by priority as the screen narrows, and whatever a row loses is
   folded into a second line under the name. Nothing becomes unreachable -
   the row is still a link into the record, which is the real job of a list on
   a phone. */
.rowsub{display:none;color:var(--muted);font-size:12px;font-weight:400;margin-top:2px}

@media(max-width:900px){
  .wrap{padding:0 16px}
  .hide-md{display:none}
}

@media(max-width:820px){
  .navtoggle{display:inline-flex}
  .topbar .wrap{gap:14px}
  .topbar nav{display:none;position:absolute;top:100%;left:0;right:0;z-index:40;
    flex-direction:column;align-items:stretch;gap:0;padding:6px;background:#fff;
    border-bottom:1px solid var(--line);box-shadow:0 10px 24px rgba(27,34,48,.12)}
  .topbar nav.open{display:flex}
  .topbar nav a{border-radius:4px;padding:11px 14px;font-size:15px}
  .brand{flex:1}
}

@media(max-width:760px){
  .g2,.g3,.g4,.g5,.g6{grid-template-columns:1fr}
  .pagehead{align-items:stretch}
  .controls{width:100%}
  .search{flex:1;min-width:0}
  .search input[type=text]{width:100%}
  h1{font-size:20px}
}

@media(max-width:640px){
  .hide-sm{display:none}
  .rowsub{display:block}
  /* One tap target per row, so the name gets the width and the padding. */
  td,th{padding:10px 8px}
  .dd-panel{position:fixed;left:12px;right:12px;top:auto;min-width:0}
  .topcta .btn{padding:8px 11px}
  .brand img{height:26px}
}

/* Ask-the-records box and its example prompts. */
.askbox textarea{width:100%;min-height:56px;resize:vertical;font:inherit;font-size:15px}
.askrow{display:flex;align-items:center;justify-content:space-between;gap:12px;
  flex-wrap:wrap;margin-top:10px}
.examples{display:flex;flex-wrap:wrap;gap:8px}
.example{text-align:left;font:inherit;font-size:12.5px;padding:7px 11px;cursor:pointer;
  border:1px solid var(--line);border-radius:4px;background:#fff;color:var(--accent-ink)}
.example:hover{border-color:var(--accent);background:var(--accent-soft)}
details summary::-webkit-details-marker{color:var(--muted)}
pre.note{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12.5px;
  white-space:pre-wrap}

/* ------------------------------------------------------------ e-consent
   Patient-facing signing pages. Wider line-height and larger type than the
   admin: this is a legal document being read once, on a phone or a handed-over
   tablet, quite possibly by someone unwell. Legibility beats density. */
body.signing{background:#fff}
.signwrap{max-width:720px;margin:0 auto;padding:0 22px}
.signhead{border-bottom:1px solid var(--line);padding:14px 0;margin-bottom:28px}
.signbrand{font-size:16px;font-weight:700;letter-spacing:-.2px;color:var(--ink)}
.signfoot{border-top:1px solid var(--line);margin-top:44px;padding:18px 0 40px;
  color:var(--muted);font-size:12.5px;line-height:1.6}
.signtitle{font-size:26px;line-height:1.25;margin:0 0 6px}
.signfor{color:var(--muted);margin:0 0 26px}
.signdone{padding:20px 0 40px;font-size:15.5px;line-height:1.65}
.signdone p{margin:0 0 14px}

.doc{font-size:15.5px;line-height:1.7}
.doc h3{font-size:16px;margin:26px 0 8px;letter-spacing:-.2px}
.doc p{margin:0 0 14px}

/* An answer inside the document, not a form field bolted underneath it - the
   initials box has to sit where the paragraph it refers to ends. */
.cfield{background:var(--accent-hint);border:1px solid var(--accent-soft);
  border-radius:4px;padding:12px 14px;margin:0 0 18px}
.cfield label{display:block;font-size:13.5px;color:var(--ink);margin-bottom:8px;
  text-transform:none;letter-spacing:0;font-weight:500;line-height:1.5}
.cfield input[type=text],.cfield select{max-width:340px}
.cfield input.initials{width:110px;text-transform:uppercase;letter-spacing:2px;
  font-weight:600;text-align:center}
.cfield.check label{display:flex;gap:10px;align-items:flex-start;margin:0}
.cfield.check input{margin-top:3px;flex:none}

.signblock{border-top:2px solid var(--ink);margin-top:36px;padding-top:22px}
.signblock h3{font-size:17px;margin:0 0 6px}
.signnote{color:var(--muted);font-size:13.5px;margin:0 0 18px;line-height:1.6}
.opt{color:var(--muted);font-weight:400;text-transform:none;letter-spacing:0}
.padwrap{position:relative}
#sigpad{width:100%;height:150px;border:1px dashed var(--line);border-radius:4px;
  background:#fff;touch-action:none;display:block;cursor:crosshair}
#sigclear{position:absolute;right:8px;bottom:8px}
.attest{background:var(--accent-hint);border:1px solid var(--accent-soft);
  border-radius:4px;padding:14px;margin:20px 0}
.attest label{display:flex;gap:11px;align-items:flex-start;font-size:14px;
  line-height:1.55;cursor:pointer;text-transform:none;letter-spacing:0;
  font-weight:400;color:var(--ink);margin:0}
.attest input{margin-top:3px;flex:none}
.signactions{display:flex;gap:12px;align-items:center;flex-wrap:wrap;margin-top:8px}
.btn.lg{font-size:15px;padding:12px 22px}
.declinebox{border:1px solid var(--line);border-radius:4px;padding:16px;
  margin-top:22px;background:var(--bg)}
.declinebox p{margin:0 0 14px;font-size:14px;line-height:1.6;color:var(--muted)}
.signerr{border:1px solid var(--warn);background:var(--warn-soft);color:var(--warn);
  border-radius:4px;padding:14px 16px;margin:0 0 24px;font-size:14px}
.signerr ul{margin:8px 0 0;padding-left:20px;line-height:1.7}

/* The frozen instrument, as shown back to staff. Same prose, answers in place
   of controls. */
.cdone{display:flex;gap:14px;align-items:baseline;background:var(--bg);
  border-left:3px solid var(--accent);padding:9px 12px;margin:0 0 14px;
  font-size:14px;line-height:1.5}
.cdone-l{flex:1;color:var(--muted)}
.cdone-v{font-weight:600;white-space:nowrap}
.cdone.initialled .cdone-v{text-transform:uppercase;letter-spacing:2px}
.cdone.check{display:block;font-weight:500}
.sigimg{border:1px solid var(--line);border-radius:4px;background:#fff;
  max-width:340px;display:block;margin-top:6px}

/* Tamper-evidence readout. Green is not decoration here - it is the answer to
   "is this still what they signed". */
.intact{color:var(--good);font-weight:600}
.tampered{color:var(--bad);font-weight:700}
.hashline{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:11.5px;
  color:var(--muted);word-break:break-all}
.draftbar{border:1px solid var(--warn);background:var(--warn-soft);color:var(--warn);
  border-radius:4px;padding:12px 14px;margin:0 0 18px;font-size:13.5px;line-height:1.6}
.linkrow{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12px;
  background:var(--bg);border:1px solid var(--line);border-radius:4px;
  padding:9px 11px;word-break:break-all;margin:6px 0 0}

@media(max-width:640px){
  .signtitle{font-size:22px}
  .doc{font-size:16px}
  .signactions .btn{width:100%;text-align:center}
}

/* ------------------------------------------------------------------ drawers
   A right-hand panel for short, contextual work. Long forms stay pages: the
   patient intake is ten fieldsets and the session form has forty fields, and
   neither wants 480px. */
.drawer{position:fixed;inset:0;z-index:80;display:none}
.drawer.on{display:block}
.drawer-scrim{position:absolute;inset:0;background:rgba(27,34,48,.32)}
.drawer-panel{position:absolute;top:0;right:0;bottom:0;width:min(560px,100vw);
  background:#fff;box-shadow:-2px 0 24px rgba(27,34,48,.18);
  display:flex;flex-direction:column;outline:0;
  animation:drawerin .16s ease-out}
@keyframes drawerin{from{transform:translateX(16px);opacity:.6}to{transform:none;opacity:1}}
/* The page behind must not scroll while the panel is open, or the scrim moves
   under the pointer and the drawer appears to drift. */
body.drawer-open{overflow:hidden}

.drawerhead{display:flex;align-items:center;justify-content:space-between;gap:14px;
  padding:14px 18px;border-bottom:1px solid var(--line);flex:none}
.drawertitle{font-size:17px;margin:0;text-transform:none;letter-spacing:-.2px;
  color:var(--ink);font-weight:700}
.drawercta{display:flex;align-items:center;gap:8px;flex:none}
.drawerx{width:30px;height:30px;padding:0;font-size:21px;line-height:1;
  border:1px solid transparent;border-radius:4px;background:transparent;
  color:var(--muted);cursor:pointer}
.drawerx:hover{background:var(--bg);color:var(--ink)}
.drawerbody{padding:18px;overflow:auto;flex:1}
/* Pinned, not scrolled with the content: on a long form the action you want is
   otherwise below the fold at the moment you want it. Secondary left, primary
   right - the same order as everywhere else. */
/* Pinned, not scrolled with the content: on a long form the action you want is
   otherwise below the fold at the moment you want it. Right-aligned, with no
   Cancel - the X, Escape and the scrim already close it. */
.drawerfoot{display:flex;align-items:center;justify-content:flex-end;gap:8px;
  padding:12px 18px;border-top:1px solid var(--line);background:var(--bg);flex:none}
.drawerbody .card{border:0;padding:0;margin:0;background:transparent}
.drawerbody fieldset{border:0;padding:0;margin:0 0 18px}
.drawerbody legend{padding:0}

@media(max-width:640px){
  .drawer-panel{width:100vw}
}

/* ----------------------------------------------------------- the day view
   Week strip: seven days with their counts, so you can see where the work is
   without opening seven pages. */
/* Three weeks from today, every day the same width.
   Equal cells because the eye is scanning ACROSS them for a gap, and columns
   that change width make that scan a measuring exercise. `flex:1 1 0` with
   min-width:0 rather than flex:1, so twenty-one of them divide the row evenly
   instead of sizing to their own content. */
.weekstrip{display:flex;align-items:stretch;gap:3px;margin:0 0 14px}
.wkday{flex:1 1 0;min-width:0;display:flex;flex-direction:column;
  align-items:center;gap:0;position:relative;
  padding:8px 3px 8px;border:1px solid var(--line);border-radius:4px;
  background-color:#fff;color:var(--muted);
  /* How full the day is, as a tide rising from the bottom of the cell. A
     TRANSLUCENT accent, so it composites with whatever the state underneath
     is - white, the selected tint, the closed grey - instead of needing three
     hand-picked colours that would drift apart.

     background-IMAGE, and every state below sets background-COLOR rather than
     the shorthand: `background:` resets the image, which would silently drop
     the fill on exactly the selected and closed days. */
  --busyfill:rgba(48,169,221,.17);
  background-image:linear-gradient(to top,
    var(--busyfill) 0 calc(var(--busy, 0) * 1%),
    transparent calc(var(--busy, 0) * 1%))}
.wkday:hover{border-color:var(--accent);text-decoration:none}
.wkday.on{border-color:var(--accent);background-color:var(--accent-soft)}
.wkday.istoday .wknum{color:var(--accent-ink)}
.wkdow{font-size:9.5px;text-transform:uppercase;letter-spacing:.3px;
  line-height:1.4;position:relative}
.wknum{font-size:15px;font-weight:700;color:var(--ink);line-height:1.15;
  position:relative}
.wkday.on .wknum{color:var(--accent-ink)}

/* The count is what the strip is SCANNED for - "where is there room" - so it is
   a chip rather than a number in a stack of numbers. Filled for today, tinted
   for every other day.

   Always the same box, including on a day with nothing booked, so twenty-one
   cells stay the same height and the row does not comb. An empty day gets the
   box with no fill: the filled chips are then the only thing with weight on the
   row, which is exactly what the eye should land on. */
.wkcount{display:flex;align-items:center;justify-content:center;
  min-width:20px;height:20px;padding:0 5px;border-radius:999px;
  margin-top:7px;                    /* the gap the number needs to breathe */
  background:var(--accent-soft);color:var(--accent-deep);
  font-size:11px;font-weight:500;line-height:1}
/* Selected: the cell is already --accent-soft, so a chip in the same tint would
   vanish. White reads as a chip against it. */
.wkday.on .wkcount{background:#fff}
/* Today: the one that should carry weight. Declared after .on so that today,
   which is also selected on arrival, keeps the solid fill. */
.wkday.istoday .wkcount{background:var(--accent);color:#fff;font-weight:700}
/* Closed days drop back but keep their width. They used to be a third as wide,
   which is fine across seven cells and wrong across twenty-one: unequal columns
   turn "where is the gap" into a measuring exercise. Muted, not narrowed -
   still selectable, because a session occasionally lands on one. */
.wkday.wkend{background-color:var(--bg);opacity:.55}
.wkday.wkend .wknum{font-weight:600;color:var(--muted)}
.wkday.wkend:hover{opacity:1}
.wkday.wkend.on{opacity:1;background:var(--accent-soft)}
.wkday.wkend.on .wknum{color:var(--accent-ink)}
/* Nothing booked. The box stays so the chips line up; the fill goes, because a
   circle around a dot is a thing to read and there is nothing there. */
/* Three weeks, then two, then one. A cell stops being readable somewhere under
   45px - thinner than the number inside it - so the strip sheds a tier rather
   than squeezing: twenty-one stop fitting at about 1080px and fourteen at about
   760px. The arrows still reach whatever is hidden and the date picker still
   jumps anywhere, so nothing becomes unreachable, only unshown.

   The selected day is kept at every tier. A strip with nothing highlighted
   reads as a lost selection, which is worse than a gap in the sequence. */
@media (max-width:1080px){
  .wkday.wkfar{display:none}
  .wkday.wkfar.on{display:flex}
}
@media (max-width:760px){
  .wkday.wkmid{display:none}
  .wkday.wkmid.on{display:flex}
}

.wkcount.none{background:transparent;color:var(--line);font-weight:400}
.wkday.istoday .wkcount.none{background:transparent;color:var(--muted)}
.wknav{display:flex;align-items:center;padding:0 6px;border:1px solid var(--line);
  border-radius:4px;background:#fff;color:var(--muted);font-size:16px;flex:none}
.wknav:hover{border-color:var(--accent);text-decoration:none}
.daypick{display:inline-block}
/* Same height as everything else on the row, and as the filters on every
   other page. */
.daypick input{width:auto;height:var(--ctl);padding:0 10px}

/* A cancelled or missed visit stays on the list - it is a fact about the day -
   but should not compete with the ones still to happen. */
/* A cancelled or no-show row reads as past tense - but NOT the cell holding
   its menu. Opacity creates a stacking context, so anything inside inherits it
   and cannot override it: the popover opened at 55% and you could not read the
   options. The row is dimmed; the way to act on it is not. */
tbody tr.dim td:not(.rowmenu){opacity:.55}

.attn{margin:0;padding-left:18px;line-height:1.9;font-size:13.5px}
.sectionrule{margin:30px 0 12px;padding-top:16px;border-top:1px solid var(--line)}

/* Which site this machine is at. A dropdown rather than a segmented control:
   it names the site in force instead of asking you to spot which of three
   buttons is highlighted, and it does not grow a button every time the clinic
   opens another location.

   Not `width:auto` - a fixed width, so the bar does not reflow when the label
   changes from "All locations" to "Charleston". Controls that move when you
   use them are how you click the wrong one. */
.sitepick select{height:var(--ctl);width:154px;font-size:13px;font-weight:600}
.sitepick{flex:none}

/* --------------------------------------------------------- room timeline
   One column per chair, one pixel per minute of the clinic day. A block's top
   and height come straight from its start and end, so an empty stretch of a
   column IS free capacity - nothing to count. */
.tlwrap{overflow-x:auto}
/* An empty stretch of column is bookable, so it says so on hover. The blocks
   inside keep their own pointer, since clicking one opens its menu instead. */
.tlbody[data-book]{cursor:copy}
.tlbody[data-book] .tlblock{cursor:pointer}
.timeline{display:flex;gap:6px;min-width:max-content}
.tlaxis{flex:none;width:52px}
.tlcol{flex:1 0 128px;min-width:128px}
.tlhead{height:30px;display:flex;align-items:center;gap:6px;font-size:12px;
  font-weight:600;color:var(--muted);text-transform:uppercase;letter-spacing:.4px;
  border-bottom:1px solid var(--line);white-space:nowrap;overflow:hidden}
/* The axis head is an empty spacer that aligns the hours with the column
   titles - it has no title to underline. Its border ran the width of the chart
   and straight through the first hour label, which sits 7px high to centre on
   its own line. */
.tlaxis .tlhead{border-bottom:0}
.tlaxis .tlhour{height:60px;position:relative;font-size:11px;color:var(--muted);
  text-align:right;padding-right:8px}
.tlaxis .tlhour span{position:relative;top:-7px}
/* overflow:visible, not hidden. The clip was for the rounded corners, and it
   also cut off any menu opened from a block near the column edge - which is
   most of them. Blocks are placed inside the column by construction (the day
   widens for anything booked outside hours), so nothing needs clipping. */
.tlbody{position:relative;background:#fff;border:1px solid var(--line);
  border-radius:4px;overflow:visible}
/* Hour rules give the eye something to measure against; without them a block
   floats and "is that 1pm or 2pm" needs the tooltip. */
.tlrule{height:60px;border-bottom:1px solid #f0f2f5}
.tlrule:last-child{border-bottom:0}
/* The block is now a menu trigger, so the positioning moved out to a wrapper -
   an absolutely positioned button cannot also be the box a panel anchors to. */
/* .tlbody .tlmenu, not .tlmenu: the wrapper also carries the base `menu`
   class, whose `position:relative` is declared further down this file and wins
   on source order between two single-class selectors. That collapsed the
   wrapper to nothing and took every block on the timeline with it. */
.tlbody .tlmenu{position:absolute;left:3px;right:3px;display:block}
/* Top-aligned, as it was when this was an <a>. A <button> centres its content
   vertically by default, so a three-hour block put the name in the middle of an
   empty box instead of at the time it starts. */
.tlblock{position:absolute;inset:0;width:100%;text-align:left;font:inherit;
  display:flex;flex-direction:column;align-items:stretch;justify-content:flex-start;
  border:0;cursor:pointer;border-radius:3px;padding:3px 6px;
  background:var(--accent-soft);border-left:3px solid var(--accent);
  color:var(--accent-ink);overflow:hidden;font-size:11.5px;line-height:1.35}
.tlblock:hover{text-decoration:none;background:#d8eefa}
.tlwho{display:block;font-weight:700;white-space:nowrap;overflow:hidden;
  text-overflow:ellipsis}
.tlwhen{display:block;color:var(--muted);font-size:10.5px}
/* The same colours the pills use, for the same states. These still said
   `.completed` after the two status axes were merged into one, so every
   finished visit fell through to the default blue - the day view and the
   status pill beside it disagreed about the same session. Keep this list and
   VISIT_STATES in step. */
.tlblock.final,.tlblock.amended{background:var(--good-soft);
  border-left-color:var(--good);color:#14603d}
.tlblock.arrived,.tlblock.in_progress,.tlblock.needs_review{background:var(--warn-soft);
  border-left-color:var(--warn);color:var(--warn)}
.tlblock.no_show,.tlblock.cancelled{background:#fdecea;
  border-left-color:var(--bad);color:var(--bad);opacity:.7}
.visually-hidden{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);
  white-space:nowrap}

/* A button that reads as a link: it reveals something rather than navigating,
   so it must be a <button> for the keyboard, but should not look like a CTA. */
.linkish{font:inherit;padding:0;border:0;background:none;color:var(--accent-ink);
  cursor:pointer;text-decoration:underline}
.linkish:hover{color:var(--accent-hover)}

/* ------------------------------------------------------------------- menu
   A "..." of occasional actions. The frequent one stays a button on the row;
   burying it here would make the forty-times-a-day path cost two clicks. */
.menu{position:relative;display:inline-block}
.menubtn{width:30px;height:30px;padding:0;font-size:17px;line-height:1;
  border:1px solid transparent;border-radius:4px;background:transparent;
  color:var(--muted);cursor:pointer;vertical-align:middle}
.menubtn:hover,.menu.open .menubtn{border-color:var(--line);background:#fff;
  color:var(--ink)}
.menupanel{display:none;position:absolute;right:0;top:calc(100% + 4px);z-index:40;
  min-width:184px;background:#fff;border:1px solid var(--line);border-radius:4px;
  box-shadow:0 6px 20px rgba(27,34,48,.14);padding:4px;text-align:left}
.menu.open .menupanel{display:block}
.menupanel a,.menupanel button{display:block;width:100%;text-align:left;
  font:inherit;font-size:13px;padding:7px 10px;border:0;border-radius:3px;
  background:transparent;color:var(--ink);cursor:pointer;white-space:nowrap}
.menupanel a:hover,.menupanel button:hover{background:var(--accent-hint);
  text-decoration:none}
.menupanel button.danger{color:var(--bad)}
.menupanel button.danger:hover{background:#fdecea}
.menusep{height:1px;background:var(--line);margin:4px 0}

/* The likely action, at the top of the menu. Weight rather than colour: it is
   still a menu item, not a call to action competing with the page's own. */
.menupanel button.primary{font-weight:700;color:var(--accent-ink)}
.menupanel button.primary:hover{background:var(--accent-soft)}

/* A lone tick at the foot of a card needs air under it - against the card edge
   it reads as clipped rather than finished. */
.card > .tick:last-child{margin-bottom:4px}

/* A card's own action, after its content rather than competing with its
   heading. Right-aligned because that is where you finish reading. */
.cardfoot{display:flex;justify-content:flex-end;margin:4px 0 0}

/* A filter option that reaches for rows the list otherwise hides. Same red as
   the destructive items at the foot of the row menu, for the same reason: it
   should not be ticked by accident. */
.dd-opt.danger{color:var(--bad)}
.dd-opt.danger:hover{background:#fdecea}

/* --------------------------------------------------------------- sign in
   The one page with no nav, because there is nobody to show it to yet. */
body.signin{display:flex;align-items:center;justify-content:center;
  min-height:100vh;background:var(--bg);margin:0}
.signinbox{background:var(--card);border:1px solid var(--line);border-radius:8px;
  padding:34px 32px;width:min(400px,calc(100vw - 32px));text-align:center;
  box-shadow:0 1px 3px rgba(27,34,48,.06)}
.signinlogo{width:190px;height:auto;margin:0 0 22px}
.signinbtn{width:100%;gap:10px}
.signinbox .hint{margin:14px 0 0}
.signinbox .signerr{text-align:left;margin:0 0 18px}

/* ------------------------------------------------------------ account menu
   The logo IS the trigger. One thing in the corner rather than a wordmark on
   the left and an avatar on the right repeating who you are on every page. */
.usermenu{flex:none}
.usermenu .brand{border-radius:4px}
.usermenu .brand img{transition:opacity .12s}
.usermenu .brand:hover img,.usermenu.open .brand img{opacity:.75}
/* The panel sits directly under the logo with no gap to cross - a few pixels
   of nothing between them is enough for the pointer to count as having left,
   and the menu shuts on the way to it. */
.usermenu .menupanel{top:100%}

/* Anchored to the logo, so it opens under the left corner rather than off the
   right edge where its trigger no longer is. */
.usermenu .menupanel{left:0;right:auto;min-width:216px}

/* Name, and the way out beneath it. Both flush left with the menu items below,
   so the panel reads as one column and not two arrangements stacked. */
.menuhead{display:flex;align-items:center;gap:10px;padding:9px 10px 11px}
/* Initials in a circle. It lives only here now - on every page it was one more
   thing telling you your own name. */
.menuhead .avatar{display:inline-flex;align-items:center;justify-content:center;
  width:36px;height:36px;flex:none;border-radius:50%;background:var(--accent);
  color:#fff;font-size:13px;font-weight:700;letter-spacing:.3px}
/* The name and the link are one block, so they sit tight together. Explicit
   line-heights, not just a small gap: the default leading is most of the space
   between two stacked lines of different sizes, and no gap value removes it. */
.menuhead .who{display:flex;flex-direction:column;align-items:flex-start;
  gap:0;min-width:0}
.menuhead .whoname{font-size:13.5px;font-weight:700;line-height:1.25;
  color:var(--ink);max-width:100%;white-space:nowrap;overflow:hidden;
  text-overflow:ellipsis}
.menuhead form{display:block;line-height:1.2}
/* A plain inline link. It posts - a GET sign-out is triggered by a prefetch or
   an <img> tag - but nothing about that is the reader's problem.
   Scoped to .menupanel deliberately: `.menupanel button` is a class AND a type
   selector, so a bare `.signout` loses to it and the button kept the 10px left
   padding every menu item has - which indented the link past the name it sits
   under. Measuring the BOX said they aligned; only the text disagreed. */
.menupanel .signout{display:inline;font:inherit;font-size:12.5px;line-height:1.2;
  color:var(--accent-ink);background:none;border:0;padding:0;width:auto;
  text-align:left;cursor:pointer}
.menupanel .signout:hover{text-decoration:underline;background:none}
.menupanel a.on{color:var(--accent-ink);background:var(--accent-soft)}

/* --------------------------------------------------------- needs attention
   A row of counters, each a link to where it gets cleared. Auto-fit rather
   than a fixed column count: the number of cards is however many things are
   actually wrong today, which is not something to hard-code. */
/* Six counters, ONE row. auto-fit at 196px put five across and dropped the
   sixth onto a line of its own, which read as a second, lesser group rather
   than as the last of six equal things. Fixed columns with minmax(0,...) so
   they divide the row evenly instead of sizing to their longest label. */
.attngrid{display:grid;gap:10px;margin:0 0 22px;
  grid-template-columns:repeat(6,minmax(0,1fr))}
@media (max-width:1180px){.attngrid{grid-template-columns:repeat(3,minmax(0,1fr))}}
@media (max-width:680px){.attngrid{grid-template-columns:repeat(2,minmax(0,1fr))}}
.attncard{display:flex;flex-direction:column;gap:1px;padding:12px 13px;
  background:var(--card);border:1px solid var(--line);border-left-width:3px;
  border-radius:6px;color:var(--ink)}
.attncard:hover{text-decoration:none;border-color:var(--accent);
  background:var(--accent-hint)}
.attncard.warn{border-left-color:var(--warn)}
.attncard.bad{border-left-color:var(--bad)}
/* Nothing outstanding. Green all the way round rather than just the edge, and
   a div, not a link - there is nothing on the other side to go and clear. */
.attncard.clear{position:relative;border-color:var(--good);cursor:default}
.attncard.clear:hover{background:var(--card);border-color:var(--good)}
.attntick{position:absolute;top:10px;right:11px;color:var(--good)}
.attnn{font-size:26px;font-weight:700;line-height:1.1;
  font-variant-numeric:tabular-nums}
.attncard.warn .attnn{color:var(--warn)}
.attncard.bad .attnn{color:var(--bad)}
.attncard.clear .attnn{color:var(--good)}
.attnlabel{font-size:13px;font-weight:600;color:var(--ink);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.attnsub{font-size:11px;color:var(--muted);line-height:1.35}

/* Air above the duplicate-name tick when it appears. It arrives between two
   other controls, and without it the question reads as part of the field
   above rather than as its own. */
#dupewarn:not([hidden]){display:block;padding-top:12px}

/* Pinned to the viewport, not to the block. .tlwrap is a horizontal scroller,
   and a scroll container clips its descendants no matter what z-index they
   carry - the panel has to leave the container entirely. position:fixed does
   that, and app.js puts the coordinates on it at open time.
   Restored to the normal anchored behaviour if the JS never runs. */
.tlmenu .menupanel{left:0;right:auto;top:calc(100% + 2px);z-index:60}
/* Capped to the window with its own scroll. Fourteen options is taller than
   the space above or below a block on a short screen, and without this the
   panel clamped to the top edge and lay across the very block it belongs to. */
.tlmenu .menupanel.floating{position:fixed;top:auto;left:auto;
  max-height:calc(100vh - 16px);overflow-y:auto}
.tlmenu.open .tlblock{outline:2px solid var(--accent);outline-offset:0}

/* ------------------------------------------------------------ split button
   Two actions that differ only in where they leave you, joined into one
   control. A hairline divider rather than a gap: apart, they read as a choice
   between saving and doing something else. */
.split{display:inline-flex}
.split .btn{border-radius:0}
.split .btn:first-child{border-top-left-radius:4px;border-bottom-left-radius:4px}
.split .btn:last-child{border-top-right-radius:4px;border-bottom-right-radius:4px}
.split .btn + .btn{border-left:1px solid rgba(255,255,255,.35)}
.split .btn + .btn{font-weight:600}

/* ------------------------------------------------------------------ toasts
   Bottom right, out of the flow. A bar at the top of the form pushed the whole
   page down to say one word, and had to be read before it could be ignored.
   pointer-events on the wrapper so a toast never swallows a click meant for
   whatever is under it. */
.toastwrap{position:fixed;right:18px;bottom:18px;z-index:80;
  display:flex;flex-direction:column;gap:8px;pointer-events:none}
.toast{display:flex;align-items:center;gap:9px;padding:11px 15px;
  border-radius:6px;font-size:13.5px;font-weight:600;
  box-shadow:0 6px 22px rgba(27,34,48,.18);pointer-events:auto;cursor:pointer;
  animation:toastin .18s ease-out}
.toast.good{background:var(--good);color:#fff}
.toast svg{flex:none}
/* Faded rather than removed on a timer, so it does not vanish mid-blink. The
   node goes when the transition ends. */
.toast.going{opacity:0;transform:translateY(6px);transition:opacity .25s,transform .25s}
@keyframes toastin{from{opacity:0;transform:translateY(8px)}
                   to{opacity:1;transform:none}}
@media (prefers-reduced-motion:reduce){
  .toast{animation:none}
  .toast.going{transition:none}
}

/* ------------------------------------------------------------- score boxes
   The number and the colour, nothing else. Everything that explains it - the
   band name, which instrument was measured, what the other one would read -
   is in the hover, where the detail already lives. A box carrying its own
   caption is not a box you read at a glance. */
/* Two halves of one control, joined edge to edge like a split button. The
   card loses its own padding so the colour block can reach the border, and
   clips so it inherits the corner radius. */
.trajcard{display:flex;align-items:stretch;padding:0;overflow:hidden}
.trajmain{flex:1;min-width:0;padding:12px}
.trajmain .traj{display:block;width:100%}

/* White, with the colour in the number and the word. A whole column of solid
   red was louder than the finding - the reading is one patient's latest score,
   not an alarm about the page. Divided from the chart by a rule rather than by
   a fill. */
/* A column, explicitly. An earlier revision dropped the base rule that said so
   and the number, the word and the count ran together on one line - which
   looked like a sentence rather than a reading. */
.scorebox{display:flex;flex-direction:column}
.trajcard .scorebox{flex:none;width:158px;border:0;border-radius:0;
  border-left:1px solid var(--line);background:var(--card);
  padding:16px 16px 14px;gap:2px;
  align-items:flex-start;justify-content:flex-start}
.trajcard .scoren{font-size:30px;font-weight:700;line-height:1.05;
  font-variant-numeric:tabular-nums}
.trajcard .scoreband{font-size:12.5px;font-weight:700;
  text-transform:uppercase;letter-spacing:.4px}
/* The count, quiet. Context for the score above it, not a second heading. */
.trajcard .scorefine{margin-top:8px;font-size:11px;line-height:1.4;
  color:var(--muted);font-weight:400;text-transform:none;letter-spacing:0}
/* The second line belongs to the first, so it sits against it rather than
   starting a new thought. */
.trajcard .scorefine.tight{margin-top:0}
.trajcard .scorebox.good  .scoren,.trajcard .scorebox.good  .scoreband{color:var(--good)}
.trajcard .scorebox.warn  .scoren,.trajcard .scorebox.warn  .scoreband{color:#a37a04}
.trajcard .scorebox.orange .scoren,.trajcard .scorebox.orange .scoreband{color:#b4620a}
.trajcard .scorebox.bad   .scoren,.trajcard .scorebox.bad   .scoreband{color:var(--bad)}
.trajcard .scorebox.none .scoren{color:var(--muted)}

/* Under the chart on a narrow screen, where a fixed column would squeeze the
   trajectory into something unreadable. */
@media(max-width:720px){
  .trajcard{flex-direction:column}
  .trajcard .scorebox{width:auto;border-left:0;border-top:1px solid var(--line)}
}

/* An estimate, visibly lighter than the measured value beside it. The whole
   point of the tooltip is that these two are not the same kind of number. */
.tip .est{color:#c9d4e0;font-weight:400}
.tip .tiprow .tipk{min-width:74px}
.tipwarn{margin-top:6px;padding-top:6px;border-top:1px solid rgba(255,255,255,.18);
  color:#f6c9c2;font-size:11px}

/* The confidence figure on a conversion card. Big enough to be the thing you
   look at, since "how much do I trust this" is why the page exists. */
.convconf{display:flex;flex-direction:column;align-items:flex-end;flex:none}
.convn{font-size:26px;font-weight:700;line-height:1;font-variant-numeric:tabular-nums}
.convn.good{color:var(--good)}
.convn.warn{color:#a37a04}
.convn.bad{color:var(--bad)}
.convlab{font-size:11px;font-weight:600;color:var(--muted);
  text-transform:uppercase;letter-spacing:.4px}

/* What would actually move this number. Set apart from the notes above it,
   because it is the one line on the card that says do something. */
.raiser{margin:12px 0 0;padding:10px 12px;background:var(--accent-hint);
  border-left:3px solid var(--accent);border-radius:0 4px 4px 0;
  font-size:12.5px;line-height:1.5}

/* ---------------------------------------------------------- questionnaires
   The form as a grid: one row per item, one column per answer. Radio buttons
   in a row are read across far faster than nine dropdowns are read down. */
.quiz{border:1px solid var(--line);border-radius:6px;padding:14px 16px;
  margin:0 0 16px}
.quizhead{display:flex;justify-content:space-between;align-items:flex-start;
  gap:16px;margin-bottom:12px}
/* The DOMAIN leads, the instrument names itself underneath - the same order the
   progress page uses, because that is what a doctor reads for. */
.quizhead h3{margin:0;font-size:15px}
.quizhead .sub{margin:2px 0 0;font-size:12px;color:var(--muted)}
.quizhead .q{font-weight:400}

/* The score, laid out like the trajectory cards: the index big and coloured,
   the band under it, and how it was arrived at in quiet type below both. The
   shared .scorebox rules give it the column; these give it the size and the
   right-hand alignment a form header wants. */
.quizhead .scorebox{flex:none;width:150px;align-items:flex-end;text-align:right;
  gap:2px}
.quizhead .scoren{font-size:28px;font-weight:700;line-height:1.05;
  font-variant-numeric:tabular-nums}
.quizhead .scoreband{font-size:12px;font-weight:700;text-transform:uppercase;
  letter-spacing:.4px}
.quizhead .scorebox.good   .scoren,.quizhead .scorebox.good   .scoreband{color:var(--good)}
.quizhead .scorebox.warn   .scoren,.quizhead .scorebox.warn   .scoreband{color:#a37a04}
.quizhead .scorebox.orange .scoren,.quizhead .scorebox.orange .scoreband{color:#b4620a}
.quizhead .scorebox.bad    .scoren,.quizhead .scorebox.bad    .scoreband{color:var(--bad)}
.quizhead .scorebox.none   .scoren{color:var(--muted)}
/* An empty span still takes a line box, which left a gap under the em dash
   while the form was half-filled. */
.quizhead .scoreband:empty{display:none}

.quizitems{width:100%;border-collapse:collapse}
.quizitems th{font-size:10.5px;text-transform:uppercase;letter-spacing:.3px;
  color:var(--muted);font-weight:600;padding:0 0 6px;vertical-align:bottom}
.quizitems th.qopt{width:88px;text-align:center;line-height:1.25}
/* Keeps the .hint look it had as a paragraph - it is a sentence to be read,
   not one of the shouted column labels beside it. */
/* Sits under the items it qualifies, not in a field row of its own. */
.quizdecline{margin-top:12px}
.quizdecline[hidden]{display:none}

.quizitems th.qlead{font-size:12px;text-transform:none;letter-spacing:0;
  font-weight:400;color:var(--muted);line-height:1.4;padding-right:14px;
  vertical-align:bottom}
.quizitems td{padding:7px 0;border-top:1px solid var(--line);font-size:13px}
.quizitems td.qtext{padding-right:14px;line-height:1.4}
.quizitems td.qopt{text-align:center}
/* The whole cell is the target, not the 13px dot inside it. */
.qradio{display:flex;align-items:center;justify-content:center;
  min-height:30px;cursor:pointer;margin:0}
.qradio input{width:auto;margin:0;cursor:pointer}
.qradio:hover{background:var(--accent-hint)}

/* PHQ-9 item 9 asks about self-harm. It is a safety question rather than a
   symptom count, and it should not look like the eight rows above it. */
.quizitems tr.alertitem td{background:#fffaf3}
.quizitems tr.alertitem td.qtext{font-weight:600}
.quizalert{margin-top:10px;padding:9px 12px;border-radius:4px;
  background:#fdecea;border-left:3px solid var(--bad);color:var(--bad);
  font-size:12.5px;font-weight:600}

/* The Beck totals. Collapsed, because they are history being corrected rather
   than something filled in today. */
.legacy{border:1px solid var(--line);border-radius:6px;padding:10px 14px}
.legacy summary{cursor:pointer;font-size:13px;font-weight:600;
  color:var(--muted)}
.legacy summary:hover{color:var(--ink)}
.legacy .grid{margin-top:12px}

@media(max-width:720px){
  .quizitems th.qopt{width:auto;font-size:9.5px}
  .quizitems td.qtext{font-size:12.5px}
}

/* ── Multi-select form field ────────────────────────────────────────────────
   Reads as a <select> does, because it sits in a grid beside real ones: the
   same box, the same --ctl height, the same chevron, and an em dash when
   nothing is picked. It borrows .dd-panel and .dd-opt from the filter
   dropdowns - the panel is identical, only what opening it means differs. */
.pick{position:relative}
.pickbtn{display:flex;align-items:center;width:100%;height:var(--ctl);
  padding:0 32px 0 10px;border:1px solid var(--line);border-radius:4px;
  background:#fff;font:inherit;color:var(--ink);cursor:pointer;text-align:left}
.pickbtn:hover{border-color:var(--accent)}
.pick.open .pickbtn{border-color:var(--accent);outline:2px solid var(--accent)}
/* The value can outrun the box - five complaints do. Truncating keeps the
   control the same size as its neighbours; the panel is where the full list
   is legible anyway. */
.pickval{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.pickval.q{color:var(--muted)}
.pick .dd-panel{min-width:100%;white-space:normal}
.pick.open .dd-panel{display:block}

/* ── Patient-record panels, inside the visit check-in ───────────────────────
   Opened by a "did anything change?" gate above. Set apart from the questions
   around them because these edit the PATIENT record rather than the visit, and
   that boundary should be visible before somebody types in one. */
.ptbox{margin-top:16px;padding:14px 16px 4px;border:1px solid var(--line);
  border-radius:6px;background:var(--bg)}
.ptbox[hidden]{display:none}
.pthead{margin-bottom:10px}
.pthead h3{margin:0;font-size:13px;text-transform:uppercase;letter-spacing:.5px;
  color:var(--muted)}
.pthead .hint{margin:2px 0 0}
/* The fields in a panel that is a plain grid rather than a table still need the
   panel's bottom padding to look deliberate. */
.ptbox > .grid{margin-bottom:10px}

/* ── One reading per domain, on a session ───────────────────────────────────
   The same score box the charts carry, laid out as a pair. Depression and
   anxiety side by side, because reading one without the other is half an
   answer. */
.scorepair{display:flex;gap:28px;flex-wrap:wrap}
.scorecell{flex:1 1 130px}
.scorelab{display:block;font-size:11px;font-weight:700;text-transform:uppercase;
  letter-spacing:.5px;color:var(--muted);margin-bottom:6px}
.scorepair .scorebox{gap:2px;align-items:flex-start}
.scorepair .scoren{font-size:30px;font-weight:700;line-height:1.05;
  font-variant-numeric:tabular-nums}
.scorepair .scoreband{font-size:12.5px;font-weight:700;text-transform:uppercase;
  letter-spacing:.4px}
/* A status a score cannot express - illegible, declined. A plain "not
   administered" never reaches here: absence is not content. */
.scorepair .scorefine{margin-top:8px;font-size:11px;line-height:1.4;
  color:var(--muted);font-weight:400;text-transform:none;letter-spacing:0}
.scorepair .scorebox.good   .scoren,.scorepair .scorebox.good   .scoreband{color:var(--good)}
.scorepair .scorebox.warn   .scoren,.scorepair .scorebox.warn   .scoreband{color:#a37a04}
.scorepair .scorebox.orange .scoren,.scorepair .scorebox.orange .scoreband{color:#b4620a}
.scorepair .scorebox.bad    .scoren,.scorepair .scorebox.bad    .scoreband{color:var(--bad)}
.scorepair .scorebox.none   .scoren{color:var(--muted)}

/* ── Patient check-in ───────────────────────────────────────────────────────
   One step per page, on whatever device is to hand. Sized for a finger: the
   admin --ctl of 38px is a mouse target, and this is not. */
.ckhead{margin-bottom:22px}
.ckstep{margin:0 0 6px;font-size:12px;font-weight:600;color:var(--muted);
  text-transform:uppercase;letter-spacing:.5px}
.ckbar{height:4px;background:var(--line);border-radius:2px;overflow:hidden;
  margin-bottom:18px}
.ckbar span{display:block;height:100%;background:var(--accent);
  transition:width .2s ease}
.ckhead h1{margin:0;font-size:26px;line-height:1.2}
.cklead{margin:8px 0 0;color:var(--muted);font-size:15px;line-height:1.5}
.ckform h2{font-size:16px;margin:26px 0 4px}
.cknote{margin:4px 0 14px;color:var(--muted);font-size:14px;line-height:1.5}
.ckform .field{margin-bottom:16px}
.ckform label{font-size:13px;text-transform:none;letter-spacing:0;
  color:var(--ink);font-weight:600;margin-bottom:6px}
.ckform input[type=text],.ckform input[type=email],.ckform input[type=tel],
.ckform input[type=date],.ckform input[type=number],.ckform select{
  height:46px;font-size:16px;padding:0 12px}
/* 16px minimum on every field: iOS zooms the whole page in on focus below it,
   and a page that jumps when you tap a box feels broken. */
.ckgrid{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));
  gap:0 18px}
.ckgrid .field.wide{grid-column:1/-1}
.ckrow{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));
  gap:0 14px;padding:12px 0;border-top:1px solid var(--line)}

/* The questionnaires. A tapped row, not a radio the size of a full stop. */
.ckitems{list-style:none;margin:0;padding:0;counter-reset:ckq}
.ckitems li{padding:18px 0;border-top:1px solid var(--line)}
.ckq{margin:0 0 12px;font-size:16px;line-height:1.45}
.ckopts{display:flex;flex-direction:column;gap:8px}
.ckopts.wrap{flex-direction:row;flex-wrap:wrap}
.ckopt{display:flex;align-items:center;gap:12px;margin:0;padding:12px 14px;
  border:1px solid var(--line);border-radius:6px;cursor:pointer;
  font-size:15px;font-weight:400;text-transform:none;letter-spacing:0;
  color:var(--ink);background:#fff}
.ckopt input{width:20px;height:20px;margin:0;flex:none;accent-color:var(--accent)}
.ckopt:has(input:checked){border-color:var(--accent);background:var(--accent-hint)}
.ckopt:hover{border-color:var(--accent)}

.ckactions{margin-top:28px;padding-top:20px;border-top:1px solid var(--line)}
.ckactions .btn{width:100%;height:52px;font-size:16px;justify-content:center}

.ckdone{text-align:center;padding:40px 0}
.ckdone svg{color:var(--good);margin-bottom:16px}
.ckdone h1{margin:0 0 10px;font-size:26px}
.ckdone p{color:var(--muted);font-size:15px;line-height:1.6;margin:0 auto;
  max-width:34em}

/* Staff side: the link, shown once. */
.linkcard .linkrow{display:flex;gap:10px;align-items:stretch;margin-top:12px}
.linkcard .linkrow input{flex:1;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;
  font-size:13px}
.plainlab{font-size:14px;text-transform:none;letter-spacing:0;font-weight:400;
  color:var(--ink);margin:0;cursor:pointer}

/* ------------------------------------------------------------- feedback */
/* The queue reads as a list of things to do, not a table: a bug report is a
   paragraph and a status, and columns would cut the paragraph short - which is
   the part somebody needs in order to recognise their own bug in it. */
.fblist{list-style:none;margin:0;padding:0}
.fbitem{display:flex;gap:16px;align-items:flex-start;padding:14px 0;
  border-bottom:1px solid var(--line)}
.fbitem.done .fbtitle b,.fbitem.declined .fbtitle b{text-decoration:line-through;
  text-decoration-color:var(--muted)}
.fbitem.done,.fbitem.declined{opacity:.72}
.fbmain{flex:1;min-width:0}
.fbtitle{display:flex;align-items:baseline;gap:8px;flex-wrap:wrap}
.fbtitle b{font-size:15px}
.fbdesc{margin:5px 0 0;white-space:pre-wrap;font-size:13.5px}
.fbmeta{margin:6px 0 0;font-size:12.5px}
.fbres{margin:8px 0 0;padding:7px 10px;border-left:2px solid var(--accent);
  background:var(--accent-hint);font-size:13px;border-radius:0 4px 4px 0}
.fbside{display:flex;flex-direction:column;align-items:flex-end;gap:6px;
  flex:0 0 auto}
/* Status, Save and Delete on one line; the note beneath, full width. The note
   is the field with something to hold, and it had 170px while three controls
   that fit their own contents shared the rest. */
.fbact{display:flex;flex-direction:column;gap:6px;width:258px}
.fbrow{display:flex;gap:6px;align-items:center}
.fbrow select{flex:1;min-width:0;width:auto}
.fbrow .btn{flex:0 0 auto}
.fbact input[type=text]{width:100%}
/* The kind tag. A bug and a request are read differently and should not have
   to be read - the colour does it. */
.tag{font-size:10.5px;letter-spacing:.06em;text-transform:uppercase;
  font-weight:700;padding:2px 6px;border-radius:3px;white-space:nowrap}
.tag.bug{background:#fdecea;color:var(--bad)}
.tag.feature{background:var(--accent-hint);color:var(--accent)}
@media (max-width:720px){
  .fbitem{flex-direction:column;gap:10px}
  .fbside{align-items:flex-start;width:100%}
  .fbact{width:100%}
}

/* ------------------------------------------------- report a problem button */
/* Fixed, bottom right, on every page. Low contrast until hovered: it has to be
   findable the moment something goes wrong and invisible the rest of the time -
   this sits over clinical work all day, and a bright circle in the corner of a
   patient's chart is a distraction on every screen to serve a few minutes a
   month. */
.bugbtn{position:fixed;right:20px;bottom:20px;z-index:60;
  width:42px;height:42px;border-radius:50%;
  display:flex;align-items:center;justify-content:center;
  background:var(--card,#fff);color:var(--muted);
  border:1px solid var(--line);box-shadow:0 2px 10px rgba(0,0,0,.10);
  transition:color .12s,border-color .12s,box-shadow .12s,transform .12s}
.bugbtn:hover,.bugbtn:focus-visible{color:var(--accent);border-color:var(--accent);
  box-shadow:0 4px 14px rgba(0,0,0,.16);transform:translateY(-1px)}
.bugbtn:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
/* The toast lands in this same corner on save. It is transient and sits above
   (z-index 80 against 60), so it covers the button for its two seconds rather
   than shoving it about - a control that moves when something unrelated
   happens is worse than one briefly hidden. */
@media print{.bugbtn{display:none}}


/* A "?" beside a label, with the answer on hover or focus.
   `.hint` was taken - it is a block of muted text - so this is its own name.
   Opens on focus as well as hover, because a control that only answers a mouse
   is one a keyboard user cannot read at all. */
.qmark{display:inline-flex;align-items:center;justify-content:center;
  width:15px;height:15px;margin-left:5px;border-radius:50%;
  border:1px solid var(--line);color:var(--muted);
  font-size:10px;font-weight:700;line-height:1;cursor:help;
  position:relative;vertical-align:middle;text-transform:none;letter-spacing:0}
.qmark:hover,.qmark:focus-visible{border-color:var(--accent);color:var(--accent)}
.qmark:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
.qtip{position:absolute;left:-8px;top:calc(100% + 7px);z-index:90;
  width:252px;padding:9px 11px;border-radius:5px;
  background:var(--ink);color:#fff;
  font-size:12px;font-weight:400;line-height:1.55;letter-spacing:0;
  text-align:left;text-transform:none;white-space:normal;
  box-shadow:0 3px 12px rgba(0,0,0,.22);
  opacity:0;visibility:hidden;transition:opacity .11s}
.qtip b{font-weight:600;white-space:nowrap}
/* The muted grey is unreadable on the dark panel - it is tuned for white. */
.qtip .q{color:#b9bfc9}
.qmark:hover .qtip,.qmark:focus-visible .qtip,.qmark:focus .qtip{
  opacity:1;visibility:visible}


/* Rooms or List. Same control as the site picker, and sized to its own content
   rather than the site picker's fixed width - it has two short options and no
   reflow to worry about. */
.viewpick select{height:var(--ctl);width:auto;font-size:13px;font-weight:600}
.viewpick{flex:none}
