/*
 * Enterprise handheld skin for TC-class rugged devices.
 *
 * THE ONE RULE: every selector in this file is scoped under
 * [data-device="handheld"]. Nothing here can reach a phone or a desktop, so
 * the iPhone UI that the warehouse runs today cannot regress no matter what
 * gets added below. `tests/test_handheld_css_scope.py` enforces it.
 *
 * What a TC is, and why the base stylesheet does not fit it:
 *
 *   360x640 CSS px    Narrower AND much shorter than the 390x844 iPhone the
 *                     base styles assume. .image-grid's minmax(220px,1fr)
 *                     collapses to a single column; .loc-card's 64px 96px 1fr
 *                     overflows; the 7-link admin topbar wraps to four rows
 *                     and eats a fifth of the screen.
 *   Gloves            40px buttons are a miss. 48px is the floor, 56px for
 *                     anything on the critical path.
 *   Sunlight          --muted #8892b8 on --panel #181c2e is ~3.1:1. Fine in
 *                     an office, unreadable at a dock door at noon.
 *   Physical trigger  The primary action is scanning, not tapping -- so the
 *                     tap targets that remain must be exactly where a thumb
 *                     already is, which is the bottom of the screen.
 */

/* --- tokens ---------------------------------------------------------- */

[data-device="handheld"] {
  /* Lifted for sunlight legibility. Same hues, more luminance, so the app
     still looks like itself next to a phone running the normal skin. */
  --fg: #f4f7ff;
  --muted: #a9b3d6;
  --border: #3a4270;
  --accent: #7db4ff;

  --tap: 48px;        /* floor for any interactive element */
  --tap-primary: 56px; /* critical-path actions */
  /* Pinned action bar, computed not guessed: 2px border + 6px + 48px button
     + 6px = 62px. It only stays true because .hh-bar buttons are nowrap and
     fixed-height below -- a wrapped label silently makes the bar taller than
     the space `main` reserves, and then it covers the end of the page. */
  --bar-h: 62px;
}

[data-device="handheld"] body {
  font-size: 17px;
  line-height: 1.4;
}

/* --- topbar: one row, nav behind a menu ------------------------------ */
/* Seven admin links wrap to four lines at 360px. Collapsing them reclaims
   roughly a fifth of the viewport on every single page. */

[data-device="handheld"] .topbar {
  padding: 0 12px;
  min-height: 52px;
  gap: 8px;
  flex-wrap: nowrap;
}
[data-device="handheld"] .brand { font-size: 17px; }
[data-device="handheld"] .who {
  font-size: 13px;
  margin-left: auto;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 40%;
}
[data-device="handheld"] .topnav { margin-left: 0; }

/* The collapse is armed by the `is-ready` class, which base.html's script adds
   only on handhelds. Without JS the wrapper stays display:contents and the nav
   just wraps, so navigation is never unreachable. */
[data-device="handheld"] .hh-menu.is-ready {
  display: block;
  position: relative;
  margin-left: auto;
}
[data-device="handheld"] .hh-menu.is-ready > .hh-menu-toggle {
  display: flex;
  align-items: center;
  justify-content: center;
  min-width: var(--tap);
  min-height: var(--tap);
  padding: 0;
  font-size: 24px;
  line-height: 1;
  color: var(--fg);
  background: none;
  border: 0;
}
/* Collapsed by default; `data-open` is toggled by the button. */
[data-device="handheld"] .hh-menu.is-ready > .topnav { display: none; }
[data-device="handheld"] .hh-menu.is-ready[data-open] > .topnav {
  display: flex;
  position: absolute;
  right: 0;
  top: calc(100% + 6px);
  z-index: 40;
  flex-direction: column;
  align-items: stretch;
  gap: 0;
  min-width: 220px;
  background: var(--panel-2);
  border: 1px solid var(--border);
  border-radius: 10px;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.55);
  padding: 6px;
}
[data-device="handheld"] .hh-menu.is-ready[data-open] > .topnav a,
[data-device="handheld"] .hh-menu.is-ready[data-open] > .topnav .linklike {
  display: flex;
  align-items: center;
  min-height: var(--tap);
  padding: 0 12px;
  font-size: 16px;
  color: var(--fg);
  border-radius: 8px;
  width: 100%;
  text-align: left;
}

/* --- layout ---------------------------------------------------------- */

[data-device="handheld"] main {
  padding: 10px;
  /* Room for the pinned action bar so the last row is never trapped under it.
     Reserved unconditionally rather than via :has(.hh-bar) -- a TC77 on its
     factory Android 9 image can still be on Chrome 83, which predates :has().
     The cost on a page with no bar is ~80px of extra scroll at the bottom. */
  padding-bottom: calc(var(--bar-h) + env(safe-area-inset-bottom, 0px) + 20px);
}
[data-device="handheld"] .card {
  padding: 12px;
  margin-bottom: 12px;
  border-radius: 10px;
}
[data-device="handheld"] .card.narrow { max-width: none; }
[data-device="handheld"] h1 { font-size: 20px; }
[data-device="handheld"] h2 { font-size: 18px; margin: 14px 0 8px; }

