/* The whole stylesheet — hand-written, no build step. Element selectors first so
   templates stay plain HTML; add a class only when an element needs to differ.

   Kave's house style: Black/White as the main pair, Linen/Clay/Sand as neutrals,
   Terracota as the one accent, Kave Haffer for display and interface, Martina
   Plantijn for editorial leads. Sections are separated by a single border, not
   boxed into cards. Straight edges throughout except the status pills.

   The :root block below is the reusable system — colours, the type scale, and
   letter-spacing steps a new component should pull from instead of retyping a
   literal px/em value. Everything past it is one-off component layout that can't
   be tokenized further without a build step. */

@font-face {
  font-family: "Kave Haffer Display";
  src: url("fonts/KaveHafferDisplay-Regular.woff2") format("woff2"),
       url("fonts/KaveHafferDisplay-Regular.woff") format("woff");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Kave Haffer Text";
  src: url("fonts/KaveHafferText-Regular.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Kave Haffer Text";
  src: url("fonts/KaveHafferText-SemiBold.woff2") format("woff2");
  font-weight: 600;
  font-style: normal;
  font-display: swap;
}
@font-face {
  /* Licensed brand asset (Klim Type Foundry), used here under Kave's own licence for
     this internal portal — see core/static/fonts/MartinaPlantijn-Regular.otf. */
  font-family: "Martina Plantijn";
  src: url("fonts/MartinaPlantijn-Regular.otf") format("opentype");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

:root {
  --bg: #ffffff;
  --surface: #f2f1e7;   /* Linen */
  --text: #000000;      /* Black */
  --muted: #6c6c66;
  --muted-2: #53534c;
  --border: #dad4c7;    /* Clay */
  --sand: #bdafa0;
  --accent: #a9431e;    /* Terracota — the signature colour */
  --danger: #a40928;
  --warning-bg: #fceec9;
  --warning-fg: #8e3712;
  --success-bg: #d1fadf;
  --success-fg: #05603a;
  --radius: 0;
  --font-display: "Kave Haffer Display", Georgia, serif;
  --font-text: "Kave Haffer Text", "Helvetica Neue", Arial, sans-serif;
  --font-lead: "Martina Plantijn", Georgia, serif;

  /* Type scale — the sizes reused across eyebrows, table headers, pills, form
     labels, and body copy. Pull from this instead of a new literal px value. */
  --fs-10: 10px;
  --fs-11: 11px;
  --fs-12: 12px;
  --fs-13: 13px;
  --fs-14: 14px;
  --fs-15: 15px;
  --fs-18: 18px;

  /* Letter-spacing steps for uppercase micro-labels. */
  --tracking-tight: -.01em;
  --tracking-snug: .02em;
  --tracking-normal: .06em;
  --tracking-wide: .08em;
  --tracking-wider: .1em;
  --tracking-widest: .14em;
  --tracking-2xl: .16em;
}

*, *::before, *::after { box-sizing: border-box; }

body {
  margin: 0;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  font: 400 var(--fs-15)/1.55 var(--font-text);
  color: var(--text);
  background: var(--bg);
}

/* Header — 72px, white, Clay bottom border. Full width, no max-width box: the
   app fills the browser tab, and responsive inline padding holds the content off
   the edges. */
header { position: sticky; top: 0; z-index: 10; height: 4.5rem; border-bottom: 1px solid var(--border); background: var(--bg); width: 100%; }
header nav { display: flex; align-items: center; gap: 1.25rem; height: 100%; padding-inline: clamp(1.25rem, 4vw, 2.5rem); }
.spacer { flex: 1; }
.brand { display: flex; align-items: center; gap: 1.25rem; text-decoration: none; color: var(--text); }
.wordmark { font: 400 25px/1 var(--font-display); letter-spacing: var(--tracking-tight); }
.vdiv { width: 1px; height: 1.375rem; background: var(--border); }
.eyebrow { font: 600 var(--fs-11)/1 var(--font-text); letter-spacing: var(--tracking-widest); text-transform: uppercase; color: var(--muted-2); }
/* The header's "Portal de proveedores"/"Supplier Portal" label reads as a subtitle
   next to the wordmark, not a section eyebrow — sentence case and a touch larger. */
.brand .eyebrow { font-size: 17px; font-weight: 400; letter-spacing: var(--tracking-snug); text-transform: none; }
.vendor-name { font: 400 var(--fs-13)/1 var(--font-text); color: var(--muted-2); text-transform: uppercase; }

/* Page content fills the whole viewport width — no max-width box. Plain pages use
   .scaffold for basic padding; the hero/section/layout-2col blocks below carry their
   own responsive inline padding instead. */
main.page { width: 100%; flex: 1 1 auto; display: flex; flex-direction: column; }
.scaffold { padding: 2.5rem 1.5rem; }

/* Header links stay quiet (black) — Terracota is reserved for primary actions in the
   page body, not header wayfinding. "Salir" is a plain underlined text link, not a
   button, even though it submits a form (for CSRF-safe logout). */
header nav a { color: var(--text); text-decoration: none; font: 400 var(--fs-13)/1 var(--font-text); }
header nav a:hover { color: var(--accent); }
/* Shared "reset button to plain text" base — .link-button and the language switcher
   buttons only differ in colour/underline, added below. */
.link-button, .lang-switch button {
  margin: 0; padding: 0; background: none; border: 0; cursor: pointer;
  font: 400 var(--fs-13)/1 var(--font-text);
}
.link-button { color: var(--text); text-decoration: underline; text-underline-offset: 3px; }
.link-button:hover { color: var(--accent); filter: none; }
.inline { display: inline; }

/* Language switcher, next to the sign-out link. */
.lang-switch { display: flex; align-items: center; gap: .35rem; margin: 0; }
.lang-switch span { color: var(--border); font-size: var(--fs-13); }
.lang-switch button { color: var(--muted); text-decoration: none; }
.lang-switch button.active { color: var(--text); font-weight: 600; text-decoration: underline; text-underline-offset: 3px; }
.lang-switch button:hover { color: var(--accent); filter: none; }

/* Type */
h1 { font: 400 40px/1 var(--font-display); letter-spacing: var(--tracking-tight); margin: 0 0 .6rem; }
h2 { font: 400 24px/1 var(--font-display); margin: 2.5rem 0 .75rem; }
h3 { font: 600 var(--fs-11)/1 var(--font-text); letter-spacing: var(--tracking-wider); text-transform: uppercase; color: var(--muted-2); margin: 2rem 0 .75rem; }
a { color: var(--accent); }
.muted { color: var(--muted); }
.lead { font: 400 var(--fs-18)/1.4 var(--font-lead); color: var(--muted-2); max-width: 44rem; margin: 0 0 1.5rem; }

/* Tables — the listings */
table { width: 100%; border-collapse: collapse; margin: 1rem 0; }
th, td { text-align: left; padding: .6rem .75rem; border-bottom: 1px solid var(--border); }
th { font: 600 var(--fs-11)/1 var(--font-text); letter-spacing: var(--tracking-wide); text-transform: uppercase; color: var(--muted-2); border-bottom: 1px solid var(--text); }
tbody tr:hover { background: var(--surface); }
td:first-child, th:first-child { padding-left: 0; }
td:last-child, th:last-child { padding-right: 0; }

/* Status pills — the one place a rounded shape survives the straight-edge rule. */
.pill { display: inline-block; padding: 5px 12px; font: 600 var(--fs-11)/1 var(--font-text); letter-spacing: var(--tracking-normal); text-transform: uppercase; border-radius: 9999px; }
.pill-pending { background: var(--warning-bg); color: var(--warning-fg); }
.pill-done { background: var(--success-bg); color: var(--success-fg); }
.pill-review { background: #ffdee5; color: var(--danger); }
.pill-neutral { background: var(--bg); color: var(--muted-2); border: 1px solid var(--border); }
.pill-accent { background: #f5e3d9; color: var(--accent); }

/* Internal (Kave) shell — a dark left nav instead of the supplier pages' plain
   top-only header. */
/* The internal shell: a fixed 220px panel (64px collapsed) with the content
   simply inset by its width. One variable drives the panel, the content inset
   and the selection bar, and `html.nav-collapsed` is the single source of
   truth for the collapsed state — CSS decides the widths, the script only
   flips the class. A fixed panel also can't be clipped or dragged sideways by
   the content, which a grid track could. */
:root { --sidebar-width: 220px; }
html.nav-collapsed { --sidebar-width: 64px; }

.internal-body { padding-left: var(--sidebar-width); min-height: calc(100dvh - 4.5rem); }
/* Internal view only: the rail runs floor-to-ceiling and the header starts
   where it ends, so the two read as one piece of chrome instead of a bar
   with a separate panel hanging under it. margin-left (not padding) so the
   header's own background stops at the rail rather than painting over it. */
body.internal header { margin-left: var(--sidebar-width); width: auto; }
body.internal .internal-nav { top: 0; }
.internal-nav { position: fixed; top: 4.5rem; bottom: 0; left: 0; width: var(--sidebar-width); background: #000; z-index: 9; }
.internal-nav-inner { height: 100%; display: flex; flex-direction: column; align-items: stretch; gap: 2px; padding: 1.75rem 1.25rem 1.5rem; overflow-y: auto; }
.internal-nav a, .internal-nav .nav-active { display: flex; align-items: center; gap: .625rem; flex: none; padding: .625rem .75rem; font: 400 14px/1.2 var(--font-text); text-decoration: none; }
.internal-nav .nav-label { min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.internal-nav a { color: var(--sand); }
.internal-nav a:hover { background: #1C1C1A; color: #fff; }
.internal-nav .nav-active { background: #fff; color: #000; font-weight: 600; }
.internal-nav .nav-icon { flex: none; display: none; }
.internal-nav .nav-footer { margin-top: auto; padding-top: 1rem; border-top: 1px solid #2E2E2B; }
.internal-nav .nav-footer .name { font: 600 13px/1.3 var(--font-text); color: #fff; }
.internal-nav .nav-footer .role { margin-top: 3px; font: 400 12px/1.3 var(--font-text); color: var(--sand); }
.nav-collapse-toggle { display: flex; align-items: center; justify-content: center; width: 28px; height: 28px; margin: 0 0 18px auto; padding: 0; border: 1px solid #2E2E2B; background: transparent; color: var(--sand); cursor: pointer; flex: none; }
.nav-collapse-toggle:hover { border-color: #fff; color: #fff; }

/* Collapsed: a 64px icon rail. Scoped to .internal-nav — an unscoped `a`
   selector here reflowed every link in the content area too. */
html.nav-collapsed .internal-nav-inner { align-items: center; padding: 1.75rem .75rem 1.5rem; }
html.nav-collapsed .nav-collapse-toggle { margin: 0 0 18px; }
html.nav-collapsed .nav-label,
html.nav-collapsed .nav-footer { display: none; }
html.nav-collapsed .nav-icon { display: block; }
html.nav-collapsed .internal-nav a,
html.nav-collapsed .internal-nav .nav-active { width: 40px; height: 40px; padding: 0; justify-content: center; }

/* Wide internal tables scroll inside their own box — the page itself must
   never scroll sideways (the sticky sidebar and the fixed selection bar
   both assume a fixed x origin). */
/* The listing block every internal screen shares, so all of them sit
   at the same rhythm rather than each inventing its own spacing. */
.internal-list { flex: 1 1 auto; min-width: 0; }
.internal-list table { margin-top: 0; }
/* Long supplier names wrap rather than widening the table past its column. */
.internal-list td, .internal-list th { overflow-wrap: anywhere; }
/* Only reserve room for the fixed selection bar while it's showing. */
html.has-selection .internal-list { padding-bottom: 5rem; }
/* The tab bar already provides the gap above a listing. */
.internal-content { display: flex; flex-direction: column; max-width: 100%; padding: clamp(1.75rem, 4vw, 2.75rem) clamp(1.5rem, 4vw, 2.5rem) 3rem; min-width: 0; }
/* Responsive shell. Below 64rem the panel falls back to the icon rail on its
   own: a 220px sidebar on a narrow window leaves the list nothing to work
   with, and a list that can't fit pushes the page sideways — with a fixed
   panel, content then slides underneath it. Above that the buyer's own
   collapse choice (html.nav-collapsed) still wins.
   The name/role footer belongs to the expanded panel: hidden in the icon rail,
   shown whenever labels are. */
@media (max-width: 64rem) {
  :root { --sidebar-width: 64px; }
  .internal-nav-inner { align-items: center; padding: 1.75rem .75rem 1.5rem; }
  .nav-collapse-toggle { display: none; }
  .internal-nav .nav-label,
  .internal-nav .nav-footer { display: none; }
  .internal-nav .nav-icon { display: block; }
  .internal-nav a,
  .internal-nav .nav-active { width: 40px; height: 40px; padding: 0; justify-content: center; }
}
/* Narrower still: the rail becomes a strip above the content, so the list gets
   the full width. The footer comes back here — it's the expanded layout again,
   just horizontal. */
@media (max-width: 40rem) {
  body.internal header { margin-left: 0; width: 100%; }
  body.internal .internal-nav { top: auto; }
  .internal-body { padding-left: 0; }
  .internal-nav { position: static; width: auto; }
  .internal-nav-inner { height: auto; flex-direction: row; flex-wrap: wrap; align-items: center; gap: .25rem 1rem; padding: 1rem 1.25rem; }
  .internal-nav .nav-footer { display: block; margin: 0 0 0 auto; padding-top: 0; border-top: 0; }
}

/* Column priority. A ten-column listing can't fit a narrow window, and the
   alternative (a horizontal scroll box) hides the PO number the row is
   identified by. Secondary columns drop out instead, widest-first. */
@media (max-width: 80rem) {
  .col-wide { display: none; }
}
@media (max-width: 64rem) {
  .col-mid { display: none; }
}

/* The PO list's segmented status bar (All/No documents/Pending processing/Processed,
   each with its own count) and the labeled filter boxes below it. */
.chip-row { display: flex; align-items: center; border: 1px solid var(--text); margin: 1.25rem 0 1rem; flex-wrap: wrap; width: fit-content; }
.chip-row .chip + .chip { border-left: 1px solid var(--border); }
/* Internal listings lead straight from the h1 into the filters — no lead
   paragraph in between to space away from. */
body.internal .chip-row { margin-top: 0; }
.chip { display: flex; align-items: center; gap: 8px; padding: 9px 16px; font: 400 13px/1 var(--font-text); color: var(--text); text-decoration: none; white-space: nowrap; }
.chip span { font-size: 12px; color: var(--muted); }
.chip-active { background: var(--text); color: #fff; font-weight: 600; }
.chip-active span { color: var(--sand); }
.filter-row { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin: 0; }
/* Chips and filters read as one control strip: the chips on the left, the
   filters pushed to the far right. `space-between` rather than a margin-auto on
   the form so that when the two no longer fit side by side the form drops to
   its own line and starts at the left, instead of hanging off the right. */
.listing-controls { display: flex; align-items: center; justify-content: space-between; gap: 10px 1.5rem; flex-wrap: wrap; margin-bottom: 1rem; }
.listing-controls .chip-row { margin: 0; }
/* The filters keep their own width instead of being squeezed by the row: they
   stay on one line and, when there is no longer room for both blocks, the whole
   form drops below the chips rather than stacking two boxes over one. */
.listing-controls .filter-row { flex: 0 0 auto; flex-wrap: nowrap; justify-content: flex-end; }
/* Narrow enough that even alone on its line the form can't hold one row. */
@media (max-width: 48rem) {
  .listing-controls .filter-row { flex-wrap: wrap; }
}
/* The base button rule's line-height (3rem, matching its own 3rem height)
   doesn't shrink along with the height override below, which is what was
   pushing the label off-center — line-height:normal + flex centering fixes
   that regardless of the button's actual height. */
.filter-row .button-outline { display: flex; align-items: center; justify-content: center; height: 40px; margin: 0; padding: 0 1.25rem; line-height: normal; }
/* The label+value+chevron box the purchase-order filter row is built from. A
   real <select>/<input> carries the value; the chevron is drawn the same way as
   .history-select/select's own. */
.filter-chip-box { display: flex; align-items: center; gap: 8px; flex: 0 1 13rem; min-width: 8.5rem; margin: 0; height: 40px; padding: 0 12px; border: 1px solid var(--border); background: #fff; }
/* The Supplier filter is a <details> instead of a plain input/select — real
   multi-select (any number of onboarded suppliers at once), with a native,
   zero-JS disclosure panel instead of a custom dropdown widget. */
.filter-multiselect { display: block; position: relative; flex: 0 1 13rem; height: auto; padding: 0; }
.filter-multiselect summary { display: flex; align-items: center; gap: 8px; height: 40px; padding: 0 12px; cursor: pointer; list-style: none; }
.filter-multiselect summary::-webkit-details-marker { display: none; }
.filter-multiselect summary::after { content: ""; width: 8px; height: 8px; margin-left: auto; border-right: 1.5px solid var(--muted-2); border-bottom: 1.5px solid var(--muted-2); transform: rotate(45deg) translateY(-2px); flex: none; }
.filter-multiselect[open] summary::after { transform: rotate(-135deg) translateY(2px); }
.filter-multiselect-value { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font: 400 13px/1.2 var(--font-text); color: var(--muted-2); }
/* Capped rather than shrink-wrapped to the longest option: a supplier name
   like "Nan Tong Glass Hardware Co.,Ltd." would otherwise push the panel
   off the page. Long names wrap instead. Anchored to the box's right edge,
   since the boxes themselves sit at the right of the controls row. */
.filter-multiselect-panel { position: absolute; top: calc(100% + 2px); right: 0; z-index: 15; min-width: 100%; width: max-content; max-width: min(24rem, 90vw); max-height: 17rem; overflow-y: auto; padding: .5rem; background: #fff; border: 1px solid var(--border); box-shadow: 0 4px 12px rgba(0, 0, 0, .08); }
.filter-multiselect-panel label { display: flex; align-items: flex-start; gap: .5rem; margin: 0; padding: .375rem .5rem; font: 400 13px/1.3 var(--font-text); color: var(--text); text-transform: none; letter-spacing: normal; cursor: pointer; }
.filter-option-label { flex: 1; min-width: 0; overflow-wrap: anywhere; }
/* The search hides rows with .hidden, and a label's own display: flex would
   otherwise beat the [hidden] attribute's default rule. */
.filter-options label[hidden] { display: none; }
.filter-option-value { flex: none; font-size: 11px; color: var(--muted-2); letter-spacing: .04em; }
.filter-multiselect-panel label:hover { background: var(--surface); }
.filter-multiselect-panel input[type="checkbox"], .filter-multiselect-panel input[type="radio"] { flex: none; margin-top: 1px; }
/* The panel's own search field — a plain bottom rule, not another boxed input,
   so it reads as part of the panel rather than a control inside a control. */
.filter-panel-head { position: sticky; top: 0; z-index: 1; display: flex; align-items: center; gap: .5rem; padding: 0 .5rem; border-bottom: 1px solid var(--border); background: #fff; }
.filter-panel-head svg { flex: none; color: var(--muted-2); }
.filter-panel-head:focus-within { border-bottom-color: var(--text); }
.filter-panel-head:focus-within svg { color: var(--text); }
.filter-search { flex: 1; min-width: 0; width: auto; max-width: none; height: 2.25rem; padding: 0; border: 0; border-radius: 0; background: transparent; font: 400 13px/1 var(--font-text); color: var(--text); }
.filter-search:focus { outline: none; }
/* Select all / Clear: quiet text actions, not buttons competing with the rows. */
.filter-panel-actions { display: flex; gap: 1rem; padding: .5rem .5rem .375rem; }
.filter-panel-actions button { height: auto; margin: 0; padding: 0; border: 0; background: none; font: 600 10px/1 var(--font-text); letter-spacing: .06em; text-transform: uppercase; color: var(--muted-2); cursor: pointer; }
.filter-panel-actions button:hover { color: var(--accent); }
.filter-no-matches { margin: .25rem .5rem; font-size: 13px; }
.filter-chip-box:focus-within { border-color: var(--accent); }
.filter-chip-label { flex: none; font: 600 10px/1 var(--font-text); letter-spacing: .06em; text-transform: uppercase; color: var(--muted); white-space: nowrap; }
.filter-chip-box input, .filter-chip-box select { flex: 1; min-width: 0; height: auto; padding: 0; border: 0; background-color: transparent; font: 400 13px/1.2 var(--font-text); color: var(--muted-2); }
/* The site-wide input:focus rule draws its own 2px outline + accent border —
   right for a full-size field, but a tight little box around just the text
   inside this compact one. The box itself (:focus-within above) carries the
   focus highlight instead. */
.filter-chip-box input:focus, .filter-chip-box select:focus { outline: none; border-color: transparent; }
/* Reuses the site-wide select chevron (background-image, part of the select's
   own hit area) rather than a separate sibling <svg> — a decorative icon next
   to a real <select> doesn't get clicks, only the select element does. Needs
   its own right padding since the shared rule above zeroes it out; the global
   select rule's own padding-right doesn't win here (higher specificity above). */
.filter-chip-box select { padding-right: 1.5rem; background-position: right 0 center; }
.clear-filters { font: 400 13px/1 var(--font-text); color: var(--accent); text-decoration: none; }
/* The PO list's sort control: a small bordered box with a chevron, not bare text. */

/* Same reason as .filter-chip-box: the site-wide input:focus outline draws a
   tight box around just the text instead of highlighting the whole field. */

/* Forms */
label { display: block; margin: 1.25rem 0 .5rem; font: 600 var(--fs-12)/1 var(--font-text); letter-spacing: var(--tracking-normal); text-transform: uppercase; color: var(--muted-2); }
input, select, textarea {
  width: 100%;
  max-width: 26rem;
  height: 3rem;
  padding: 0 1rem;
  font: var(--fs-15)/1.3 var(--font-text);
  color: inherit;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius);
}
/* Checkboxes and radios keep their native box. The field sizing above would
   make each one a full-width 3rem control — which is what pushed the supplier
   names out of the multi-select panel and bloated every row checkbox.
   Undone here rather than excluded with :not([type="checkbox"]) up there: the
   attribute selectors that would take would outweigh a plain class, and the
   boxed look then leaked past .searchbar into the borderless hero field. */
input[type="checkbox"], input[type="radio"] {
  width: auto;
  max-width: none;
  height: auto;
  padding: 0;
  margin: 0;
  border: 0;
  border-radius: 0;
  background: none;
  accent-color: var(--text);
}
input:focus, select:focus, textarea:focus { outline: 2px solid var(--accent); outline-offset: -1px; border-color: var(--accent); }
/* Safari draws its own rounded box and pins the arrow flush to the edge, ignoring
   padding — appearance: none plus a hand-drawn chevron keeps the arrow's position
   and the square-cornered look identical across Safari, Chrome, and Firefox. */
select {
  appearance: none;
  -webkit-appearance: none;
  -moz-appearance: none;
  padding-right: 2.25rem;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='%2353534c' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right .875rem center;
}
button, .button {
  display: inline-block;
  margin-top: 1rem;
  height: 3rem;
  padding: 0 1.3rem;
  font: 600 var(--fs-14)/3rem var(--font-text);
  color: #fff;
  background: var(--text);
  border: 1px solid var(--text);
  border-radius: var(--radius);
  cursor: pointer;
  text-decoration: none;
}
button:hover, .button:hover { opacity: .92; }
button:disabled { opacity: .5; cursor: not-allowed; }
.button-outline { color: var(--text); background: var(--bg); }
.button-outline:hover { background: var(--surface); opacity: 1; }
.button-white { color: var(--text); background: #fff; border-color: #fff; margin: 0; }
.button-white:hover { opacity: .85; }
/* Internal screens run buttons at 44px, not the supplier side's default 48px —
   one modifier instead of repeating the override inline on every one. */
/* Centred by flex rather than by a line-height matching the height: this one
   is shorter than the base button, and the two numbers had already drifted
   apart (3rem of leading in a 2.75rem box). */
.button-internal { display: inline-flex; align-items: center; justify-content: center; margin: 0; height: 2.75rem; padding: 0 1.25rem; line-height: normal; }
.button-internal[aria-disabled="true"] { pointer-events: none; opacity: .5; }

/* The row-selection bar: pinned to the bottom of the viewport once at least
   one row is checked, not part of normal document flow. */
/* Pinned to the actual bottom of the viewport, spanning everything right of
   the sidebar — not just the padded content column it's written inside.
   --sidebar-width is kept in sync with the collapse toggle by
   internal/_base.html's own script. */
/* :not([hidden]) — same reason as .verifying-overlay/.file-columns above: an
   unconditional `display` here would beat the browser's own `[hidden]{display:
   none}` rule, showing the bar even with nothing selected. */
.selection-bar { position: fixed; bottom: 0; left: var(--sidebar-width, 220px); right: 0; z-index: 20; }
.selection-bar:not([hidden]) { display: flex; align-items: center; gap: 1rem; padding: .875rem 1.5rem; background: var(--text); color: #fff; font: 400 13px var(--font-text); }
/* The selection bar's secondary action: outlined in white on its black ground,
   where .button-outline's own light-on-light pairing wouldn't read. */
.button-ghost { margin: 0; height: 40px; padding: 0 18px; background: transparent; border: 1px solid #fff; color: #fff; line-height: normal; }
.button-ghost:hover { background: rgba(255, 255, 255, .12); opacity: 1; }

/* The review inbox's filter chips — pill-shaped, unlike the PO list's segmented status bar: the
   inbox filters a queue, it doesn't split it into fixed buckets. */
.pill-chip-row { display: flex; align-items: center; gap: 10px; margin: 1.25rem 0 1.125rem; flex-wrap: wrap; }
.pill-chip { padding: 6px 14px; border-radius: 9999px; font: 400 var(--fs-11)/1 var(--font-text); letter-spacing: var(--tracking-normal); text-transform: uppercase; color: var(--muted-2); text-decoration: none; white-space: nowrap; }
.pill-chip:hover { background: var(--surface); }
.pill-chip-active { background: var(--text); color: #fff; font-weight: 600; }
.pill-chip-unread { color: var(--danger); }
.pill-chip-unread.pill-chip-active { color: #fff; }

/* The 6px dot before a PO number whose supplier has said something new. */
.unread-dot { display: inline-block; width: 6px; height: 6px; margin-right: 7px; border-radius: 50%; background: var(--danger); vertical-align: middle; }

/* The activity feed — a grid, not a table: each row's Activity cell stacks a
   title over a wrapping list of filenames or the message itself. Same column
   track on the header and the rows so they stay aligned, with the scroll
   confined to the rows (scrollbar-gutter keeps the columns from shifting). */
.activity-head, .activity-row { display: grid; grid-template-columns: 9.5rem minmax(12rem, 1fr) 11rem 8rem 8.5rem; gap: 20px; }
.activity-head { padding-bottom: 10px; border-bottom: 1px solid var(--text); font: 600 var(--fs-10)/1 var(--font-text); letter-spacing: var(--tracking-wide); text-transform: uppercase; color: var(--muted); }
/* The feed scrolls with the page: it's capped at ACTIVITY_FEED_LIMIT rows,
   and a nested vertical scroller inside a scrolling page traps the wheel. */
.activity-row { align-items: baseline; padding: 14px 0; border-bottom: 1px solid var(--border); }
.activity-row:hover { background: var(--surface); }
@media (max-width: 64rem) {
  .activity-head { display: none; }
  .activity-row { grid-template-columns: 1fr; gap: 6px; }
}

/* The visibility list and the supplier list — grids for the same reason the activity feed's
   feed is one: a cell stacks two lines, and the whole row is a single control
   (a label in one, a link in the other) rather than a set of <td>s. Both need their own
   [hidden] rule: the display here would otherwise beat the attribute and the
   search box would filter nothing. */
.access-controls { display: flex; align-items: flex-end; gap: 1.5rem; flex-wrap: wrap; margin-bottom: 1.125rem; }
.access-search { flex: 0 1 20rem; min-width: 14rem; gap: .625rem; padding-bottom: .5rem; }
.access-search input { font: 400 var(--fs-14)/1.2 var(--font-text); }
.access-search svg { flex: none; color: var(--text); }
.access-head, .access-row { display: grid; grid-template-columns: 1.625rem 5.5rem minmax(12rem, 1fr) 8rem 9rem 7rem; gap: 16px; align-items: center; }
.access-head { padding-bottom: 9px; border-bottom: 1px solid var(--text); font: 600 var(--fs-10)/1 var(--font-text); letter-spacing: var(--tracking-wide); text-transform: uppercase; color: var(--muted); }
.access-row { margin: 0; padding: 11px 0; border-bottom: 1px solid var(--border); font: 400 var(--fs-14)/1.3 var(--font-text); color: var(--text); text-transform: none; letter-spacing: normal; cursor: pointer; }
.access-row:hover { background: var(--surface); }
.access-row[hidden] { display: none; }
/* A fixed internal page: the whole list is on it, and scrolling the document
   would take the search box and the actions under it out of reach. The content
   column is exactly the room under the header and only the rows scroll — the
   same shape a PO's order-lines table has (see _po_lines_table.html). Used by
   the visibility catalogue and the supplier list. */
body.internal-fixed .internal-content { height: calc(100dvh - 4.5rem); overflow: hidden; padding-bottom: clamp(1.25rem, 3vw, 1.75rem); }
body.internal-fixed .internal-content > * { flex: none; }
.scroll-pane { position: relative; flex: 1 1 0; min-height: 8rem; }
/* The gutter the drawn scrollbar sits in; a list header keeps the same one so
   its columns stay over the rows'. */
.scroll-pane-rows { height: 100%; overflow-y: auto; overscroll-behavior: contain; padding-right: 12px; }
body.internal-fixed .access-head,
body.internal-fixed .supplier-list-head { padding-right: 12px; }

#visibility-form { display: flex; flex-direction: column; flex: 1 1 0; min-height: 0; }

/* Suppliers and access is the same fixed page, with the height split between the list and the
   rail beside it. The layout cancels .internal-content's padding so the Linen
   rail is a band down the whole right side — the PO detail's own idiom (see
   .layout-2col-internal) — and .supplier-main brings that padding back for the
   half that needs it. Each column is then its own flex chain, so the list and
   the portal-user cards grow into whatever height is left and scroll there. */
body.internal-fixed .supplier-layout {
  flex: 1 1 0;
  min-height: 0;
  align-items: stretch;
  gap: 0;
  margin: calc(-1 * clamp(1.75rem, 4vw, 2.75rem)) calc(-1 * clamp(1.5rem, 4vw, 2.5rem)) calc(-1 * clamp(1.25rem, 3vw, 1.75rem));
}
.supplier-main { display: flex; flex-direction: column; min-width: 0; min-height: 0; padding: clamp(1.75rem, 4vw, 2.75rem) clamp(1.5rem, 4vw, 2.5rem) clamp(1.25rem, 3vw, 1.75rem); }
body.internal-fixed .supplier-rail {
  position: static;
  display: flex;
  flex-direction: column;
  min-height: 0;
  border: 0;
  border-left: 1px solid var(--border);
  padding: clamp(1.75rem, 4vw, 2.75rem) clamp(1.25rem, 3vw, 1.5rem) clamp(1.25rem, 3vw, 1.75rem);
}
.supplier-rail-inner { display: flex; flex-direction: column; flex: 1 1 auto; min-height: 0; }
.supplier-rail-inner > * { flex: none; }
.supplier-rail-inner > .scroll-pane { flex: 1 1 0; min-height: 5rem; }
@media (max-width: 40rem) {
  /* The nav is a strip above the content here, so the viewport no longer
     describes what is left for this column — let the page scroll instead. */
  body.internal-fixed .internal-content { height: auto; overflow: visible; }
  .scroll-pane { flex: none; }
  .scroll-pane-rows { height: auto; overflow: visible; padding-right: 0; }
  body.internal-fixed .access-head,
  body.internal-fixed .supplier-list-head { padding-right: 0; }
  /* Stacked: the rail is no longer a side, so it goes back to its own padding
     and lets the page carry the height. */
  body.internal-fixed .supplier-layout { margin: 0; }
  .supplier-main { padding: 0; }
  body.internal-fixed .supplier-rail { border: 1px solid var(--border); padding: 1.75rem 1.5rem; }
  .supplier-rail-inner > .scroll-pane { flex: none; }
}
/* A supplier of your own is ticked and locked, not greyed into illegibility. */
.access-row input[disabled] { opacity: 1; cursor: default; }
.access-actions { display: flex; align-items: center; gap: 1.25rem; margin-top: 1.5rem; flex-wrap: wrap; }

.supplier-head-row { display: flex; align-items: flex-end; justify-content: space-between; gap: 2rem; margin-bottom: 8px; flex-wrap: wrap; }
.supplier-layout { display: grid; grid-template-columns: minmax(0, 1fr) 21.25rem; gap: 2rem; align-items: start; }
.supplier-list-head, .supplier-row { display: grid; grid-template-columns: 4.625rem minmax(11rem, 1fr) 5.25rem 6rem 7.25rem 6.5rem; gap: 14px; align-items: center; }
.supplier-list-head { padding-bottom: 9px; border-bottom: 1px solid var(--text); font: 600 var(--fs-10)/1 var(--font-text); letter-spacing: var(--tracking-wide); text-transform: uppercase; color: var(--muted); }
.supplier-row { padding: 12px 0; border-bottom: 1px solid var(--border); color: var(--text); text-decoration: none; }
.supplier-row:hover { background: var(--surface); color: var(--text); }
.supplier-row-active { background: var(--surface); }
.supplier-row[hidden] { display: none; }
.supplier-rail { padding: 1.75rem 1.5rem; background: var(--surface); border: 1px solid var(--border); position: sticky; top: 5.5rem; }
.supplier-user-card { padding: 12px 14px; background: var(--bg); border: 1px solid var(--border); margin-bottom: .625rem; }
/* The invite disclosure: its summary is styled as an outline button, so the
   marker and the default list-item display have to go. */
.invite-box summary { display: flex; cursor: pointer; list-style: none; }
.invite-box summary::-webkit-details-marker { display: none; }
.invite-form { padding: 1rem 0 0; }
.invite-form label { display: block; margin: 0 0 .35rem; font: 600 var(--fs-10)/1 var(--font-text); letter-spacing: var(--tracking-wide); text-transform: uppercase; color: var(--muted); }
.invite-form input { max-width: none; height: 2.5rem; margin-bottom: .875rem; font-size: var(--fs-14); }
/* Revoke/restore sits under the account it belongs to, quiet — it's a rare
   action on a card that is mostly there to be read. */
/* A revoked account reads as a warning, not as a neutral fact: it is the one
   card in the rail where somebody's access is closed. Same warning pair the
   "Sin acceso" pill uses in the list beside it. */
.supplier-user-card-revoked { border-color: var(--warning-fg); background: var(--warning-bg); }
.account-revoked { font: 600 var(--fs-12)/1 var(--font-text); letter-spacing: var(--tracking-normal); text-transform: uppercase; color: var(--warning-fg); }
.access-toggle { margin: .5rem 0 0; }
.access-toggle button { font-size: var(--fs-12); color: var(--muted-2); }
.access-toggle button:hover { color: var(--accent); }
@media (max-width: 64rem) {
  .supplier-layout { grid-template-columns: 1fr; }
  .supplier-rail { position: static; }
  .supplier-list-head, .access-head { display: none; }
  .supplier-row, .access-row { grid-template-columns: 1fr; gap: 6px; }
}

/* The inbox tab bar sits inside .internal-content's padding, so it drops the
   full-bleed padding/background .tabs carries on the supplier pages. */
.tabs-inline { padding: 0; background: none; gap: 1.75rem; margin-bottom: 1.5rem; }
.tabs-inline .tab { padding: 0 0 12px; }
@media (max-width: 40rem) {
  .selection-bar { left: 0; }
}

/* History filters — a compact row of date fields, not a stacked form. */
.filters { display: flex; gap: 1rem; align-items: flex-end; flex-wrap: wrap; margin-bottom: 1.5rem; }
.filters label { margin: 0 0 .35rem; }
.filters input[type="date"] { max-width: 10rem; }
.filters button { margin-top: 0; }

/* The full-viewport login screen — no header (see block main_class), so this fills
   the whole browser tab: a Clay identity panel beside the sign-in form. */
.main-full { max-width: none; margin: 0; }
.login-shell { display: grid; grid-template-columns: minmax(22rem, 30rem) 1fr; min-height: 100vh; }
.login-side { background: var(--border); color: var(--text); padding: 2.5rem 0 0 2.5rem; display: flex; flex-direction: column; overflow: hidden; }
.login-tag { font: 400 var(--fs-11)/1 var(--font-text); letter-spacing: var(--tracking-2xl); text-transform: uppercase; color: var(--muted-2); margin-bottom: auto; }
/* The wordmark is oversized and cropped by the panel — a deliberate "zoomed-in
   logo" treatment, not a rendering bug. */
.login-wordmark-crop { width: 17rem; height: 6.6rem; overflow: hidden; margin: 0 2.5rem -1.4rem -.6rem; }
.login-wordmark { display: block; font-size: 75px; line-height: .8; letter-spacing: -.03em; color: var(--text); }
.login-main { padding: clamp(2.5rem, 6vw, 5.5rem) clamp(1.5rem, 6vw, 6rem); display: flex; flex-direction: column; justify-content: center; }
/* Centred within the (now full-width) right panel rather than pinned to its left
   edge — a fixed-width form stretched across a wide viewport would otherwise leave
   most of the panel empty. */
.login-card { width: 100%; max-width: 40rem; margin: 0 auto; }
/* The generic input/select rule caps at 26rem sitewide — too narrow once the card
   itself is 40rem, which made the username/password fields look out of step with
   the full-width buttons below them. Match the card's own width instead. */
.login-card input { max-width: none; }
.login-eyebrow { font: 600 var(--fs-11)/1 var(--font-text); letter-spacing: var(--tracking-wide); text-transform: uppercase; color: var(--muted); margin-bottom: .875rem; }
.login-main h2 { margin: 0 0 .5rem; font-size: 32px; }
.login-lead { margin: 0 0 2rem; font: 400 var(--fs-15)/1.5 var(--font-text); color: var(--muted-2); }
.login-label { margin: 1.25rem 0 .5rem; }
#id_username { border-color: var(--text); margin-bottom: 1.25rem; }
#id_password { border-color: var(--sand); margin-bottom: 1.75rem; }
.login-submit { width: 100%; }
.login-divider { display: flex; align-items: center; gap: 1rem; margin: 2.5rem 0 1.75rem; }
.login-divider span:first-child, .login-divider span:last-child { flex: 1; height: 1px; background: var(--border); }
.login-divider span:not(:first-child):not(:last-child) { font: 400 var(--fs-11)/1 var(--font-text); letter-spacing: var(--tracking-widest); text-transform: uppercase; color: var(--muted); white-space: nowrap; }
.login-sso {
  display: flex; align-items: center; justify-content: center; height: 3rem; width: 100%;
  font: 600 var(--fs-14)/1 var(--font-text); color: var(--text); background: var(--bg);
  border: 1px solid var(--text); text-decoration: none; box-sizing: border-box;
}
.login-sso:hover { background: var(--surface); }
.login-footer-row {
  display: flex; align-items: center; justify-content: space-between; gap: 1.5rem;
  margin-top: 2.5rem; padding-top: 1.5rem; border-top: 1px solid var(--border);
}
.login-footer-row a { font: 400 var(--fs-13)/1 var(--font-text); color: var(--text); text-decoration: underline; text-underline-offset: 3px; }
.login-footer-row a:hover { color: var(--accent); }
.login-lang { display: flex; align-items: center; gap: .625rem; margin: 0; }
.login-lang label { display: inline; margin: 0; font: 400 var(--fs-12)/1 var(--font-text); color: var(--muted); text-transform: none; letter-spacing: normal; }
.login-lang select {
  width: auto; max-width: none; height: 2rem; padding-left: .75rem; font-size: var(--fs-13);
  background-position: right .625rem center; padding-right: 1.75rem;
  border-color: var(--sand);
}
@media (max-width: 40rem) {
  .login-shell { grid-template-columns: 1fr; }
  .login-main { padding: 3rem 2rem; }
}

/* The dashboard's editorial header: vendor name and search, on Linen, full width.
   Only border-bottom — not a boxed card. */
.hero { background: var(--surface); padding: clamp(2rem, 6vw, 4rem) clamp(1.25rem, 6vw, 5rem) clamp(1.75rem, 4vw, 3.5rem); border-bottom: 1px solid var(--border); }
.hero .eyebrow { margin-bottom: .625rem; }
.hero h1 { font-size: clamp(32px, 5vw, 56px); margin-bottom: .875rem; }
/* Same band inside .internal-content, which is a padded column — so it cancels
   that padding to run edge to edge instead of sitting in it as a card. Same
   reasoning as .tabs-inline, in the other direction. */
.hero-internal { margin: calc(-1 * clamp(1.75rem, 4vw, 2.75rem)) calc(-1 * clamp(1.5rem, 4vw, 2.5rem)) clamp(1.5rem, 3vw, 2rem); padding: clamp(1.5rem, 3vw, 2rem) clamp(1.5rem, 4vw, 2.5rem); }
.hero-internal .searchbar { max-width: 32rem; }
/* Shared "quiet search row" layout: an icon, a borderless input that inherits the
   page's background, and a bottom rule instead of a boxed field. .searchbar (the
   dashboard) and .history-search ("Documentación entregada") both use it; each
   overrides its own input's font size/family below. */
.searchbar, .history-search { display: flex; align-items: center; border-bottom: 1px solid var(--text); }
.searchbar { gap: 1rem; max-width: 40rem; padding-bottom: .75rem; }
.searchbar svg { flex: none; color: var(--text); }
.searchbar input, .history-search input { flex: 1; min-width: 0; max-width: none; height: auto; border: 0; padding: 0; background: transparent; color: var(--muted); }
.searchbar input { font: 400 26px/1.1 var(--font-display); }
.searchbar input:focus, .history-search input:focus { outline: 0; }
.searchbar button { margin: 0; padding: 0; height: auto; background: none; border: 0; color: var(--muted); font: 600 var(--fs-11)/1 var(--font-text); letter-spacing: var(--tracking-wider); text-transform: uppercase; white-space: nowrap; }
.searchbar button:hover { opacity: 1; color: var(--accent); }

/* The Pendientes/Documentación entregada tab bar — switches between the two list
   pages, distinct from the PO detail's own "← Todos los pedidos" back-link. */
.tabs { display: flex; gap: 2rem; padding: 0 clamp(1.25rem, 6vw, 5rem); border-bottom: 1px solid var(--border); background: var(--bg); flex-wrap: wrap; }
.tab { padding: 1.125rem 0; margin-bottom: -1px; font: 400 var(--fs-14)/1 var(--font-text); color: var(--muted-2); text-decoration: none; border-bottom: 2px solid transparent; }
.tab:hover { color: var(--text); }
.tab.active { font-weight: 600; color: var(--text); border-bottom-color: var(--text); }
.tab-count { margin-left: .5rem; font: 400 var(--fs-13)/1 var(--font-text); color: var(--muted); }

/* "Documentación entregada"'s own filter row: a search-style number field plus a
   plain <select> dropdown (verification status). */
.history-filters { display: flex; align-items: flex-end; gap: 1.5rem; flex-wrap: wrap; }
.history-search { flex: 1; min-width: 18rem; gap: .875rem; padding-bottom: .625rem; }
.history-search input { font: 400 var(--fs-18)/1.1 var(--font-text); }
.history-select { height: 2.5rem; width: auto; max-width: none; padding-left: .875rem; font-size: var(--fs-13); border-color: var(--sand); }
/* The filters auto-submit on change (see history.html's script) — this button only
   exists as a <noscript> fallback, so it needs its own sizing to match the row
   instead of the generic button's 3rem height/line-height. */
.history-filters button { height: 2.5rem; margin: 0; padding: 0 1rem; font: 600 var(--fs-13)/2.5rem var(--font-text); }

/* Section padding: 80px at desktop, scaled down on narrow viewports. Full
   width, no max-width box. */
.section { padding: clamp(2rem, 5vw, 3.5rem) clamp(1.25rem, 6vw, 5rem) clamp(2.5rem, 6vw, 4.5rem); }
/* A section that opens with a line of text directly under the tab bar: the
   full top padding plus the paragraph's own margin left a gap wide enough to
   read as a missing heading. */
.section-under-tabs { padding-top: clamp(1.25rem, 3vw, 1.75rem); }
.section-under-tabs > p:first-child { margin-top: 0; }

/* PO detail: content + Linen sidebar, side by side, separated by one border — not
   a boxed layout, full width. Stacks on narrow screens. */
.layout-2col { display: grid; grid-template-columns: 1fr minmax(18rem, 22.5rem); flex: 1 1 auto; align-items: stretch; }
.layout-2col > .main { padding: clamp(1.75rem, 5vw, 3rem) clamp(1.25rem, 5vw, 3.5rem) clamp(2.5rem, 6vw, 4.5rem); border-right: 1px solid var(--border); min-width: 0; }
.layout-2col > .side { background: var(--surface); }
/* The Clay column's background fills the full row height (align-items: stretch,
   above); this inner wrapper is what actually sticks in view while its own content
   is shorter than the page, without capping the column's background height to it. */
.side-inner { padding: clamp(1.75rem, 5vw, 3rem) clamp(1.25rem, 5vw, 2.5rem); position: sticky; top: 4.5rem; }
/* The internal detail puts this layout inside .internal-content's padded
   column, which left the linen rail floating in white on three sides. Cancel
   that padding so it reaches the page edges the way it does on the supplier
   detail — each column already brings its own — and fill the height below the
   header so the rail is a full band, not a short block. */
.layout-2col-internal { margin: calc(-1 * clamp(1.75rem, 4vw, 2.75rem)) calc(-1 * clamp(1.5rem, 4vw, 2.5rem)) -3rem; min-height: calc(100dvh - 4.5rem); }
/* The left column is a flex chain, the same one the supplier's own PO page
   builds inline: the order-lines table then fills whatever height is left and
   scrolls its own rows (with the drawn scrollbar) instead of running the page
   long. min-height:0 so it can actually give the table that height back. */
.layout-2col-internal > .main { display: flex; flex-direction: column; min-height: 0; }
@media (max-width: 40rem) {
  /* The nav is a strip above the content here, so the viewport height no
     longer describes what is left for this layout. */
  .layout-2col-internal { min-height: 0; }
}
@media (max-width: 52rem) {
  .layout-2col { grid-template-columns: 1fr; }
  .layout-2col > .main { border-right: 0; border-bottom: 1px solid var(--border); }
}
.reconcile-note-textarea:focus { border-color: var(--text); outline: none; }

/* A line-item list that scrolls within a fixed area (reconcile's comparison
   table, the PO detail's order lines). macOS's "Show scroll bars: When
   scrolling"/"Automatically based on mouse or trackpad" preference hides the
   native scrollbar outside of an active scroll gesture no matter what CSS a
   page applies to it — there's no way to override that from here — so instead
   of relying on the real scrollbar at all, a small always-visible track/thumb
   pair is drawn next to the content (in the padding reserved for it on the
   table's last column) and kept in sync with real scroll position by the
   per-template script below. */
.scroll-indicator-track { position: absolute; top: 0; right: 2px; width: 4px; height: 100%; background: var(--border); pointer-events: none; }
.scroll-indicator-thumb { position: absolute; right: 0; width: 4px; background: var(--sand); }

/* Key/value facts about a PO, four to a row. */
.meta-grid { display: grid; grid-template-columns: repeat(4, 1fr); border-top: 1px solid var(--text); margin: 1.5rem 0; }
.meta-grid > div { padding: 1.125rem 1.25rem 1.125rem 0; border-bottom: 1px solid var(--border); }
.meta-grid dt { font: 600 var(--fs-10)/1 var(--font-text); letter-spacing: var(--tracking-wider); text-transform: uppercase; color: var(--muted); margin-bottom: .5rem; }
.meta-grid dd { margin: 0; font-size: 16px; }
@media (max-width: 40rem) { .meta-grid { grid-template-columns: repeat(2, 1fr); } }
.meta-grid-3 { grid-template-columns: repeat(3, 1fr); }
@media (max-width: 40rem) { .meta-grid-3 { grid-template-columns: repeat(2, 1fr); } }

/* Document upload: a clickable chosen-file row (native <input type="file"> hidden
   behind it — the raw control renders inconsistently across browsers and its native
   button was getting clipped by the sitewide input styles) and the dashed drop target
   for another one. */
/* Off-screen but still read aloud — for a heading the layout already makes
   obvious, and for the native file input a styled label stands in for. */
.visually-hidden,
.file-input-hidden { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0; }
.file-row { display: flex; align-items: center; gap: 1rem; padding: 1rem 1.25rem; border: 1px solid var(--text); background: var(--bg); margin-bottom: .75rem; cursor: pointer; }
.file-row.disabled { cursor: not-allowed; opacity: .5; }
.file-row .file-icon { flex-shrink: 0; color: var(--muted-2); }
.file-row .info { flex: 1; display: flex; flex-direction: column; gap: .15rem; min-width: 0; }
.file-row .name { font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.file-row .size { color: var(--muted); font-size: .85em; }
.file-row .file-remove-btn { flex-shrink: 0; background: none; border: none; padding: 0; font: 400 var(--fs-14) var(--font-text); color: var(--muted-2); text-decoration: underline; text-underline-offset: 3px; cursor: pointer; }
.dropzone { display: flex; align-items: center; justify-content: center; gap: .625rem; height: 3.5rem; border: 1px dashed var(--sand); background: var(--surface); cursor: pointer; font: 600 var(--fs-13)/1 var(--font-text); }
.doc-row { display: flex; gap: .75rem; align-items: center; margin-bottom: .75rem; }
.doc-row input[type="text"] { max-width: 15rem; height: 3rem; }
.doc-row .file-row { flex: 1; margin-bottom: 0; }

/* Combined/separate toggle switch. */
.toggle-row { display: flex; align-items: center; justify-content: space-between; gap: 1rem; padding: 1rem 1.25rem; background: var(--surface); border: 1px solid var(--border); margin-bottom: 2rem; }
.toggle-row label { margin: 0; font: var(--fs-15)/1.4 var(--font-text); color: var(--text); text-transform: none; letter-spacing: normal; }
.switch { position: relative; display: inline-block; width: 44px; height: 24px; flex-shrink: 0; }
.switch-input { position: absolute; inset: 0; margin: 0; opacity: 0; cursor: pointer; z-index: 1; }
.switch-track { position: absolute; inset: 0; background: var(--sand); border-radius: 9999px; transition: background .15s ease; }
.switch-thumb { position: absolute; top: 2px; left: 2px; width: 20px; height: 20px; background: var(--bg); border-radius: 50%; transition: transform .15s ease; }
.switch-input:checked + .switch-track { background: var(--text); }
.switch-input:checked + .switch-track .switch-thumb { transform: translateX(20px); }

/* Empty/error state — tone carried by a left accent border or the Linen background,
   no icons needed. */
.state-box { padding: 2rem 2.2rem; border: 1px solid var(--border); margin: 1.5rem 0; }
.state-box.state-empty { background: var(--surface); border: 0; }
.state-box h2 { margin-top: 0; font-size: 22px; }
.state-box p { margin: 0; }

/* Pagination — real paged listings for suppliers with many POs, not just "load more". */
.pager { display: flex; align-items: center; justify-content: space-between; gap: 1.5rem; margin-top: 1.5rem; flex-wrap: wrap; }
.pager-summary { font-size: var(--fs-13); color: var(--muted); }
.pager-controls { display: flex; align-items: center; gap: .375rem; }
/* Shared box dimensions for a page number and an ellipsis placeholder; each adds
   its own border/colour/font below. */
.pager-box, .pager-ellipsis {
  display: flex; align-items: center; justify-content: center;
  width: 2.25rem; height: 2.25rem; font-size: var(--fs-13);
}
.pager-box { border: 1px solid var(--border); font: 400 var(--fs-13)/1 var(--font-text); color: var(--text); text-decoration: none; }
.pager-box:hover { border-color: var(--text); color: var(--accent); }
.pager-box.active { background: var(--text); color: #fff; border-color: var(--text); }
.pager-box.disabled { color: var(--sand); cursor: default; }
.pager-box.disabled:hover { border-color: var(--border); color: var(--sand); }
.pager-ellipsis { color: var(--muted); }

/* Feedback banners driven by Django's messages framework (message.tags: success,
   error, warning, info). */
.notice, .errorlist {
  padding: .8rem 1rem;
  margin: 0 0 1rem;
  border: 1px solid var(--border);
  border-left: 3px solid var(--accent);
  border-radius: var(--radius);
  background: var(--surface);
}
.notice.success { border-left-color: var(--success-fg); background: var(--success-bg); color: var(--success-fg); }
.notice.warning { border-left-color: var(--warning-fg); background: var(--warning-bg); color: var(--warning-fg); }
.notice.error, .errorlist { border-left-color: var(--danger); background: #fff7f8; color: var(--danger); }
/* Django's messages float over the page instead of sitting in its flow. In
   flow they pushed everything down by their own height, which on the internal
   screens — fixed to the viewport, with a fixed sidebar beside them — sent the
   whole layout past the bottom and sideways under the rail. Over the page they
   cost no height at all, so a banner can never change the layout underneath it.
   Top right, clear of the sidebar, above the selection bar (z-index 20) and
   below the verifying overlay (50). */
.messages {
  position: fixed;
  top: calc(4.5rem + .75rem);
  right: clamp(1rem, 3vw, 1.5rem);
  z-index: 40;
  display: flex;
  flex-direction: column;
  gap: .5rem;
  width: min(32rem, calc(100vw - 2rem));
  /* Only the banners themselves take clicks; the gap between them doesn't. */
  pointer-events: none;
}
.messages .notice { margin: 0; display: flex; align-items: flex-start; gap: .75rem; pointer-events: auto; box-shadow: 0 6px 20px rgba(0, 0, 0, .12); transition: opacity .3s ease, transform .3s ease; }
/* A confirmation clears itself after a few seconds; warnings and errors wait to
   be closed (see base.html). This is the going-away state for both. */
.messages .notice-leaving { opacity: 0; transform: translateY(-.5rem); pointer-events: none; }
.messages .notice > span { flex: 1; min-width: 0; }
/* Resets the global button box back to a bare glyph. */
.notice-close {
  flex: none; width: 1.25rem; height: 1.25rem; margin: 0; padding: 0;
  border: 0; background: none; color: inherit; cursor: pointer; opacity: .55;
  font: 400 18px/1 var(--font-text);
}
.notice-close:hover { opacity: 1; filter: none; }
.errorlist { list-style: none; }

/* A short hint on hover — e.g. spelling out an abbreviation like "ETD" — shown
   instantly via CSS instead of the browser's native title tooltip (slow to appear,
   inconsistent styling across browsers). Usage: class="tooltip" data-tooltip="...". */
.tooltip { position: relative; cursor: help; }
.tooltip::after {
  content: attr(data-tooltip);
  position: absolute; left: 0; bottom: 100%; margin-bottom: .375rem;
  padding: .375rem .625rem;
  background: var(--text); color: #fff;
  font: 400 var(--fs-12)/1.2 var(--font-text);
  /* Wraps inside a cap rather than running on in one line: a nowrap tooltip is
     an absolutely-positioned box as wide as its text, and it still counts
     toward the page's scrollable area even at opacity 0 — which is exactly how
     an invisible tooltip on a right-hand column gave the whole page a
     horizontal scrollbar into empty space. */
  width: max-content; max-width: 18rem;
  opacity: 0; pointer-events: none; transition: opacity .1s ease;
  z-index: 20;
}
/* On a last column the box would still overhang the page edge — open it
   inward from the right instead. */
th:last-child.tooltip::after, td:last-child.tooltip::after { left: auto; right: 0; }
.tooltip:hover::after { opacity: 1; }

/* A small loading indicator for a synchronous wait (e.g. the invoice-verification
   overlay) — the one place motion survives the otherwise-static design. */
.spinner { width: 40px; height: 40px; border: 2px solid var(--border); border-top-color: var(--text); border-radius: 50%; animation: spin .8s linear infinite; }
@keyframes spin { to { transform: rotate(360deg); } }

/* The upload page's "verifying" overlay. Deliberately no inline `display` on the
   element itself — an inline style beats the browser's own `[hidden]{display:
   none}` rule, which would make `hidden` a no-op and show this on every load. */
.verifying-overlay { position: fixed; inset: 0; z-index: 50; background: var(--surface); align-items: center; justify-content: center; padding: 2rem; }
.verifying-overlay:not([hidden]) { display: flex; }

/* Split invoice/packing-list file pickers, side by side. Grid only applies
   when shown — same reasoning as .verifying-overlay above: an inline
   `display` would beat the browser's `[hidden]{display:none}` rule. */
.file-columns:not([hidden]) { display: grid; grid-template-columns: 1fr 1fr; gap: 0 1.5rem; }
.verifying-card { max-width: 440px; width: 100%; text-align: center; }
.verify-step { display: flex; align-items: center; gap: .875rem; padding: .875rem 1.25rem; border: 1px solid var(--border); margin-bottom: .625rem; background: var(--bg); }
.verify-step-icon { width: 1rem; flex-shrink: 0; text-align: center; font: 600 15px/1 var(--font-text); color: var(--sand); }
.verify-step[data-status="done"] .verify-step-icon { color: var(--success-fg); }
.verify-step-label { flex: 1; font-weight: 600; }
.verify-step-status { color: var(--muted); font-size: var(--fs-13); }

/* A mandatory-document tag next to a section heading, and the sidebar checklist
   tracking those same slots live as files are picked (upload.html's JS). */
.required-tag { font: 600 10px/1 var(--font-text); letter-spacing: var(--tracking-wide); text-transform: uppercase; color: var(--danger); }
.required-check { display: flex; align-items: center; gap: .75rem; padding: .75rem 1rem; background: var(--bg); border: 1px solid var(--border); font-size: var(--fs-14); }
.required-check-icon { display: flex; align-items: center; justify-content: center; width: 1.125rem; height: 1.125rem; border-radius: 50%; border: 1.5px solid var(--danger); flex-shrink: 0; }
.required-check.done .required-check-icon { border-color: var(--success-fg); }
.required-check.done .required-check-icon::after { content: "✓"; color: var(--success-fg); font-size: 11px; font-weight: 700; }
