:root {
  --primary: #2E7D32;
  --primary-dark: #1B5E20;
  --accent: #A5D6A7;
  --on-primary: #FFFFFF;
  --surface: #FFFFFF;
  --surface-soft: #F5F8F5;
  --background: #F5F8F5;
  --border: #D3D4D9;
  --text: #221F1F;
  --muted: #6F6F6F;
  --danger: #C0564B;
  /* Cancelar and Sair. Dark enough for white text at the weight buttons use:
     7.0:1 against #FFFFFF, where 4.5:1 is the floor for 15px bold. */
  --neutral: #55585B;
  --neutral-dark: #3F4245;
  --shadow: rgba(27, 94, 32, .12);
}

* {
  box-sizing: border-box;
}

body {
  margin: 0;
  min-width: 320px;
  font-family: "Figtree", "Segoe UI", Arial, sans-serif;
  background: var(--background);
  color: var(--text);
}

button,
input,
select {
  font: inherit;
}

.admin-shell {
  max-width: 1320px;
  margin: 0 auto;
  padding: 20px;
}

/* `display: grid` on a class beats the browser's `[hidden] { display: none }`,
 * so setting the attribute did nothing visually: the header stayed on screen
 * through the whole login, Sair included. The test asserted `.hidden === true`
 * — the property, which was set — and passed while the bug was on screen. */
.admin-header[hidden] {
  display: none;
}

.admin-header {
  /* Two rows: the lockup and status on top, the module bar underneath. The bar
     spans the full width because eleven buttons do not fit beside a logo. */
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: center;
  gap: 14px 20px;
  padding: 18px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 8px;
  box-shadow: 0 12px 28px var(--shadow);
}

.brand-lockup {
  display: flex;
  align-items: center;
  gap: 14px;
  min-width: 0;
  /* It is a <button> now — the way back to the launcher — but it has to keep
     reading as the product mark, not as a control. */
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  color: inherit;
  text-align: left;
  cursor: pointer;
  border-radius: 8px;
}

.brand-lockup:hover h1 {
  color: var(--primary);
}

.brand-lockup:focus-visible {
  outline: 3px solid var(--focus, var(--accent));
  outline-offset: 3px;
}

.brand-logo {
  width: 150px;
  height: 74px;
  display: block;
  object-fit: contain;
  padding: 6px 10px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 8px;
}

.eyebrow {
  margin: 0 0 4px;
  color: var(--primary);
  font-size: 12px;
  font-weight: 800;
  letter-spacing: .08em;
  text-transform: uppercase;
}

h1,
h2 {
  margin: 0;
  line-height: 1.2;
}

h1 {
  font-size: 24px;
}

h2 {
  font-size: 20px;
}

.header-status {
  display: flex;
  align-items: center;
  gap: 10px;
}

/* The signed-in user, beside the way out. It was a pill reading "Conectado",
 * which said nothing the Sair button next to it did not already imply. The slot
 * still carries a failure — that is the one thing worth interrupting for. */
.header-user {
  color: var(--text);
  font-size: 14px;
  font-weight: 800;
  white-space: nowrap;
}

.header-user[data-mode="warn"] {
  color: var(--danger);
}

.tabbar {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin: 16px 0;
}

.tab-button,
.icon-button,
.row-action {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  min-height: 40px;
  border: 1px solid var(--border);
  border-radius: 8px;
  cursor: pointer;
  font-weight: 800;
  transition: border-color .16s ease, box-shadow .16s ease, transform .16s ease;
}

.tab-button {
  padding: 8px 12px;
  background: var(--surface);
  color: var(--text);
}

.tab-button.active {
  border-color: var(--primary);
  color: var(--on-primary);
  background: var(--primary);
}

.icon-button {
  padding: 8px 12px;
  background: var(--primary);
  color: var(--on-primary);
  border-color: var(--primary);
  box-shadow: 0 10px 18px color-mix(in srgb, var(--primary) 18%, transparent);
}

.row-action {
  /* Sized to the glyph, so the button is the height of the line it sits on and
     the row can be as thin as its text. */
  min-height: 28px;
  padding: 4px 7px;
  margin: 0 0 0 2px;
  background: var(--surface-soft);
  color: var(--primary-dark);
}

.tab-button:hover,
.icon-button:hover,
.row-action:hover {
  border-color: var(--primary);
  transform: translateY(-1px);
}

.row-action.danger {
  color: var(--danger);
}

