/* app.css — A25 look-match.
 *
 * RayMar's STRUCTURE (type scale, weights, spacing, radii, bordered cards with
 * no shadows, bar, sheet easing, safe areas) over MarayGov's OWN colours.
 * Per DESIGN-REFERENCE rule 2 the chrome stays NAVY — RayMar's brand red is not
 * adopted, because red here means a bad rating and nothing else.
 * DESIGN-REFERENCE §10's invented 1-5 ramp is rejected and unused.
 */

:root {
  /* base — RayMar's, verbatim */
  --ink: #141414;
  --ink-2: #5c5c5c;
  --line: #e4e4e4;
  --bg: #f4f4f5;
  --card: #fff;

  /* chrome — MarayGov's navy, NOT RayMar's red. Carries no data meaning (§9). */
  --brand: #123b52;
  --brand-d: #0d2c3e;
  --ink-bar: #123b52;
  /* childcare v16 — the admin Users / Inspections row, a brighter blue of the bar. */
  --brand-nav: #2a7eab;

  /* Rating scale 1-5 — copied verbatim from the app's own CSS, which matches
     the government template. Not eyeballed, not re-derived, not §10. */
  --s5: #1f7a3d; --s4: #6aa84f; --s3: #d79b1e; --s2: #cf6a1a; --s1: #b3251f;

  /* Text colour per score, set by measured contrast against the fill above:
     white clears 5:1 on 1 and 5; on 2, 3 and 4 the fills are light enough that
     ink reads better (2.45:1 white vs 6.48:1 ink on the amber). Read outdoors. */
  --on-s5: #fff; --on-s4: var(--ink); --on-s3: var(--ink); --on-s2: var(--ink); --on-s1: #fff;

  /* Childcare fork — the Major/Minor defect ("M"). One hue family (purple) that
     nothing else in the app uses; strength = severity. Same values as
     src/defect.js, asserted by tests/mdefect.test.js. */
  --m-major: #7b1fa2; --on-m-major: #fff;
  --m-minor: #d1b3e6; --on-m-minor: var(--ink);

  /* §9's completion ramp — the "can I leave site yet" colours, not the rating
     scale. Used only for the offline chip's dot, in the chrome bar. */
  --done: #2f7d5b;
  --todo: #e08600;

  /* A67 — all FOUR insets, not two.
     index.html asks for viewport-fit=cover, which extends the page under the
     notch and hands back four insets to respect. The app used the top and the
     bottom and ignored the sides, so in landscape — where the left/right inset
     is 40-50px on a notched phone — Done, Close and Phone camera sat under the
     notch or the rounded corner. Every surface that draws to the edge of the
     screen uses these; tests/viewport.test.js overrides --safe-l / --safe-r and
     fails any that does not move. */
  --safe-t: env(safe-area-inset-top, 0px);
  --safe-b: env(safe-area-inset-bottom, 0px);
  --safe-l: env(safe-area-inset-left, 0px);
  --safe-r: env(safe-area-inset-right, 0px);

  --ease-sheet: cubic-bezier(.32, .72, 0, 1);
}

* { box-sizing: border-box; }

body {
  margin: 0;
  font: 15px/1.45 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  -webkit-font-smoothing: antialiased;
  color: var(--ink);
  background: var(--bg);
  padding-bottom: calc(var(--safe-b) + 24px);
  -webkit-text-size-adjust: 100%;

  /* A67 — the longest word must not set the width of the page.
     A note, a location name or a building name can carry an unbroken run: a
     serial number, a plant tag, a pasted link. Measured on a 390px phone, a
     120-character token took the page to 1368px and everything went with it —
     the right edge and the controls on it off the screen, pinch-zoom the only
     way to find them again. This is the cause, not a clamp: the page is told it
     may break such a word, so nothing needs to be hidden or scrolled away.
     `anywhere` rather than `break-word` because only `anywhere` also shrinks a
     flex item's min-content width, and the measure rows and the entry list are
     flex. Text that must stay on one line (the score chips, the pills) already
     says white-space: nowrap, which wins over this. */
  overflow-wrap: anywhere;
}

/* ---------- §8 bar ---------- */

.bar {
  position: sticky; top: 0; z-index: 40;
  background: var(--ink-bar); color: #fff;
  padding: calc(var(--safe-t) + 10px) calc(var(--safe-r) + 14px) 12px calc(var(--safe-l) + 14px);
  display: flex; align-items: center; flex-wrap: wrap; gap: 10px;
}
/* childcare v16 — second row under the bar, admin session only. The negative
   margins paint the brighter blue to the bar edges, under the notch insets. */
