/* ----------------------------------------------------------------------
   DESIGN SYSTEM
   A single, deliberately "precision instrument" palette - deep steel
   blue + ink neutrals, the same family the app already used, refined
   for more contrast and consistency - plus a real type scale (Inter)
   and an elevation/spacing scale, so the whole app (40+ page templates)
   reads as one coherent, professional tool instead of a collection of
   individually-patched screens. Every existing selector below this
   block is untouched in structure - only values here, and a handful of
   new global rules (headings, tables, buttons, focus states) that fill
   in gaps the app never had shared styling for.
   ---------------------------------------------------------------------- */
:root {
  --color-bg: #eef1f5;
  --color-surface: #ffffff;
  --color-surface-sunken: #f6f8fa;
  --color-border: #dde2e9;
  --color-border-strong: #c4ccd6;
  --color-text: #182230;
  --color-text-muted: #5b6b7c;
  /* Per your explicit request ("match the blue to our logo", then
     "doesnt look the same") - re-sampled against the rendered logo
     side by side: #3399cc is the shade that actually matches the
     "NEW ENGLAND" wordmark's brightness/saturation as it reads on
     screen (the darker #0066cc pixels sampled first turned out to be
     the gradient's shadow side, not its true color). */
  --color-primary: #3399cc;
  --color-primary-dark: #1f6f99;
  --color-primary-light: #eaf5fb;
  --color-danger: #b3261e;
  --color-danger-light: #fbe9e7;
  --color-success: #1e7d43;
  --color-success-light: #e3f5e9;
  --color-warning: #8a5b00;
  --color-warning-light: #fff4dd;
  /* A second accent family - teal - purely for a bit of life: the
     colorful top stripe on every card, the second home-tile group,
     active tabs/nav. Never used for status meaning (that's still
     danger/success/warning above), so it adds color without adding
     ambiguity about what anything means. */
  --color-teal: #0e8f82;
  --color-teal-dark: #0a6a60;
  --color-teal-light: #e3f5f3;
  --color-amber: #c7820a;
  --color-amber-light: #fdf1dd;
  --radius: 8px;
  --radius-lg: 12px;
  --radius-sm: 6px;
  --shadow: 0 1px 3px rgba(16, 32, 52, 0.08), 0 1px 2px rgba(16, 32, 52, 0.06);
  --shadow-md: 0 4px 12px rgba(16, 32, 52, 0.1), 0 1px 3px rgba(16, 32, 52, 0.06);
  --shadow-lg: 0 10px 28px rgba(16, 32, 52, 0.14), 0 2px 6px rgba(16, 32, 52, 0.08);
  /* .topbar's own rendered height (12px padding top/bottom + its
     34px logo) - used to offset .calibration-page-header-sticky below
     it instead of overlapping it. */
  --topbar-height: 58px;
  --font-sans: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
}

* { box-sizing: border-box; }

/* ---------------- GLOBAL TYPOGRAPHY ----------------
   The app has never had shared heading styles - every "<h4>Section
   Name</h4>" at the top of a .card (there are hundreds, across every
   page) rendered in plain, loose browser-default bold text. This is
   the single highest-leverage change in this pass: a consistent
   section-header treatment, applied once here, immediately gives every
   page in the app the same clear visual rhythm (title -> thin rule ->
   content) with no per-page changes needed. */
h1, h2, h3, h4, h5, h6 {
  font-family: var(--font-sans);
  color: var(--color-text);
  font-weight: 700;
  line-height: 1.25;
}

.card > h3,
.card > h4,
.customer-card-body > h4,
.model-card-body > h4,
.manufacturer-card-body > h4 {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 0 0 16px;
  padding-bottom: 10px;
  border-bottom: 1px solid var(--color-border);
  font-size: 15px;
  letter-spacing: 0.01em;
}

/* A little color before every section title - a small dot in the
   card's own accent color, not a status indicator, just a bit of life
   at the start of every single section header in the app. */
.card > h3::before,
.card > h4::before,
.customer-card-body > h4::before,
.model-card-body > h4::before,
.manufacturer-card-body > h4::before {
  content: "";
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: linear-gradient(135deg, var(--color-teal), var(--color-primary));
  flex-shrink: 0;
}

/* A card section header that's paired with controls on the same line
   (e.g. .instruments-section-header h4) already manages its own
   margin/border via that wrapper - don't double up on this one. */
.instruments-section-header h4,
.location-slot-heading-row h4,
.vendor-slot-heading-row h5,
.contact-heading-row h5,
.location-fields h5 {
  padding-bottom: 0;
  border-bottom: none;
}

/* Visible keyboard-navigation outline, app-wide - a professional tool
   used daily by a whole team should never leave keyboard focus
   invisible, and nothing in the app set this before. */
:focus-visible {
  outline: 2px solid var(--color-primary);
  outline-offset: 2px;
}

/* Belt-and-suspenders: guarantee the HTML "hidden" attribute always
   wins, even on an element (like .login-screen below) that also sets
   its own "display" property. Without this, a same-specificity clash
   between an author rule's "display" and the browser's built-in
   "[hidden] { display: none }" rule can leave a "hidden" element
   visible on screen even though JavaScript correctly set it hidden. */
[hidden] {
  display: none !important;
}

body {
  margin: 0;
  font-family: var(--font-sans);
  background: var(--color-bg);
  color: var(--color-text);
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

/* ---------------- LOGIN ---------------- */

.login-screen {
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 16px;
  /* A quiet, deliberate backdrop instead of the same flat --color-bg
     every other page sits on - this is the one screen in the app
     where there's nothing else on the page to carry visual weight. */
  background: radial-gradient(circle at 50% -10%, #1d4e8914 0%, transparent 55%), var(--color-bg);
}

.login-card {
  position: relative;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  padding: 40px;
  width: 100%;
  max-width: 380px;
  text-align: center;
}

/* Covers the login card from the moment "Log In" is clicked until the
   6-digit code screen (or an error) shows up - the credential check
   and emailing the code both take a moment, and without this it just
   looks like nothing happened. */
.login-wait-overlay {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 14px;
  background: var(--color-surface);
  border-radius: var(--radius);
}

.login-wait-overlay p {
  margin: 0;
  font-size: 14px;
  color: var(--color-text-muted);
}

.spinner {
  width: 32px;
  height: 32px;
  border: 3px solid var(--color-border);
  border-top-color: var(--color-primary);
  border-radius: 50%;
  animation: spin 0.8s linear infinite;
}

@keyframes spin {
  to { transform: rotate(360deg); }
}

.login-logo {
  display: block;
  height: 56px;
  width: auto;
  max-width: 100%;
  margin: 0 auto 20px;
}

.login-card h1 {
  font-size: 22px;
  margin: 0 0 4px;
  color: var(--color-primary-dark);
}

.login-card .subtitle {
  margin: 0 0 24px;
  color: var(--color-text-muted);
  font-size: 14px;
}

.login-card form {
  display: flex;
  flex-direction: column;
  text-align: left;
}

.login-card label {
  font-size: 13px;
  font-weight: 600;
  margin: 12px 0 4px;
  color: var(--color-text-muted);
}

.login-card input {
  padding: 10px 12px;
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  font-size: 14px;
  font-family: inherit;
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
}

.login-card input:focus {
  outline: none;
  border-color: var(--color-primary);
  box-shadow: 0 0 0 3px var(--color-primary-light);
}

.login-card button {
  margin-top: 20px;
}

.login-code-actions {
  display: flex;
  gap: 10px;
  margin-top: 10px;
}

.login-code-actions button {
  margin-top: 0;
  flex: 1;
}

/* ---------------- TOP BAR ---------------- */

.topbar {
  display: flex;
  align-items: center;
  gap: 24px;
  background: var(--color-surface);
  border-bottom: 1px solid var(--color-border);
  box-shadow: 0 1px 2px rgba(16, 32, 52, 0.04);
  padding: 12px 24px;
  position: sticky;
  top: 0;
  z-index: 40;
}

.topbar-logo {
  height: 34px;
  width: auto;
  /* The gap between it and "Calibration Management" is already
     handled by .topbar's own gap above, so no separate margin here. */
}

.topbar-title {
  font-weight: 700;
  font-size: 15px;
  letter-spacing: 0.005em;
  color: var(--color-primary-dark);
  white-space: nowrap;
}

.topbar-nav {
  display: flex;
  gap: 4px;
  flex: 1;
}

.topbar-nav a {
  padding: 7px 12px;
  border-radius: var(--radius-sm);
  text-decoration: none;
  color: var(--color-text-muted);
  font-size: 14px;
  font-weight: 500;
  cursor: pointer;
  transition: background 0.12s ease, color 0.12s ease;
}

.topbar-nav a.active,
.topbar-nav a:hover {
  background: var(--color-primary-light);
  color: var(--color-primary-dark);
}

.topbar-nav a.active {
  font-weight: 600;
}

/* Topbar "Calibration Work" / "Requests & Admin" dropdowns - condenses
   the nav into the same two categories the Home page already uses.
   See navDropdown() in app.js. */
.nav-dropdown {
  position: relative;
}

.nav-dropdown-toggle {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 7px 12px;
  border: none;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--color-text-muted);
  font-size: 14px;
  font-weight: 500;
  font-family: inherit;
  cursor: pointer;
  transition: background 0.12s ease, color 0.12s ease;
}

.nav-dropdown-toggle:hover {
  background: var(--color-primary-light);
  color: var(--color-primary-dark);
}

/* The topbar's last dropdown is always "Requests & Admin" (see
   navDropdown() in app.js) - grey to match that same group's color on
   the Home page, so the category cue carries through the nav too. */
.nav-dropdown:last-child .nav-dropdown-toggle:hover {
  background: var(--color-surface-sunken);
  color: var(--color-text);
}

.nav-dropdown-caret {
  font-size: 10px;
}

.nav-dropdown-menu {
  position: absolute;
  top: calc(100% + 4px);
  left: 0;
  z-index: 30;
  display: flex;
  flex-direction: column;
  min-width: 220px;
  padding: 6px;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-md);
}

.nav-dropdown-menu a {
  padding: 8px 10px;
  border-radius: var(--radius-sm);
  text-decoration: none;
  color: var(--color-text);
  font-size: 14px;
  cursor: pointer;
  white-space: nowrap;
  transition: background 0.12s ease, color 0.12s ease;
}

.nav-dropdown-menu a:hover {
  background: var(--color-primary-light);
  color: var(--color-primary-dark);
}

.topbar-user {
  display: flex;
  align-items: center;
  gap: 12px;
  font-size: 14px;
  color: var(--color-text-muted);
  white-space: nowrap;
}

/* ---------------- CONTENT ---------------- */

.content {
  padding: 24px;
  max-width: 1100px;
  margin: 0 auto;
}

/* A handful of pages (Access Control, Change Requests, Audit Log)
   hold a table with more columns than the normal 1100px content
   width can show at once, forcing horizontal scroll even on a big
   monitor that has the room to show every column. Their outer .page
   carries .page-wide, which widens .content just for that page (via
   :has(), so no JS is needed to toggle it) up to 1700px - still
   capped, and still centered with margin: 0 auto, so it doesn't
   stretch edge-to-edge on an ultra-wide screen, but wide enough that
   the table's own overflow-x: auto (see .card) only kicks in when the
   window itself is genuinely too narrow for it. */
.content:has(.page-wide) {
  max-width: 1700px;
}

.page-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 20px;
  gap: 16px;
  flex-wrap: wrap;
}

.page-header h2 {
  margin: 0;
  font-size: 21px;
  letter-spacing: -0.01em;
}

.page-header-actions {
  display: flex;
  align-items: flex-end;
  gap: 12px;
}

/* Per your explicit request ("in the cert I need a back to gage
   button") - keeps a cert's header (title/status/Back to Gage button)
   pinned right below the top bar as you scroll through its steps,
   instead of only being reachable by scrolling all the way back up.
   Scoped to just the two calibration page templates (not every
   .page-header app-wide) - see tpl-calibration-page and
   tpl-optical-calibration-page in index.html. */
.calibration-page-header-sticky {
  position: sticky;
  top: var(--topbar-height);
  z-index: 30;
  background: var(--color-bg);
  padding: 12px 0;
  margin: -12px 0 8px;
}

/* Stacks "+ New Calibration" directly above "Resume Draft" (per your
   explicit request - "a button under create cert") instead of the two
   sitting side by side like the rest of .page-header-actions. */
.instrument-page-cert-btn-stack {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

/* ---------------- HOME PAGE ---------------- */

/* A colored banner up top so the Home page doesn't open on a bare
   white page before you've even reached the tiles - per your request
   that the whole page look more "appealing" for everyone, not just
   functional. */
.home-welcome {
  /* Per your explicit request ("darker left light right") - dark
     primary at the start (top-left), lighter primary at the end
     (bottom-right), same direction as every other gradient in the app
     now. */
  background: linear-gradient(135deg, var(--color-primary-dark) 0%, var(--color-primary) 100%);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-md);
  padding: 28px 32px;
  margin-bottom: 28px;
  color: #ffffff;
}

.home-welcome h2 {
  margin: 0 0 6px;
  font-size: 24px;
  color: #ffffff;
  letter-spacing: -0.01em;
}

.home-welcome-subtitle {
  margin: 0;
  font-size: 14px;
  color: rgba(255, 255, 255, 0.85);
}

/* Groups the tiles below into "Calibration Work" (Customers, adding a
   customer's gage, Model Catalog, NEP Equipment) and "Requests &
   Administration" (everything else) - per your explicit request to
   separate day-to-day work from admin/request tools. */
.home-section-title {
  margin: 0 0 12px;
  padding-bottom: 8px;
  border-bottom: 1px solid var(--color-border);
  font-size: 13px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--color-primary-dark);
}

/* Per your follow-up request ("gives visual queues on category
   separation") - each group's own eyebrow title and tile titles pick
   up that group's own accent color, not just the left bar, so the two
   categories read as different at a glance even scrolled past the
   section edges. */
.home-section-slate .home-section-title {
  color: var(--color-text-muted);
}

/* Per your follow-up request: the three groups ("Calibrations", "Cert
   Prep", "Requests & Administration") now sit in their own lightly
   tinted panel, so they read as visually distinct groups instead of
   one long unbroken run of identical tiles - while the tiles inside
   each panel keep the same size/spacing/density as before. Each
   panel's left accent bar and tint match that group's own tile accent
   color (blue for the first two, slate for the third) so the panel,
   its heading, and its tiles all visibly belong together. */
.home-section {
  /* A faint tint of the section's own accent color - distinct from
     both the page's plain background and the white tiles inside it,
     without competing with them for attention. */
  background: rgba(51, 153, 204, 0.06);
  border: 1px solid var(--color-border);
  border-left: 4px solid var(--color-primary);
  border-radius: var(--radius);
  padding: 20px 24px 24px;
  margin-bottom: 24px;
}

.home-section:last-child {
  margin-bottom: 0;
}

/* Per your follow-up request ("color helps separate the monotony",
   then "I also dont like the yellow", then "maybe grey and have the
   others a more distinctive blue") - "Requests & Administration" is
   back to a plain neutral grey, and the other two groups (still blue)
   now stand out more since --color-primary itself is a brighter,
   more saturated blue - so the contrast between the two categories
   comes from "color vs. no color" rather than two competing hues. */
