/* THE JOB MATERIALS EDITOR'S LOOK (3K-8e-1) — the table job-materials.js draws inside
   fxf-ui.css's .fxo-panel.

   🔴 EVERY SELECTOR IN THIS FILE STARTS WITH .jm, WITHOUT EXCEPTION. This file is loaded by
      designer.html on every page load, so a single selector naming an element or an existing
      class would restyle the designer itself for the sake of a dialog most jobs never open.
      That is a rule about blast radius, not tidiness.

   🔴 IT COPIES THE PRODUCTS PAGE'S MATERIALS TABLE AND IMPORTS NOTHING. products.css is 104 KB
      of page-wide rules; loading it here to reach .mat-table would drag the whole products page
      over the designer. So the LOOK is reproduced — the same spacing, the same hairline between
      rows, the same quiet uppercase header, the same right-aligned tabular figures, the same
      input that shows no chrome until you reach for it — under .jm names of its own. */

/* Five columns need more room than the preferences dialog's two checkboxes, and .fxo-panel
   sizes to its content. 92vw is the ceiling a phone imposes; .jm-scroll below is what makes
   the difference survive. */
.jm{min-width:min(760px,92vw)}
.jm-note{margin:0 0 10px;font-size:12.5px;color:var(--muted)}
/* 3K-8e-3f R7: the short Apply is phone-only; it is switched on in the block at the end.
   🔴 3K-8e-4c (Round 3, A2/A3): THE "i" IS ON EVERY WIDTH NOW. It opens the one place a message can be (.jm-info-panel,
   under the bar) and turns amber, glyph and all, while something is refused -- which a laptop needs as much as a phone.
   A FIXED SIZE, so turning amber or "!" never moves anything beside it. 42px is Apply's height, which the bar is built on. */
.jm-info{box-sizing:border-box;display:inline-flex;width:42px;height:42px;flex:0 0 auto;align-items:center;
  justify-content:center;border-radius:8px;border:1.5px solid var(--line);background:#fff;color:var(--muted);
  font-size:17px;font-weight:700;font-style:italic;line-height:1;padding:0;cursor:pointer}