/* --- controls -------------------------------------------------------- */

[data-device="handheld"] button,
[data-device="handheld"] .primary,
[data-device="handheld"] .secondary,
[data-device="handheld"] .danger {
  min-height: var(--tap);
  padding: 12px 18px;
  font-size: 17px;
  border-radius: 10px;
  border-width: 2px;
}
[data-device="handheld"] button.primary,
[data-device="handheld"] a.primary {
  min-height: var(--tap-primary);
  font-weight: 700;
}
[data-device="handheld"] form input,
[data-device="handheld"] form textarea,
[data-device="handheld"] form select {
  min-height: var(--tap);
  font-size: 17px;
  padding: 12px 14px;
  border-width: 2px;
}
[data-device="handheld"] form label {
  font-size: 15px;
  color: var(--muted);
  margin: 12px 0;
}

/* Condition radios are the most-tapped control in the whole flow. Full-width
   rows beat inline chips: no mis-taps with gloves, and the hit area is the
   whole row rather than a 16px dot. */
[data-device="handheld"] .radio {
  display: flex;
  align-items: center;
  gap: 12px;
  min-height: var(--tap-primary);
  margin: 8px 0;
  padding: 0 14px;
  border: 2px solid var(--border);
  border-radius: 10px;
  background: var(--panel-2);
  font-size: 17px;
}
/* Enhancement only. On an older Chrome without :has() the row simply does not
   highlight -- the 24px native radio dot below still shows the selection, so
   nothing becomes ambiguous. styles.css already relies on :has() the same way
   for .variant-option. */
[data-device="handheld"] .radio:has(input:checked) {
  border-color: var(--accent);
  background: rgba(125, 180, 255, 0.12);
}
[data-device="handheld"] .radio input { width: 24px; height: 24px; }

/* --- sticky bottom action bar ---------------------------------------- */
/* The single biggest usability win. On /tag/verify the "Correct -- continue"
   button sits below the image grid, the description and the variant picker;
   at 640px tall that is three screens down. Pinning it means the primary
   action is always under the thumb. */

/* OPT-IN via `.hh-bar`, never bare `.actions`. Admin pages carry several
   .actions rows apiece, and pinning all of them would stack four fixed bars in
   the same 68px of screen. Only the one action row that ends a tagger flow
   gets hoisted. */
[data-device="handheld"] .actions.hh-bar {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 30;
  margin: 0;
  gap: 8px;
  flex-wrap: nowrap;
  padding: 6px 10px calc(6px + env(safe-area-inset-bottom, 0px));
  background: var(--panel);
  border-top: 2px solid var(--border);
  box-shadow: 0 -6px 18px rgba(0, 0, 0, 0.45);
}
/* Fixed height and no wrapping. 48px is still the accepted gloved-hand
   minimum; the extra 8px the primary action used to get was not worth 26px of
   a 640px screen, and a wrapping label was worth far less than that. */