.home-section-slate {
  background: var(--color-surface-sunken);
  border-left-color: var(--color-text-muted);
}

.home-tiles {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: 16px;
}

.home-tile {
  position: relative;
  overflow: hidden;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 20px 20px 20px 26px;
  text-align: left;
  cursor: pointer;
  display: flex;
  flex-direction: column;
  gap: 6px;
  transition: transform 0.15s ease, box-shadow 0.15s ease, border-color 0.15s ease;
}

/* A thin colored accent bar down the left edge of every tile - blue
   for the everyday "Calibration Work" group, slate for "Requests &
   Administration" - so the two groups still read as distinct even
   when tiles wrap onto the same visual row on a wide screen. */
.home-tile::before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  bottom: 0;
  width: 4px;
  background: var(--color-primary);
}

.home-tile-accent-slate::before {
  background: var(--color-text-muted);
}

.home-tile:hover {
  border-color: var(--color-primary);
  transform: translateY(-2px);
  box-shadow: var(--shadow-md);
}

.home-tile-accent-slate:hover {
  border-color: var(--color-text-muted);
}

.home-tile-icon {
  font-size: 26px;
  line-height: 1;
}

.home-tile-title {
  font-size: 16px;
  font-weight: 700;
  color: var(--color-primary-dark);
}

.home-tile-accent-slate .home-tile-title {
  color: var(--color-text);
}

.home-tile-subtitle {
  font-size: 13px;
  color: var(--color-text-muted);
}

.unsaved-label {
  font-size: 13px;
  font-weight: 600;
  color: var(--color-danger);
}

.card {
  /* A thin blue-to-teal stripe across the top of every single card in
     the app - purely decorative (no status meaning), but it breaks up
     the monotony of dozens of identical white boxes stacked down each
     page and ties every section back to the same two accent colors.
     Layered as a second background (not a border) so it still clips
     cleanly to the card's own rounded corners. */
  background: linear-gradient(90deg, var(--color-teal), var(--color-primary)) top left / 100% 4px no-repeat,
    var(--color-surface) top left / 100% 100% no-repeat;
  border: 1px solid var(--color-border);
  /* Per your follow-up request ("highlighted borders for the
     sections") - a solid colored left edge on every card, the same
     language the Home page's own section panels already use, so a
     section's boundary is unmistakable at a glance on every page, not
     just Home. */
  border-left: 4px solid var(--color-primary);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow);
  padding: 26px 24px 22px 22px;
  margin-bottom: 20px;
  overflow-x: auto;
}

/* ---------------- BUTTONS ---------------- */

.btn {
  border: none;
  border-radius: var(--radius-sm);
  padding: 7px 14px;
  font-size: 13px;
  font-weight: 600;
  font-family: inherit;
  cursor: pointer;
  transition: background 0.12s ease, border-color 0.12s ease, box-shadow 0.12s ease, transform 0.05s ease;
}

.btn:active {
  transform: translateY(1px);
}

.btn-full {
  width: 100%;
  display: block;
}

.btn-primary {
  background: var(--color-primary);
  color: white;
  box-shadow: 0 1px 2px rgba(16, 32, 52, 0.12);
}
.btn-primary:hover { background: var(--color-primary-dark); }

.btn-secondary {
  background: var(--color-surface);
  color: var(--color-text);
  border: 1px solid var(--color-border);
}
.btn-secondary:hover {
  background: var(--color-primary-light);
  border-color: var(--color-primary);
  color: var(--color-primary-dark);
}

.btn-small {
  padding: 4px 9px;
  font-size: 11px;
}

.btn-danger-text {
  color: var(--color-danger);
}
.btn-danger-text:hover {
  background: var(--color-danger-light) !important;
  border-color: var(--color-danger) !important;
  color: var(--color-danger) !important;
}

.btn:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

/* ---------------- FORMS ---------------- */

.form-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 14px;
}

.form-grid label {
  display: flex;
  flex-direction: column;
  font-size: 13px;
  font-weight: 600;
  color: var(--color-text-muted);
  gap: 4px;
}

/* The Calibration page's Procedure field is the ONLY item in its own
   .form-grid, so the normal auto-fit column rule stretches it (and
   its "View PDF" button) across the whole card. Per your explicit
   request, pin it to a small, fixed-width column instead of letting
   it span the full row. */
.calibration-page-gage-defaults-grid {
  grid-template-columns: minmax(160px, 260px);
}

/* Per your explicit request ("lets make a clause with fill in
   sections") - the Optical Comparator Uncertainty section (both on
   the calibration page and the model's own Uncertainty Defaults)
   reads as one sentence with small inline blanks for the uncertainty
   value/coverage factor/confidence level, instead of three separate
   labeled fields in a grid. Flex-wrap so it still reads sensibly at
   phone width, with the blanks sized to their typical content rather
   than stretching full width like a normal form-grid input. */
.uncertainty-clause {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 4px;
  line-height: 1.8;
}

.uncertainty-clause input {
  display: inline-block;
  width: auto;
}

.uncertainty-clause .uncertainty-clause-value {
  min-width: 90px;
  max-width: 160px;
}

.uncertainty-clause .uncertainty-clause-k,
.uncertainty-clause .uncertainty-clause-confidence {
  min-width: 48px;
  max-width: 70px;
  text-align: center;
}

/* Per your explicit request ("this should be locked for all areas to
   edit exept the model") - the read-only version of the clause above,
   on the Optical Comparator calibration page. Plain flowing text (no
   input boxes, no brackets/parentheses - see the "carried though
   without the brackets"/"aand paranthesis" follow-up), styled like a
   muted field-hint so it reads as inherited/locked rather than an
   editable form field. */
.uncertainty-clause-readonly {
  color: var(--color-text-muted, #6b7280);
  line-height: 1.6;
  margin-top: 4px;
}

/* Per your explicit request ("I want the uncertainty here to be a
   notice if it is to be on the cert or not" / "a stronger notice") -
   a solid, impossible-to-miss banner (not quiet field-hint text)
   stating whether THIS gage is currently set to print the Uncertainty
   statement on its certificates - green/solid when it is, amber/
   warning when it isn't, so a cert with the statement hidden always
   says WHY instead of just showing nothing. See
   #optical-page-uncertainty-notice in renderCalibrationOpticalPage()
   in app.js, which toggles the two modifier classes below. */
.uncertainty-on-cert-notice {
  margin: 8px 0;
  padding: 10px 14px;
  border-radius: var(--radius-sm);
  font-weight: 700;
  font-size: 14px;
  border: 1px solid transparent;
}

.uncertainty-on-cert-notice.uncertainty-on-cert-notice-on {
  background: var(--color-success-light);
  color: var(--color-success);
  border-color: var(--color-success);
}

.uncertainty-on-cert-notice.uncertainty-on-cert-notice-off {
  background: var(--color-warning-light);
  color: var(--color-warning);
  border-color: var(--color-warning);
}

/* The Batch Certification PO step's form-grid has just the one PO
   Number field in it too - same "single field in a .form-grid
   otherwise stretches full width" issue as the Procedure field above,
   same fix: pin it to a small, fixed-width column per your explicit
   request to make it smaller. */
.batch-po-page-grid {
  grid-template-columns: minmax(180px, 260px);
}

/* The Optical Comparator Lens table's shared Resolution field is also
   the only item in its own .form-grid - same fix, per your explicit
   request ("I want the resolution to be a smaller cell"). */
.optical-page-lens-resolution-grid {
  grid-template-columns: minmax(140px, 200px);
}
/* Per your explicit request ("make resolution be more noticeable") -
   it applies to every lens row below it, so a missed/wrong setting here
   is easy to overlook as a plain small dropdown. A tinted, bordered
   callout box (same blue family as the rest of the app) plus a bigger,
   bolder label and field make it read as a setting that matters, not
   just another form field. */
.optical-page-lens-resolution-callout {
  background: var(--color-primary-light);
  border: 1px solid var(--color-primary);
  border-radius: var(--radius);
  padding: 10px 14px;
  margin-bottom: 14px;
}
.optical-page-lens-resolution-callout label {
  font-size: 13.5px;
  font-weight: 700;
  color: var(--color-primary-dark);
}
.optical-page-lens-resolution-callout select {
  font-size: 15px;
  font-weight: 700;
  padding: 7px 10px;
  border-color: var(--color-primary);
  background: var(--color-surface);
}

.form-grid input,
.form-grid select,
.form-grid textarea {
  padding: 5px 8px;
  /* Per your explicit request ("better fill in to background
     contrast so its easier to see where to fill in") - a plain white
     field on this card's own white background, with only a very light
     border, was hard to spot at a glance. A light sunken fill plus a
     visibly darker border makes every fillable field read as its own
     box instead of blending into the card. */
  background: var(--color-surface-sunken);
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius);
  font-size: 13px;
  font-weight: 400;
  font-family: inherit;
  color: var(--color-text);
  transition: border-color 0.12s ease, box-shadow 0.12s ease, background 0.12s ease;
}

.form-grid input:focus,
.form-grid select:focus,
.form-grid textarea:focus {
  outline: none;
  background: var(--color-surface);
  border-color: var(--color-primary);
  box-shadow: 0 0 0 3px var(--color-primary-light);
}

.form-grid textarea {
  resize: vertical;
  min-height: 60px;
}

.form-grid input:disabled,
.form-grid select:disabled,
.form-grid textarea:disabled {
  background: var(--color-surface-sunken);
  color: var(--color-text-muted);
  border-color: transparent;
}

.form-grid .span-2 {
  grid-column: span 2;
}

/* The Limited Use Description field lives in the Approval card, which
   is a plain .card (not a .form-grid), so it gets none of the
   .form-grid textarea styling above - it needs its own rule to
   stretch to the full width of the card (matching the points table
   above it) instead of the browser-default narrow textarea. This
   governs the calibration's overall Limited Use decision, which
   applies across every block/point in the calibration - there is one
   Approval card per calibration, not one per block. */
#calibration-page-limited-use-desc-wrap {
  display: block;
  width: 100%;
}

#calibration-page-limited-use-desc {
  display: block;
  width: 100%;
  box-sizing: border-box;
  padding: 5px 8px;
  /* Same fill/border contrast treatment as .form-grid input above,
     for the same reason - this textarea lives outside .form-grid so
     it needs its own copy of the rule. */
  background: var(--color-surface-sunken);
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius);
  font-size: 13px;
  font-weight: 400;
  font-family: inherit;
  color: var(--color-text);
  resize: vertical;
  min-height: 60px;
  transition: border-color 0.12s ease, box-shadow 0.12s ease, background 0.12s ease;
}

#calibration-page-limited-use-desc:focus {
  outline: none;
  background: var(--color-surface);
  border-color: var(--color-primary);
  box-shadow: 0 0 0 3px var(--color-primary-light);
}

/* Stretches a field across the FULL width of its .form-grid row, no
   matter how many columns that grid happens to have (unlike .span-2,
   which is a fixed 2 columns) - used for the Calibration Details
   page's Findings box, so it reaches the right edge of the card like
   the rest of the form instead of sitting at its cramped browser
   default width. */
.form-grid .span-full {
  grid-column: 1 / -1;
}

/* Per-block "+ Add Point" mini-form (just Nominal) - per your explicit
   request, this single field shouldn't stretch to fill the whole card
   width the way .form-grid's auto-fit columns normally do when there's
   only one field. A fixed, compact column keeps it small and flush to
   the left instead. */
.block-add-point-fields {
  grid-template-columns: 160px;
}

/* The Category checkbox group near the top of the Add/Edit Model
   forms, per your explicit request. Reuses the .form-grid's own
   column tracks (it's a direct .span-2 child of that grid) but lays
   its own options out as a wrapping row instead of the grid's usual
   label-above-field stack. */
.model-category-group {
  grid-column: span 2;
  display: flex;
  flex-wrap: wrap;
  gap: 6px 18px;
  background: var(--color-surface-sunken);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  padding: 10px 14px 12px;
  margin: 0;
}

.model-category-group legend {
  padding: 2px 8px;
  margin-left: -4px;
  border-radius: 4px;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--color-text-muted);
}

/* Per your explicit request ("lets make x and y like the cert... and
   in two tables") - the Model page's "Default DRO Nominals" X/Y
   blocks, stacked full-width one after another (same idea as the X/Y
   DRO Readings cards on the calibration page), instead of
   .model-category-group's flex-wrap layout, which is meant for short
   wrapping checkbox rows and mis-arranged this block's own
   Start/End/Increment grid, buttons, and table as overlapping flex
   items rather than stacking them top to bottom. */
.model-dro-axis-block {
  display: block;
  background: var(--color-surface-sunken);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  padding: 10px 14px 14px;
  margin: 0 0 14px;
}

.model-dro-axis-block:last-child {
  margin-bottom: 0;
}

.model-dro-axis-block legend {
  padding: 2px 8px;
  margin-left: -4px;
  border-radius: 4px;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--color-text-muted);
}

.model-dro-axis-block > .form-grid,
.model-dro-axis-block > .form-actions,
.model-dro-axis-block > .employee-table-wrap,
.model-dro-axis-block > .field-hint,
.model-dro-axis-block > .error-text {
  margin-top: 10px;
}

.model-dro-axis-block > *:first-child {
  margin-top: 0;
}

/* Same "its own clean white table, numbers right-aligned" treatment as
   .block-points-table above, applied to the Default DRO Nominals
   tables - they sit on this block's own sunken grey background too,
   so without their own white panel they'd blend into it the same way. */
.model-dro-axis-block .employee-table,
.model-lens-template-section .employee-table {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
}

.model-dro-axis-block .employee-table thead th {
  background: var(--color-surface-sunken);
}

.model-dro-axis-block .employee-table th:nth-child(1),
.model-dro-axis-block .employee-table th:nth-child(2),
.model-dro-axis-block .employee-table th:nth-child(3) {
  text-align: right;
}

.model-dro-axis-block .employee-table td:nth-child(1),
.model-dro-axis-block .employee-table td:nth-child(2),
.model-dro-axis-block .employee-table td:nth-child(3) {
  text-align: right;
  font-variant-numeric: tabular-nums;
}

/* Per your explicit request ("uncertainty should be its own space and
   the units are weirdly located") - the Linear Measurement Tolerance
   section's own X Axis/Y Axis fieldsets, same "stack top to bottom
   instead of .model-category-group's wrapping flex box" fix as
   .model-dro-axis-block above (that flex-wrap layout is meant for
   short checkbox rows - applied here it let Mode/Fixed/Formula/
   Copy-from-X all jostle for space as flex items instead of forming
   clean, full-width sections). */
.model-tolerance-axis-group {
  display: block;
  background: var(--color-surface-sunken);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  padding: 10px 14px 14px;
  margin: 0;
}

.model-tolerance-axis-group legend {
  padding: 2px 8px;
  margin-left: -4px;
  border-radius: 4px;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--color-text-muted);
}

.model-tolerance-axis-group > * {
  margin-top: 10px;
}

.model-tolerance-axis-group > *:first-child {
  margin-top: 0;
}