button:disabled {
  cursor: wait;
  opacity: .72;
}

.material-symbols-outlined {
  font-size: 20px;
  line-height: 1;
  font-variation-settings:
    "FILL" 0,
    "wght" 500,
    "GRAD" 0,
    "opsz" 24;
}

.admin-main {
  min-height: 520px;
}

.admin-panel {
  display: none;
  padding: 18px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 8px;
  box-shadow: 0 12px 28px var(--shadow);
}

.admin-panel.active {
  display: grid;
  gap: 14px;
}

.panel-heading {
  display: flex;
  align-items: end;
  justify-content: space-between;
  gap: 16px;
}

.search-input,
.admin-form input,
.admin-form select,
.filters-row select {
  min-height: 40px;
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 0 10px;
  background: var(--surface-soft);
  color: var(--text);
}

.search-input {
  width: min(360px, 100%);
}

.admin-form,
.filters-row {
  display: grid;
  gap: 10px;
}

.admin-form {
  grid-template-columns: repeat(4, minmax(140px, 1fr)) auto;
  align-items: end;
  padding: 12px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--surface-soft);
}

.modules-form {
  grid-template-columns: repeat(6, minmax(110px, 1fr)) auto;
}

.permissions-form {
  grid-template-columns: minmax(130px, 1fr) minmax(130px, .8fr) minmax(130px, .8fr) minmax(180px, 1.2fr) auto;
}

.filters-row {
  grid-template-columns: minmax(220px, 360px) minmax(160px, 220px);
}

/* The module screens render their grid straight into this, with no frame. It
 * needs the same scroll container: the columns no longer wrap, so a wide grid
 * — the analytical sales report has seven — would otherwise push the whole page
 * sideways instead of scrolling inside its own box. */
.module-grid {
  overflow-x: auto;
}

/* The module's name is already on the filled button above, so printing it again
 * as a heading says the same thing twice. It stays in the document — it is the
 * page's only h1, and a screen reader navigating by heading needs it. */
.module-header h1 {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.grid-frame {
  overflow: auto;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--surface);
}

table {
  width: 100%;
  border-collapse: collapse;
  min-width: 760px;
}

th,
td {
  /* Tight to the text. The row used to be 10px above and below with the content
     pinned to the top, which left the action buttons floating away from the
     line they belong to. */
  padding: 6px 12px;
  border-bottom: 1px solid var(--border);
  text-align: left;
  vertical-align: middle;
}

/* Every column hugs its content except one, which takes the leftover width.
   Without this the browser spreads the slack across all of them and the Ações
   column sits at a different x in every module — and shifts as soon as a name
   gets longer. */
th:not(.col-fill),
td:not(.col-fill) {
  width: 1%;
  white-space: nowrap;
}

.col-fill {
  width: 100%;
}

/* Actions hard against the right edge, in one place, on every screen. */
th.col-actions,
td.col-actions {
  text-align: right;
}

td.col-actions {
  /* The buttons are the row's height; anything more re-introduces the padding
     just removed above. */
  padding-top: 2px;
  padding-bottom: 2px;
}

td.col-actions .row-action {
  margin: 0 0 0 2px;
}

th {
  position: sticky;
  top: 0;
  z-index: 1;
  background: var(--surface-soft);
  color: var(--muted);
  font-size: 13px;
}

tr:last-child td {
  border-bottom: 0;
}

.sort-button {
  all: unset;
  cursor: pointer;
  font-weight: 800;
}

.state-badge {
  display: inline-flex;
  padding: 3px 8px;
  border-radius: 999px;
  color: var(--primary-dark);
  background: color-mix(in srgb, var(--primary) 12%, white);
  font-size: 12px;
  font-weight: 800;
}

/* One badge for every state made the column decorative: eleven green pills say
 * nothing, and finding the inactive seller meant reading each row. Red is for
 * the state that means "do not use this" — nothing else.
 *
 * Deliberately NOT red: `open` on a payable and `sold` on a piece. Money still
 * owed and a piece that sold are the normal course of business, and colouring
 * them as problems would train the operator to ignore the colour. */
.state-badge[data-state="inactive"] {
  color: var(--danger);
  background: color-mix(in srgb, var(--danger) 12%, white);
}

/* ---------------------------------------------------------------- dashboard */

