/* cutlist
 *
 * One stylesheet, one design, written from nothing.
 *
 * The sheet this replaces had a base rule making every button in the document
 * a full width slab (`input, select, textarea, button { width: 100% }` with a
 * solid accent background on `button`). Scoped rules added later lost to it, so
 * a hamburger became a blue bar across the page and a nudge control became a
 * blue block taller than the field it nudges.
 *
 * The rule that keeps that from coming back: no bare element selector ever
 * gives an element a size. Elements get typography and color. Size, width and
 * layout come from a class, so a control is only ever as large as its job.
 *
 * Layout is two columns wherever there is room, because the two things a person
 * compares constantly are the sheet diagram and the list of cuts describing it.
 * One column on a phone, where there is no width to spend.
 */

:root {
  --ink: #14181c;
  --ink-soft: #55606b;
  --paper: #f7f6f2;
  --panel: #ffffff;
  --line: #cfd4da;
  --line-soft: #e8ebee;
  --accent: #2f6f9f;
  --accent-soft: #eaf1f7;
  --danger: #9a2b2b;
  --warn-bg: #fff4d6;
  --warn-line: #d4a017;
  --buy-bg: #e8f1f8;
  --buy-line: #2f6f9f;
}

* { box-sizing: border-box; }

/* The user agent hides [hidden] with an attribute selector, which loses to any
   class rule that sets display. That is not a corner case here: it left the
   menu permanently on screen while its hidden property toggled correctly
   underneath, so the code and the tests both looked right. One rule, stated
   once, so no future display declaration can quietly un-hide something. */
[hidden] { display: none !important; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  padding: 0 20px 48px;
  background: var(--paper);
  color: var(--ink);
  font: 15px/1.45 system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
}

h1, h2, h3 { margin: 0; font-weight: 700; }

/* Typography and color only. Size belongs to a class. */
input, select, textarea, button { font: inherit; color: var(--ink); }

input[type="text"], input[type="number"], input[type="date"], select, textarea {
  padding: 5px 8px;
  border: 1px solid var(--line);
  border-radius: 6px;
  background: var(--panel);
}

input:focus-visible, select:focus-visible, textarea:focus-visible, button:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}

textarea { width: 100%; resize: vertical; }

.muted { color: var(--ink-soft); }

/* ---------------------------------------------------------------------------
   Header and menu
   --------------------------------------------------------------------------- */

.app-head {
  display: flex;
  align-items: center;
  gap: 16px;
  justify-content: space-between;
  padding: 14px 0 10px;
  border-bottom: 2px solid var(--line);
}

.app-head h1 { flex: 1 1 auto; min-width: 0; font-size: 1.3rem; overflow-wrap: anywhere; }

.menu { position: relative; flex: 0 0 auto; }

/* A button and a panel, never a <details>: a disclosure widget does not close
   when you click away and reads as a section of the document. */
.icon-button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 38px;
  height: 38px;
  padding: 0;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--panel);
  cursor: pointer;
}

.icon-button[aria-expanded="true"] { background: var(--ink); border-color: var(--ink); color: var(--panel); }

.menu-body {
  position: absolute;
  top: calc(100% + 6px);
  right: 0;
  z-index: 30;
  min-width: 14rem;
  /* Never wider than the screen it drops onto, whatever the min-width asks for. */
  max-width: calc(100vw - 40px);
  display: flex;
  flex-direction: column;
  padding: 6px;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--panel);
  box-shadow: 0 8px 24px rgba(0, 0, 0, .14);
}

.menu-body hr { width: 100%; margin: 5px 0; border: 0; border-top: 1px solid var(--line-soft); }

/* The GitHub entry stays an anchor so middle-click and open-in-new-tab keep
   working, and is styled exactly like the buttons beside it so it does not
   read as the odd one out. */