.model-category-group .checkbox-label {
  display: inline-flex;
  /* .form-grid label (element+class, still a higher a/b/c match on
     just class-count than you'd expect at a glance) sets its own
     labels to flex-direction: column for the usual label-above-field
     layout - that still applies here unless overridden explicitly,
     same gotcha already noted on .equipment-frequency-inputs
     .checkbox-row above. Set it back to a row so the radio sits
     beside its own text instead of above it. */
  flex-direction: row;
  align-items: center;
  gap: 6px;
  font-size: 13px;
  font-weight: 400;
  color: var(--color-text);
  white-space: nowrap;
}

.model-category-group .checkbox-label input {
  margin: 0;
}

/* The Category badge shown next to a model's name/manufacturer in its
   card header (collapsed or expanded) - a plain neutral pill, unlike
   the green/red/yellow status-badge variants, since a category isn't
   good or bad. */
.model-category-display {
  background: var(--color-bg);
  color: var(--color-text-muted);
  border: 1px solid var(--color-border);
}

.field-with-action {
  display: flex;
  align-items: center;
  gap: 8px;
}

.field-with-action input,
.field-with-action select {
  flex: 1 1 auto;
}

.field-with-action .btn {
  flex: 0 0 auto;
  white-space: nowrap;
}

.field-hint {
  margin: 0;
  font-size: 12px;
  color: var(--color-text-muted);
}

/* Audit Log's Prev/Next bar - see AUDIT_LOG_PAGE_SIZE in app.js. */
.audit-log-pagination {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 16px;
  margin-bottom: 16px;
  padding-bottom: 16px;
  border-bottom: 1px solid var(--color-border);
}

/* The Angle D.R.O. table's own Decimal/DMS/DM reading-format picker -
   see optical-page-angle-format in app.js. A plain block label/select,
   not part of a .form-grid, so it gets a little breathing room of its
   own above and below the table. */
.angle-format-label {
  display: block;
  max-width: 320px;
  margin: 10px 0 12px;
}

/* Per your explicit request ("I need a resolution selection, one for
   x, 1 for y... they may not match") - the X/Y DRO cards' own
   Resolution field, same plain-block-label treatment as the Angle
   format picker above. */
.dro-resolution-label {
  display: block;
  max-width: 260px;
  margin: 6px 0 10px;
}

/* Per your explicit request ("the resolution button should be
   clearer") - same tinted/bordered callout treatment as the Lens
   table's own shared Resolution field (see
   .optical-page-lens-resolution-callout above), so this reads as a
   setting that matters rather than a plain small dropdown. */
.dro-resolution-callout {
  background: var(--color-primary-light);
  border: 1px solid var(--color-primary);
  border-radius: var(--radius);
  padding: 10px 14px;
  margin-bottom: 10px;
  max-width: 320px;
}
.dro-resolution-callout .dro-resolution-label {
  max-width: none;
  margin: 0;
  font-size: 13.5px;
  font-weight: 700;
  color: var(--color-primary-dark);
}
.dro-resolution-callout select {
  font-size: 15px;
  font-weight: 700;
  padding: 7px 10px;
  border-color: var(--color-primary);
  background: var(--color-surface);
}

/* Per your explicit request ("make the fill in points more
   identifiable") - the Generate Points Start/End/Increment fields used
   to be three bare boxes distinguished only by a small label above
   each. A light bordered box groups them as one "fill these in"
   control, and each field now also carries a worked-example
   placeholder (see index.html) so it's clear what to type even before
   reading the label. */
.dro-generate-fields {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
  gap: 14px;
  max-width: 560px;
  background: var(--color-surface-sunken);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  padding: 10px 14px;
  margin-bottom: 10px;
}
.dro-generate-fields label {
  display: flex;
  flex-direction: column;
  font-size: 13px;
  font-weight: 600;
  color: var(--color-text-muted);
  gap: 4px;
}
.dro-generate-fields input {
  padding: 5px 8px;
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  font-size: 13px;
  font-family: inherit;
  color: var(--color-text);
  background: var(--color-surface);
}
.dro-generate-fields input:focus {
  outline: none;
  border-color: var(--color-primary);
  box-shadow: 0 0 0 3px var(--color-primary-light);
}

/* Per your explicit request ("I dont want there to be a arrow in the
   cells") - hides the browser's default up/down spinner on every
   number input in the X/Y D.R.O. tables, same fix as the Lens table's
   own (see #optical-page-lens-table input[type="number"] above). */
.dro-combined-table input[type="number"]::-webkit-outer-spin-button,
.dro-combined-table input[type="number"]::-webkit-inner-spin-button {
  -webkit-appearance: none;
  margin: 0;
}
.dro-combined-table input[type="number"] {
  -moz-appearance: textfield;
}

/* Per your explicit request ("reduce the cell size and remove the
   arrows in the cell") - Perpendicularity Overall is a single number,
   not a long value, so it doesn't need to stretch the full width of
   the form-grid cell like a text field would; same spinner-arrow
   removal as the DRO/Lens tables above. */
.optical-page-perpendicularity-input {
  max-width: 120px;
}
.optical-page-perpendicularity-input::-webkit-outer-spin-button,
.optical-page-perpendicularity-input::-webkit-inner-spin-button {
  -webkit-appearance: none;
  margin: 0;
}
.optical-page-perpendicularity-input {
  -moz-appearance: textfield;
}

/* Per your explicit request ("for angles I need the option for each to
   be a negative number (single click option is preferred)") - the +/-
   sign-toggle button sits right next to its own As Found/As Left
   reading, in the same table cell. */
#optical-page-dro-angle-table td {
  white-space: nowrap;
}

.angle-sign-toggle-btn {
  margin-left: 4px;
  padding-left: 6px;
  padding-right: 6px;
  font-weight: bold;
}


/* Per your explicit request: X and Y DRO readings shown as ONE table
   per axis (not two side-by-side tables, which each inherited the
   720px .employee-table min-width below and together forced a wide
   horizontal scroll / overlapping headers) - Nominal/Min/Max appear
   once, then the two directions' As Found/As Left columns sit grouped
   side by side within that same table for direct comparison, narrow
   enough to fit on one page with no scroll. .dro-combined-table's own
   min-width overrides the general .employee-table one since it only
   has 8 columns, 4 of them narrow number inputs, instead of needing
   the room a typical wide data table does. */
.dro-combined-table {
  min-width: 0;
  table-layout: fixed;
}

.dro-combined-table th,
.dro-combined-table td {
  text-align: center;
}

.dro-combined-table td:first-child,
.dro-combined-table th:first-child {
  text-align: left;
}

.dro-combined-table .dro-group-header {
  border-left: 1px solid var(--color-border);
  color: #35506b;
  font-size: 11px;
}

/* Per your explicit request ("I want the copy button above the as left
   section") - the Copy All to As Left button lives right inside the As
   Left group header cell, directly above those columns, instead of off
   to the side above the whole table. */
.dro-group-header-asleft {
  padding-bottom: 6px;
}

.dro-group-header-asleft .btn {
  margin-top: 4px;
  font-weight: normal;
  text-transform: none;
  letter-spacing: normal;
}

.dro-combined-table input {
  min-width: 0;
  text-align: center;
}

/* Per your explicit request: a required-field note right under
   Calibration Date itself (in the Calibration Details form) instead
   of only explained in a paragraph further down the page - normal
   weight/color so it doesn't read as loud as the bold field label
   above it. */
.calibration-date-required-hint {
  font-weight: 400;
  color: var(--color-danger);
}

/* Per your explicit request: a star next to each mandatory Details
   field's label (Cert Editor, Calibration Date, Temperature,
   Humidity) - a quick visual flag right on the label itself, on top
   of the red "Required before signing..." hints shown later on the
   Sign-off step. */
.required-star {
  color: var(--color-danger);
  font-weight: 700;
}

.form-actions {
  grid-column: 1 / -1;
  display: flex;
  gap: 10px;
}

/* Per your explicit request ("I should be able to override the unit
   and have it auto switch if needed") - the Unit dropdown that replaced
   the old pair of "Convert in -> mm"/"Convert mm -> in" buttons on each
   Fixed/Formula tolerance group. Sits inline in the same .form-actions
   row the buttons used to. */
.unit-select-label {
  display: flex;
  align-items: center;
  gap: 6px;
  font-weight: 600;
  font-size: 0.85em;
}

.unit-select-label .unit-select {
  font-weight: 400;
  width: auto;
}

/* Per your explicit request ("I want to be able to see what it is in
   either mm or inches though") - the small read-only "= 0.0001575 in"
   style hint that appears right under each Fixed/Formula tolerance
   number field, showing that same value in the OTHER unit, live as you
   type - see wireUnitConvertButtons in app.js. Muted/italic so it never
   competes with the real input above it. */
.unit-equivalent-hint {
  font-size: 11px;
  font-style: italic;
  font-weight: 400;
  color: var(--color-text-muted);
  min-height: 14px;
}

/* Per your explicit request ("in the formula can you include what the
   tolerance amount would be per 10mm (in metric) and per inch in
   inches") - the computed-example line under each axis's Formula
   fields (Base/Divisor/Multiplier), showing what that formula actually
   works out to at two concrete reference lengths. Slightly bolder than
   .unit-equivalent-hint since this is a useful summary of the whole
   formula, not just a per-field conversion. */
.formula-tolerance-example {
  font-size: 12px;
  font-weight: 600;
  color: var(--color-text-muted);
  grid-column: 1 / -1;
  margin: 2px 0 0;
  min-height: 14px;
}

/* Per your explicit request: "Save & New" and "Clear & Close" only
   show at the top of the page now (see #calibration-page-top-actions
   in index.html) - not duplicated again down here. The real buttons
   stay in the DOM (mirrorActionButton() in app.js still needs them to
   hold the actual click/disabled/label logic the top ones mirror),
   just permanently hidden visually, independent of their own "hidden"
   attribute toggling. The other 4 bottom buttons (Save Changes/Save
   Draft & Close/Save Draft & New/Delete Draft) are unaffected and
   still appear in both places. */
#calibration-page-start-new-btn,
#calibration-page-clear-close-btn {
  display: none !important;
}

.error-text {
  color: var(--color-danger);
  font-size: 13px;
  grid-column: 1 / -1;
}

/* Amber, non-blocking heads-up (e.g. "this ID looks similar to an
   existing one") - distinct from .error-text, which is red and means
   the thing you're doing is actually blocked. */
.warning-text {
  color: #9a6700;
  font-size: 12px;
  font-weight: 600;
}

/* Indeterminate progress bar for long server-side operations (backup
   download/restore) where there's no real percentage to show - it just
   needs to visibly keep moving so it's obvious the page isn't frozen. */
.progress-bar-track {
  grid-column: 1 / -1;
  height: 6px;
  border-radius: 999px;
  background: var(--color-primary-light);
  overflow: hidden;
  margin-top: 4px;
}

.progress-bar-fill {
  height: 100%;
  width: 40%;
  border-radius: 999px;
  background: linear-gradient(90deg, var(--color-primary), var(--color-primary-dark));
  animation: progress-bar-sweep 1.3s ease-in-out infinite;
}

@keyframes progress-bar-sweep {
  0% { transform: translateX(-100%); }
  100% { transform: translateX(250%); }
}

.success-text {
  color: var(--color-success);
  font-size: 13px;
  font-weight: 600;
  grid-column: 1 / -1;
}

/* ---------------- EMPLOYEE TABLE ---------------- */

.employee-table {
  width: 100%;
  min-width: 720px; /* forces horizontal scroll instead of illegibly squashed columns */
  border-collapse: collapse;
  font-size: 13px;
}

.employee-table th {
  text-align: left;
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--color-text-muted);
  border-bottom: 1px solid var(--color-border-strong);
  padding: 7px 6px;
  white-space: nowrap;
}

.employee-table td {
  padding: 6px;
  border-bottom: 1px solid var(--color-border);
  vertical-align: middle;
}

/* Batch Certification's "Add a gage to this batch" table - per your
   explicit request ("quick select when viewing all the tools", "date
   range filter option", "sorting option for each category"), then your
   follow-up ("I just have check boxes or something to indicate that
   its part of the batch list. I shouldnt be able to open the gage
   there. just read only with a selecting option") - every column
   header is clickable to sort by that column (see
   renderBatchAddGagePage in app.js), but the table itself is read-only
   data: no click-to-open-the-gage anywhere. Per your explicit request,
   a click ANYWHERE on a row (not just its own checkbox) toggles that
   row's selection too, same effect either way - checked/selected rows
   feed "Add Selected" above the table. */
.batch-add-gage-table th[data-sort-key] {
  cursor: pointer;
  user-select: none;
  position: relative;
}
.batch-add-gage-table tbody tr {
  cursor: pointer;
}
.batch-add-gage-table th[data-sort-key]:hover {
  color: var(--color-text);
}
.batch-add-gage-table th[data-sort-key] .batch-add-gage-sort-arrow {
  display: inline-block;
  margin-left: 3px;
  opacity: 0.35;
  font-size: 9px;
}
.batch-add-gage-table th[data-sort-key].batch-add-gage-sort-active .batch-add-gage-sort-arrow {
  opacity: 1;
}
.batch-add-gage-table tbody tr.instrument-summary-row-inactive {
  opacity: 0.55;
}
.batch-add-gage-table tbody tr.batch-add-gage-row-selected td {
  background: var(--color-row-hover, rgba(27, 79, 140, 0.06));
}
/* Per your explicit request ("I want to be able to drag select too") -
   dragging across rows to paint checkboxes on/off would otherwise also
   highlight/select the row's own text every time, which looks broken
   and fights the drag. Text in this table is never meant to be copied
   anyway (it's read-only data, not source material), so it's simply
   not selectable. */
.batch-add-gage-table tbody {
  user-select: none;
}

/* Per your explicit request ("dont like it go into a scroll bar left
   and right") - the Lens table grew to 11 columns once the Before/After
   calculated columns were added, which pushed it past the usual
   .employee-table 720px floor and forced the whole card into horizontal
   scroll. Scoped overrides so just this table shrinks to fit the card
   instead of scrolling: headers wrap onto two lines instead of forcing
   width with nowrap, columns share the row evenly (table-layout:
   fixed), and inputs/buttons drop their own minimum widths so they
   shrink with their column rather than overflowing it. */
#optical-page-lens-table {
  min-width: 0;
  table-layout: fixed;
  width: 100%;
}
#optical-page-lens-table th {
  white-space: normal;
  font-size: 10px;
  line-height: 1.25;
  padding: 7px 5px;
  font-weight: 600;
  letter-spacing: 0.02em;
}
#optical-page-lens-table td {
  padding: 5px 4px;
}
/* Per your request ("can we make this look less busy") - this table's
   <input>/<select> elements previously had no border/background/radius
   of their own at all (only sizing - width/padding/font-size, below),
   so every browser drew them with its own native, inconsistent control
   chrome (default blue focus rings, mismatched heights/corners) right
   next to this app's own cleanly-styled inputs elsewhere - that clash,
   not any one piece of data, was most of what read as "busy" here.
   This gives every input/select in this table the SAME quiet, rounded,
   light-bordered look the rest of the app already uses (see .form-grid
   input above), so the table reads as one calm grid instead of a pile
   of mismatched little boxes. */