/* Three columns, as asked. Two below 1200px and one below 780px, because a
 * chart squeezed into a third of a phone is a coloured smudge. `auto-fit` with
 * a minimum does that without a media query per breakpoint. */
.dashboard-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(340px, 1fr));
  gap: 16px;
  margin-top: 4px;
}

@media (min-width: 1200px) {
  .dashboard-grid {
    grid-template-columns: repeat(3, 1fr);
  }
}

.dashboard-panel {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 14px 16px 10px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 8px;
  box-shadow: 0 8px 20px var(--shadow);
  min-width: 0;
}

.dashboard-panel header {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
}

.dashboard-panel h2 {
  font-size: 15px;
}

.panel-hint {
  color: var(--muted);
  font-size: 12px;
}

.panel-totals {
  margin: 0;
  color: var(--muted);
  font-size: 13px;
}

.panel-totals strong {
  color: var(--text);
  font-variant-numeric: tabular-nums;
}

.panel-totals span {
  margin: 0 4px;
}

.dashboard-greeting {
  margin: 0;
  color: var(--muted);
}

/* The chart scales with its panel: the viewBox fixes the coordinate system and
 * the element takes whatever width the column gives it. */
.chart {
  width: 100%;
  height: 230px;
}

/* The panel's own month picker. `<input type="month">` is unimplemented in
 * enough browsers that it cannot be relied on — it silently degrades to a text
 * box showing the raw `2026-08`, with no picker and no error. */
.month-picker {
  position: relative;
  max-width: 210px;
  margin-left: auto;
}

.month-field {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  width: 100%;
  min-height: 38px;
  padding: 0 10px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--surface-soft);
  color: var(--text);
  font: inherit;
  font-weight: 600;
  cursor: pointer;
}

.month-field:hover {
  border-color: var(--primary);
}

.month-field .material-symbols-outlined {
  font-size: 20px;
  color: var(--primary);
}

.month-popover {
  position: fixed;
  z-index: 60;
  padding: 10px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 8px;
  box-shadow: 0 12px 28px var(--shadow);
}

.month-popover[hidden] {
  display: none;
}

.month-year {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 8px;
  font-size: 15px;
}

.month-step {
  display: inline-flex;
  padding: 4px;
  border: 1px solid transparent;
  border-radius: 6px;
  background: transparent;
  color: var(--primary-dark);
  cursor: pointer;
}

.month-step:hover {
  border-color: var(--primary);
}

.month-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 6px;
}

.month-grid button {
  padding: 8px 0;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: var(--surface-soft);
  color: var(--text);
  font: inherit;
  font-weight: 700;
  font-size: 13px;
  cursor: pointer;
}

.month-grid button:hover:not(:disabled) {
  border-color: var(--primary);
}

.month-grid button.chosen {
  background: var(--primary);
  border-color: var(--primary);
  color: var(--on-primary);
}

/* Outside the data, drawn rather than hidden: the grid keeps its shape and the
 * operator can see where the store's history stops. */
.month-grid button:disabled {
  opacity: .35;
  cursor: not-allowed;
}

.chart-bar {
  fill: color-mix(in srgb, var(--primary) 55%, white);
}

.chart-bar:hover {
  fill: var(--primary);
}

.chart-line {
  fill: none;
  stroke: var(--primary-dark);
  stroke-width: 2;
  stroke-linejoin: round;
  vector-effect: non-scaling-stroke;
}

.chart-dot {
  fill: var(--primary-dark);
}

.chart-grid {
  stroke: var(--border);
  stroke-width: 1;
  vector-effect: non-scaling-stroke;
}

.chart-tick {
  fill: var(--muted);
  font-size: 10px;
  font-variant-numeric: tabular-nums;
}

.tick-left {
  text-anchor: end;
}

.tick-right {
  text-anchor: start;
}

.chart-label {
  fill: var(--muted);
  font-size: 10px;
  text-anchor: end;
}

.chart-legend {
  display: flex;
  gap: 14px;
  font-size: 12px;
  font-weight: 800;
  color: var(--muted);
}

.chart-legend span::before {
  content: "";
  display: inline-block;
  width: 10px;
  height: 10px;
  margin-right: 5px;
  border-radius: 2px;
  vertical-align: -1px;
}

.legend-bar::before {
  background: color-mix(in srgb, var(--primary) 55%, white);
}

.legend-line::before {
  background: var(--primary-dark);
  border-radius: 999px;
}

