/* The sheet's one stylesheet.
   Linked by the web UI and imported as text by worker/lib/pdf.ts — the same
   bytes, so the sheet on screen, the sheet the browser prints and the sheet
   the server renders cannot drift. There used to be a second, byte-identical
   copy at templates/sheet.css kept in step by hand; it is gone.
   --a and --b are replaced per-render with the shop's own colours. */
:root{
  --a:#0151BE; --b:#00C1FD;
  --ink:#0E1520; --body:#3E4A5C; --muted:#8592A3;
  --line:#E4EAF3; --surf:#F6F9FD; --tint:#F1F7FE; --paper:#fff;
  --grad:linear-gradient(135deg,var(--a),var(--b));
  --r:14px;
}
*{box-sizing:border-box;margin:0;padding:0}
body{font-family:Inter,-apple-system,"Segoe UI",system-ui,sans-serif;
     color:var(--body);background:var(--paper);line-height:1.5;
     -webkit-font-smoothing:antialiased;font-size:11pt}

/* ---- the masthead ----
   Light on purpose. We store one customer logo with no light or dark variant,
   so a dark header gambles on every customer's artwork: a white wordmark
   disappears on white, a black one on our navy. A light masthead makes any
   single upload work, and reads as a document rather than as a web page.

   Named .mast rather than .hero because app.css also defines .hero and loads
   after this file, so it was quietly winning: the sheet in the editor wore the
   landing page's header while print and the PDF wore this one. The whole point
   of one renderer is that what is on screen is what prints, and a shared class
   name was breaking that promise underneath it. Same for .mast-eyebrow. */
.mast{background:var(--paper);color:var(--ink);padding:23px 24px 18px;position:relative;
      border-bottom:2px solid var(--a)}
.mast:before{content:"";position:absolute;inset:0 0 auto 0;height:5px;background:var(--grad)}
.mast-top{display:flex;align-items:flex-start;justify-content:space-between;gap:20px;
          margin-bottom:17px}
/* The customer, at a size they would put their name to. */
.mast-id{display:flex;align-items:center;gap:14px;min-width:0}
.mast-id img{max-height:64px;max-width:280px;width:auto;display:block}
.mast-id .co{font-weight:800;font-size:15pt;color:var(--ink);letter-spacing:-.3px;line-height:1.2}
/* Document control. Two columns so labels and values line up down the block
   rather than stacking into a ragged list. */
.mast-doc{display:grid;grid-template-columns:auto auto;gap:2px 10px;align-items:baseline;
          flex:none;text-align:right}
.mast-doc .dk{font-size:7.5pt;color:var(--muted);text-transform:uppercase;letter-spacing:.7px;
              font-weight:700}
.mast-doc b{color:var(--ink);font-size:9.5pt;font-weight:700;text-align:left;
            font-variant-numeric:tabular-nums;min-width:74px}
/* A field nobody filled in is a line to sign, not a gap. It only rules itself
   where there is nothing in it. */
.mast-doc b:empty:before{content:"";display:inline-block;width:74px;
  border-bottom:1px solid var(--line);vertical-align:2px}
.mast-eyebrow{font-size:8.5pt;letter-spacing:1.7px;color:var(--a);font-weight:700;
              text-transform:uppercase}
.mast h1{font-size:23pt;font-weight:800;letter-spacing:-.6px;margin-top:7px;line-height:1.15;
         color:var(--ink)}
/* The TWI operation name, under the title the customer chose. An operation
   nobody has named must not print an empty line — but it still needs somewhere
   to click in the editor, which is the only place the field is contenteditable
   and so the only place these two rules do not apply. */
.mast .op{font-size:10.5pt;color:var(--body);margin-top:7px}
.mast .op:empty:not([contenteditable]){display:none}
.mast .op[contenteditable]:empty:before{content:"Name the operation";color:var(--muted);
  font-style:italic}
.mast .meta{font-size:9.5pt;color:var(--muted);margin-top:7px}

/* ---- what the job needs ----
   Three of the four fields printed above the columns on a standard TWI
   breakdown sheet. A list nobody filled in does not print at all: a sheet
   carrying three empty headings says less than one carrying none. */