#optical-page-lens-table input,
#optical-page-lens-table select {
  min-width: 0;
  width: 100%;
  padding: 4px 6px;
  font-size: 11.5px;
  font-family: inherit;
  color: var(--color-text);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  transition: border-color 0.12s ease, box-shadow 0.12s ease;
}
#optical-page-lens-table input:focus,
#optical-page-lens-table select:focus {
  outline: none;
  border-color: var(--color-primary);
  box-shadow: 0 0 0 2px var(--color-primary-light);
}
#optical-page-lens-table input:disabled,
#optical-page-lens-table select:disabled {
  background: var(--color-surface-sunken);
  color: var(--color-text-muted);
  border-color: transparent;
}
/* Per your request to look less busy - Copy/Override/Remove no longer
   carry a full bordered button box in every row (12 columns' worth of
   boxes stacked down the table was a big part of the clutter); they
   read as quiet text-style actions instead, with the bordered/filled
   look only appearing on hover as an affordance. Still real .btn
   elements underneath (same click targets, same JS), just restyled
   here. */
#optical-page-lens-table .btn-small {
  padding: 4px 6px;
  font-size: 11px;
  white-space: normal;
  background: transparent;
  border-color: transparent;
  color: var(--color-text-muted);
  font-weight: 600;
}
#optical-page-lens-table .btn-small:hover {
  background: var(--color-primary-light);
  border-color: var(--color-primary);
  color: var(--color-primary-dark);
}
#optical-page-lens-table .btn-danger-text {
  color: var(--color-danger);
}
/* Per your explicit request ("do not include the arrows in the fill in
   cells, just let us fill the numebr in") - hides the browser's
   default up/down spinner on every number input in this table (As
   Found/As Left Deviation, and Tol. Min/Tol. Max when overriding). */
#optical-page-lens-table input[type="number"]::-webkit-outer-spin-button,
#optical-page-lens-table input[type="number"]::-webkit-inner-spin-button {
  -webkit-appearance: none;
  margin: 0;
}
#optical-page-lens-table input[type="number"] {
  -moz-appearance: textfield;
}
/* Per your explicit request ("two options for the deviations, a check
   mark being 0.0001 and another be a other deviation section which we
   can fill in the value") - As Found/As Left Deviation's quick "0.0001"
   checkbox + "Other" free-entry box (see numberCell in app.js), stacked
   to fit this table's narrow columns. The checkbox needs its own
   narrower, more specific rule to override the table-wide
   input{width:100%} above (a checkbox stretched to the column's full
   width looks broken). */
#optical-page-lens-table .lens-table-deviation-wrap {
  display: flex;
  flex-direction: column;
  gap: 3px;
}
#optical-page-lens-table .lens-table-deviation-check {
  display: flex;
  align-items: center;
  gap: 3px;
  font-size: 10.5px;
  color: var(--color-text-muted);
  white-space: nowrap;
  cursor: pointer;
}
#optical-page-lens-table .lens-table-deviation-check input[type="checkbox"] {
  width: auto;
  margin: 0;
}

/* Per your explicit request ("for the lens size I'd like the drop down
   options to be 1, 0.625, 0.25, 0.1875, 0.0625 and other which we
   manually write in") - Size's quick-pick dropdown + "Other" free-entry
   box (see lensSizeCell in app.js), stacked the same way as the
   deviation checkbox/Other pair above. */
#optical-page-lens-table .lens-table-size-wrap {
  display: flex;
  flex-direction: column;
  gap: 3px;
}

/* Per your request ("full workover for that section") - Mode/Tol. Min/
   Tol. Max collapsed from three columns into one "Tolerance" cell (see
   the Tolerance cell in renderLensTable in app.js): a small mode label
   (or select, while overriding) sitting right above the resolved
   [min, max] reading window, read as one unit instead of three
   separate grid cells that used to repeat "Fixed"/"% of Size" down the
   whole table for little payoff. */
#optical-page-lens-table .lens-table-tolerance-cell {
  min-width: 0;
}
#optical-page-lens-table .lens-table-tolerance-mode-label {
  font-size: 10px;
  margin-bottom: 2px;
}
#optical-page-lens-table .lens-table-tolerance-range {
  font-size: 11px;
  font-variant-numeric: tabular-nums;
  color: var(--color-text);
  white-space: nowrap;
}
#optical-page-lens-table .lens-table-tolerance-mode {
  margin-bottom: 3px;
}
#optical-page-lens-table .lens-table-tolerance-bounds {
  display: flex;
  gap: 3px;
}
#optical-page-lens-table .lens-table-tolerance-bounds input {
  min-width: 0;
}

/* Per your request ("full workover for that section") - the calculated
   reading (Size + Deviation) used to sit in its own "Before/After
   (Calculated)" column; now it's one quiet line right under the input
   it comes from (see numberCell in app.js), so the two numbers that
   belong together - what was typed, and what it means - read together
   instead of across a column gap. */
#optical-page-lens-table .lens-table-deviation-calc {
  font-size: 10px;
  font-variant-numeric: tabular-nums;
  color: var(--color-text-muted);
  min-height: 12px;
}

/* The Copy button is now a single compact arrow between As Found and As
   Left (see numberCell's neighboring copyBtn in app.js) rather than a
   wide "Copy →" box - the column shrinks to fit it instead of forcing
   width onto the two reading columns either side. */
#optical-page-lens-table .lens-table-copy-btn {
  width: 100%;
  padding: 4px 2px;
  font-size: 13px;
}

/* Per your request ("full workover for that section") - Override/Done+
   Restore Mfg Spec and Remove used to be two columns that were blank
   as often as full; combined into one "Actions" cell (see actionsTd/
   actionsWrap in app.js) with its buttons stacked, so there's one
   column here instead of two mostly-empty ones. The flex layout goes
   on this inner wrap div, not the <td> itself, so the cell keeps its
   normal table-cell box (a <td> with display:flex drops out of table
   layout and can break row sizing). */
#optical-page-lens-table .lens-table-actions-wrap {
  display: flex;
  flex-direction: column;
  gap: 2px;
}
#optical-page-lens-table .lens-table-actions-wrap .btn {
  width: 100%;
  text-align: center;
}

/* A quiet hover highlight across any data table built on
   .employee-table, so tracking a row across many columns (there are
   plenty of wide ones in this app) is easier - any cell that sets its
   own background (.row-dirty, a fail/limited reading cell, the pinned
   last column, etc.) paints over it, so none of those special states
   are affected. */
.employee-table tbody tr:hover td {
  background: var(--color-surface-sunken);
}

.employee-table input,
.employee-table select {
  width: 100%;
  min-width: 90px;
  padding: 4px 6px;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  font-size: 12px;
  font-family: inherit;
  transition: border-color 0.12s ease, box-shadow 0.12s ease;
}

.employee-table input:focus,
.employee-table select:focus {
  outline: none;
  border-color: var(--color-primary);
  box-shadow: 0 0 0 2px var(--color-primary-light);
}

/* The Save/Deactivate column is the whole reason the Access Control
   table exists - it must never be the part that scrolls out of view.
   Pinning it to the right edge of the scrolling .card means it's
   always visible, however wide the rest of the row's fields get, on
   any window size. Scoped to ".pin-last-col" specifically (Access
   Control, Manufacturers, Blocks) rather than every ".employee-table"
   - the Change Requests and Audit Log tables' View column is just a
   normal last column instead, since those tables have enough other
   columns that pinning made the sticky column's shadow line overlap
   the column right before it. */
.employee-table.pin-last-col th:last-child,
.employee-table.pin-last-col td:last-child {
  position: sticky;
  right: 0;
  /* Defaults to the normal white card background (--color-surface),
     but reads a --pin-col-bg custom property first so a table sitting
     on a non-white container (like .model-block below) can override
     just this pinned column's background to match ITS OWN background
     instead - an inherited CSS variable rather than a second override
     rule, so there's no specificity/ordering fight over which one
     wins. */
  background: var(--pin-col-bg, var(--color-surface));
  box-shadow: -6px 0 6px -6px rgba(0, 0, 0, 0.2);
}

.employee-table input:disabled,
.employee-table select:disabled {
  background: var(--color-bg);
  color: var(--color-text-muted);
  border-color: transparent;
}

/* A row with an unsaved edit gets a soft highlight, so it's obvious
   which rows the page-level Save Changes button will act on. Also used
   by the Model's own Lens Template (.model-lens-template-row) for its
   Confirm Changes button, per your explicit request. */
.employee-row.row-dirty td,
.model-lens-template-row.row-dirty td {
  background: #fff9e6;
}
.employee-row.row-dirty td:last-child {
  background: #fff9e6;
}

/* Per your explicit request ("condense this section and have the
   options being all 1 line per option") - the Optical/Mechanical-
   Electrical Components checklist's Result cell. Without this, the
   normal ".employee-table input { width: 100% }" rule stretches the
   text box across the whole column, pushing the OK/N/A (etc.) quick-
   fill buttons onto their own line below it instead of sitting beside
   it. */
.employee-table td.checklist-value-cell {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.3em;
}
/* The text box + quick-fill buttons (OK/N/A/Damaged-Scratched/Adjusted/
   etc.) - per your explicit request, these now wrap onto a second line
   within the cell instead of forcing the row wider, since Damaged/
   Scratched and Adjusted made this row longer than the old OK/N/A
   pair. */
.checklist-text-wrap {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.4em;
}
.employee-table td.checklist-value-cell input[type="text"] {
  /* Per your explicit request ("make the result smaller and align
     vertically the check options") - a FIXED width (not flex-grow)
     so every row's text box is identical, and the buttons after it
     start at the same x position on every row regardless of how many
     buttons that row has (e.g. Lens Selector/Motor Electrical Systems'
     extra "Not Functioning" button no longer shifts its own OK/N/A
     left of every other row's). Per your follow-up explicit request
     ("have the result section wider so we can see all the text") -
     widened back up from 90px so a composed value like "Adjusted -
     0.004" or "Damaged/Scratched" isn't clipped. */
  width: 150px;
  flex: 0 0 150px;
  min-width: 0;
}
.employee-table td.checklist-value-cell .btn {
  flex: 0 0 auto;
  white-space: nowrap;
}
/* Per your explicit request ("like up the cells and bottoms to the
   table below column wse") - keeps the Maintenance Components table's
   Item column a fixed width (sized to fit its longest item name,
   "Incandescent/Tungsten/Merc Arc/LED") instead of auto-sizing, so its
   Item/Result column boundary lines up with the table below it on the
   page. Per your later explicit request ("lets combine optical
   components with mechanical / electrical and call it maintenance
   components") - this used to keep TWO separate tables' columns
   aligned with each other (Optical Components + Mechanical/Electrical
   Components); those are now one merged table, so this rule just
   fixes that one table's own column width, but is otherwise unchanged. */
.optical-page-checklist-table th:first-child,
.optical-page-checklist-table td:first-child {
  width: 260px;
}
/* Per your explicit request ("the check box should be adjusted then a
   text box should be an optional adjusted by amount" - then "removed the
   measured value and keep everything within the same row") - the
   "Adjusted" checkbox and its optional amount box now sit inline with
   the OK/N/A/etc. buttons in .checklist-text-wrap, instead of a
   separate toggle row/box stacked below it like the old Measured Value
   feature was. */
.checklist-adjusted-toggle {
  display: flex;
  align-items: center;
  gap: 0.35em;
  font-size: 12px;
  color: var(--color-text-muted);
  font-weight: 500;
  cursor: pointer;
  flex: 0 0 auto;
  white-space: nowrap;
}
.employee-table td.checklist-value-cell input.checklist-adjusted-amount[type="text"] {
  width: 180px;
  flex: 0 0 180px;
  min-width: 0;
}

.status-badge {
  display: inline-block;
  padding: 3px 8px;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 600;
}

/* A "Previous" certificate's status badge doubles as a "make this the
   current one" button - per your explicit request ("I want current
   status on the uploaded to be a clickable thing ... In case an older
   cert is uploaded after I want to select the file that is current").
   Only applied to a "Previous" badge (see loadAndRenderCertificates()
   in app.js) - the "Current" badge stays plain text, since it's
   already current and clicking it wouldn't do anything. Reuses the
   plain <button> element with no border/background of its own so it
   still looks like every other status badge until you hover it. */
.equipment-cert-current-badge.clickable {
  cursor: pointer;
  border: none;
  font: inherit;
  padding: 3px 8px;
}

.equipment-cert-current-badge.clickable:hover {
  text-decoration: underline;
}

.status-badge.active {
  background: #e3f5e9;
  color: var(--color-success);
}

.status-badge.inactive {
  background: #fbe9e7;
  color: var(--color-danger);
}

.status-badge.pending {
  background: #fff4dd;
  color: #8a5b00;
}

.status-badge.approved {
  background: #e3f5e9;
  color: var(--color-success);
}

/* Per your explicit request ("give feedback or make edit requests to
   those submitted by others") - the Certs Approval Log's third event
   type, alongside the existing .pending ("Submitted")/.approved rows
   above. */
.status-badge.changes-requested {
  background: #fde3e3;
  color: #a12d2d;
}

/* Per your explicit request - the "Corrections Requested" banner
   shown on a calibration page (see calibration-page-changes-requested-
   banner/optical-page-changes-requested-banner in index.html and
   renderChangesRequestedBanner() in app.js). Same warm-red family as
   .status-badge.changes-requested above, so the two read as the same
   signal wherever they appear. */
.changes-requested-banner {
  background: #fdf1f1;
  border: 1px solid #f3c7c7;
}
.changes-requested-banner h4 {
  color: #a12d2d;
  margin-top: 0;
}

.status-badge.denied {
  background: #fbe9e7;
  color: var(--color-danger);
}

/* Equipment's two request workflows use their own status words
   ("resolved" for a general change request, "rejected" for a due-date
   request) instead of "approved"/"denied" - same color meaning
   though, so these just alias the two above. See
   fillChangeRequestRowCells/normalizeRequestRow in app.js. */
.status-badge.resolved {
  background: #e3f5e9;
  color: var(--color-success);
}

.status-badge.rejected {
  background: #fbe9e7;
  color: var(--color-danger);
}

/* A piece of equipment whose due_date has passed - see is_expired on
   EquipmentOut in schemas.py. Shown next to its name on the Equipment
   page so a technician sees it's blocked from use at a glance. */
.status-badge.expired {
  background: #fbe9e7;
  color: var(--color-danger);
}

/* Per your explicit request: a failed point's badge reads "Limited"
   in amber/yellow instead of "FAIL" in red once this calibration is
   flagged/approved Limited Use (calibration.is_limited_use) - same
   #8A6D00 amber family as the certificate's own "LIMITED USE" status
   text (see certificates.py), so this page and the PDF always agree. */
.status-badge.limited {
  background: #fff3c4;
  color: #8a6d00;
}

/* The number + unit dropdown pair for equipment's calibration
   frequency (e.g. "1" + "Year(s)") - sits side by side inside the
   "Frequency" label instead of stacking full-width like other fields. */
/* Wraps the Frequency label + the "End of month" checkbox together as
   one .form-grid cell, so the checkbox sits right after the
   years/months select AND the "End of month" checkbox all inline in
   ONE row, per your request. The "Frequency" heading can't be a real
   <label> anymore here (a <label> can't validly contain the "End of
   month" <label> inside it), so it's a plain .form-grid-label-text
   span styled to match every other .form-grid label. */