.menu-body button,
.menu-body a {
  display: block;
  width: 100%;
  padding: 7px 10px;
  border: 0;
  border-radius: 6px;
  background: none;
  color: var(--ink);
  text-align: left;
  text-decoration: none;
  cursor: pointer;
}

.menu-body button:hover, .menu-body a:hover { background: var(--accent-soft); }
.menu-body a[aria-disabled="true"] { opacity: .45; cursor: default; }

.status { margin: 8px 0 0; color: var(--ink-soft); }
.status:empty { display: none; }
.status.banner-warn { position: sticky; z-index: 20; top: 8px; }

/* ---------------------------------------------------------------------------
   Landing
   --------------------------------------------------------------------------- */

body.landing-mode { padding: 0 20px 64px; }
body.landing-mode > .status { display: none; }

.landing { width: min(64rem, 100%); margin: 0 auto; padding-top: clamp(40px, 9vw, 96px); }
.landing-hero { max-width: 42rem; margin-bottom: 44px; }
.landing-kicker { margin: 0 0 8px; color: var(--accent); font-size: .76rem; font-weight: 800; letter-spacing: .12em; text-transform: uppercase; }
.landing-hero h1 { font-size: clamp(2rem, 7vw, 4.2rem); line-height: 1; letter-spacing: -.04em; }
.landing-hero > p:not(.landing-kicker) { max-width: 36rem; margin: 18px 0 24px; color: var(--ink-soft); font-size: 1.08rem; }

.landing-primary,
.landing-card,
.landing-library-card button,
.landing-library-card a {
  border: 1px solid var(--line);
  border-radius: 9px;
  background: var(--panel);
  color: var(--ink);
  cursor: pointer;
  text-decoration: none;
}

.landing-primary { padding: 10px 18px; border-color: var(--accent); background: var(--accent); color: white; font-weight: 700; }
.landing-primary:hover { filter: brightness(.94); }
.landing-section { margin-top: 30px; }
.landing-section h2 { margin-bottom: 10px; font-size: .78rem; letter-spacing: .1em; text-transform: uppercase; color: var(--ink-soft); }
.landing-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(16rem, 100%), 1fr)); gap: 10px; }
.landing-card { display: flex; flex-direction: column; align-items: flex-start; gap: 4px; min-height: 86px; padding: 14px 16px; text-align: left; }
button.landing-card:hover, .landing-library-card:hover { border-color: var(--accent); box-shadow: 0 2px 10px rgba(0, 0, 0, .06); }
.landing-card strong { font-size: 1rem; }
.landing-card span { color: var(--ink-soft); font-size: .82rem; }
.landing-card span + span { display: -webkit-box; overflow: hidden; -webkit-box-orient: vertical; -webkit-line-clamp: 2; }
.landing-library-card { padding: 0; overflow: hidden; }
.landing-library-card button { width: 100%; flex: 1 1 auto; padding: 14px 16px 10px; border: 0; border-radius: 0; background: none; text-align: left; }
.landing-library-card button strong, .landing-library-card button span { display: block; }
.landing-library-card button .landing-open { margin-top: 8px; color: var(--accent); }
.landing-library-card a { align-self: stretch; margin: 0 12px 12px; padding: 7px 10px; color: var(--accent); text-align: center; }
.landing-library-card a:hover { border-color: var(--accent); background: var(--accent-soft); }

/* ---------------------------------------------------------------------------
   Workspace: input on the left, the plan on the right
   --------------------------------------------------------------------------- */

.workspace { display: grid; gap: 28px; align-items: start; padding-top: 18px; }

@media (min-width: 62rem) {
  .workspace { grid-template-columns: minmax(28rem, 5fr) 6fr; gap: 32px; }
}

/* The plan column used to be sticky with its own max-height and overflow. That
   turned it into a second scroll container: the page could only scroll as far
   as the capped column was tall, so a wheel over the input side moved a little
   and then stopped dead with the bottom of the form out of reach. One page,
   one scrollbar. */

.section { margin: 0 0 26px; }