.needs{display:flex;gap:0;border-bottom:1px solid var(--line);background:var(--surf)}
.need{flex:1;padding:13px 16px;min-width:0;border-right:1px solid var(--line)}
.need:last-child{border-right:0}
.need h2{font-size:7.5pt;letter-spacing:1.3px;text-transform:uppercase;color:var(--muted);
  font-weight:700;margin-bottom:6px}
.need ul{list-style:none}
.need li{font-size:9.5pt;color:var(--body);padding-left:11px;position:relative;line-height:1.5}
.need li:before{content:"";position:absolute;left:0;top:8px;width:3px;height:3px;
  border-radius:50%;background:var(--muted)}
/* The editor's way into an empty list. It only exists where the field is
   contenteditable, and it carries no bullet because it is not an item yet. */
.need li.need-new:empty:not([contenteditable]){display:none}
.need li.need-new:before{display:none}
.need li.need-new[contenteditable]:empty:before{content:"Add one";display:inline;position:static;
  width:auto;height:auto;background:none;color:var(--muted);font-style:italic;font-size:9pt}

.rows{width:100%;border-collapse:collapse}
.rows th{background:var(--surf);font-size:7.5pt;letter-spacing:1.3px;text-transform:uppercase;
         color:var(--muted);text-align:left;padding:9px 13px;border-bottom:1px solid var(--line);font-weight:700}
.rows th.wy{color:var(--a);background:var(--tint)}
.rows td{padding:11px 13px;border-bottom:1px solid var(--line);vertical-align:top}
.rows tr{page-break-inside:avoid;break-inside:avoid}
/* One row per key point, with the frame and the step spanning them — the
   classic TWI form. The old layout stacked every key point in one cell and
   every reason in another, so a step with three points and one reason showed
   them side by side with nothing to say which belonged to which. */
.col-im{width:104px;background:var(--surf);padding:9px}
/* A cropped frame gets real room, because zoom is box width divided by the
   crop's size in source pixels and nothing else. At 104px a crop of a button
   and its surroundings lands at 0.2x — a quarter of life size, which is why
   cropping read as "it moved but did not zoom". At 300px the same crop is
   0.63x and legible. Driven by whether there are crops rather than by how the
   job was captured: a hand-cropped camera frame wants the same room, and
   min-width because a table with automatic layout treats `width` as a hint. */
.rows:has(.ph-box[style]) .col-im{width:300px;min-width:300px}
.col-st{width:28%}
.col-kp{width:30%}
.col-wy{width:30%;background:var(--tint)}
/* A step's cell spans its key points, so its own bottom border would cut
   across them. */
.rows td.col-im,.rows td.col-st{border-bottom:1px solid var(--line)}
/* The frame, and the part of it worth looking at.
   The box is square and never changes size, so the crop is square too — a
   16:9 crop in a square box can only be letterboxed or clipped, and clipping
   is what made the first attempt point at the wrong thing.

   Uncropped, the defaults below are the plain full-bleed image this has
   always been. Cropped, the image is widened to 100%/w so the chosen region
   is exactly a box-width across, height follows the image's own aspect, and
   it is translated by the crop's own origin — which is why nothing here needs
   to know the frame's dimensions. One stored frame serves every zoom and
   nothing is ever re-encoded. */