.equipment-frequency-group {
  display: flex;
  flex-direction: column;
  gap: 4px;
}

/* Calibration Date / Frequency / Due Date - forced onto a single row
   (not the default auto-fit wrap every other .form-grid uses), per
   your explicit request to keep everything in the same row.
   Traceability Number moved up to the ID/Manufacturer/etc. grid per
   your later request, so this is down to 3 columns now. Horizontal
   scroll on very narrow screens is the trade-off for never wrapping. */
.equipment-calibration-grid {
  grid-template-columns: repeat(3, minmax(160px, 1fr));
}

@media (max-width: 720px) {
  .equipment-calibration-grid {
    grid-auto-flow: column;
    overflow-x: auto;
    padding-bottom: 4px;
  }
}

/* The Active/Retired toggle now sits at the very top of the card body,
   above every other field, per your request. */
.equipment-active-top-row {
  margin-bottom: 4px;
}

/* Sits BELOW the Due Date input (not beside it), per your request -
   .form-grid label is already a flex column, so this is just the
   default stacking; align-self keeps the button compact instead of
   stretching to the input's full width. */
.equipment-recalc-duedate-btn {
  align-self: flex-start;
}

.form-grid-label-text {
  font-size: 13px;
  font-weight: 600;
  color: var(--color-text-muted);
}

.equipment-frequency-inputs {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}

/* The "End of month" <label> sits inside .form-grid (via
   .equipment-frequency-group), so the general ".form-grid label"
   rule (flex-direction: column, for every OTHER field's label-above-
   input layout) was winning over ".checkbox-row"'s own row layout -
   same specificity class-count doesn't matter here, ".form-grid
   label" is element+class (higher) vs ".checkbox-row" alone (class
   only), so it silently overrode flex-direction and stacked the
   checkbox above its own text instead of beside it. This rule is
   scoped with an extra class to outrank it. */
.equipment-frequency-inputs .checkbox-row {
  flex-direction: row;
  align-items: center;
}

.equipment-frequency-inputs input[type="number"] {
  flex: 1;
  /* Per your bug report - this could shrink all the way down to just
     the spinner arrows, with no room left to actually see the typed
     number, once the select/checkbox next to it claimed enough of the
     row. A real min-width (not 0) keeps at least 2-3 digits visible no
     matter how tight the row gets. */
  min-width: 56px;
}

/* "End of month" sits inline, in the same row as the frequency number
   and years/months select - per your explicit request. */
.equipment-frequency-eom-row {
  margin: 0;
  white-space: nowrap;
  font-weight: 500;
}

/* A loud, impossible-to-miss red banner - currently just for a piece
   of equipment that's out of calibration (past its due date), per
   your own explicit request for a "red notice." Deliberately much
   more prominent than .error-text, which is meant for small inline
   validation messages, not a standing warning. */
.expired-banner {
  background: #fbe9e7;
  color: var(--color-danger);
  border: 1px solid var(--color-danger);
  border-radius: 6px;
  padding: 10px 14px;
  font-weight: 700;
  font-size: 14px;
  margin-bottom: 12px;
}

/* Small red count pill on a home tile (e.g. pending deletion requests). */
.badge-count {
  display: inline-block;
  min-width: 18px;
  padding: 1px 6px;
  border-radius: 999px;
  background: var(--color-danger);
  color: white;
  font-size: 11px;
  font-weight: 700;
  text-align: center;
  vertical-align: middle;
}

/* .row-actions is the <td> itself - kept a plain table-cell (no
   display override) so its row still sizes and lines up with every
   other cell in that <tr>, exactly like every other td. "display:
   flex" used to be set right on the td, which on a row with a much
   taller neighboring cell (a wrapped multi-line date or address, for
   example) let the browser lay this one cell out on its own instead
   of as part of the row's normal grid, throwing its border-bottom out
   of line with the rest of the row - most visible on the Audit Log
   and Change Requests tables, whose rows vary a lot in height. The
   side-by-side button layout now lives on .row-actions-inner, a
   plain <div> wrapped around the button(s) inside the td, so it can
   be flex without the td itself leaving table layout. */
.row-actions-inner {
  display: flex;
  gap: 6px;
  white-space: nowrap;
}

.employee-table .btn-reset-password:disabled,
.employee-table .btn-toggle-active:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

/* Long text cells (Change Requests' Reason column, Audit Log's
   From/To columns) - collapsed to one line with a "..." by default;
   clicking the cell (see the click handler in app.js) toggles the
   .expanded class to wrap and show the rest, instead of a hover-only
   tooltip that's easy to miss and awkward on a touch screen. */
.expandable-cell {
  max-width: 260px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  cursor: pointer;
}

.expandable-cell:hover {
  text-decoration: underline dotted;
}

.expandable-cell.expanded {
  max-width: none;
  overflow: visible;
  white-space: normal;
  word-break: break-word;
  cursor: default;
  text-decoration: none;
}

/* ---------------- MODAL (Reset Password, etc.) ---------------- */

.modal-overlay {
  position: fixed;
  inset: 0;
  background: rgba(10, 18, 28, 0.55);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 16px;
  z-index: 100;
}

.modal-card {
  background: var(--color-surface);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  padding: 24px;
  width: 100%;
  max-width: 420px;
}

/* Wider variant for the pending-catalog-edit before/after review
   modal (tpl-catalog-edit-review-modal) - the side-by-side diff table
   doesn't fit the normal 420px modal width. */
.modal-card-wide {
  max-width: 960px;
  max-height: 90vh;
  overflow-y: auto;
}

.pce-diff-table {
  margin-bottom: 16px;
}

.pce-diff-after {
  width: 100%;
}

/* A field whose "Proposed" value differs from "Current" - highlighted
   in red so what actually changed is obvious at a glance. Applied to
   the editable "Proposed" input in tpl-pce-diff-row; JS toggles this
   on/off live as the super_admin edits the value before approving. */
.pce-diff-after.pce-diff-changed {
  border-color: var(--color-danger);
  color: var(--color-danger);
  font-weight: 600;
}

.modal-card h3 {
  margin: 0 0 8px;
  color: var(--color-primary-dark);
}

.modal-subtitle {
  margin: 0 0 16px;
  font-size: 13px;
  color: var(--color-text-muted);
}

.modal-card form {
  display: flex;
  flex-direction: column;
}

.modal-card label {
  font-size: 13px;
  font-weight: 600;
  color: var(--color-text-muted);
  display: flex;
  flex-direction: column;
  gap: 4px;
  margin-bottom: 12px;
}

.modal-card input {
  padding: 10px 12px;
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  font-size: 14px;
  font-weight: 400;
  font-family: inherit;
  color: var(--color-text);
  transition: border-color 0.12s ease, box-shadow 0.12s ease;
}

.modal-card input:focus {
  outline: none;
  border-color: var(--color-primary);
  box-shadow: 0 0 0 3px var(--color-primary-light);
}

.modal-card .field-hint {
  margin: 6px 0 0;
  font-size: 12px;
  color: var(--color-text-muted);
}

.modal-card .form-actions {
  margin-top: 16px;
}

/* The list of possible-duplicate matches on the "Possible Duplicate
   Customer" modal - see findPossibleDuplicateMatches() in app.js. */
.duplicate-customer-matches {
  margin: 0 0 4px;
  padding: 0;
  list-style: none;
  max-height: 200px;
  overflow-y: auto;
}

.duplicate-customer-matches li {
  padding: 8px 10px;
  border: 1px solid var(--color-border);
  border-radius: 6px;
  margin-bottom: 6px;
  font-size: 13px;
}

.duplicate-customer-matches li .match-name {
  font-weight: 600;
  color: var(--color-text);
}

.duplicate-customer-matches li .match-reason {
  display: block;
  color: var(--color-text-muted);
  font-size: 12px;
  margin-top: 2px;
}

/* ---------------- CUSTOMERS PAGE ---------------- */

/* Centered search shown when the Customers page first opens, before a
   customer has been picked. See setCustomerStage() in app.js - the same
   search box/button move up into .page-header-actions once selected. */
.customer-landing {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 72px 16px;
  text-align: center;
}

.customer-landing h3 {
  margin: 0;
  font-size: 20px;
  color: var(--color-primary-dark);
}

.customer-landing-hint {
  margin: 0 0 12px;
  color: var(--color-text-muted);
  font-size: 14px;
}

.customer-landing .search-wrap {
  width: 100%;
  max-width: 420px;
}

.customer-landing .search-input {
  font-size: 16px;
  padding: 12px 16px;
}

/* Pull the "+ Add" button in tight right underneath its search box
   (overriding .customer-landing's flex gap), then push "Show All"
   (now placed after "+ Add" per your request) further down and keep
   it a small, plainly-a-button size (not stretched to the search
   box's width) so it reads as its own, separate action - shared by
   Customers/Equipment/Models, which all reuse .customer-landing for
   their centered search layout. */
.customer-landing #show-add-customer-btn,
.customer-landing #show-add-equipment-btn,
.customer-landing #show-add-model-btn,
.customer-landing #show-add-manufacturer-btn {
  margin-top: -2px;
}

.customer-landing #customer-search-show-all-btn,
.customer-landing #equipment-search-show-all-btn,
.customer-landing #model-search-show-all-btn,
.customer-landing #manufacturer-search-show-all-btn {
  margin-top: 12px;
  width: auto;
  align-self: center;
}

/* Wraps the Manufacturers search box with its Add/Show All/Show Less
   buttons (see tpl-manufacturer-search-controls) so the suggestions
   dropdown below can be anchored to the bottom of this whole group
   instead of just the search box - otherwise it opened right under the
   input and sat on top of the buttons. Re-lays out as a plain flex
   column matching .customer-landing's own spacing, since the group now
   sits between .customer-landing and the search box/buttons in the DOM.
   Per your explicit request ("I want the drop down to be under the show
   less button"). */
#manufacturer-search-controls-group {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  width: 100%;
  position: relative;
}

/* The search box no longer needs to be its own positioning anchor here -
   the group above is - so the dropdown (anchored below) isn't clipped to
   just the input's own width/position. */
#manufacturer-search-controls-group .search-wrap {
  position: static;
}

/* Re-anchor and re-center the dropdown to the group (see above) instead
   of the search box alone, keeping it the same width as the search box
   so it still reads as "attached" to it, just opening below the Add/Show
   All/Show Less buttons instead of overlapping them. */
#manufacturer-search-controls-group .search-suggestions {
  left: 50%;
  right: auto;
  width: 100%;
  max-width: 420px;
  transform: translateX(-50%);
}

/* Once a customer is selected, the search box moves into the compact
   page-header spot - give it a sensible fixed width there instead of
   stretching to fill the header row. */
.page-header-actions .search-wrap {
  width: 260px;
}

.search-wrap {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 3px;
}

/* Sits above a search box that's paired with another one right next
   to it (e.g. the Models tab's "by number" and "by description"
   boxes) so it's clear which is which once you've typed something and
   the placeholder text is gone. */
.search-label {
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--color-text-muted);
}

.search-input {
  padding: 8px 12px;
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  font-size: 14px;
  min-width: 220px;
  width: 100%;
}

.search-suggestions {
  position: absolute;
  top: 100%;
  left: 0;
  right: 0;
  margin: 4px 0 0;
  padding: 4px;
  list-style: none;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  max-height: 260px;
  overflow-y: auto;
  z-index: 20;
  /* On a centered landing search (.customer-landing, reused by
     Customers/Equipment/Manufacturers/Models/Add Gage) the dropdown
     was inheriting that container's text-align: center, so every
     suggestion's text sat centered instead of reading naturally left
     to right - per your explicit request, force it back to flush
     left everywhere this dropdown appears. */
  text-align: left;
}

.search-suggestions li {
  padding: 8px 10px;
  border-radius: 6px;
  font-size: 14px;
  cursor: pointer;
}

.search-suggestions li:hover {
  background: var(--color-bg);
}

.search-suggestions li .inactive-tag {
  color: var(--color-text-muted);
  font-size: 12px;
  margin-left: 6px;
}

/* Secondary line under a suggestion's main label (used by equipment
   search to show description + due date at a glance). */
.search-suggestions li .search-suggestion-sub {
  display: block;
  margin-top: 2px;
  font-size: 12px;
  color: var(--color-text-muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* A non-clickable label separating close/typo-like "similar" matches
   from real prefix/substring matches above it. */
.search-suggestions li.search-suggestions-divider {
  padding: 6px 10px 2px;
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--color-text-muted);
  cursor: default;
}

.search-suggestions li.search-suggestions-divider:hover {
  background: none;
}

.customer-card {
  padding: 0;
}

.customer-card-header {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 16px 20px;
}

.customer-card-header-top {
  display: flex;
  align-items: center;
}

/* Per your explicit request ("I dont want them all in 1 row,
   categorize the buttons by little blocks") - the header's buttons sit
   on their own row below the customer name, and wrap onto additional
   rows (rather than overflowing sideways or all cramming into one
   line) on a narrow screen. */
.customer-card-header-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
}

/* Per your explicit request ("little titles on the blocks") - each
   .customer-header-block pairs a small uppercase label (what the
   block's buttons are FOR) with its .customer-header-btn-group box
   right below it. */
.customer-header-block {
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.customer-header-block-label {
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--color-text-muted);
  padding-left: 2px;
}

/* Each group of related header buttons (creating a cert, generating
   field paperwork, managing the customer record itself) is its own
   little boxed "block" - a sunken background + border + rounded
   corners - so the categories read as visually separate at a glance,
   instead of one flat run of buttons. */
.customer-header-btn-group {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  background: var(--color-surface-sunken);
  border: 1px solid var(--color-border);
  border-radius: 8px;
  padding: 6px 8px;
}

.customer-toggle-btn {
  display: flex;
  align-items: center;
  gap: 10px;
  background: none;
  border: none;
  cursor: pointer;
  font-size: 15px;
  font-weight: 600;
  color: var(--color-text);
  padding: 0;
  flex: 1;
  min-width: 0;
  text-align: left;
}

/* A plain, non-clickable stand-in for .customer-toggle-btn above, for
   a .customer-card-header that has no expand/collapse toggle to be -
   just the title text, sized the same way, taking up the same left
   space so the header's buttons still land at the top right via
   justify-content: space-between. Used by the Add Equipment page's
   single merged card, per your explicit request to move its Add/Clear
   buttons up there like an existing equipment's own Save Changes/
   Clear Edits. */
.card-header-title {
  font-size: 15px;
  font-weight: 600;
  color: var(--color-text);
  flex: 1;
  min-width: 0;
}

.customer-toggle-icon {
  font-size: 10px;
  color: var(--color-text-muted);
  width: 10px;
  flex-shrink: 0;
  display: inline-block;
  transition: transform 0.1s ease;
}

.customer-toggle-btn.expanded .customer-toggle-icon {
  transform: rotate(90deg);
}

