/* Staff spend the day in Famly, whose portal sets its type in Matter — a
   commercial face — with Inter beside it. Inter is free, so it is the face here.
   Offline, the system sans takes over and nothing else changes. */
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap');

:root {
  /* Colours sampled from the Famly portal, so moving between the two feels like
     one system: a deep purple rail, lavender selection, near-white pages. */
  --bg: #fdfdfe;
  --bg-soft: #f7f6f9;
  --panel: #ffffff;
  --ink: #2e3137;
  --muted: #64657f;
  --line: #ececed;
  --line-strong: #c6c6d1;
  --brand: #4d1797;        /* the rail and primary buttons */
  --brand-hover: #7145ac;  /* the selected rail item */
  --accent: #6a0ac9;       /* links, selection, focus */
  --accent-soft: #f3eff9;
  --ok: #008a5c;
  --ok-soft: #e3f6ee;
  --warn: #a8620a;
  --warn-soft: #fdf3e3;
  --edit: #e8830c;         /* the frame round a day changed by hand */
  --bad: #c9001b;
  --bad-soft: #fdebed;
  --ecce: #6a0ac9;
  --ecce-soft: #f3eff9;
  /* Column rules carry the weekly sheet's grid; row rules are lighter so a long
     sheet does not turn into a wall of stripes. Softer than they were, to sit with
     the portal's flat lists, but kept: the sheet is typed into, not only read. */
  --grid-col: #d6d2e0;
  --grid-row: #ececed;
  --grid-strong: #b3abc4;  /* outer frame, and the rule between children */
  /* Every table in the portal is ruled the same way: a clear frame, rows a shade
     firmer than a hairline, and columns lighter still. */
  --tbl-frame: #c4bdd3;
  --tbl-row: #e4e1ea;
  --tbl-col: #e9e6ef;
  --radius: 8px;
  --shadow: 0 1px 2px rgba(46,49,55,.05);
  --rail-w: 88px;
}

* { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
body {
  margin: 0;
  font: 15px/1.5 Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  color: var(--ink);
  background: var(--bg);
}
/* Room for the rail on every page that has one. */
body.has-rail { padding-left: var(--rail-w); }
a { color: var(--accent); text-underline-offset: 2px; }

/* ---------- chrome: the purple rail down the left ---------- */
header.top {
  position: fixed; left: 0; top: 0; bottom: 0; z-index: 40; width: var(--rail-w);
  background: var(--brand); color: #fff;
  display: flex; flex-direction: column; gap: 4px; padding: 14px 8px;
}
.brand {
  display: grid; place-items: center; width: 44px; height: 44px; margin: 0 auto 14px;
  border-radius: 12px; background: rgba(255,255,255,.16); color: #fff;
  font-weight: 700; font-size: 15px; letter-spacing: .02em; text-decoration: none;
}
nav.top { display: flex; flex-direction: column; gap: 4px; }
nav.top a {
  display: flex; flex-direction: column; align-items: center; gap: 4px;
  padding: 9px 2px 7px; border-radius: 10px; text-decoration: none; text-align: center;
  color: rgba(255,255,255,.82); font-size: 11px; font-weight: 500; line-height: 1.15;
}
nav.top a svg { width: 22px; height: 22px; }
nav.top a:hover { background: rgba(255,255,255,.1); color: #fff; }
nav.top a.on { background: var(--brand-hover); color: #fff; }
.spacer { flex: 1; }
#headerSlot { color: #fff; font-size: 11px; text-align: center; overflow-wrap: anywhere; }
#headerSlot a { color: #fff; }
#headerSlot button, #headerSlot .btn {
  background: transparent; color: #fff; border-color: rgba(255,255,255,.4);
  font-size: 11px; padding: 5px 4px; width: 100%;
}
/* A phone is too narrow to give up a column, so the rail lies along the top. */
@media (max-width: 700px) {
  body.has-rail { padding-left: 0; }
  header.top { position: sticky; bottom: auto; width: auto; flex-direction: row;
               align-items: center; padding: 6px 10px; }
  .brand { margin: 0 8px 0 0; width: 36px; height: 36px; }
  nav.top { flex-direction: row; }
  nav.top a { padding: 6px 8px; }
}

main { padding: 26px 24px 80px; max-width: 1760px; margin: 0 auto; }
h1 { font-size: 26px; font-weight: 500; margin: 0 0 4px; letter-spacing: -.015em; }
h2 { font-size: 17px; font-weight: 600; margin: 26px 0 10px; }
.sub { color: var(--muted); font-size: 13.5px; margin: 0 0 18px; }

.panel {
  background: var(--panel); border: 1px solid var(--line);
  border-radius: var(--radius); box-shadow: var(--shadow); padding: 16px;
  margin-bottom: 16px;
}

/* ---------- controls ---------- */
button, .btn {
  font: inherit; font-size: 14px; font-weight: 500; line-height: 1.4; cursor: pointer;
  background: var(--panel); color: var(--ink);
  border: 1px solid var(--line-strong); border-radius: 6px;
  padding: 7px 14px; text-decoration: none; display: inline-block;
}
button:hover, .btn:hover { background: var(--bg-soft); border-color: #aeaebd; }
button.primary, .btn.primary { background: var(--brand); border-color: var(--brand); color: #fff; }
button.primary:hover, .btn.primary:hover { background: var(--brand-hover); border-color: var(--brand-hover); }
button:disabled { opacity: .5; cursor: default; }
input, select, textarea {
  font: inherit; font-size: 14px; color: var(--ink); background: var(--panel);
  border: 1px solid var(--line-strong); border-radius: 6px; padding: 7px 10px;
}
input::placeholder { color: #9a9bb0; }
input:focus, select:focus, textarea:focus {
  outline: 3px solid var(--accent-soft); outline-offset: 0; border-color: var(--accent);
}
/* No spinner arrows on number boxes: nobody steps an hourly rate by 1, and in a
   narrow register cell the arrows crowd out the number itself. */
input[type="number"] { -moz-appearance: textfield; appearance: textfield; }
input[type="number"]::-webkit-inner-spin-button,
input[type="number"]::-webkit-outer-spin-button { -webkit-appearance: none; margin: 0; }
label.field { display: block; margin-bottom: 10px; font-size: 12px; color: var(--muted); }
label.field span { display: block; margin-bottom: 3px; font-weight: 500; }
label.field input, label.field select { width: 100%; }

.toolbar { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; }

/* ---------- badges ---------- */
.badge {
  display: inline-block; padding: 1px 7px; border-radius: 999px;
  font-size: 11.5px; font-weight: 600; white-space: nowrap;
}
.badge.ok   { background: var(--ok-soft);   color: var(--ok); }
.badge.warn { background: var(--warn-soft); color: var(--warn); }
.badge.bad  { background: var(--bad-soft);  color: var(--bad); }
.badge.flat { background: #f1f1f4; color: var(--muted); }
.badge.ecce { background: var(--ecce-soft); color: var(--ecce); }

/* ---------- week strip ---------- */
.weekbar {
  position: sticky; top: var(--header-h, 57px); z-index: 30;
  background: var(--panel); border-bottom: 1px solid var(--line);
  padding: 8px 24px; display: flex; align-items: flex-start; gap: 10px;
}
.weekbar .weeks { flex: 1; }
.weekbar .years { display: flex; align-items: center; gap: 4px; }
.weekbar .years b { font-variant-numeric: tabular-nums; min-width: 3.4em; text-align: center; }
.weeks { display: flex; flex-wrap: wrap; gap: 3px; }
/* Fixed width so W1 and W52 are the same size, as a row of tabs should be. */
.weeks button {
  width: 42px; padding: 4px 0; text-align: center; font-size: 12px;
  font-variant-numeric: tabular-nums; border-radius: 4px;
}
.weeks button.on {
  background: var(--brand); border-color: var(--brand); color: #fff; font-weight: 650;
}
.weeks button.now:not(.on) { border-color: var(--accent); color: var(--accent); font-weight: 650; }
.weeks button.future { opacity: .45; }

/* ---------- weekly sheet ---------- */
/* border-collapse stays `separate` because collapsed borders are dropped from
   position:sticky cells in WebKit; each cell therefore paints its own right and
   bottom rule, and the first row and column paint the top and left of the frame. */
/* Dense on purpose: a week of forty-odd children is meant to be checked at a
   glance and typed straight down, so a row is one line tall and every day column
   is the same width — `table-layout: fixed` with only the two end columns sized,
   which leaves the days an equal share of what is left. */
.sheet { width: auto; table-layout: fixed; border-collapse: separate; border-spacing: 0;
         background: var(--panel); font-size: 13px; }
.sheet th, .sheet td {
  padding: 0;
  border-right: 1px solid var(--tbl-col);
  border-bottom: 1px solid var(--tbl-row);
}
/* Alternating rows and a lit row under the cursor or the caret: on a grid this
   tight, they are what keeps the eye on one child across five days. */
.sheet tbody tr:nth-child(even) > td { background: #fbfafd; }
.sheet tbody tr:hover > td, .sheet tbody tr:focus-within > td { background: var(--accent-soft); }
.sheet th:first-child, .sheet td:first-child,
table.grid th:first-child, table.grid td:first-child { border-left: 1px solid var(--tbl-frame); }
.sheet th:last-child, .sheet td:last-child,
table.grid th:last-child, table.grid td:last-child { border-right: 1px solid var(--tbl-frame); }
.sheet thead th, table.grid thead th { border-top: 1px solid var(--tbl-frame); }
.sheet tbody tr:last-child td,
table.grid tbody tr:last-child td { border-bottom: 1px solid var(--tbl-frame); }
/* Rounded like the panels, so a table reads as one of them. */
.sheet thead tr:first-child th:first-child,
table.grid thead tr:first-child th:first-child { border-top-left-radius: var(--radius); }
.sheet thead tr:first-child th:last-child,
table.grid thead tr:first-child th:last-child { border-top-right-radius: var(--radius); }
.sheet tbody tr:last-child td:first-child,
table.grid tbody tr:last-child td:first-child { border-bottom-left-radius: var(--radius); }
.sheet tbody tr:last-child td:last-child,
table.grid tbody tr:last-child td:last-child { border-bottom-right-radius: var(--radius); }
/* No scroll box around the sheet: the page itself is the scroller, so the table
   runs the full width of the page and one scroll gesture moves the whole thing.
   The header row therefore sticks below the nav and week strip, not at 0. */
.sheet thead th {
  position: sticky; top: calc(var(--sticky-top, 130px) - 1px); z-index: 20;
  background: var(--panel); border-bottom: 1px solid var(--tbl-frame);
  padding: 5px 7px; text-align: left; font-size: 11.5px; color: var(--muted);
  font-weight: 600; white-space: nowrap; overflow: hidden;
}
.sheet thead th .dow { color: var(--ink); font-weight: 650; }
.sheet thead th .dte { color: var(--muted); font-weight: 500; }
/* A day marker small enough to sit on the header's one line. */
.chip { display: inline-block; padding: 0 5px; border-radius: 999px;
        font-size: 10px; font-weight: 700; line-height: 15px; }
.chip.ecce { background: var(--ecce-soft); color: var(--ecce); }
.chip.bad { background: var(--bad-soft); color: var(--bad); }
.sheet thead th.weekend { background: var(--bg-soft); }
.sheet thead th.closed { background: var(--bad-soft); color: var(--bad); }
/* Today's column, so the eye lands on the day being typed without hunting along
   the header. Tinted rather than outlined: every day column is the same width by
   design, and a border on one of them would shift the grid. The accent is what
   marks the current thing elsewhere, and the tint deepens through the striped and
   hovered rows so neither loses to the other. */
.sheet thead th.today { background: var(--accent-soft); }
.sheet thead th.today .dow, .sheet thead th.today .dte { color: var(--accent); }
.sheet tbody tr > td.today { background: #f7f2fd; }
.sheet tbody tr:nth-child(even) > td.today { background: #f2ebfb; }
.sheet tbody tr:hover > td.today, .sheet tbody tr:focus-within > td.today {
  background: #e9defa;
}

.who {
  padding: 8px 12px !important; width: 250px; vertical-align: middle;
  overflow: hidden;
}
/* The child's face beside their name, small enough to leave the row one line
   tall. The name and its detail share what is left of the column. */
.who .whorow { display: flex; align-items: center; gap: 7px; min-width: 0; }
.who .whotext { min-width: 0; }
.who .whorow { gap: 10px; }
.who .avatar { width: 34px; height: 34px; font-size: 12px; }
.who .nm { display: flex; align-items: center; gap: 5px; font-weight: 600; font-size: 14px;
           line-height: 1.25; white-space: nowrap; }
.who .nm a { overflow: hidden; text-overflow: ellipsis; color: inherit; text-decoration: none; }
.who .nm a:hover { color: var(--accent); }
.who .meta { font-size: 11px; color: var(--muted); line-height: 1.25;
             white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.who .meta b { color: var(--ink); font-weight: 600; }

/* the editable cell: one line — arrival, departure, hours */
.cell { display: flex; align-items: center; justify-content: center; gap: 2px;
        padding: 8px 6px; flex-wrap: wrap;
        position: relative; border-radius: 5px; }
.cell input {
  /* Boxes give way before the page does: they shrink towards a narrow day column
     instead of forcing the sheet wider than the window. */
  flex: 0 1 50px; min-width: 0;
  text-align: center; padding: 2px 1px; font-size: 11.5px; border-radius: 4px;
  font-variant-numeric: tabular-nums; border-color: var(--line-strong);
}
.cell input:placeholder-shown { border-color: var(--line); background: var(--bg-soft); }
.cell .dash { color: var(--muted); font-size: 11px; }
.cell .hrs {
  flex: none; width: 1.9em; text-align: right; font-size: 10.5px; color: var(--muted);
  font-variant-numeric: tabular-nums;
}
/* A day the session cuts: the ECCE hours are in the tooltip and on the report, so
   the cell only has to say that it was cut. */
.cell.hasecce .hrs { color: var(--ecce); font-weight: 600; }
/* No fixed day width: the days share whatever the window has left, so a week,
   weekend included, fits without scrolling sideways. */
td.day { min-width: 0; }
.sheet th:not(.who):not(.tot) { width: 150px; }
td.day.weekend { background: var(--bg-soft); }
td.day.closed { background: repeating-linear-gradient(45deg, transparent, transparent 6px, var(--bad-soft) 6px, var(--bad-soft) 12px); }
/* A day somebody changed by hand: the whole cell is framed in orange, and the
   hover card says who changed it and from what. */
.cell.edited { box-shadow: inset 0 0 0 2px var(--edit); }
.cell .undo {
  position: absolute; top: 1px; right: 1px; width: 16px; height: 16px; padding: 0;
  border-radius: 50%; border: 1px solid var(--edit); background: var(--panel);
  color: var(--edit); font-size: 10px; line-height: 1; cursor: pointer; display: none;
}
.cell:hover .undo:not([hidden]), .cell:focus-within .undo:not([hidden]) { display: block; }
.celltip {
  position: fixed; z-index: 50; max-width: 280px; padding: 8px 10px;
  background: var(--panel); color: var(--ink); font-size: 12px; line-height: 1.4;
  border: 1px solid var(--line-strong); border-radius: 6px;
  box-shadow: 0 4px 14px rgba(46,49,55,.14); pointer-events: none;
}
.celltip .tiphead { font-weight: 650; color: var(--edit); margin-bottom: 4px; }
.celltip .tipchange { padding: 3px 0; border-top: 1px solid var(--line); }
.celltip .tipwhen { font-size: 11px; color: var(--muted); }
.celltip .was { color: var(--muted); text-decoration: line-through; }
.celltip .tipnote { margin-top: 4px; font-size: 11px; color: var(--muted); }
.celltip .tipbad { margin-top: 4px; color: var(--bad); }
.cell.bad input { border-color: var(--bad); background: var(--bad-soft); }
.cell.saving { opacity: .55; }

.tot { padding: 8px 10px !important; text-align: right; white-space: nowrap;
       font-variant-numeric: tabular-nums; width: 84px; font-size: 13px; }
.tot.first { border-left: 1px solid var(--tbl-frame); }
.sheet thead th.tot { text-align: right; }
td.tot.ecce { color: var(--ecce); }
.tot .totline { display: flex; align-items: center; justify-content: flex-end; gap: 4px;
                line-height: 1.25; }
.tot .big { font-size: 13px; font-weight: 650; }
.tot .ecce { color: var(--ecce); font-size: 11px; font-weight: 600; }
.tot .lbl { font-size: 11px; color: var(--muted); }

/* ---------- generic table ---------- */
/* Ruled like the weekly sheet (the frame and rules are set beside it, above), with
   the table itself as the frame. */
table.grid { width: 100%; border-collapse: separate; border-spacing: 0; font-size: 14px;
             background: var(--panel); }
table.grid th, table.grid td {
  padding: 10px 12px; text-align: left; vertical-align: middle;
  border-bottom: 1px solid var(--tbl-row); border-right: 1px solid var(--tbl-col);
}
/* A panel that only holds a table would draw a second frame round the first. */
.panel:has(> table.grid:only-child) {
  border: 0; box-shadow: none; background: transparent;
}
/* No table scrolls inside the page — the page is the only scroller — so the
   header pins to the top of the window, or below the bar a phone lays along the
   top, which mountHeader measures into --header-h. */
table.grid th {
  position: sticky; top: var(--header-h, 0px); background: var(--panel); z-index: 5;
  font-size: 13px; font-weight: 500; color: var(--muted);
  border-bottom-color: var(--tbl-frame);
}
/* Cells shrink to fit the page rather than pushing it sideways. A long email is
   clipped inside its box; the whole value is there once the box has focus. */
table.grid td input, table.grid td select { width: 100%; min-width: 0; }
table.grid tbody tr:hover { background: var(--bg-soft); }
table.grid td.num { text-align: right; font-variant-numeric: tabular-nums; }

/* ---------- register ---------- */
/* A compact list — one line per child, carrying only what says whether the record
   is done — and one child's full record opened beneath their line to fill in. */
.rlist tbody tr { scroll-margin-top: 52px; }
.rlist tbody td { cursor: pointer; }
.rlist tr.open > td { background: var(--accent-soft); }
.rname { display: flex; align-items: center; gap: 10px; font-weight: 500; }
.rname small { display: block; color: var(--muted); font-weight: 400; font-size: 12px; line-height: 1.2; }
.avatar {
  display: inline-grid; place-items: center; flex: none; width: 34px; height: 34px;
  border-radius: 50%; background: var(--accent-soft); color: var(--brand);
  font-size: 12px; font-weight: 600;
}
img.avatar { object-fit: cover; }
.rlist tr.open span.avatar { background: var(--brand); color: #fff; }
.chev { display: inline-block; color: var(--muted); font-size: 20px; line-height: 1;
        transition: transform .15s ease; }
.rlist tr.open .chev { transform: rotate(90deg); color: var(--brand); }
.todo { color: var(--warn); font-weight: 500; white-space: nowrap; }
.done { color: var(--ok); font-weight: 500; white-space: nowrap; }
.flags { display: flex; gap: 4px; flex-wrap: wrap; margin-top: 4px; }

.rlist tr.editor-row:hover { background: transparent; }
.rlist td.reditor-cell { padding: 0; cursor: default; background: var(--bg-soft); }
.reditor { padding: 16px 16px 18px; border-bottom: 2px solid var(--accent-soft); }
.reditor .sections { display: grid; gap: 12px;
                     grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); }
.rsection { background: var(--panel); border: 1px solid var(--line);
            border-radius: var(--radius); padding: 12px 14px 14px; }
.rsection h3 { margin: 0 0 10px; font-size: 11.5px; font-weight: 600; letter-spacing: .07em;
               text-transform: uppercase; color: var(--brand); }
/* Boxes line up along their bottoms, so a label that wraps to two lines does not
   drop its own box below its neighbour's. */
.rfields { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px 10px;
           align-items: end; }
.rf { display: block; min-width: 0; font-size: 12px; font-weight: 500; color: var(--muted); }
.rf > span { display: block; margin-bottom: 3px; }
.rf.wide { grid-column: 1 / -1; }
.rf input:not([type="checkbox"]), .rf select { width: 100%; font-size: 14px; padding: 6px 9px; }
.rf.check { display: flex; align-items: center; gap: 8px; align-self: end;
            padding-bottom: 8px; color: var(--ink); }
.rf.check > span { margin: 0; }
.rf .gender { display: flex; align-items: center; gap: 8px; min-height: 33px; }
.rf .gicon { display: inline-flex; align-items: center; gap: 5px; padding: 4px 11px 4px 8px;
  border: 1px solid var(--line); border-radius: 999px; font-size: 13px; font-weight: 600;
  color: var(--muted); opacity: .45; }
.rf .gicon b { font-size: 17px; line-height: 1; }
.rf .gicon.on { opacity: 1; color: #fff; }
.rf .gicon.boy.on { background: #2f6fd6; border-color: #2f6fd6; }
.rf .gicon.girl.on { background: #d63f86; border-color: #d63f86; }
.rf.check input { width: 16px; height: 16px; margin: 0; accent-color: var(--brand); }
/* A blank field a return needs: amber, and named as required. */
.rf.missing input, .rf.missing select { border-color: #e2a855; background: var(--warn-soft); }
.rf.missing > span::after { content: " · required"; color: var(--warn); }
.reditor .foot { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; margin-top: 14px; }

/* ---------- statistics heat row ---------- */
.heat { display: flex; gap: 3px; }
/* The squares take whatever the other columns leave: `width: 100%` on one cell of
   an auto-layout table hands it the slack rather than widening the table. */
table.grid td.heatcell, table.grid thead th:last-child { width: 100%; }
/* Squares share the cell's width, so a year of weeks fits the page. A square too
   narrow for its number hides the text, which is still in the tooltip. The cell
   takes no percentage width: in an auto-layout table that makes the table grow
   past the page to honour it. */
.heat i {
  /* width 0 and inline-size containment: the number inside must not count towards
     the column's minimum width, or 52 squares of text force the table wider. */
  flex: 1 1 0; width: 0; min-width: 0; max-width: 22px; contain: inline-size;
  overflow: hidden; white-space: nowrap;
  height: 22px; border-radius: 2px; display: block;
  font-style: normal; font-size: 10px; line-height: 22px; text-align: center;
  font-variant-numeric: tabular-nums; color: #22282e;
}
.heat i.off { background: #f4f5f7; color: transparent; }   /* not on the roll */
.heat i.na  { background: #d7dbe0; color: #4a525a; }  /* present, but no claim to measure */
.heat i.ok  { background: #9fd3b4; }
.heat i.mid { background: #f5cf8e; }
.heat i.low { background: #ef9b8f; }
.heat i.out { background: #b4291f; color: #fff; }
/* Measured against a claim that has since lapsed: same reading, less authority. */
.heat i.lapsed { opacity: .5; box-shadow: inset 0 0 0 1px rgba(0,0,0,.18); }

/* Spaced like the register, with each child's photo, and squares big enough to
   read the number in them at a glance. */
.stats { font-size: 14px; }
.stats th, .stats td { padding: 8px 12px; white-space: nowrap; }
/* The child as the weekly sheet and register show them: photo, then name. */
.stats a.kid { display: inline-flex; align-items: center; gap: 10px; font-weight: 600;
               color: inherit; text-decoration: none; }
.stats a.kid:hover { color: var(--accent); }
.stats .heat { gap: 3px; }
.stats .heat i {
  height: 30px; line-height: 30px; max-width: 38px; font-size: 12.5px; font-weight: 600;
  border-radius: 4px;
}
.stats .streakcell { display: inline-flex; align-items: center; gap: 6px; }
.stats .badge { font-size: 12px; padding: 1px 8px; }

/* The two points where the scheme requires something: the parent notified at
   eight weeks, Pobal levelling at twelve. A flag rather than a darker shade,
   because they are obligations rather than a worse version of the same number. */
.flagicon { display: inline-flex; line-height: 0; }
.flagicon.warn { color: #d08700; }
.flagicon.bad { color: var(--bad); }

/* A page given over to one wide table has no use for the reading-width limit. */
main.wide { max-width: none; }

/* ---------- alerts ---------- */
.alert { display: flex; gap: 12px; padding: 12px 14px; border-radius: var(--radius);
         border: 1px solid var(--line); background: var(--panel); margin-bottom: 8px; }
.alert .bar { width: 4px; border-radius: 3px; flex: none; }
.alert.critical { background: var(--bad-soft); border-color: #f3c9c5; }
.alert.critical .bar { background: var(--bad); }
.alert.action   { background: var(--warn-soft); border-color: #f0dcbc; }
.alert.action .bar { background: var(--warn); }
.alert.warning .bar { background: #d9b45f; }
.alert h4 { margin: 0 0 3px; font-size: 14px; }
.alert p { margin: 0; font-size: 13px; color: var(--muted); }
.alert .who2 { font-weight: 600; }

.stat-row { display: flex; gap: 12px; flex-wrap: wrap; }
.stat {
  flex: 1 1 150px; background: var(--panel); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 12px 14px; box-shadow: var(--shadow);
}
.stat b { display: block; font-size: 26px; font-weight: 650; letter-spacing: -.02em; }
.stat span { font-size: 12px; color: var(--muted); }
.stat.bad b { color: var(--bad); }
.stat.warn b { color: var(--warn); }

#toast {
  position: fixed; bottom: 18px; left: 50%; transform: translateX(-50%) translateY(120%);
  background: #16191d; color: #fff; padding: 9px 16px; border-radius: 999px;
  font-size: 13px; z-index: 100; transition: transform .18s ease; max-width: 90vw;
}
#toast.show { transform: translateX(-50%) translateY(0); }
#toast.err { background: var(--bad); }

.empty { color: var(--muted); padding: 30px; text-align: center; }
/* Was a scroll box with its own scrollbars. Tables now render at full size on the
   page, so the class is kept only so the pages that use it need no edit. */
.scroll { overflow: visible; }

/* ---------- printable weekly report ---------- */
/* The page is the workbook's printed weekly sheet: the same left-hand child
   block, the same five day groups, the same programme rows. What it adds is the
   pair that the spreadsheet never printed — claimable whole hours in bold with
   the exact time attended in grey underneath — so the rounding is auditable on
   paper rather than only inside a formula. */
.report { padding: 16px 18px 60px; }
.toolbar.noprint { padding: 12px 18px; border-bottom: 1px solid var(--line);
                   background: var(--panel); position: sticky; top: 0; z-index: 5; }

.rhead { display: flex; align-items: flex-end; gap: 26px; flex-wrap: wrap;
         margin-bottom: 12px; }
.rhead .title h1 { font-size: 17px; margin: 0; }
.rhead .title .org { color: var(--muted); font-size: 13px; }
.rhead .fields { display: flex; gap: 18px; flex-wrap: wrap; }
.rhead .f span { display: block; font-size: 10px; text-transform: uppercase;
                 letter-spacing: .04em; color: var(--muted); }
.rhead .f b { font-size: 14px; font-variant-numeric: tabular-nums; }
.rhead .headline { margin-left: auto; display: grid; grid-auto-flow: column;
                   grid-template-rows: auto auto auto; gap: 1px 16px;
                   text-align: right; }
.rhead .headline b { font-size: 19px; font-variant-numeric: tabular-nums; }
.rhead .headline .exact { font-size: 11px; color: var(--muted);
                          font-variant-numeric: tabular-nums; }
.rhead .headline .lbl { font-size: 10.5px; color: var(--muted); }

/* Sized to the page on screen, as it is to the sheet on paper: the percentage
   column widths scale the grid down rather than scrolling it sideways, and text
   breaks inside its column instead of spilling into the next one. */
.rscroll { padding-bottom: 4px; }
table.rgrid {
  width: 100%; table-layout: fixed; overflow-wrap: anywhere;
  border-collapse: collapse; font-size: 10.5px; font-variant-numeric: tabular-nums;
}
table.rgrid th, table.rgrid td {
  border: 1px solid var(--grid-row); padding: 2px 4px; text-align: left;
  vertical-align: top;
}
table.rgrid thead th { background: var(--bg); font-weight: 600; font-size: .9em;
                       line-height: 1.15; vertical-align: bottom; }
table.rgrid tr.group th { background: var(--accent-soft); color: var(--accent);
                          text-align: center; font-size: .95em; letter-spacing: .03em;
                          text-transform: uppercase; }
table.rgrid tr.group th.weekend { background: var(--bg); color: var(--muted); }
table.rgrid tr.group th.closed { background: var(--bad-soft); color: var(--bad); }
table.rgrid .num { text-align: right; }
table.rgrid .tin { text-align: center; }
/* Times and dates never break mid-figure — "08:5" over "4" cannot be read — and
   headers break between words only. */
table.rgrid .tin, table.rgrid .date {
  white-space: nowrap; overflow-wrap: normal; padding-left: 1px; padding-right: 1px;
  font-size: .94em;
}
table.rgrid thead th { overflow-wrap: break-word; hyphens: auto; }
/* Figures and initials stay on one line: "1" over "0" reads as two numbers. */
table.rgrid td.num, table.rgrid .dh, table.rgrid .ini {
  white-space: nowrap; overflow-wrap: normal;
}
table.rgrid .dh, table.rgrid .ini, table.rgrid td:first-child, table.rgrid th:first-child {
  padding-left: 1px; padding-right: 1px; text-align: center;
}
/* A narrow window gets a smaller grid rather than a sideways scroll. */
@media screen and (max-width: 1150px) {
  table.rgrid { font-size: 9px; }
}
table.rgrid .ini { text-align: center; color: var(--muted); overflow: hidden; }
table.rgrid td.weekend { background: var(--bg); }
table.rgrid td.closed { background: var(--bad-soft); }

/* Each child is one tbody, so the programme rows never split across a page. */
tbody.kid { break-inside: avoid; page-break-inside: avoid; }
tbody.kid > tr:first-child > td { border-top: 1.4px solid var(--grid-strong); }
tbody.kid .nm { font-weight: 650; font-size: 1.08em; line-height: 1.15; }
tbody.kid .seg { color: var(--muted); font-size: .9em; line-height: 1.15; }
tbody.kid .seg.ecce { color: var(--ecce); background: var(--ecce-soft); font-weight: 600; }
tbody.kid tr.note td { color: var(--warn); background: var(--warn-soft); font-size: .9em; }
.rgrid .flag { color: var(--bad); font-weight: 600; }
.rgrid .na { color: var(--muted); }

/* the rounded/exact pair, wherever it appears */
.rgrid .sum b, .rgrid .seg b { display: block; font-size: 1.15em; line-height: 1.1; }
.rgrid .exact { display: block; font-size: .88em; color: var(--muted); line-height: 1.1; }
.rgrid td.sum { background: #fbfcfd; }
.rgrid td.sum.ecce b { color: var(--ecce); }
/* Named `status`, not `alert`: `.alert` is already the dashboard's card, and it
   sets display:flex, which on a <td> drops the cell out of the column flow and
   shifted every programme row one column left. */
.rgrid td.status { line-height: 1.15; }
.rgrid td.status b { display: block; font-size: .95em; }
.rgrid td.status.ok   b { color: var(--ok); }
.rgrid td.status.bad  b { color: var(--bad); }
.rgrid td.status.warn b { color: var(--warn); }

table.rgrid tfoot td { border-top: 1.4px solid var(--grid-strong);
                       background: var(--bg); font-weight: 600; }
table.rgrid tfoot .lbl { font-weight: 500; color: var(--muted); }
table.rgrid tfoot .lbl b { color: var(--ink); font-weight: 650; }
table.rgrid td.daytot { text-align: center; }
table.rgrid td.daytot b { font-size: 1.1em; }
table.rgrid td.daytot span { display: block; font-size: .9em; font-weight: 500;
                             color: var(--ecce); }

.rfoot { margin-top: 14px; font-size: 11px; color: var(--muted); max-width: 100%; }
.rfoot p { margin: 0 0 10px; line-height: 1.5; }
.rfoot b { color: var(--ink); }
.rfoot .sign { display: flex; gap: 40px; margin: 18px 0 10px; font-size: 11px; }
.rfoot .sign .rule { display: inline-block; width: 180px; margin-left: 8px;
                     border-bottom: 1px solid var(--line-strong); }
.rfoot .gen { font-size: 10px; }

@media print {
  /* Paper size and orientation are set by the page that needs them — the weekly
     report asks for landscape in its own <style>. Setting it here would put every
     printed page, the register included, on its side. */
  html, body { background: #fff; }
  .noprint, header.top, .weekbar, #toast { display: none !important; }
  body.has-rail { padding-left: 0; }
  .report { padding: 0; }
  /* Column headers repeat on every sheet of paper; without this the second page
     of a 60-child week is a grid of unlabelled times. */
  table.rgrid thead { display: table-header-group; }
  table.rgrid tfoot { display: table-footer-group; }
  .rscroll { overflow: visible; }
  table.rgrid { font-size: 8.4px; min-width: 0; }
  table.rgrid th, table.rgrid td { padding: 1px 4px; }
  .rhead { flex-wrap: nowrap; gap: 16px; margin-bottom: 8px; }
  .rhead .title h1 { font-size: 13px; }
  .rhead .fields { gap: 12px; }
  .rhead .headline b { font-size: 15px; }
  table.rgrid th, table.rgrid td { line-height: 1.15; }
  .rfoot { break-inside: avoid; page-break-inside: avoid; }
  a { color: inherit; text-decoration: none; }
  * { -webkit-print-color-adjust: exact; print-color-adjust: exact; }
}

/* ---------- signed in: who, which service, and what they may do ---------- */
/* "Edited by AB" under a day's times. An untouched Famly import shows nothing,
   so the line only appears where somebody changed the hours by hand. */
.cell .by {
  flex-basis: 100%; text-align: center; font-size: 10px; line-height: 1.25;
  color: var(--accent);
}
.cell .by:empty { display: none; }
button.linkish {
  border: 0; background: none; padding: 0; font: inherit; font-size: 10px;
  color: var(--accent); text-decoration: underline; cursor: pointer;
}
/* Hidden from staff, who record hours but do not change the register or settings. */
body.staff .manager-only { display: none !important; }

/* The account sits at the foot of the purple rail, so it is written in white
   rather than the muted grey a white top bar used to call for. */
header.top .account {
  display: flex; flex-direction: column; align-items: stretch; gap: 6px;
  font-size: 11.5px; text-align: center; color: rgba(255,255,255,.85);
}
header.top .account a {
  color: rgba(255,255,255,.85); text-decoration: none; padding: 5px 4px;
  border-radius: 8px; background: rgba(255,255,255,.12); font-weight: 600;
}
header.top .account a:hover, header.top .account a.on { color: #fff; background: var(--brand-hover); }
header.top .account select {
  background: rgba(255,255,255,.12); color: #fff; border-color: rgba(255,255,255,.35);
  font-size: 11px; padding: 4px 6px; width: 100%;
}
header.top .account select option { color: var(--ink); }
header.top .account button.linkish { color: rgba(255,255,255,.85); font-size: 11px; }
header.top .account button.linkish:hover { color: #fff; }
@media (max-width: 700px) {
  header.top .account { flex-direction: row; align-items: center; }
  header.top .account select { width: auto; }
}
.brand select {
  display: block; margin-top: 2px; font-size: 12px; padding: 1px 4px;
  max-width: 180px;
}

/* Hidden while a page's translation loads (common.js lifts it within 2 s). */
html.i18n-wait body { visibility: hidden; }

/* ---------- sign in, account, admin ---------- */
.auth { max-width: 380px; margin: 10vh auto 0; }
.auth h1 { margin-bottom: 4px; }
.auth .language { text-align: center; margin-top: 14px; }
.auth .language select { width: auto; font-size: 12.5px; }
.err { color: var(--bad); font-size: 13px; margin: 0 0 10px; min-height: 1.2em; }
.kv { display: flex; gap: 10px; padding: 4px 0; font-size: 13.5px; }
.kv > span { color: var(--muted); min-width: 90px; }
.formgrid { display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
            gap: 0 14px; }
label.check { display: flex; align-items: center; gap: 6px; font-size: 13px;
              margin: 0 0 10px; }
/* A temporary password, shown once. Selectable in one click for reading out. */
.secret {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 15px;
  background: var(--panel); border: 1px solid var(--line-strong); border-radius: 6px;
  padding: 3px 8px; user-select: all;
}
tr.muted td { color: var(--muted); }

/* A five-minute check that has stopped is silent otherwise: the sheet keeps
   showing yesterday's times and looks perfectly healthy. */
.sub.stale { color: var(--warn); font-weight: 500; }

/* ---------- ECCE calendar ---------- */
/* A list of periods rather than a grid: each one is a date range, what it is, and
   how long it runs, which is all there is to say about it. */
.termlist { display: flex; flex-direction: column; gap: 6px; margin-bottom: 16px; }
.termlist .year {
  font-size: 11px; letter-spacing: .06em; text-transform: uppercase;
  color: var(--muted); font-weight: 650; margin: 12px 0 2px;
}
.termlist .year:first-child { margin-top: 0; }
.termlist .none { color: var(--muted); font-size: 13px; margin: 0; }
.term {
  display: flex; align-items: center; gap: 12px; padding: 9px 12px;
  background: var(--panel); border: 1px solid var(--line);
  border-left: 3px solid var(--ecce); border-radius: var(--radius);
}
/* A break is the absence of ECCE, so it is drawn as the quieter of the two. */
.term.off { border-left-color: var(--line-strong); background: var(--bg-soft); }
.term .when { display: flex; align-items: center; gap: 8px; min-width: 0; }
.term .when b { font-size: 13.5px; font-variant-numeric: tabular-nums; }
.term .what { margin-left: auto; text-align: right; font-size: 12px; color: var(--muted); }
.term .what .len { display: block; font-size: 11px; }
.term .x {
  flex: none; border: 0; background: none; color: var(--muted);
  font-size: 18px; line-height: 1; padding: 2px 6px; border-radius: 6px; cursor: pointer;
}
.term .x:hover { color: var(--bad); background: var(--bad-soft); }

.addterm {
  display: flex; gap: 10px; align-items: flex-end; flex-wrap: wrap;
  border-top: 1px solid var(--line); padding-top: 14px;
}
.addterm .field { margin: 0; }
.addterm .field.grow { flex: 1 1 220px; }
.addterm .field input { width: 100%; }
/* Term or break as two halves of one control: the choice is visible without
   reading a checkbox label, and there is no unchecked state to misread. */
.seg { display: inline-flex; border: 1px solid var(--line-strong); border-radius: 6px;
       overflow: hidden; }
.seg input { position: absolute; opacity: 0; pointer-events: none; }
.seg label { padding: 6px 11px; font-size: 13px; cursor: pointer; color: var(--muted);
             background: var(--panel); }
.seg label:nth-of-type(2) { border-left: 1px solid var(--line-strong); }
.seg input:checked + label { background: var(--accent-soft); color: var(--accent);
                             font-weight: 600; }
.seg input:focus-visible + label { outline: 2px solid var(--accent); outline-offset: -2px; }

/* An access token is a secret but not a password: masked against shoulder-surfing,
   without the input type that invites a password manager to fill it with a login. */
.masked { -webkit-text-security: disc; }

/* ---------- compact tables: import history, account activity ---------- */
table.grid.compact { font-size: 12.5px; }
table.grid.compact th, table.grid.compact td { padding: 5px 10px; white-space: nowrap; }
table.grid.compact td.when { color: var(--muted); font-variant-numeric: tabular-nums; }
table.grid.compact td.detail { white-space: normal; color: var(--muted); font-size: 12px; }

/* ---------- admin: people ---------- */
.person-cell { display: flex; align-items: center; gap: 10px; min-width: 0; }
.person-cell .who { min-width: 0; }
.person-cell .who b { display: block; font-weight: 600; line-height: 1.25; }
.person-cell .who small {
  display: block; color: var(--muted); font-size: 11.5px; line-height: 1.25;
  overflow: hidden; text-overflow: ellipsis;
}
.inits {
  flex: none; display: inline-grid; place-items: center; width: 32px; height: 32px;
  border-radius: 50%; background: var(--accent-soft); color: var(--accent);
  font-size: 12px; font-weight: 650;
}
.access { display: flex; flex-direction: column; align-items: flex-start; gap: 3px;
          font-size: 12.5px; }
.access .svc { color: var(--muted); }
.access .svc b { color: var(--ink); font-weight: 600; }
td.actions { text-align: right; white-space: nowrap; }