.admin-subnav {
  flex: 1 0 100%;
  display: flex; align-items: center; gap: 18px;
  margin: 0 calc(-1 * (var(--safe-r) + 14px)) -12px calc(-1 * (var(--safe-l) + 14px));
  padding: 8px calc(var(--safe-r) + 14px) 10px calc(var(--safe-l) + 14px);
  background: var(--brand-nav);
}
.admin-subnav a {
  color: #fff; font-size: 13px; font-weight: 700; text-decoration: none;
}
.bar .back {
  width: 38px; height: 38px; flex: 0 0 38px; padding: 0;
  border: none; border-radius: 11px;
  background: rgba(255, 255, 255, .14); color: #fff;
  font-size: 20px; font-weight: 700; line-height: 1;
}
.bar .title {
  flex: 1; min-width: 0; margin: 0;
  font-size: 15.5px; font-weight: 700; line-height: 1.2;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.bar .wordmark { font-size: 15.5px; font-weight: 800; letter-spacing: .08em; text-transform: uppercase; }
.swchip {
  flex: none; display: inline-flex; align-items: center; gap: 6px;
  border: none; border-radius: 9px; padding: 5px 9px;
  background: rgba(255, 255, 255, .16); color: #fff;
  font-size: 11px; font-weight: 800; letter-spacing: .03em; text-transform: uppercase;
  white-space: nowrap;
}
.swdot { width: 7px; height: 7px; border-radius: 50%; background: var(--todo); }
.sw-ready .swdot { background: var(--done); }
.sw-registering .swdot { background: var(--todo); }
.sw-unsupported .swdot { background: var(--s1); }
.sw-failed .swdot { background: var(--s1); }
.sw-dev-url .swdot { background: #9fb0b9; }

.bar .prog {
  flex: none; font-size: 12px; font-weight: 700;
  padding: 5px 9px; border-radius: 9px;
  background: rgba(255, 255, 255, .16); color: #fff;
  font-variant-numeric: tabular-nums;
}
.bar .admin-badge {
  flex: none; margin-left: auto;
  display: inline-flex; align-items: center;
  padding: 5px 9px; border-radius: 9px;
  background: rgba(255, 255, 255, .16); color: #fff;
  font-size: 11px; font-weight: 800; letter-spacing: .03em; text-transform: uppercase;
  white-space: nowrap;
}
.bar .bar-logout {
  flex: none; width: auto; margin: 0; padding: 5px 11px;
  border: none; border-radius: 9px;
  background: #c62828; color: #fff;
  font-size: 12px; font-weight: 700; line-height: 1.2;
  white-space: nowrap;
}

/* ---------- layout ---------- */

main { padding: 12px calc(var(--safe-r) + 15px) 0 calc(var(--safe-l) + 15px); }   /* §3 page gutter 15px, + A67 notch */
.stack > * + * { margin-top: 10px; }      /* §3 gap between stacked cards */

/* the one animation curve in the app (§8) */
@keyframes sheet-in { from { transform: translateY(14px); opacity: 0; } to { transform: none; opacity: 1; } }
.sheet-enter { animation: sheet-in .26s var(--ease-sheet) both; }

h2 { font-size: 17px; font-weight: 700; line-height: 1.2; margin: 0 0 2px; }
h3 { font-size: 16px; font-weight: 600; line-height: 1.2; margin: 0 0 6px; }
h4 {
  font-size: 11px; font-weight: 800; letter-spacing: .06em; text-transform: uppercase;
  color: var(--ink-2); margin: 16px 0 6px;
}
p { margin: 2px 0; }
.muted { color: var(--ink-2); font-size: 12.5px; font-weight: 500; }
/* childcare v20 — AUTH-6 invite form: inline validation, not rating colours. */
.hub-meta .form-error,
.form-error {
  color: #b00020;
  font-size: 12.5px;
  font-weight: 700;
  margin-top: 12px;
  line-height: 1.45;
}
.form-error[hidden] { display: none; }
.crumb { color: var(--ink-2); font-size: 12.5px; font-weight: 600; }
.prose { line-height: 1.5; }

/* ---------- §6 cards, rows, panels ---------- */

.card-surface, .panel, .hub-meta {
  background: var(--card); border: 1px solid var(--line); border-radius: 14px;
}
.panel { overflow: hidden; }
.hub-meta { padding: 14px 15px; }

/* ---------- §5 buttons ---------- */

button { font: inherit; cursor: pointer; color: var(--ink); }
.btn {
  width: 100%; padding: 15px; border: none; border-radius: 13px;
  font-size: 15.5px; font-weight: 700; background: #fff;
}
a.btn { display: block; box-sizing: border-box; text-align: center; text-decoration: none; color: var(--ink); }
a.btn.btn-primary { color: #fff; }
.btn-primary { background: var(--brand); color: #fff; }
.btn-secondary {
  border: 1.5px solid var(--line); background: #fff;
  border-radius: 11px; padding: 10px 13px; font-size: 14.5px; font-weight: 700;
}
/* childcare v23 — admin user list disable/enable actions (AUTH-7). */
.btn-user-disable {
  background: #F27D66;
  color: #fff;
  border: none;
}
.btn-user-enable {
  background: #3dc354;
  color: #fff;
  border: none;
}
.btn-user-resend {
  background: #3b63ed;
  color: #fff;
  border: none;
}
.working { opacity: .6; }

label { display: block; font-size: 11px; font-weight: 800; letter-spacing: .06em;
        text-transform: uppercase; color: var(--ink-2); margin: 14px 0 6px; }
/* A67 — 16px is LOAD-BEARING, not a type choice.
   Mobile Safari zooms the page IN when a text field smaller than 16px takes
   focus, and it does not zoom back out. The fixed full-screen panels (the burst
   camera, the photo viewer) are laid out to the unzoomed width, so once that
   has happened their right-hand controls — Done, Phone camera — are outside
   what you can see, and pinching out is the only way back. That is the reported
   bug, and it explains why it struck the camera and the viewer AFTER typing on
   the defect screen. 16px is the accessible fix; forbidding pinch-zoom in the
   viewport meta is not, and index.html must never start doing it. */
input, textarea, select {
  width: 100%; font: inherit; font-size: 16px; font-weight: 500;
  padding: 12px; border: 1.5px solid var(--line); border-radius: 11px;
  background: #fff; color: var(--ink);
}
textarea { line-height: 1.45; }
.row { display: flex; gap: 8px; align-items: center; }
.row input { flex: 1; }

/* ---------- job hub ---------- */

.hub-meta .bigcount { font-size: 28px; font-weight: 800; line-height: 1.1; margin-top: 8px; font-variant-numeric: tabular-nums; }
.hub-meta .bigcount span { font-size: 12.5px; font-weight: 600; color: var(--ink-2); }
.bar-track { height: 6px; background: #efefef; border-radius: 3px; overflow: hidden; margin: 8px 0 12px; }
.bar-track i { display: block; height: 100%; background: var(--brand); }

/* ---------- category rows (§6 .row) ---------- */

.cat {
  display: flex; align-items: center; gap: 13px; width: 100%; text-align: left;
  background: var(--card); border: 1px solid var(--line); border-radius: 14px;
  padding: 16px 15px;
}
.cat + .cat { margin-top: 10px; }
.cat-body { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.cat-title { display: block; font-size: 16px; font-weight: 600; line-height: 1.2; }
.cat-meta { display: block; font-size: 12.5px; font-weight: 500; color: var(--ink-2); margin-top: 2px; }
.count {
  flex: none; font-size: 12px; font-weight: 700; padding: 3px 9px;
  border-radius: 20px; background: #efefef; color: var(--ink-2);
  font-variant-numeric: tabular-nums;
}
.chev { flex: none; color: #b9c1c6; font-size: 20px; font-weight: 700; line-height: 1; }

/* status dot — three states (A24). Navy = has ratings; it is a completion
   signal, not a grade, so it never borrows a colour from the rating scale. */
.dot { flex: none; width: 14px; height: 14px; border-radius: 50%; border: 2px solid #cfcfcf; background: #fff; }
.dot-accounted { border-color: #9fb0b9; background: #9fb0b9; }
.dot-scored { border-color: var(--brand); background: var(--brand); }

/* ---------- measure list (§6 .panel + .item) ---------- */

.panel + .panel { margin-top: 10px; }
.sys-head {
  display: flex; justify-content: space-between; align-items: center; gap: 10px;
  padding: 11px 15px; background: #fafafa; border-bottom: 1px solid var(--line);
  font-size: 11px; font-weight: 800; letter-spacing: .06em; text-transform: uppercase;
  color: var(--ink-2);
}
.sys-head b { color: var(--ink); font-size: 12px; font-variant-numeric: tabular-nums; }

.mrow { display: flex; align-items: center; gap: 8px; padding: 0 13px; border-bottom: 1px solid var(--line); }
.mrow:last-child { border-bottom: none; }
.mrow-open {
  flex: 1; min-width: 0; display: flex; align-items: center; gap: 11px;
  border: none; background: none; padding: 12px 0; text-align: left;
}
/* Measure names run long ("Reticulation System (Steam Production)"). Two lines
   maximum, or the list stops being scannable and the rows lose a common rhythm. */
.mrow-name {
  flex: 1; min-width: 0; font-size: 14.5px; font-weight: 550; line-height: 1.25;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}

/* A28 — the scores, worst first, one line, never wrapping. */
.scorestrip { flex: none; display: flex; gap: 4px; align-items: center; white-space: nowrap; }
.sbox {
  min-width: 21px; padding: 3px 6px; border-radius: 7px;
  font-size: 11.5px; font-weight: 800; line-height: 1.25; text-align: center;
  font-variant-numeric: tabular-nums;
}
.smore { font-size: 11.5px; font-weight: 800; color: var(--ink-2); padding-left: 1px; }

.mrow-fast { flex: none; display: flex; gap: 4px; }
.pill {
  border: 1.5px solid var(--line); background: #efefef; color: var(--ink-2);
  border-radius: 7px; padding: 4px 7px;
  font-size: 10.5px; font-weight: 800; letter-spacing: 0; text-transform: uppercase;
  white-space: nowrap;
}
.pill.on { background: var(--brand); border-color: var(--brand); color: #fff; }
.pill-wide { flex: 1; padding: 11px 8px; font-size: 12px; border-radius: 11px; }

/* ---------- the measure sheet ---------- */

.sheet-card { background: var(--card); border: 1px solid var(--line); border-radius: 14px; padding: 16px 15px; }
.std { font-size: 12.5px; font-weight: 600; line-height: 1.45; margin: 6px 0 0; }
.std .muted { font-weight: 500; }

.scores { display: flex; gap: 6px; }
.score {
  flex: 1 1 0; min-width: 0;      /* equal tiles — content widths differ a lot */
  display: flex; flex-direction: column; align-items: center; gap: 4px;
  padding: 9px 2px; border: 1.5px solid var(--line); border-radius: 11px; background: #fff;
}
.score b {
  display: flex; align-items: center; justify-content: center;
  width: 30px; height: 30px; border-radius: 9px; font-size: 15px; font-weight: 800;
}
.score span { font-size: 10px; font-weight: 700; color: var(--ink-2); text-align: center; line-height: 1.15; }
.score.on { border-color: var(--brand); border-width: 2px; background: #eef3f6; }
.score.on span { color: var(--ink); }

/* ---------- A69: a measure rated on its own words ----------
 * Sits directly under the rating tiles on the two measures that have their own
 * 1-5 wording, and nowhere else — the other 96 draw nothing here at all.
 * Reference text, not a control: quiet, readable, and clearly not something to
 * tap. Deliberately no heading — A69 says the five lines and nothing else, and
 * sitting under "Rating" is what says what they are. */
.ratinghelp {
  margin-top: 8px; padding: 10px 12px;
  border: 1px solid var(--line); border-radius: 11px; background: #fafafa;
}
.ratingline {
  margin: 0; font-size: 12.5px; font-weight: 500; line-height: 1.45; color: var(--ink-2);
}
.ratingline + .ratingline { margin-top: 6px; }
.ratingline b { color: var(--ink); font-weight: 800; }

/* ---------- A70: copy the description you picked into the note ----------
 * Sits directly under the A69 block, on the same two measures and no others —
 * the same gate draws both, so this line can never appear where the five
 * descriptions do not.
 *
 * The colours are the app's EXISTING amber hint, the same three values
 * .tagprompt and the storage warning already use: #fbf1df fill, #f2cf94 edge,
 * #7a5310 ink, measured for contrast on a phone read outdoors. No new colour
 * is introduced here, and deliberately none of the 1-5 scale's — an amber that
 * borrowed --s3 would read as a rating on a screen whose whole subject is
 * ratings. tests/copyhint.test.js measures this against .tagprompt on the
 * shipped stylesheet rather than trusting the hex above. */
.ratingcopyhint {
  margin: 8px 0 0; padding: 10px 12px; border-radius: 11px;
  background: #fbf1df; border: 1px solid #f2cf94; color: #7a5310;
  font-size: 12.5px; font-weight: 700; line-height: 1.45;
}

/* Childcare v10 — the compliance prompt is the same amber hint, under the note box. */
.compliancehint { margin-top: 8px; }
/* Childcare v12 — Not reached here, and the long-asset-field warning */
.chip-nr { background: #eceff1; color: #37474f; border: 1px solid #b0bec5; }
.score.chip-nr.on { border-color: var(--brand); border-width: 2px; }
.nrtiles { margin-top: 8px; }
.assetwarn { margin: 4px 0 0; color: #b3251f; font-size: 12.5px; font-weight: 700; }
.assetwarn[hidden] { display: none; }
.assetbox { margin-top: 14px; border: 1px solid var(--line); border-radius: 11px; padding: 10px 12px; }
.assetbox summary { font-weight: 800; cursor: pointer; }
.assetbox input { width: 100%; box-sizing: border-box; }
.assetbox label { margin-top: 10px; }

.chips { display: flex; flex-wrap: wrap; gap: 8px; }
.chip-loc {
  border: 1.5px solid var(--line); background: #fff; border-radius: 20px;
  padding: 7px 13px; font-size: 13px; font-weight: 600; color: var(--ink-2);
}
.chip-loc.on { background: var(--brand); border-color: var(--brand); color: #fff; }
.chip-loc.reserved { font-style: italic; }
.loc-add {
  border: 1.5px dashed #c2c2c2; background: #fafafa; border-radius: 20px;
  padding: 7px 13px; font-size: 13px; font-weight: 700; color: var(--brand);
}
.filebtn {
  display: block; text-align: center; padding: 14px;
  border: 1.5px dashed #c2c2c2; background: #fafafa; border-radius: 11px;
  color: var(--brand); font-size: 13.5px; font-weight: 700;
  margin: 0; letter-spacing: 0; text-transform: none;
}
.filebtn input { display: none; }
.savebar { margin-top: 16px; gap: 8px; }
.savebar .btn { flex: 1; width: auto; }
.savebar .btn-secondary { flex: 0 0 auto; }

/* ---------- score chips, shared by every surface ---------- */

.chip {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 20px; padding: 2px 6px; border-radius: 7px;
  font-size: 11.5px; font-weight: 800; font-variant-numeric: tabular-nums;
}
.chip.chip-5, .sbox.chip-5, .score.chip-5 b { background: var(--s5); color: var(--on-s5); }
.chip.chip-4, .sbox.chip-4, .score.chip-4 b { background: var(--s4); color: var(--on-s4); }
.chip.chip-3, .sbox.chip-3, .score.chip-3 b { background: var(--s3); color: var(--on-s3); }
.chip.chip-2, .sbox.chip-2, .score.chip-2 b { background: var(--s2); color: var(--on-s2); }
.chip.chip-1, .sbox.chip-1, .score.chip-1 b { background: var(--s1); color: var(--on-s1); }
/* Childcare fork — the M chip, on every surface the 1-5 chips appear on. */
.chip.chip-major, .sbox.chip-major, .score.chip-major b { background: var(--m-major); color: var(--on-m-major); }
.chip.chip-minor, .sbox.chip-minor, .score.chip-minor b { background: var(--m-minor); color: var(--on-m-minor); }

/* Childcare fork — the Major / Minor defect tiles under the 1-5 tiles, and the
   comment box they open. */
.defects { display: flex; gap: 6px; margin-top: 6px; }
.defects .score { flex-direction: row; justify-content: center; gap: 8px; padding: 8px 6px; }
.defects .score span { font-size: 12px; }
.defectbox {
  position: fixed; inset: 0; z-index: 80; display: flex; align-items: flex-end; justify-content: center;
  background: rgba(10, 20, 28, .45);
  padding: 0 max(12px, env(safe-area-inset-right)) max(12px, env(safe-area-inset-bottom)) max(12px, env(safe-area-inset-left));
}
.defectbox[hidden] { display: none; }
.defectbox-card {
  width: 100%; max-width: 560px; background: #fff; border-radius: 14px; padding: 16px 15px;
  display: flex; flex-direction: column; gap: 10px;
}
.defectbox-card h3 { margin: 0; display: flex; align-items: center; gap: 8px; font-size: 16px; }
.defectbox-card textarea { width: 100%; min-height: 110px; font-size: 16px; }
.defectbox-card select { width: 100%; font-size: 16px; padding: 9px 10px; border-radius: 10px; }
.defectbox-card input { width: 100%; font-size: 16px; padding: 9px 10px; border-radius: 10px; box-sizing: border-box; }
.defectbox-card input[hidden] { display: none; }
.defectbox-card .row { display: flex; gap: 8px; }
.defectbox-card .btn { flex: 1; }

.badge {
  font-size: 11px; font-weight: 800; letter-spacing: .03em; text-transform: uppercase;
  padding: 3px 8px; border-radius: 7px; background: #efefef; color: var(--ink-2);
}

.entries { list-style: none; margin: 6px 0 0; padding: 0; }
.entries li {
  display: flex; gap: 8px; align-items: center; flex-wrap: wrap;
  padding: 10px 0; border-bottom: 1px solid var(--line); font-size: 13px; font-weight: 500;
}
.entries li:last-child { border-bottom: none; }
.entries b { font-weight: 700; }
.note { color: var(--ink-2); }
.see { display: block; color: var(--brand); font-weight: 600; font-size: .92em; }
.thumb {
  width: 44px; height: 44px; border-radius: 8px; border: 1px solid var(--line);
  /* A54 — CONTAIN, not cover: a finding photo is evidence, so no part of the
     defect is cropped off to fill a square. The backdrop makes the letterbox
     read as deliberate rather than as a half-loaded image. */
  object-fit: contain; background: #eef2f4;
}
.link { border: none; background: none; color: var(--ink-2); font-size: 12.5px; font-weight: 700; text-decoration: underline; padding: 0; }

/* ---------- review ---------- */

.two { display: grid; gap: 10px; }
@media (min-width: 720px) { .two { grid-template-columns: 1fr 1fr; } }
.grp { margin: 10px 0; }
.grp-name { font-size: 13px; font-weight: 700; }
.sys-name { font-size: 11px; font-weight: 800; letter-spacing: .06em; text-transform: uppercase; color: var(--ink-2); margin: 8px 0 2px; }
.meas { padding-left: 6px; }
.meas-name { font-size: 13px; font-weight: 600; }
.tallybar { display: inline-flex; gap: 4px; align-items: center; flex-wrap: wrap; }
.tallybar i { font-style: normal; font-size: 12px; font-weight: 700; margin-right: 6px; font-variant-numeric: tabular-nums; }
.reconcile { font-size: 12.5px; font-weight: 700; }
.reconcile .ok { color: #2f7d5b; }
.reconcile .bad { color: var(--s1); }

/* ---------- toast ---------- */

#flash {
  position: fixed; z-index: 60;
  left: calc(var(--safe-l) + 15px); right: calc(var(--safe-r) + 15px);
  bottom: calc(var(--safe-b) + 18px);
  padding: 12px 14px; border-radius: 11px;
  background: rgba(20, 20, 20, .92); color: #fff;
  font-size: 13.5px; font-weight: 700; text-align: center;
  transition: opacity .26s var(--ease-sheet);
}
#flash:empty { opacity: 0; }
#flash.bad { background: var(--s1); }

/* ---------- report fragment ---------- */

.fragment { border-left: 3px solid var(--brand); padding-left: 12px; }
.fragment h2 { font-size: 16px; }
.entry { border-bottom: 1px solid var(--line); padding: 10px 0; }
.entry:last-child { border-bottom: none; }
.entry-head { display: flex; gap: 8px; align-items: center; }
.loc { color: var(--ink-2); font-size: 12.5px; font-weight: 600; }
.action { font-size: 11.5px; font-weight: 500; color: var(--ink-2); }
.shot { max-width: 100%; border-radius: 8px; border: 1px solid var(--line); margin-top: 6px; }
.caveat { font-size: 11.5px; font-weight: 500; line-height: 1.45; color: var(--ink-2); border-top: 1px solid var(--line); padding-top: 8px; margin-top: 8px; }
.state { font-size: 11px; font-weight: 800; letter-spacing: .06em; text-transform: uppercase; color: var(--ink-2); }
.tally { margin-top: 10px; }

footer { padding: 20px 15px; text-align: center; }
footer a { color: var(--ink-2); font-size: 12.5px; font-weight: 600; }

/* ---------- A30 settings + details screens ---------- */

.tickrow {
  display: flex; align-items: flex-start; gap: 10px; margin: 12px 0 6px;
  font-size: 14px; font-weight: 600; color: var(--ink);
  text-transform: none; letter-spacing: 0;
}
.tickrow input[type="checkbox"] { width: 22px; height: 22px; flex: none; margin: 0; accent-color: var(--brand); }
.signpreview {
  font-size: 13.5px; font-weight: 700; color: var(--ink);
  background: #f2f4f5; border-radius: 11px; padding: 11px 12px; margin-top: 4px; line-height: 1.4;
}

.logo-preview { max-height: 56px; max-width: 200px; border: 1px solid var(--line); border-radius: 8px; background: #fff; }
.sig-preview { max-height: 70px; max-width: 220px; border: 1px solid var(--line); border-radius: 8px; background: #fff; }
.sigpad {
  width: 100%; height: 160px; margin-top: 6px;
  border: 1.5px dashed #c2c2c2; border-radius: 11px; background: #fff;
  touch-action: none;                 /* the pad draws; the page must not scroll under the finger */
}

.termsbox {
  max-height: 220px; overflow-y: auto;
  border: 1px solid var(--line); border-radius: 11px; padding: 10px 12px; background: #fafafa;
}
.termsblock { font-size: 11.5px; line-height: 1.45; color: var(--ink-2); margin: 0 0 10px; }
.termsblock b { color: var(--ink); }
.termsblock i { font-style: italic; }

/* ---------- A35 view + edit a logged entry ---------- */

.entry-row { display: flex; align-items: center; gap: 6px; }
.entry-open {
  flex: 1; min-width: 0; display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  border: none; background: none; padding: 4px 0; text-align: left; font: inherit;
  font-size: 13px; font-weight: 500;
}
.entry-open b { font-weight: 700; }
.entry-row.editing { background: #eef3f6; border-radius: 8px; }
.editbanner {
  background: #eef3f6; border: 1.5px solid var(--brand); border-radius: 11px;
  padding: 10px 12px; margin: 14px 0 0; font-size: 13px; font-weight: 700; color: var(--brand);
}
.editbanner .link { color: var(--brand); margin-left: 6px; }

.photoslot { position: relative; display: inline-block; }
.photodel {
  position: absolute; top: -6px; right: -6px;
  width: 22px; height: 22px; min-height: 0; padding: 0; border-radius: 50%;
  border: 1.5px solid #fff; background: var(--s1); color: #fff;
  font-size: 14px; font-weight: 800; line-height: 1;
}

/* ---------- A38/A49/A52 report actions ----------
 * The inline PDF frame that used to live here is GONE (A52): it only ever
 * showed page 1, and the phone's own viewer shows all of them. */

.actionhint {
  margin: 6px 0 0; font-size: 11.5px; font-weight: 500;
  color: var(--ink-2); line-height: 1.4;
}

/* ---------- A40 cover photo ---------- */

/* A57 — the WHOLE building shot, like the finding photos: never cropped, never
   stretched (this reverses A54's crop-to-fill, which cut the top and bottom off
   the building). No fixed-height band: the box takes the photo's own shape
   inside the max bounds, so there are no letterbox bars and no frame line.
   object-fit: contain stays as the guarantee should a height ever be fixed. */
.covercard .cover-thumb {
  display: block; margin: 0 auto;
  width: auto; height: auto; max-width: 100%; max-height: 190px;
  object-fit: contain; border-radius: 11px;
}

/* ---------- A41 storage chip ---------- */

.storagechip {
  margin-top: 4px; padding: 10px 12px; border-radius: 11px;
  background: #eef2f4; border: 1px solid var(--line);
  font-size: 12px; font-weight: 600; color: var(--ink-2); line-height: 1.4;
}
.storagechip.warn { background: #fbf1df; border-color: #f2cf94; color: #7a5310; }

/* ---------- A43 save-failure banner ----------
 * Sticky on purpose. The toast this replaces disappeared after six seconds,
 * which is how "looked saved, wasn't" happened: the message went away and the
 * observation stayed on screen. This stays until a write actually succeeds. */

#savebanner:empty { display: none; }
.savebanner {
  margin: 0; padding: 12px 14px;
  border-bottom: 1px solid #7d1a16;
  background: var(--s1); color: #fff;
  font-size: 13px; font-weight: 700; line-height: 1.45;
}
.savebanner .link { color: #fff; margin-left: 6px; font-weight: 800; }

/* ---------- A46 walk-past capture + unsorted bucket ----------
 * The bucket is not observations, and must never look like them: no rating
 * colours anywhere in here, and an amber edge on anything missing its note. */

.walkcard h3 { margin: 0 0 4px; font-size: 14px; font-weight: 800; }

.unsortedbtn {
  display: block; width: 100%; margin-top: 10px; padding: 11px 13px;
  border: 1.5px dashed var(--line); border-radius: 11px;
  background: #eef2f4; color: var(--ink-2); text-align: left; font: inherit;
}
.unsortedbtn b { display: block; font-size: 13px; font-weight: 800; color: var(--ink); }
.unsortedbtn span { font-size: 12px; font-weight: 600; }
.unsortedbtn.needsnote { background: #fbf1df; border-color: #f2cf94; color: #7a5310; }
.unsortedbtn.needsnote b { color: #7a5310; }

.unsorted-item { border-left: 3px solid var(--line); }
.unsorted-item.needsnote { border-left-color: #e0a12a; background: #fdf8ef; }
.unsorted-loc { margin: 8px 0 2px; font-size: 13.5px; font-weight: 800; }
.unsorted-note { margin: 0 0 10px; font-size: 12.5px; font-weight: 500; color: var(--ink-2); }
.unsorted-note .nonote { color: #8a5a10; font-weight: 700; }

.tagprompt {
  margin: 0; padding: 11px 13px; border-radius: 11px;
  background: #fbf1df; border: 1px solid #f2cf94; color: #7a5310;
  font-size: 12.5px; font-weight: 700; line-height: 1.45;
}
.thumb-lg { width: 96px; height: 96px; object-fit: contain; background: #eef2f4; }

.assignbanner { background: #eef2f4; border-color: var(--ink-2); color: var(--ink); }

/* ---------- A50 optional category chip on a walk-past capture ----------
 * Chips are NEUTRAL: they carry no rating meaning and must never borrow the
 * 1-5 scale's colours. Selected reads as chosen, not as scored. */

.optional {
  font-size: 10.5px; font-weight: 700; text-transform: uppercase; letter-spacing: .06em;
  color: var(--ink-2); background: #eef2f4; border: 1px solid var(--line);
  border-radius: 999px; padding: 2px 7px; margin-left: 6px; vertical-align: middle;
}

.chip-cat {
  border: 1.5px solid var(--line); border-radius: 999px;
  background: #fff; color: var(--ink-2);
  padding: 8px 12px; font-size: 12.5px; font-weight: 700;
}
.chip-cat.on { background: var(--brand); border-color: var(--brand); color: #fff; }

.bucket-group {
  display: flex; justify-content: space-between; align-items: baseline; gap: 10px;
  margin: 18px 0 6px; font-size: 11px; font-weight: 800;
  letter-spacing: .06em; text-transform: uppercase; color: var(--ink-2);
}
.bucket-group b { font-size: 12px; font-variant-numeric: tabular-nums; color: var(--ink); }

.assigncat {
  display: inline-block; margin-left: 6px; padding: 1px 7px; border-radius: 999px;
  background: var(--brand); color: #fff; font-size: 11px; font-weight: 800;
}

/* --- A51: the burst camera --------------------------------------------------
   A full-bleed panel over everything, because a viewfinder that shares the
   screen with a form is a viewfinder nobody can aim. It lives outside #app
   (index.html) so a re-render cannot tear the live stream down mid-burst.
   Controls sit inside the safe area: on a phone the shutter is where the thumb
   already is, and Done is nowhere near it.                                    */

.burstbtn { width: 100%; margin-top: 4px; }
.bursthint { margin: 6px 0 12px; }

.cap {
  position: fixed; inset: 0; z-index: 60;
  background: #000; color: #fff;
  display: flex; flex-direction: column;
}
.cap[hidden] { display: none; }
body.capturing { overflow: hidden; }
/* v21 — the WHOLE camera, not one part of it: a second finger on the viewfinder,
   the bars or the shutter must never hand the gesture to Safari, which zooms and
   slides the page until the shutter is off the screen. Taps still fire; this
   takes away only panning and zooming, of which the camera needs neither. */
.cap { touch-action: none; }

.cap video {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  /* cover, not contain: the frame the shutter grabs is the whole sensor frame
     either way (drawImage uses videoWidth/Height), so this is framing only. */
  object-fit: cover;
  background: #000;
}

.cap-flash {
  position: absolute; inset: 0; background: #fff;
  opacity: 0; pointer-events: none;
}
.cap-flash.on { opacity: .85; transition: opacity .18s ease-out; }

.cap-top {
  position: relative; z-index: 2;
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  padding: calc(var(--safe-t) + 10px) calc(var(--safe-r) + 14px) 10px calc(var(--safe-l) + 14px);
  background: linear-gradient(#000c, #0000);
}
.cap-btn {
  border: 1.5px solid #ffffff59; border-radius: 999px;
  background: #00000059; color: #fff;
  padding: 8px 14px; font-size: 13px; font-weight: 700;
}
.cap-where {
  flex: 1; text-align: center; font-size: 12.5px; font-weight: 700;
  color: #ffffffcc; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

.cap-msg {
  position: relative; z-index: 2;
  margin: 10px calc(var(--safe-r) + 14px) 10px calc(var(--safe-l) + 14px);
  padding: 10px 12px; border-radius: 11px;
  background: #000000a6; border: 1px solid #ffffff2e;
  font-size: 12.5px; font-weight: 600; line-height: 1.45;
  display: none;
}
.cap-msg.on { display: block; }
.cap-msg.flash { background: #7a1b1ba6; border-color: #ffffff40; }

.cap-zoom {
  position: relative; z-index: 2; margin-top: auto;
  display: none; justify-content: center; gap: 8px;
  padding: 10px calc(var(--safe-r) + 14px) 10px calc(var(--safe-l) + 14px);
}
.cap-zoom.on { display: flex; }
.cap-zoom button {
  min-width: 46px; padding: 7px 0; border-radius: 999px;
  border: 1.5px solid #ffffff40; background: #00000066; color: #fff;
  font-size: 12.5px; font-weight: 800; font-variant-numeric: tabular-nums;
}
.cap-zoom button.on { background: #fff; color: #111; border-color: #fff; }

.cap-bottom {
  position: relative; z-index: 2;
  display: grid; grid-template-columns: 1fr auto 1fr; align-items: center;
  padding: 14px calc(var(--safe-r) + 16px) calc(var(--safe-b) + 18px) calc(var(--safe-l) + 16px);
  background: linear-gradient(#0000, #000c);
}
.cap-count {
  font-size: 13px; font-weight: 800; font-variant-numeric: tabular-nums;
  color: #ffffffdd;
}
.cap-count.bad { color: #ff9b9b; }
.cap-shutter {
  width: 74px; height: 74px; border-radius: 50%;
  background: #fff; border: 5px solid #ffffff4d;
  box-shadow: 0 0 0 2px #0006;
}
.cap-shutter:active { transform: scale(.94); }
.cap-shutter:disabled { opacity: .45; }
.cap-side { justify-self: end; }

/* The second door's input is never seen — it is opened by the shutter in phone
   camera mode, or by the labelled button on the screen underneath. */
.cap-file { position: absolute; width: 1px; height: 1px; opacity: 0; pointer-events: none; }

/* --- A66: the full-size photograph, and the drawing layer over it ---------
   Fixed and full-screen, like the burst camera: an inspector marking a defect
   is doing one thing, and a page scrolling behind the photograph is a page
   that will be scrolled by accident mid-drag.

   touch-action:none on the canvas is LOAD-BEARING, not styling. Without it a
   drag across the photograph is delivered to the browser as a pan and the page
   moves instead of a box being drawn — the whole feature failing silently on
   the one device it is for. */
.photoview {
  position: fixed;
  inset: 0;
  z-index: 90;
  display: flex;
  flex-direction: column;
  background: #0b0f13;
  color: #fff;
}
.photoview[hidden] { display: none; }
body.viewing-photo { overflow: hidden; }
/* v21 — the whole viewer, not just the photograph. In v20 only the stage and
   canvas said none; a pinch with a finger on Done, the zoom buttons or the tools
   zoomed the PAGE. Nothing on this panel scrolls. */
.photoview { touch-action: none; }

.pv-top {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: calc(var(--safe-t) + 10px) calc(var(--safe-r) + 12px) 10px calc(var(--safe-l) + 12px);
  background: rgba(0, 0, 0, .45);
}
/* A67 — the measured cause of "Done is off the screen".
   This is a flex item, and a flex item's default min-width is `auto`: it
   refuses to shrink below its own longest word. With a long location name the
   top bar measured 1093px wide on a 390px phone and Done sat 633px past the
   right edge — off the screen, with pinch-zoom the only way to find it. The
   burst camera's equivalent label always had this and the viewer's did not.
   min-width:0 lets it shrink; the ellipsis is what it shrinks INTO, so the
   label is shortened rather than the way out being taken away. */
.pv-where {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  text-align: center;
  font-size: 13px;
  opacity: .75;
}
.pv-btn {
  min-height: 42px;
  padding: 0 16px;
  border: 1px solid rgba(255, 255, 255, .3);
  border-radius: 10px;
  background: rgba(255, 255, 255, .08);
  color: #fff;
  font: inherit;
  font-weight: 600;
}
.pv-btn.pv-done {
  background: #1f7a4d;
  border-color: #1f7a4d;
}

/* The photograph gets every pixel that is left after the bars. */
.pv-stage {
  flex: 1;
  min-height: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 8px calc(var(--safe-r) + 8px) 8px calc(var(--safe-l) + 8px);
  /* A79 — the pinch is caught on the STAGE, not just the canvas: at 1x the
     second finger often lands on the letterbox, and there touch-action:auto
     would let Safari zoom the whole page instead. overflow:hidden keeps a
     zoomed photograph from spilling over Done and the tools. */
  position: relative;
  overflow: hidden;
  touch-action: none;
}
#anno-canvas {
  max-width: 100%;
  max-height: 100%;
  /* A79 — photozoom.js cssTransform() is written for this origin. */
  transform-origin: 0 0;
  touch-action: none;          /* see the note above — this is the feature */
  -webkit-user-select: none;
  user-select: none;
  border-radius: 4px;
}

/* A79 — the gloves-on zoom. 44px is the smallest target a thumb hits reliably. */
.pv-zoom {
  display: flex;
  justify-content: center;
  gap: 8px;
  padding: 6px calc(var(--safe-r) + 12px) 6px calc(var(--safe-l) + 12px);
}
.pv-zbtn {
  min-height: 44px;
  min-width: 44px;
  padding: 0 14px;
  border: 1px solid rgba(255, 255, 255, .3);
  border-radius: 10px;
  background: rgba(255, 255, 255, .08);
  color: #fff;
  font: inherit;
  font-size: 13px;
  font-weight: 600;
}
.pv-zbtn:disabled { opacity: .35; }

.pv-msg {
  margin: 0;
  padding: 0 calc(var(--safe-r) + 14px) 8px calc(var(--safe-l) + 14px);
  font-size: 13px;
  line-height: 1.4;
  opacity: .8;
  text-align: center;
  min-height: 18px;
}

/* Childcare fork — the caption field in the photo viewer. 16px so iOS does not zoom on focus. */
.pv-caption { padding: 0 calc(var(--safe-r) + 12px) 8px calc(var(--safe-l) + 12px); }
.pv-caption input {
  width: 100%; font-size: 16px; padding: 9px 11px; border-radius: 10px;
  border: 1px solid rgba(255,255,255,.35); background: rgba(0,0,0,.35); color: #fff;
}
.pv-caption input::placeholder { color: rgba(255,255,255,.6); }

.pv-tools {
  display: flex;
  gap: 8px;
  padding: 10px calc(var(--safe-r) + 12px) calc(var(--safe-b) + 12px) calc(var(--safe-l) + 12px);
  background: rgba(0, 0, 0, .45);
}
.pv-tool {
  flex: 1;
  min-height: 58px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 3px;
  border: 1px solid rgba(255, 255, 255, .22);
  border-radius: 12px;
  background: rgba(255, 255, 255, .06);
  color: #fff;
  font: inherit;
  font-size: 12px;
  font-weight: 600;
}
.pv-tool svg {
  width: 22px;
  height: 22px;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.pv-tool.on {
  background: #e8342a;
  border-color: #e8342a;
}
.pv-tool:disabled { opacity: .35; }
.pv-tool.pv-del:not(:disabled) { color: #ff9d95; }

/* A66 — a photograph anywhere on the app is a door to the full-size view. */
.photo-open { cursor: zoom-in; }
.photo-marked { outline: 2px solid #e8342a; outline-offset: 1px; }
.entry-thumb {
  flex: 0 0 auto;
  align-self: center;
}
