/* ============================================================
   Admin styles — loaded only on admin_* pages (see header.php)
   Uses the color variables defined in styles.css :root.
   ============================================================ */

/* --- small shared helpers --- */
.muted{color:var(--ink-soft)}
.inline-form{display:inline}
.btn-danger{background:#a03a2a; color:#fff; border:0}
.btn-danger:hover{background:#873122}

/* --- flash messages --- */
.notice{padding:12px 16px; border-radius:10px; margin-bottom:16px}
.notice-ok{background:#e5f2e8; color:#1e6b3a}
.notice-err{background:#f6e2df; color:#a03a2a}

/* --- informational note callout --- */
.note{display:flex; gap:12px; align-items:flex-start; padding:14px 16px; margin:16px 0;
  background:var(--panel-green); border:1px solid var(--line); border-left:4px solid var(--gold);
  border-radius:10px; color:var(--ink-soft); font-size:.95rem; line-height:1.55}
.note .note-ico{flex:0 0 auto; margin-top:2px; color:var(--gold)}
.note b, .note strong{color:var(--pine-deep)}

/* --- toolbar / dropdown --- */
.mp-bar{display:flex; flex-wrap:wrap; gap:12px; align-items:center; margin:6px 0 18px}
.mp-bar select{padding:8px 12px; border:1px solid var(--line); border-radius:8px; font:inherit; background:var(--white)}

/* --- upload dropzone --- */
.uploader{background:var(--panel-green); border:1px dashed var(--gold-soft); border-radius:12px; padding:18px; margin:0 0 20px}

/* --- control-panel tiles --- */
.admin-tools{display:grid; grid-template-columns:repeat(auto-fill,minmax(180px,1fr)); gap:18px; margin-top:8px}
.tool-card{display:flex; flex-direction:column; align-items:center; gap:12px; padding:26px 18px; background:var(--white); border:1px solid var(--line); border-radius:16px; text-decoration:none; color:var(--pine-deep); text-align:center; transition:transform .12s ease, box-shadow .2s ease, border-color .2s ease}
.tool-card:hover{transform:translateY(-3px); box-shadow:0 12px 26px rgba(14,48,89,.12); border-color:var(--gold-soft)}
.tool-ico{width:56px; height:56px; display:grid; place-items:center; border-radius:50%; background:var(--panel-green); color:var(--pine)}
.tool-label{font-family:"Fraunces",serif; font-size:1.1rem}

/* --- users table --- */
.admin-bar{display:flex; flex-wrap:wrap; gap:12px; align-items:center; justify-content:space-between; margin:6px 0 18px}
.admin-bar .left{display:flex; gap:12px; flex-wrap:wrap; align-items:center}
.table-wrap{overflow-x:auto; border:1px solid var(--line); border-radius:12px}
.admin-table{width:100%; border-collapse:collapse; background:var(--white); min-width:640px}
.admin-table th, .admin-table td{padding:12px 14px; text-align:left; border-bottom:1px solid var(--line); font-size:.96rem; vertical-align:middle}
.admin-table th{background:var(--panel-green); font-family:"Fraunces",serif; color:var(--pine-deep)}
.admin-table tr:last-child td{border-bottom:0}
.admin-table tr.is-deleted td{opacity:.6}
.admin-actions{display:flex; gap:8px; flex-wrap:wrap}
.badge{display:inline-block; padding:2px 10px; border-radius:999px; font-size:.78rem; font-weight:600}
.badge-active{background:#e5f2e8; color:#1e6b3a}
.badge-deleted{background:#f6e2df; color:#a03a2a}

/* --- galleries grid --- */
.gal-grid{display:grid; grid-template-columns:repeat(auto-fill,minmax(220px,1fr)); gap:18px}
.gal-card{background:var(--white); border:1px solid var(--line); border-radius:14px; overflow:hidden; display:flex; flex-direction:column}
.gal-card .cover{width:100%; aspect-ratio:4/3; object-fit:cover; background:var(--panel-green); display:block}
.gal-card .body{padding:14px 16px; display:flex; flex-direction:column; gap:8px}
.gal-card h3{margin:0; font-size:1.1rem}
.gal-card .acts{display:flex; gap:8px; flex-wrap:wrap; margin-top:4px}
.gal-card.is-deleted{opacity:.75}
.gal-card.is-deleted .cover{filter:grayscale(.25)}

/* --- photos / auto-images grid (shared) --- */
.photo-grid{display:grid; grid-template-columns:repeat(auto-fill,minmax(200px,1fr)); gap:16px}
.photo-card{background:var(--white); border:1px solid var(--line); border-radius:12px; overflow:hidden; display:flex; flex-direction:column}
.photo-card .thumb{width:100%; aspect-ratio:1/1; object-fit:cover; background:var(--panel-green); display:block}
.photo-grid.wide .photo-card .thumb{aspect-ratio:4/3}   /* landscape thumbs (auto-images) */
.photo-card.is-deleted{opacity:.75}
.photo-card.is-deleted .thumb{filter:grayscale(.25)}
.photo-card .body{padding:10px 12px; display:flex; flex-direction:column; gap:6px}
.photo-card label{font-size:.78rem; color:var(--ink-soft)}
.photo-card input{width:100%}
.photo-card .acts{display:flex; gap:8px; margin-top:4px}

/* --- security checkboxes (manage users) --- */
/* These live inside .field, whose rules in styles.css are more specific than a
   bare class (.field label / .field input = 0,1,1). Everything here is scoped
   under .field so it actually wins, and the checkbox has to undo the full-width
   padded styling .field input applies to text boxes. */
.field .security-grid{display:grid; grid-template-columns:repeat(auto-fill,minmax(160px,1fr)); gap:10px}
.field label.security-item{display:flex; align-items:center; gap:9px; margin-bottom:0; padding:10px 12px; font-weight:500; font-size:.95rem; color:var(--ink); background:var(--white); border:1px solid var(--line); border-radius:10px; cursor:pointer}
.field label.security-item:hover{border-color:var(--gold-soft)}
.field .security-item input[type="checkbox"]{width:16px; height:16px; min-width:16px; flex:0 0 auto; margin:0; padding:0; border:0; border-radius:0; background:none; accent-color:var(--pine); cursor:pointer}
.field .security-item input[type="checkbox"]:disabled{cursor:not-allowed}
.field label.security-item:has(input:disabled){opacity:.7; cursor:not-allowed; background:var(--panel)}
.field label.security-item:has(input:checked){border-color:var(--gold); background:#fdf8ee}

/* --- read-only table viewers (logins, password resets) --- */
/* .field rules in styles.css are (0,1,1), so these are scoped to win. */
.viewer-filters{display:flex; flex-wrap:wrap; align-items:flex-end; gap:14px; padding:16px 18px; margin-bottom:18px; background:var(--white); border:1px solid var(--line); border-radius:14px}
/* The field sizes itself; the control fills it. The control used to carry a
   min-width of its own, which beat the max-width some fields set inline - CSS
   gives min-width the last word - so a 170px select sat inside a 150px field
   and lapped over the next one. */
/* Growing to fill is right for a chooser with long names in it, but a bar
   with one field in it should not stretch a select across the whole page. */
.viewer-filters .field{margin-bottom:0; flex:1 1 200px; min-width:0; max-width:420px}
.viewer-filters .field input[type="date"],
.viewer-filters .field select{width:100%; min-width:0; max-width:100%; padding:10px 12px; font:inherit; font-size:.95rem; color:var(--ink); background:var(--paper); border:1.5px solid var(--line); border-radius:10px}
.viewer-actions{display:flex; gap:10px; margin-left:auto}
.viewer-count{margin:0 0 14px}
.admin-table .col-id{font-variant-numeric:tabular-nums; color:var(--ink-soft); white-space:nowrap}
.admin-table .col-wrap{max-width:320px; overflow-wrap:anywhere; font-size:.86rem; color:var(--ink-soft)}
@media (max-width:640px){
  .viewer-filters{flex-direction:column; align-items:stretch}
  .viewer-filters .field input[type="date"],
  .viewer-filters .field select{width:100%}
  .viewer-actions{margin-left:0}
}

/* --- event / memory editing forms --- */
/* .field rules in styles.css are (0,1,1), so these are scoped the same way the
   security checkboxes above are, or the padded full-width input styling wins. */
.field-row{display:flex; flex-wrap:wrap; gap:16px}
.field-row .field{flex:1 1 200px; min-width:0}
.formcard .field select{width:100%; padding:13px 15px; font:inherit; font-size:1rem; color:var(--ink); background:var(--paper); border:1.5px solid var(--line); border-radius:12px}
.formcard .field select:focus{outline:none; border-color:var(--pine); background:var(--white)}
.field label.check-item{display:flex; align-items:center; gap:9px; margin-bottom:0; padding:10px 12px; font-weight:500; font-size:.95rem; color:var(--ink); background:var(--white); border:1px solid var(--line); border-radius:10px; cursor:pointer}
.field label.check-item:hover{border-color:var(--gold-soft)}
.field label.check-item:has(input:checked){border-color:var(--gold); background:#fdf8ee}
.field .check-item input[type="checkbox"]{width:16px; height:16px; min-width:16px; flex:0 0 auto; margin:0; padding:0; border:0; border-radius:0; background:none; accent-color:var(--pine); cursor:pointer}

/* --- image panel (families / members) --- */
.field .image-panel{display:flex; gap:18px; align-items:flex-start; flex-wrap:wrap}
.image-current{display:block; width:140px; height:140px; border:1px solid var(--line); border-radius:12px; overflow:hidden; background:var(--panel); flex:0 0 auto}
.image-current img{width:100%; height:100%; object-fit:cover; display:block}
.image-current.is-empty{display:grid; place-items:center; color:var(--ink-soft)}
.image-pick{flex:1 1 240px; min-width:0}
.field .image-pick input[type="file"]{width:100%; padding:10px 12px; font:inherit; font-size:.92rem; background:var(--paper); border:1.5px dashed var(--line); border-radius:10px}
.image-history{display:grid; grid-template-columns:repeat(auto-fill,minmax(150px,1fr)); gap:16px}
.image-hist{margin:0; background:var(--white); border:1px solid var(--line); border-radius:12px; overflow:hidden}
.image-hist.is-current{border-color:var(--gold); box-shadow:0 0 0 2px rgba(169,124,51,.18)}
.image-hist img{width:100%; aspect-ratio:1/1; object-fit:cover; display:block; background:var(--panel)}
.image-hist figcaption{padding:9px 10px; display:flex; flex-wrap:wrap; gap:6px; align-items:center; font-size:.8rem}
.grid-thumb{width:52px; height:52px; object-fit:cover; border-radius:8px; border:1px solid var(--line); display:block; background:var(--panel)}

/* --- side-by-side form fields --- */
.field-row{display:flex; gap:16px; flex-wrap:wrap}
.field-row .field{flex:1 1 200px; min-width:0}
@media (max-width:640px){ .field-row{flex-direction:column; gap:0} .field-row .field{max-width:none !important} }

/* --- family picker (members) --- */
.field input.family-filter{width:100%; margin-bottom:8px}
.field select.family-list{width:100%; padding:8px; font:inherit; font-size:.95rem; color:var(--ink); background:var(--paper); border:1.5px solid var(--line); border-radius:10px}
.field select.family-list option{padding:5px 6px}
.newfamily{margin:0 0 18px; padding:18px 20px; background:var(--panel-green); border:1px solid var(--line); border-radius:14px}
.newfamily h3{margin:0 0 4px; font-size:1.05rem}

/* --- family typeahead (members) --- */
.fam-picker{position:relative}
.field .fam-input{width:100%}
.fam-results{position:absolute; z-index:20; left:0; right:0; top:100%; margin:4px 0 0; padding:4px; list-style:none; overflow-y:auto; background:var(--white); border:1.5px solid var(--gold-soft); border-radius:12px; box-shadow:0 14px 34px rgba(14,48,89,.16)}
.fam-row{padding:11px 12px; border-radius:8px; cursor:pointer; font-size:.95rem; line-height:1.3; min-height:44px; display:flex; align-items:center}
.fam-row.is-hi{background:var(--panel-green)}
.fam-row.is-add{color:var(--pine); font-weight:600; border-top:1px solid var(--line); border-radius:0 0 8px 8px; margin-top:2px}

/* --- docked detail report (members grid) --- */
/* Desktop only. The breakpoint is 1220px, and that number is arithmetic rather
   than taste: the panel takes 360px out of the page, and the site's own header
   collapses to its compact nav at 860px. Media queries see the VIEWPORT, not
   the narrowed content, so engaging any earlier leaves the header believing it
   has room it no longer has and the brand collides with the menu.
   860 + 360 = 1220. It must stay in step with the matchMedia call in
   includes/inc_detailPanel.php.

   Below it none of this engages and the page behaves exactly as it did before
   the panel existed.

   The panel is fixed to the edge of the WINDOW, not placed in the content
   column, and the page is padded by its width so it can never cover anything.
   On a wide monitor that padding eats margin that was empty anyway - the
   content column caps at 1120px - so the grid keeps its full width. On a
   narrower screen the content shifts instead of shrinking.

   Fixed positioning resolves against the viewport only while no ancestor has a
   transform, filter or will-change. None does today; adding one to main,
   section or .container would silently re-anchor this panel. */
.detail-layout{display:block}
.detail-panel{display:none}
.row-open{padding:0; border:0; background:none; font:inherit; color:var(--pine-deep); text-align:left; cursor:pointer; text-decoration:underline; text-decoration-color:var(--gold-soft); text-underline-offset:3px}
.row-open:hover{color:var(--pine); text-decoration-color:var(--gold)}

@media (min-width:1220px){
  body.dp-open .detail-panel{display:flex; flex-direction:column; position:fixed; top:0; bottom:0;
    width:360px; z-index:60; background:var(--white); overflow:hidden;
    box-shadow:0 0 40px rgba(14,48,89,.18)}
  body.dp-open.dp-right .detail-panel{right:0; border-left:1px solid var(--line)}
  body.dp-open.dp-left  .detail-panel{left:0;  border-right:1px solid var(--line)}

  /* The page is padded so nothing sits under the panel. The sticky site header
     is in normal flow, so it narrows with everything else. */
  body.dp-open.dp-right{padding-right:360px}
  body.dp-open.dp-left {padding-left:360px}

  .admin-table tr.is-open > td{background:#fdf8ee}
}

/* Header pinned, body scrolls: the panel is full height, so a long record
   scrolls within it rather than the page. */
.detail-head{display:flex; align-items:flex-start; gap:10px; padding:16px 18px 12px; border-bottom:1px solid var(--line); background:var(--white); flex:0 0 auto}
.detail-head h2{margin:0; font-size:1.15rem; line-height:1.25; flex:1 1 auto; min-width:0; overflow-wrap:anywhere}
.detail-tools{display:flex; gap:6px; flex:0 0 auto}
.detail-body{padding:16px 18px 24px; overflow-y:auto; flex:1 1 auto}
.dp-photo{display:block; width:120px; height:120px; margin:0 0 16px; border:1px solid var(--line); border-radius:12px; overflow:hidden; background:var(--panel)}
.dp-photo img{width:100%; height:100%; object-fit:cover; display:block}
.dp-list{margin:0 0 14px; padding:0}
.dp-row{display:grid; grid-template-columns:118px 1fr; gap:10px; padding:6px 0; border-bottom:1px solid var(--panel)}
.dp-row:last-child{border-bottom:0}
.dp-row dt{margin:0; font-size:.82rem; color:var(--ink-soft)}
.dp-row dd{margin:0; font-size:.94rem; overflow-wrap:anywhere}
.dp-sub{margin:18px 0 6px; font-size:.95rem; color:var(--pine-deep)}
.dp-quiet .dp-row dd{color:var(--ink-soft); font-size:.86rem}

/* --- the class register, inside the detail report ---
   Absent is what this list gets read for on a Wednesday, so it is the one
   that carries colour; present is deliberately quiet. Reading down a column
   of identical words is how somebody misses a name. */
.dp-sheet{list-style:none; margin:0 0 14px; padding:0}
.dp-sheet li{display:flex; align-items:baseline; gap:10px; padding:6px 0;
             border-bottom:1px solid var(--panel); font-size:.92rem}
.dp-sheet li:last-child{border-bottom:0}
.dp-mark{flex:0 0 58px; font-size:.74rem; letter-spacing:.04em; text-transform:uppercase}
.dp-sheet .is-here .dp-mark{color:var(--ink-soft)}
.dp-sheet .is-away .dp-mark{color:#9a3412; font-weight:700}
.dp-sheet .is-away{font-weight:600}
.dp-sheet .is-off{opacity:.62}

/* --- the household's people, inside the detail report --- */
.dp-people{list-style:none; margin:0 0 14px; padding:0}
.dp-people li{display:flex; align-items:center; gap:10px; padding:7px 0; border-bottom:1px solid var(--panel)}
.dp-people li:last-child{border-bottom:0}
.dp-people li.is-inactive{opacity:.7}
.dp-thumb{width:50px; height:50px; flex:0 0 50px; border-radius:8px; object-fit:cover; display:block; border:1px solid var(--line); background:var(--panel)}
/* An empty box in place of a missing photo, so the names stay in a column. */
.dp-thumb.is-empty{background:var(--panel); border-style:dashed}
.dp-who{display:flex; flex-wrap:wrap; align-items:baseline; gap:4px 8px; min-width:0}
.dp-person{font-size:.95rem; overflow-wrap:anywhere}
.dp-role{font-size:.8rem; color:var(--ink-soft)}

/* Cross-links between the two reports: readable as links, not shouty. */
.dp-row dd a, .dp-person a{color:var(--pine); text-decoration:underline; text-decoration-color:var(--gold-soft); text-underline-offset:3px}
.dp-row dd a:hover, .dp-person a:hover{color:var(--pine-deep); text-decoration-color:var(--gold)}

/* Back links. Two levels down there are two of them side by side, so the
   spacing lives on the row and the links themselves drop their own margin. */
.backlinks{display:flex; flex-wrap:wrap; align-items:center; gap:10px 22px; margin-bottom:16px}
.backlinks .backlink{margin-bottom:0}

/* A second line under a grid cell - an activity's assistant leader sits under
   the leader rather than taking a column most rows would leave empty. */
.admin-table .col-sub{margin-top:3px; font-size:.82rem; color:var(--ink-soft)}

/* Table Information. The table's own name is the heading people look for
   first, so it gets to be loud. */
.ti-name{margin:26px 0 12px; font-size:1.25rem}
.ti-name span{color:var(--gold); font-family:"Fraunces",serif; font-size:1.5rem}
.ti-count{margin:10px 0 24px; color:var(--ink-soft)}
.admin-table code{font-size:.86rem; background:var(--panel); padding:2px 6px; border-radius:6px}

/* The permissions list in a user's report: every right, ticked or not, in one
   column so the eye can run down it. */
.dp-rights{list-style:none; margin:0 0 14px; padding:0}
.dp-rights li{display:flex; align-items:baseline; gap:9px; padding:4px 0; font-size:.92rem}
.dp-rights li.is-off{color:var(--ink-soft)}
.dp-tick{flex:0 0 14px; text-align:center; font-weight:700}
.dp-rights li.is-on .dp-tick{color:#1e6b3a}
.dp-rights li.is-off .dp-tick{color:var(--line)}

/* A paragraph of body text in a report - a memory's summary. */
.dp-text{margin:0 0 14px; font-size:.92rem; line-height:1.55; color:var(--ink)}

/* A placeholder where a grid thumbnail would be, so the column keeps its
   width and the names stay in line whether there is a photo or not. */
.grid-thumb.is-empty{display:block; border-style:dashed}

/* A checkbox with its label on one line. .field label is display:block, which
   would otherwise drop the text under the box. */
.field label.check-line{display:flex; align-items:center; gap:10px; font-weight:600; cursor:pointer}
.field label.check-line input{width:auto; margin:0}

/* ===== Take the Register =====
   A sheet meant to be read at arm's length and clicked down in one go. The
   state lives on aria-pressed, so the buttons announce themselves correctly
   and there is no second class name to keep in step with it. */
.visually-hidden{position:absolute; width:1px; height:1px; padding:0; margin:-1px; overflow:hidden; clip:rect(0 0 0 0); white-space:nowrap; border:0}

.wz-pick-class{display:flex; align-items:center; gap:12px; margin:0 0 18px}
.wz-class-form{flex:1 1 auto; display:flex; gap:10px; min-width:0}
.wz-class-form select{width:100%; padding:13px 15px; font:inherit; font-size:1.05rem; color:var(--ink); background:var(--paper); border:1.5px solid var(--line); border-radius:12px}
.wz-arrow{font-size:1.3rem; line-height:1; padding:12px 18px}
.wz-arrow.is-off{opacity:.3; cursor:default}

.wz-sheet{width:100%; border-collapse:collapse; background:var(--white); border:1px solid var(--line); border-radius:12px; overflow:hidden}
.wz-sheet th[scope="row"]{text-align:left; padding:10px 14px; font-size:1.05rem; font-weight:600; border-bottom:1px solid var(--panel)}
.wz-sheet td{border-bottom:1px solid var(--panel); padding:0; width:78px}
.wz-sheet tr:last-child th, .wz-sheet tr:last-child td{border-bottom:0}
.wz-visitors th[scope="row"]{font-weight:700}
.wz-visitors input{width:100%; max-width:150px; padding:10px 12px; font:inherit; font-size:1.05rem; text-align:center; border:1.5px solid var(--ink); border-radius:8px; background:var(--paper)}

.wz-cell{text-align:center}
.wz-cell button{width:100%; min-height:48px; border:0; background:none; font:inherit; font-size:1.1rem; font-weight:800; color:var(--ink-soft); cursor:pointer}
.wz-cell button:focus-visible{outline:3px solid var(--gold); outline-offset:-3px}
/* Unpressed A still reads as the absent side, just quietly. */
.wz-p[aria-pressed="true"]{background:#2f6fbf; color:#fff}
.wz-a[aria-pressed="true"]{background:#c62828; color:#fff}
.wz-p[aria-pressed="false"], .wz-a[aria-pressed="false"]{background:var(--white); color:var(--ink-soft)}

/* Adding somebody written in on the paper sheet, without leaving the page. */
.wz-add{display:flex; align-items:center; gap:10px; flex-wrap:wrap; margin:22px 0 0;
        padding:14px 16px; background:var(--panel); border-radius:12px}
.wz-add label{font-weight:700; white-space:nowrap}
.wz-add select{flex:1 1 240px; min-width:0; padding:11px 13px; font:inherit; color:var(--ink);
               background:var(--white); border:1.5px solid var(--line); border-radius:10px}

.wz-total{margin:16px 0 0; font-size:1.15rem; font-weight:700; color:var(--pine-deep)}

/* ===== The attendance sheet =====
   On screen it is a preview; on paper it is the thing itself. No PDF library:
   every browser's print dialog can save to PDF already. */
.sheet{background:var(--white); border:1px solid var(--line); border-radius:12px; padding:26px 28px; margin:0 0 26px}
.sheet-head{display:flex; justify-content:space-between; align-items:flex-start; gap:20px; flex-wrap:wrap;
            border-bottom:2px solid var(--ink); padding-bottom:12px; margin-bottom:16px}
.sheet-head h2{margin:0; font-size:1.4rem}
.sheet-when{margin:4px 0 0; color:var(--ink-soft)}
.sheet-teacher{text-align:right; font-size:.95rem}
.sheet-label{display:block; font-size:.72rem; letter-spacing:.09em; text-transform:uppercase; color:var(--ink-soft)}

.sheet-roll{width:100%; border-collapse:collapse}
.sheet-roll th{text-align:left; font-size:.78rem; letter-spacing:.07em; text-transform:uppercase;
               color:var(--ink-soft); border-bottom:1px solid var(--ink); padding:0 8px 6px}
.sheet-roll td{border-bottom:1px solid var(--line); padding:9px 8px; font-size:1rem}
.sheet-num{width:34px; text-align:right; color:var(--ink-soft)}
/* Boxes big enough to tick with a pen resting on a knee. */
.sheet-box{width:42px; text-align:center}
.sheet-roll tbody td.sheet-box{border:1px solid var(--ink); height:28px}
.sheet-notes{width:34%}
.sheet-spare td{height:30px}
.sheet-empty{text-align:center; color:var(--ink-soft); font-style:italic}

.sheet-foot{display:flex; gap:34px; flex-wrap:wrap; margin-top:18px; padding-top:14px; border-top:2px solid var(--ink)}
.sheet-rule{display:inline-block; width:88px; border-bottom:1px solid var(--ink); height:1.3em}

@media print {
    /* Everything that is screen furniture goes: the site is not what is being
       printed, one sheet is. */
    .site-header, .site-footer, .page-head, .no-print, .backlinks, .notice { display:none !important; }
    body{background:#fff; color:#000}
    body.dp-open{padding:0 !important}
    main, section, .container, .container.narrow{margin:0; padding:0; max-width:none; width:auto}

    .sheet{border:0; border-radius:0; padding:0; margin:0;
           page-break-after:always; break-after:page}
    /* The last one must not eject a blank page after it. */
    .sheet:last-child{page-break-after:auto; break-after:auto}
    .sheet-head{border-bottom:2px solid #000}
    .sheet-roll th, .sheet-roll td{border-color:#000}
    .sheet-roll tbody td.sheet-box{border:1px solid #000}
    .sheet-foot{border-top:2px solid #000}
    .sheet-rule{border-bottom:1px solid #000}
    /* A row split across two pages is a row nobody can tick. */
    .sheet-roll tr{page-break-inside:avoid; break-inside:avoid}
    .sheet-roll thead{display:table-header-group}
    a[href]{text-decoration:none; color:#000}
}
@page { margin:14mm; }

/* ===== The reports list =====
   A list rather than a grid of tiles: a report has a name and a line saying
   what it does, and that reads down the page far better than it reads in a
   square. */
.rep-section{margin:28px 0 10px; font-size:1.15rem; padding-bottom:7px; border-bottom:2px solid var(--gold-soft)}
.rep-section:first-child{margin-top:6px}
.rep-list{list-style:none; margin:0 0 6px; padding:0}
.rep-list li{border-bottom:1px solid var(--panel)}
.rep-list li:last-child{border-bottom:0}
.rep-list a{display:flex; align-items:flex-start; gap:14px; padding:14px 10px; text-decoration:none;
            color:var(--pine-deep); border-radius:10px}
.rep-list a:hover{background:var(--panel)}
.rep-ico{flex:0 0 40px; height:40px; display:flex; align-items:center; justify-content:center;
         border-radius:10px; background:var(--panel); color:var(--pine)}
.rep-list a:hover .rep-ico{background:var(--white)}
.rep-text{min-width:0}
.rep-name{display:block; font-weight:700; font-size:1.05rem}
.rep-hint{display:block; margin-top:2px; font-size:.9rem; color:var(--ink-soft)}

/* ===== Report tables =====
   Figures read down a column, so they are right-aligned and tabular: a 9 under
   a 12 has to line up on the units. */
.rep-heading{margin:22px 0 8px; font-size:1.05rem; letter-spacing:.04em; text-transform:uppercase; color:var(--ink-soft)}
.rep-table td.num, .rep-table th.num{text-align:right; font-variant-numeric:tabular-nums; white-space:nowrap}
.rep-table tbody tr.rep-group th{background:var(--panel); font-size:.95rem; text-align:left; padding:8px 12px}
.rep-table .rep-indent{padding-left:26px}
.rep-table tr.rep-sub th, .rep-table tr.rep-sub td{background:var(--paper); font-weight:700; border-top:1px solid var(--line)}
.rep-table tr.rep-total th, .rep-table tr.rep-total td{background:var(--panel); font-weight:800; border-top:2px solid var(--ink)}
.rep-table tr.rep-sub th, .rep-table tr.rep-total th{text-align:left}
.rep-foot{font-size:.85rem; color:var(--ink-soft)}
.rep-foot .sheet-label{display:inline; margin-right:5px}

@media print {
    .rep-table tr.rep-group th{background:#eee}
    .rep-table tr.rep-sub th, .rep-table tr.rep-sub td{background:#f4f4f4; border-top:1px solid #000}
    .rep-table tr.rep-total th, .rep-table tr.rep-total td{background:#e4e4e4; border-top:2px solid #000}
    .rep-table thead{display:table-header-group}
    .rep-table tr{page-break-inside:avoid; break-inside:avoid}
}

/* ===== The quarter grid =====
   A wide table read across rather than down: names pinned at the left, one
   narrow column per meeting. The colours are the point of it - a red streak
   across a row is visible from further away than any number. */
.qa-scroll{overflow-x:auto; -webkit-overflow-scrolling:touch}
.qa-table{width:auto; min-width:100%}
.qa-table th, .qa-table td{padding:6px 9px; font-size:.9rem; white-space:nowrap;
                           border:1px solid var(--line); vertical-align:middle}
/* Names stay put while the dates scroll past them; a P nine weeks along is no
   use if you cannot see whose row it is on. */
.qa-table .qa-name{position:sticky; left:0; z-index:1; text-align:left; min-width:180px}
.qa-table tbody th.qa-name{background:var(--white); font-family:inherit; color:var(--ink); font-weight:500}
.qa-table thead th{position:sticky; top:0; z-index:2}
.qa-table thead th.qa-name{z-index:3}
.qa-table tr.rep-sub th.qa-name{background:var(--paper); font-weight:700}
.qa-table tr.rep-total th.qa-name{background:var(--panel); font-weight:800}
.qa-num{text-align:right; font-variant-numeric:tabular-nums; width:62px}
.qa-mark{text-align:center; width:38px; font-weight:800; font-variant-numeric:tabular-nums}
.qa-month{display:block; font-size:.68rem; font-weight:600; letter-spacing:.05em;
          text-transform:uppercase; color:var(--ink-soft); line-height:1.4}
.qa-table thead th.qa-mark{font-weight:700}
/* The same two colours the register is marked in, so the sheet and the report
   look like the same thing. */
.qa-p{background:#2f6fbf; color:#fff}
.qa-a{background:#c62828; color:#fff}

@media print {
    /* Nine or thirteen date columns do not fit down a portrait page. */
    @page qa-land { size: landscape; margin:10mm; }
    .qa-sheet{page:qa-land}
    .qa-scroll{overflow:visible}
    /* On paper the grid sits at its own width rather than stretching: all the
       slack in a full-width table lands in the name column, and a 700px column
       of short names next to squares you cannot read is the wrong trade. */
    .qa-table{min-width:0}
    .qa-table th.qa-name{width:170px}
    /* Sticky and paged output do not mix: a pinned column reprints itself. */
    .qa-table .qa-name, .qa-table thead th{position:static}
    .qa-table th, .qa-table td{border:1px solid #000; padding:3px 5px; font-size:.78rem}
    .qa-table tbody th.qa-name, .qa-table thead th{background:#fff}
    .qa-table tr.rep-sub th.qa-name{background:#f4f4f4}
    .qa-table tr.rep-total th.qa-name{background:#e4e4e4}
    /* Tints rather than solid blocks: it reads the same and costs a tenth of
       the ink on a page that is mostly squares. */
    .qa-p, .qa-a{-webkit-print-color-adjust:exact; print-color-adjust:exact; color:#000}
    .qa-p{background:#d3e3f5}
    .qa-a{background:#f6d4d4}
}

/* A third badge, for a state that is neither good news nor bad: a job that has
   not run yet is not a failure, and colouring it like one would have somebody
   chasing it. */
.badge-muted{background:var(--panel); color:var(--ink-soft)}

/* ===== Queue these emails =====
   Folded away behind a summary: the report is what the page is for, and the
   send form is a thing you do occasionally. */
.send-card{background:var(--white); border:1px solid var(--line); border-radius:14px;
           padding:0 18px; margin:0 0 18px}
.send-card summary{cursor:pointer; padding:14px 0; font-weight:700; color:var(--pine-deep)}
.send-card[open] summary{border-bottom:1px solid var(--line); margin-bottom:14px}
.send-card form{padding-bottom:18px}
.send-card select[multiple]{width:100%; max-width:520px; padding:8px; font:inherit; font-size:.95rem;
                            border:1.5px solid var(--line); border-radius:10px; background:var(--paper)}
.send-list{list-style:none; margin:8px 0 14px; padding:0; font-size:.93rem}
.send-list li{padding:6px 0; border-bottom:1px solid var(--panel)}
.send-list li:last-child{border-bottom:0}
.send-who{display:inline-block; margin-left:10px; color:var(--ink-soft)}

/* ===== The working grid =====
   A grid you work through rather than read: it fills the window, scrolls
   inside itself, and the actions live once above it instead of on every row.
   Desktop only - below the breakpoint the per-row buttons come back and the
   page behaves exactly as it always has. */

.grid-bar{display:flex; flex-wrap:wrap; gap:14px; align-items:center; justify-content:space-between;
          padding:10px 12px; margin:0 0 10px; background:var(--white);
          border:1px solid var(--line); border-radius:12px}
.grid-bar .left, .grid-bar .right{display:flex; gap:10px; align-items:center; flex-wrap:wrap}
.grid-bar .sep{width:1px; align-self:stretch; background:var(--line); margin:0 4px}
.grid-bar select{padding:8px 10px; font:inherit; font-size:.92rem; color:var(--ink);
                 background:var(--paper); border:1.5px solid var(--line); border-radius:9px}
/* A disabled action has to look disabled, or it reads as a broken button. */
.grid-bar .btn[disabled]{opacity:.42; cursor:not-allowed; pointer-events:none}
.tag-count{font-weight:700; color:var(--pine-deep); white-space:nowrap}
.tag-count.is-none{font-weight:400; color:var(--ink-soft)}

/* The scroller. max-height is set in JS from where this lands on the page, so
   a notice appearing above it cannot push the bottom off screen. With no JS
   there is no max-height and the page scrolls as it always did.
   min-height stays modest on purpose: a floor taller than the space available
   gives you a page scrollbar AND a grid scrollbar, and the wheel then does
   whatever it likes. */
.grid-scroll{overflow-y:auto; overflow-x:auto; min-height:20rem;
             border:1px solid var(--line); border-radius:12px; background:var(--white)}
.grid-scroll .admin-table{border-radius:0; border:0; margin:0}

/* Sticky header. The bottom edge is a box-shadow, NOT a border: with
   border-collapse the borders belong to the table rather than the cell, so
   they do not travel with a stuck header and simply vanish. */
.grid-scroll thead th{position:sticky; top:0; z-index:2;
                      box-shadow:inset 0 -1.5px 0 var(--ink); border-bottom:0}

/* Rows are shorter with the buttons gone - that was the point. */
.grid-tight th, .grid-tight td{padding:6px 12px; font-size:.93rem}
.grid-tight .grid-thumb{width:34px; height:34px; border-radius:6px}
.grid-tight tbody tr{cursor:default}
/* scroll-margin so scrollIntoView does not park a row underneath the header. */
.grid-tight tbody tr, [data-grid] tbody tr{scroll-margin-top:3rem}

/* The selected row drives the buttons AND the confirm dialog, so it has to be
   unmistakable - a tint alone is fine for "this is what the panel shows", not
   for "this is what Delete will act on".

   Keyed on [data-grid] as well as .grid-tight, because .grid-tight is only
   how TIGHT the rows are. Attendance Dates and Attendance are selectable and
   are not tight, so the row that Delete was about to act on looked exactly
   like every other row - the toolbar changed and nothing else did. */
.grid-tight tbody tr.is-sel > td, .grid-tight tbody tr.is-sel > th,
[data-grid] tbody tr.is-sel > td, [data-grid] tbody tr.is-sel > th{
    background:#fbf1d9; box-shadow:inset 0 0 0 9999px rgba(0,0,0,0)}
.grid-tight tbody tr.is-sel > td:first-child, .grid-tight tbody tr.is-sel > th:first-child,
[data-grid] tbody tr.is-sel > td:first-child, [data-grid] tbody tr.is-sel > th:first-child{
    box-shadow:inset 4px 0 0 var(--gold)}

.tag-col{width:38px; text-align:center}
.tag-col input[type="checkbox"]{width:17px; height:17px; accent-color:var(--pine); cursor:pointer; margin:0}
/* A tag that failed to save flashes back, so nobody acts on a count the
   server does not share. */
.tag-col.is-bad{background:#f6e2df}

@media (min-width:1220px){
    /* The toolbar is live here, so the per-row buttons stand down. They stay
       in the markup on purpose: below this width they come back, and mobile
       keeps the page it has always had with no second layout to maintain.

       Keyed on data-row-tools, which a list sets ONLY when it has a toolbar
       carrying Edit, Make inactive and Delete for the selected row. Nothing
       else may hide those buttons, because nothing else puts them back.

       This is the second time that has had to be narrowed. It was keyed on
       .grid-tight and hid the buttons on the Filters list, which uses the
       same tight rows and has no toolbar. Re-keying it on [data-grid] fixed
       that and then did the same thing again the moment data-grid was added
       to six more lists - for the tick boxes, which have nothing to do with
       row buttons - and Edit and Delete quietly disappeared on every one of
       them above 1220px. A rule that hides something must be keyed on the
       thing that REPLACES it, not on whatever markup happens to sit nearby. */
    [data-grid][data-row-tools] .admin-actions{display:none}

    /* And the column with them. Hiding only the buttons leaves a strip of
       empty cells under a heading that says Actions, which reads as a fault
       rather than as a design - it is what made this worth reporting in the
       first place. A list marks that column and it goes with them. */
    [data-grid][data-row-tools] .col-actions{display:none}
}
@media (max-width:1219px){
    .grid-bar .desk-only{display:none}
    .grid-scroll{max-height:none !important; min-height:0; border:0; border-radius:0}
    [data-grid][data-row-tools] .admin-actions{display:flex}
    .grid-scroll thead th{position:static; box-shadow:none}
    .grid-tight th, .grid-tight td{padding:12px 14px; font-size:.96rem}
    .grid-tight .grid-thumb{width:52px; height:52px; border-radius:8px}
}

/* Edit lives in the toolbar AND at the top of the detail panel: the panel is
   already showing the record, so it is the other place a hand reaches. */
.dp-actions{margin:0 0 14px}

/* ===== The filter builder =====
   The controls sit in table cells rather than in .field wrappers, so none of
   the form styling reached them and they came out as raw browser selects in a
   styled table - which reads as half-finished rather than as deliberate. */
.cond-table{width:100%}
.cond-table th{font-size:.8rem; letter-spacing:.04em; text-transform:uppercase}
.cond-table td{padding:7px 8px; vertical-align:middle}
.cond-table select,
.cond-table input[type="text"]{
    width:100%; padding:9px 11px; font:inherit; font-size:.93rem; color:var(--ink);
    background:var(--paper); border:1.5px solid var(--line); border-radius:9px}
.cond-table select:focus,
.cond-table input[type="text"]:focus{outline:none; border-color:var(--pine); background:var(--white)}
/* The bracket columns are one character wide; centring stops them reading as
   empty boxes somebody forgot to fill in. */
.cond-table .cond-group{width:66px}
.cond-table .cond-group select{text-align:center; padding-left:6px; padding-right:6px; font-weight:700}
.cond-table .cond-conj{width:96px}
.cond-table .cond-x{width:44px; text-align:center}
.cond-table .cond-clear{padding:6px 10px; line-height:1; border-radius:8px}
.cond-table .cond-val2{margin-top:6px}
@media (max-width:900px){
    .cond-table select, .cond-table input[type="text"]{font-size:.88rem; padding:7px 8px}
}

/* A select sitting in the toolbar rather than in a .field got none of the form
   styling and came out as a raw browser control next to styled buttons. Only
   the Filters page and the Members grid have one. */
.admin-bar select{padding:8px 11px; font:inherit; font-size:.92rem; color:var(--ink);
                  background:var(--paper); border:1.5px solid var(--line); border-radius:9px}
.admin-bar select:focus{outline:none; border-color:var(--pine); background:var(--white)}
.admin-bar label{margin:0}

/* A filter's lines, read as a list rather than opened one at a time. */
.dp-lines{margin:0 0 10px; padding-left:22px; font-size:.95rem; line-height:1.7}
.dp-lines li{margin-bottom:3px}
.dp-lines i{color:var(--pine-deep); font-style:normal; background:var(--panel);
            padding:1px 6px; border-radius:6px}

/* The row whose filter is loaded in the form above. Distinct from .is-open,
   which the detail panel uses for the row you are reading. */
.admin-table tr.is-editing > td{background:#fbf1d9}
.admin-table tr.is-editing > td:first-child{box-shadow:inset 4px 0 0 var(--gold)}

/* ---- the two-list column picker (Grids, Step 1) --------------------------
   Two boxes and four buttons, because that is what everybody has used since
   Windows 3.1 and nothing about choosing eight things out of thirty-six is
   improved by inventing something newer. Side by side while there is room,
   stacked below 820px with the buttons turned to lie across the middle. */
.pick-two{display:grid; grid-template-columns:1fr auto 1fr; gap:14px;
          align-items:start; margin-top:6px}
.pick-side h3{margin:0 0 7px; font-size:.95rem; font-weight:700; color:var(--ink)}
.pick-side h3 .muted{font-weight:500}
.pick-side select{width:100%; padding:6px; font:inherit; font-size:.93rem;
                  border:1.5px solid var(--line); border-radius:10px;
                  background:var(--white); color:var(--ink)}
.pick-side select option{padding:4px 7px; border-radius:6px}
.pick-mid{display:flex; flex-direction:column; gap:8px; padding-top:30px}
.pick-mid .btn{min-width:44px; justify-content:center}

@media (max-width: 820px){
  .pick-two{grid-template-columns:1fr}
  .pick-mid{flex-direction:row; justify-content:center; padding-top:0}
}

/* ---- the column settings table (Grids, Step 2) --------------------------
   A row is a button: click it and it loads into the editor above. The saved
   flash is a word rather than a dialog, because saving one column of eight is
   not an event worth stopping for. */
.col-table tbody tr{cursor:pointer}
.col-table tbody tr:hover > td{background:var(--panel)}
.col-flash{font-size:.9rem; font-weight:700; color:var(--pine-deep);
           background:#fdf8ee; border:1px solid var(--gold-soft);
           padding:3px 10px; border-radius:999px}
.col-edit{border-bottom:1px solid var(--line); padding-bottom:14px; margin-bottom:4px}

/* ---- section tabs (Grids: Report / Columns / Report order) ---------------
   One section at a time, so reaching the third does not mean scrolling past
   the other two. Switching is done in the browser - the two lists below save
   as you go and may be holding unsaved edits in their boxes. */
.tabs{display:flex; gap:4px; flex-wrap:wrap; margin:18px 0 0;
      border-bottom:2px solid var(--line)}
.tabs .tab{appearance:none; border:0; background:none; cursor:pointer;
           font:inherit; font-weight:600; font-size:.98rem; color:var(--ink-soft);
           padding:10px 18px; border-radius:10px 10px 0 0;
           border-bottom:3px solid transparent; margin-bottom:-2px}
.tabs .tab:hover{color:var(--ink); background:var(--panel)}
.tabs .tab[aria-selected="true"]{color:var(--pine-deep); background:var(--white);
                                 border-bottom-color:var(--gold)}
.tabs .tab:focus-visible{outline:2px solid var(--pine); outline-offset:-2px}
/* Belt and braces: the hidden attribute already does this, but a stylesheet
   that later gives .tab-panel a display would silently turn every panel on. */
.tab-panel[hidden]{display:none}
.tab-panel > h2.rep-heading:first-child{margin-top:18px}

/* ---- Save as (Grids) ------------------------------------------------------
   Asked for inline rather than in a prompt box, so the name can be typed,
   corrected and read before anything happens. Hidden until it is wanted. */
.save-as{display:flex; gap:10px; flex-wrap:wrap; align-items:center;
         margin-top:14px; padding:14px; border:1px solid var(--gold-soft);
         border-radius:12px; background:#fdf8ee}
.save-as label{font-weight:600; font-size:.95rem; color:var(--ink)}
.save-as input[type="text"]{padding:9px 12px; font:inherit; font-size:.95rem;
                            min-width:230px; border:1.5px solid var(--line);
                            border-radius:10px; background:var(--white)}
.save-as[hidden]{display:none}

/* ===== A custom grid, printed =====
   The figures come from gridReportRun(); this is only how they look. Breaks
   and totals have to read as different KINDS of line at a glance, or a long
   report is a wall of numbers. */
.gr-sheet{background:var(--white); border:1px solid var(--line); border-radius:12px;
          padding:18px; margin-top:14px; overflow-x:auto}
.gr-head{border-bottom:2px solid var(--gold-soft); padding-bottom:10px; margin-bottom:12px}
.gr-head h2{margin:0 0 3px; font-size:1.3rem}
.gr-head p{margin:0; font-size:.92rem}

.gr-table{width:100%; border-collapse:collapse; font-size:.92rem}
.gr-table th{text-align:left; font-weight:700; padding:7px 9px;
             border-bottom:2px solid var(--line); white-space:nowrap}
.gr-table td{padding:6px 9px; border-bottom:1px solid var(--line-soft, #eee);
             vertical-align:top}

/* A group heading: the value it broke on, spanning the whole width. */
.gr-table tr.gr-break > td{background:var(--panel); font-size:.95rem;
                           padding-top:12px; border-bottom:1px solid var(--line)}
.gr-table tr.gr-break-1 > td{background:transparent; padding-left:22px}

.gr-table tr.gr-total > td{background:#fdf8ee; font-weight:600;
                           border-top:1px solid var(--gold-soft);
                           border-bottom:1px solid var(--gold-soft)}
.gr-table tr.gr-grand > td{background:var(--panel); font-weight:700;
                           border-top:2px solid var(--ink-soft)}
.gr-pagebreak > td{padding:0; border:0; height:0}

@media print {
    .gr-sheet{border:0; border-radius:0; padding:0; margin:0; overflow:visible}
    .gr-head{border-bottom:2px solid #000}
    .gr-table{font-size:.8rem}
    .gr-table th{border-bottom:1px solid #000}
    .gr-table td{border-bottom:1px solid #ddd}
    /* The column headings reprint at the top of every page. A table that runs
       to four pages is unreadable from page two without them. */
    .gr-table thead{display:table-header-group}
    /* A record split across two pages is a record nobody can read. */
    .gr-table tr{page-break-inside:avoid; break-inside:avoid}
    /* Where the report order asked for a new page. */
    .gr-pagebreak{page-break-after:always; break-after:page}
    .gr-table tr.gr-total > td{background:#f4f4f4; border-top:1px solid #000;
                               border-bottom:1px solid #000}
    .gr-table tr.gr-grand > td{background:#e8e8e8; border-top:2px solid #000}
    .gr-table tr.gr-break > td{background:#f4f4f4}
    /* A group heading with nothing under it on the same page is a heading on
       the wrong page. */
    .gr-table tr.gr-break{page-break-after:avoid; break-after:avoid}
    /* Landscape is NOT set here. A named page (@page gr-land, page: gr-land)
       reads well and does not reliably reach the printer - Chromium only
       learned it recently, Firefox never has - so a grid marked Landscape
       printed portrait with nothing to say why. rep_gridReport.php puts a
       plain @page in its own head instead, which every browser understands
       and which cannot leak onto another page of the site. */
}

/* ===== The staff noticeboard =====
   Above the tiles on the Control Panel, because that is where somebody lands
   after signing in and so where a note cannot be missed. An Alert looks
   different from a Notice; if everything shouted, nothing would. */
.notice-board{margin:0 0 22px}
.notice-item{background:var(--white); border:1px solid var(--line);
             border-left:4px solid var(--gold); border-radius:12px;
             padding:13px 16px; margin-bottom:10px}
.notice-item.is-alert{border-left-color:#c62828; background:#fff8f7}
.notice-head{display:flex; gap:10px; flex-wrap:wrap; align-items:baseline}
.notice-head .muted{font-size:.9rem}
.notice-body{margin:7px 0 9px; color:var(--ink)}
.notice-item .inline-form{margin:0}

/* Who a notice goes to: a column of names that stays readable at twenty. */
.notice-who{display:grid; grid-template-columns:repeat(auto-fill, minmax(210px, 1fr));
            gap:6px 18px; padding:12px; border:1px solid var(--line);
            border-radius:10px; background:var(--white)}