.ph-box{position:relative;overflow:hidden;border-radius:7px;aspect-ratio:1;display:block;
    background:linear-gradient(135deg,#DCE6F2,#EFF4FA);
    /* A cropped screen is often pale, and without this it bleeds into the
       cell behind it and you cannot tell where the picture ends. */
    box-shadow:inset 0 0 0 1px rgba(14,21,32,.13)}
.ph{position:absolute;left:0;top:0;width:var(--fw,100%);height:var(--fh,100%);
    object-fit:cover;display:block;
    transform:translate(var(--tx,0),var(--ty,0))}
.ph-empty{width:100%;aspect-ratio:1;border-radius:7px;display:flex;align-items:center;
    justify-content:center;font-size:8pt;color:var(--muted);
    background:linear-gradient(135deg,#DCE6F2,#EFF4FA)}
.stamp{font-size:8pt;color:var(--muted);text-align:center;margin-top:5px}
.seq{display:inline-grid;place-items:center;width:19px;height:19px;border-radius:50%;
     background:var(--grad);color:#fff;font-size:8.5pt;font-weight:700;margin-right:7px}
.st{font-weight:700;color:var(--ink);font-size:11.5pt}
.detail{margin-top:5px;font-size:10pt}
.kp{margin-top:7px;padding-left:13px;position:relative;font-size:10pt}
.kp:before{content:"";position:absolute;left:0;top:7px;width:5px;height:5px;border-radius:50%;background:var(--a)}
/* Qualified so it outranks `.rows td`'s padding shorthand. Unqualified it
   lost, and the dot below was drawn over the first letter of every key point. */
.rows td.col-kp{padding-left:26px;position:relative}
/* Body cells only. The header carries .col-kp too, and an unscoped dot either
   bullets the word "Key point" or — with no positioned ancestor on a th —
   escapes to the top-left corner of the page. */
.rows td.col-kp:before{content:"";position:absolute;left:13px;top:17px;width:5px;height:5px;
  border-radius:50%;background:var(--a)}
.rows td.col-kp:has(.none):before{display:none}
.kp-tag{display:inline-block;font-size:7pt;font-weight:700;padding:1px 6px;border-radius:999px;
     margin-left:5px;vertical-align:1px;letter-spacing:.4px}
.kp-tag.t-ok{background:#E2F5EC;color:#0B7A52}
.kp-tag.t-seen{background:#EAF0F9;color:#41566F}
/* t-ask, not ask: a bare .ask is the trainer's-questions panel below, and a
   badge wearing it came out as a 15px-padded box on its own line. */
.kp-tag.t-ask{background:#FDF0DC;color:#96590A}

/* TWI's three tests. These two colours are FIXED and never take the shop's
   brand colours: a safety mark that is blue in one plant and green in the next
   tells a reader nothing, and it is the one mark on this sheet somebody might
   act on. Technique has no badge — see KIND_TAG in sheet.js. */
.kp-tag.k-safety{background:#FCEBEA;color:#B3261E;margin-left:0;margin-right:6px}
.kp-tag.k-quality{background:#E3F3F3;color:#0B6A6A;margin-left:0;margin-right:6px}
.col-kp,.col-wy{font-size:10pt}
.none{color:var(--muted);font-style:italic}
/* An empty detail line still needs somewhere to click in the editor. Named
   is-empty because a bare .empty is app.css's empty-state panel, which loads
   later and was dressing every blank detail in 60px of padding and a dashed
   border. */
.detail.is-empty{min-height:1px}

.ask{margin:22px 24px 0;border:1px solid #F0D9AE;background:#FDF8EF;border-radius:11px;padding:15px 17px;
     page-break-inside:avoid;break-inside:avoid}
.ask h2{font-size:11pt;color:#96590A;margin-bottom:9px;font-weight:700}
.ask li{margin:0 0 6px 17px;font-size:10pt;color:#6B4708}

/* ---- how to instruct ----
   The breakdown is the instructor's preparation, not the lesson. TWI expects
   the four steps in front of them while they teach. Kept whole across a page
   break: half a method is worse than none. */
.method{margin:22px 24px 0;border:1px solid var(--line);border-radius:11px;padding:14px 17px;
  background:var(--surf);page-break-inside:avoid;break-inside:avoid}
.method h2{font-size:7.5pt;letter-spacing:1.3px;text-transform:uppercase;color:var(--muted);
  font-weight:700;margin-bottom:9px}
.method ol{list-style:none;counter-reset:step;display:grid;grid-template-columns:1fr 1fr;
  gap:7px 20px}
.method li{counter-increment:step;font-size:9pt;color:var(--body);line-height:1.5;
  padding-left:20px;position:relative}
.method li:before{content:counter(step);position:absolute;left:0;top:1px;width:14px;height:14px;
  border-radius:50%;background:var(--a);color:#fff;font-size:7.5pt;font-weight:700;
  display:grid;place-items:center}
.method li b{color:var(--ink)}
.method > p{margin-top:10px;font-size:8.5pt;color:var(--muted);font-style:italic}

.foot{margin:26px 24px 0;padding:14px 0 0;border-top:1px solid var(--line);
      display:flex;justify-content:space-between;align-items:center;gap:14px;
      font-size:8.5pt;color:var(--muted)}
.foot b{color:var(--ink)}
.foot .dk{text-transform:uppercase;letter-spacing:.6px;font-weight:700;font-size:7.5pt}
.foot b:empty:before{content:"";display:inline-block;width:64px;
  border-bottom:1px solid var(--line);vertical-align:2px}
.foot a{color:var(--a);text-decoration:none;font-weight:600}