.jm-info:focus-visible{outline:2px solid var(--wine);outline-offset:2px}
/* Amber AND a different glyph ("!", upright), never the hue alone: INK, NOT COLOUR, the rule the takeoff marks follow. */
.jm-info.jm-info-alert{border-color:#c47a17;background:#fdf1dc;color:#8a5200;font-style:normal;font-size:20px}
/* 🔴 3K-8e-4c (Round 4, C2): THE STANDING NOTE IS ON SCREEN ON A LAPTOP (.jm-note-desk, above the bar, where it always
   sat) and behind the "i" on a phone (.jm-note-phone, in the panel). Exactly one of the two is ever displayed; the phone
   half is in the phone block at the end of this file. The "i" disables itself on a laptop when it has nothing else. */
.jm-note-phone{display:none}
.jm-info:disabled{opacity:.38;cursor:default}
/* THE DISCLOSURE DROPS DOWN FROM THE BAR AND TAKES NO ROOM: out of the flow, so opening it moves no button and does not
   make the laptop's dialog taller (a taller dialog re-centres, which moves every button -- measured 25.2px at 1200). The
   bar is position:sticky, so it is what this is placed against, and the panel sticks with it. It covers the top of the
   list while open; a long list of refusals scrolls inside it rather than growing it past 40% of the screen. */
.jm-info-panel{position:absolute;left:0;right:0;top:100%;z-index:5;box-sizing:border-box;max-height:40vh;overflow:auto;
  padding:10px 14px 4px;background:var(--panel);border-bottom:1px solid var(--line);box-shadow:0 6px 12px rgba(0,0,0,.10)}
.jm-info-panel .jm-note{margin:0 0 6px}
.jm-apply-short{display:none}
.jm-empty{margin:0;font-size:13px;color:var(--muted)}

/* 🔴 THE TABLE SCROLLS SIDEWAYS, THE DIALOG DOES NOT. Five columns with two inputs in them do
   not fit a 380px screen at any font size worth reading, and the two ways out of that are a
   sideways scroll or a reflow into cards. A scroll keeps every row the same shape as the
   printed list it mirrors, so a contractor is reading the same table on both. */
.jm-scroll{overflow-x:auto;max-height:56vh;overflow-y:auto}
/* 3K-8e-2c (T11): 810, not 700. A sixth column comes out of Name, the one width:auto column: at 700 a 768px
   window left Name 66px and a 38-character catalog name wrapped to 7 lines (measured).
   🔴 SEPARATE BORDERS, SPACING 0, NOT COLLAPSE: with collapsed borders Chrome painted the pinned total row (below)
   as a thin band with the rows scrolling past showing above and below it (screenshot). Separate borders look the
   same, except where two 1px rules meet -- which is only under the header, handled below. */
.jm-table{width:100%;min-width:810px;border-collapse:separate;border-spacing:0;table-layout:fixed;font-size:13px}
.jm-table th,.jm-table td{text-align:left;padding:6px 6px;vertical-align:top}

/* The header reads as a header by its size, weight and letterspacing, and clips inside its own
   box: under table-layout:fixed nothing else stops a long label painting over its neighbour. */
.jm-table th{position:sticky;top:0;z-index:2;background:#fff;font-size:11px;font-weight:700;color:var(--ink);text-transform:uppercase;letter-spacing:.03em;border-bottom:1px solid var(--line);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;vertical-align:bottom}

/* A light rule BETWEEN rows and nothing else. A full grid draws a dozen lines to separate five
   numbers, and the numbers are what you came to read. */
.jm-table .jm-row + .jm-row td{border-top:1px solid var(--line)}

/* 🔴 width:auto IS THE POINT. Under table-layout:fixed every other column declares a width, so
   auto here means "all the rest" — and Name is the only column that says WHAT the material is. */
.jm-table .jm-c-name{width:auto;font-weight:700;color:var(--ink)}
/* 3K-8e-3c (Y8): 150, was 104. Using per fence is gone, and a line used by several fences stacks a labelled Qty box for each
   ("Fence 1" and a box) in this cell; the rest of the freed 176px goes to Name. */
.jm-table .jm-c-qty{width:150px;text-align:right}
/* 3K-8e-3: 150, was 132. Two boxes, the word "per" and "ft" need 138px at the table font (measured);
   the 18px comes out of Name, the one width:auto column, and the table still fits the panel at 1280. */
.jm-table .jm-c-per{width:150px;color:var(--muted);font-size:11.5px;text-align:center}
/* 🔴 3K-8e-3b (W7): ONE ALIGNMENT PER COLUMN. Per is centred -- its header, its boxes and its catalog line -- where it
   read left, left and right (measured). Qty and Price were already right-aligned, but their digits sit 7.5px inside the
   box (6px padding + a 1.5px border), so the header and the grey line move in by that much to end where the digits end. */
.jm-table td.jm-c-per .jm-per{justify-content:center}
.jm-table td.jm-c-per .jm-calc,.jm-table td.jm-c-per .jm-gone{text-align:center}
.jm-table th.jm-c-qty,.jm-table th.jm-c-price{padding-right:13.5px}
.jm-table td.jm-c-qty .jm-calc,.jm-table td.jm-c-price .jm-calc{padding-right:7.5px}
.jm-table .jm-c-price{width:132px;text-align:right;font-weight:700;color:var(--ink)}
/* 3K-8e-2c (T3): the Total column, rightmost. The Remove cell after it exists for the phone only. */
.jm-table .jm-c-total{width:104px;text-align:right;font-weight:700;color:var(--ink)}
.jm-table td.jm-c-act{display:none}

/* 🔴 TABULAR FIGURES, AND THE INPUT SELECTORS ARE NOT REDUNDANT. A column of figures is only
   comparable when the digits share an edge, and an <input> does not inherit
   font-variant-numeric from its cell in every engine — so the rule on the cell alone would
   leave the editable numbers, which is all of them here, proportional.
   🔴 NAME GETS NONE. It is prose; tabular digits in a product name look wrong. */
.jm-table .jm-c-qty,
.jm-table .jm-c-price,
.jm-table .jm-c-total,
.jm-table .jm-c-qty .jm-qty,
.jm-table .jm-c-price .jm-price{font-variant-numeric:tabular-nums}

/* The section heading: the fence this block of materials belongs to, in the same words the
   printed takeoff heads it with. */
/* 3K-8e-3b (W9): bigger, with a wine rule under it, so a section reads as a heading and not as one more row. */
.jm-table .jm-section td{padding-top:18px;padding-bottom:8px;font-size:13.5px;font-weight:800;color:var(--wine);text-transform:uppercase;letter-spacing:.04em;border-top:1px solid var(--line);border-bottom:2px solid var(--wine)}
.jm-section-sub{margin-left:8px;font-size:12.5px;font-weight:600;color:var(--muted);text-transform:none;letter-spacing:0}
/* 3K-8e-3b (W9): the heading is the fold button. The chevron is drawn here, so the words of the heading stay as they were. */
.jm-sec{padding:0;border:0;background:none;font:inherit;color:inherit;letter-spacing:inherit;text-transform:inherit;text-align:left;cursor:pointer}
.jm-sec::before{content:"▾ "}
.jm-sec[aria-expanded="false"]::before{content:"▸ "}
.jm-sec:focus-visible{outline:2px solid var(--wine);outline-offset:2px;border-radius:5px}
.jm-table tr.jm-folded{display:none !important}
/* 🔴 3K-8e-5b (P4): THE GATES SUB-SECTION -- a block inside a fence section, not a section of its own. Quieter than
   the heading above it on every axis that heading shouts on (smaller, indented, ink rather than wine, a hairline
   instead of the 2px wine rule), so the eye reads fence > gates and never two headings of equal weight. */
.jm-table .jm-subsection td{padding-top:10px;padding-bottom:6px;font-size:12px;font-weight:800;color:var(--ink);text-transform:uppercase;letter-spacing:.04em;border-top:1px solid var(--line);border-bottom:1px solid var(--line)}
.jm-table .jm-subsection td:first-child{padding-left:18px}
.jm-subsec{color:var(--ink)}
/* Its own fold, inside the section's. Two classes, never one: a gate row hidden by its own fold must stay hidden
   when the fence section is folded and unfolded again, and one shared class would have the two folds erasing each
   other's answer. */
.jm-table tr.jm-subfolded{display:none !important}
/* The gate rows sit under their heading, indented by the same step, so the block reads as one. */
.jm-table tbody tr.jm-row.jm-gate-row td.jm-c-name{padding-left:18px}
/* Separate borders would draw the header's rule AND the first section's as a 2px line; today's is 1px. */
.jm-table tbody tr.jm-section:first-child td{border-top:0}
/* The section's total is a figure, not a heading: ink, not wine, and not shouted. */
.jm-table .jm-section td.jm-c-total{font-size:14px;font-weight:800;color:var(--ink);text-transform:none;letter-spacing:0}

.jm-name{overflow-wrap:anywhere}
.jm-sub{margin-top:2px;font-size:11.5px;font-weight:400;color:var(--muted)}
/* The ✎ and ⚠ are CHARACTERS, and the colour only supports them: a mark that exists solely as
   a colour is a mark half the people reading this cannot see. */
.jm-mark{display:inline-block;margin-top:3px;font-size:11.5px;font-weight:400;color:var(--wine)}

/* The expand control is the row's own text, not a button-looking thing: a column of framed
   buttons is a form, and this is a list you occasionally open. */
.jm-expand{display:inline-block;margin-top:4px;padding:0;border:0;background:none;font:inherit;font-size:11.5px;font-weight:700;color:var(--wine);cursor:pointer}
.jm-expand:focus-visible{outline:2px solid var(--wine);outline-offset:2px;border-radius:5px}

/* A source line sits under the merged row it belongs to, indented and quieter, so the eye reads
   it as part of that row rather than as a sixth row of its own. */
.jm-table .jm-source .jm-c-name{padding-left:18px;font-weight:600;color:var(--muted);font-size:12px}
.jm-table .jm-source[hidden]{display:none !important}

/* The input fills its cell and carries no chrome until you touch it: a table where every box is
   visibly a box reads as a form, and this is a list you occasionally correct. */
.jm-qty,.jm-price{width:100%;box-sizing:border-box;padding:4px 6px;border:1.5px solid transparent;border-radius:7px;background:transparent;font:inherit;font-weight:700;color:var(--ink);text-align:right}
.jm-qty:hover,.jm-price:hover{border-color:var(--line);background:#fdfbf8}
.jm-qty:focus,.jm-price:focus{outline:none;border-color:var(--wine);background:#fff}
/* 🔴 3K-8e-3b (W6): A LOCKED BOX. Disabled (no caret, no Tab stop), greyed and dashed so it reads as "not yours to type
   right now", with its number still readable: Safari fades a disabled field, so opacity and the text fill are set back. */
.jm-qty.jm-locked{border:1.5px dashed var(--line);background:#f3f0eb;color:var(--muted);-webkit-text-fill-color:var(--muted);opacity:1;cursor:not-allowed}
/* 3K-8e-2d (U4): THE PENDING LOOK, copied from the products page's td[data-cell-state="pending"] -- products.css is never
   loaded here. A box Apply would change gets the same orange border and pale fill; a line that counts gets them on its
   Total. 🔴 NOT COLOUR ALONE: a ● before the grey figure under the box and before every pending Total. After :focus, so
   the box you are typing in still shows it; before .jm-invalid, so a refusal at Apply turns it red. */
.jm-qty.jm-pending,.jm-price.jm-pending{border-color:#c47a17;background:#fdf6ec}
.jm-cell-pending .jm-calc::before,.jm-table td.jm-c-total.jm-pending::before,.jm-bar-total strong.jm-pending::before{content:"● ";color:#c47a17}
.jm-table td.jm-c-total.jm-pending{background:#fdf6ec}
/* Chrome reserves room for the spin buttons inside a number input, and that room comes out of
   the digits — which in a 104px column is the difference between a price that fits and one
   that clips. Scoped to these two boxes; no other number field on the page is touched. */
.jm-qty::-webkit-outer-spin-button,
.jm-qty::-webkit-inner-spin-button,
.jm-price::-webkit-outer-spin-button,
.jm-price::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}
.jm-qty[type=number],.jm-price[type=number]{-moz-appearance:textfield}

/* ---- 3K-8e-3: THE PER, FOR THIS JOB ---- */
/* The boxes carry .jm-qty, so every rule above -- the quiet border, the focus ring, the pending orange, the
   refused red, the tabular figures, the 16px phone size -- reaches them without being written twice. Only
   their width and the words between them belong here. */
.jm-per{display:flex;align-items:center;gap:4px;white-space:nowrap}
.jm-table .jm-c-per .jm-perqty,.jm-table .jm-c-per .jm-perft{width:44px;flex:0 0 auto;font-size:13px}
.jm-per-word{font-size:11.5px;color:var(--muted)}
/* 3K-8e-4c: the counting rule of a material added for this job -- ONE per line, in its first fence's Per cell. 16px so
   iOS does not zoom the page on focus, as every box in this dialog; max-width so it never widens the column. */
.jm-rule{display:flex;flex-direction:column;align-items:flex-start;gap:2px;margin-top:4px;text-align:left}
.jm-rule-label{font-size:10.5px;font-weight:700;color:var(--muted);white-space:nowrap}
/* It is the WHOLE LINE's control, so it may run past its own fence column into the next, as its label does: in one 92px
   column at 320 even "Per point" was clipped at 16px (measured). max-content, never wider than the text needs. */
.jm-rule-select{font-size:16px;width:max-content;min-width:0;box-sizing:border-box;padding:2px 4px;border:1px solid var(--line);border-radius:6px;background:#fff;color:inherit}
.jm-rule-select.jm-pending{border-color:#c47a17;background:#fdf6ec}
.jm-rule-select.jm-invalid{border-width:2.5px;border-color:#b3261e;background:#fdf5f3}
/* On a phone the unit is a flex column of fence columns (below): there the control goes UNDER the boxes, or it pushes
   this fence's Per box below the next fence's (seen at 320px). On a laptop it stays first, above them (the JS says why). */
@media (max-width:560px){.jm-table tbody tr.jm-row-open .jm-rule{order:1}}

/* 🔴 NOT COLOUR ALONE. A red border is invisible to a red-green colour-blind user against this
   palette, so a refused box is also thicker, also filled, and also named in the message under
   the table — three signals, only one of them a hue. */
.jm-qty.jm-invalid,.jm-price.jm-invalid{border-width:2.5px;border-color:#b3261e;background:#fdf5f3;font-style:italic}

.jm-calc{display:block;margin-top:3px;font-size:11px;font-weight:400;color:var(--muted);text-align:right}
/* 3K-8e-3b (W8): OLD AND NEW while Apply would change them. The ● is ink, so "new" is never colour alone. */
.jm-was{display:block;margin-top:3px;font-size:11px;font-weight:400;color:var(--muted)}
/* 🔴 3K-8e-3c (Y2, Y7, Y8): A QTY BOX PER FENCE. Each box sits in its own block with its grey line and, while a Per moves that
   fence count, its "was N" under it. With several fences each box carries its fence name on its left. The pending dot
   belongs to the block, so only the box that changed shows it. */
.jm-fbox + .jm-fbox{margin-top:8px}
.jm-fq{display:flex;align-items:center;justify-content:flex-end;gap:6px}
.jm-fq-label{font-size:11px;font-weight:600;color:var(--muted);white-space:nowrap}
.jm-table td.jm-c-qty .jm-was{text-align:right;padding-right:7.5px}
.jm-qty-text{display:block;padding:4px 7.5px;font-weight:700;color:var(--ink)}
/* 🔴 3K-8e-3f: WHICH FENCES A ROW IS FOR, in the combined list. It takes the slot the "Per, price and Remove shared
   with Fence 2" line had, and that line is gone with its rule: each fence has its own Per, price and Remove now, so
   nothing under a name is shared any more. A tag, not a sentence -- it sits beside a material name to tell two rows of
   one material apart, and there can be two of them on screen at once. */
.jm-fence-tag{display:inline-block;margin-top:3px;padding:1px 6px;border:1px solid var(--line);border-radius:999px;font-size:10.5px;font-weight:700;color:var(--muted);white-space:nowrap}
.jm-warn{margin:4px 0 0;font-size:11px;font-weight:600;color:#8a6100;text-align:right;line-height:1.3}
.jm-warn[hidden]{display:none !important}

/* 🔴 3K-8e-2d (U7): THE BAR IS AT THE TOP, pinned to the top of the dialog's scrolling body (-14px is that body's own
   padding) while the list scrolls. It replaces 3K-8e-2c's bottom bar. Opaque, and above the table's pinned header
   (z-index 3). 🔴 ALWAYS DRAWN, AND NEVER SHORTER THAN APPLY: drawn only once something changed, it made a laptop's
   dialog grow 63px and re-centre under the first keystroke (measured). So it always shows the job's total, and its
   minimum height is Apply's, so Apply appearing moves nothing. */
.jm-actions{position:sticky;top:-14px;z-index:4;display:flex;flex-wrap:wrap;align-items:center;gap:8px;box-sizing:border-box;min-height:63px;margin:0 -14px 10px;padding:10px 14px;background:var(--panel);border-bottom:1px solid var(--line)}
/* 🔴 flex-grow:1 is LOAD-BEARING for 3K-8e-3d: it is what pushes the icon group to the bar's right edge and keeps it there
   whether Apply is showing or not. Do not change it to flex:0. */
.jm-bar-total{flex:1 1 auto;margin:0;font-size:12.5px;line-height:1.25}
.jm-bar-total strong{display:block;font-size:15px}
/* 🔴 3K-8e-2e: APPLY WEARS THE MATERIALS PAGE'S GREEN SAVE LOOK, COPIED, NOT IMPORTED. The source is styles.css:286-287
   (.btn-primary and its :hover). --ok is the same palette colour, so a new --ok reaches both buttons; a new hover shade,
   corner or border there does NOT reach this one. Not the class itself: .jm-actions button out-ranked .btn-primary and
   painted Apply white with a wine border until the mouse was on it (measured).
   🔴 THE EDITOR'S SIZE, NOT THE PRODUCTS BAND'S COMPACT ONE: this is the thumb target the phone bar exists for, and the
   bar's minimum height above is built on it. The button carries no "primary" class: that pulled styles.css's big wine
   .primary under this look (letter-spacing, a colour fade, a 1px press-down). No outline rule, so the browser's own focus
   ring stays. No :disabled rule: Apply is hidden when nothing changed, never disabled. */
/* 🔴 3K-8e-2f: A FIXED HEIGHT, SO APPLY APPEARING MOVES NOTHING ON ANY SCREEN. Its height used to be padding + text + a 1.5px
   border, and screens draw that border at 1px (1x), 1.5px (2x) or about 1.33px (3x): the bar grew 0.4, 1.4 or 1.06px when
   Apply appeared and the list under it moved (measured). A fixed height does not round. 42px fills the bar exactly
   (min-height 63px = 10 + 42 + 10 + a 1px rule). The phone size is in the phone block at the end of this file. */
.jm-actions .jm-apply{box-sizing:border-box;height:42px;padding:0 14px;border-radius:8px;border:1.5px solid var(--ok);background:var(--ok);color:#fff;font-weight:700;cursor:pointer}
.jm-actions .jm-apply:hover{background:#245f3d;border-color:#245f3d}
/* 3K-8e-4c (Round 4): Apply while something is refused -- out of sight and out of reach, but holding its place, so the bar
   neither unwraps nor slides when a refusal arrives or clears. Tabular figures, so "Apply 1" and "Apply 0" are one width. */
.jm-actions .jm-apply.jm-apply-held{visibility:hidden}
.jm-actions .jm-apply{font-variant-numeric:tabular-nums}
.jm-msg{margin:10px 0 0;font-size:13px;line-height:1.4}

/* On a phone the panel is nearly the whole screen. 3K-8e-2c replaces 3K-8e-2's phone rules (a 640px table
   scrolling under a 122px pinned Name): see the phone layout at the end of this file. */
@media (max-width:560px){
  .jm{min-width:0}
}
/* 🔴 3K-8e-1 GATE D: THE ONE SELECTOR IN THIS FILE THAT DOES NOT START WITH .jm, AND IT CAN ONLY
   MATCH THE PANEL HOLDING THIS EDITOR. fxf-ui.css caps every overlay at 520px. GATE D measured
   it at a 1280px screen: the panel ended at x=900 while Price ran to 979 and the next column to
   1155, so the two columns this editor exists for were past the edge. :has(> .fxo-body > .jm)
   widens only a panel whose body holds .jm; the Preferences dialog and every products-page
   overlay keep their 520px. A browser without :has keeps the sideways scroll, which still works. */
/* 3K-8e-2c (T11): 920, was 820. With a Total column, 820 left Name 142px on a laptop (3 lines for a long name);
   920 gives it 242px, what it had before the column (measured). */
.fxo-panel:has(> .fxo-body > .jm){width:min(920px, calc(100vw - 24px));max-width:920px}
/* 🔴 3K-8e-2d (U8): THE SECOND SELECTOR THAT DOES NOT START WITH .jm, scoped exactly like the one above: it can only match
   the body of the panel holding this editor. The bar is pinned to the top of that body, and a box scrolled half under it
   and then tapped STAYED under it (measured, 3 of 3). scroll-padding-top makes the browser scroll a focused box clear of
   the bar instead (measured, 3 of 3, Chrome). */
.fxo-panel:has(> .fxo-body > .jm) > .fxo-body{scroll-padding-top:112px}

/* ---- 3K-8e-2 ---- */
/* 🔴 THE NAME COLUMN AND THE SECTION HEADING STAY ON THE LEFT WHILE THE TABLE SCROLLS SIDEWAYS
   (8e-1 hand test, H13 #2: scrolled to Price, a row read "ulated 27 | 1 per 7.5 ft | 285.00" and you
   could not tell which line you were editing). Opaque, so the columns passing underneath never show
   through. The header's Name cell is pinned on both axes, so it sits above everything. On a laptop
   nothing scrolls and nothing here moves. */
.jm-table th.jm-c-name,.jm-table td.jm-c-name{position:sticky;left:0;z-index:1;background:var(--panel)}
.jm-table th.jm-c-name{z-index:3}
.jm-section-label{position:sticky;left:6px;display:inline-block}

/* A line taken off this job: its name struck and quiet, its figures shown as text, struck. The ✕ is
   a CHARACTER; the strike and the colour only support it. */
.jm-table .jm-removed .jm-name{text-decoration:line-through;color:var(--muted)}
.jm-gone{display:block;font-weight:700;color:var(--muted);text-decoration:line-through;text-align:right}
.jm-remove{display:block;margin-top:4px;padding:0;border:0;background:none;font:inherit;font-size:11.5px;font-weight:700;color:var(--wine);text-decoration:underline;cursor:pointer}
.jm-remove:focus-visible{outline:2px solid var(--wine);outline-offset:2px;border-radius:5px}
/* 🔴 `hidden` MUST WIN. .jm-calc and .jm-gone set display:block and .jm-mark inline-block, and an
   author display rule beats the browser's own [hidden]{display:none} -- so without this a hidden box's
   "calculated 54" would still show under a removed line. */
.jm [hidden]{display:none !important}

/* ---- 3K-8e-2b: hand adjustments that apply to no line ---- */
/* The one warning in this dialog, at its top. The ⚠, the ✎ and the ✕ are characters; the wine rule on
   the left only supports them. A discarded entry is struck until Apply, exactly like a removed line. */
.jm-na{margin:0 0 12px;padding:10px 12px;border:1px solid var(--line);border-left:3px solid var(--wine);border-radius:8px}
.jm-na-head{margin:0 0 4px;font-size:13px;font-weight:800}
.jm-na-lead{margin:0 0 8px;font-size:12px;line-height:1.4;color:var(--muted)}
.jm-na-list{margin:0;padding:0;list-style:none}
.jm-na-item{display:flex;flex-wrap:wrap;align-items:baseline;gap:2px 10px;padding:6px 0;border-top:1px solid var(--line);font-size:12.5px}
.jm-na-name{font-weight:700}
.jm-na-where{flex-basis:100%;font-size:11.5px;color:var(--muted)}
.jm-na-pending{font-size:11.5px;font-weight:700;color:var(--wine)}
.jm-na-discard{margin-left:auto;padding:0;border:0;background:none;font:inherit;font-size:11.5px;font-weight:700;color:var(--wine);text-decoration:underline;cursor:pointer}
.jm-na-discard:focus-visible{outline:2px solid var(--wine);outline-offset:2px;border-radius:5px}
.jm-na-discarded .jm-na-name,.jm-na-discarded .jm-na-what{text-decoration:line-through;color:var(--muted)}

/* ---- 3K-8e-2c: totals, the live preview, the phone layout ---- */
/* The job's total: the table's last row, PINNED to the bottom of the scroll box the way the header is pinned to its
   top, so the figure that moves while you type is never below the fold. */
.jm-table tfoot td{position:sticky;bottom:0;z-index:2;background:#fff;padding-top:8px;border-top:2px solid var(--ink);font-weight:800;color:var(--ink)}
.jm-table .jm-foot-label{text-align:right}
/* T6: the line an adjustment taken back moves to another section. Under the name, never in the Total cell: in
   the Total cell it squeezed "Staple box" to three lines at 360px (measured). */
.jm-moves{display:block;margin-top:3px;font-size:11.5px;font-weight:600;color:var(--wine)}
/* T5: which box the totals wait for. Colour AND words: the words are the signal. */
.jm-wait{margin:0 0 6px;font-size:12px;font-weight:600;color:#b3261e}
/* 3K-8e-2d (U6): the refusal is one red line -- in the "i" panel since 3K-8e-4c Round 3 -- and an empty one takes no room. */
.jm-info-panel .jm-msg{margin:0 0 6px;font-size:12px;font-weight:600;color:#b3261e}
.jm-info-panel .jm-msg:empty{display:none}
/* 3K-8e-3h: THE NAME IS THE BUTTON AT EVERY WIDTH. A laptop row is shut until its name is tapped, exactly as a
   phone row has been since 3K-8e-2c -- the SAME row and the SAME boxes, restyled, never copied. */
.jm-opener{display:block;width:100%;padding:0;border:0;background:none;font:inherit;font-weight:700;color:var(--ink);text-align:left;cursor:pointer;overflow-wrap:anywhere}
.jm-opener::after{content:" ▸";color:var(--wine)}
.jm-opener[aria-expanded="true"]::after{content:" ▾"}
/* A merged row already says "N lines ▸": one chevron per row, not two. */
.jm-opener-merged::after,.jm-opener-merged[aria-expanded="true"]::after{content:none}
/* It is a Tab stop on a laptop now, so its focus ring comes with it. */
.jm-opener:focus-visible{outline:2px solid var(--wine);outline-offset:2px;border-radius:5px}
/* 3K-8e-3h: THE PLAIN NAME AND THE OLD REMOVE LINK BOTH GIVE WAY, at every width. The name becomes the opener
   above; Remove comes back for an OPEN row only -- in the Name cell on a laptop (the min-width block below),
   in the act cell on a phone (the max-width block). A SHUT row therefore cannot be removed without opening it
   first -- deliberate, and what narrow has always done: Remove is the one destructive-looking control here. */
.jm-table tbody .jm-c-name > .jm-name,.jm-table tbody .jm-c-name > .jm-remove{display:none}

@media (min-width:561px){
  /* 🔴 3K-8e-3f R5: THE LAPTOP'S REMOVE COMES BACK FOR AN OPEN ROW ONLY. The act cell cannot be used
     here: .jm-table is table-layout:fixed with a 5-cell thead, so showing a 6th body cell creates a
     column for the WHOLE table -- measured at 1280px, opening one row took Name from 346.9px to
     174.1px and slid Total 172.9px left, for every row at once. The Name cell costs no column.
     Narrow keeps the act cell's own Remove; this rule cannot reach it. */
  .jm-table tbody tr.jm-row-open .jm-c-name > .jm-remove{display:block}
}
/* 3K-8e-3d (D3): the end-of-list total, off by default and switched on in the phone block at the end of this file. */
.jm .jm-end-total{display:none;margin:14px 0 0;padding-top:12px;border-top:1px solid var(--line);font-size:13px;line-height:1.25}
.jm .jm-end-total strong{display:block;font-size:17px}
/* 🔴 3K-8e-3d (D2): THE THREE ICONS, LAST IN THE BAR SO THEY SIT ON ITS RIGHT EDGE. The bar total has flex-grow:1, so the
   last child is pinned right and Apply appears BETWEEN them: measured 0.000px of icon movement when Apply appeared, and
   0.000px when "Apply 1 change" grew to "Apply 2 changes", at 1280, 768, 600, 390 and 360.
   🔴 8e-3b W10's GUARD 2 IS DELETED HERE, NOT REPLACED -- the `min-width:160px` and the `[hidden]{visibility:hidden}` slot
   that held Apply's space while it was invisible. They existed only because "Clear all edits" stood next to a button that
   vanished; nothing stands there now. That slot IS the 168px of empty bar (measured: Clear 781.95-917.00, bar content
   ending at 1085.00), which is the whole reason this slice exists. */
.jm-actions .jm-hist{display:flex;align-items:center;gap:6px}
.jm-hist-btn{box-sizing:border-box;width:42px;height:42px;display:inline-flex;align-items:center;justify-content:center;border-radius:8px;border:1.5px solid var(--line);background:#fff;color:#4a4a4a;font-size:19px;line-height:1;padding:0;cursor:pointer}
.jm-hist-btn:disabled{opacity:.38;cursor:default}
/* The reset is the destructive one, so it is the only wine-coloured icon -- and it still asks before it acts (onReset). */
.jm-hist-reset{border-color:var(--wine);color:var(--wine)}
/* 3K-8e-4 (part two): the + is the only ADDITIVE icon in the bar, so it wears the green Apply already wears.
   It is a .jm-hist-btn like the other three -- same 42px box, same disabled look, same shrink below 390px. */
.jm-hist-add{border-color:var(--ok);color:var(--ok);font-size:22px}
/* 3K-8e-2d (U3, U4): "Keep this number" reads like Remove; what a staged press will do is said in words, with the ●. */
.jm-keep{display:block;margin-top:4px;padding:0;border:0;background:none;font:inherit;font-size:11.5px;font-weight:700;color:var(--wine);text-decoration:underline;cursor:pointer}
.jm-keep:focus-visible{outline:2px solid var(--wine);outline-offset:2px;border-radius:5px}
.jm-staged{display:block;margin-top:3px;font-size:11.5px;font-weight:600;color:#8a5200}
.jm-staged::before{content:"● ";color:#c47a17}

/* 3K-8e-3h: A SHUT ROW HOLDS NO FURNITURE. The boxes are hidden, never destroyed -- the same rule the phone
   layout has always followed, so a value typed into a row you then shut still applies (3K-8e-1 N4). */
.jm-table tbody tr.jm-row:not(.jm-row-open) td.jm-c-qty .jm-fbox,
.jm-table tbody tr.jm-row:not(.jm-row-open) td.jm-c-per .jm-fbox,
.jm-table tbody tr.jm-row:not(.jm-row-open) td.jm-c-price .jm-fbox,
.jm-table tbody tr.jm-row:not(.jm-row-open) .jm-fence-list{display:none}
.jm-table tbody tr.jm-row.jm-row-open .jm-shut{display:none}
/* 🔴 THE SUMMARY IS designer.js's OWN row.qty AND row.unitPrice, printed. Nothing here adds anything up. */
.jm-shut{display:block;font-weight:700;color:var(--ink);font-variant-numeric:tabular-nums}
.jm-shut-per{font-weight:400;color:var(--muted);font-size:11.5px}

/* 3K-8e-3f: THE FENCE IS NAMED ONCE, UNDER THE MATERIAL NAME. Measured on c9b83e1: a two-fence row
   printed the fence name SIX times, once per fence per column, with a catalog line under every one.
   The Name column names it twice and the number columns hold numbers. The cells are bottom-anchored
   so the Nth fence name lines up with the Nth box: both stacks are the same height and both grow
   downward from the same edge. */
.jm-fbox{min-height:46px;box-sizing:border-box}
.jm-table tbody tr.jm-row-fences td.jm-c-name,
.jm-table tbody tr.jm-row-fences td.jm-c-qty,
.jm-table tbody tr.jm-row-fences td.jm-c-per,
.jm-table tbody tr.jm-row-fences td.jm-c-price{vertical-align:bottom}
.jm-fence-list{margin-top:6px}
.jm-fence-row{min-height:46px;box-sizing:border-box;padding-top:4px}
.jm-fence-name{display:block;font-size:11.5px;font-weight:700;color:var(--muted);white-space:nowrap}
.jm-fence-default{display:block;font-size:11px;font-weight:400;color:var(--muted);margin-top:3px}
/* The narrow-only strip is off on a laptop, so it is never a column and never a Tab stop. */
.jm-table td.jm-c-fhead{display:none}

/* 🔴 T7-T10: THE PHONE. The SAME table, restyled: a row is a small grid showing Name and Total; its editing area
   (Qty, Price, Per, Remove) opens UNDERNEATH when its name is tapped. No second set of boxes, so a
   value typed into a closed row still applies (3K-8e-1 N4). Nothing scrolls sideways, so 3K-8e-2's pinned Name has
   nothing to do here and is switched off; it still works between 561px and ~944px, where the table scrolls. */
@media (max-width:560px){
  .jm-scroll{max-height:none;overflow:visible}
  .jm-table{min-width:0;table-layout:auto}
  .jm-table thead tr,.jm-table tbody tr{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr) auto;grid-template-areas:"name name total"}
  .jm-table tbody tr + tr{border-top:1px solid var(--line)}
  .jm-table .jm-row + .jm-row td,.jm-table .jm-section td,.jm-table .jm-subsection td{border-top:0}
  .jm-table thead th,.jm-table tbody td{display:none;width:auto;padding:6px 4px}
  .jm-table thead th.jm-c-name,.jm-table tbody td.jm-c-name,.jm-table .jm-section td:first-child,.jm-table .jm-subsection td:first-child{display:block;grid-area:name;position:static;background:transparent}
  .jm-table thead th.jm-c-total,.jm-table tbody td.jm-c-total{display:block;grid-area:total;width:auto;min-width:84px}
  .jm-section-label{position:static}
  .jm-table tbody tr.jm-row-open{grid-template-areas:"name name total" "qty price price" "per per per" "act act act";background:#fdfbf8}
  /* 3K-8e-3c (Y9): a row holding a Qty box for several fences gives them a line of their own above Price (measured in the
     sketch: stacked beside Price, the Fence 1 box ran under the Price box). */
  /* 3K-8e-3c (Y8): the 150px Qty width is a laptop width. Here the cell is one part of a stacked row and sizes itself, as the
     Per cell does below (measured: at 150px the Qty box ran under the Price box at 390px). */
  .jm-table tbody tr.jm-row-open td.jm-c-qty{width:auto}
  /* 3K-8e-3f: and the Price cell the same, for the same reason it was needed for Qty -- with a fence name beside the
     box its laptop 132px is not a width any more but a cage, and "catalog $10.00" wrapped inside it (measured at 390px). */
  .jm-table tbody tr.jm-row-open td.jm-c-price{width:auto}
  .jm-table tbody tr.jm-row-open.jm-row-fences{grid-template-areas:"name name total" "qty qty qty" "price price price" "per per per" "act act act"}
  .jm-table tbody tr.jm-row-open td.jm-c-qty{display:block;grid-area:qty}
  .jm-table tbody tr.jm-row-open td.jm-c-price{display:block;grid-area:price}
  .jm-table tbody tr.jm-row-open td.jm-c-per{display:block;grid-area:per}
  .jm-table tbody tr.jm-row-open td.jm-c-act{display:block;grid-area:act}
  /* No column headers on a phone, so the open row names its own boxes. */
  /* 🔴 16px AGAIN, EXPLICITLY: the rule above names the cell, so it outranks the 16px this file gives every
     box at this width, and a box under 16px is what iOS zooms the page into. The cell also gives up the
     150px it needs on a laptop: here it is one line of a stacked row, and 150px made its catalog line paint
     outside its own cell. */
  .jm-table tbody tr.jm-row-open td.jm-c-per{width:auto}
  /* 3K-8e-3b (W7): on a phone the Per line reads from the left, under its PER label, and its catalog line sits under
     its boxes (it painted at the right edge, measured). The 7.5px tuck of the laptop does not apply: here the boxes are bordered. */
  .jm-table tbody tr.jm-row-open td.jm-c-per,.jm-table tbody tr.jm-row-open td.jm-c-per .jm-calc,.jm-table tbody tr.jm-row-open td.jm-c-per .jm-gone{text-align:left}
  .jm-table tbody tr.jm-row-open td.jm-c-per .jm-per{justify-content:flex-start}
  .jm-table td.jm-c-qty .jm-calc,.jm-table td.jm-c-price .jm-calc{padding-right:0}
  /* 3K-8e-3b (W9): the rule under the heading goes on the row, which is one grid here, not under each of its two cells. */
  .jm-table .jm-section td{border-bottom:0}
  .jm-table tbody tr.jm-section{border-bottom:2px solid var(--wine)}
  /* 3K-8e-5b (P4): the same, one step quieter -- the rule belongs to the row here, which is one grid, not to each cell. */
  .jm-table .jm-subsection td{border-bottom:0}
  .jm-table tbody tr.jm-subsection{border-bottom:1px solid var(--line)}
  /* The laptop's indent would eat the name column at 390px; the heading and its rows read as a block from the rule alone. */
  .jm-table .jm-subsection td:first-child,.jm-table tbody tr.jm-row.jm-gate-row td.jm-c-name{padding-left:4px}
  .jm-actions .jm-hist{gap:6px}
  /* 🔴 A BOX LOOKS LIKE A BOX, AND IS 16px. With no border a tapped-open "9" read as plain text (screenshot), and
     iOS Safari zooms the whole page into a box whose text is under 16px (read, not measurable headless: Part B). */
  .jm-qty,.jm-price{font-size:16px;border-color:var(--line);background:#fff}
  /* 3K-8e-2d (U7): on a phone the bar's total is the only one, so the table's own total row gives way to it. */
  .jm-table tfoot{display:none}
  .jm-actions{min-height:59px;padding:8px 14px}
  /* 3K-8e-2f (F8): smaller at phone width, where 16px text made Apply the loudest thing in the bar. Still a fixed height, so
     nothing moves when it appears: 38px sits inside the bar (min-height 59px = 8 + 42 + 8 + a 1px rule). */
  .jm-actions .jm-apply{height:38px;padding:0 12px;font-size:14px}
  /* 🔴 3K-8e-3d (D3): ON A NARROW SCREEN THE BAR CARRIES THE ICONS AND THE TOTAL GOES TO THE END OF THE LIST. The icons keep
     their full 42px: measured, three of them plus Apply fit at 360px with 29.53px to spare, so the thumb target does NOT
     shrink on a phone. The bar stays 59px when Apply appears (measured 59 -> 59, icons moving 0.000px, at 390 and 360). */
  .jm-actions .jm-bar-total{display:none}
  .jm .jm-end-total{display:block}
  /* 🔴 3K-8e-3d: RIGHT-ALIGNED HERE BECAUSE THE GROWER IS GONE. Above 560px the bar total has flex-grow:1 and that is
     what pushes Apply and the icons to the right edge; the rule above hides it, so without this the row packed LEFT.
     flex-end, NOT `margin-left:auto` on the icons: it keeps Apply and the icons TOGETHER at the edge, the arrangement
     the laptop already has, instead of stranding Apply at the far left of an otherwise empty bar.
     🔴 IT STILL PINS THE LAST CHILD, so D2's invariant survives: measured 0.000px of icon movement when Apply appeared
     and 0.000px when "Apply 1 change" grew to "Apply 12 changes", at 390 and 360, with the icons flush to the content
     edge (gap 0.000px) and the bar holding 59px. Above 560px nothing changes (measured at 1280: total still at the
     left content edge, icons flush right, 0.000px, bar 63px).
     The full-width .jm-wait and .jm-msg lines have flex-basis:100%, so flex-end cannot reach them: both measured still
     flush to the LEFT content edge at 360px, full 332px wide. */
  .jm-actions{justify-content:flex-end}
  /* 🔴 3K-8e-3f R7: THE NOTE BECOMES AN "i" (on every width since 3K-8e-4c Round 3; its look is at the top of this file).
     margin-right:auto is what keeps Apply and the three icons flush right on a phone; the bar is justify-content:flex-end
     here, so nothing needs a margin-left. What it opens is .jm-info-panel, which drops down and takes no room. */
  .jm-info{margin-right:auto}
  /* 3K-8e-4c (Round 4, C2): on a phone the note lives behind the "i", as it did before Round 3. */
  .jm-note-desk{display:none}
  .jm-info-panel .jm-note-phone{display:block}
  /* Apply keeps its count and loses only the word: "Apply 12 changes" is 147px, "Apply 12" is 86px. */
  .jm-apply-long{display:none}
  .jm-apply-short{display:inline}

  /* 🔴 3K-8e-3f: THE OPEN ROW IS A SMALL TABLE. Rows are QTY / PRICE / PER, columns are the fences,
     and a strip of fence numbers sits on top. Every band is full width and carries its own label, so
     every box in the row is the same size: measured 122.92px wide and 32.84px tall for all three at
     390px, and 147.50 x 32.84 with one fence. An earlier draft put Qty and Price side by side; that
     band gives Qty a third of the row and Price two thirds, and the boxes came out 47 / 130 / 148. */
  .jm-table tbody tr.jm-row-open,
  .jm-table tbody tr.jm-row-open.jm-row-fences{grid-template-areas:"name name total" "fhead fhead fhead" "qty qty qty" "price price price" "per per per" "act act act"}
  .jm-table tbody tr.jm-row-open td.jm-c-qty,
  .jm-table tbody tr.jm-row-open td.jm-c-price,
  .jm-table tbody tr.jm-row-open td.jm-c-per{
    display:grid;align-items:start;grid-template-columns:62px repeat(var(--jm-n,1),minmax(0,1fr));
    column-gap:8px;padding:8px 4px 8px 0}
  /* 🔴 3K-8e-3f R9: NO LEFT PADDING ON A SCROLLING BAND. The sticky curtain is a GRID ITEM, so it lives in
     the CONTENT box and cannot start left of it. With padding-left:4px that 4px was a channel the scrolled
     content slid through in front of nothing -- measured at 390px, 4 fences, scrollLeft 130: 48 elements
     showing in a 4.0px strip. The labels take the 4px back below, so nothing sits on the panel edge. */
  /* 3K-8e-3f R9: ONE SCROLLBAR PER ROW, NOT THREE. One swipe moved three bands and drew three bars. The PER
     band is the bottom-most scrolling band, so its bar is the one an open row keeps. */
  .jm-table tbody tr.jm-row-open td.jm-c-qty,
  .jm-table tbody tr.jm-row-open td.jm-c-price,
  .jm-table tbody tr.jm-row-open td.jm-c-fhead{scrollbar-width:none}
  .jm-table tbody tr.jm-row-open td.jm-c-qty::-webkit-scrollbar,
  .jm-table tbody tr.jm-row-open td.jm-c-price::-webkit-scrollbar,
  .jm-table tbody tr.jm-row-open td.jm-c-fhead::-webkit-scrollbar{display:none}
  /* 3b: ALWAYS SHOWN, not the transient overlay macOS draws -- styling ::-webkit-scrollbar is what makes
     Chrome and Safari paint a persistent bar. */
  .jm-table tbody tr.jm-row-open td.jm-c-per{scrollbar-width:thin;scrollbar-color:var(--line) transparent}
  .jm-table tbody tr.jm-row-open td.jm-c-per::-webkit-scrollbar{-webkit-appearance:none;height:8px}
  .jm-table tbody tr.jm-row-open td.jm-c-per::-webkit-scrollbar-track{background:transparent}
  .jm-table tbody tr.jm-row-open td.jm-c-per::-webkit-scrollbar-thumb{background:var(--line);border-radius:4px}
  /* 3K-8e-3f R6: four or more fences cannot hold a 63px box in one view -- measured 59.1px per
     column at 390px and 51.5px at 360px. Up to three they all fit and nothing scrolls. */
  .jm-table tbody tr.jm-row-open.jm-row-many td.jm-c-qty,
  .jm-table tbody tr.jm-row-open.jm-row-many td.jm-c-price,
  .jm-table tbody tr.jm-row-open.jm-row-many td.jm-c-per,
  .jm-table tbody tr.jm-row-open.jm-row-many td.jm-c-fhead{
    grid-template-columns:62px repeat(var(--jm-n,1),minmax(92px,1fr));overflow-x:auto}
  /* With one fence the value track is capped, or a single box stretches the whole band (measured 260px). */
  .jm-table tbody tr.jm-row-open:not(.jm-row-fences) td.jm-c-qty,
  .jm-table tbody tr.jm-row-open:not(.jm-row-fences) td.jm-c-price,
  .jm-table tbody tr.jm-row-open:not(.jm-row-fences) td.jm-c-per{grid-template-columns:62px minmax(0,150px)}
  /* The label column: the small word naming the grey number on top, the row name under it. */
  .jm-table tbody tr.jm-row-open td.jm-c-qty::before{content:"Calc"}
  .jm-table tbody tr.jm-row-open td.jm-c-price::before{content:"Catalog"}
  .jm-table tbody tr.jm-row-open td.jm-c-per::before{content:"Catalog"}
  .jm-table tbody tr.jm-row-open td.jm-c-qty::after{content:"Qty"}
  .jm-table tbody tr.jm-row-open td.jm-c-price::after{content:"Price"}
  .jm-table tbody tr.jm-row-open td.jm-c-per::after{content:"Per"}
  .jm-table tbody tr.jm-row-open td.jm-c-qty::before,
  .jm-table tbody tr.jm-row-open td.jm-c-price::before,
  .jm-table tbody tr.jm-row-open td.jm-c-per::before{
    grid-column:1;grid-row:1;align-self:stretch;z-index:1;text-align:left;margin:0;padding:0;font-size:9.5px;
    font-weight:700;color:var(--muted);text-transform:uppercase;letter-spacing:.2px;line-height:15px;white-space:nowrap}
  .jm-table tbody tr.jm-row-open td.jm-c-qty::after,
  .jm-table tbody tr.jm-row-open td.jm-c-price::after,
  .jm-table tbody tr.jm-row-open td.jm-c-per::after{
    grid-column:1;grid-row:1;align-self:start;z-index:2;text-align:left;margin:18px 0 0;padding:0;font-size:10.5px;
    font-weight:700;color:var(--muted);text-transform:uppercase;line-height:34px;white-space:nowrap}
  /* The band scrolls under its own label, so the label is pinned and paints over what passes beneath it.
     3K-8e-3f R8: the z-index is NOT set here any more. This rule comes after the two above, so one shared
     value clobbered both -- the curtain and the row name need different layers. */
  .jm-table tbody tr.jm-row-open td.jm-c-qty::before,
  .jm-table tbody tr.jm-row-open td.jm-c-price::before,
  .jm-table tbody tr.jm-row-open td.jm-c-per::before,
  .jm-table tbody tr.jm-row-open td.jm-c-qty::after,
  .jm-table tbody tr.jm-row-open td.jm-c-price::after,
  .jm-table tbody tr.jm-row-open td.jm-c-per::after{position:sticky;left:0;background:#fdfbf8;padding-right:6px;padding-left:4px}
  /* 🔴 THE GREY NUMBER SITS ABOVE ITS BOX AND THE PER WORD BELOW ITS OWN BOX. Word-above read downward
     as "per 3 ft 8" - the numbers and their words in the wrong order, in the one column this slice
     exists to fix. order:-1 lifts the grey line without moving it in the DOM. */
  .jm-table tbody tr.jm-row-open .jm-fbox{margin-top:0;grid-row:1;display:flex;flex-direction:column;align-items:stretch;gap:3px}
  .jm-table tbody tr.jm-row-open .jm-calc{order:-1;text-align:center;padding-left:0;font-size:11px;white-space:nowrap;margin:0;line-height:15px}
  /* 3K-8e-3f R6: "1 per end post" is 71px at 11px and a 3-fence column at 360px is 71.3px. At 10px it is 64px. */
  .jm-table tbody tr.jm-row-fences .jm-calc{font-size:10px}
  .jm-table tbody tr.jm-row-open .jm-fq{justify-content:center;width:100%}
  .jm-table tbody tr.jm-row-open .jm-qty,
  .jm-table tbody tr.jm-row-open .jm-price{width:100%;flex:1 1 auto;min-width:0;height:auto;box-sizing:border-box;padding:4px 6px}
  .jm-table tbody tr.jm-row-open td.jm-c-per .jm-per{display:flex;flex-direction:column;align-items:stretch;gap:3px;width:100%}
  .jm-table tbody tr.jm-row-open .jm-per-g{display:flex;flex-direction:column;align-items:center;gap:1px}
  .jm-table tbody tr.jm-row-open .jm-per-g .jm-per-word{font-size:9.5px;font-weight:700;color:var(--muted);text-transform:uppercase;white-space:nowrap;letter-spacing:.2px;line-height:13px;text-align:center}
  .jm-table tbody tr.jm-row-open .jm-per-g .jm-perqty,
  .jm-table tbody tr.jm-row-open .jm-per-g .jm-perft{width:100%;flex:1 1 auto;min-width:0;font-size:16px;height:auto;box-sizing:border-box;padding:4px 6px}
  /* 3K-8e-3f R6: NO BOX IS WIDER THAN WHAT IT CAN HOLD. "999.99" at 16px bold plus 14px of padding is 63px;
     "99999" is 59px. A two-fence row was giving each box 122.5px of a column it could not fill. */
  .jm-table tbody tr.jm-row-open .jm-qty,
  .jm-table tbody tr.jm-row-open .jm-price,
  .jm-table tbody tr.jm-row-open td.jm-c-per .jm-per-g .jm-perqty,
  .jm-table tbody tr.jm-row-open td.jm-c-per .jm-per-g .jm-perft{max-width:63px}
  /* The fence number strip. Same track sizes as the bands under it, so the columns line up. */
  .jm-table tbody tr.jm-row-open td.jm-c-fhead{
    display:grid;grid-area:fhead;grid-template-columns:62px repeat(var(--jm-n,1),minmax(0,1fr));
    column-gap:8px;padding:4px 4px 2px 0;border-bottom:1px solid var(--line);width:auto;
    scrollbar-width:none}
  .jm-fhead-cell{font-size:10.5px;font-weight:700;color:var(--muted);text-transform:uppercase;text-align:center}
  .jm-fhead-pad{position:sticky;left:0;z-index:2;display:block;background:#fdfbf8;
    font-size:9.5px;font-weight:700;color:var(--muted);text-transform:uppercase;letter-spacing:.2px;
    white-space:nowrap;padding-right:6px;padding-left:4px}
  /* The wide view's fence list is off here - the strip names the fences now. */
  .jm-fence-list{display:none}
}

/* ==========================================================================
   🔴 3K-8e-4 (part two): BELOW 390px, AND ONLY BELOW 390px — FOUR ICONS PLUS APPLY ON ONE LINE.
   .jm-actions is flex-wrap:wrap, so an overflow does not clip: it silently becomes a second row
   and the bar grows from 59px, which would move every icon and break 8e-3d's D2 invariant. So the
   four icons and Apply are made to FIT instead.

   The bar's fixed parts, added up from the rules resolved below (the one figure that is not
   arithmetic is Apply's TEXT, which needs a font metric; it is carried through unchanged from the
   slice's own browser measurement of today's bar, so the three lines compare like with like):
     today, 3 icons at 42 .......... 281.35px needed   (measured in a browser: 281.35)
     with the + at its full 42px ... 329.35px needed   (measured in a browser: 329.35)
     with the + and this shrink .... 281.35px needed   (the slice measured 277.19)
   So the + costs +48.00px at full size -- 42 for the button and 6 for its gap, exactly -- and this
   block gives all 48 back: the shrunk FOUR-icon bar needs what today's THREE-icon bar needs, to the
   hundredth of a pixel. Nothing that fits today stops fitting. The slice's own measurement made the
   shrunk bar 4.16px narrower still; the arithmetic here will not reproduce that last 4.16px, and it
   is recorded rather than rounded away.

   🔴 AT 390px AND ABOVE NOTHING HERE APPLIES and the icons keep their full 42px thumb target.
   🔴 THE BAR'S HEIGHT DOES NOT MOVE. min-height stays 59px and the tallest thing in the row is now
      36px: 8 + 36 + 8 = 52, under the 59 the phone block already sets, so the bar is 59px here
      exactly as it is at 390px. Nothing below changes a height of the bar itself.
   ========================================================================== */
@media (max-width:389px){
  .jm-hist-btn{width:36px;height:36px}
  .jm-info{width:36px;height:36px}
  .jm-actions .jm-apply{height:36px;padding:0 8px}
  .jm-actions .jm-hist{gap:4px}
  .jm-actions{gap:6px}
}