/* The pie sits beside its legend on a wide panel and above it on a narrow one.
 * A slice's angle is readable to about ten percent, so the count is what the
 * operator actually reads — the drawing is the shape of the month. */
.pie-wrap {
  display: flex;
  align-items: center;
  gap: 14px;
  flex-wrap: wrap;
}

.pie {
  width: 168px;
  height: 168px;
  flex: none;
}

.pie-slice {
  stroke: var(--surface);
  stroke-width: 1.5;
}

.pie-legend {
  flex: 1 1 180px;
  min-width: 0;
  margin: 0;
  padding: 0;
  list-style: none;
  font-size: 13px;
}

.pie-legend li {
  display: grid;
  grid-template-columns: 12px 1fr auto auto;
  align-items: center;
  gap: 8px;
  padding: 2px 0;
}

.pie-key {
  width: 10px;
  height: 10px;
  border-radius: 2px;
}

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

.pie-count {
  font-weight: 800;
  font-variant-numeric: tabular-nums;
}

.pie-share {
  color: var(--muted);
  font-variant-numeric: tabular-nums;
  min-width: 34px;
  text-align: right;
}

/* Eight steps around the brand green, ordered so neighbours never sit next to
 * each other on the wheel — adjacent slices have to be told apart at a glance,
 * and a smooth gradient of one hue cannot do that. */