.customer-name-display {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.customer-card-body {
  padding: 0 20px 20px;
  border-top: 1px solid var(--color-border);
}

/* Details/Gages tabs at the top of a customer's card body - per your
   explicit request to split them apart so a long gage list doesn't
   push the company fields/locations further down the page. Styled as
   a clearly-a-tab segmented switcher (a light track with a raised,
   white active pill) rather than plain underlined text, per your
   follow-up that the first version didn't read as tabs at a glance.
   See the customer-tab-btn wiring in buildCustomerCard() in app.js. */
.customer-tabs {
  display: flex;
  gap: 2px;
  width: fit-content;
  margin-top: 16px;
  margin-bottom: 20px;
  padding: 4px;
  background: var(--color-bg);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
}

.customer-tab-btn {
  background: none;
  border: none;
  border-radius: 6px;
  padding: 8px 20px;
  font-size: 14px;
  font-weight: 600;
  color: var(--color-text-muted);
  cursor: pointer;
  transition: background 0.15s ease, color 0.15s ease, box-shadow 0.15s ease;
}

.customer-tab-btn:hover {
  color: var(--color-text);
}

.customer-tab-btn.active {
  background: var(--color-surface);
  color: var(--color-primary-dark);
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12);
}

.customer-tab-panel .form-grid:first-child {
  margin-top: 0;
}

/* Calibration entry wizard (general + Optical Comparator calibration
   pages) - per your explicit request ("make the calibration entry
   page look less busy... mini popup tab steps") - splits each of
   those long pages into numbered step panels. Steps are clickable
   directly (jump to any step) and also move with Back/Next at the
   bottom of each step - a hybrid of tabs and a guided wizard. Same
   segmented-pill look as .customer-tabs above, just wider (more
   steps, longer labels) and numbered. See the wizard wiring near the
   end of renderCalibrationPage()/renderOpticalComparatorPage() in
   app.js - this is purely a show/hide layer; every field/id/handler
   inside a step panel is unchanged. */
.wizard-steps {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  margin-bottom: 20px;
  padding: 4px;
  background: var(--color-bg);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  position: sticky;
  top: 0;
  z-index: 5;
}

.wizard-step-btn {
  background: none;
  border: none;
  border-radius: 6px;
  padding: 8px 14px;
  font-size: 13px;
  font-weight: 600;
  color: var(--color-text-muted);
  cursor: pointer;
  transition: background 0.15s ease, color 0.15s ease, box-shadow 0.15s ease;
  white-space: nowrap;
}

.wizard-step-btn:hover {
  color: var(--color-text);
}

.wizard-step-btn.active {
  background: var(--color-surface);
  color: var(--color-primary-dark);
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12);
}

.wizard-step-panel {
  animation: wizard-panel-in 0.12s ease;
}

@keyframes wizard-panel-in {
  from { opacity: 0; }
  to { opacity: 1; }
}

.wizard-footer {
  display: flex;
  justify-content: space-between;
  margin-top: 8px;
  margin-bottom: 20px;
}

.customer-card-body .form-grid,
#add-customer-form > .form-grid {
  margin-bottom: 20px;
}

.customer-card-body .form-grid {
  margin-top: 16px;
}

.customer-card-body h4,
#add-customer-form h4 {
  margin: 0 0 10px;
  font-size: 13px;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--color-text-muted);
}

#add-customer-form .field-hint {
  margin-bottom: 10px;
}

.customer-locations-container {
  margin-bottom: 12px;
}

.location-slot {
  background: var(--color-bg);
  border-radius: var(--radius);
  padding: 14px 16px;
  margin-bottom: 10px;
}

.location-slot-heading-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  margin: 0 0 10px;
}

.location-slot-heading-row h4 {
  margin: 0;
}

.location-slot-remove-btn {
  flex-shrink: 0;
}

.location-slot-toggle {
  margin-bottom: 0;
  font-weight: 600;
}

.location-fields {
  margin-top: 12px;
}

.location-fields h5 {
  margin: 16px 0 8px;
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--color-text-muted);
}

.location-fields h5:first-of-type {
  margin-top: 4px;
}

/* Purchasing Contact / Accounting-Billing Contact headings each pair
   with their own "Same as Point of Contact" checkbox, sitting right
   next to the heading text instead of stacked above the fields or
   pushed out to the far right edge. */
.contact-heading-row {
  display: flex;
  align-items: center;
  justify-content: flex-start;
  gap: 12px;
}

.contact-heading-row h5 {
  margin: 16px 0 8px;
  /* Fixed width (instead of hugging each heading's own text length) so
     "Purchasing Contact" and "Accounting / Billing Contact" - two
     different lengths - still leave their checkboxes lined up at the
     same horizontal position. */
  flex: 0 0 210px;
}

.contact-heading-row:first-of-type h5 {
  margin-top: 4px;
}

.loc-contact-same-toggle-row {
  margin: 0;
  font-weight: 500;
  font-size: 13px;
}

/* Per your explicit request: "no set limit on add ons, just the
   option to add and remove extra contacts" under Point of Contact,
   Purchasing, and Accounting/Billing - each always-visible section's
   own unlimited list of extra contact rows sits directly under that
   section's main form-grid, with its own "+ Add Another Contact"
   button right below the list. */
.loc-extra-contacts:not(:empty) {
  margin-top: 10px;
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.loc-extra-contact-row {
  grid-template-columns: repeat(4, 1fr) auto;
  align-items: end;
  padding: 10px;
  background: #f7f8fa;
  border: 1px solid #e2e5ea;
  border-radius: 6px;
}

.loc-extra-contact-remove-btn {
  height: fit-content;
}

.loc-add-contact-btn {
  margin: 10px 0 4px;
}

.location-fields .form-grid {
  margin-bottom: 0;
}

.checkbox-row {
  display: flex;
  align-items: center;
  gap: 6px;
  font-weight: 500;
  margin: 10px 0;
}

.checkbox-row input[type="checkbox"],
.checkbox-row input[type="radio"] {
  width: 16px;
  height: 16px;
}

/* Per your explicit follow-up request ("select from the point of
   contact list who is my primary for each") - the per-row "Primary"
   radio inside .loc-extra-contact-row (a .form-grid) would otherwise
   hit the exact same ".form-grid label" vs ".checkbox-row" specificity
   gotcha already noted on .equipment-frequency-inputs above (element+
   class outranks class-only, so the row's own flex-row layout loses
   and the radio stacks above its own text). Scoped the same way. */
.loc-extra-contact-row .checkbox-row {
  flex-direction: row;
  align-items: center;
  margin: 0;
}

.loc-contact-primary-row {
  font-size: 13px;
  color: var(--color-text-muted);
}

.add-another-location-prompt {
  background: transparent;
  padding: 4px 0 0;
}

/* Equipment "Sent For Calibration To" vendor slots - same look as the
   customer location slots above, just a shorter field set (see
   buildVendorSlots() in app.js). */
.equipment-vendors-container {
  margin-bottom: 12px;
}

.vendor-slot {
  background: var(--color-bg);
  border-radius: var(--radius);
  padding: 14px 16px;
  margin-bottom: 10px;
}

.vendor-slot-heading-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  margin: 0 0 10px;
}

.vendor-slot-heading-row h5 {
  margin: 0;
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--color-text-muted);
}

.vendor-slot-remove-btn {
  flex-shrink: 0;
}

.vendor-slot-toggle {
  margin-bottom: 0;
  font-weight: 600;
}

.vendor-fields {
  margin-top: 4px;
}

.vendor-fields .form-grid {
  margin-bottom: 0;
}

.add-another-vendor-prompt {
  background: transparent;
  padding: 4px 0 0;
}

.loc-billing-fields,
.loc-address-fields,
.loc-contact-fields {
  margin-top: 8px;
  padding: 10px 12px;
  background: #fff;
  border: 1px solid var(--color-border);
  border-radius: 8px;
}

.loc-billing-fields[hidden] {
  display: none;
}

/* ---------------- MODEL CATALOG ---------------- */

.catalog-tabs {
  display: flex;
  gap: 8px;
  margin-bottom: 16px;
  border-bottom: 1px solid var(--color-border);
}

.catalog-tab-btn {
  background: none;
  border: none;
  border-bottom: 2px solid transparent;
  padding: 10px 4px;
  margin-right: 16px;
  font-size: 14px;
  font-weight: 600;
  color: var(--color-text-muted);
  cursor: pointer;
}

.catalog-tab-btn:hover {
  color: var(--color-text);
}

.catalog-tab-btn.active {
  color: var(--color-primary-dark);
  border-bottom-color: var(--color-primary);
}

.model-manufacturer-display {
  color: var(--color-text-muted);
  font-weight: 400;
  font-size: 13px;
}

.model-range-display {
  color: var(--color-text-muted);
  font-weight: 400;
  font-size: 12px;
  font-style: italic;
}

.model-card-body {
  padding-top: 4px;
}

.manufacturer-card-body {
  padding-top: 4px;
}

/* Per your explicit request ("the models looks busy and not organized
   well") - a Model's card body is really 4-5 separate concerns
   (Basic Info, Calibration Blocks, Lens Template, Linear Measurement
   Tolerance, Default DRO Nominals) that used to just run straight into
   each other with nothing but a bare, unstyled <h4> between them. Each
   major section now gets its own clear break (a top rule + breathing
   room) and the same colored-dot heading treatment every other card's
   own title gets - so a long expanded Model card reads as a handful of
   distinct, scannable sections instead of one dense, undifferentiated
   block of fields. */
.model-blocks-section,
.model-lens-template-section,
.model-linear-tolerance-section,
.model-dro-defaults-section {
  margin-top: 24px;
  padding-top: 20px;
  border-top: 1px solid var(--color-border);
}

.model-blocks-section > h4,
.model-lens-template-section > h4,
.model-linear-tolerance-section > h4,
.model-dro-defaults-section > h4 {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 0 0 12px;
  font-size: 15px;
  letter-spacing: 0.01em;
}

.model-blocks-section > h4::before,
.model-lens-template-section > h4::before,
.model-linear-tolerance-section > h4::before,
.model-dro-defaults-section > h4::before {
  content: "";
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: linear-gradient(135deg, var(--color-teal), var(--color-primary));
  flex-shrink: 0;
}

.model-blocks-container {
  display: flex;
  flex-direction: column;
  gap: 14px;
  margin-bottom: 10px;
}

/* Wraps the "+ Add Block" button below the block list (see
   #calibration-page-points-card in index.html). The top border/padding
   is a deliberate visual break so this reads as a separate "start a
   new block" action, not as part of whatever block card sits above it
   (e.g. right after using Prefill). */
.add-block-row {
  margin-top: 4px;
  padding-top: 14px;
  border-top: 1px dashed var(--color-border);
}

.customer-equipment-add-form {
  display: flex;
  flex-direction: column;
  gap: 10px;
  align-items: flex-start;
}

.customer-equipment-add-form .form-grid {
  width: 100%;
}

.customer-equipment-add-form .form-grid label:last-child {
  flex-direction: row;
  align-items: center;
  gap: 6px;
}

.customer-equipment-actions {
  display: flex;
  gap: 6px;
  flex-wrap: wrap;
}

.customer-equipment-due-date-edit {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}

.customer-equipment-due-date-edit .checkbox-label {
  display: inline-flex;
  flex-direction: row;
  align-items: center;
  gap: 4px;
  white-space: nowrap;
}

.customer-equipment-asset-id-input,
.customer-equipment-description-input,
.customer-equipment-due-date-edit input[type="date"] {
  max-width: 140px;
}

.model-block {
  background: var(--color-bg);
  box-shadow: none;
  border: 1px solid var(--color-border);
  /* Makes the points table's pinned Delete column (see .pin-last-col
     above) blend with THIS card's own gray background instead of
     defaulting to white. */
  --pin-col-bg: var(--color-bg);
}

.model-block .page-header {
  margin-bottom: 10px;
}

/* Per your explicit request ("the title boxes of the calibration
   blocks should have a white fill so its clear the box is
   editable") - these title fields sit directly on the block card's
   own gray background (.model-block above), so a transparent fill
   made them look like plain text instead of an editable field. They
   now stay filled white at rest, with the border only appearing on
   hover/focus so it's not just drawn as a divider line. Covers both
   the Model Catalog's block name field and the Calibration page's
   (same card, different field class - see calibration-block-card). */
.model-block .block-name-field,
.model-block .calibration-block-name-field {
  font-size: 15px;
  font-weight: 700;
  border: 1px solid transparent;
  border-radius: var(--radius);
  padding: 6px 8px;
  background: var(--color-surface);
  max-width: 320px;
}

.model-block .block-name-field:hover,
.model-block .block-name-field:focus,
.model-block .calibration-block-name-field:hover,
.model-block .calibration-block-name-field:focus {
  border-color: var(--color-border);
  background: var(--color-surface);
}

/* Per your explicit request ("clean up within the table to make it
   easier to follow") - a Model's Calibration Block points table sits
   right on the block's own grey background, so its rows and header
   used to blend into the surrounding controls with nothing to mark
   where the table starts. It's now a distinct white panel with its
   own tinted header row, and its number columns (Nominal/Min/Max/
   Uncertainty) are right-aligned with tabular figures so a long list
   of points lines up into real columns instead of a ragged left-
   aligned grid. */
.block-points-table {
  margin-top: 12px;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  /* This table's own background is white (unlike the grey .model-block
     it sits in) - its pinned last column (see .pin-last-col in the
     EMPLOYEE TABLE rules above) needs to match THAT, not the grey
     --pin-col-bg: var(--color-bg) .model-block sets for every other
     table inside it, or the sticky Delete column would show as a grey
     square against this table's now-white rows. */
  --pin-col-bg: var(--color-surface);
}

.block-points-table thead th {
  background: var(--color-surface-sunken);
}

.block-points-table th:nth-child(2),
.block-points-table th:nth-child(3),
.block-points-table th:nth-child(4),
.block-points-table th:nth-child(5) {
  text-align: right;
}

.block-points-table td:nth-child(2),
.block-points-table td:nth-child(3),
.block-points-table td:nth-child(4),
.block-points-table td:nth-child(5) {
  font-variant-numeric: tabular-nums;
}

.block-points-table td:nth-child(2) input,
.block-points-table td:nth-child(3) input,
.block-points-table td:nth-child(4) input,
.block-points-table td:nth-child(5) input {
  text-align: right;
  font-variant-numeric: tabular-nums;
}

/* The drag handle that lets a point be dragged to a new position in
   its block (see makePointRowDraggable() in app.js) - a narrow column
   with a "grab" cursor so it's obvious the row can be picked up from
   there, not just anywhere in it. */
.point-drag-handle {
  width: 20px;
  padding-left: 4px !important;
  padding-right: 0 !important;
  color: var(--color-text-muted);
  cursor: grab;
  user-select: none;
  font-size: 16px;
  text-align: center;
}

/* The row currently being dragged - faded so it's clear it's "picked
   up", while the other rows shift to show where it would land. */
.model-point-row.dragging {
  opacity: 0.4;
}

/* Same drag-handle treatment as .point-drag-handle above, reused for
   a calibration's own measurement points (see
   makeCalibrationPointRowDraggable() in app.js) - per your explicit
   request to be able to drag those rows around too. */
.calibration-point-drag-handle {
  width: 20px;
  padding-left: 4px !important;
  padding-right: 0 !important;
  color: var(--color-text-muted);
  cursor: grab;
  user-select: none;
  font-size: 16px;
  text-align: center;
}

.calibration-point-drag-col {
  width: 20px;
}

.calibration-point-row.dragging {
  opacity: 0.4;
}