.section > summary {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 0 0 8px;
  padding: 2px 0;
  cursor: pointer;
  list-style: none;
}

.section > summary::-webkit-details-marker { display: none; }

/* Our own marker, so it sits on the line rather than above a block-level
   heading, and turns to say which way the section is going. */
.section > summary::before {
  content: "";
  flex: 0 0 auto;
  width: 0;
  height: 0;
  border-left: 5px solid var(--ink-soft);
  border-top: 4px solid transparent;
  border-bottom: 4px solid transparent;
  transition: transform .12s ease;
}

.section[open] > summary::before { transform: rotate(90deg); }
.section > summary:hover::before { border-left-color: var(--ink); }

.section > summary > h2 {
  margin: 0;
  font-size: .72rem;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--ink-soft);
}

/* ---------------------------------------------------------------------------
   Tabular entry
   --------------------------------------------------------------------------- */

.grid-table { width: 100%; border-collapse: collapse; }

.grid-table th {
  padding: 3px 6px;
  border-bottom: 1px solid var(--line);
  font-size: .68rem;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--ink-soft);
  text-align: left;
  white-space: nowrap;
}

.grid-table th[scope="row"] {
  width: 1%;
  padding-right: 10px;
  border-bottom: 0;
  font-size: .8rem;
  letter-spacing: 0;
  text-transform: none;
  color: var(--ink-soft);
}

.grid-table td { padding: 2px 6px; border-bottom: 1px solid var(--line-soft); vertical-align: middle; }
.grid-table tbody tr:last-child td { border-bottom: 0; }
.grid-table th.num, .grid-table td.num { text-align: right; }
.grid-table th.mid, .grid-table td.mid { text-align: center; }

.grid-table input[type="text"],
.grid-table input[type="number"],
.grid-table input[type="date"],
.grid-table select { width: 100%; min-width: 4rem; }

.grid-table input[type="number"] { text-align: right; }
.grid-table td.qty input { width: 4.5rem; min-width: 0; }

/* A checkbox is a checkbox. Its column header already names it. */
.grid-table input[type="checkbox"] { width: 16px; height: 16px; margin: 0; }

.row-remove {
  width: 24px;
  height: 24px;
  padding: 0;
  border: 1px solid transparent;
  border-radius: 5px;
  background: none;
  color: var(--ink-soft);
  font-size: 16px;
  line-height: 1;
  cursor: pointer;
}

.row-remove:hover { border-color: var(--line); color: var(--danger); background: var(--panel); }

.add-row {
  width: 100%;
  margin-top: 6px;
  padding: 6px;
  border: 1px dashed var(--line);
  border-radius: 8px;
  background: none;
  color: var(--ink-soft);
  cursor: pointer;
}

.add-row:hover { border-color: var(--accent); color: var(--accent); }

/* A spinner shaped like the browser's own: a narrow gutter beside the box, so
   nudging a number never costs more room than the number itself. */
.stepper { display: inline-flex; align-items: stretch; width: 100%; min-width: 5rem; }
.stepper input { flex: 1 1 auto; min-width: 0; border-radius: 6px 0 0 6px; }
.stepper .steps { display: flex; flex-direction: column; flex: 0 0 15px; }

.stepper .step {
  flex: 1 1 50%;
  padding: 0;
  border: 1px solid var(--line);
  border-left: 0;
  background: var(--panel);
  color: var(--ink-soft);
  font-size: 7px;
  line-height: 1;
  cursor: pointer;
}

.stepper .step:first-child { border-radius: 0 6px 0 0; }
.stepper .step:last-child { border-top: 0; border-radius: 0 0 6px 0; }
.stepper .step:hover { background: var(--accent-soft); color: var(--ink); }

