/* ══════════════════════════════════════════════════════════════════════════
   MYXIMUS INSPECT — N3d FIELD CAPTURE.

   The design constraint is inherited from www/style.css and is not softened,
   because this is the surface it was written about: used ONE-HANDED, on a
   phone, standing in a crawlspace or a driveway, sometimes in direct sun,
   sometimes with a glove on.

     · 44px minimum targets, and the primary actions are 56px
     · high contrast in both themes
     · no hover-dependent affordance — there is no hover on a phone
     · nothing that needs animation to be understood
     · no sideways scroll at 320px

   COLOUR IS NEVER THE STATE. Every [data-state] and [data-net] rule below
   tints something whose TEXT already says what it is. Removing every colour
   in this file must leave the interface fully readable — that is the test,
   and it is A-7's "no colour-only state" criterion written as a CSS rule.

   Rule 1: nothing external. No font file, no CDN, no image request.
   ══════════════════════════════════════════════════════════════════════════ */

:root {
  --surface: #f4f6f9;
  --surface-2: #ffffff;
  --text: #10151c;
  --muted: #55606e;
  --border: #d7dde5;
  --border-strong: #7b8694;
  --accent: #0f5fd0;
  --accent-text: #ffffff;
  --ok: #17683a;
  --warn: #8a5300;
  --danger: #b3261e;
  --shade: rgba(16, 21, 28, .06);
}

@media (prefers-color-scheme: dark) {
  :root {
    --surface: #0e131b;
    --surface-2: #161d28;
    --text: #eaeef4;
    --muted: #a3aebd;
    --border: #2a3442;
    --border-strong: #8593a5;
    --accent: #67a6ff;
    --accent-text: #08101c;
    --ok: #57d08a;
    --warn: #f0b24a;
    --danger: #ff8a80;
    --shade: rgba(255, 255, 255, .06);
  }
}

* { box-sizing: border-box; }

/* 🔴 `[hidden]` MUST WIN. THIS IS NOT DEFENSIVE, IT IS A FIX.
 *
 * The whole shell hides things with the `hidden` ATTRIBUTE — the binding
 * contract in index.html is written around it. But `hidden` is only a UA
 * stylesheet rule (`display: none`), and ANY author rule that sets `display`
 * beats it on specificity. `.annotate { display: flex }` did exactly that, and
 * the annotation surface rendered full-screen over the login form on first
 * load, before a single photograph existed.
 *
 * This estate has had this precise bug before — the dashboard onboarding modal
 * that could not be dismissed, where `.hide{display:none}` lost to
 * `#onbWrap{display:flex}`. The lesson recorded then was "test the RENDERED
 * DOM, not the JS state", and it is the reason this was caught: every
 * assertion about the markup passed, and the screenshot showed the black
 * annotation surface.
 *
 * `!important` here rather than a per-component `[hidden]` guard, because the
 * per-component version only protects the components somebody remembered.
 */
[hidden] { display: none !important; }

html, body {
  margin: 0;
  background: var(--surface);
  color: var(--text);
  font: 16px/1.45 system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  /* `text-size-adjust` off: a phone that "helpfully" inflates our type breaks
     the 44px grid this layout is built on. */
  -webkit-text-size-adjust: 100%;
}

body.annotating { overflow: hidden; }

