/* =============================================================================
   app.css — Application shell styles
   Loaded after Bootstrap 5 and style.ink-signal.css (Ink & Signal design system).

   Responsibilities:
   1. Dark mode — overrides CSS variables when <body class="dark-mode">
   2. App shell layout — .app-content wrapper, .topbar component
   3. Topbar component styles
   4. Smooth theme-switch transitions
   ============================================================================= */

/* =============================================================================
   1. DARK MODE
   All custom token overrides hang off body.dark-mode.
   Child elements inherit these via CSS var() cascade — no individual class needed.

   UI/UX audit fix (Critical #1): this whole block used to hardcode the OLD
   light "Ledger Precision" theme's forest-green dark variant (#0F1511 /
   #162018 / #2A3A2A / rgba(42,96,64,…) etc.), which visibly clashed with
   Ink & Signal's near-black/red palette that now loads by default on every
   page — toggling "dark mode" produced a second, mismatched, greenish dark
   theme instead of a coherent refinement of the one theme the app actually
   uses. Ink & Signal is already dark by design, so this now applies a
   subtle, same-family darkening (neutral near-black + the red signal accent
   for hover/emphasis) instead of swapping in an unrelated palette.
   ============================================================================= */
body.dark-mode {
  --paper:    #050506;
  --surface:  #101013;
  --border:   #26262B;
  --ink:      #F2F1EE;
  --ink-mid:  #A8A7A2;
  --ink-soft: #8A897F;
  --ledger:   #000000;
  --ledger-h: #000000;

  background: #050506;
  color: #F2F1EE;
}