/* A material owns its sheet sizes, so they are drawn inside it behind a rule. */
.group { margin: 0 0 14px; padding: 10px 12px; border: 1px solid var(--line); border-radius: 10px; background: var(--panel); }
.group-head { display: flex; gap: 8px; align-items: center; margin-bottom: 8px; }
.group-head > div { display: flex; align-items: center; gap: 6px; min-width: 0; }
.group-head label { font-size: .7rem; letter-spacing: .06em; text-transform: uppercase; color: var(--ink-soft); white-space: nowrap; }
.group-head input[type="text"] { flex: 1 1 auto; min-width: 6rem; }
.group-sheets { margin-left: 6px; padding-left: 12px; border-left: 3px solid var(--line-soft); }

.group-sheets > h3 {
  margin: 4px 0;
  font-size: .68rem;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--ink-soft);
}

/* ---------------------------------------------------------------------------
   Results
   --------------------------------------------------------------------------- */

.notes-banner, .banner-warn, .shopping-list, .banner-buy {
  margin: 0 0 14px;
  padding: 10px 12px;
  border-radius: 8px;
}

.notes-banner { border-left: 4px solid var(--accent); background: var(--panel); white-space: pre-line; }
.banner-warn { border: 1px solid var(--warn-line); background: var(--warn-bg); }
.banner-warn ul, .shopping-list ul { margin: 4px 0 0; padding-left: 20px; }
.shopping-list { border: 1px solid var(--buy-line); background: var(--buy-bg); }
.shopping-list h2 { margin-bottom: 4px; font-size: .95rem; }
.banner-buy { border: 1px solid var(--buy-line); background: var(--buy-bg); }

.material-section { margin: 0 0 22px; }
.material-section > h2 { margin-bottom: 4px; font-size: 1rem; }
.material-note { margin: 0 0 8px; color: var(--ink-soft); white-space: pre-line; }

.sheet { margin: 0 0 16px; padding: 12px; border: 1px solid var(--line); border-radius: 10px; background: var(--panel); }
.sheet > h3 { margin-bottom: 8px; font-size: .9rem; }
.sheet-grid { display: grid; gap: 14px; align-items: start; }

@media (min-width: 44rem) {
  .sheet-grid { grid-template-columns: minmax(0, 1fr) minmax(11rem, 15rem); }
}

.sheet-figure { min-width: 0; }
.sheet-view { display: block; }
.sheet-view svg, .sheet-svg { display: block; width: 100%; height: auto; }
.board-view svg, .board-svg { display: block; width: 100%; height: auto; }
.board-figure { min-width: 8%; }
.board-part-label { fill: var(--ink); font-weight: 700; }
.board-cut-label { fill: var(--ink); paint-order: stroke; stroke: var(--panel); stroke-width: .2em; }
.board-cut-line { stroke-dasharray: none; }

.thickness-custom {
  display: grid;
  grid-template-columns: minmax(7rem, 1fr) minmax(5.5rem, .7fr);
  gap: 6px;
  align-items: center;
}

.thickness-custom label { display: contents; }
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}
/* Turning the picture.
 *
 * A bare `transform: rotate(90deg)` does not change an element's layout box, so
 * the turned diagram kept the tall footprint of the upright one: the picture
 * shrank into the middle of a column sized for its old shape, and the overflow
 * ran across whatever sat beside it as a white stripe.
 *
 * The wrapper is what reserves space instead. It swaps to the rotated aspect
 * ratio, and the SVG inside is sized to the wrapper's other axis before being
 * turned about its own center, so the picture fills the room it is given and
 * nothing spills out of it. */
.sheet-view.rotated {
  position: relative;
  width: 100%;
  /* The turned shape: a 96 x 48 sheet shown on its side is 48 wide by 96 long,
     so the wrapper reserves that, and nothing below it gets overlapped. */
  aspect-ratio: var(--turned-ratio);
  overflow: hidden;
}

.sheet-view.rotated > svg {
  position: absolute;
  top: 50%;
  left: 50%;
  /* Sized so that after the quarter turn the picture exactly fills the wrapper:
     its pre-rotation width becomes the wrapper's height, and vice versa. */
  width: calc(100% * var(--sheet-ratio));
  height: auto;
  max-width: none;
  transform: translate(-50%, -50%) rotate(90deg);
  transform-origin: center;
}