.pie-slice[data-index="0"], .pie-key[data-index="0"] { fill: #2E7D32; background: #2E7D32; }
.pie-slice[data-index="1"], .pie-key[data-index="1"] { fill: #8BC34A; background: #8BC34A; }
.pie-slice[data-index="2"], .pie-key[data-index="2"] { fill: #1B5E20; background: #1B5E20; }
.pie-slice[data-index="3"], .pie-key[data-index="3"] { fill: #C0564B; background: #C0564B; }
.pie-slice[data-index="4"], .pie-key[data-index="4"] { fill: #4DB6AC; background: #4DB6AC; }
.pie-slice[data-index="5"], .pie-key[data-index="5"] { fill: #A5D6A7; background: #A5D6A7; }
.pie-slice[data-index="6"], .pie-key[data-index="6"] { fill: #55585B; background: #55585B; }
.pie-slice[data-index="7"], .pie-key[data-index="7"] { fill: #7E9E45; background: #7E9E45; }

/* Anterior / Próxima, and how much of the table is on screen. Sits under the
 * grid, right-aligned with the count on the left so the eye lands on the number
 * first — "de 3.746" is the part that changes what the operator does next. */
.module-pager {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 2px 2px;
}

.module-pager:empty {
  display: none;
}

.pager-count {
  margin-right: auto;
  color: var(--muted);
  font-size: 13px;
  font-variant-numeric: tabular-nums;
}

.module-pager button:disabled {
  opacity: .45;
  cursor: not-allowed;
}

.empty-state {
  padding: 24px;
  color: var(--muted);
  text-align: center;
}

.spinner {
  width: 14px;
  height: 14px;
  border-radius: 50%;
  border: 2px solid rgba(255, 255, 255, .55);
  border-top-color: var(--on-primary);
  animation: spin .7s linear infinite;
}

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

@media (max-width: 980px) {
  .admin-header,
  .panel-heading,
  .header-status {
    align-items: stretch;
    flex-direction: column;
  }

  .admin-form,
  .modules-form,
  .permissions-form,
  .filters-row {
    grid-template-columns: 1fr;
  }

  .search-input {
    width: 100%;
  }
}

/* ---------------------------------------------------------------- CRUD pattern
 *
 * The shape every module screen shares: a toolbar with search on the left and
 * the primary action anchored top-right, a grid with a trailing Ações column,
 * and a footer total. See docs/core/DESIGN_SYSTEM.md.
 *
 * Every colour here is a token reference. A literal would survive a rebrand and
 * quietly leave one screen the old colour.
 */

.module-screen {
  display: flex;
  flex-direction: column;
  gap: 16px;
}

.module-toolbar {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
}

.module-search {
  /* Takes the available width; the filters and the primary action keep theirs. */
  flex: 1 1 240px;
  min-width: 200px;
  padding: 9px 12px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--surface);
  color: var(--text);
  font: inherit;
}

.module-search:focus-visible {
  outline: 3px solid var(--focus, var(--accent));
  outline-offset: 1px;
}

.module-filters {
  display: flex;
  gap: 8px;
  align-items: center;
}

/* Anchors the primary action to the right end of the toolbar. */
/* One button, three intents.
 *
 * `.button-secondary` was used on "+ Adicionar peça", "+ Bloco" and
 * "Reprocessar estoque" and never existed in this file, so those three fell
 * back to the browser's default button — a different size, a different font and
 * a different colour sitting next to Salvar. That is the same defect the
 * comment below described for `.button-primary`, found again on 2026-08-03.
 *
 * Geometry is declared once for all of them. Only the fill differs, and it
 * differs only to separate "do the thing" from "leave without doing it".
 *
 * The base rule. There was only the toolbar override, so a `.button-primary`
 * anywhere else — the login screen, the Administração header — fell back to the
 * browser's default button and came out blue in a green panel. */
.button-primary,
.button-secondary,
.button-cancel {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  min-height: 40px;
  padding: 8px 14px;
  border: 1px solid var(--primary);
  border-radius: 8px;
  background: var(--primary);
  color: var(--on-primary);
  font: inherit;
  font-weight: 800;
  cursor: pointer;
  box-shadow: 0 10px 18px color-mix(in srgb, var(--primary) 18%, transparent);
  transition: background .16s ease, border-color .16s ease;
}

/* Same weight as Salvar, because it is the same kind of act: it changes the
 * document. Only leaving does not. */
.button-secondary {
  border-color: var(--primary);
  background: var(--primary);
  color: var(--on-primary);
}

/* Cancelar, Fechar, Sair. The same button as Salvar in every dimension the eye
 * measures — height, padding, radius, weight — and a different fill, because
 * the only thing that separates them is whether anything happens. */
.button-cancel {
  border-color: var(--neutral);
  background: var(--neutral);
  color: var(--on-primary);
}

.button-primary:hover,
.button-secondary:hover {
  background: var(--primary-dark, var(--primary));
  border-color: var(--primary-dark, var(--primary));
}

.button-cancel:hover {
  background: var(--neutral-dark);
  border-color: var(--neutral-dark);
}

.button-primary:focus-visible,
.button-secondary:focus-visible,
.button-cancel:focus-visible {
  outline: 3px solid var(--focus, var(--accent));
  outline-offset: 2px;
}

.button-primary:disabled,
.button-secondary:disabled,
.button-cancel:disabled {
  opacity: .7;
  cursor: wait;
}

.module-toolbar .button-primary {
  margin-left: auto;
}

.module-total {
  align-self: flex-end;
  padding: 8px 4px;
  color: var(--muted);
}

.module-total strong {
  color: var(--text);
  font-variant-numeric: tabular-nums;
}

/* Money and references line up when the digits are the same width. */
td.numeric,
.module-total strong {
  text-align: right;
  font-variant-numeric: tabular-nums;
}

td.reference {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
}

.row-action {
  border: 1px solid transparent;
  background: transparent;
  color: var(--primary);
  border-radius: 6px;
  padding: 4px 6px;
  cursor: pointer;
  line-height: 1;
}

/* One family, one weight, one size for every action glyph.
 *
 * These were emoji, and the system rendered 🗑 👁 🔑 in colour from the emoji
 * font while ✎ ✓ ↔ came out as thin text glyphs — so a single row of buttons
 * had three weights and two colour treatments. Material Symbols is what the
 * rest of the panel already uses. */
.row-action .material-symbols-outlined {
  font-size: 20px;
  font-variation-settings: "wght" 400;
  color: inherit;
}


.row-action:hover {
  background: var(--surface-soft);
  border-color: var(--border);
}

.row-action:focus-visible {
  outline: 3px solid var(--focus, var(--accent));
  outline-offset: 1px;
}

/* ------------------------------------------------------------------- modal */

.modal-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, .45);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
  z-index: 50;
}

.modal {
  background: var(--surface);
  color: var(--text);
  border-radius: 12px;
  box-shadow: 0 18px 48px var(--shadow);
  width: min(560px, 100%);
  max-height: 90vh;
  display: flex;
  flex-direction: column;
}

/* Documents carry a header plus a lines grid; fifteen lines has to be workable,
 * so they get a full-width panel rather than a small centred card. */
.modal-wide {
  width: min(1100px, 100%);
}

.modal-header,
.modal-footer {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 14px 18px;
}

.modal-header {
  border-bottom: 1px solid var(--border);
}

.modal-header h2 {
  margin: 0;
  font-size: 17px;
}

.modal-close {
  margin-left: auto;
  border: none;
  background: transparent;
  color: var(--muted);
  font-size: 22px;
  line-height: 1;
  cursor: pointer;
}

.modal-body {
  padding: 18px;
  overflow: auto;
}

.modal-footer {
  border-top: 1px solid var(--border);
  justify-content: flex-end;
}

/* ------------------------------------------------------------------ dialog */

/* A question the panel asks, not one the browser asks. `window.confirm` drew an
 * OS sheet at the top of the window, in the browser's typeface and language,
 * with buttons the design system has no say over. This is the same modal and
 * the same buttons as everything else. */
.dialog {
  width: min(440px, 100%);
}

.dialog-message {
  margin: 0;
  line-height: 1.5;
  color: var(--text);
}

/* Destructive confirmations only — discarding a form, deleting a document. The
 * neutral fill is for leaving; this is for something that cannot be undone. */
.button-danger {
  border-color: var(--danger);
  background: var(--danger);
  color: var(--on-primary);
}

.button-danger:hover {
  border-color: var(--danger);
  background: color-mix(in srgb, var(--danger) 82%, black);
}

/* Validation errors render against their field; module-level ones above the
 * form. A single banner for everything makes the operator hunt. */
.field-error,
.form-error {
  color: var(--danger);
  margin: 6px 0 0;
  font-size: 13px;
}

.form-error {
  margin: 0 0 12px;
  padding: 8px 10px;
  border-radius: 8px;
  border: 1px solid var(--danger);
}

/* --------------------------------------------------------------- module form
 * The modal body. Two columns on a wide screen, one when narrow — a form that
 * needs scrolling on a laptop is a form the counter will resent.
 */

.module-form {
  display: grid;
  grid-template-columns: repeat(2, minmax(200px, 1fr));
  gap: 12px 16px;
}

.form-field {
  display: flex;
  flex-direction: column;
  gap: 4px;
  min-width: 0;
}

.form-field > span {
  color: var(--muted);
  font-size: 13px;
  font-weight: 800;
}

.form-field input,
.form-field select {
  min-height: 38px;
  padding: 0 10px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--surface-soft);
  color: var(--text);
}

/* A readonly field still looks like a field, so the operator can see it exists
 * and is deliberately not editable — an immutable reference rendered as plain
 * text reads as a rendering bug. */
.form-field input[readonly] {
  background: var(--surface);
  color: var(--muted);
  cursor: not-allowed;
}

/* Not the same case as the readonly input above, and the difference is the
 * modal's mode. A readonly field sits inside a form the operator is filling in,
 * so it has to look like a field that is deliberately locked. A document opened
 * for viewing has no save button at all — every field is locked — and drawing
 * boxes around all of them makes a record look like a form that will not work.
 * Here the value is the content. */
.form-field .form-static {
  min-height: 38px;
  display: flex;
  align-items: center;
  margin: 0;
  padding: 0 2px;
  font-weight: 600;
  color: var(--text);
  overflow-wrap: anywhere;
}

/* The list opens upward.
 *
 * These fields sit at the top of a document modal, right above the lines the
 * operator is building. A list dropping down covers exactly the thing they are
 * looking at, and on the sale form it would cover the pieces already added. */
.combobox {
  position: relative;
}

/* The same field in a toolbar, where there is no room for a label above it and
 * the current value already says what the filter is. */
.combobox-filter {
  position: relative;
  min-width: 190px;
}

.combobox-filter .combobox-input {
  width: 100%;
  min-height: 40px;
  padding: 0 10px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--surface-soft);
  color: var(--text);
}

.combobox-list {
  /* Fixed, not absolute: `.modal-body` scrolls, and a scrolling box clips
     anything positioned inside it. Opening upward from the first row of a
     document header put the list through the modal's top edge and it was cut
     off. Top, left, width and height are set from combobox.js. */
  position: fixed;
  z-index: 60;
  max-height: 260px;
  overflow-y: auto;
  margin: 0;
  padding: 4px;
  list-style: none;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 8px;
  box-shadow: 0 -10px 24px var(--shadow);
}

.combobox-list[hidden] {
  display: none;
}

.combobox-list li {
  padding: 7px 10px;
  border-radius: 6px;
  cursor: pointer;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.combobox-list li.active,
.combobox-list li:hover {
  background: var(--primary);
  color: var(--on-primary);
}

.combobox-empty {
  color: var(--muted);
  cursor: default;
}

.combobox-empty:hover {
  background: none;
  color: var(--muted);
}

.form-field small {
  color: var(--muted);
  font-size: 12px;
}

.form-readonly {
  margin: 0;
  min-height: 38px;
  display: flex;
  align-items: center;
  color: var(--text);
}

.form-note,
.form-error {
  grid-column: 1 / -1;
}

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

@media (max-width: 720px) {
  .module-form {
    grid-template-columns: 1fr;
  }
}

/* ------------------------------------------------------------ document modal
 * Header plus a lines grid, with the line editor and the stock picker opening
 * on top. The legacy desktop already nested its dialogs this way.
 */

.document-form {
  grid-template-columns: 1fr;
}

.document-header {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 12px 16px;
}

.document-lines {
  border-top: 1px solid var(--border);
  padding-top: 12px;
  display: grid;
  gap: 10px;
}

.lines-toolbar {
  display: flex;
  align-items: center;
  gap: 12px;
}

.lines-toolbar .button-secondary {
  margin-left: auto;
}

/* The reference the API will assign, shown while the operator adds lines. It
 * reads as a preview because it says so — silently showing a number that later
 * differs is worse than showing none. */
.preview-hint {
  color: var(--muted);
  font-size: 13px;
}

.lines-grid table {
  min-width: 0;
}

.lines-total {
  align-self: end;
  text-align: right;
  color: var(--muted);
}

.lines-total strong {
  color: var(--text);
  font-variant-numeric: tabular-nums;
}

.stock-picker {
  display: grid;
  gap: 12px;
}

.filter-toggle {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  color: var(--muted);
  font-size: 13px;
}

.movement-view {
  display: grid;
  gap: 12px;
}

.content-editor {
  display: grid;
  gap: 10px;
}

.content-block {
  display: grid;
  grid-template-columns: 130px auto 1fr 40px;
  gap: 8px;
  align-items: start;
  padding: 10px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--surface-soft);
}

.content-block textarea,
.module-form textarea {
  width: 100%;
  padding: 8px 10px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--surface);
  color: var(--text);
  font: inherit;
  resize: vertical;
}

/* Shows the blocks as the app renders them. The contract is a legal text and
 * an editor that does not show its shape invites surprises. */
.content-preview {
  padding: 14px;
  border: 1px dashed var(--border);
  border-radius: 8px;
  background: var(--surface);
}

.content-preview h3,
.content-preview h4,
.content-preview h5 {
  margin: 8px 0 4px;
}

@media (max-width: 720px) {
  .content-block {
    grid-template-columns: 1fr;
  }
}

/* ------------------------------------------------------------------ launcher
 * Rectangular tiles with a large icon above the module name, per
 * docs/core/DESIGN_SYSTEM.md. Only modules the user can view are rendered —
 * the backend decides that, the panel renders it.
 */

.module-root:empty {
  display: none;
}


/* The template's admin screens are now one module among eleven, hidden until
 * ADMIN is opened. */
.admin-legacy {
  display: none;
}

.admin-legacy.visible {
  display: block;
}


/* --------------------------------------------------------------- module bar
 *
 * Every module the user holds, always on screen. It replaced a back button and
 * then a dropdown; both hid the destinations until you asked for them.
 */

.module-nav {
  grid-column: 1 / -1;
  display: flex;
  flex-wrap: nowrap;
  gap: 6px;
  padding-top: 14px;
  border-top: 1px solid var(--border);
}

.module-tab {
  /* Icon over label, so eleven buttons fit one row instead of wrapping into
     two. Stacked they are about 100px wide against 150px side by side, and the
     shell is 1320px: side by side the eleventh always fell to a second line. */
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 4px;
  flex: 1 1 0;
  min-width: 0;
  min-height: 60px;
  padding: 8px 6px;
  border: 1px solid transparent;
  border-radius: 8px;
  background: var(--surface-soft);
  color: var(--primary-dark);
  font: inherit;
  font-weight: 800;
  font-size: 14px;
  white-space: nowrap;
  cursor: pointer;
  transition: background .16s ease, border-color .16s ease, color .16s ease;
}

.module-tab .material-symbols-outlined {
  font-size: 24px;
}

.module-tab-label {
  font-size: 12px;
  line-height: 1.1;
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
}

.module-tab:hover {
  border-color: var(--primary);
}

.module-tab:focus-visible {
  outline: 3px solid var(--focus, var(--accent));
  outline-offset: 2px;
}

/* Where you are. Filled rather than outlined: at a glance across eleven
   buttons, a border weight is not a difference you can see. */
.module-tab[aria-current="page"] {
  background: var(--primary);
  border-color: var(--primary);
  color: var(--on-primary);
  box-shadow: 0 8px 16px color-mix(in srgb, var(--primary) 22%, transparent);
}

.module-tab[aria-current="page"]:hover {
  background: var(--primary-dark, var(--primary));
}

/* One row holds eleven stacked buttons down to about 900px. Below that they
   wrap rather than shrink into unreadable slivers. */
@media (max-width: 900px) {
  .module-nav {
    flex-wrap: wrap;
  }

  .module-tab {
    flex: 0 1 auto;
    min-width: 78px;
  }
}

@media (max-width: 560px) {
  /* Narrower still and eleven labels eat the screen. The icon carries it, and
     the accessible name survives on the button's own label. */
  .module-tab-label {
    display: none;
  }

  .module-tab[aria-current="page"] .module-tab-label {
    display: inline;
  }
}

/* ---------------------------------------------------------- dashboards home */

.dashboard-placeholder {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 12px;
  min-height: 320px;
  padding: 40px 20px;
  text-align: center;
}

.dashboard-placeholder .material-symbols-outlined {
  font-size: 56px;
  color: color-mix(in srgb, var(--primary) 45%, transparent);
}

.dashboard-greeting {
  margin: 0;
  font-size: 18px;
  font-weight: 800;
  color: var(--text);
}

/* --------------------------------------------------------------- sign in
 *
 * The panel had no login at all: it sent a hard-coded identity and a flag told
 * the API to trust it. AUTH-004 replaced that with a real session, and this is
 * the screen that was missing.
 */

.login-screen {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 70vh;
  padding: 24px 16px;
}

.login-card {
  display: flex;
  flex-direction: column;
  gap: 14px;
  width: 100%;
  max-width: 380px;
  padding: 32px 28px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 12px;
  box-shadow: 0 18px 40px var(--shadow);
}

.login-logo {
  align-self: center;
  width: 200px;
  max-width: 70%;
  height: auto;
  margin-bottom: 4px;
}

.login-card h1 {
  margin: 0;
  font-size: 20px;
  text-align: center;
}

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

.login-field {
  display: flex;
  flex-direction: column;
  gap: 6px;
  font-size: 13px;
  font-weight: 800;
  color: var(--muted);
}

.login-field input {
  padding: 10px 12px;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: var(--surface);
  color: var(--text);
  font: inherit;
  font-weight: 500;
}

.login-field input:focus-visible {
  outline: 3px solid var(--focus, var(--accent));
  outline-offset: 1px;
}

.login-field small {
  font-weight: 500;
  color: var(--muted);
}

.login-submit {
  margin-top: 6px;
  min-height: 44px;
}

/* Present in the DOM from the start and revealed on failure, so the card does
   not jump when a message appears. */
.login-error {
  margin: 0;
  padding: 10px 12px;
  border-radius: 8px;
  background: color-mix(in srgb, var(--danger) 12%, transparent);
  color: var(--danger);
  font-size: 13px;
  font-weight: 700;
  text-align: center;
}

.login-error[hidden] {
  display: none;
}

/* Sair sits beside Atualizar but must not compete with it for attention. */
/* A block inside a form that is optional as a whole — panel access on the
 * seller form. Grouped so an operator registering someone who will never sign
 * in can see there is nothing here they have to fill in. */
.form-section {
  margin: 8px 0 0;
  padding: 14px 14px 4px;
  border: 1px solid var(--border);
  border-radius: 8px;
}

.form-section legend {
  padding: 0 6px;
  font-size: 13px;
  font-weight: 800;
  color: var(--primary-dark);
}

/* Search and a primary action side by side in a panel heading. */
.heading-actions {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
}

.heading-actions .search-input {
  min-width: 220px;
}

/* A cell that says "nothing here, and that means something" — an account with
 * no login, a password still waiting to be replaced. */
.muted-cell {
  color: var(--muted);
  font-size: 12px;
  font-weight: 600;
}

/* The shared modal is used by the Administração screens too, so its forms need
 * to stack the same way the module forms do. */
.modal-form {
  display: flex;
  flex-direction: column;
  gap: 12px;
}