body.dark-mode .sidebar         { background: #000000; border-right: 1px solid #26262B; }
body.dark-mode .card,
body.dark-mode .stat-card       { background: #101013; border-color: #26262B; }
body.dark-mode .card-header     { background: #050506; border-color: #26262B; }
body.dark-mode th               { background: #050506; color: #A8A7A2; border-color: #26262B; }
body.dark-mode td               { border-color: #26262B; color: #F2F1EE; }
body.dark-mode tbody tr:nth-child(even) td { background: #0C0C0E; }
body.dark-mode tbody tr:hover td           { background: rgba(232,57,75,.08) !important; }
body.dark-mode .topbar          { background: #101013; border-color: #26262B; }
body.dark-mode .topbar-title    { color: #F2F1EE; }
body.dark-mode .topbar-user-name { color: #F2F1EE; }
body.dark-mode .topbar-btn      { border-color: #26262B; color: #A8A7A2; }
body.dark-mode .topbar-btn:hover { background: #050506; }
body.dark-mode input,
body.dark-mode select,
body.dark-mode textarea         { background: #101013; border-color: #26262B; color: #F2F1EE; }
body.dark-mode .alert           { border-color: #26262B; }
body.dark-mode code             { background: #050506 !important; border-color: #26262B !important; }

/* =============================================================================
   2. APP SHELL
   .app is defined in style.ink-signal.css as a 2-column grid (232px sidebar + 1fr main).
   .app-content stacks topbar above the scrollable main area.
   ============================================================================= */
.app-content {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  overflow: hidden;
}

/* =============================================================================
   3. TOPBAR
   ============================================================================= */
.topbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 0 32px;
  height: 56px;
  flex-shrink: 0;
  background: var(--surface);
  border-bottom: 1px solid var(--border);
  position: sticky;
  top: 0;
  z-index: 20;
}

.topbar-left  { display:flex; align-items:center; gap:12px; min-width:0; }
.topbar-right { display:flex; align-items:center; gap:10px; flex-shrink:0; }

.topbar-title {
  font-family: var(--font-mono);
  font-size: 13px;
  font-weight: 600;
  letter-spacing: .04em;
  color: var(--ink);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.topbar-user {
  display: flex;
  align-items: center;
  gap: 8px;
}

.topbar-user-name {
  font-family: var(--font-mono);
  font-size: 12px;
  font-weight: 600;
  color: var(--ink);
  white-space: nowrap;
}

.topbar-btn {
  background: none;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  cursor: pointer;
  width: 32px;
  height: 32px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 15px;
  color: var(--ink-mid);
  transition: background-color .15s, border-color .15s;
}
.topbar-btn:hover        { background: var(--paper); border-color: var(--accent); }
.topbar-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.topbar-btn:disabled     { opacity: .4; cursor: default; }

/* =============================================================================
   Phase B — hamburger (mobile drawer toggle) + breadcrumb slot
   Hidden by default; .hamburger is revealed at the tablet/mobile breakpoints
   defined in style.ink-signal.css §5 RESPONSIVE. .crumb reuses .topbar-title's
   typography so pages without $breadcrumbs fall back seamlessly.
   ============================================================================= */
.hamburger {
  display: none;
  background: none;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  cursor: pointer;
  width: 32px;
  height: 32px;
  align-items: center;
  justify-content: center;
  font-size: 16px;
  color: var(--ink-mid);
  flex-shrink: 0;
}
.hamburger:hover         { background: var(--paper); border-color: var(--accent); }
.hamburger:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

.crumb {
  display: flex;
  align-items: center;
  gap: 6px;
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--ink-mid);
  white-space: nowrap;
  overflow: hidden;
  min-width: 0;
}
.crumb a    { color: var(--ink-mid); text-decoration: none; }
.crumb a:hover { color: var(--accent); }
.crumb .sep { color: var(--border); }
.crumb span:last-child { color: var(--ink); font-weight: 600; overflow: hidden; text-overflow: ellipsis; }

body.dark-mode .hamburger { border-color: #26262B; color: #A8A7A2; }
body.dark-mode .hamburger:hover { background: #050506; }

/* =============================================================================
   Phase 4 — dark mode additions
   ============================================================================= */
body.dark-mode .modal             { background: #101013; border-color: #26262B; }
body.dark-mode .modal-header      { background: #050506; border-color: #26262B; }
body.dark-mode .modal-footer      { background: #050506; border-color: #26262B; }
body.dark-mode .modal-overlay     { background: rgba(0,0,0,.8); }
body.dark-mode #notifDropdown     { background: #101013; border-color: #26262B; }
body.dark-mode .notif-item        { border-color: #26262B; }
body.dark-mode .notif-item:hover  { background: #050506; }
body.dark-mode .btn-danger        { background: #7A1F1F; border-color: #7A1F1F; color: #FFD0D0; }
body.dark-mode .btn-danger:hover  { background: #9A2F2F; }
body.dark-mode .tab-btn           { border-color: #26262B; color: #A8A7A2; }
body.dark-mode .tab-btn.active    { background: var(--accent); color: #fff; border-color: var(--accent); }
body.dark-mode .empty             { color: #8A897F; }
body.dark-mode .detail-full,
body.dark-mode .detail-short      { color: #A8A7A2; }
body.dark-mode .step-indicator    { background: #050506; border-color: #26262B; }

/* =============================================================================
   4. SMOOTH TRANSITIONS on theme switch
   ============================================================================= */
body,
.sidebar, .topbar, .card, .stat-card, .card-header,
th, td, input, select, textarea {
  transition: background-color .2s ease, border-color .2s ease, color .2s ease;
}

/* =============================================================================
   5. RESPONSIVE
   Breakpoint aligned with the tablet/mobile tiers in style.ink-signal.css §5
   (was a standalone 700px break; now 767px to match the shared mobile tier).
   ============================================================================= */
@media (max-width: 767px) {
  .topbar            { padding: 0 12px; gap: 10px; }
  .topbar-user-name  { display: none; }
  .topbar-title      { font-size: 12px; }
  .crumb             { font-size: 11px; }
}

/* =============================================================================
   6. BOM drag-and-drop tree editor (PRODUCTION_MODULE_PLAN.md, Fase 3)
   ============================================================================= */
.bom-builder {
  display: grid;
  grid-template-columns: 1.6fr 1fr;
  gap: 20px;
  padding: 20px;
}
@media (max-width: 900px) {
  .bom-builder { grid-template-columns: 1fr; }
}

.bom-panel-label {
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: .04em;
  color: var(--ink-soft);
  margin-bottom: 8px;
}

/* min-width:0 on both: CSS Grid gives grid items an implicit min-width:auto,
   which floors a cell at its content's min-content size (e.g. one long,
   unbreakable item name/number in a search result or tree row) — with
   nothing else claiming a smaller minimum, that alone can force this whole
   .bom-builder grid, and the page around it, wider than the viewport. Every
   .bom-node-row/.bom-search-result fix below (§7) only works once these
   cells are actually allowed to shrink to the viewport in the first place. */
.bom-tree-panel   { border: 1px solid var(--border); border-radius: var(--radius); padding: 12px; min-height: 160px; min-width: 0; }
.bom-tree         { min-height: 40px; }
.bom-tree-empty   { text-align: center; padding: 24px 8px; font-size: 13px; }

.bom-node,
.bom-preview-node {
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
  margin-bottom: 8px;
}
.bom-node.dragging { opacity: .4; }

.bom-node-row {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 10px;
}
.bom-node        { cursor: default; }
.bom-drag-handle { cursor: grab; color: var(--ink-soft); user-select: none; }
.bom-node-toggle {
  border: none; background: none; cursor: pointer; width: 24px; text-align: center;
  color: var(--green); font-size: 19px; padding: 0; line-height: 1;
}
.bom-node-toggle:hover { filter: brightness(1.2); }
.bom-node-toggle-spacer { cursor: default; }
/* Groups drag-handle + toggle + name into one flex item of .bom-node-row,
   so the mobile media query below (§7) can give the whole trio its own
   full-width line without touching the individual pieces. On desktop this
   is invisible — same gap/alignment the three used to get directly from
   .bom-node-row. Not present on .bom-preview-node (read-only, no drag). */
.bom-node-header { display: flex; align-items: center; gap: 8px; min-width: 0; flex: 1 1 auto; }
.bom-node-label  { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.bom-node-uom    { font-size: 12px; width: 44px; flex: 0 0 auto; }
/* Specificity note: style.ink-signal.css has `input[type=number] { width: 100% }`
   (0,0,1,1) — a plain `.bom-node-qty` class rule (0,0,1,0) loses to it, so
   the qty input stretched to fill the whole row (and even overflowed past
   the tree panel into the search panel), crushing the label to 0 width.
   Scoping through the row raises specificity to (0,0,2,1) so this wins. */
.bom-node-row .bom-node-qty { width: 90px !important; flex: 0 0 auto; }
.bom-node-qty-display { font-size: 13px; width: 70px; flex: 0 0 auto; }
.bom-node-cost         { font-size: 13px; width: 80px; flex: 0 0 auto; text-align: right; }
.bom-node-line-cost    { width: 90px; }

/* Mobile-only ▲/▼ reorder controls (see §7 below) — hidden on desktop,
   where reordering is still done by dragging .bom-drag-handle. */
.bom-node-reorder { display: none; gap: 6px; flex: 0 0 auto; }
.bom-node-move-up,
.bom-node-move-down { padding: 2px 8px; font-size: 13px; line-height: 1; }
.bom-node-move-up:disabled,
.bom-node-move-down:disabled { opacity: .35; cursor: default; }

/* Multi-level tree connector guides — used both by the drag-and-drop
   editor's read-only sub-assembly preview and by boms/show.php's full BOM
   structure viewer, so both places render the same "branching" look. */
.bom-node-children {
  display: none;
  margin-left: 20px;
  padding-left: 14px;
  border-left: 1px dashed var(--border);
}
.bom-node-children.open { display: block; }
.bom-node-children-empty { font-size: 12px; padding: 6px 0; }
.bom-node-children > .bom-node,
.bom-node-children > .bom-preview-node { position: relative; }
.bom-node-children > .bom-node::before,
.bom-node-children > .bom-preview-node::before {
  content: '';
  position: absolute;
  left: -14px;
  top: 18px;
  width: 14px;
  border-top: 1px dashed var(--border);
}

.bom-tree-view       { padding: 4px 0; }
.bom-tree-header-row {
  display: flex; align-items: center; gap: 8px;
  padding: 0 10px 6px; font-size: 11px; text-transform: uppercase; letter-spacing: .02em;
}
.bom-tree-root-row {
  display: flex; align-items: baseline; gap: 6px;
  font-weight: 600; padding-bottom: 10px; margin-bottom: 4px;
  border-bottom: 1px solid var(--border);
}
.bom-tree-total-row  { border-top: 1px solid var(--border); margin-top: 6px; padding-top: 10px; }

.bom-preview-node .bom-node-row { padding: 6px 8px; }
.bom-preview-node { background: var(--paper); }

.bom-search-panel     { border: 1px solid var(--border); border-radius: var(--radius); padding: 12px; min-width: 0; }
.bom-search-results   { margin-top: 10px; max-height: 360px; overflow-y: auto; }
.bom-search-empty     { font-size: 13px; padding: 8px 0; }

.bom-search-result {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  margin-bottom: 6px;
  cursor: grab;
  background: var(--surface);
}
.bom-search-result .bom-node-label { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 13px; }

/* Legacy Fase 2 typeahead dropdown (still used for the header "Item to
   Produce" field via BomPicker) */
.bom-picker-cell    { position: relative; }
.bom-picker-list    {
  display: none;
  position: absolute;
  z-index: 20;
  top: 100%;
  left: 0;
  right: 0;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-lg);
  max-height: 260px;
  overflow-y: auto;
}
.bom-picker-option  { padding: 8px 10px; cursor: pointer; font-size: 13px; }
.bom-picker-option:hover { background: var(--paper); }

body.dark-mode .bom-node,
body.dark-mode .bom-preview-node,
body.dark-mode .bom-search-result,
body.dark-mode .bom-tree-panel,
body.dark-mode .bom-search-panel { background: #101013; border-color: #26262B; }
body.dark-mode .bom-preview-node { background: #050506; }
body.dark-mode .bom-node-children { border-color: #26262B; }
body.dark-mode .bom-node-children > .bom-node::before,
body.dark-mode .bom-node-children > .bom-preview-node::before { border-color: #26262B; }
body.dark-mode .bom-tree-root-row { border-color: #26262B; }
body.dark-mode .bom-picker-list  { background: #101013; border-color: #26262B; }
body.dark-mode .bom-picker-option:hover { background: #050506; }

/* =============================================================================
   7. BOM tree — sub-assembly depth shading
   Requested: with several sub-assemblies nested inside each other (see
   boms/show.php's read-only structure viewer), every .bom-preview-node used
   the same flat background regardless of depth, making it hard to tell
   where one sub-assembly's components end and its parent's resume.
   Alternates between --paper and --surface-elev (existing tokens — both are
   custom properties, so this adapts to dark mode automatically, unlike the
   body.dark-mode override above which this section deliberately comes after
   so it wins any specificity tie at depth 2). Cycles rather than defining
   unlimited levels: a BOM nested deeper than this just repeats the pattern,
   which still reads as "a new level" without an ever-growing selector list.
   Placed after §6 rather than inline with §8 below because it applies at
   every width, not just mobile — a desktop view benefits from it too.
   ============================================================================= */
.bom-node-children .bom-preview-node { background: var(--surface-elev); }
.bom-node-children .bom-node-children .bom-preview-node { background: var(--paper); }
.bom-node-children .bom-node-children .bom-node-children .bom-preview-node { background: var(--surface-elev); }

/* =============================================================================
   8. BOM drag-and-drop tree editor — mobile layout
   Reported: the "+" add button (and the remove/reorder controls on
   existing lines) end up outside the visible viewport on phone widths,
   and native drag-and-drop doesn't work at all via touch.

   Root cause of the first bug: neither .bom-node-row nor .bom-search-result
   wrap, and several of their children (the qty input, the UOM/location
   selects) are fixed or auto width with flex-shrink:0 — only the label
   can shrink. Their combined width alone exceeds a phone viewport, and
   since nothing up the tree sets overflow-x:hidden, that pushes the whole
   page right instead of scrolling a contained box, hiding controls.
   Fix: stack each row's fields one per line below 767px — same approach
   style.ink-signal.css's .line-items-table already uses for PO/Invoice
   line items, just adapted from <table><td> to these <div> rows.

   Root cause of the second bug: HTML5 native drag-and-drop
   (draggable="true" + dragstart/dragover/drop) is mouse-only — there is
   no touch equivalent in any browser without a JS polyfill, so dragging
   .bom-drag-handle silently does nothing on a phone. Fix: .bom-node-reorder
   (▲/▼ buttons — see bom-editor.js's updateReorderButtons()/click
   delegation) replaces the drag gesture on mobile; desktop keeps drag only,
   .bom-node-reorder stays display:none there (see rule above, §6).
   ============================================================================= */
@media (max-width: 767px) {
  .bom-node-row { flex-wrap: wrap; row-gap: 8px; }
  .bom-node-header,
  .bom-node-uom {
    flex: 1 1 100% !important;
    width: auto !important;
  }
  /* Selects need an explicit width, not just flex-basis: both carry their
     own inline style="width:auto;flex:0 0 auto" (see buildUomHtml()/
     buildNode() and edit.php), and relying on flex-basis alone to stretch
     a <select> is inconsistent across mobile browsers — force it. */
  .bom-node-uom-select,
  .bom-node-location-select {
    flex: 1 1 100% !important;
    width: 100% !important;
    /* Item 3.19, UX_IMPROVEMENT_PLAN.md — full-width didn't fix the actual
       problem: both still carry the desktop inline style="font-size:12px;
       padding:2px 4px", so even stretched edge-to-edge they were only ~20px
       tall — well under the ~44px touch-target guideline. !important is
       required here for the same reason as flex/width above: an inline
       style always outranks a class rule otherwise. */
    font-size: 14px !important;
    padding: 8px 10px !important;
    min-height: 40px !important;
  }
  .bom-node-row .bom-node-qty { flex: 1 1 100% !important; width: 100% !important; }

  /* Remove (×) and the reorder div are the only two items left on the
     final wrapped line — space them to opposite ends instead of letting
     the browser's default flex-start packing leave remove-button-shaped
     stray space next to reorder, or (worse) stretching it into an
     odd-looking near-empty bar if something upstream forces it to grow. */
  .bom-node-row { justify-content: space-between; }
  .bom-node-remove { flex: 0 0 auto; }

  /* The handle implies a gesture that doesn't work on touch (see above) —
     hiding it avoids advertising an interaction the buttons now replace.
     Toggle (expand sub-assembly) stays — that's a plain click, unaffected. */
  .bom-node-header .bom-drag-handle { display: none; }

  .bom-node-reorder { display: flex; }
  .bom-node-move-up,
  .bom-node-move-down { min-width: 44px; min-height: 36px; }

  /* .bom-search-result has the same overflow risk as .bom-node-row above,
     just with fewer fields — wrap instead of forcing one non-shrinking
     row, and never let the "+" button itself shrink below a tappable size. */
  .bom-search-result { flex-wrap: wrap; }
  .bom-search-add { flex-shrink: 0; min-width: 44px; min-height: 36px; }
  #bomSearchResults { overflow-x: hidden; }

  /* Put "Find components" ahead of the (possibly empty) tree panel, so
     the add-item panel isn't buried below an empty box on a new BOM. */
  .bom-search-panel { order: -1; margin-bottom: 16px; }

  /* Nested sub-assemblies (boms/show.php) eat into an already-narrow phone
     width fast at the desktop indent (20px margin + 14px padding per
     level — 3-4 levels deep already costs 100px+). Desktop keeps the wider
     indent; §7's background shading now carries most of the "which level
     is this" signal on mobile, so a slimmer indent still reads clearly. */
  .bom-node-children { margin-left: 5px; padding-left: 5px; }
  /* The connector tick (§6) spans the padding-left gap it sits in (was
     14px to match the desktop 14px padding) — without this it would
     overshoot past the new, much narrower 5px gap above. */
  .bom-node-children > .bom-node::before,
  .bom-node-children > .bom-preview-node::before {
    left: -5px;
    width: 5px;
  }

  /* Let the item name/description wrap instead of truncating with an
     ellipsis (reported: "60-.750-48 — GLASS; PAU EMBOSSE…" never shows the
     rest). Each field already gets its own full-width line on mobile, so
     there's vertical room — a smaller font wouldn't reliably fit a long
     name either, and would hurt legibility/tap targets for no guarantee.
     Unscoped (not just .bom-node-header .bom-node-label): .bom-node-label
     is also used directly under .bom-node-row with no header wrapper by
     .bom-preview-node (the read-only rows boms/show.php's tree view and
     the editor's own "expand sub-assembly" preview both render — see
     buildPreviewNode() in bom-editor.js and boms/show.php's $renderNodes),
     so the same fix needs to reach both shapes.
     Handle is hidden on mobile already (see rule above); toggle + label
     align to the top of the now possibly multi-line label instead of the
     desktop align-items:center, which would otherwise float that small
     toggle icon in the vertical middle of 2-3 wrapped lines — applied to
     .bom-node-row directly so it also covers rows with no header wrapper. */
  .bom-node-row,
  .bom-node-header { align-items: flex-start; }
  .bom-node-label {
    white-space: normal;
    overflow: visible;
    text-overflow: clip;
    word-break: break-word;
  }
}
