/* Fulcrum PMA — shared styling.
   Purple and Inter carry over from app.fulcrum360.com so the two products read
   as one family; the layout is denser here because this page is a table. */

/* ─── Skins ───────────────────────────────────────────────────────────────
   Three palettes, chosen in the rail and remembered per browser.

   There is no prefers-color-scheme block: a script in <head> resolves
   "system" to an explicit data-theme before the first paint, so every rule
   below keys off one attribute. That avoids maintaining the dark tokens
   twice — once for the media query and once for the explicit choice — which
   is exactly how the three scattered dark blocks this replaced fell out of
   step with each other.

   :root carries the default (Fulcrum) so the page is still correct if the
   script never runs. */
:root,
:root[data-theme="fulcrum"] {
  /* Brand. Constant across skins — the logo does not change colour. */
  --purple: #65318F;
  --purple-light: #7d3fa8;
  --purple-ink: #4a2469;
  /* Sampled from the logo artwork itself — #F3991F is the triangle's orange,
     40k pixels of it. The main app hard-codes #F29820, which is the same
     colour to the eye; this is the source rather than a copy of a copy. */
  --orange: #F3991F;
  --orange-hover: #dd8710;

  --rail-bg: #4a2469;
  --paper: #fbfaf8;
  --rule: #ece9e4;
  --rule-strong: #ddd9d2;
  --group-open: #f5f1f9;

  --bg: #ffffff;
  --bg-secondary: #f8f9fa;
  --bg-raised: #ffffff;
  --text: #1a1a2e;
  --text-secondary: #64748b;
  --border: #e2e8f0;

  --link: #65318F;
  --pn-ink: #65318F;
  --th-ink: #4a2469;
  --header-bg: linear-gradient(135deg, #e8eaed 0%, #f1f3f5 100%);
  --header-ink: #2c3e50;
  --logo-chip: transparent;

  --amber: #b45309;
  --amber-bg: #fef3c7;
  --green: #15803d;
  --green-bg: #dcfce7;
  --red: #dc2626;
  --radius: 6px;
}

/* Slate — the same layout without the purple ground, for people who stare at
   this all day. Purple is kept for part numbers and links so a record still
   looks like a Fulcrum record. */
:root[data-theme="slate"] {
  --rail-bg: #2f3542;
  --paper: #f7f8fa;
  --rule: #e6e9ef;
  --rule-strong: #d7dce5;
  --group-open: #eef1f6;

  --bg: #ffffff;
  --bg-secondary: #f2f4f8;
  --bg-raised: #ffffff;
  --text: #1a1d24;
  --text-secondary: #5b6470;
  --border: #dfe3ea;

  --link: #65318F;
  --pn-ink: #65318F;
  --th-ink: #2f3542;
  --header-bg: linear-gradient(135deg, #e9ecf1 0%, #f3f5f8 100%);
  --header-ink: #2f3542;
  --logo-chip: transparent;
}

:root[data-theme="dark"] {
  color-scheme: dark;
  /* A shade below the light rail: the same #4a2469 against a dark page reads
     as a lit panel rather than furniture. */
  --rail-bg: #3a1d52;
  --paper: #16151f;
  --rule: #2a2838;
  --rule-strong: #3a3750;
  --group-open: #221d33;

  --bg: #12121f;
  --bg-secondary: #1a1a2e;
  --bg-raised: #1f1f38;
  --text: #e7e7ee;
  --text-secondary: #9aa3b2;
  --border: #2f3350;

  --link: #b98fdd;
  --pn-ink: #b98fdd;
  --th-ink: #cbb3e0;
  --header-bg: linear-gradient(135deg, #201f2b 0%, #262533 100%);
  --header-ink: #d8d8e2;
  --logo-chip: #ffffff;

  --amber: #fbbf24;
  --amber-bg: #3b2f10;
  --green: #4ade80;
  --green-bg: #14311f;
  --red: #f87171;
}

* { margin: 0; padding: 0; box-sizing: border-box; }

body {
  font-family: Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  background: var(--bg);
  color: var(--text);
  font-size: 14px;
  -webkit-font-smoothing: antialiased;
}

a { color: var(--link); }

code {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 0.9em;
  background: var(--bg-secondary);
  padding: 0.1em 0.35em;
  border-radius: 3px;
}

/* ─── Header ───────────────────────────────────────────────────────────────
   Lifted from app.fulcrum360.com so the two products share one chrome: the
   light grey gradient, the 75px logo, the rounded translucent search box with
   its magnifier, and the bordered pill buttons. The values below are the main
   app's own, not approximations of them.

   It stays light in dark mode because the main app's default skin does — its
   header is a fixed gradient that the dark theme never overrides. */
.header {
  background: var(--header-bg);
  color: var(--header-ink);
  padding: 0.9rem 1.5rem;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.12);
  position: relative;
  z-index: 100;
  flex-shrink: 0;
}
/* The PMA label is set on the same baseline as the FULCRUM 360 wordmark, so
   the two read as one lockup rather than as a caption floating beside a
   picture. Getting there is geometry, not eyeballing:

   `align-items: baseline` puts the label's alphabetic baseline on the image's
   baseline, and an inline replaced element's baseline is its bottom edge — so
   the label lands at the very bottom of the artwork. The wordmark's own
   baseline was measured from the PNG's pixels (its ink spans y 591..746 of
   1064) at 70.1% of the image height, i.e. 29.9% up from the bottom. Lifting
   the label by exactly that much lands it on the wordmark.

   Doing it this way rather than with a nudged margin means the alignment is
   independent of the label's font size and survives a change to --logo-h. */
:root { --logo-h: 92px; }
.logo { display: flex; align-items: baseline; gap: 1rem; text-decoration: none; }
.logo-img {
  height: var(--logo-h); width: auto; display: block;
  /* The FULCRUM 360 wordmark is black. On the light skins it sits straight on
     the header; on dark it needs a chip or it disappears. box-sizing keeps
     --logo-h the artwork's height either way, so the baseline maths below
     does not change with the skin. */
  background: var(--logo-chip); box-sizing: content-box;
}
:root[data-theme="dark"] .logo-img { border-radius: 6px; padding: 5px 10px; }
/* The chip pushes the image's bottom edge — its baseline — down by its
   padding, so the label follows it down by the same 5px. */
:root[data-theme="dark"] .logo-product { top: calc(var(--logo-h) * -0.299 - 5px); }
/* Sized against the wordmark, not against the header. FULCRUM 360 renders a
   10.5px cap at --logo-h:75px; at 1.5rem PMA was a 17px cap, 62% taller, which
   read as a separate label parked next to the logo. 1.15rem lands ~12px — a
   peer of the wordmark, still a shade more prominent because it is the
   product name. Letter-spacing echoes the wordmark's own wide tracking. */
.logo-product {
  color: var(--purple); font-size: 1.15rem; font-weight: 700; letter-spacing: 0.06em;
  line-height: 1;
  position: relative;
  top: calc(var(--logo-h) * -0.299);
}

/* Search box — the main app's .search-container / .search-input. */
/* The container is the flex item; the BOX is what the magnifier and the
   typeahead menu position against, so the caption underneath cannot shift
   either of them. */
.search-container { flex: 1; max-width: 500px; margin: 0 1rem; }
.search-box { position: relative; }
.search-caption {
  margin: 5px 2px 0; font-size: 11.5px; color: #5b6470; text-align: center;
}
.search-input {
  width: 100%;
  padding: 0.7rem 2.5rem 0.7rem 1rem;
  border: none;
  border-radius: 12px;
  font-size: 1rem;
  font-family: inherit;
  background: rgba(255, 255, 255, 0.95);
  color: #000;
  backdrop-filter: blur(10px);
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
  transition: all 0.3s ease;
}
.search-input:focus {
  outline: none;
  box-shadow: 0 6px 20px rgba(242, 152, 32, 0.3);
  transform: translateY(-1px);
}
.search-icon {
  position: absolute; right: 1rem; top: 50%; transform: translateY(-50%);
  color: var(--purple); font-size: 1.25rem; pointer-events: none;
}
.search-dropdown {
  position: absolute; top: 100%; left: 0; right: 0;
  background: var(--bg-raised);
  border: 1px solid var(--border);
  border-radius: 8px;
  margin-top: 4px;
  max-height: 320px;
  overflow-y: auto;
  z-index: 1000;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.15);
}
.search-result {
  padding: 0.6rem 1rem; cursor: pointer;
  display: flex; align-items: center; gap: 0.75rem;
  border-bottom: 1px solid var(--border);
  transition: background 0.15s;
}
.search-result:last-child { border-bottom: none; }
.search-result:hover, .search-result.active { background: var(--bg-secondary); }
.search-result-label {
  font-weight: 600; font-size: 0.9rem; color: var(--purple);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace; white-space: nowrap;
}
.search-result-desc {
  font-size: 0.8rem; color: var(--text-secondary);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* Pushed right so the counts line up down the list. */
.search-result-count {
  margin-left: auto; font-size: 0.72rem; color: var(--text-secondary); white-space: nowrap;
}
.search-loading {
  padding: 0.75rem 1rem; font-size: 0.85rem; color: var(--text-secondary); text-align: center;
}

.header-actions { display: flex; gap: 0.6rem; align-items: center; font-size: 0.8rem; }
/* Signed out: the two buttons in a row, the tier pill centred beneath them. */
.signed-out { display: flex; flex-direction: column; align-items: center; gap: 0.35rem; }
.signed-out .header-btns { display: flex; gap: 0.6rem; }
.who { color: var(--header-ink); max-width: 18ch; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* ─── Account menu ───────────────────────────────────────────────────────
   One control where there used to be four. The trigger shows who you are;
   everything you might do about it is behind it, because none of it is
   frequent enough to earn a permanent place beside the search box. */
.account { position: relative; }
.account-btn { display: inline-flex; align-items: center; gap: 0.4rem; }
.account-name { max-width: 16ch; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.account-caret { font-size: 0.7em; opacity: 0.7; }

.account-menu {
  position: absolute; top: calc(100% + 6px); right: 0; z-index: 1100;
  min-width: 15rem;
  background: var(--bg-raised); color: var(--text);
  border: 1px solid var(--border); border-radius: 8px;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.18);
  overflow: hidden;
}
.account-head {
  padding: 0.7rem 0.9rem; border-bottom: 1px solid var(--border);
  background: var(--bg-secondary);
}
.account-email { font-size: 0.82rem; font-weight: 600; word-break: break-all; }
.account-company { font-size: 0.75rem; color: var(--text-secondary); margin-top: 0.1rem; }
.account-head .tier { margin-top: 0.4rem; display: inline-block; }

.account-item {
  display: block; width: 100%; text-align: left;
  padding: 0.55rem 0.9rem; font-size: 0.82rem; font-weight: 500;
  background: none; border: none; border-radius: 0;
  color: var(--text); text-decoration: none; white-space: nowrap;
}
.account-item:hover { background: var(--bg-secondary); }
.account-item + .account-item { border-top: 1px solid var(--border); }

/* The main app's .header-btn: a white pill with a 2px border. */
.header-btn {
  padding: 0.5rem 1rem;
  border: 2px solid #d0d5dd;
  background: #fff;
  color: var(--header-ink);
  border-radius: 8px;
  cursor: pointer;
  font-family: inherit; font-size: 0.85rem; font-weight: 600;
  white-space: nowrap; text-decoration: none;
  transition: all 0.2s ease;
}
/* :not(.primary) matters: this selector outranks .header-btn.primary, so
   without it the dark skin repainted the orange Sign in button grey. */
:root[data-theme="dark"] .header-btn:not(.primary) { background: #2f2e3d; border-color: #45435a; }
:root[data-theme="dark"] .header-btn:not(.primary):hover { background: #3a3850; }
:root[data-theme="dark"] .search-input { background: rgba(255,255,255,0.08); color: #e7e7ee; }
:root[data-theme="dark"] .search-input::placeholder { color: #8b8aa0; }
:root[data-theme="dark"] .tier { background: #2f2e3d; border-color: #45435a; }
:root[data-theme="dark"] .search-caption { color: #9a99ad; }
.header-btn:hover { background: #f0f0f0; transform: translateY(-1px); box-shadow: 0 2px 8px rgba(0,0,0,0.1); }
.header-btn.primary { background: var(--orange); border-color: var(--orange); color: #2c3e50; }
.header-btn.primary:hover { background: var(--orange-hover); border-color: var(--orange-hover); }

.tier {
  font-size: 0.65rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.05em;
  padding: 0.16rem 0.5rem; border-radius: 999px;
  background: #fff; color: var(--text-secondary); border: 1px solid #d0d5dd;
}
.tier-pro, .tier-owner { background: var(--purple); color: #fff; border-color: var(--purple); }

/* ─── Buttons ────────────────────────────────────────────────────────── */
button, .btn-solid, .btn-ghost, .link-btn {
  font-family: inherit; font-size: 0.8rem; font-weight: 600;
  border-radius: var(--radius); cursor: pointer; white-space: nowrap;
  text-decoration: none; border: 1px solid transparent;
  padding: 0.45rem 0.9rem; transition: background 0.15s, opacity 0.15s;
}
.btn-solid { background: var(--purple); color: #fff; display: inline-block; }
.btn-solid:hover { background: var(--purple-light); }
.btn-ghost { background: transparent; color: var(--text); border-color: var(--border); }
.btn-ghost:hover:not(:disabled) { background: var(--bg-secondary); }
.sm { padding: 0.3rem 0.6rem; font-size: 0.75rem; }
button:disabled, .btn-ghost:disabled, [aria-disabled="true"] { opacity: 0.45; cursor: not-allowed; }
.lock-hint {
  font-size: 0.65rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em;
  color: var(--purple); text-decoration: none; border: 1px solid var(--border);
  padding: 0.15rem 0.4rem; border-radius: 999px;
}

/* ─── Upgrade bar ────────────────────────────────────────────────────── */
.upgrade {
  display: flex; align-items: center; justify-content: space-between; gap: 1rem;
  flex-wrap: wrap;
  padding: 0.6rem 1.25rem; font-size: 0.8rem;
  background: var(--bg-secondary); border-bottom: 1px solid var(--border);
}
.upgrade-warn { background: var(--amber-bg); color: var(--amber); }
.upgrade-warn a.btn-solid { background: var(--amber); }
.meter { color: var(--text-secondary); }

/* ─── Search bar ─────────────────────────────────────────────────────── */
.search-bar {
  padding: 0.75rem 1.25rem;
  background: var(--bg-secondary);
  border-bottom: 1px solid var(--border);
  display: flex; gap: 0.6rem; align-items: flex-end; flex-wrap: wrap;
}
.search-field { display: flex; flex-direction: column; gap: 0.25rem; flex: 1; min-width: 150px; position: relative; }
.search-field label, .tool label {
  font-size: 0.63rem; font-weight: 700; color: var(--text-secondary);
  text-transform: uppercase; letter-spacing: 0.04em;
}
.search-field input, .tool input {
  padding: 0.48rem 0.6rem; border: 1px solid var(--border); border-radius: var(--radius);
  font-size: 0.82rem; font-family: inherit; background: var(--bg); color: var(--text);
  outline: none; width: 100%;
}
.search-field input:focus, .tool input:focus, .search-field select:focus {
  border-color: var(--purple); box-shadow: 0 0 0 2px rgba(101,49,143,0.18);
}
.search-field select {
  padding: 0.48rem 0.6rem; border: 1px solid var(--border); border-radius: var(--radius);
  font-size: 0.82rem; font-family: inherit; background: var(--bg); color: var(--text);
  outline: none; cursor: pointer; width: 100%;
}
/* The two searches are unrelated inputs sharing a row, so each keeps a fixed
   footprint rather than flexing into the other's space. */
.search-field.name-field { flex: 0 1 20rem; }
.search-field.model-field { flex: 0 1 13rem; }
.search-field.nha-field { flex: 0 1 auto; }
.search-field .inline { display: flex; gap: 0.4rem; }
.search-field .inline input { width: 14rem; }
.search-field .inline button { white-space: nowrap; }
.search-field label .lock-hint { margin-right: 0.5rem; vertical-align: middle; }
.search-divider { width: 1px; align-self: stretch; background: var(--border); margin: 0 0.6rem; }
.search-bar .clear-btn { background: transparent; color: var(--text-secondary); border-color: var(--border); font-weight: 500; }
.search-bar > button { align-self: flex-end; }
.search-bar > button[type="submit"] { background: var(--purple); color: #fff; }
.search-bar > button[type="submit"]:hover:not(:disabled) { background: var(--purple-light); }

/* ─── Filter panel + results ─────────────────────────────────────────── */
/* Searches run across the top and START a result set; filters sit down the
   left and NARROW it. The panel is sticky so the filters stay in reach while
   a long result list scrolls, and it must not clip its own overflow — the
   holder and model suggestion lists hang below their fields. */
.layout { display: flex; align-items: flex-start; }
.filters {
  flex: 0 0 15rem; width: 15rem;
  position: sticky; top: 0;
  padding: 0.9rem 1rem 1.25rem;
  border-right: 1px solid var(--border);
  display: flex; flex-direction: column; gap: 0.85rem;
}
.filters-head { display: flex; align-items: baseline; justify-content: space-between; }
.filters-head h3 {
  font-size: 0.7rem; font-weight: 700; color: var(--text-secondary);
  text-transform: uppercase; letter-spacing: 0.06em;
}
.filters-head h3 .count-badge { margin-left: 0.35rem; vertical-align: middle; }
.link-btn {
  background: none; border: none; padding: 0; color: var(--purple);
  font-size: 0.72rem; font-weight: 600; cursor: pointer; font-family: inherit;
}
.link-btn:hover { text-decoration: underline; }
.filters .search-field { flex: none; min-width: 0; width: 100%; }
.results { flex: 1; min-width: 0; }
@media (max-width: 860px) {
  .layout { flex-direction: column; }
  .filters { position: static; width: auto; flex: none; border-right: none; border-bottom: 1px solid var(--border); align-self: stretch; }
}

/* Chips */
.chips {
  display: flex; flex-wrap: wrap; gap: 0.3rem; align-items: center;
  border: 1px solid var(--border); border-radius: var(--radius);
  padding: 0.2rem 0.3rem; background: var(--bg); min-height: 2.1rem;
}
.chips:focus-within { border-color: var(--purple); box-shadow: 0 0 0 2px rgba(101,49,143,0.18); }
.chips input { border: none !important; box-shadow: none !important; flex: 1; min-width: 7rem; padding: 0.25rem; }
.chip {
  display: inline-flex; align-items: center; gap: 0.3rem;
  background: var(--purple); color: #fff; border-radius: 999px;
  padding: 0.15rem 0.3rem 0.15rem 0.6rem; font-size: 0.72rem; max-width: 22ch;
}
.chip button { background: none; border: none; color: #fff; cursor: pointer; padding: 0 0.25rem; font-size: 0.9rem; line-height: 1; }

.suggestions {
  position: absolute; top: 100%; left: 0; right: 0; z-index: 20;
  background: var(--bg-raised); border: 1px solid var(--border); border-radius: var(--radius);
  box-shadow: 0 8px 24px rgba(0,0,0,0.14); list-style: none; max-height: 16rem; overflow-y: auto;
}
.suggestions li { padding: 0.4rem 0.6rem; font-size: 0.78rem; cursor: pointer; }
.suggestions li:hover, .suggestions li.active { background: var(--bg-secondary); }
.suggestions b { color: var(--purple); }
/* Sticky so the multi-select hint stays visible while scrolling a long list. */
.suggestions .suggest-hint {
  position: sticky; bottom: 0;
  background: var(--bg-secondary); border-top: 1px solid var(--border);
  color: var(--text-secondary); font-size: 0.68rem; cursor: default;
  padding: 0.35rem 0.6rem;
}
.suggestions .suggest-hint:hover { background: var(--bg-secondary); }

/* ─── Tools row ──────────────────────────────────────────────────────── */
.tools {
  display: flex; gap: 1rem; align-items: flex-end; flex-wrap: wrap;
  padding: 0.6rem 1.25rem; border-bottom: 1px solid var(--border);
}
.tool { display: flex; gap: 0.4rem; align-items: center; flex-wrap: wrap; }
.tool label { align-self: center; }
.tool input { width: 14rem; }
.tool.right { margin-left: auto; }

/* ─── Notices ────────────────────────────────────────────────────────── */
.notice {
  margin: 1rem 1.25rem; padding: 0.8rem 1rem; border-radius: var(--radius);
  display: flex; align-items: center; justify-content: space-between; gap: 1rem;
  flex-wrap: wrap; font-size: 0.85rem;
  background: var(--bg-secondary); border: 1px solid var(--border);
}
.notice-limit, .notice-upgrade { background: var(--amber-bg); color: var(--amber); border-color: transparent; }
.notice-error { border-color: var(--red); color: var(--red); }
/* Data-quality caveats read as information, not as a warning to act on —
   an orange rule rather than a filled amber block. */
.notice-caveat {
  display: block; line-height: 1.55; font-size: 0.8rem;
  background: var(--bg-secondary); border-color: var(--border);
  border-left: 3px solid var(--orange);
}

.results-info { padding: 0.6rem 1.25rem; font-size: 0.8rem; color: var(--text-secondary); border-bottom: 1px solid var(--border); }

/* ─── Table ──────────────────────────────────────────────────────────── */
/* clip, not auto: the column widths are percentages and every cell either
   wraps or ellipses, so nothing is meant to sit outside the table — a
   sideways scrollbar here is a symptom, never a feature. clip (rather than
   hidden) avoids making this a scroll container, which would otherwise trap
   the page's own scrolling. */
.table-wrap { overflow-x: clip; }

/* The table fits the viewport: every column is a share of the table width, the
   shares add up to 100%, and the table is never wider than its container. The
   earlier fixed pixel widths summed to 1966px and forced a sideways scroll on
   any ordinary screen, which hid Supp, Date and Status behind the scrollbar.

   Fixed layout is kept so columns do not re-measure and jump between result
   sets. The shares favour the identity columns people read first (part number,
   name, what it replaces) and give the short-content columns only what they
   need: Supp holds values like "4 Amended", Date is ISO, Status is one word.

   Long text wraps rather than clipping — a part number or holder name that is
   cut off with an ellipsis is data the reader cannot see. The one floor is
   min-width: below ~1000px the narrow columns would no longer hold a date, so
   only then does the table scroll inside .table-wrap. The table sits beside
   the 15rem filter panel, so a 1280px screen leaves it ~1040px. */
.results-table {
  width: 100%;
  min-width: 1000px;
  table-layout: fixed;
  border-collapse: collapse;
  font-size: 0.8rem;
}
.results-table th:nth-child(1),  .results-table td:nth-child(1)  { width: 13%; }  /* PMA Part Number     */
.results-table th:nth-child(2),  .results-table td:nth-child(2)  { width: 14%; }  /* Part Name           */
.results-table th:nth-child(3),  .results-table td:nth-child(3)  { width: 11%; }  /* OEM / Replaced Part */
.results-table th:nth-child(4),  .results-table td:nth-child(4)  { width: 11%; }  /* PMA Company         */
.results-table th:nth-child(5),  .results-table td:nth-child(5)  { width: 8%; }   /* Supplement          */
.results-table th:nth-child(6),  .results-table td:nth-child(6)  { width: 9%; }   /* Date                */
.results-table th:nth-child(7),  .results-table td:nth-child(7)  { width: 12%; }  /* Approval            */
.results-table th:nth-child(8),  .results-table td:nth-child(8)  { width: 11%; }  /* Models              */
.results-table th:nth-child(9),  .results-table td:nth-child(9)  { width: 9%; }   /* Status              */
.results-table th:nth-child(10), .results-table td:nth-child(10) { width: 2%; }   /* expand              */
/* A group header spans the first four columns and the detail row spans all
   ten, so neither may take a width from the rules above. */
.results-table td[colspan] { width: auto; }
.results-table thead th {
  position: sticky; top: 0; z-index: 5;
  background: var(--bg-secondary); padding: 0.5rem 0.75rem; text-align: left;
  font-weight: 700; color: var(--text-secondary); font-size: 0.68rem;
  text-transform: uppercase; letter-spacing: 0.04em;
  border-bottom: 2px solid var(--border); vertical-align: bottom;
}
/* Ten columns share the width, so a label like "OEM / Replaced Part" wraps
   to a second line rather than being cut off mid-word, and the header cells
   run tighter than the body so "Supplement" still fits its 8% at 1280px. */
.results-table thead th { white-space: normal; padding-left: 0.5rem; padding-right: 0.5rem; letter-spacing: 0.02em; }
.results-table th.sortable { cursor: pointer; user-select: none; }
.results-table th.sortable:hover { color: var(--purple); }
.results-table tbody tr { border-bottom: 1px solid var(--border); cursor: pointer; }
.results-table tbody tr:hover { background: var(--bg-secondary); }
.results-table tbody tr.expanded { background: var(--bg-secondary); }
.results-table td { padding: 0.45rem 0.75rem; vertical-align: top; overflow-wrap: anywhere; }
/* Fixed layout means a nowrap cell would spill over its neighbour instead of
   widening the column, so part numbers wrap instead. They have no spaces to
   break at, hence overflow-wrap: anywhere on every cell above; a long FAA
   value like "(112A4011-36), (112A4011-37)" then takes two lines rather than
   losing its second half behind an ellipsis. */
.results-table td.pn {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-weight: 600; color: var(--purple);
}
.results-table td.dim { font-weight: 400; color: var(--text-secondary); }

/* A holder name a company has claimed and been approved for. The brand orange
   rather than a badge: it is a property of the name itself, it appears on
   every row that name owns, and a column of badges would drown the table. */
.results-table td.verified-holder { color: var(--orange); font-weight: 600; }

/* The tick before a claimed holder's name. Sized down and nudged up: it is a
   mark on the name, not a character of it. */
.pah-mark {
  color: var(--orange); font-weight: 700; font-size: 0.78em;
  margin-right: 0.3rem; vertical-align: 1px;
}

/* Said once under the table rather than on every row. Only drawn when there
   is something orange on screen to explain. */
.pah-legend {
  margin: 0.5rem 0 0; font-size: 0.78rem; color: var(--text-secondary);
}
.pah-legend .pah-mark { margin-right: 0.25rem; }
.pah-legend b { color: var(--orange); font-weight: 600; }

/* The greyed-out twin of the holder picker. Left visible rather than hidden:
   someone looking for the filter should find it and be told why it is not the
   one in charge, not wonder where it went. */
.company-field.is-disabled { opacity: 0.5; }
.company-field.is-disabled input,
.company-field.is-disabled .chip button { cursor: not-allowed; }

/* Clear the part number. Sits inside the box, left of the magnifier. */
.search-clear {
  position: absolute; right: 2.6rem; top: 50%; transform: translateY(-50%);
  background: none; border: 0; padding: 0 .35rem; line-height: 1;
  font-size: 1.15rem; color: var(--text-secondary); cursor: pointer;
}
.search-clear:hover { color: var(--text); }

/* Monthly / annual on the PMA plan card. */
/* Three separate facts stacked under the price -- the period, the choice of
   period, and what the yearly one saves. Run together they read as one
   confused block, so each gets its own air. Centred to sit under the price,
   which is centred; the negative top margin that used to pull this up against
   "per month" is gone. */
.plan .interval {
  display: flex; align-items: center; justify-content: center;
  gap: .4rem; margin: 0.9rem 0 0.25rem; flex-wrap: wrap;
}
.plan .int-opt {
  background: #fff; border: 1px solid var(--line, #e2e8f0); border-radius: 999px;
  padding: .2rem .7rem; font: inherit; font-size: .78rem; cursor: pointer; color: var(--text-secondary);
}
.plan .int-opt.active { background: var(--purple); border-color: var(--purple); color: #fff; font-weight: 600; }
/* Its own line under the two pills, not squeezed alongside them. */
.plan .int-note {
  font-size: .74rem; color: var(--orange); font-weight: 600;
  flex-basis: 100%; text-align: center; margin-top: 0.45rem;
}
.plan .cta-note { font-size: .74rem; color: var(--text-secondary); margin: .5rem 0 0; line-height: 1.45; }
/* Approval basis and the model list are paragraphs, not values. Inline they
   are clipped to one line with the full text a click away on the expanded
   row — the main app's PMA window does the same — so a page of results stays
   one row per approval. */
.results-table td.clip { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.models-link { color: var(--purple); text-decoration: underline dotted; text-underline-offset: 2px; }
.view-tag { font-size: 0.6rem; color: var(--purple); margin-left: 4px; opacity: 0.7; font-weight: 600; }
.locked-cell { opacity: 0.45; font-size: 0.75rem; cursor: help; }
mark { background: rgba(101,49,143,0.15); color: inherit; border-radius: 2px; padding: 0 1px; }
.results-table td.num { white-space: nowrap; text-align: right; font-variant-numeric: tabular-nums; }
.results-table td.chevron { color: var(--text-secondary); width: 1.5rem; }
.detail-row { background: var(--bg-secondary); cursor: default; }
.detail-row:hover { background: var(--bg-secondary); }

/* ─── Grouped rows ───────────────────────────────────────────────────── */
/* A group header is a disclosure, not a data row: heavier, tinted, and with
   the triangle leading rather than trailing so a column of them reads as a
   list you open. */
.group-row { background: var(--bg-secondary); border-bottom: 1px solid var(--border); }
.group-row:hover { background: var(--border); }
.group-row.open { box-shadow: inset 3px 0 0 var(--purple); }
.group-row td { padding: 0.5rem 0.75rem; }
.disc { display: inline-block; width: 1rem; color: var(--text-secondary); }
.group-title { font-weight: 700; }
.group-title.pn { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }
.group-sub { color: var(--text-secondary); margin-left: 0.6rem; font-size: 0.75rem; }
.count-badge {
  display: inline-block; min-width: 1.5rem; text-align: center;
  background: var(--purple); color: #fff; border-radius: 999px;
  padding: 0.05rem 0.4rem; font-size: 0.7rem; font-weight: 700;
}
/* A mixed group shows two counts ("8 Current" / "1 Historical"). Side by side
   they overrun the Status column, so they stack — the column is sized for one
   status word, and widening it for the minority of mixed groups would waste
   the space on every other row. */
/* Inline: rows are one line now, so a stacked pill per status would make a
   mixed group twice as tall as everything around it. The dominant status is
   drawn with a "+N" for the rest, and the breakdown is on the cell title. */
.status-cell .status { display: inline-block; }
.status-more { margin-left: 0.35rem; font-size: 12px; color: var(--text-secondary); }

/* Members of an open group are indented under their header so the nesting is
   readable without a second table. */
.results-table tbody tr.in-group td:first-child { padding-left: 2rem; }
.results-table tbody tr.in-group { background: var(--bg); }

/* The grouped-on value repeats on every member row and is already in the
   header, so dim it — the eye should land on what actually varies down the
   group: supplement, date and status. */
.grouped-part tbody tr.in-group td:nth-child(1),
.grouped-holder tbody tr.in-group td:nth-child(4) {
  color: var(--text-secondary); font-weight: 400;
}

/* ─── Segmented control ──────────────────────────────────────────────── */
.segmented { display: inline-flex; border: 1px solid var(--border); border-radius: var(--radius); overflow: hidden; }
.segmented button {
  border: none; border-radius: 0; background: var(--bg); color: var(--text-secondary);
  padding: 0.4rem 0.7rem; font-size: 0.75rem; font-weight: 600;
  /* No transition. Buttons inherit `transition: background` globally, and the
     active state is white-on-purple — so during the fade the newly-selected
     button is white text on a still-white background and reads as blank for
     150ms. A selector must never flicker unreadable; it should just snap. */
  transition: none;
}
.segmented button + button { border-left: 1px solid var(--border); }
.segmented button:hover:not(.active) { background: var(--bg-secondary); color: var(--text); }
/* The selected view is marked with the brand orange as a ring, not a fill.
   It is drawn as an INSET box-shadow rather than a border: a real border
   would add 2px to the button's box and shove its neighbours sideways every
   time the selection moved. z-index lifts the ring above the 1px dividers of
   the buttons either side, which would otherwise cut across it. */
.segmented button.active {
  background: var(--bg);
  color: var(--text);
  box-shadow: inset 0 0 0 2px var(--orange);
  position: relative;
  z-index: 1;
}

/* panel_pma.Status is Current (1.42M), Historical (195k) or Pending (50).
   Current vs Historical is the field someone actually decides on — whether
   this approval is still live — so it carries colour rather than being one
   more grey column. */
.status {
  display: inline-block; padding: 0.15rem 0.45rem; border-radius: 4px;
  font-size: 0.7rem; font-weight: 600; white-space: nowrap; line-height: 1.3;
}
.s-current { background: var(--green-bg); color: var(--green); }
.s-historical { background: var(--bg-secondary); color: var(--text-secondary); border: 1px solid var(--border); }
.s-pending { background: var(--amber-bg); color: var(--amber); }

/* ─── Expanded detail ────────────────────────────────────────────────── */
.detail {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: 1.25rem; padding: 0.9rem 0.4rem 1.1rem;
}
.detail-block h4 {
  font-size: 0.65rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.05em;
  color: var(--text-secondary); margin-bottom: 0.4rem;
}
.detail-block p { font-size: 0.78rem; line-height: 1.55; }
.detail-block .count {
  background: var(--border); color: var(--text-secondary);
  border-radius: 999px; padding: 0.05rem 0.4rem; margin-left: 0.3rem; letter-spacing: 0;
}
.models { list-style: none; display: flex; flex-wrap: wrap; gap: 0.25rem; max-height: 11rem; overflow-y: auto; }
.models li { font-size: 0.7rem; background: var(--bg); border: 1px solid var(--border); border-radius: 3px; padding: 0.1rem 0.4rem; }
.locked { color: var(--text-secondary); font-style: italic; }
.muted { color: var(--text-secondary); }

.drs { display: flex; flex-direction: column; gap: 0.5rem; align-items: flex-start; font-size: 0.78rem; }
.drs-line { color: var(--text-secondary); line-height: 1.5; }
.drs-more summary { cursor: pointer; color: var(--purple); font-size: 0.75rem; }
.drs-more ul { list-style: none; margin-top: 0.4rem; display: flex; flex-direction: column; gap: 0.25rem; }
.drs-more li { font-size: 0.75rem; }

/* ─── Empty state ────────────────────────────────────────────────────── */
.empty { max-width: 46rem; margin: 3rem auto; padding: 0 1.25rem; }
.empty h2 { font-size: 1.4rem; font-weight: 700; margin-bottom: 0.6rem; }
.empty p { color: var(--text-secondary); line-height: 1.65; margin-bottom: 1rem; }
.empty p strong { color: var(--text); }
.hints { list-style: none; display: flex; flex-direction: column; gap: 0.5rem; margin-bottom: 1.25rem; }
.hints li { font-size: 0.82rem; color: var(--text-secondary); line-height: 1.5; padding-left: 1rem; position: relative; }
.hints li::before { content: "—"; position: absolute; left: 0; color: var(--purple); }
.hints b { color: var(--text); }

/* ─── Footer ─────────────────────────────────────────────────────────── */
.footer {
  margin-top: 3rem; padding: 1.25rem; border-top: 1px solid var(--border);
  display: flex; justify-content: space-between; gap: 1rem; flex-wrap: wrap;
  font-size: 0.75rem; color: var(--text-secondary);
}
.footer a { color: var(--text-secondary); }

/* ─── Standalone pages (login, pricing, errors) ──────────────────────── */
.page { max-width: 60rem; margin: 0 auto; padding: 2.5rem 1.25rem 4rem; }
.page h1 { font-size: 1.7rem; margin-bottom: 0.5rem; }
.page .lede { color: var(--text-secondary); line-height: 1.65; max-width: 42rem; }
.card {
  max-width: 24rem; margin: 3rem auto; padding: 2rem;
  background: var(--bg-raised); border: 1px solid var(--border); border-radius: 10px;
  box-shadow: 0 10px 30px rgba(0,0,0,0.06);
}
.card h1 { font-size: 1.3rem; margin-bottom: 0.4rem; }
.card p.lede { color: var(--text-secondary); font-size: 0.85rem; margin-bottom: 1.25rem; line-height: 1.55; }
.field { display: flex; flex-direction: column; gap: 0.3rem; margin-bottom: 0.9rem; }
.field label { font-size: 0.65rem; font-weight: 700; color: var(--text-secondary); text-transform: uppercase; letter-spacing: 0.04em; }
.field input {
  padding: 0.6rem 0.7rem; border: 1px solid var(--border); border-radius: var(--radius);
  font-size: 0.9rem; font-family: inherit; background: var(--bg); color: var(--text); outline: none;
}
.field input:focus { border-color: var(--purple); box-shadow: 0 0 0 2px rgba(101,49,143,0.18); }
.card button[type="submit"] { width: 100%; background: var(--purple); color: #fff; padding: 0.65rem; font-size: 0.9rem; }
.card button[type="submit"]:hover:not(:disabled) { background: var(--purple-light); }
.error-msg { color: var(--red); font-size: 0.8rem; margin-bottom: 0.9rem; }
.card .aside { margin-top: 1.1rem; font-size: 0.78rem; color: var(--text-secondary); line-height: 1.6; text-align: center; }

/* 305px, the reference width. minmax(...,1fr) stretched them to whatever the
   page was wide, so the same three cards were a different size here than on
   the marketing site — which is most of what made them look unrelated. */
/* The plans page is wider than the rest of the app: three 305px cards and
   their gaps do not fit the 60rem measure the search pages use, and they
   wrapped to a second row. */
.plans-page { max-width: 64rem; }
/* One centred line under the cards. The page's .lede caps at 42rem, which is
   what wrapped it; the note is wider than that and reads as a single sentence.
   Below the cards' own width it may wrap again rather than overflow. */
.plans-note {
  text-align: center; color: var(--text-secondary); line-height: 1.65;
  white-space: nowrap; margin-top: 0.5rem;
}
@media (max-width: 900px) { .plans-note { white-space: normal; } }
.plans { display: grid; grid-template-columns: repeat(auto-fit, 305px); gap: 1.6rem; margin: 2rem 0; justify-content: center; }
/* ─── The marketing site's typography, on the plan cards ──────────────────
   Open Sans for text and Antonio for the plan names and prices, the same two
   faces www.fulcrum360.com/pricing uses. Scoped to the cards rather than set
   on the body: the rest of this product is Inter, and the point here is that
   these cards read as the same family as the marketing ones, not that the
   whole app changes typeface. */
.plans, .plans button, .plans input { font-family: 'Open Sans', var(--font-sans, sans-serif); }

/* Every size below is measured off the redesigned marketing cards, not
   chosen: head 35/700 at 2px tracking, price 50/400, list 15/400, CTA 29/700
   at 1px. Antonio is a condensed face — at our old 21px the plan names read
   as a caption rather than a heading, which is what "the fonts look off"
   was. */
.plan-head h3 {
  font-family: 'Antonio', 'Open Sans', sans-serif;
  font-size: 35px; font-weight: 700; letter-spacing: 2px;
  /* White on the band. Lost once already, when two .plan-head h3 rules were
     folded into one and this was in the half that went. */
  color: #fff;
}
.plan .price {
  font-family: 'Antonio', 'Open Sans', sans-serif;
  font-size: 50px; font-weight: 400; letter-spacing: normal; line-height: 1.1;
  text-align: center; margin: 0.6rem 0 0.2rem; color: var(--text);
}
/* On its own line: "Included with your plan" set inline at this size wrapped
   into three ragged lines. */
.plan .price small {
  display: block; font-family: 'Open Sans', sans-serif; font-size: 13px;
  font-weight: 400; color: var(--text-secondary); letter-spacing: 0;
  margin-top: 0.4rem;
}
/* The same style, above the figure instead of below it -- so the margin goes
   the other way. Everything else is inherited from the rule above rather than
   restated, which is what keeps the two halves matching. */
.plan .price small.pre { margin-top: 0; margin-bottom: 0.3rem; }
.plan li { font-size: 15px; color: var(--text); line-height: 1.4; }
.plan .cta > a {
  font-family: 'Antonio', 'Open Sans', sans-serif;
  font-size: 29px; font-weight: 700; letter-spacing: 1px;
  text-decoration: underline;
}

/* Cards carry the marketing site's header band: the same gradients from its
   globals.css, the same white plan name across the top, the same drop shadow.
   The padding moved from the card to .plan-body so the band can run edge to
   edge -- a header inset by 1.5rem reads as a label, not a header.

   border-radius stays on the card with overflow:hidden, so the band's top
   corners are the card's corners and there is one radius to change, not two
   that can drift apart. */
.plan {
  border: 0; border-radius: 10px; overflow: hidden;
  background: var(--bg-raised); display: flex; flex-direction: column;
  /* Their shadow exactly: 0.3 alpha, not the 0.16 that made these look flat
     beside the marketing ones. */
  box-shadow: 0 2px 30px 0 rgba(0, 0, 0, 0.3);
}
.plan-body { padding: 1.5rem; display: flex; flex-direction: column; flex: 1; }
.plan.featured { box-shadow: 0 0 0 3px var(--orange), 0 2px 30px 0 rgba(0, 0, 0, 0.3); }

.plan-head { min-height: 4rem; display: flex; align-items: center; justify-content: center; padding: 0.4rem 1rem; }
.plan-head h3 { margin: 0; line-height: 1.15; text-align: center; }
/* The gradients, lifted from the marketing site so the two pages cannot drift.
   Free takes the green rather than the marketing site's yellow-orange: that
   one sits beside PMA's orange here and the pair read as the same tier at a
   glance, which is the opposite of what the colour is for. */
.plan-free .plan-head,
.plan-free .cta > a     { background-image: linear-gradient(170deg, #77a815 0%, #457a2e 99%); }
.plan-pma .plan-head,
.plan-pma .cta > a      { background-image: linear-gradient(170deg, #F3991F 0%, #d97706 99%); }
.plan-platform .plan-head,
.plan-platform .cta > a { background-image: linear-gradient(170deg, #8300e9 0%, #42135f 100%); }

/* The call to action wears its card's colour, the way GET NOW does on the
   marketing site — so the card reads as one block, headed and footed in the
   same colour, rather than a coloured band with an unrelated button under it.
   The gradient comes from the rules above; everything shape-related is here,
   once, so the three cannot drift. */
.plan .cta > a {
  display: inline-block; color: #fff; border: 0; cursor: pointer;
  transition: filter .15s ease;
}
.plan .cta > a:hover { filter: brightness(1.08); }

/* ─── What a search found, above the table ────────────────────────────── */
.result-summary {
  margin: 0.4rem 0 0.75rem; padding: 0.6rem 0.8rem;
  background: var(--bg-secondary); border: 1px solid var(--border);
  border-radius: 8px;
}
.rs-line { display: flex; flex-wrap: wrap; align-items: center; gap: 0.35rem 1.1rem; }
.rs-stat { font-size: 0.78rem; color: var(--text-secondary); white-space: nowrap; }
.rs-stat strong { color: var(--text); font-size: 0.9rem; }
.rs-models {
  background: none; border: 0; padding: 0; font: inherit; font-size: 0.78rem;
  color: var(--purple); cursor: pointer; white-space: nowrap;
}
.rs-models strong { font-size: 0.9rem; }
.rs-lock { font-size: 0.75rem; color: var(--text-secondary); }
.rs-caveat { font-size: 0.72rem; color: var(--text-secondary); margin-top: 0.35rem; }
/* The model list can run to hundreds of designations, so it is capped and
   scrolls rather than pushing the results off the screen. */
.rs-modellist {
  display: flex; flex-wrap: wrap; gap: 0.3rem;
  margin-top: 0.55rem; max-height: 11rem; overflow-y: auto;
  padding-top: 0.5rem; border-top: 1px solid var(--border);
}
.rs-model {
  font-size: 0.7rem; padding: 0.1rem 0.45rem; border-radius: 999px;
  background: var(--bg-raised); border: 1px solid var(--border); color: var(--text-secondary);
  white-space: nowrap;
}
.plan ul { list-style: none; margin: 1rem 0; display: flex; flex-direction: column; gap: 0.45rem; flex: 1; }
.plan li { padding-left: 1.4rem; position: relative; }
.plan li::before { content: "✓"; position: absolute; left: 0; color: #57a300; font-weight: 700; }
.plan li.no::before { content: "—"; color: var(--text-secondary); }
/* margin-top:auto pins this to the bottom of the card, and the button is the
   LAST thing inside it, so the three buttons line up whatever else the card
   carries. The PMA card's note sits above the button for exactly that reason:
   below it, the note pushed that one button 77px higher than the other two. */
.plan .cta { text-align: center; margin-top: auto; padding-top: 0.75rem; }
.plan .cta-note { margin: 0 0 0.6rem; }
.plan .cta > a {
  padding: 0.3rem 0.75rem; border-radius: 6px;
  /* Uppercase like the reference's GET NOW, and set in the markup's own case
     so the HTML still reads as a sentence. */
  text-transform: uppercase;
  /* One width for all three. Sized to content, "SIGN UP" was 50px narrower
     than "SEARCH FREE" and the row of buttons stepped. */
  width: 210px; max-width: 100%; box-sizing: border-box;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.plan .cta > a:hover { text-decoration: none; }

/* ─── Holder portal and claim review ──────────────────────────────────────
   The vendor surface is a form-heavy page rather than a table, so it gets
   panels and a wider measure than the search page's dense layout. */
.wide-page { max-width: 74rem; }
.page h1 + .lede { margin-bottom: 1.5rem; }

.panel {
  background: var(--bg-raised);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 1.5rem;
  margin-bottom: 1.5rem;
}
.panel h2 {
  font-size: 1.05rem; margin-bottom: 0.5rem;
  display: flex; align-items: center; gap: 0.5rem;
}
.panel h3 { font-size: 0.9rem; margin: 1.25rem 0 0.6rem; }
.panel .lede { font-size: 0.85rem; margin-bottom: 1.1rem; }
/* A section that is deliberately unavailable explains itself rather than
   just being greyed out. */
.locked-panel { border-style: dashed; background: var(--bg-secondary); }

.small { font-size: 0.75rem; }
.ok-msg { color: var(--green); font-size: 0.8rem; margin-bottom: 0.8rem; }
.link-inline {
  background: none; border: none; padding: 0; font-size: inherit;
  color: var(--purple); text-decoration: underline; cursor: pointer;
}

/* ─── Compact tables ─────────────────────────────────────────────────────
   Distinct from .results-table: no fixed widths, no sticky header, smaller
   padding. These list a handful of the user's own rows, not a search result. */
.mini-table { width: 100%; border-collapse: collapse; font-size: 0.8rem; margin-bottom: 1rem; }
.mini-table th {
  text-align: left; padding: 0.4rem 0.6rem;
  font-size: 0.65rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em;
  color: var(--text-secondary); border-bottom: 2px solid var(--border); white-space: nowrap;
}
.mini-table td { padding: 0.45rem 0.6rem; border-bottom: 1px solid var(--border); vertical-align: top; }
.mini-table td.pn { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-weight: 600; }
.mini-table td.dim { color: var(--text-secondary); font-weight: 400; }
.mini-table td.num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
.mini-table td.actions { white-space: nowrap; text-align: right; }
.mini-table td.actions button + button { margin-left: 0.3rem; }
.btn-ghost.danger { color: var(--red); border-color: var(--red); }
.btn-ghost.danger:hover:not(:disabled) { background: var(--red); color: #fff; }

.claim-status {
  font-size: 0.65rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em;
  padding: 0.12rem 0.45rem; border-radius: 999px; white-space: nowrap;
}
.claim-status.s-pending  { background: var(--amber-bg); color: var(--amber); }
.claim-status.s-approved { background: var(--green-bg); color: var(--green); }
.claim-status.s-rejected { background: var(--bg-secondary); color: var(--red); border: 1px solid var(--red); }

/* ─── Forms ──────────────────────────────────────────────────────────────── */
.claim-form { max-width: 34rem; }
.claim-form textarea, .part-form textarea, .field textarea {
  padding: 0.55rem 0.7rem; border: 1px solid var(--border); border-radius: var(--radius);
  font-size: 0.85rem; font-family: inherit; background: var(--bg); color: var(--text);
  outline: none; resize: vertical;
}
.field textarea:focus, .field select:focus {
  border-color: var(--purple); box-shadow: 0 0 0 2px rgba(101,49,143,0.18);
}
.field select {
  padding: 0.55rem 0.7rem; border: 1px solid var(--border); border-radius: var(--radius);
  font-size: 0.85rem; font-family: inherit; background: var(--bg); color: var(--text);
  outline: none; cursor: pointer;
}
.form-grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
  gap: 0 1rem;
}
.form-grid .field.wide { grid-column: 1 / -1; }
.form-actions { display: flex; gap: 0.5rem; margin-top: 0.5rem; }
.part-form button[type="submit"] { background: var(--purple); color: #fff; }
.part-form button[type="submit"]:hover:not(:disabled) { background: var(--purple-light); }
.claim-form button[type="submit"] { background: var(--purple); color: #fff; }
.claim-form button[type="submit"]:hover:not(:disabled) { background: var(--purple-light); }

/* The holder picker sits in the flow rather than floating, because it is
   part of filling the form in, not a transient overlay on a search box. */
.suggestions.static {
  position: static; box-shadow: none; margin-top: 0.35rem; max-height: 14rem;
}
/* A name already picked, or already claimed, stays listed so the absence of
   it is not mistaken for a search that missed — but it is plainly not a
   target any more. */
.suggestions li.is-picked { opacity: 0.5; cursor: default; }
.suggestions li.is-picked:hover { background: transparent; }

.picked-holders { display: flex; flex-wrap: wrap; gap: 0.35rem; margin-bottom: 0.45rem; }
.picked-holders .chip { max-width: 100%; font-size: 0.78rem; }
.chip-n {
  background: rgba(255,255,255,0.28); border-radius: 999px;
  padding: 0 0.35rem; margin-left: 0.35rem; font-size: 0.7rem;
}

.inline-search { display: flex; gap: 0.5rem; margin-bottom: 0.9rem; }
.inline-search input {
  flex: 1; max-width: 22rem;
  padding: 0.45rem 0.6rem; border: 1px solid var(--border); border-radius: var(--radius);
  font-size: 0.82rem; font-family: inherit; background: var(--bg); color: var(--text); outline: none;
}

.upload-form { display: flex; gap: 0.6rem; align-items: center; flex-wrap: wrap; margin-bottom: 1rem; }
.upload-form input[type="file"] { font-size: 0.82rem; font-family: inherit; }
.upload-form button[type="submit"] { background: var(--purple); color: #fff; }
.upload-form button[type="submit"]:hover:not(:disabled) { background: var(--purple-light); }
.notice-ok { background: var(--green-bg); color: var(--green); border-color: transparent; }
/* An import result is a report, not a one-liner — it has to stack. */
.notice-ok, .notice-caveat { display: block; }
.row-errors { margin-top: 0.7rem; }
.row-errors summary { cursor: pointer; font-weight: 600; font-size: 0.78rem; }
.row-errors .mini-table { margin-top: 0.6rem; margin-bottom: 0; }

/* ─── Claim review cards ─────────────────────────────────────────────────── */
.claim-card {
  background: var(--bg-raised); border: 1px solid var(--border);
  border-left: 3px solid var(--amber);
  border-radius: 10px; padding: 1.25rem; margin-bottom: 1rem;
}
.claim-head { display: flex; justify-content: space-between; gap: 1rem; margin-bottom: 0.9rem; }
.claim-holder { font-size: 1rem; font-weight: 700; }
.claim-facts {
  display: grid; grid-template-columns: max-content 1fr; gap: 0.3rem 1rem;
  font-size: 0.82rem; margin-bottom: 0.9rem;
}
.claim-facts dt { color: var(--text-secondary); font-weight: 600; }
.claim-evidence {
  border-left: 2px solid var(--border); padding: 0.4rem 0 0.4rem 0.8rem;
  margin-bottom: 0.9rem; font-size: 0.85rem; color: var(--text-secondary); line-height: 1.55;
  white-space: pre-wrap;
}
.claim-note {
  width: 100%; padding: 0.45rem 0.6rem; border: 1px solid var(--border);
  border-radius: var(--radius); font-size: 0.82rem; font-family: inherit;
  background: var(--bg); color: var(--text); outline: none; margin-bottom: 0.7rem;
}
.claim-actions { display: flex; gap: 0.5rem; }

/* ─── Source badge in search results ─────────────────────────────────────
   Vendor data solves the FAA's lag, but it must never be mistaken for the
   FAA's own record — so the badge is always present, not only on hover. */
.src {
  font-size: 0.6rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.05em;
  padding: 0.08rem 0.35rem; border-radius: 3px; white-space: nowrap; margin-left: 0.4rem;
  vertical-align: 1px;
}
.src-faa { background: var(--bg-secondary); color: var(--text-secondary); border: 1px solid var(--border); }
.src-vendor { background: var(--purple); color: #fff; }

/* ─── Option D — dark filter rail ─────────────────────────────────────────
   Everything that starts, narrows or exports a search lives in one
   deep-purple column; the results side is nothing but results, on a warm
   off-white with 15px rows, no row chrome, and an orange rule under the
   headers.

   The rail keeps its purple in both themes — it is brand furniture, not a
   surface that should invert — while the results side follows the tokens. */
/* Layout constant; the colours that used to live here are per-skin now. */
:root { --rail-w: 300px; }
body { background: var(--paper); }

.layout { display: flex; align-items: stretch; min-height: 60vh; }

.rail {
  width: var(--rail-w); flex: 0 0 var(--rail-w);
  box-sizing: border-box; padding: 22px 22px 28px;
  background: var(--rail-bg); color: #fff;
  align-self: stretch;
}
.rail > form { display: flex; flex-direction: column; gap: 22px; min-height: 100%; }
.rail-sec { display: flex; flex-direction: column; gap: 12px; }
.rail-sec-head { display: flex; justify-content: space-between; align-items: baseline; }
.rail-rule { height: 1px; background: rgba(255,255,255,0.15); }

/* Orange is the rail's one accent: section headings, the primary button, and
   the selected radio. Nothing else in the rail is orange. */
.rsec {
  font-size: 11.5px; font-weight: 700; text-transform: uppercase;
  letter-spacing: 0.08em; color: var(--orange);
}
.rail-field { display: flex; flex-direction: column; gap: 6px; position: relative; }
.rail-field label {
  font-size: 12px; font-weight: 600; color: rgba(255,255,255,0.72);
  display: flex; align-items: center; gap: 0.4rem; flex-wrap: wrap;
}
.rail-field input, .rail-field select {
  padding: 10px 12px; border: 1px solid rgba(255,255,255,0.28); border-radius: 6px;
  font-size: 15px; font-family: inherit; width: 100%; box-sizing: border-box;
  background: rgba(255,255,255,0.1); color: #fff; outline: none;
}
.rail-field input::placeholder { color: rgba(255,255,255,0.5); }
.rail-field input:focus, .rail-field select:focus {
  border-color: var(--orange); box-shadow: 0 0 0 2px rgba(243,153,31,0.25);
}
.rail-field input:disabled { opacity: 0.45; cursor: not-allowed; }
/* The native menu is painted by the OS, so its options need readable ink of
   their own — white-on-white otherwise. */
.rail-field select option { background: var(--rail-bg); color: #fff; }
.rail-hint { font-size: 11.5px; color: var(--orange); }
.rail-link { font-size: 13px; color: #fff; opacity: 0.85; text-decoration: underline; text-underline-offset: 2px; line-height: 1.4; }
.rail-link:hover { opacity: 1; color: var(--orange); }

/* ─── Multi-part report page ─────────────────────────────────────────────
   Three columns, the shape of the main app's report: the parts in, the fields
   wanted, the result. */
.report-page { max-width: 100%; padding: 1.25rem; }
.report-page h1 { font-size: 1.4rem; margin-bottom: 0.25rem; }
.report-page .lede { color: var(--text-secondary); font-size: 0.9rem; margin-bottom: 1rem; }
.report-grid { display: grid; grid-template-columns: 280px 240px minmax(0, 1fr); gap: 1rem; align-items: start; }
@media (max-width: 1000px) { .report-grid { grid-template-columns: 1fr; } }
.report-card {
  background: var(--bg-raised); border: 1px solid var(--border); border-radius: var(--radius);
  padding: 1rem; display: flex; flex-direction: column; gap: 0.6rem;
}
.report-card h3 {
  font-size: 0.7rem; font-weight: 700; color: var(--text-secondary);
  text-transform: uppercase; letter-spacing: 0.06em;
}
.report-card .hint { font-size: 0.75rem; color: var(--text-secondary); line-height: 1.45; }
.report-card textarea {
  width: 100%; min-height: 16rem; resize: vertical;
  padding: 0.55rem 0.6rem; border: 1px solid var(--border); border-radius: var(--radius);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 0.82rem; line-height: 1.5;
  background: var(--bg); color: var(--text); outline: none;
}
.report-card textarea:focus { border-color: var(--purple); box-shadow: 0 0 0 2px rgba(101,49,143,0.18); }
.report-card textarea:disabled { opacity: 0.5; }
.report-meta { display: flex; justify-content: space-between; align-items: center; font-size: 0.78rem; color: var(--text-secondary); }
.report-upload { display: inline-block; }
.report-upload input { display: none; }
.report-run { background: var(--orange); color: #2c1a3d; font-weight: 700; padding: 0.6rem; font-size: 0.9rem; }
.report-run:hover:not(:disabled) { background: var(--orange-hover); }
.check-actions { display: flex; gap: 0.5rem; }
.check-actions .link-btn { font-size: 0.72rem; }
.checklist { display: flex; flex-direction: column; gap: 0.3rem; }
.checklist label { display: flex; gap: 0.5rem; align-items: center; font-size: 0.85rem; cursor: pointer; }
.checklist input { accent-color: var(--purple); }
.report-results { display: flex; flex-direction: column; gap: 0.75rem; min-width: 0; }
.stats-bar { display: flex; gap: 1.25rem; flex-wrap: wrap; font-size: 0.85rem; color: var(--text-secondary); }
.stats-bar strong { color: var(--text); }
.stats-bar .found strong { color: var(--green); }
.stats-bar .missing strong { color: var(--red); }
.export-bar { display: flex; gap: 0.5rem; }
.report-table-wrap { overflow: auto; border: 1px solid var(--border); border-radius: var(--radius); max-height: calc(100vh - 16rem); }
.report-table { width: 100%; border-collapse: collapse; font-size: 0.8rem; }
.report-table thead th {
  position: sticky; top: 0; z-index: 2; background: var(--bg-secondary);
  padding: 0.5rem 0.6rem; text-align: left; font-weight: 700; color: var(--text-secondary);
  font-size: 0.68rem; text-transform: uppercase; letter-spacing: 0.04em; white-space: nowrap;
  border-bottom: 2px solid var(--border);
}
.report-table td { padding: 0.4rem 0.6rem; border-bottom: 1px solid var(--border); vertical-align: top; max-width: 22rem; }
.report-table td.pn { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-weight: 600; color: var(--purple); white-space: nowrap; }
.report-table td.clip { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.report-table td.num { text-align: right; white-space: nowrap; color: var(--text-secondary); }
.report-table td.nowrap { white-space: nowrap; }
.report-table tr.missing td { color: var(--text-secondary); }
.report-table tr.first td { border-top: 2px solid var(--border); }
.report-empty { padding: 3rem 1rem; text-align: center; color: var(--text-secondary); font-size: 0.9rem; }
.rail-lock { border-color: rgba(255,255,255,0.4); color: #fff; }

.rail-buttons { display: flex; gap: 8px; margin-top: 4px; }
.rail-go {
  flex: 1; background: var(--orange); color: #2c1a3d; border: 1px solid transparent;
  padding: 11px 16px; border-radius: 6px; font-size: 14px; font-weight: 600;
}
.rail-go:hover:not(:disabled) { background: var(--orange-hover); }
.rail-clear {
  background: transparent; color: rgba(255,255,255,0.85);
  border: 1px solid rgba(255,255,255,0.35); border-radius: 6px;
  padding: 11px 16px; font-size: 14px; font-weight: 500;
}
.rail-clear:hover { background: rgba(255,255,255,0.1); color: #fff; }
.rail-reset {
  background: none; border: none; padding: 0;
  font-size: 12.5px; font-weight: 600; color: rgba(255,255,255,0.7); text-decoration: underline;
}
.rail-reset:hover { color: #fff; }

/* Radios, not a segmented control: three stacked options read faster in a
   narrow column than three squeezed side by side. */
.rail-radios { display: flex; flex-direction: column; gap: 0; }
.rail-radio {
  display: flex; align-items: center; gap: 10px;
  background: none; border: none; padding: 6px 0; width: 100%;
  font-size: 14.5px; font-weight: 400; text-align: left;
  color: rgba(255,255,255,0.85);
}
.rail-radio:hover { color: #fff; }
.rail-radio.on { color: #fff; font-weight: 600; }
.rail-radio .dot {
  width: 16px; height: 16px; border-radius: 999px; flex: 0 0 16px;
  border: 2px solid rgba(255,255,255,0.55); box-sizing: border-box;
}
.rail-radio.on .dot {
  border-color: var(--orange);
  background: radial-gradient(circle, var(--orange) 0 4px, transparent 4.5px);
}

/* Pinned to the foot of the rail — the last thing you do, in the last place
   you look. */
.rail-export, .rail-export-locked { margin-top: auto; }
.rail-export {
  display: flex; align-items: center; justify-content: center; gap: 8px;
  background: transparent; color: #fff;
  border: 1px solid rgba(255,255,255,0.45); border-radius: 6px;
  padding: 10px 16px; font-size: 14px; font-weight: 600; text-decoration: none;
}
.rail-export:hover:not([aria-disabled="true"]):not(:disabled) { background: rgba(255,255,255,0.1); }
.rail-export-n { font-weight: 400; opacity: 0.75; }
.rail-export-locked { display: flex; align-items: center; gap: 0.5rem; }
.rail-export-locked .rail-export { flex: 1; }

/* The holder chips sit on the dark rail now. */
.rail-field .chips {
  border-color: rgba(255,255,255,0.28); background: rgba(255,255,255,0.1);
  min-height: 2.6rem;
}
.rail-field .chips:focus-within { border-color: var(--orange); box-shadow: 0 0 0 2px rgba(243,153,31,0.25); }
.rail-field .chips input { color: #fff; font-size: 15px; }
.rail-field .chips input::placeholder { color: rgba(255,255,255,0.5); }
.rail-field .chip { background: var(--orange); color: #2c1a3d; }
.rail-field .chip button { color: #2c1a3d; }
/* The suggestion menu floats off the rail onto the page, so it keeps the
   page's own surface rather than the rail's. */
.rail-field .suggestions { background: var(--bg-raised); color: var(--text); }

.results { flex: 1; min-width: 0; padding: 22px 28px 28px; }
.results-head { display: flex; justify-content: flex-end; margin-bottom: -0.4rem; }

/* ─── Results table, D's treatment ───────────────────────────────────────
   15px rows on the warm paper, generous padding, one hairline rule per row
   and no zebra — the quiet list the design asks for. Column widths are
   percentages so the table fits the viewport instead of scrolling. */
.results-table { min-width: 0; }
.results-table thead th {
  background: var(--paper);
  font-size: 12.5px; font-weight: 700; letter-spacing: 0;
  text-transform: none; color: var(--th-ink);
  padding: 10px 16px;
  border-bottom: 2px solid var(--orange);
}
.results-table td {
  /* 13px, down from 15, and tighter horizontally. Ten columns share the
     width and the PMA company name was the first to get cut off; this buys
     every column several characters without moving a single width. */
  padding: 14px 12px; font-size: 13px; line-height: 1.4;
  border-bottom: 1px solid var(--rule);
  /* break-word, not anywhere: a long unbroken part number still has to
     break, but "Manufacturing" should not be split when it would have fit
     on the next line. */
  overflow-wrap: break-word;
}
.results-table td.pn { color: var(--pn-ink); }
/* The PMA part number keeps the full size. It is what the eye lands on first
   and what a reader checks against their own list, so it is the one column
   that should not shrink -- unlike the Replaces column, which shares the .pn
   class but is reference, not the answer. */
.results-table td:nth-child(1) { font-size: 15px; }
/* It is a link, but the column is already a column of part numbers — an
   underline on every row would be noise. The affordance shows on hover. */
.pn-link { color: inherit; text-decoration: none; }
.pn-link:hover { text-decoration: underline; text-underline-offset: 2px; }
.results-table tbody tr:hover { background: var(--bg-hover, rgba(101,49,143,0.04)); }
.results-table tbody tr.expanded,
.results-table tbody tr.in-group,
.results-table .detail-row { background: var(--group-open); }
.group-row { background: var(--paper); border-bottom: 1px solid var(--rule-strong); }
.group-row.open { background: var(--group-open); box-shadow: none; }
.group-row td { padding: 16px 16px 12px; }
.group-title { font-size: 16px; }

/* Status reads as a pill here, not as coloured text. */
.status {
  display: inline-block; padding: 3px 10px; border-radius: 999px;
  font-size: 13px; font-weight: 600; text-transform: none; letter-spacing: 0;
}
.s-current { background: var(--green-bg); color: var(--green); }
.s-historical { background: var(--bg-secondary); color: var(--text-secondary); border: 1px solid var(--rule-strong); }
.s-pending { background: var(--amber-bg); color: var(--amber); }

.count-badge { background: var(--orange); color: #2c1a3d; font-size: 13px; padding: 3px 9px; }
.src { font-size: 10.5px; padding: 1px 6px; border-radius: 4px; vertical-align: 2px; }
.results-info { font-size: 15px; border-bottom: none; padding: 0.6rem 0 0.9rem; }
.results-info strong { color: var(--text); }

/* The table no longer needs the fixed 1966px canvas: D's widths are
   proportional, so it fits the viewport and only scrolls on a narrow one. */
/* No min-width: the widths are percentages, so the table always fits its
   column and the horizontal scrollbar never appears. Below 900px the rail
   stacks above instead, which is where the room comes from. */
.results-table { table-layout: fixed; width: 100%; }
/* Now that every cell truncates, the widths are a budget: the columns a
   reader identifies a record by — part number, name, what it replaces, who
   holds it — get the room, and the rest ellipse with the full value on hover.
   Each is sized against its real content: the part number at 15px, the rest
   at 13px, less 32px of cell padding. */
.results-table th:nth-child(1), .results-table td:nth-child(1) { width: 14%; }
.results-table th:nth-child(2), .results-table td:nth-child(2) { width: 11%; }
/* Replaces was 9% (66px of content) which cut "S287W5013-11" to "S287W5…". */
.results-table th:nth-child(3), .results-table td:nth-child(3) { width: 11%; }
/* PMA company was 13% (149px) against holder names that run past 200px, so
   the one column a reader scans for a name was the one being cut. Dropping
   the body type to 13px freed room in the fixed-width columns below — a date
   and a status pill need the same pixels whatever the table's total — and
   all of it goes here. At 19% of a 1400px table that is ~234px, which fits
   "Honeywell International Inc." and most of what the FAA files. */
.results-table th:nth-child(4), .results-table td:nth-child(4) { width: 19%; }
/* Supp. holds "4 Amended" and "ODA-TK-260", not just a number. */
.results-table th:nth-child(5), .results-table td:nth-child(5) { width: 8%; }
/* Date and Status are the two that must never truncate: a clipped date says
   nothing and a clipped pill looks broken. "2005-08-24" in tabular figures
   is ~78px at 13px and the Current pill ~78px, both plus 32px of padding —
   so 10% and 9% still clear them, where 12% each was slack. */
.results-table th:nth-child(6), .results-table td:nth-child(6) { width: 10%; }
/* Approval and Models are prose that ellipses at any width; the expanded row
   carries the full value, so they give up the last point. */
.results-table th:nth-child(7), .results-table td:nth-child(7) { width: 8%; }
.results-table th:nth-child(8), .results-table td:nth-child(8) { width: 7%; }
.results-table th:nth-child(9), .results-table td:nth-child(9) { width: 9%; }
.results-table th:nth-child(10), .results-table td:nth-child(10) { width: 3%; }
/* The disclosure arrow needs a column, not a cell's worth of padding. */
.results-table td.chevron, .results-table th:nth-child(10) { padding-left: 2px; padding-right: 8px; }

/* Belt and braces for the whole class of bug above: under a fixed layout a
   nowrap cell has no way to shrink, so clip it rather than let it print over
   the column next door. */
.results-table td.num, .results-table td.pn { overflow: hidden; text-overflow: ellipsis; }

/* Supplement is text, not a number ("4 Amended", "243 Revised 01/29/2014"),
   so it reads left — but on one line like every other cell. */
.results-table td:nth-child(5), .results-table th:nth-child(5) { text-align: left; }

/* ─── One line per row ────────────────────────────────────────────────────
   Every data cell truncates rather than wraps. A wrapping cell makes rows
   different heights and pushes the next result off the screen — one long
   holder name cost three rows of vertical space. Fixed-height lines mean you
   can scan far more results and open the one worth reading; the full value is
   on the cell's hover title and in the opened row.

   The detail panel is exempt: it is the place the full text goes. */
.results-table tbody td {
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.results-table tbody tr.detail-row td {
  white-space: normal; overflow: visible;
}
/* With one-line rows the generous vertical padding is no longer needed to
   keep them apart. */
/* One padding for every row, group header included, so the list is a even
   rhythm rather than headers that sit 2px taller than the rows they head. */
.results-table tbody td { padding-top: 9px; padding-bottom: 9px; }
.group-row td { padding: 9px 16px; }
/* Pills and badges are inline-block, so their own padding can make the line
   box taller than a row of plain text — which is where the last 2px of row
   drift came from. Sized to land inside a 15px/1.4 line. */
.results-table .status, .results-table .count-badge { line-height: 1.1; padding-top: 2px; padding-bottom: 2px; }

/* Under a fixed layout a nowrap header does not shrink — it spills over its
   neighbour, which is how "Supplement" ended up printed across Date. Let
   headers wrap instead; two short lines beat one that overlaps. */
.results-table thead th { white-space: normal; }
/* Supp. and Date sit next to each other and both were right-aligned, so a
   long supplement ran straight into the date. Date reads left, as D draws
   it, which puts a gutter between them. */
.results-table td:nth-child(6) { text-align: left; }

/* On a narrow window the rail would leave the table nothing to live in. */
@media (max-width: 900px) {
  .layout { flex-direction: column; }
  .rail { width: auto; flex: none; }
  .rail-export, .rail-export-locked { margin-top: 0; }
}