.view-rotated-note { margin: 6px 0 0; font-size: .78rem; color: var(--ink-soft); }

/* Controls that act on the picture sit under it, quiet and small. */
.figure-tools { display: flex; flex-wrap: wrap; gap: 6px; justify-content: flex-end; margin-top: 6px; }

.figure-tools button {
  padding: 3px 9px;
  border: 1px solid var(--line);
  border-radius: 6px;
  background: var(--panel);
  color: var(--ink-soft);
  font-size: .78rem;
  cursor: pointer;
}

.figure-tools button:hover { color: var(--ink); border-color: var(--ink); }

.sheet-todo-title { margin: 0 0 4px; font-size: .68rem; letter-spacing: .06em; text-transform: uppercase; color: var(--ink-soft); }

.cuts { margin: 0 0 10px; padding: 0; list-style: none; counter-reset: cut; }

.cuts li {
  display: flex;
  gap: 6px;
  align-items: baseline;
  padding: 3px 5px;
  border-radius: 5px;
  cursor: pointer;
}

.cuts li::before {
  counter-increment: cut;
  content: counter(cut) ".";
  flex: 0 0 1.4rem;
  text-align: right;
  color: var(--ink-soft);
  font-variant-numeric: tabular-nums;
}

.cuts .measure { font-weight: 700; font-variant-numeric: tabular-nums; }
.cuts .from, .cuts .frees { color: var(--ink-soft); font-size: .85em; }
.cuts li:hover { background: var(--accent-soft); }
.cuts li.is-active { background: var(--buy-bg); box-shadow: inset 0 0 0 2px var(--buy-line); }

.parts { margin: 0; padding: 0; list-style: none; font-size: .88rem; }
.parts li { padding: 2px 0; }
.parts label { display: flex; gap: 6px; align-items: center; cursor: pointer; }
.parts input[type="checkbox"] { flex: 0 0 auto; width: 16px; height: 16px; margin: 0; }

.leftover { margin: 8px 0 0; font-size: .82rem; color: var(--ink-soft); }
.part-block { font-size: .88rem; }

/* Diagram internals.
 *
 * NEVER set font-size or stroke-width here in pixels. The viewBox is the
 * sheet's real size in inches, so one user unit is one inch: a `font-size:
 * 10px` rule beats the renderer's own presentation attribute and draws a label
 * ten inches tall, which is exactly what it did. The renderer sizes its own
 * text and strokes in sheet units, scaled to the sheet. Color and weight only. */