.sr {
  position: absolute; width: 1px; height: 1px;
  margin: -1px; padding: 0; overflow: hidden;
  clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* ── the bar ────────────────────────────────────────────────────────────── */
.bar {
  position: sticky; top: 0; z-index: 5;
  display: flex; align-items: center; gap: 8px;
  padding: 10px 12px;
  padding-top: max(10px, env(safe-area-inset-top));
  background: var(--surface-2);
  border-bottom: 1px solid var(--border);
}
/* 🔴 R63.J4.a — THE HEADER MUST NOT OVERFLOW, AND MY OWN J4 FIX BROKE IT.
   Adding the tenant name and the TEST badge to a 393px bar pushed `help` off
   the right edge and wrapped "Inspect Fixture Tenant" onto three lines —
   caught in the very screenshot taken to prove J4 worked. The badges are the
   fixed part (44px each, by J2); the two TEXT items are what must give, so
   the brand and the tenant name shrink and ellipsise.
   The TEST badge never shrinks: it is the thing being made unmissable.

   🔴 AND `nowrap` + `overflow: hidden` IS SUPERSEDED BY OWNER RULING
   `D-20261014-4` (2026-10-14, his words): "the field app's top bar WRAPS to a
   second line when it does not fit; nothing is ever cut off; Sign out is
   always visible." The yield order above had reached its FLOOR — `.brand`
   ellipsed away to nothing and `.badge` is `flex: 0 0 auto` — so the only
   thing left to give was a CONTROL, and `overflow: hidden` took `sign out`
   SILENTLY. That is `FIELD.F36`, found in a looked-at shot and not by a check.

   🔴 THE CLIP IS REMOVED, NOT WIDENED. `overflow: hidden` is deliberately
   GONE rather than left sitting beside `wrap`: with wrapping there is nothing
   to clip horizontally, and if a future item ever cannot fit, this bar must
   overflow VISIBLY rather than eat a control without a word. The silent
   failure is the defect; a visible one is a bug report somebody can act on.

   🔵 THE TEXT ITEMS KEEP THEIR ELLIPSIS, so J4.a's real goal survives intact:
   the wrap happens BETWEEN flex items, never inside a word, so no tenant name
   goes onto three lines again. The bar is occasionally two rows tall, which is
   exactly the trade he was offered and took. */
.bar { flex-wrap: wrap; }
.brand { font-weight: 600; flex: 0 1 auto; min-width: 0;
         overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.badge, .testbadge { flex: 0 0 auto; }
/* 🔴 R63.J4.a — and when it yields, it really is gone. `[hidden]` is
   display:none in the UA sheet, but this stylesheet sets `display` explicitly
   on its neighbours, and the day somebody adds `.brand { display: flex }` the
   brand would come back and squeeze the tenant again without a word. The
   `!important` is the same argument as `.testbadge[hidden]` two rules down. */
.brand[hidden] { display: none !important; }

/* 🔴 R63.J4 — THE TEST BADGE CANNOT BE STYLED AWAY.
   `!important` on display, visibility, opacity and the box, because the whole
   point of this badge is that it is visible on the one tenant where being
   confused about which tenant you are on does real damage. A later stylesheet
   that hid it — deliberately or by collision — would remove exactly the
   warning that matters, and it would do so silently. `field_pwa_test` asserts
   these declarations on the SERVED bytes, so this comment is not the guard. */
/* Shrinks and ellipsises before anything else does: a tenant called
   "Those Guys Inspections (Miami)" must not push `help` off a phone. */
.tenant { font-size: .8rem; font-weight: 600; opacity: .85; margin-left: 8px;
          flex: 0 1 auto; min-width: 0; max-width: 34vw;
          overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.testbadge {
  display: inline-flex !important;
  visibility: visible !important;
  opacity: 1 !important;
  min-height: 44px !important;
  align-items: center; justify-content: center;
  margin-left: 6px; padding: 0 10px;
  font-size: .78rem; font-weight: 800; letter-spacing: .08em;
  border-radius: 999px;
  border: 2px solid var(--danger) !important;
  color: var(--danger) !important;
  background: transparent !important;
}
.testbadge[hidden] { display: none !important; }
.spacer { flex: 1; }

.badge {
  font-size: .8rem; font-weight: 600;
  padding: 6px 10px; border-radius: 999px;
  border: 1px solid var(--border-strong);
  background: transparent; color: var(--text);
}
/* 🔴 R63.J2 — 44x44 MINIMUM, ON EVERY TOP-BAR CONTROL.
   Measured in the feel-pass: `help` was 47x36 and `queue` 69x36 — both under
   the figure Apple's HIG and WCAG 2.5.5 both use, and both in the corner a
   thumb reaches for while holding a ladder. The rule is on `.badge` rather
   than only on `.badge-btn` because `netbadge` is a span today and would be a
   button the day somebody makes it one. */
.badge { min-height: 44px; min-width: 44px; display: inline-flex;
         align-items: center; justify-content: center; }
.badge-btn { cursor: pointer; }
.badge[data-net="offline"] { border-color: var(--warn); color: var(--warn); }

main { padding: 16px 12px 96px; max-width: 720px; margin: 0 auto; }

h1 { font-size: 1.4rem; margin: 4px 0 12px; }
h2 { font-size: 1.05rem; margin: 20px 0 8px; }
.sub { color: var(--muted); margin: 0 0 12px; }

/* D-20260923-11 ROW 1 — THE ONE LINE.
   Deliberately NOT `--muted`: the service list above it is a label, and this
   is the job's release and payment state, which is what the inspector came to
   this screen to find out.

   🔴 IT WRAPS, AND THE WRAP IS THE DECISION. At 390px the longest clause pair
   this function can compose — "Revision not signed yet · unpaid — collect
   off-app" — does not fit one line at this weight, and both ways of making it
   fit lie about something:

     · `white-space: nowrap` + `text-overflow: ellipsis` renders the payment
       half as "…" — turning "unpaid" into a sentence the server did not write,
       on the exact surface where the owner needs to read it;
     · shrinking the type makes the most load-bearing line on the screen the
       hardest one to read in direct sun, against this file's own constraint.

   So it wraps to two lines and says the whole thing. `field_words_test` pins
   the ABSENCE of both properties on this id, because the next person tidying
   a layout would reach for `nowrap` and nothing would look broken.

   And no colour: this file's header rule is COLOUR IS NEVER THE STATE. The
   words carry it. */
#release-line {
  color: var(--text); font-weight: 600; margin: 0 0 14px;
  overflow-wrap: break-word;
}
.mono { font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
        font-size: .78rem; word-break: break-all; }
.note {
  color: var(--muted); font-size: .88rem;
  margin: 16px 0 0; padding-left: 10px;
  border-left: 3px solid var(--border);
}

.banner {
  margin: 0; padding: 12px;
  border-bottom: 1px solid var(--border);
  background: var(--shade);
  font-size: .92rem;
}
.banner[data-kind="error"] { border-left: 4px solid var(--danger); }

/* ── controls ───────────────────────────────────────────────────────────── */
button, .filebtn, input {
  font: inherit;
  min-height: 44px;
}
.primary, .filebtn {
  display: inline-flex; align-items: center; justify-content: center;
  min-height: 56px; padding: 0 18px;
  border: 0; border-radius: 12px;
  background: var(--accent); color: var(--accent-text);
  font-weight: 600; cursor: pointer;
}
.primary.small, .ghost.small { min-height: 44px; padding: 0 12px;
                               font-size: .88rem; }
.primary.wide { width: 100%; margin-top: 24px; }
.ghost {
  background: transparent; color: var(--text);
  border: 1px solid var(--border-strong); border-radius: 12px;
  padding: 0 14px; cursor: pointer;
}
button:disabled { opacity: .45; cursor: default; }

/* A focus ring that survives both themes and direct sun. Never `outline:none`. */
:focus-visible {
  outline: 3px solid var(--accent);
  outline-offset: 2px;
}

label { display: block; margin: 14px 0 6px; font-weight: 600; }
input[type="text"], input[type="password"] {
  width: 100%; padding: 12px;
  background: var(--surface-2); color: var(--text);
  border: 1px solid var(--border-strong); border-radius: 10px;
}

form .primary { width: 100%; margin-top: 20px; }

.actions { display: flex; flex-wrap: wrap; gap: 10px; }
.actions > * { flex: 1 1 46%; }

/* ── cards and lists ────────────────────────────────────────────────────── */
.card {
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 14px;
  margin: 12px 0;
}
.card.warnish { border-left: 4px solid var(--warn); }
/* AUDIT.F10 — Getting in. The code is read at arm's length in daylight. */
.card.access { border-left: 4px solid var(--border); }
.card.access[data-state="on_file"] { border-left-color: var(--ok, var(--border)); }
.card.access[data-state="not_collected"],
.card.access[data-state="unreadable"],
.card.access[data-state="none_given"] { border-left-color: var(--warn); }
.access-list { display: grid; grid-template-columns: max-content 1fr; gap: 6px 12px; margin: 10px 0; }
.access-list dt { font-weight: 600; }
.access-list dd { margin: 0; overflow-wrap: anywhere; }
.access-code { font-family: ui-monospace, Menlo, Consolas, monospace; font-size: 1.35em; letter-spacing: 0.08em; }
.access-quote { white-space: pre-wrap; margin: 4px 0 10px; }
/* CONT.F1 — the "on another device" notice. A card, not a modal: it must be
   readable and dismissable by scrolling past, never something that blocks a
   tap. Sized at the tap minimum so it is never a sliver between two lists. */
.card.devices { min-height: 44px; }
.card.devices li { min-height: 44px; display: flex; align-items: center; }

.list { list-style: none; margin: 0; padding: 0; }
.list.plain li { border: 0; background: transparent; padding: 8px 0; }

.row {
  display: flex; flex-wrap: wrap; align-items: center; gap: 8px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 12px;
  margin-bottom: 8px;
}
.rowbtn {
  all: unset;
  display: flex; flex-direction: column; gap: 2px;
  flex: 1; min-height: 44px; justify-content: center;
  cursor: pointer;
}
.row-main { font-weight: 600; }
.row-sub { color: var(--muted); font-size: .88rem; flex-basis: 100%; }
.row-state {
  font-size: .78rem; font-weight: 700; text-transform: uppercase;
  letter-spacing: .04em;
  padding: 4px 8px; border-radius: 6px;
  border: 1px solid var(--border-strong);
}
.row-state[data-state="complete"],
.row-state[data-state="trusted"]  { color: var(--ok);     border-color: var(--ok); }
.row-state[data-state="open"],
.row-state[data-state="pending"],
.row-state[data-state="awaiting_trust"] { color: var(--warn); border-color: var(--warn); }
.row-state[data-state="refused"],
.row-state[data-state="revoked"] { color: var(--danger); border-color: var(--danger); }

.grid {
  list-style: none; margin: 0; padding: 0;
  display: grid; gap: 8px;
  grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
}
.cell {
  background: var(--surface-2); border: 1px solid var(--border);
  border-radius: 10px; padding: 8px; font-size: .84rem;
}
.cell img { width: 100%; border-radius: 6px; display: block; }
.cell-cap { display: block; }
.cell-state { display: block; color: var(--muted); font-size: .76rem; }

/* ───────────────────────────────────────────────── R63 — the photo strip */
/* 🔴 SELECTION IS SHOWN BY A BORDER AND A TICK, NOT BY COLOUR ALONE. This app
   is used outdoors, on a phone, in sunlight, by somebody who may be one of the
   ~8% of men with a colour-vision deficiency. A 3px outline survives all
   three; a tint does not. */
.cell[data-sel="1"] { outline: 3px solid var(--accent, #2563eb); outline-offset: 1px; }
.cell[data-sel="1"]::after { content: "✓ selected"; display: block;
  font-size: .74rem; font-weight: 600; color: var(--accent, #2563eb); }
.cell[data-attached="1"]::before { content: "on a finding"; display: block;
  font-size: .7rem; text-transform: uppercase; letter-spacing: .04em;
  color: var(--muted); }
.cell button { margin-top: 6px; width: 100%; }

/* The action bar sits at the bottom of the viewport because the strip is
   scrolled with a thumb and the decision is made after the scrolling. */
.stripbar { position: sticky; bottom: 0; display: flex; flex-wrap: wrap;
  gap: 8px; align-items: center; padding: 10px; margin-top: 12px;
  background: var(--bg, #fff); border-top: 1px solid var(--line, #ddd); }
.stripbar .sub { margin: 0; flex: 1 1 100%; }

/* The picker overlays whatever screen asked for it — it is used from the
   strip AND from the section screen. */
.card.overlay { position: fixed; left: 8px; right: 8px; bottom: 8px;
  max-height: 70vh; overflow: auto; z-index: 20;
  box-shadow: 0 -8px 30px rgba(0, 0, 0, .28); }

.linkish { border: 0; background: transparent; padding: 0 0 0 10px;
  font-size: .82rem; text-decoration: underline; cursor: pointer;
  color: var(--accent, #2563eb); }

.chip {
  background: var(--surface-2);
  border: 1px solid var(--border-strong);
  border-radius: 12px; padding: 12px; margin-bottom: 8px;
}
.chip-text { display: block; font-weight: 600; }
.chip-src { display: block; color: var(--muted); font-size: .82rem;
            margin: 2px 0 10px; }
.chip-actions { display: flex; gap: 8px; }

/* ── the annotation surface ─────────────────────────────────────────────
   Full-screen and NOT a dialog. §8.2: "one tap, no modal" — Spectora burying
   this in modals is the named complaint we are answering, so the layout is
   the answer rather than a comment about it. */
.annotate {
  position: fixed; inset: 0; z-index: 20;
  display: flex; flex-direction: column;
  background: #000; color: #fff;
  padding-bottom: env(safe-area-inset-bottom);
}
.annotate-stage {
  position: relative; flex: 1; min-height: 0;
  display: flex; align-items: center; justify-content: center;
}
.annotate-stage img {
  max-width: 100%; max-height: 100%;
  width: 100%; height: 100%;
  object-fit: contain;
  /* `object-fit: contain` letterboxes the picture inside this box, which is
     exactly why annotate.js has `pointToImage()` — a touch measured against
     the ELEMENT drifts toward the edges, differently on every aspect ratio. */
}
.annotate-stage svg {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  touch-action: none;      /* a drag must draw, not scroll the page */
}
/* 🔴 THE SVG SHARES THE IMAGE'S GEOMETRY, NOT THE ELEMENT'S.
   Its viewBox is set to the photograph's natural pixel size and it uses the
   DEFAULT preserveAspectRatio (xMidYMid meet), which is the same letterboxing
   `object-fit: contain` applies above — so the overlay lands on the picture
   without any correction.

   The first draft used `viewBox="0 0 1 1" preserveAspectRatio="none"`, which
   is tidier to store and wrong to draw: non-uniform scaling turns a circle
   into an ellipse on every photograph that is not square, and stretches the
   glyphs of a caption. Coordinates are still STORED as 0..1 fractions; only
   the rendering multiplies up.

   `vector-effect: non-scaling-stroke` keeps the stroke a constant number of
   SCREEN pixels, so an arrow is equally visible on a 4000px photograph and a
   thumbnail. The dark halo under the caption is not decoration: white text on
   pale stucco in direct sun is invisible without it. */
.an-arrow, .an-circle {
  fill: none; stroke: #ff3b30;
  stroke-width: 3px; stroke-linecap: round;
  vector-effect: non-scaling-stroke;
}
.an-caption {
  fill: #fff; paint-order: stroke;
  stroke: #000; stroke-width: 4px;
  vector-effect: non-scaling-stroke;
  font-family: system-ui, sans-serif; font-weight: 700;
}
.annotate-tools {
  display: flex; gap: 8px; padding: 10px;
  overflow-x: auto;
}
.tool {
  flex: 1; min-height: 56px;
  background: #1c1c1e; color: #fff;
  border: 1px solid #48484a; border-radius: 12px;
  font-weight: 600; cursor: pointer;
}
.tool[aria-pressed="true"] {
  background: #fff; color: #000; border-color: #fff;
}
#annotate-caption {
  margin: 0 10px 10px; padding: 12px;
  background: #1c1c1e; color: #fff;
  border: 1px solid #48484a; border-radius: 10px;
}
.annotate-actions {
  display: flex; gap: 10px; padding: 0 10px 10px;
}
.annotate-actions > * { flex: 1; }
.annotate-actions .ghost { color: #fff; border-color: #8e8e93; min-height: 56px; }

@media (prefers-reduced-motion: reduce) {
  * { animation: none !important; transition: none !important; }
}

/* ── N3e, the field assistant ─────────────────────────────────────────── */
/* 🔴 `.assist-rule` is the sentence that must survive every future edit of
   this screen: personal use, never a report. It is styled to be read, not
   skipped — the same weight as a warning, because it is one. */
.assist-rule { border-left: 4px solid var(--warn, #b45309);
               background: var(--warn-bg, #fffbeb);
               padding: .6rem .8rem; margin: .5rem 0 1rem;
               font-weight: 600; }
.assist-ask { display: flex; flex-direction: column; gap: .5rem; }
.assist-ask textarea { width: 100%; font: inherit; padding: .6rem;
                       border: 1px solid var(--line, #d4d4d8); border-radius: 8px; }
.assist-live { color: #b91c1c; font-weight: 700; }
.assist-heard { font-style: italic; opacity: .8; margin: 0 0 .4rem; }
.assist-text { white-space: pre-wrap; margin: .2rem 0 .6rem; }
/* A citation is the load-bearing part of an answer here, so it reads as
   evidence rather than as a footnote. */
.assist-cite { font-size: .85rem; margin: .15rem 0; padding-left: .6rem;
               border-left: 3px solid var(--ok, #15803d); }
.assist-disclaimer { font-size: .8rem; opacity: .75; margin-top: .8rem; }

/* ── FIELD.F16, the finding form ───────────────────────────────────────── */
/* Inline on the section screen rather than a dialog: a native prompt() is one
   line on a phone, cannot hold a severity, and blocks the page hard enough to
   freeze automation — which is what it does to a browser in an attic too. */
.fnd-form { border: 1px solid var(--line, #d4d4d8); border-radius: 12px;
            padding: 1rem; margin: .75rem 0; background: var(--card, #fff); }
.fnd-form h3 { margin: 0 0 .75rem; }
.fnd-form label { display: block; font-weight: 600; font-size: .9rem;
                  margin: .7rem 0 .25rem; }
.fnd-form textarea, .fnd-form select {
  width: 100%; font: inherit; padding: .6rem;
  border: 1px solid var(--line, #d4d4d8); border-radius: 8px; }
/* Thumb-sized: this is filled in standing up. */
.fnd-form select { min-height: 44px; }
/* The support form (SUPPORT.F4) reuses this shell — same constraints, same
   thumbs. Its text input is styled by the global input[type="text"] rule. */
.fnd-actions { display: flex; gap: .6rem; margin-top: 1rem; }
.fnd-actions button { flex: 1; min-height: 46px; }

/* ── coverage: the segmented control and the disposition sheet ──────────
   🔴 Sized for a thumb in a crawlspace, not for a design review: every
   control is >=48px tall, the sheet fills the bottom of the screen where a
   hand already is, and nothing depends on colour alone — every state has a
   word in it, because a phone in direct Florida sun is effectively greyscale.
*/
.seg { display: flex; gap: 8px; margin: 0 0 12px; }
.seg-btn {
  flex: 1; min-height: 48px; font: inherit; font-weight: 600;
  background: var(--card, #fff); color: inherit;
  border: 1px solid var(--line, #d1d1d6); border-radius: 8px; cursor: pointer;
}
.seg-btn[aria-selected="true"] {
  border-color: var(--accent, #0a5); box-shadow: inset 0 0 0 1px var(--accent, #0a5);
}
.sheet {
  position: fixed; inset: 0; background: rgba(0,0,0,.45);
  display: flex; align-items: flex-end; z-index: 50;
}
.sheet-inner {
  width: 100%; max-height: 86vh; overflow-y: auto;
  background: var(--card, #fff); border-radius: 14px 14px 0 0;
  padding: 16px 16px 24px;
}
.sheet-inner h2 { margin: 0 0 4px; }
.sheet-inner select, .sheet-inner textarea, .sheet-inner input {
  width: 100%; font: inherit; padding: .6rem; min-height: 48px;
  border: 1px solid var(--line, #d1d1d6); border-radius: 8px;
  margin: 0 0 10px; background: var(--card, #fff); color: inherit;
}
.sheet-inner hr { border: 0; border-top: 1px solid var(--line, #d1d1d6);
                  margin: 16px 0; }
.row-state[data-state="excluded"],
.row-state[data-state="skipped"],
.row-state[data-state="not_reached"] { color: var(--warn); border-color: var(--warn); }
.row-state[data-state="scanned"] { color: var(--ok); border-color: var(--ok); }
.row-state[data-state="referral"] { color: var(--muted); border-color: var(--muted); }
.card[data-gate="blocked"] { border-left: 4px solid var(--warn); }
.card[data-gate="ready"]   { border-left: 4px solid var(--ok); }

/* P7.F3: the in-page confirmation keeps the line breaks the words were written with */
.ask-text { white-space: pre-line; margin: 8px 0 16px; }

/* OUTCOME.F1: what the visit came to, on the report screen. The three words
   are the server's, so their length is not this file's to promise: the row
   WRAPS rather than clipping a choice (FIELD.F36's lesson — if one ever cannot
   fit, the row grows visibly instead of eating a control). Thumb-sized, as the
   disposition sheet is: this is set standing in a driveway. */
#oc-pick { flex-wrap: wrap; }
#oc-pick .seg-btn { flex: 1 1 30%; }
/* OUTCOME.F2: the reason is a list of rows, each printed whole. No width and
   no overflow rule on a row: a reason that cannot fit takes another line. */
#oc-reason-set { border: 0; padding: 0; margin: 0; min-width: 0; }
#oc-reason-set legend { font-weight: 600; margin: 14px 0 6px; padding: 0; }
#oc-reason label.choice {
  display: flex; align-items: center; gap: .6rem; min-height: 48px;
  margin: 0 0 8px; padding: .5rem .75rem; font-weight: 400;
  border: 1px solid var(--line, #d1d1d6); border-radius: 8px;
  overflow-wrap: anywhere;
}
#oc-reason label.choice input { flex: none; width: 22px; height: 22px; margin: 0; }
#report-outcome textarea {
  width: 100%; font: inherit; padding: .6rem; min-height: 48px;
  border: 1px solid var(--line, #d1d1d6); border-radius: 8px;
  background: var(--card, #fff); color: inherit;
}
/* FORMJOB.F2: one row per carrier form - its name, its state, and its own
   button; each wraps whole at 390 rather than clipping a long form name. */
#rf-list .rf-row {
  display: flex; flex-direction: column; gap: 6px;
  padding: 10px 0; border-top: 1px solid var(--border);
  overflow-wrap: anywhere;
}
#rf-list .rf-row:first-child { border-top: 0; }
#rf-list .rf-row button { min-height: 48px; white-space: normal; }

/* P7.F7 (2026-10-22): a section is rated IN PLACE. The picker opens inside
   the tapped row (the row is already flex-wrap), so it takes the full width. */
.inplace { flex-basis: 100%; width: 100%; margin-top: 4px; }
.inplace .df-input { display: block; width: 100%; box-sizing: border-box; min-height: 44px; margin: 8px 0; font-size: 1rem; }
.inplace .lim-row { display: flex; align-items: center; gap: 10px; min-height: 44px; }
.inplace .lim-row input { width: 22px; height: 22px; }

/* ── D-20261023-7: the Forms screen ──────────────────────────────────────
   A thumb's worth of target on every answer, the form's words beside it, and
   the Q9 chart as the form's own grid at 390px. */
.fa-group h2 { margin: 0 0 8px; }
.fa-line { margin: 0 0 14px; }
.fa-choice { border: 0; padding: 0; margin: 0; }
.fa-choice legend { font-weight: 600; margin: 0 0 6px; }
.fa-opt, .fa-check {
  display: flex; gap: 10px; align-items: flex-start; min-height: 44px;
  margin: 0; padding: 8px 0; font-weight: 400; border-top: 1px solid var(--border);
}
.fa-opt input, .fa-check input { width: 22px; height: 22px; flex: none; margin-top: 2px; }
.fa-clear, .fa-offer button { min-height: 40px; margin-top: 6px; }
.fa-matrix table { width: 100%; border-collapse: collapse; table-layout: fixed;
  font-size: .72rem; }
.fa-matrix th, .fa-matrix td { border: 1px solid var(--border); padding: 2px;
  text-align: center; word-break: break-word; }
.fa-matrix tbody th { width: 2.4em; font-size: .85rem; }
.fa-matrix td input { width: 26px; height: 26px; margin: 4px 0; }
.fa-legend { font-size: .82rem; margin: 10px 0 0; }
.fa-legend dt { font-weight: 700; float: left; width: 2.6em; }
.fa-legend dd { margin: 0 0 6px 2.8em; }

/* D-20261027-1 step F: while a job opens, its work buttons are not offered
   (they would act on no job); the loading line says what is happening. */
#screen-job.is-opening > button.wide:not(#btn-job-retry) { display: none; }
.opening { font-weight: 600; }

/* D-20261027-1 STEP A — General first; Review a count he opens; Getting in folds once visited. */
.card.general { border-left: 4px solid var(--border); }
.gen-cover { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin: 4px 0 8px; }
.gen-cover img { width: 120px; height: 90px; object-fit: cover; border-radius: 6px; }
.gen-cover button { min-height: 44px; }
details.card.review > summary { min-height: 44px; display: flex; align-items: center;
  cursor: pointer; font-weight: 600; }
.card.access.folded > :not(h2) { display: none; }
.card.access h2 .fold { min-height: 36px; margin-left: 8px; font-size: 0.85em; }

/* D-20261027-2: the office tray's upload groups, moved into the writer's strip. A heading
   spans the grid; the chip states below carry their word, never the colour alone. */
.grid > .batch-head { grid-column: 1 / -1; list-style: none; display: flex; flex-wrap: wrap;
  align-items: center; gap: 8px; margin-top: 10px; }
.batch-head h3 { margin: 0; font-size: 1rem; flex: 1 1 auto; }
.batch-head .batch-pick[aria-pressed="true"] { outline: 2px solid var(--accent, #2563eb); }
#btn-strip-range[aria-pressed="true"] { outline: 2px solid var(--accent, #2563eb); }
.card.slots ul { margin: 4px 0 8px; }
.row-state[data-state="todo"] { color: var(--muted); border-color: var(--border); }
.row-state[data-state="na"] { color: var(--muted); border-style: dashed; }

/* D-20261027-1 STEP B — the section rail: badge, tier rows, Not on this house?, the left rail. */
.row-count { min-width: 28px; text-align: center; font-weight: 700; font-size: .85rem;
  padding: 2px 8px; border-radius: 999px; border: 1px solid var(--border-strong); }
.tiers { display: flex; flex-wrap: wrap; gap: 8px; margin: 0 0 8px; }
.tiers .tier { min-height: 44px; padding: 0 12px; border-radius: 8px; }
.tiers .tier[aria-pressed="true"] { outline: 2px solid var(--accent, #2563eb); font-weight: 700; }
details.card.na > summary { min-height: 44px; display: flex; align-items: center; cursor: pointer; font-weight: 600; }
.na-act { min-height: 44px; }
@media (min-width: 1100px) {
  main:has(#screen-job:not([hidden])) { max-width: 1240px; }
  #screen-job:not([hidden]) { display: grid; grid-template-columns: minmax(280px, 360px) 1fr;
    column-gap: 24px; align-items: start; }
  #screen-job > * { grid-column: 2; }
  #screen-job > #job-rail { grid-column: 1; grid-row: 1 / span 60; }
  /* a plain left column that scrolls with the page: a sticky rail was built and MEASURED not to hold
     (walk w702, lane 1 s22), so it is not claimed; no nested scroller either */
}

/* D-20261027-1 step C: a description is one dense row of chips (DESIGN-WRITER-FLOW §3). */
#v4-desc-list .df-req { color: var(--warn); font-size: .7rem; margin-right: 4px; }
#v4-desc-list li[data-chips="1"] .df-value { display: none; }
#v4-desc-list li[data-answered="1"] { opacity: .72; }
.df-chips { display: flex; flex-wrap: wrap; gap: 6px; flex-basis: 100%; margin-top: 6px; }
.df-chip { min-height: 40px; padding: 6px 12px; border-radius: 999px;
  border: 1px solid var(--border-strong); background: var(--surface-2);
  font-size: .9rem; color: inherit; cursor: pointer; }
.df-chip[aria-pressed="true"] { background: var(--accent, #2563eb); border-color: var(--accent, #2563eb);
  color: #fff; font-weight: 600; }
.df-chip:disabled { opacity: .5; }

/* WRITER.FP1 (owner, 2026-10-28): the section rail is ONE LINE a section - the state's glyph and
   word, the name, the photographs, the findings badge, the row's menu. No card, no full-width
   button, no capitals shouting "NOT STARTED" down the page. */
#job-rail .row.rail-row { flex-wrap: nowrap; gap: 8px; background: transparent; border: 0;
  border-bottom: 1px solid var(--border); border-radius: 0; padding: 0 2px; margin: 0; }
#job-rail .rail-row .rowbtn { flex-direction: row; align-items: center; gap: 8px; min-width: 0; }
#job-rail .rail-row .row-state { order: -1; flex: 0 0 auto; text-transform: none; letter-spacing: 0;
  border: 0; padding: 0; font-size: .85rem; font-weight: 600; white-space: nowrap; }
#job-rail .rail-row .row-state::before { content: "\25CB"; margin-right: 4px; }
#job-rail .rail-row .row-state[data-state="open"]::before { content: "\25D0"; }
#job-rail .rail-row .row-state[data-state="complete"]::before { content: "\25CF"; }
#job-rail .rail-row .row-state[data-state="na"]::before { content: "\2013"; }
/* D-20261028-3 (DES.SR6/SR7): the fixed rows carry no state; they read as the rail's frame, in
   weight, never in colour. Every section state above has its own glyph AND word (○ ◐ ● –). */
#job-rail .rail-row.rail-fixed .row-main { font-weight: 700; flex: 0 0 auto; overflow: visible; }
/* the name is never cut on a fixed row; its line gives way instead (phone 393 px, s31's shot) */
#job-rail .rail-row.rail-fixed .row-sub { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis;
  text-align: right; }
/* "Not on this house" is longer than the word it replaced: in the group the name wraps, never "Elev..." */
#job-rail #section-na-list .row.rail-row { flex-wrap: wrap; padding-bottom: 6px; }
#job-rail #section-na-list .rail-row .rowbtn { flex: 1 1 100%; }
#job-rail #section-na-list .rail-row .row-main { white-space: normal; overflow: visible; }
#job-rail #section-na-list .rail-row .na-act { margin-left: auto; }
#job-rail .rail-fixed-list { margin: 0 0 8px; }
#job-rail #rail-foot { margin-top: 8px; border-top: 2px solid var(--border); }
#job-rail .rail-row .row-main { flex: 1 1 auto; min-width: 0; overflow: hidden;
  text-overflow: ellipsis; white-space: nowrap; }
#job-rail .rail-row .row-sub { flex: 0 0 auto; flex-basis: auto; white-space: nowrap; font-size: .82rem; }
#job-rail .rail-row .row-sub:empty { display: none; }
#job-rail .rail-row .na-act { flex: 0 0 auto; }
.row-more { display: inline-flex; align-items: center; justify-content: center; flex: 0 0 auto;
  min-width: 44px; min-height: 44px; font-size: 1.2rem; line-height: 1; color: var(--muted);
  cursor: pointer; border-radius: 8px; }
.row-more:focus-visible { outline: 2px solid var(--accent, #2563eb); }
/* WRITER.FP1: the Photographs page - Add / Take at the top, the proof list a closed drawer. */
#strip-add { margin: 8px 0 12px; }
#strip-add > #strip-empty { flex-basis: 100%; margin: 0; }
details.card.slots > summary { min-height: 44px; display: flex; align-items: center;
  cursor: pointer; font-weight: 600; }
#proof-gaps #release-line { margin: 8px 0; }
/* D-20261027-1 step D: the preview draws inside #preview-host's shadow root;
   only the frame it sits in is this app's to style. */
#preview-host { display: block; margin: 8px 0 24px; overflow-x: auto;
  border: 1px solid #c9d1da; border-radius: 6px; background: #fff; }

/* RAILEDIT.F1 (D-20261028-3 B2a): Reorder in the rail's head; ▲ ▼ big enough for a glove;
   the one Undo toast above the bottom edge. */
#job-rail .rail-head { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; }
#job-rail .rail-head h2 { margin-right: auto; }
.row-move { display: inline-flex; align-items: center; justify-content: center; flex: 0 0 auto;
  min-width: 44px; min-height: 44px; font-size: 1.05rem; border: 1px solid var(--line, #d1d1d6);
  border-radius: 8px; background: var(--card, #fff); cursor: pointer; user-select: none; }
.row-move[aria-disabled="true"] { opacity: .35; pointer-events: none; }
.row-move:focus-visible { outline: 2px solid var(--accent, #2563eb); }
#section-list.moving .rail-row { border-bottom: 1px dashed var(--line, #d1d1d6); }
.toast { position: fixed; left: 50%; bottom: 16px; transform: translateX(-50%); z-index: 60;
  max-width: calc(100vw - 24px); padding: 10px 14px; border-radius: 10px; background: #1c1c1e;
  color: #fff; box-shadow: 0 4px 18px rgba(0,0,0,.25); }
.toast .link { color: #9cc3ff; font-weight: 700; margin-left: 8px; background: transparent;
  border: 1px solid #9cc3ff; border-radius: 8px; min-height: 44px; padding: 0 14px; font-size: 1rem; }
#rename-sheet input { width: 100%; font-size: 1rem; padding: 8px; margin: 6px 0 10px; box-sizing: border-box; }