[data-device="handheld"] .actions.hh-bar > .primary,
[data-device="handheld"] .actions.hh-bar > .secondary,
[data-device="handheld"] .actions.hh-bar > button {
  min-height: 48px;
  height: 48px;
  padding: 0 12px;
  font-size: 16px;
  line-height: 48px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
[data-device="handheld"] .actions.hh-bar > * { flex: 1 1 0; }
/* The primary action gets the bigger half -- it is what gets tapped 95% of
   the time, and an even split invites mis-taps on "Wrong item -- rescan". */
[data-device="handheld"] .actions.hh-bar > .primary { flex: 2 1 0; }
/* Every other action row stays in the flow, just roomier. */
[data-device="handheld"] .actions { gap: 8px; margin-top: 14px; }

/* --- status strip ---------------------------------------------------- */
/* Location + next lot + retailer, always visible. A tagger who loses track of
   which lot number is next has to guess, and a wrong guess collides in
   tag_items. */

[data-device="handheld"] .scan-head {
  position: sticky;
  top: 52px;
  z-index: 20;
  margin: -10px -10px 10px;
  padding: 10px;
  background: var(--panel);
  border-bottom: 2px solid var(--border);
  gap: 8px;
}
[data-device="handheld"] .scan-head-left { gap: 8px; width: 100%; }
[data-device="handheld"] .scan-head strong { font-size: 19px; }
[data-device="handheld"] .skip-form { display: flex; gap: 6px; align-items: center; }
[data-device="handheld"] .skip-form input { width: 5.5em; }

/* --- grids that break at 360px --------------------------------------- */

[data-device="handheld"] .image-grid {
  grid-template-columns: repeat(2, 1fr);
  gap: 8px;
}
[data-device="handheld"] .variant-grid {
  grid-template-columns: repeat(2, 1fr);
  gap: 8px;
}
[data-device="handheld"] .variant-option {
  min-height: var(--tap-primary);
  padding: 10px;
  border-width: 2px;
}
[data-device="handheld"] .variant-option span { font-size: 15px; }
[data-device="handheld"] .variant-option input[type="radio"] { width: 24px; height: 24px; }
[data-device="handheld"] .row-2 { grid-template-columns: 1fr; }
[data-device="handheld"] .photo-slots { grid-template-columns: repeat(2, 1fr); }

/* .loc-card's 64px 96px 1fr is 160px of fixed columns plus gaps -- the title
   gets ~180px and wraps to five lines. Two rows reads far better. */
[data-device="handheld"] .loc-card {
  grid-template-columns: 56px 1fr;
  gap: 10px;
}
[data-device="handheld"] .loc-card-img { grid-row: span 2; display: none; }
[data-device="handheld"] .loc-card-num strong { font-size: 24px; }
[data-device="handheld"] .loc-scroll { max-height: 45vh; }

/* --- notices --------------------------------------------------------- */

[data-device="handheld"] .notice {
  padding: 12px;
  font-size: 15px;
  align-items: flex-start;
}
[data-device="handheld"] .muted { color: var(--muted); }
[data-device="handheld"] table.data th,
[data-device="handheld"] table.data td { padding: 10px 8px; }

/* --- scanning affordances -------------------------------------------- */

/* The camera viewport is dead weight on a device with a real imager;
   scanner.js already refuses to arm, this makes sure nothing reserves space. */
[data-device="handheld"] #scan-start,
[data-device="handheld"] #scan-wrap { display: none !important; }

/* The scan sink is the focal point of the whole app on a handheld. */
[data-device="handheld"] [data-wedge-sink] {
  font-size: 20px;
  font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
  letter-spacing: 0.02em;
  min-height: var(--tap-primary);
  border-color: var(--accent);
}
[data-device="handheld"] .hh-ready {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 10px 0;
  padding: 12px 14px;
  border: 2px dashed var(--border);
  border-radius: 10px;
  color: var(--muted);
  font-size: 15px;
}
[data-device="handheld"] .hh-ready .hh-dot {
  width: 12px;
  height: 12px;
  border-radius: 50%;
  background: var(--success);
  flex: none;
}

/* --- in-page camera (photocap.js) ------------------------------------ */

[data-device="handheld"] .pc-viewport { aspect-ratio: 3 / 4; }
[data-device="handheld"] .pc-shutter {
  min-height: var(--tap-primary);
  font-size: 18px;
}
[data-device="handheld"] .pc-thumbs img { width: 76px; height: 76px; }

/* --- /tag/verify "scan the next item" sink --------------------------- */
/* This page has no other input, and a STOCK DataWedge profile commits through
   an IME into the focused field -- so without a real, focused field here the
   scan lands nowhere. Visible rather than hidden on purpose: a tagger needs to
   see that the scanner is armed, and a hidden autofocused input reads as a
   bug when the keyboard is suppressed and nothing appears to happen. */
[data-device="handheld"] .hh-nextscan {
  position: sticky;
  top: 52px;
  z-index: 20;
  margin: 0 0 10px;
  padding: 8px 0;
  background: var(--bg);
}
[data-device="handheld"] .hh-nextscan input {
  width: 100%;
  font-size: 18px;
  font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
  min-height: var(--tap-primary);
  border: 2px dashed var(--accent);
  background: var(--panel-2);
}

/* --- collapsed sections ---------------------------------------------- */
/* `<details><summary>Description</summary>` rendered as a bare line of text
   wedged between the image grid and an open variant picker, which is why it
   read as invisible on a 360x640 screen. Give it a real, obviously-tappable
   row with a disclosure caret. */
[data-device="handheld"] details > summary {
  display: flex;
  align-items: center;
  gap: 8px;
  min-height: var(--tap);
  padding: 0 12px;
  margin: 10px 0;
  border: 2px solid var(--border);
  border-radius: 10px;
  background: var(--panel-2);
  color: var(--fg);
  font-size: 16px;
  font-weight: 600;
  cursor: pointer;
  list-style: none;
}
[data-device="handheld"] details > summary::-webkit-details-marker { display: none; }
[data-device="handheld"] details > summary::after {
  content: "BC";
  margin-left: auto;
  font-size: 12px;
  color: var(--muted);
}
[data-device="handheld"] details[open] > summary::after { content: "B2"; }
/* The variant pickers carry their own heading markup inside the summary, so
   keep their nested strong/em from inheriting the row's weight twice. */
[data-device="handheld"] details.variant-pick > summary strong { font-weight: 700; }

/* Quantity stepper: the +/- are tapped with gloves, so they get the primary
   tap target, and the number is read at arm's length. */
[data-device="handheld"] .qty .qty-step {
  min-width: var(--tap-primary);
  min-height: var(--tap-primary);
  font-size: 26px;
}
[data-device="handheld"] .qty input { font-size: 22px; width: 4em; }