.cut-line { fill: none; stroke: #8a949d; stroke-dasharray: 5 4; }
/* A cut label must be readable wherever the line happens to run: over a
   saturated part fill, over white offcut, or straddling the two. The halo is
   what makes one rule work in all three places, and it is drawn behind the
   glyphs so it never thickens them. */
.cut-step-no {
  fill: var(--ink);
  font-weight: 700;
  paint-order: stroke fill;
  stroke: var(--paper);
  stroke-width: 0.6px;
  stroke-linejoin: round;
}
.cut-line.is-active { stroke: #c0392b; stroke-dasharray: none; }
.cut-step-no.is-active { fill: #c0392b; stroke: #fff; }
.cut-label { fill: #fff; font-weight: 700; }
.cut-dims, .edge-dim, .scrap-label { fill: var(--ink-soft); }
.sheet-edge { fill: none; stroke: var(--ink); }
.sheet-usable { fill: none; stroke: var(--line); }

/* ---------------------------------------------------------------------------
   Dialogs
   --------------------------------------------------------------------------- */

dialog { padding: 18px; border: 1px solid var(--line); border-radius: 12px; background: var(--panel); color: var(--ink); }
dialog::backdrop { background: rgba(0, 0, 0, .35); }
dialog h2 { margin-bottom: 10px; font-size: 1.05rem; }
dialog label { display: block; margin: 10px 0 4px; font-size: .8rem; color: var(--ink-soft); }
dialog select { width: 100%; min-width: 16rem; }
dialog .row { display: flex; gap: 8px; justify-content: flex-end; margin-top: 14px; }

dialog .row button {
  padding: 6px 14px;
  border: 1px solid var(--line);
  border-radius: 7px;
  background: var(--panel);
  cursor: pointer;
}

dialog .row button:hover { border-color: var(--ink); }

#dialog-library { width: min(42rem, calc(100vw - 32px)); max-height: calc(100vh - 32px); overflow: auto; }
#dialog-library > form > .muted { margin: 0 0 10px; }
.library-material { margin: 12px 0; padding: 10px 12px 12px; border: 1px solid var(--line); border-radius: 8px; }
.library-material legend { padding: 0 5px; font-weight: 700; }
.library-material legend .muted { margin-left: 4px; font-size: .8rem; font-weight: 400; }
.library-material > label { margin-top: 0; }
.library-stock-list { margin-top: 8px; border-top: 1px solid var(--line-soft); }
#dialog-library .library-stock-row { display: flex; align-items: center; gap: 9px; margin: 0; padding: 8px 2px; border-bottom: 1px solid var(--line-soft); color: var(--ink); cursor: pointer; }
.library-stock-row input { flex: 0 0 auto; width: 18px; height: 18px; margin: 0; }

/* A cut line reads as one sentence: the measurement, the edge it is taken
   from, and what it frees. Letting the three wrap into columns of their own
   turned four steps into a ragged grid. */
.cuts li { flex-wrap: wrap; }
.cuts .measure { white-space: nowrap; }
.cuts .from { white-space: nowrap; }
.cuts .frees { flex: 1 1 100%; padding-left: 1.4rem; }

/* A part's name is the widest thing in its row and the one you scan for, so it
   gets the room and the numbers stay narrow. */
.grid-table td:first-child input[type="text"] { min-width: 8rem; }
.grid-table td.num { width: 6rem; }
.grid-table td.mid { width: 2rem; }

/* Reordering. Two small chevrons in their own column, disabled at the ends so
   the column keeps its width as a row travels. */
.moves { display: inline-flex; flex-direction: column; gap: 1px; }

.row-move {
  width: 18px;
  height: 12px;
  padding: 0;
  border: 1px solid var(--line);
  border-radius: 3px;
  background: var(--panel);
  color: var(--ink-soft);
  font-size: 6px;
  line-height: 1;
  cursor: pointer;
}

.row-move:hover:not(:disabled) { background: var(--accent-soft); color: var(--ink); }
.row-move:disabled { opacity: .3; cursor: default; }
.grid-table td.move { width: 1.6rem; }

/* A sheet's heading is a link to that sheet on its own, which is the view for a
   phone at the saw. It carries the whole project, so it can be opened in a tab,
   bookmarked, or sent to another device. */
.sheet-link { color: inherit; text-decoration: none; border-bottom: 1px dashed var(--line); }
.sheet-link:hover { color: var(--accent); border-bottom-color: var(--accent); }
.focus-back { margin: 0 0 12px; }
.focus-back a { color: var(--accent); text-decoration: none; }
.focus-back a:hover { text-decoration: underline; }

/* In the focused view the input column is not on screen at all, so the plan
   gets the whole width and none of the sticky-column behavior. */
body.focus-sheet .inputs { display: none; }
body.focus-sheet .workspace { grid-template-columns: 1fr; }
body.focus-sheet .results { position: static; max-height: none; overflow: visible; }

/* A sortable header is a button that still looks like a header. */
.grid-table th.sortable { padding: 0; }

.grid-table th.sortable button {
  width: 100%;
  padding: 3px 6px;
  border: 0;
  background: none;
  color: inherit;
  font: inherit;
  letter-spacing: inherit;
  text-transform: inherit;
  text-align: inherit;
  cursor: pointer;
}

.grid-table th.sortable.num button { text-align: right; }
.grid-table th.sortable button:hover { color: var(--ink); background: var(--accent-soft); }
.grid-table th.sorted button { color: var(--accent); }

/* A shopping list you can work down in a store: big enough to hit with a thumb,
   and a ticked line reads as done at a glance. */
.buy-list { margin: 6px 0 0; padding: 0; list-style: none; }
.buy-list li { padding: 4px 0; }
.buy-list label { display: flex; gap: 10px; align-items: center; cursor: pointer; }
.buy-list input[type="checkbox"] { flex: 0 0 auto; width: 20px; height: 20px; margin: 0; }
.buy-list li.done label { text-decoration: line-through; opacity: .55; }
.parts li.done label { text-decoration: line-through; opacity: .55; }

.open-alone {
  margin-left: 8px;
  font-size: .72rem;
  font-weight: 400;
  letter-spacing: 0;
  text-transform: none;
  color: var(--accent);
}

body.focus-sheet .shopping-list { border-width: 0; background: none; padding: 0; }
body.focus-sheet .shopping-list li { padding: 8px 0; border-bottom: 1px solid var(--line-soft); }

/* Stepping between sheets on a phone: back on the left, position in the
   middle, Prev and Next big enough to hit with a thumb on the right. */
.sheet-nav {
  display: flex;
  gap: 12px;
  align-items: center;
  justify-content: space-between;
  margin: 0 0 12px;
  padding-bottom: 10px;
  border-bottom: 1px solid var(--line);
}

.sheet-nav > a { color: var(--accent); text-decoration: none; }
.sheet-nav > a:hover { text-decoration: underline; }
.sheet-count { color: var(--ink-soft); font-variant-numeric: tabular-nums; }
.sheet-steps-nav { display: flex; gap: 8px; }

.sheet-step {
  padding: 6px 14px;
  border: 1px solid var(--line);
  border-radius: 7px;
  background: var(--panel);
  color: var(--ink);
  text-decoration: none;
}

.sheet-step:hover { border-color: var(--accent); color: var(--accent); }
.sheet-step.is-off { opacity: .35; }

.sub-head { margin: 16px 0 6px; font-size: .72rem; letter-spacing: .09em; text-transform: uppercase; color: var(--ink-soft); }
.material-kind-head { margin-top: 22px; color: var(--ink); }
.material-stock-group {
  margin-top: 14px;
  padding: 10px 12px 12px;
  border: 1px solid var(--line);
  border-radius: 9px;
  background: var(--panel);
}
.material-stock-group > .material-kind-head { margin-top: 0; }
.material-stock-group > .sub-head:not(.material-kind-head) { margin-top: 18px; }
.hint { margin: 6px 0 0; font-size: .8rem; }
.add-row:disabled { opacity: .45; cursor: default; }
.add-row:disabled:hover { border-color: var(--line); color: var(--ink-soft); }

/* A wide entry table scrolls inside its section. The header and body remain one
   table, so every heading always uses the exact same columns as its rows. */
.table-scroll { width: 100%; overflow-x: auto; }
.section .grid-table { display: table; width: 100%; min-width: 100%; table-layout: auto; }

/* An edit row contains intrinsically wide controls; a display row contains
   short text. Both use the same explicit columns so entering edit mode never
   makes the whole table jump. Narrow panes scroll the complete table instead
   of squeezing a measurement control until it is unusable. */
.section .grid-table.row-table { table-layout: fixed; }
.section .grid-table.sheet-material-table { min-width: 48rem; }
.section .grid-table.sheet-stock-table { min-width: 58rem; }
.section .grid-table.board-material-table { min-width: 51rem; }
.section .grid-table.board-stock-table { min-width: 42rem; }
.section .grid-table.parts-table { min-width: 52rem; }
.row-table .col-move { width: 2rem; }
.row-table .col-name { width: 11rem; }
.row-table .col-thickness { width: 15rem; }
.row-table .col-material { width: 10rem; }
.row-table .col-size { width: 10rem; }
.row-table .col-measure { width: 7rem; }
.row-table .col-qty { width: 5rem; }
.row-table .col-note { width: 11rem; }
.row-table .col-grain { width: 4rem; }
.row-table .col-actions { width: 5.5rem; }
.row-table input,
.row-table select { max-width: 100%; }

/* Display and edit mode use the exact same grid template. Unlike table auto
   sizing, content cannot make a row disagree with its headings. */
.supply-grid { min-width: 54rem; }
.supply-grid-row {
  display: grid;
  grid-template-columns: 1.6rem 2rem minmax(8rem, 1.2fr) 4rem 5rem 3.5rem 6rem minmax(7rem, 1fr) minmax(8rem, 1.2fr) 4.5rem;
  column-gap: 4px;
  align-items: center;
  border-bottom: 1px solid var(--line-soft);
}
.supply-grid-row > * { min-width: 0; padding: 3px 6px; }
.supply-grid-head {
  border-bottom-color: var(--line);
  color: var(--ink-soft);
  font-size: .68rem;
  font-weight: 600;
  letter-spacing: .06em;
  text-transform: uppercase;
  white-space: nowrap;
}
.supply-grid .num { text-align: right; }
.supply-grid input[type="text"],
.supply-grid input[type="number"],
.supply-grid input[type="url"] { width: 100%; min-width: 0; }
.supply-grid input[type="number"] { text-align: right; }
.supply-grid input[type="checkbox"] { width: 16px; height: 16px; margin: 0; }
.supply-buy output { font-variant-numeric: tabular-nums; font-weight: 600; }
.supply-display { min-height: 34px; }
.supply-name { font-weight: 600; }
.supply-editable,
.grid-table td[data-action="edit-row"] { cursor: text; }
.supply-editable:hover,
.grid-table td[data-action="edit-row"]:hover { background: var(--accent-soft); }
.supply-domain { display: block; overflow: hidden; color: var(--accent); text-overflow: ellipsis; white-space: nowrap; }
.supply-actions,
.row-actions { display: flex; gap: 4px; align-items: center; justify-content: flex-end; white-space: nowrap; }
.supply-edit-action,
.row-edit-action { padding: 2px 4px; border: 0; background: none; color: var(--accent); font: inherit; cursor: pointer; }
.supply-edit-action:hover,
.row-edit-action:hover { text-decoration: underline; }
.grid-table .row-display { height: 35px; }

/* Selecting a step clears the picture down to that one cut.
 *
 * A sheet with a dozen cuts carries a dozen measurements, and on a narrow sheet
 * they are wider than the strip they label. Once someone has said which cut
 * they are making, the other eleven are noise: they fade to their lines and
 * only the chosen label keeps its text. */
.sheet-view.has-selection .cut-step-no { opacity: 0; }
.sheet-view.has-selection .cut-step-no.is-active { opacity: 1; }
.sheet-view.has-selection .cut-line { stroke-opacity: .25; }
.sheet-view.has-selection .cut-line.is-active { stroke-opacity: 1; }

/* The input column stays in view while the plan scrolls past it.
 *
 * On a project with three sheets the left side ran out long before the right
 * did, so by the third sheet there were no parts on screen and no way to see
 * what changing one did. Only this column is capped and scrollable; the page
 * itself is still driven by the plan, which is what keeps the wheel working
 * everywhere. Capping both was the earlier mistake: it left the document
 * shorter than its own content and scrolling died halfway down. */
@media (min-width: 62rem) {
  .inputs {
    position: sticky;
    top: 14px;
    align-self: start;
    max-height: calc(100vh - 28px);
    overflow-y: auto;
    overscroll-behavior: contain;
    padding-right: 6px;
  }
}