/* Per your explicit request ("I also want to be able to slide the
   lens around ... from the models section to change order") - same
   drag-handle/dragging treatment as .point-drag-handle/.model-point-
   row.dragging above, reused for a Model's own Lens Template (see
   makeLensTemplateRowDraggable() in app.js). */
.model-lens-template-row.dragging {
  opacity: 0.4;
}

/* Same dragging treatment, for a specific gage's own Lens Checklist
   (see makeInstrumentLensChecklistRowDraggable() in app.js). */
.instrument-lens-checklist-row.dragging {
  opacity: 0.4;
}

/* Per your explicit request ("I also want to be able to move lens rows
   around by dragging them up and down to adjust order") - same dragging
   treatment, for a CALIBRATION's own Lens table (see
   makeCalibrationLensRowDraggable() in app.js). */
.optical-page-lens-row.dragging {
  opacity: 0.4;
}

/* SAFEGUARDING per your explicit request - flags a lens row on a
   gage's own Lens Checklist whose tolerance overrides the Model's own
   Lens Template, so it's never mistaken for the Model's value. See
   renderInstrumentLensChecklist() in app.js. */
.instrument-lens-checklist-override-badge {
  margin-left: 8px;
}

/* The Model's own Lens Template value, shown as plain reference text
   on a gage's Lens Checklist row while that lens isn't overriding it -
   per your explicit follow-up ("I hit 10x and it didn't match or pull
   from what I had in the model"), so it's visibly "inheriting the
   Model" rather than looking like a blank/broken field. See
   renderInstrumentLensChecklist() in app.js. */
.instrument-lens-checklist-model-value {
  color: var(--color-text-muted);
  font-style: italic;
}

/* Per your follow-up request ("can we make this look less busy") -
   this table used to shade EVERY cell sunken-grey by default and only
   light individual cells white when they held something editable (see
   the removed rule this replaces), so each row was a checkerboard of
   grey/white boxes before you even got to the borders/buttons inside
   them. Now that every input/select carries its own clear border and
   its own disabled-grey style (see the input/select rules above), the
   cell-level shading was redundant - it was marking "editable" twice.
   Dropped in favor of a single flat table background plus a very
   quiet zebra stripe on alternating ROWS (below), which helps you
   track one lens across its many columns without adding another layer
   of per-cell color. */
#optical-page-lens-table tbody tr:nth-child(even) td {
  background: var(--color-surface-sunken);
}

/* The calculated, read-only As Found/As Left Deviation cells - per
   your explicit request that entry be the READING (an editable
   input) while the raw deviation count is shown "greyed out" next to
   it instead, since it's now derived rather than typed in. */
.calibration-point-deviation-cell {
  color: var(--color-text-muted);
  background: var(--color-bg);
}

/* Highlights just the Test Point (Nominal) cell - NOT the whole row -
   when a point's current reading (As Left if entered, otherwise As
   Found) is out of tolerance. Per your explicit request: only the
   test point itself should go red, not the entire measurement row. */
/* Per your explicit request: the Nominal cell is no longer highlighted
   red on a failed point - the As Found/As Left Reading cell itself
   (below) is the only red indicator now. */

/* Per your explicit request: the As Found/As Left Reading cell itself
   turns red when THAT specific reading is out of tolerance. */
.calibration-point-reading-cell-fail {
  background: #fbe9e7 !important;
}
.calibration-point-reading-cell-fail input {
  background: #fbe9e7;
  color: #c62828;
  font-weight: 600;
}

/* Per your explicit request: yellow instead of red once this
   calibration is flagged/approved Limited Use - same amber family as
   the "Limited" badge and the certificate PDF, above. */
.calibration-point-reading-cell-limited {
  background: #fff3c4 !important;
}
.calibration-point-reading-cell-limited input {
  background: #fff3c4;
  color: #8a6d00;
  font-weight: 600;
}

/* Per your explicit request: a small "Copy As Found -> As Left" button
   sits right above the As Left Reading column, in its own header cell.
   The table is table-layout:fixed with narrow columns (see
   .calibration-points-table below), so this button must be allowed to
   WRAP onto a second line and shrink to the column's own width -
   white-space:nowrap (the default for a table header/button) was
   forcing it wider than its column and spilling text into the next
   column over ("As Found Deviation"). display:block on its own line,
   under the "As Left Reading" label, keeps it from ever sharing a
   line with that label either. */
.calibration-points-table th {
  overflow-wrap: break-word;
}
.calibration-copy-before-to-after-btn {
  display: block;
  margin: 4px auto 0;
  white-space: normal;
  overflow-wrap: break-word;
  max-width: 100%;
  font-size: 9px;
  line-height: 1.2;
  padding: 3px 4px;
}

/* Per your explicit request: the Points tables (Ungrouped Points and
   each Block's own table) must fit on one page with no horizontal
   scrollbar, even with the extra As Found/As Left Pass-Fail columns
   and the Copy button - so this is a tighter, compacted variant of
   the shared .employee-table look, scoped to just these two tables
   rather than changing every other table in the app. */
.calibration-points-table {
  min-width: 0;
  width: 100%;
  table-layout: fixed;
  font-size: 12px;
}
.calibration-points-table th {
  white-space: normal;
  line-height: 1.25;
  padding: 4px 3px;
  font-size: 10px;
  /* Per your request: these columns are narrow and the header titles
     wrap onto two lines, so the default left-aligned heading text (set
     by .employee-table th) sat noticeably left of the narrow input/text
     it was labeling. Centering the heading over its own column lines
     the title up with the point values below it. */
  text-align: center;
}
.calibration-points-table td {
  padding: 3px 3px;
  text-align: center;
}
.calibration-points-table .calibration-point-drag-col,
.calibration-points-table td.calibration-point-drag-col {
  text-align: left;
}
.calibration-points-table input,
.calibration-points-table select {
  min-width: 0;
  width: 100%;
  padding: 3px 4px;
  font-size: 12px;
  box-sizing: border-box;
}
.calibration-points-table .status-badge {
  padding: 2px 5px;
  font-size: 11px;
}
.calibration-points-table .calibration-point-drag-col {
  width: 18px;
}
.calibration-points-table .calibration-point-delete-btn {
  padding: 3px 6px;
  font-size: 11px;
  white-space: nowrap;
}

.model-change-requests-container {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin-bottom: 10px;
}

.model-change-request-row {
  background: var(--color-bg);
  border-radius: var(--radius);
  padding: 10px 12px;
}

.model-change-request-row p {
  margin: 0 0 4px;
}

.model-change-request-row .field-hint {
  margin-bottom: 8px;
}

/* ---------------------------------------------------------------------
   GAGES (nested under each Customer's card as a compact list of
   summary rows - viewing/editing an existing one, and adding a new
   one, both happen on their own dedicated pages instead; see
   buildInstrumentSummaryRow/renderInstrumentPage/
   renderAddInstrumentPage in app.js). Still called "instrument" in
   class names/IDs/code - "Gage" is just the name shown on screen.
   --------------------------------------------------------------------- */

.instruments-section-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 4px;
}

.instruments-section-header h4 {
  margin: 0;
}

/* The "(N)" gage count next to the "Gages" heading, per your request
   that the list show how many gages there are. */
.instruments-count {
  font-weight: 400;
  font-size: 13px;
  color: var(--color-text-muted);
}

/* Due-date-range + Active/Inactive filters, plus Export Excel/PDF, on
   the per-customer Gages tab - per your explicit request. Sits below
   the text search box; all three filters combine (AND) with each
   other and with the text search. */
.instruments-filter-row {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 14px;
  margin-top: 12px;
  padding-top: 12px;
  border-top: 1px solid var(--color-border);
}

.instruments-filter-field {
  display: flex;
  flex-direction: column;
  gap: 3px;
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--color-text-muted);
}

.instruments-filter-field input,
.instruments-filter-field select {
  padding: 6px 10px;
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  font-size: 14px;
  font-weight: 400;
  text-transform: none;
  letter-spacing: normal;
  color: var(--color-text);
}

/* The WS-001 and Full Work Form due-date panels on a customer's Gages
   tab (toggled by customer-create-field-service-forms-btn and
   customer-full-work-form-btn) - per your explicit request ("under the
   customer there should be the ability to pick their full list with
   the option of the date range"). Reuses .instruments-filter-field for
   the date inputs, same look as the filter row above. */
.customer-ws001-panel,
.customer-full-work-form-panel {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 14px;
  margin-top: 10px;
  padding: 12px;
  background: var(--color-surface-alt, #f6f6f6);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
}

.instruments-export-actions {
  display: flex;
  gap: 8px;
  margin-left: auto;
}

/* The "Print Blank Templates" page's list of blank field-work PDFs -
   per your explicit request ("lets have a new form, print blank
   templates" - "button i mean on the work forms home page"). Plain
   rows (not .home-tile cards) since there's nothing to preview, just
   a label and a View/Print button per template. */
.blank-templates-list {
  list-style: none;
  margin: 16px 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
  max-width: 560px;
}

.blank-template-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  padding: 12px 16px;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
}

.blank-template-row-label {
  font-size: 14px;
  font-weight: 600;
}

/* The Certifications page's "Search By <category> + term" row - a
   narrow category select paired with the same search box styling
   used everywhere else, per your explicit request that this page
   search by certificate #/Gage ID/serial #/customer as separate
   categories instead of one combined free-text box. */
.certifications-search-row {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 14px;
  margin-bottom: 12px;
}

.certifications-search-term-wrap {
  flex: 1;
  min-width: 240px;
}

/* Per-customer Gages table (tpl-customer-card's Gages tab) - shows a
   running row number, ID, Manufacturer, Model, Description, Serial #,
   Due, and Status, per your request. Reuses the same .employee-table
   base look as the global Gages search results and the Employees
   page. */
.customer-instruments-table {
  margin-top: 10px;
}

.instrument-summary-row {
  cursor: pointer;
}

.instrument-summary-row:hover {
  background: var(--color-bg);
}

.instrument-summary-index,
.instrument-summary-id {
  color: var(--color-text-muted);
  font-variant-numeric: tabular-nums;
}

/* An overdue-but-active gage's Due date, in red, per your request. */
.instrument-summary-due-overdue {
  color: var(--color-danger);
  font-weight: 700;
}

/* An inactive gage's whole row, greyed out and sorted to the bottom
   of the list (see the sort in loadAndRenderCustomerInstruments) -
   per your request that inactive gages read as "out of the way"
   rather than sitting inline with the active ones. Its Due date does
   NOT also get the red overdue treatment above, since an inactive
   gage being "overdue" isn't meaningful the way an active one's is. */
.instrument-summary-row-inactive {
  color: var(--color-text-muted);
  background: var(--color-bg);
}

.instrument-summary-row-inactive:hover {
  background: var(--color-border);
}

.instrument-summary-row-inactive .instrument-summary-due-overdue {
  color: inherit;
  font-weight: 400;
}

/* A clearer search box for the per-customer Gages list - a visible
   label above it plus a search icon inside it, per your request that
   the search bar be easier to spot as a search field. */
.search-icon-input {
  position: relative;
}

.search-icon-input .search-icon {
  position: absolute;
  top: 50%;
  left: 12px;
  transform: translateY(-50%);
  font-size: 13px;
  line-height: 1;
  pointer-events: none;
  opacity: 0.55;
}

.search-icon-input .search-input {
  padding-left: 32px;
}

.search-icon-input .search-input:focus {
  outline: none;
  border-color: var(--color-primary);
  box-shadow: 0 0 0 3px rgba(44, 95, 138, 0.15);
}

.instrument-model-readonly {
  background: var(--color-bg);
  border-radius: var(--radius);
  padding: 10px 14px;
  margin-bottom: 14px;
}

.instrument-model-summary {
  font-weight: 600;
  margin-bottom: 8px;
}

.instrument-blocks-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 13px;
}

.instrument-blocks-table th,
.instrument-blocks-table td {
  text-align: left;
  padding: 4px 8px;
  border-bottom: 1px solid var(--color-border);
}

.instrument-blocks-table th:first-child,
.instrument-blocks-table td:first-child {
  padding-left: 0;
}

/* The Tolerance/Unit override row at the bottom of the (grey,
   read-only-looking) model info panel above - per your explicit
   request that this area be editable. Its inputs get a white
   background so they read as clearly interactive against the grey
   panel, even though the panel itself still looks like an info box.
   Auto-filled from the picked model (see the modelSelect "change"
   handlers in app.js) but always editable/savable per gage - unlike
   the read-only per-block table above it, which still only ever
   reflects the Model Catalog. */
.instrument-override-grid {
  margin-top: 12px;
  padding-top: 12px;
  border-top: 1px solid var(--color-border);
}

.instrument-override-label {
  display: block;
  margin-bottom: 6px;
}

.instrument-override-fields {
  margin-top: 0;
}

.instrument-override-fields input,
.instrument-override-fields select {
  background: var(--color-surface);
}

/* Per your explicit request ("since this is a comparator the
   tolerance and unit override should be afiliiated with the model") -
   this wraps Tolerance Min/Max/Unit specifically so
   renderInstrumentModelReadonly() in app.js can hide all three as one
   group for an Optical Comparator gage, while Resolution/Procedure
   (still per-gage even there) stay put. "display: contents" makes the
   wrapper itself invisible to the grid - its 3 children lay out
   exactly as if they were still direct children of
   .instrument-override-fields - and the global "[hidden] { display:
   none !important }" rule (see the top of this file) still wins over
   that when JS sets .hidden, hiding the whole group correctly. */
.instrument-override-tolerance-fields {
  display: contents;
}

.instrument-override-grid .field-hint {
  margin: 6px 0 0;
}

/* The model's own recommended Tolerance Min/Max/Resolution/Unit,
   shown next to the override fields so it's always visible what the
   model ORIGINALLY specified, even after you've typed something
   different into the override fields above - per your explicit
   request. See renderInstrumentModelReadonly in app.js. */
.instrument-override-model-defaults {
  margin: 6px 0 0;
  font-size: 12px;
  color: var(--color-text-muted);
}

/* Optical Comparator category only - the four "Included on
   Certificate" checkboxes (see instrument-override-optical-includes
   in renderInstrumentModelReadonly in app.js). A distinct sub-section
   within .instrument-override-grid, so it gets its own top border/
   spacing rather than running straight into the fields above it. */
.instrument-override-optical-includes {
  margin-top: 12px;
  padding-top: 12px;
  border-top: 1px solid var(--color-border);
}

.instrument-override-optical-includes .form-grid-label-text {
  display: block;
  margin-bottom: 6px;
}

.instrument-override-optical-includes .checkbox-label {
  display: block;
  margin-bottom: 4px;
}

/* Per your explicit request ("I NEED a check box showing if the
   uncertainty will be on the cert or not") - this gage's own Report
   Uncertainty checkbox, sitting right above the Uncertainty statement
   it controls (see instrument-override-optical-report-uncertainty in
   renderInstrumentModelReadonly in app.js). */
.instrument-override-optical-report-uncertainty {
  display: block;
  margin: 10px 0 4px;
}

/* Per your explicit request ("could we imbed the check list for the
   lens right under this check box") - this gage's own Lens Checklist
   (see renderInstrumentLensChecklist in app.js), nested right under
   the Lens/Magnification checkbox above it rather than living in its
   own separate card further down the page. Indented + left-bordered
   so it reads as a sub-detail of that one checkbox, not a sibling of
   Micrometer/DRO/Angles below it. */
.instrument-page-lens-checklist-inline {
  margin: 4px 0 10px 24px;
  padding: 8px 0 8px 12px;
  border-left: 2px solid var(--color-border);
}

.instrument-page-lens-checklist-inline .field-hint {
  margin-top: 0;
}

/* Per your explicit request ("I need to also be able to select which
   lens the gauge has with the option to add a custom one which also
   selects the lens on this page") - this gage's own plain lens
   checklist (see renderInstrumentLensSelector in app.js), nested
   right under the Lens/Magnification checkbox above it, same
   indented/left-bordered "sub-detail" treatment as the old detailed
   Lens Checklist table used to have (.instrument-page-lens-checklist-
   inline above) before it was simplified away from this page. */
.instrument-page-lens-selector {
  margin: 4px 0 10px 24px;
  padding: 8px 0 8px 12px;
  border-left: 2px solid var(--color-border);
}

.instrument-page-lens-selector .field-hint {
  margin-top: 4px;
}

.instrument-page-lens-selector .form-grid {
  margin-top: 8px;
}

/* The preset lens checkboxes (5x/10x/20x/.../100x) - same checkbox-
   label look as "Included on Certificate" above it, but laid out as a
   wrapping row of short chips instead of one-per-line, since there
   are up to 9 of them and each label is only a couple characters. */
.instrument-page-lens-selector-presets {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 16px;
}

.instrument-page-lens-selector-presets .checkbox-label {
  margin-bottom: 0;
}

/* Any ADDED lens whose label isn't one of the standard presets (a
   custom one typed in below) - shown as its own small row with a
   Remove button, since there's no checkbox for it to uncheck. */
.instrument-page-lens-selector-custom-list {
  list-style: none;
  margin: 6px 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.instrument-page-lens-selector-custom-row {
  display: flex;
  align-items: center;
  gap: 8px;
}

.instrument-page-lens-selector-custom-row-label {
  font-size: 13px;
}

/* Rows on the Gages search page (tpl-instruments-search-page) - each
   one navigates straight to that gage's own dedicated page on click. */
.instrument-result-row {
  cursor: pointer;
}

.instrument-result-row:hover {
  background: var(--color-bg);
}

/* Generic clickable-row look, reused by the Customers/Equipment/Models
   "Show All" tables below the search box - same idea as
   .instrument-result-row above (the Gages search page). */
.clickable-row {
  cursor: pointer;
}

.clickable-row:hover {
  background: var(--color-bg);
}

/* The three "Show All" tables sit inside their .customer-landing
   spot, which centers/shrinks its content - let them use the page's
   normal full-width table look instead. */
.customer-landing .employee-table {
  margin-top: 12px;
  text-align: left;
}

/* The Calibration Procedures page (tpl-procedures-page/tpl-procedure-
   card) - each procedure's Title/Description, then its list of
   reference PDFs (tpl-procedure-document-row), one of which is
   "Active" - the one every other page's "View PDF" button opens. */
.procedure-card {
  margin-bottom: 12px;
}

.procedures-search-grid {
  margin-bottom: 16px;
}

.procedure-documents-section {
  margin-top: 10px;
}

.procedure-documents-label {
  margin: 0 0 4px;
}

.procedure-documents-list {
  list-style: none;
  margin: 0 0 8px;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.procedure-document-row {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 6px 10px;
  border: 1px solid var(--color-border);
  border-radius: 6px;
  font-size: 13px;
}

.procedure-document-row-main {
  display: flex;
  align-items: center;
  gap: 8px;
}

.procedure-document-name {
  flex: 1;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--color-text-muted);
}

/* Read-only "Version Rev C — effective 3/1/2026" line under a document
   row, and the Version/Effective Date inputs that replace it while
   editing - see buildProcedureDocumentRow() in app.js. */
.procedure-document-version-summary {
  margin: 0;
}

.procedure-document-edit-row {
  display: flex;
  align-items: flex-end;
  flex-wrap: wrap;
  gap: 8px;
  font-size: 12px;
}

.procedure-document-edit-row label {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

/* The Version/Effective Date fields next to "Add PDF" on a procedure
   card - filled in before picking a file, and sent along with the
   upload. */
.procedure-upload-row {
  display: flex;
  align-items: flex-end;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 6px;
}

.procedure-upload-row label {
  display: flex;
  flex-direction: column;
  gap: 2px;
  font-size: 12px;
}

.procedure-document-active-badge {
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--color-success, #1a7f37);
  border: 1px solid currentColor;
  border-radius: 4px;
  padding: 2px 6px;
}

/* Reused wherever a Procedure's reference PDF can be viewed inline
   next to a read-only Procedure display - the Model Catalog card, the
   Add/Edit Gage pages, and the Calibration Details card. */
.procedure-view-pdf-inline {
  margin-left: 8px;
}

/* Per your explicit request ("Under Models I want to include
   supporting document attachments") - the Model Catalog card's own
   manuals/tech specs/etc list (tpl-model-document-row), same visual
   shape as the Procedure document list above, just without an Active
   badge/Set Active button. */
.model-documents-section {
  margin-top: 10px;
}

.model-documents-list {
  list-style: none;
  margin: 0 0 8px;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.model-document-row {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 6px 10px;
  border: 1px solid var(--color-border);
  border-radius: 6px;
  font-size: 13px;
}

.model-document-row-main {
  display: flex;
  align-items: center;
  gap: 8px;
}

.model-document-name {
  flex: 1;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--color-text-muted);
}

.model-document-label-summary {
  margin: 0;
}

.model-document-edit-row {
  display: flex;
  align-items: flex-end;
  flex-wrap: wrap;
  gap: 8px;
  font-size: 12px;
}

.model-document-edit-row label {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

/* The Label field next to "+ Add Document" on a model card - filled in
   (optionally) before picking a file, and sent along with the upload. */
.model-upload-row {
  display: flex;
  align-items: flex-end;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 6px;
}

.model-upload-label-field {
  display: flex;
  flex-direction: column;
  gap: 2px;
  font-size: 12px;
}

/* Technician Notes log - mounted via mountInstrumentNotesSection() in
   app.js, on both a gage's own page (inside its own .card, added in
   the HTML there) and the Calibration page (embedded plainly under
   Findings, inside that same Calibration Details card - see
   tpl-calibration-page) - the top border/padding here is what
   separates it from Findings in that second, card-less case. */
.instrument-notes-section {
  border-top: 1px solid var(--color-border);
  margin-top: 16px;
  padding-top: 16px;
}

.instrument-notes-list {
  margin-top: 12px;
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.instrument-note-row {
  border-top: 1px solid var(--color-border);
  padding-top: 10px;
}

.instrument-note-meta {
  font-size: 13px;
  color: var(--color-text-muted);
  margin: 0 0 4px;
}

.instrument-note-text {
  margin: 0;
  white-space: pre-wrap;
}

/* Parts Log - mounted via mountInstrumentPartsLogSection() in app.js,
   per your explicit request now embedded directly under the Parts
   Installed field on the Optical Comparator calibration page (inside
   the same "Comments / Parts Installed" card, not its own - see
   tpl-instrument-parts-log-section) - same top border/margin treatment
   .instrument-notes-section uses for the same "embedded, not its own
   card" situation. */
.instrument-parts-log-section {
  border-top: 1px solid var(--color-border);
  margin-top: 16px;
  padding-top: 16px;
}

.instrument-parts-log-list {
  margin-top: 12px;
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.instrument-part-log-row {
  border-top: 1px solid var(--color-border);
  padding-top: 10px;
}

.instrument-part-log-meta {
  font-size: 13px;
  color: var(--color-text-muted);
  margin: 0 0 4px;
}

.instrument-part-log-text {
  margin: 0;
  white-space: pre-wrap;
}

/* Per your explicit request: Findings' typed text reads at the same
   size as Technician Notes' text (16px, the browser default) rather
   than the smaller 13px every other form-grid textarea now uses -
   Findings is what actually prints on the certificate, so it stays
   larger/easier to read while writing it. */
.calibration-page-findings-input {
  font-size: 16px;
}

/* --------------------------------------------------------------------
   BATCH CERTIFICATION - the batch bar shown at the top of a
   calibration page when it belongs to a batch, the batch picker/PO
   step pages, and the batch review page. See renderCalibrationBatchBar,
   renderBatchCustomerPickerPage, renderBatchPoPage,
   renderBatchAddGagePage, and renderBatchReviewPage in app.js.
   -------------------------------------------------------------------- */
.calibration-batch-bar {
  border-left: 4px solid var(--color-primary);
  padding: 12px 16px;
  margin-bottom: 16px;
}

.calibration-batch-bar-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
}

#calibration-page-batch-bar-label {
  font-weight: 600;
  font-size: 14px;
}

.calibration-batch-bar-actions {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
}

.calibration-batch-bar-tabs {
  display: flex;
  gap: 6px;
  flex-wrap: wrap;
  margin-top: 10px;
}

.calibration-batch-tab-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  background: var(--color-bg);
  border: 1px solid var(--color-border);
  border-radius: 999px;
  padding: 5px 12px;
  font-size: 12px;
  font-weight: 600;
  color: var(--color-text-muted);
  cursor: pointer;
  transition: background 0.15s ease, color 0.15s ease, border-color 0.15s ease;
}

.calibration-batch-tab-btn:hover {
  color: var(--color-text);
}

.calibration-batch-tab-btn.active {
  background: var(--color-surface);
  color: var(--color-primary-dark);
  border-color: var(--color-primary);
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12);
}

.calibration-batch-tab-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--color-text-muted);
  flex-shrink: 0;
}

.calibration-batch-tab-dot.draft { background: #b0b6bd; }
.calibration-batch-tab-dot.signed { background: #4a90d9; }
.calibration-batch-tab-dot.limited { background: #c99a00; }
.calibration-batch-tab-dot.failed { background: #c0392b; }
.calibration-batch-tab-dot.approved { background: #2e8b57; }

/* Batch customer/PO picker pages - reuse the plain "landing" search
   look already used by the Customers page/Certification picker (see
   .customer-landing), just under a distinct id per page so each can
   still be targeted individually. */
.batch-picker-page .customer-landing-hint {
  margin-bottom: 12px;
}

.batch-po-page-customer-label {
  font-weight: 600;
  margin-bottom: 4px;
}

/* Which customer a batch is for, shown as a bold colored chip - per
   your explicit request ("I need better clarity of which customer the
   batch is for"). Reused wherever a batch shows up: the Batch Review
   page's title, the Add Gage page's header, and the batch bar on the
   Calibration page (see batch-review-customer-badge/batch-add-gage-
   label/calibration-page-batch-bar-label in app.js) - same look every
   time so it's immediately recognizable as "the customer", not just
   another piece of text in the label. */
.batch-customer-badge {
  display: inline-block;
  padding: 4px 12px;
  border-radius: 999px;
  background: var(--color-primary-light);
  color: var(--color-primary-dark);
  font-size: 15px;
  font-weight: 700;
}

/* Per your explicit request ("can you have this show if it is also
   part of a batch") - a small clickable pill next to a Gage ID on the
   Certifications page (both the search results table and Certificate
   History), shown only for a cert that belongs to a batch. Deliberately
   smaller/quieter than .batch-customer-badge above (that one's meant to
   stand out as a page's main subject; this is a secondary, per-row
   hint) - see buildCertificationHistoryRow()/renderCertificationsTable()
   in app.js. */
.cert-batch-badge {
  display: inline-block;
  margin-left: 6px;
  padding: 1px 8px;
  border-radius: 999px;
  border: none;
  background: var(--color-primary-light);
  color: var(--color-primary-dark);
  font-size: 11px;
  font-weight: 700;
  cursor: pointer;
}
.cert-batch-badge:hover {
  background: var(--color-primary);
  color: #fff;
}

/* Per your explicit request ("If they are a batch I need the batch
   number. Maybe make it its own column") - the Certifications page's
   (and the Certificate History tables') own dedicated Batch column.
   Plain underlined link text showing the real "BATCH-#####", not a
   pill, since it now has a whole column to itself rather than
   crowding the Gage ID cell. Starts as inert "—" text (no border/
   padding so it reads as plain, non-interactive text) and only turns
   into a real link once JS confirms this row belongs to a batch - see
   buildCertificationHistoryRow()/renderCertificationsTable() in
   app.js. */
.cert-batch-link {
  background: none;
  border: none;
  padding: 0;
  font: inherit;
  color: var(--color-text-muted);
  cursor: default;
}
.cert-batch-link.cert-batch-link-active {
  color: var(--color-primary);
  text-decoration: underline;
  cursor: pointer;
}
.cert-batch-link.cert-batch-link-active:hover {
  color: var(--color-primary-dark);
}

/* Per your explicit request ("If its from a batch then I'd like for
   this to reference the batch and the quantity vs individual ones")
   - the Certs Approval queue's own batch pill (one combined row per
   batch instead of one row per gage). Same pill look as
   .cert-batch-badge above, but NOT a button/clickable here (the row
   already has its own "Review Batch" button) so no pointer cursor or
   hover state. */
.certs-approval-batch-cell {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 2px;
}
.certs-approval-batch-label {
  display: inline-block;
  padding: 1px 8px;
  border-radius: 999px;
  background: var(--color-primary-light);
  color: var(--color-primary-dark);
  font-size: 11px;
  font-weight: 700;
}
.certs-approval-batch-count {
  font-size: 12px;
}

.batch-review-title-group {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
}

/* Batch review page - "Review All" summary table plus a segmented
   tab strip (Review All / one per cert), same visual family as
   .customer-tabs above. */
.batch-review-tabs {
  display: flex;
  gap: 2px;
  width: fit-content;
  max-width: 100%;
  overflow-x: auto;
  margin-top: 12px;
  margin-bottom: 20px;
  padding: 4px;
  background: var(--color-bg);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
}

.batch-review-tab-btn {
  background: none;
  border: none;
  border-radius: 6px;
  padding: 8px 16px;
  font-size: 13px;
  font-weight: 600;
  color: var(--color-text-muted);
  cursor: pointer;
  white-space: nowrap;
  transition: background 0.15s ease, color 0.15s ease, box-shadow 0.15s ease;
}

.batch-review-tab-btn:hover {
  color: var(--color-text);
}

.batch-review-tab-btn.active {
  background: var(--color-surface);
  color: var(--color-primary-dark);
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12);
}

.batch-review-summary-table td,
.batch-review-summary-table th {
  vertical-align: middle;
}

.batch-review-bulk-actions {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
  margin: 16px 0;
}

/* The "PO #" display/edit row just under the batch title (see
   wireBatchReviewPoEdit() in app.js) - a plain inline row either way,
   matching .batch-review-bulk-actions' own spacing. */
.batch-review-po-row {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 4px 0 12px;
  font-size: 14px;
  color: var(--color-text);
}

.batch-review-po-row label {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 14px;
}

.batch-review-action-results {
  margin-top: 12px;
}

.batch-review-action-results ul {
  margin: 6px 0 0;
  padding-left: 20px;
}

.batch-review-action-results li {
  font-size: 13px;
  color: var(--color-text-muted);
}
