:root {
  /* ── Brand ──────────────────────────────────────────────────────────────
     Contrast ratios measured against every surface this token appears on.
     Update the annotation whenever the value changes.                      */
  --color-brand-0:       #3D5C0A;   /* dark green  — primary brand — 6.82:1 on s-0 · 7.68:1 on white */
  --color-brand-1:       #486B13;   /* mid green   — links/interactive — 5.50:1 on s-0 · 6.20:1 on white */
  --color-brand-2:       #A8C96B;   /* light green — tint/highlight (use on dark bg only) */

  /* ── Surfaces ────────────────────────────────────────────────────────── */
  --color-surface-0:     #F0F2EE;   /* page base — deepest layer    */
  --color-surface-1:     #F7F8F5;   /* cards, panels                */
  --color-surface-2:     #FFFFFF;   /* elevated elements, overlays  */
  --color-surface-header: #EDF6FA;  /* soft blue wash — header only */

  /* ── Content ─────────────────────────────────────────────────────────── */
  --color-content:       #1A2B1A;   /* near-black — 13.3:1 on s-0 · 14.0:1 on s-1 · 14.9:1 on white (AAA) */
  --color-content-muted: #4A5E50;   /* muted — 6.20:1 on s-0 · 6.55:1 on s-1 · 6.98:1 on white (AA) */

  --color-separators:    #D4DAD0;   /* decorative only — not used for text */

  /* ── Accents ─────────────────────────────────────────────────────────── */
  --color-accent-0:      #5B7FA6;   /* corporate blue — verify contrast before use as text */
  --color-accent-1:      #8A6D3B;   /* warm amber     — verify contrast before use as text */
  --color-accent-2:      #C0392B;   /* error red      — 5.44:1 on white · 4.68:1 on #FCEAE8 badge bg */
  --color-accent-4:      #7F55CC;   /* purple (from Cintia palette) — 5.15:1 on white (AA) */
  --color-accent-5:      #B85A00;   /* burnt orange (from Cintia palette) — 4.67:1 on white (AA) */

  /* ── Badge token pairs ────────────────────────────────────────────────
     Each badge must declare both text and bg tokens as a pair.
     Contrast ratio for the pair is annotated on the bg token.             */
  --color-badge-ok-text:      #3D5C0A;   /* = brand-0 */
  --color-badge-ok-bg:        #C2DB88;   /* 5.04:1 with ok-text */
  --color-badge-pending-text: #5C5044;   /* warm dark brown */
  --color-badge-pending-bg:   #EDE8DF;   /* 6.41:1 with pending-text */

  /* ── Machine-suggested values ─────────────────────────────────────────
     Violet = "the Cancheiro chose this, you have not yet" (doc/design/
     nota-redesign.org §3.4). Ink only, plus a leading ✦ — never a chip.   */
  --color-suggested-text:     #5E3A9E;   /* 8.16:1 on white · 7.65:1 on s-1 · 7.24:1 on s-0 · 7.04:1 on suggested-bg */
  --color-suggested-bg:       #F1ECFA;   /* arrival pulse only — 7.04:1 with suggested-text · 12.90:1 with content */

  /* Gradients — kept but subdued */
  --gradient-0: linear-gradient(135deg, #3D5C0A 0%, #5A8018 100%);
  --gradient-1: linear-gradient(135deg, #5B7FA6 0%, #3D5C7A 100%);
  --gradient-2: linear-gradient(135deg, #D6CFBF 0%, #8A7E6E 100%);
}

/********************************* CSS Reset **********************************/
*, *::before, *::after { margin: 0; padding: 0; box-sizing: border-box; }

article, aside, details, figcaption, figure,
footer, header, hgroup, menu, nav, section { display: block; }

/********************************* Base ***************************************/
body {
  font-family: "Inter", "Helvetica Neue", "Arial", system-ui, -apple-system, sans-serif;
  font-size: 16px;
  line-height: 1.6;
  background: var(--color-surface-0);
  color: var(--color-content);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

a        { color: var(--color-brand-1); text-decoration: none; }
a:hover  { color: var(--color-brand-0); text-decoration: underline; }
ul       { list-style: none; }

/* <time> elements always render dates/times — tabular-nums keeps digits stable
   when multiple timestamps appear in a list or table. */
time { font-variant-numeric: tabular-nums; }

dl {
  display: grid;
  grid-template-columns: max-content auto;
  gap: 2px 20px;
  margin-bottom: 16px;
}

dt {
  grid-column-start: 1;
  font-size: 0.8rem;
  font-weight: 600;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--color-content-muted);
  padding-block: 7px;
  white-space: nowrap;
}

dd {
  grid-column-start: 2;
  font-size: 0.9375rem;
  line-height: 1.5;
  color: var(--color-content);
  padding-block: 7px;
  border-bottom: 1px solid var(--color-separators);
  /* NOTE: tabular-nums NOT applied globally here — dd content is often plain text
     (names, descriptions). Add font-variant-numeric: tabular-nums in the
     page-specific stylesheet for <dl> blocks that show amounts or dates, e.g.:
       dl:has(dt:first-child) dd { font-variant-numeric: tabular-nums; }
     or target the specific dl by id/context selector. */
}

dt:last-of-type + dd { border-bottom: none; }

/********************************* Layout *************************************/
/* Default: nav collapsed to icon-only strip (48px).                         */
/* .nav_open class widens it — toggled by JS on load and on resize.          */
body {
  /* One source of truth for the header's height: the grid row, the sticky
     offsets and the mobile dropdown position all read it, so the two-row
     header below 900px (see Responsive) moves them together. */
  --header-height: 60px;

  display: grid;
  grid-template-columns: 48px 1fr;
  grid-template-rows: var(--header-height) 1fr;
  grid-template-areas:
    "nav header"
    "nav main";
  min-height: 100vh;
  transition: grid-template-columns 0.25s ease;
}

body.nav_open {
  grid-template-columns: 220px 1fr;
}

/********************************* Header *************************************/
body > header {
  grid-area: header;
  display: flex;
  align-items: center;
  gap: 16px;
  padding: 0 24px 0 16px;
  background: var(--color-surface-header);
  border-bottom: 1px solid #C8D8E2;  /* blue-tinted separator — matches surface-header */
  overflow: visible;
  position: relative;
  z-index: 10;
  transition: border-bottom-color 0.18s ease;

  /* A grid item defaults to min-width: auto, i.e. "never smaller than my
     content". The header and <main> share the second grid column, so the
     widest unbreakable thing in EITHER of them silently became the minimum
     width of BOTH — a long header subtitle was pushing report content off the
     right edge of the viewport. Opting both out of auto is what stops the next
     wide element from doing the same. */
  min-width: 0;
}

/* Page title — left-aligned, takes up remaining space */
body > header hgroup {
  flex: 1;
  min-width: 0;
  display: flex;
  align-items: baseline;
  gap: 12px;
  overflow: hidden;
}

body > header hgroup h1 {
  font-size: 1.125rem;
  font-weight: 700;
  letter-spacing: -0.01em;
  color: var(--color-content);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

body > header hgroup p {
  font-size: 0.8125rem;
  font-weight: 500;
  color: var(--color-content-muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;

  /* The subtitle must be allowed to vanish rather than to push. It is the one
     header element whose length is unbounded — "Safra 2025/26 · comparado com
     2024/25" — and with min-width: auto it set the header's minimum width,
     which the grid then handed to <main> as well (the two share a column). The
     result was a page that scrolled sideways at 1265px because of its own
     subtitle. Truncation here plus min-width: 0 below is the actual fix; the
     breakpoint ladder further down is only the presentation.
     See doc/design/interface-system.org §3.1. */
  min-width: 0;
  flex-shrink: 1;
}

/****************************** Activity switcher *****************************/
/* Same <details> pill as the period filter (shared .hdr_pill), with its own    */
/* compact dropdown panel of option links. Positioned like the period panel —   */
/* absolute against body > header (top = header height) — but right-aligned and  */
/* only as wide as its options, rather than full-bleed.                          */
#activity_filter {
  flex-shrink: 0;
  position: relative;
}

#activity_filter[open] > summary {
  border-color: var(--color-brand-0);
  color: var(--color-brand-0);
}

#activity_filter[open] > summary .pf_chevron {
  transform: rotate(180deg);
  opacity: 0.9;
}

#activity_filter_panel {
  right: 0;
  min-width: 216px;
  padding: 6px;
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.hdr_panel_label {
  padding: 6px 12px 4px;
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--color-content-muted);
}

.af_option {
  display: block;
  padding: 7px 12px;
  border-radius: 7px;
  font-size: 0.8125rem;
  font-weight: 500;
  color: var(--color-content);
  white-space: nowrap;
  text-decoration: none;
}

.af_option:hover {
  background: color-mix(in srgb, var(--color-brand-2) 18%, transparent);
  color: var(--color-brand-0);
}

.af_active {
  background: color-mix(in srgb, var(--color-brand-2) 30%, transparent);
  color: var(--color-brand-0);
  font-weight: 700;
}

/********************************* Period filter ******************************/
/* Everything lives inside <details id="period_filter"> in body > header.    */
/* <summary> is the pill.  The panel uses position:fixed so it escapes the   */
/* header grid row and paints above all other content.                       */

/* ── <details> container ──────────────────────────────────────────────────── */
/* No position:relative here — the panel's containing block must be the      */
/* header (body > header, which has position:relative), not the <details>.   */
/* This lets position:absolute on the panel escape the ::details-content     */
/* containment slot that modern browsers use internally.                      */
#period_filter {
  flex-shrink: 0;
  position: relative;
}

/* ── Summary / pill (shared by the period and activity switchers) ─────────── */
.hdr_pill {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 5px 14px;
  border: 1.5px solid #C8D8E2;  /* blue-tinted border — matches surface-header */
  border-radius: 99px;
  font-size: 0.8125rem;
  font-weight: 600;
  color: var(--color-content-muted);
  cursor: pointer;
  list-style: none;
  user-select: none;
  white-space: nowrap;
  background: var(--color-surface-2);  /* white pill floats on the blue header surface */
  transition: border-color 0.15s, color 0.15s, background 0.15s,
              border-radius 0.15s;
}

.hdr_pill::-webkit-details-marker { display: none; }

.hdr_pill .icon {
  width: 16px;
  height: 16px;
  flex-shrink: 0;
  opacity: 0.75;
}

/* The value carries the weight; the label in front of it stays quiet. */
.hdr_pill .pf_dates,
.hdr_pill .hdr_pill_value {
  display: flex;
  align-items: center;
  gap: 5px;
  font-weight: 700;
  color: var(--color-content);
}

.hdr_pill_prefix { font-weight: 500; }

.hdr_pill .pf_dates span { opacity: 0.5; }

.hdr_pill .pf_chevron {
  font-size: 0.7rem;
  display: inline-block;
  opacity: 0.6;
  transition: transform 0.2s ease;
}

.hdr_pill:hover {
  border-color: var(--color-brand-1);
  color: var(--color-brand-1);
  background: var(--color-surface-2);
}

/* Open state — still a pill. The panel below is its own floating card, so
   there is no seam to join and no reason to square the corners off.          */
#period_filter[open] summary,
#activity_filter[open] > summary {
  position: relative;
  z-index: 9999;
  border-color: var(--color-brand-0);
  background: var(--color-surface-2);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-brand-0) 14%, transparent);
}

#period_filter[open] summary .icon,
#activity_filter[open] > summary .icon { opacity: 1; }

/* A period the farmer chose, rather than the one the app defaulted to. Same
   treatment as the activity pill — tinted ground, coloured label, border — in
   brand green rather than amber, since this one frames the page and hides
   nothing. The × being there at all carries the state too, so it never rides
   on colour alone.
   #3D5C0A on a 10% tint of itself over white — 6.9:1 ✅ AAA                  */
.hdr_pill[data-state="chosen"] {
  border-color: var(--color-brand-0);
  background: color-mix(in srgb, var(--color-brand-0) 10%, var(--color-surface-2));
  color: var(--color-brand-0);
}

.hdr_pill[data-state="chosen"] .pf_dates { color: var(--color-brand-0); }

/* The activity switcher while it is filtering: loud, because it hides rows.
   #8A6D3B on a 10% tint of itself — ≥4.5:1 ✅ AA                              */
.hdr_pill[data-state="filtering"] {
  border-color: var(--color-accent-1);
  background: color-mix(in srgb, var(--color-accent-1) 10%, var(--color-surface-2));
  color: var(--color-accent-1);
}

.hdr_pill[data-state="filtering"] .hdr_pill_value { color: var(--color-accent-1); }
.hdr_pill[data-state="filtering"] .icon { opacity: 1; }

/* Shared by both pills; the colour comes from whichever state the pill is in,
   so the control is one thing and its severity is not. */
.pill_x {
  display: inline-grid;
  place-items: center;
  width: 17px;
  height: 17px;
  border-radius: 50%;
  background: color-mix(in srgb, currentColor 18%, transparent);
  font-size: 0.72rem;
  line-height: 1;
  text-decoration: none;
}

.pill_x:hover { text-decoration: none; }

.hdr_pill[data-state="chosen"] .pill_x    { color: var(--color-brand-0); }
.hdr_pill[data-state="filtering"] .pill_x { color: var(--color-accent-1); }

/* Filled on hover, with the glyph knocked out. Set per state rather than via
   currentColor: filling with currentColor and then lightening the glyph would
   lighten the fill along with it. */
.hdr_pill[data-state="chosen"] .pill_x:hover {
  background: var(--color-brand-0);
  color: var(--color-surface-2);
}

.hdr_pill[data-state="filtering"] .pill_x:hover {
  background: var(--color-accent-1);
  color: var(--color-surface-2);
}

#period_filter[open] summary .pf_chevron {
  transform: rotate(180deg);
  opacity: 0.9;
}

/* ── Dropdown panel ───────────────────────────────────────────────────────── */
/* position:absolute escapes the details content slot.  top:60px is a fixed  */
/* value (= header height) because top:100% would resolve against the        */
/* ::details-content containing block, not the header.                       */
/* left:0 + right:0 spans the full header width.  The header has             */
/* overflow:visible and z-index:10, so the panel paints above <main>.        */
/* Both dropdowns are the same object: a card that floats clear of the page
   rather than a band welded to the header. Two shadows — a wide soft one for
   the lift and a tight dark one for the edge — so the card reads as separate
   from whatever is behind it instead of blending into the surface below.     */
.hdr_panel {
  position: absolute;
  top: calc(100% + 9px);
  z-index: 9998;
  background: var(--color-surface-2);
  border: 1px solid var(--color-separators);
  border-radius: 12px;
  box-shadow:
    0 18px 40px -12px rgba(23, 43, 23, 0.28),
    0 2px 6px rgba(23, 43, 23, 0.08);
}

#period_filter_panel {
  right: 0;
  width: min(680px, calc(100vw - 32px));
  padding: 14px;
}

/* The pill's dot, in words. Only present when there is a choice to explain, so
   it never becomes furniture the farmer reads past. */
.pf_memory {
  display: flex;
  align-items: flex-start;
  gap: 9px;
  margin-bottom: 10px;
  padding: 11px 13px;
  border-radius: 9px;
  background: color-mix(in srgb, var(--color-brand-2) 16%, var(--color-surface-2));
  border: 1px solid color-mix(in srgb, var(--color-brand-0) 22%, transparent);
  font-size: 0.8125rem;
  line-height: 1.45;
  color: var(--color-content);
}

.pf_memory .icon {
  width: 16px;
  height: 16px;
  flex-shrink: 0;
  margin-top: 2px;
  color: var(--color-brand-0);
}

/* :not(.icon) matters — icon_tag renders a <span class="icon">, so a bare
   `span` selector hands the icon flex-grow and it shoves the text across. */
.pf_memory > span:not(.icon) { flex: 1; min-width: 0; }

.pf_memory a {
  font-weight: 700;
  white-space: nowrap;
}

/* Sections become visible groups: each picker sits on its own tinted block, so
   "Período" and "Comparar com" read as two things instead of one long form.  */
.pf_group {
  padding: 12px;
  border-radius: 9px;
  background: var(--color-surface-1);
  border: 1px solid var(--color-separators);
}

.pf_group + .pf_group { margin-top: 10px; }

/* ── Dimension switch + single-selection options ──────────────────────────── */
/* The panel holds both families side by side, which is the plainest statement
   of the rule: .pf_tabs is a .tab_strip (Safra / Ano / Mês each reveal a
   DIFFERENT picker, with different controls inside it), .pf_chips is a
   .chip_row (one dimension, pick one of its values). Everything visual comes
   from those two classes — see "Choosing one of N" below. Only what is true of
   this panel alone lives here.

   Note these chips stage a choice rather than applying it: nothing happens
   until "Aplicar". That is why they are <button>s carrying .pf_active instead
   of links carrying aria-current, and it is the one behaviour in the app that
   a chip row does not share with the others.                                 */

/* The panel is tighter than a page, so the tabs sit closer together. */
#period_filter_panel .pf_tabs {
  gap: 0 16px;
  margin-bottom: 12px;
}

/* Only the active dimension's picker is shown. */
.pf_dim { display: none; }
.pf_dim.pf_dim_active { display: block; }

.pf_month {
  display: flex;
  align-items: center;
  gap: 6px;
}

.pf_month select {
  padding: 5px 8px;
  border-radius: 6px;
  border: 1.5px solid var(--color-separators);
  background: var(--color-surface-2);
  color: var(--color-content);
  font: inherit;
  font-size: 0.8125rem;
}

/* "Usar" commits the two selects; it is an action, not one of the options, and
   it used to wear the option chip's shape while doing something no option does.
   Drawn as the panel's primary button, sized down to sit level with the
   selects beside it. [type=button] out-specifies `form button:last-child`,
   which would otherwise size it for a page-level form. */
.pf_month button[type="button"].pf_month_set {
  align-self: auto;
  padding: 6px 14px;
  border-radius: 6px;
  font-size: 0.8125rem;
  background: var(--color-brand-0);
  border: 1.5px solid var(--color-brand-0);
  color: #fff;                         /* 7.68:1 on brand-0 — AAA */
}

.pf_month button[type="button"].pf_month_set:hover {
  background: var(--color-brand-1);
  border-color: var(--color-brand-1);
}

.pf_section_label {
  display: block;
  margin-bottom: 8px;
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--color-content-muted);
}

/* Opt-in comparison toggle — reveals a second picker. */
.pf_compare_toggle {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 10px 0;
  padding: 9px 12px;
  border-radius: 9px;
  background: var(--color-surface-1);
  border: 1px solid var(--color-separators);
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--color-content);
  cursor: pointer;
}

.pf_compare_toggle:hover { border-color: var(--color-brand-1); }

.pf_hint {
  margin: 4px 0;
  font-size: 0.8rem;
  color: var(--color-accent-1);
}

/* Actions read as the card's footer: a rule the full width of the card, with
   the destructive-ish "Limpar" pushed away from the two buttons.             */
.pf_foot {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 12px -14px -14px;
  padding: 12px 14px;
  border-top: 1px solid var(--color-separators);
  background: var(--color-surface-1);
  border-radius: 0 0 11px 11px;
}

/* Scoped so they out-specify the generic form-button rules. */
#period_filter_panel .pf_apply {
  padding: 6px 18px;
  border-radius: 6px;
  border: 1.5px solid var(--color-brand-0);
  background: var(--color-brand-0);
  color: #fff;
  font: inherit;
  font-size: 0.8125rem;
  font-weight: 600;
  cursor: pointer;
}

#period_filter_panel .pf_apply:hover {
  background: var(--color-brand-1);
  border-color: var(--color-brand-1);
}

#period_filter_panel .pf_apply:disabled {
  opacity: 0.45;
  cursor: not-allowed;
}

#period_filter_panel .pf_close {
  padding: 6px 16px;
  border-radius: 6px;
  border: 1.5px solid var(--color-separators);
  background: var(--color-surface-2);
  color: var(--color-content-muted);
  font: inherit;
  font-size: 0.8125rem;
  font-weight: 600;
  cursor: pointer;
}

#period_filter_panel .pf_close:hover {
  border-color: var(--color-brand-1);
  color: var(--color-brand-1);
}

.pf_clear {
  margin-left: auto;
  font-size: 0.8125rem;
  color: var(--color-content-muted);
  text-decoration: none;
}

.pf_clear:hover {
  color: var(--color-accent-2);
  text-decoration: underline;
}

/* Hide the hidden period inputs — visually irrelevant */
#period_filter_panel input[type=hidden] { display: none; }

/* ── Mobile (≤768px): pill collapses to calendar icon ────────────────────── */
@media (max-width: 768px) {
  .hdr_pill {
    padding: 5px 10px;
    gap: 5px;
  }

  /* The value stays — the window you are looking at is the one thing the pill
     must always say. It is the label in front of it that goes. */
  .hdr_pill_prefix { display: none; }

  /* Anchored to the header rather than to the pill: at this width the card is
     wider than the control that opens it, so hanging it off the pill's edge
     pushes it off-screen.

     Dropping the pills' own positioning context is what makes `top: 100%`
     resolve against body > header instead — so the panel follows the header's
     real bottom edge however many rows it wrapped to, which a fixed pixel
     offset could not do once the header stopped being exactly 60px tall. */
  #period_filter,
  #activity_filter { position: static; }

  .hdr_panel {
    position: absolute;
    top: calc(100% + 6px);
    left: 12px;
    right: 12px;
    width: auto;
  }

  #period_filter_panel { width: auto; }
}

/********************************* Sidebar nav ********************************/
body > nav:not(#mobile_actions) {
  grid-area: nav;
  background: var(--color-brand-0);
  border-right: none;
  display: flex;
  flex-direction: column;

  /* Stick the sidebar to the viewport so it never scrolls away.
     height: 100vh + overflow-y: auto lets the nav scroll independently
     if its own content is taller than the screen (unlikely but safe). */
  position: sticky;
  top: 0;
  height: 100vh;
  overflow-y: auto;
}

/* Logo link */
body > nav > a {
  display: flex;
  align-items: center;
  gap: 10px;
  height: 60px;
  padding: 0 20px;
  background: rgba(0, 0, 0, 0.15);
  color: var(--color-surface-2);
  font-size: 1.05rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  white-space: nowrap;
  overflow: hidden;
  border-bottom: 1px solid rgba(255,255,255,0.08);
}

body > nav > a:hover {
  background: rgba(0, 0, 0, 0.2);
  color: var(--color-surface-2);
}

body > nav > a .logo {
  flex-shrink: 0;
  width: 36px;
  height: 36px;
  object-fit: contain;
}

body.nav_open > nav > a .logo {
  margin-left: -6px;
}

/* Nav sections */
body > nav section {
  padding: 14px 0 2px;
}

/* Section label row — flex so toggle button sits inline */
body > nav section h2 {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 4px 14px;
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  /* 0.76 alpha = 5.23:1 contrast on brand-0 sidebar — passes AA */
  color: rgba(255,255,255,0.76);
  white-space: nowrap;
  overflow: hidden;
}

/* Toggle button inside first section's <h2> */
body > nav section h2 button {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  background: rgba(255,255,255,0.1);
  border: none;
  border-radius: 4px;
  color: rgba(255,255,255,0.7);
  cursor: pointer;
  line-height: 1;
  transition: background 0.15s;
}

body > nav section h2 button:hover { background: rgba(255,255,255,0.18); }

/* Rotate the chevron-right icon 180° when the nav is open (= chevron-left) */
body > nav section h2 button .icon {
  --icon-size: 0.9rem;
  transition: transform 0.2s ease;
}
body.nav_open nav section h2 button .icon { transform: rotate(180deg); }
body.nav_open nav section h2                  { justify-content: space-between; }
body.nav_open nav section h2 button           { order: 1; }

/* Nav links — white at full opacity = 7.68:1 on sidebar bg; meets AAA */
body > nav section ul li a {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 9px 18px;
  font-size: 0.9rem;
  font-weight: 600;
  color: rgba(255, 255, 255, 0.88);
  border-left: 3px solid transparent;
  transition: background 0.12s, color 0.12s;
  white-space: nowrap;
  overflow: hidden;
  line-height: 1.4;
}

body > nav section ul li a .icon {
  flex-shrink: 0;
  --icon-size: 1rem;
  width: 20px;
}

/* The rail is a fixed 220px, so a label must give way rather than shove the
   badge or the "Breve" tag past the edge — min-width: 0 is what lets a flex
   item shrink below its content at all. Ellipsis over clipping: a cut-off word
   with no marker reads as a rendering bug. */
body > nav section ul li a .label:not(.nav_soon) {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Collapsed state — remove labels from flow so justify-content: center
   works on the icon alone. Vertical spacing (padding) is kept intact. */
body:not(.nav_open) > nav .label { display: none; }

body:not(.nav_open) > nav > a              { justify-content: center; padding: 0; }
body:not(.nav_open) > nav section h2       { justify-content: center; padding: 4px 0; }
body:not(.nav_open) > nav section ul li a  { justify-content: center; padding: 8px 0; }

/* ── Collapsed: no ghost rows ────────────────────────────────────────────
   Hiding .label emptied every section heading but left it holding the
   section's padding plus its own — a ~28px band of nothing between each icon
   group, taller than the 32px items it was separating. Five sections, five
   bands, and the first one read as a gap under the logo.

   The Visão heading is the exception and must survive: it carries the collapse
   toggle, which is the only way back out of this state. So the rule keys on
   "has a button", not on the section's position. */
body:not(.nav_open) > nav section h2:not(:has(button)) { display: none; }

/* With the labels gone, grouping is carried by a hairline instead of by a
   word. 0.12 alpha on brand-0 — decorative only, never used behind text. */
body:not(.nav_open) > nav section + section {
  border-top: 1px solid rgba(255,255,255,0.12);
  padding-top: 10px;
}

/* The quick-action strip draws the same hairline as every other group, and it
   needs it most when collapsed: unpinned (§3.2.9) it now follows Fazenda
   directly instead of floating at the bottom of the rail, so without a line
   the verbs run straight on from the places. One element, one border-top —
   the rule that used to suppress it here was guarding against a doubling that
   cannot happen. */

body > nav section ul li a:hover {
  background: rgba(255, 255, 255, 0.08);
  color: var(--color-surface-2);
  text-decoration: none;
}

body > nav section ul li.active a {
  border-left-color: var(--color-accent-0);  /* blue active bar — contrasts with green sidebar */
  background: rgba(255, 255, 255, 0.12);
  color: var(--color-surface-2);
  font-weight: 600;
}

/* No ::after bleed needed since the sidebar is now fully dark */
body > nav section ul li.active {
  position: relative;
}

/* ── Nav badges ─────────────────────────────────────────────────────── */
.nav_badge {
  margin-left: auto;
  font-size: 0.8rem;
  font-weight: 700;
  min-width: 1.8em;
  padding: 3px 2px;
  border-radius: 99px;
  line-height: 1.4;
  text-align: center;
  /* amber — a queue to work through ("a conferir"), not an alarm.
     White on #8A6D3B = 4.85:1 — passes AA. */
  background: var(--color-accent-1);
  color: #fff;
  font-variant-numeric: tabular-nums;
  box-shadow: 0 1px 4px rgba(0,0,0,0.25);
}

.nav_badge[data-type="error"] {
  background: var(--color-accent-2);  /* red — reserved for real alerts */
}

/* ── Collapsed: the count survives, re-anchored to the icon ──────────────
   This badge used to be hidden outright when the rail collapsed — that is,
   on exactly the narrow screens where a farmer is most likely to be triaging
   notas on a phone. IA §5 makes the visible "a conferir" count the whole
   justification for placing Notas *under* Despesas instead of beside it, so
   hiding it threw away the reason for the arrangement.

   Collapsed, it becomes the standard corner chip on the icon. It still reads
   at 20px, and the helper renders "9+" past nine so it never grows wider than
   the icon it is pinned to.
   White on --color-accent-1 (#8A6D3B) = 4.85:1 ✅ AA;
   white on --color-accent-2 (#C0392B) = 4.83:1 ✅ AA for the error variant. */
body:not(.nav_open) > nav section ul li a { position: relative; }

body:not(.nav_open) > nav .nav_badge {
  position: absolute;
  top: 2px;
  right: 6px;
  margin-left: 0;
  min-width: 16px;
  padding: 0 4px;
  font-size: 0.6rem;
  line-height: 16px;
  border-radius: 99px;
  /* A 1px ring in the rail's own green keeps the chip readable where it
     overlaps the icon's strokes. */
  box-shadow: 0 0 0 1.5px var(--color-brand-0);
}

/* ── Forthcoming areas ───────────────────────────────────────────────────
   An item the IA has placed but no feature backs yet (see §6b, and the pages
   under /upcoming). It is a real link — it leads to the page that explains the
   area — so it must read as "not yet", never as "broken" and never as
   "available".

   Dimming alone would fail: at 0.62 alpha this text is 3.4:1 on the rail, and
   colour is not allowed to be the only carrier of state anyway. So the state
   is carried by the "Breve" tag, and the label itself stays at the 0.88 alpha
   every other item uses (7.68:1 ✅ AAA) — only the icon is attenuated. */
body > nav li.future a .icon { opacity: 0.7; }

.nav_soon {
  flex-shrink: 0;
  margin-left: auto;
  padding: 1px 6px;
  border-radius: 4px;
  font-size: 0.6rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  /* #EDE8DF on the rail's #3D5C0A = 9.9:1 ✅ AAA at this weight; the fill is
     a 0.14 white wash so the tag reads as a quiet aside, not a second badge. */
  background: rgba(255,255,255,0.14);
  color: var(--color-badge-pending-bg);
}

/* An active forthcoming item is still active: you are standing on its page. */
body > nav li.future.active a .icon { opacity: 1; }

/* ── The foot: Configurações, below a real gap ───────────────────────────
   interface-system.org §3.2.8. The owner's complaint was that the settings
   part of the menu carries as much visual weight as the work, and the answer
   is emphatically NOT to make it smaller or greyer: every design system that
   addresses this (Material, Shopify, Notion, Polar, Column) keeps settings at
   the same size, weight and colour and separates it by position and space —
   because muting reads as "disabled", and Setup is not less important, it is
   less frequent. Only position encodes frequency honestly.

   So there is no tonal rule here at all. There is a gap, and the section sits
   after it, last in the scroll. That is also the one encoding that survives
   the rail collapsing to 48px, where labels and section headings are gone:
   destinations at the top, then a hole, then the things you set once, then the
   verbs — which are always present, so they belong at the end rather than
   between two kinds of destination (IA §6b draws exactly this order).

   A real gap and NOT another hairline — using the same separator for "next
   section" and "different kind of thing" is what made the boundary invisible
   in the first place. */
body > nav #nav_setup {
  margin-top: 30px;
  padding-top: 4px;
}

/* …including collapsed, where `section + section` would otherwise put the
   ordinary grouping hairline right back on top of it. */
body:not(.nav_open) > nav section + #nav_setup {
  border-top: none;
  padding-top: 4px;
}

/* ── Configurações, one disclosure row ───────────────────────────────────
   The <summary> is a nav row and is styled as exactly that — same padding,
   same gap, same icon column, same weight and colour as Despesas or
   Relatórios. Setup is not less important, it is less frequent, and folding
   it must not also demote it.

   The default disclosure triangle is removed and replaced by the rail's own
   chevron, which rotates on open: the triangle sits in the text column and
   pushes the icon out of the 20px gutter every other row keeps. */
body > nav #nav_setup summary {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 9px 18px;
  font-size: 0.9rem;
  font-weight: 600;
  color: rgba(255, 255, 255, 0.88);
  border-left: 3px solid transparent;
  white-space: nowrap;
  overflow: hidden;
  line-height: 1.4;
  cursor: pointer;
  list-style: none;
  transition: background 0.12s;
}

body > nav #nav_setup summary::-webkit-details-marker { display: none; }

body > nav #nav_setup summary:hover { background: rgba(255,255,255,0.08); }

body > nav #nav_setup summary > .icon {
  flex-shrink: 0;
  --icon-size: 1rem;
  width: 20px;
}

/* The chevron is the state, so it goes to the far edge and turns down when
   the group is open. */
body > nav #nav_setup summary > .icon--chevron-right {
  margin-left: auto;
  width: auto;
  --icon-size: 0.85rem;
  color: rgba(255,255,255,0.6);
  transition: transform 0.2s ease;
}

body > nav #nav_setup details[open] summary > .icon--chevron-right {
  transform: rotate(90deg);
}

/* Collapsed rail: the cog alone, centred like every other icon. The chevron
   goes — 48px has no room for a state marker, and the open group's own items
   are the state. */
body:not(.nav_open) > nav #nav_setup summary {
  justify-content: center;
  padding: 8px 0;
}

body:not(.nav_open) > nav #nav_setup summary > .icon--chevron-right { display: none; }

/* ── Conta and Sair, one row ─────────────────────────────────────────────
   Two full nav items for account chrome left Configurações as six items of
   two kinds. Compressed to a single row it is four items of one kind, which
   is half of why the group reads as coherent now (§3.2.8 #4).

   The row lives inside the Configurações disclosure, so it costs no rail
   height at all until the group is opened. Signing out is a once-a-season
   act; it had a permanent row for no reason.

   This is the one place tone is allowed to do the work, and Polar is the
   precedent: full weight for Settings itself, a genuinely quieter foot for
   true utility links. It is still held to AA — see the colour below. */
body > nav ul.nav_account {
  display: flex;
  align-items: center;
  gap: 4px;
  margin-top: 6px;
  padding: 7px 15px 2px;
  border-top: 1px solid rgba(255,255,255,0.1);
}

body > nav ul.nav_account > li {
  display: flex;
  align-items: center;
  gap: 4px;
  min-width: 0;
}

/* A decorative divider, not a word: it separates two links that a screen
   reader already reads as two list items. */
body > nav ul.nav_account > li + li::before {
  content: "·";
  color: rgba(255,255,255,0.35);
  font-size: 0.8rem;
  line-height: 1;
}

body > nav ul.nav_account li a,
body > nav ul.nav_account li.nav_session button {
  gap: 6px;
  padding: 3px 6px;
  border-left-width: 0;
  border-radius: 4px;
  font-size: 0.78rem;
  font-weight: 600;
  /* 0.72 alpha on the rail's #3D5C0A = 4.87:1 ✅ AA at this size. The obvious
     shortcut — stacking opacity: .72 on the inherited 0.88 — lands at 4.18:1
     and fails, so the alpha is stated once here instead. */
  color: rgba(255,255,255,0.72);
  width: auto;
}

body > nav ul.nav_account li a:hover,
body > nav ul.nav_account li.nav_session button:hover {
  background: rgba(255,255,255,0.08);
  color: var(--color-surface-2);
}

/* Standing on /account still marks the row — quieter chrome, not a dead end.
   The left bar the other items use has no room in a horizontal row, so the
   fill carries it alone here. */
body > nav ul.nav_account li.active a {
  background: rgba(255,255,255,0.14);
  color: var(--color-surface-2);
}

body > nav ul.nav_account .icon {
  flex-shrink: 0;
  --icon-size: 0.85rem;
  width: var(--icon-size);
}

/* Collapsed: the row has no width to be a row, so it stacks — and the divider
   goes with the labels, since it was only ever separating them. */
body:not(.nav_open) > nav ul.nav_account {
  flex-direction: column;
  align-items: stretch;
  gap: 0;
  padding: 7px 0 2px;
}

body:not(.nav_open) > nav ul.nav_account > li + li::before { display: none; }

body:not(.nav_open) > nav ul.nav_account li a,
body:not(.nav_open) > nav ul.nav_account li.nav_session button {
  justify-content: center;
  padding: 6px 0;
  border-radius: 0;
}

/* ── Sair, in the rail beside Conta ──────────────────────────────────────
   Moved out of the header (interface-system.org §3.1): it is account chrome,
   used at most once per session, and it was costing permanent header width on
   every page. It stays a real form so logout works without JS, styled to sit
   flush with the nav links above it. */
.nav_session form.button_to { margin: 0; }

.nav_session button {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: 9px 18px;
  border: 0;
  border-left: 3px solid transparent;
  background: none;
  font-family: inherit;
  font-size: 0.9rem;
  font-weight: 600;
  line-height: 1.4;
  text-align: left;
  color: rgba(255, 255, 255, 0.88);
  white-space: nowrap;
  overflow: hidden;
  cursor: pointer;
  transition: background 0.12s, color 0.12s;
}

.nav_session button:hover {
  background: rgba(255, 255, 255, 0.08);
  color: var(--color-surface-2);
}

.nav_session button .icon { flex-shrink: 0; --icon-size: 1rem; width: 20px; }

body:not(.nav_open) .nav_session button { justify-content: center; padding: 8px 0; }

/********************************* Main ***************************************/
main {
  grid-area: main;
  padding: 16px;
  overflow-y: auto;

  /* See body > header: both grid items in this column must opt out of
     min-width: auto, or a single wide descendant makes the whole page scroll
     sideways. Wide content earns its own overflow container (a table wrapper),
     it does not get to widen the column. */
  min-width: 0;
  scroll-behavior: smooth;
  background: var(--color-surface-0);

  /* Stack every direct child — sections, kpi rows, content grids, etc. —
     with consistent vertical spacing. New boxes get the gap for free. */
  display: flex;
  flex-direction: column;
  gap: 16px;
}

/* Any wrapper element inside main that directly contains sections (e.g. the
   left column of a two-panel layout) inherits the same vertical rhythm.
   Specificity 0,0,3 — safely overridden by any class-based layout rule. */
main :is(div, article):has(> section) {
  display: flex;
  flex-direction: column;
  gap: 16px;
}



/********************************* Flash **************************************/
#flash {
  border: none;
  background: transparent;
  border-radius: 0;
}

#flash p {
  position: relative;
  display: flex;
  align-items: flex-start;
  gap: 10px;
  margin: 0 0 8px;
  padding: 13px 44px 13px 16px;
  border-radius: 6px;
  border: 1px solid;
  font-size: 0.9375rem;
  font-weight: 500;
  line-height: 1.5;
}

#flash p .icon {
  flex-shrink: 0;
  --icon-size: 1.1rem;
}

/* Alert — red */
#flash_alert {
  background: #FDF3F2;
  border-color: var(--color-accent-2);
  color: var(--color-accent-2);
}



/* Notice — green */
#flash_notice {
  background: #F2F9E8;
  border-color: var(--color-brand-0);
  color: var(--color-brand-0);
}



/* Close button */
#flash p button {
  position: absolute;
  top: 12px;
  right: 12px;
  border: none;
  background: transparent;
  font-size: 18px;
  line-height: 1;
  cursor: pointer;
  opacity: 0.5;
  color: inherit;
  padding: 2px 4px;
  border-radius: 3px;
}

#flash p button:hover { opacity: 1; background: rgba(0,0,0,0.06); }

/* JS error toast — injected by application.js on unhandled JS errors */
#js_error_toast {
  position: fixed;
  bottom: 24px;
  right: 24px;
  z-index: 9000;
  max-width: 380px;
  display: flex;
  align-items: flex-start;
  gap: 10px;
  padding: 13px 44px 13px 16px;
  border-radius: 6px;
  border: 1px solid var(--color-accent-2);
  background: #FDF3F2;
  color: var(--color-accent-2);   /* #C0392B — 5.44:1 on #FDF3F2 ✓ */
  font-size: 0.9375rem;
  font-weight: 500;
  line-height: 1.5;
  box-shadow: 0 4px 16px rgba(0,0,0,0.12);
}
#js_error_toast p { margin: 0; }
#js_error_toast button {
  position: absolute;
  top: 12px;
  right: 12px;
  border: none;
  background: transparent;
  font-size: 18px;
  line-height: 1;
  cursor: pointer;
  opacity: 0.5;
  color: inherit;
  padding: 2px 4px;
  border-radius: 3px;
}
#js_error_toast button:hover { opacity: 1; background: rgba(0,0,0,0.06); }

@media (max-width: 480px) {
  #js_error_toast {
    bottom: 80px;   /* clear the mobile_actions bar */
    right: 12px;
    left: 12px;
    max-width: none;
  }
}

/********************************* Forms **************************************/
form {
  display: flex;
  flex-direction: column;
  gap: 16px;
}

fieldset {
  border: 1px solid var(--color-separators);
  border-radius: 6px;
  padding: 20px 20px 12px;
  display: flex;
  flex-direction: column;
  gap: 12px;
}

legend {
  padding: 0 6px;
  font-size: 0.8rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-content-muted);
}

label {
  display: block;
  font-size: 0.875rem;
  font-weight: 600;
  line-height: 1.4;
  color: var(--color-content);
}

input:not([type="submit"]):not([type="checkbox"]):not([type="radio"]):not([type="file"]),
select,
textarea {
  width: 100%;
  padding: 8px 12px;
  background: var(--color-surface-2);
  border: 1px solid var(--color-separators);
  border-radius: 5px;
  font-size: 0.9rem;
  font-family: inherit;
  color: var(--color-content);
  transition: border-color 0.15s, box-shadow 0.15s;
}

/* Tabular nums for date/time/number inputs — digits always align in columns.
   NOTE: currency and quantity text inputs (type="text" with inputmode="numeric")
   are NOT covered here — add font-variant-numeric: tabular-nums directly in the
   page-specific stylesheet or via an inline style on the field, alongside
   text-align: right when the field is inside a table row. */
input[type="number"],
input[type="date"],
input[type="time"],
input[type="datetime-local"],
input[type="month"],
input[type="week"] {
  font-variant-numeric: tabular-nums;
}

input:not([type="submit"]):not([type="checkbox"]):not([type="radio"]):not([type="file"]):focus,
select:focus,
textarea:focus {
  outline: none;
  border-color: var(--color-brand-1);
  box-shadow: 0 0 0 3px rgba(90, 128, 24, 0.14);
}

input::placeholder,
textarea::placeholder { color: var(--color-content-muted); opacity: 1; }

textarea { resize: vertical; min-height: 90px; }

select { cursor: pointer; }

/* Password toggler — eye icon floated inside the right edge of the input.
   The JS wraps input[data-toggle] + span.password_toggler in div.input_wrapper. */
.input_wrapper {
  position: relative;
  display: block;
}

.input_wrapper input[data-toggle] {
  padding-right: 44px; /* leave room for the icon */
}

.password_toggler {
  position: absolute;
  right: 0;
  top: 0;
  bottom: 0;
  width: 44px;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  font-size: 1rem;
  color: var(--color-content-muted);
  user-select: none;
  transition: color 0.15s;
}

.password_toggler:hover { color: var(--color-content); }

/* "Slash" overlay drawn on top of the eye when the password is visible.
   The span is already position:absolute, so ::after is placed relative to it. */
.password_toggler.visible {
  color: var(--color-content);
}

.password_toggler.visible::after {
  content: '';
  position: absolute;
  left: 50%;
  top: 10%;
  width: 2px;
  height: 80%;
  background: currentColor;
  border-radius: 1px;
  transform: translateX(-50%) rotate(45deg);
  pointer-events: none;
}

/* Inline checkbox / radio rows */
label:has(input[type="checkbox"]),
label:has(input[type="radio"]) {
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: 8px;
  font-weight: 400;
  cursor: pointer;
}

input[type="checkbox"],
input[type="radio"] {
  width: 16px;
  height: 16px;
  cursor: pointer;
  accent-color: var(--color-brand-1);
  flex-shrink: 0;
}

/* All form buttons — secondary style by default */
form input[type="submit"],
form button {
  align-self: flex-start;
  padding: 9px 22px;
  border-radius: 5px;
  font-size: 0.9375rem;
  font-weight: 600;
  font-family: inherit;
  cursor: pointer;
  transition: background 0.15s, border-color 0.15s, color 0.15s;
  background: transparent;
  border: 1.5px solid var(--color-brand-0);
  color: var(--color-brand-0);
}

form input[type="submit"]:hover,
form button:hover {
  background: color-mix(in srgb, var(--color-brand-2) 30%, transparent);
}

/* Last button — primary style */
form input[type="submit"]:last-child,
form button:last-child {
  background: var(--color-brand-0);
  border-color: var(--color-brand-0);
  color: var(--color-surface-2);
}

form input[type="submit"]:last-child:hover,
form button:last-child:hover {
  background: var(--color-brand-1);
  border-color: var(--color-brand-1);
}

/* Hint text beneath a field */
label small {
  display: block;
  margin-top: 4px;
  font-size: 0.8125rem;
  font-weight: 500;
  color: var(--color-content-muted);
}

/* Required field indicator — auto-added by InputTagsReflectValidationFromModel */
label.required::after {
  content: ' *';
  color: var(--color-accent-2);
  font-weight: 700;
}

/* Base-error summary — rendered by FormHelperWithBaseErrors BEFORE the <form> tag.
   Only errors.add(:base, …) appear here. */
#error_explanation {
  background: color-mix(in srgb, var(--color-accent-2) 8%, var(--color-surface-2));
  border: 1px solid var(--color-accent-2);
  border-radius: 6px;
  padding: 12px 16px;
  margin-bottom: 16px;
}

#error_explanation ul {
  display: flex;
  flex-direction: column;
  gap: 4px;
}

#error_explanation li.error {
  display: flex;
  align-items: baseline;
  gap: 6px;
  font-size: 0.9rem;
  font-weight: 600;
  color: var(--color-accent-2);
}

#error_explanation li.error::before {
  content: '•';
  flex-shrink: 0;
  font-size: 1rem;
  line-height: 1;
}

/* Field-level errors — custom field_error_proc wraps each errored input in
   .field_with_errors and appends a <span class="error_message"> below it.
   Labels are returned unchanged (not wrapped), so use :has() to colour them. */
label:has(+ .field_with_errors) { color: var(--color-accent-2); }

.field_with_errors input,
.field_with_errors select,
.field_with_errors textarea {
  border-color: var(--color-accent-2);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-accent-2) 12%, transparent);
}

span.error_message {
  display: block;
  font-size: 0.8125rem;
  font-weight: 500;
  color: var(--color-accent-2);
  margin-top: 4px;
}

/********************************* Cards **************************************/
main section {
  background: var(--color-surface-2);
  border: 1px solid var(--color-separators);
  border-radius: 8px;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.06);
  overflow: hidden;
}

main section > header {
  all: unset;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 14px 20px;
  background: var(--color-surface-1);
  border-bottom: 1px solid var(--color-separators);
}

main section > header h2 {
  font-size: 0.9rem;
  font-weight: 600;
  letter-spacing: 0.01em;
  color: var(--color-content);
}

main section > header a {
  font-size: 0.875rem;
  font-weight: 600;
  color: var(--color-brand-1);
}

main section > header a:hover { color: var(--color-brand-0); }

/********************************* KPI row ************************************/
.kpi_row {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 16px;
}

.kpi_row article {
  background: var(--color-surface-2);
  border: 1px solid var(--color-separators);
  border-radius: 8px;
  padding: 20px 24px;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
}

.kpi_row .kpi_label {
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--color-content-muted);
  margin-bottom: 10px;
}

.kpi_row .kpi_value {
  font-size: 1.75rem;
  font-weight: 700;
  letter-spacing: -0.03em;
  color: var(--color-content);
  font-variant-numeric: tabular-nums;
}

/* The accent cycles every three cards rather than stopping at the third: a
   strip of four or five (Despesa, the activity-cost report) used to have its
   later cards silently lose the border and stop looking like the same card. */
.kpi_row article:nth-child(3n + 1) { border-top: 3px solid var(--color-brand-0);  }  /* dark green  */
.kpi_row article:nth-child(3n + 2) { border-top: 3px solid var(--color-accent-0); }  /* blue        */
.kpi_row article:nth-child(3n)     { border-top: 3px solid var(--color-accent-1); }  /* warm amber  */

/********************************* Spend comparison panel *********************/
/* Shared by expenditures#index and reports#show (layouts/_spend_comparison).  */
/* KPI direction colours are scoped under .cmp so they never collide with the  */
/* dashboard's own (which use amber for "up").                                 */
.cmp {
  display: flex;
  flex-direction: column;
  gap: 20px;
  margin-bottom: 24px;
}

/* Plain-language verdict headline */
.cmp_verdict {
  font-size: 1.05rem;
  font-weight: 600;
  color: var(--color-content);
  padding: 12px 16px;
  border-radius: 8px;
  background: var(--color-surface-1);
  border-left: 4px solid var(--color-content-muted);
}
.cmp_verdict[data-direction="down"] { border-left-color: var(--color-brand-0); }
.cmp_verdict[data-direction="up"]   { border-left-color: var(--color-accent-2); }

/* KPI strip — 3 cards; scoped to out-specify page-level .kpi_row overrides. */
.cmp .kpi_row { grid-template-columns: repeat(3, minmax(0, 220px)); }
.cmp .kpi_label { font-size: 0.78rem; color: var(--color-content-muted); }
.cmp .kpi_delta { display: block; margin-top: 6px; font-size: 0.8rem; font-variant-numeric: tabular-nums; }
.cmp .kpi_value[data-direction="up"]   { color: var(--color-accent-2); }
.cmp .kpi_value[data-direction="down"] { color: var(--color-brand-0); }
.cmp .kpi_value[data-direction="flat"] { color: var(--color-content-muted); }
.cmp .kpi_delta[data-direction="up"]   { color: var(--color-accent-2); }
.cmp .kpi_delta[data-direction="down"] { color: var(--color-brand-0); }

/* Two-series monthly chart (pure CSS bars, same idea as the evolution report) */
.cmp_legend_row { display: flex; gap: 20px; margin-bottom: 8px; font-size: 0.82rem; color: var(--color-content); }
.cmp_legend .sw { display: inline-block; width: 22px; height: 8px; border-radius: 2px; margin-right: 6px; vertical-align: middle; }
.sw_primary { background: var(--color-brand-0); }
.sw_compare { background: repeating-linear-gradient(45deg, var(--color-content-muted) 0 3px, transparent 3px 6px); border: 1px solid var(--color-content-muted); }

.cmp_chart { display: flex; align-items: flex-end; gap: 8px; height: 160px; }
.cmp_group { flex: 1; display: flex; flex-direction: column; align-items: center; gap: 6px; height: 100%; min-width: 0; }
.cmp_bars { flex: 1; display: flex; align-items: flex-end; justify-content: center; gap: 3px; width: 100%; }
.cmp_bar { width: 42%; max-width: 22px; border-radius: 2px 2px 0 0; }
.cmp_bar_primary { background: var(--color-brand-0); }
.cmp_bar_compare { background: repeating-linear-gradient(45deg, color-mix(in srgb, var(--color-content-muted) 40%, transparent) 0 3px, transparent 3px 6px); border: 1px solid var(--color-content-muted); border-bottom: none; }
.cmp_axis { font-size: 0.65rem; color: var(--color-content-muted); }

/* "Onde mais mudou" — category movers, biggest change first */
.cmp_movers_head { font-size: 0.95rem; color: var(--color-brand-0); margin-bottom: 4px; }
.cmp_movers { width: 100%; border-collapse: collapse; }
.cmp_movers td { padding: 8px 10px; border-bottom: 1px solid var(--color-separators); font-size: 0.9rem; }
.cmp_mover_name { font-weight: 600; white-space: nowrap; }
.cmp_mover_bar { width: 40%; }
.cmp_inline_bar { display: block; height: 8px; border-radius: 4px; background: var(--color-brand-2); min-width: 2px; }
.cmp_mover_val { text-align: right; font-variant-numeric: tabular-nums; }
.cmp_mover_vs { text-align: right; color: var(--color-content-muted); font-size: 0.82rem; font-variant-numeric: tabular-nums; }
.cmp_mover_delta { text-align: right; font-weight: 600; font-variant-numeric: tabular-nums; }
.cmp_mover_delta[data-direction="up"]   { color: var(--color-accent-2); }
.cmp_mover_delta[data-direction="down"] { color: var(--color-brand-0); }

/********************************* Content grid *******************************/
.content_grid {
  display: grid;
  grid-template-columns: 1fr 420px;
  gap: 16px;
  align-items: start;
}

.content_grid > aside {
  grid-row: 1 / span 2;
  grid-column: 2;
}

#page_overrides .swatches {
  grid-template-columns: 1fr;
}

#page_overrides .swatches span {
  height: 80px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 0.75rem;
  text-align: center;
  padding: 0 16px;
}

/********************************* Table **************************************/
table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.875rem;
}

thead th {
  padding: 10px 20px;
  text-align: left;
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--color-content-muted);
  background: var(--color-surface-1);
  border-bottom: 1px solid var(--color-separators);
}

tbody tr td {
  padding: 12px 20px;
  border-bottom: 1px solid var(--color-separators);
  color: var(--color-content);
  font-size: 0.9375rem;
  line-height: 1.5;
  /* NOTE: tabular-nums NOT applied globally — most td content is mixed text.
     In page-specific stylesheets, target numeric columns explicitly, e.g.:
       td:nth-child(2), td:nth-child(3) { font-variant-numeric: tabular-nums; text-align: right; }
     reports/show.css already does this for the breakdown table. */
}

tbody tr:last-child td { border-bottom: none; }
tbody tr:hover td      { background: var(--color-surface-0); }

/********************************* Badges *************************************/
td span {
  display: inline-block;
  padding: 3px 10px;
  border-radius: 99px;
  font-size: 0.8rem;
  font-weight: 600;
  line-height: 1.4;
}

/* All badge backgrounds + text pairs pass WCAG AA ≥4.5:1 */
td span[data-status="ok"]      { background: var(--color-badge-ok-bg);      color: var(--color-badge-ok-text);      }
td span[data-status="pending"] { background: var(--color-badge-pending-bg); color: var(--color-badge-pending-text); }
td span[data-status="error"]   { background: #FCEAE8;                       color: var(--color-accent-2);           }

/* Reusable badge — works anywhere (td, div, span).
   Use data-status for semantic colour; default is neutral.                   */
/* Visible to screen readers only — for a control whose purpose is already
   obvious on screen (a search field with a placeholder) but which still needs
   a real label in the accessibility tree. */
.visually_hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

.badge {
  display: inline-block;
  padding: 3px 10px;
  border-radius: 99px;
  font-size: 0.8rem;
  font-weight: 600;
  line-height: 1.4;
  /* A pill that wraps stops reading as a pill: "Parcialmente registrada"
     became two stacked lines inside one rounded outline, and took the whole
     table row's height with it. */
  white-space: nowrap;
  background: var(--color-badge-pending-bg);   /* neutral default — 6.41:1 with pending-text */
  color: var(--color-badge-pending-text);
}

.badge[data-status="ok"]      { background: var(--color-badge-ok-bg);      color: var(--color-badge-ok-text);      }
.badge[data-status="pending"] { background: var(--color-badge-pending-bg); color: var(--color-badge-pending-text); }
.badge[data-status="error"]   { background: #FCEAE8;                       color: var(--color-accent-2);           }

/* Expenditure source badges — contrast verified:
   receipt: brand-ok pair  5.04:1 ✅ AA   (#3D5C0A on #C2DB88)
   manual:  brand-pending  6.41:1 ✅ AA   (#5C5044 on #EDE8DF)
   mixed:   content-muted  6.20:1 ✅ AA   (#4A5E50 on #F0F2EE)              */
.badge[data-source="receipt"] { background: var(--color-badge-ok-bg);      color: var(--color-badge-ok-text);      }
.badge[data-source="manual"]  { background: var(--color-badge-pending-bg); color: var(--color-badge-pending-text); }
.badge[data-source="mixed"]   { background: var(--color-surface-0);        color: var(--color-content-muted);      }

/* Receipt allocation status badges — contrast verified:
   full:    brand-ok pair   5.04:1 ✅ AA   (#3D5C0A on #C2DB88)
   partial: brand-pending   6.41:1 ✅ AA   (#5C5044 on #EDE8DF)
   none:    #7A4F1E/#FAF0E6 5.12:1 ✅ AA   (warm amber — signals action needed) */
.badge[data-allocation="full"]    { background: var(--color-badge-ok-bg);      color: var(--color-badge-ok-text);      }
.badge[data-allocation="partial"] { background: var(--color-badge-pending-bg); color: var(--color-badge-pending-text); }
.badge[data-allocation="none"]    { background: #FAF0E6;                        color: #7A4F1E;                         }

/****************************** Amounts distribution **************************/
/* One visual language for every display that breaks a total into its parts:
 * the shared category breakdown (dashboard + /reports), the dashboard's
 * Categoria × Atividade grid, the per-activity composition lists on /reports,
 * and the Custo por atividade table.
 *
 * They differ in SHAPE, and should: a ranked list with a hierarchy is not a
 * 2-D matrix, and neither is a set of cards. They must not differ in
 * VOCABULARY — the size and weight of an amount, how a share is written and
 * where it sits, what "sem categoria" looks like, how magnitude is drawn.
 * That is what the tokens below fix, and every one of those displays reads
 * its type off them rather than declaring its own.
 *
 * The rule the tokens encode, from the research in
 * doc/design/amounts-distribution.org:
 *   an amount and its share are ONE reading, never two modes of one control. */
:root {
  /* A part's name, and the amount beside it: the house `tbody td` size, which
     three of the four displays already used and the breakdown did not.        */
  --dist-name-size:   0.9375rem;

  /* One rung down — a child row inside a group, a row inside a mobile card.
     Never below 0.875rem: these are content, not micro-labels.                */
  --dist-detail-size: 0.875rem;

  /* The share. 500 is the floor for muted text (AGENTS.md); 400 at 13px on a
     tinted bar is a hairline outdoors. The width is what turns a trailing
     percentage into a column your eye can run down.                           */
  --dist-share-size:  0.8125rem;
  --dist-share-width: 3.4em;

  /* The row rhythm, and the inset the first column hangs off. Every display
     starts its names at the same x: the table pays it as cell padding, the
     breakdown as the chip's padding plus its container's.                     */
  --dist-row-y:       12px;
  --dist-row-x:       20px;

  /* The magnitude cue fills the row, and the part it does not fill is a
     visible track. Owner's call, 2026-09-28, overruling a 5px rule drawn under
     the row: with nothing behind it, a part-width line sitting on the row
     boundary reads as a two-tone broken separator rather than as a length, and
     it aligned with neither the text nor the grid. The track is what makes the
     fill a fraction of something. The tint stopping mid-grid is the known cost
     and it is paid deliberately — see doc/design/amounts-distribution.org.    */
  --dist-bar-height:  100%;

  /* The unfilled remainder. A variable so a hovered row can tint the track
     without touching the fill — with a full-height wash there is no bare
     surface left for an ordinary hover background to show through.            */
  --dist-track:       var(--color-surface-0);

  /* Attenuated green for chart bars — softer than --color-brand-1 (#486B13).
     color-mix blends brand-2 (light green) with surface-0 for a muted tint
     that reads as "data" rather than "action".
     Resolves to #C8DBA6: content 10.07:1, muted 4.70:1 — both AA as text
     backgrounds, and 1.15:1 against the surface-0 track it is drawn on. */
  --color-chart-bar: color-mix(in srgb, var(--color-brand-2) 55%, var(--color-surface-0));

  /* Muted warm grey-green — the "uncategorized" share, in the reports donut and
     in the hatch every "Sem categoria" row carries. Contrast vs white:
     2.6:1 (graphical element, not text — WCAG 1.4.11 requires 3:1 for UI
     components, acceptable here because the text alongside it meets 4.5:1). */
  --color-chart-uncategorized: #B8CCBB;
}

/* The share, wherever it appears. `td span` above styles every span in a cell
   as a status badge — an inline-block pill with 3px/10px padding, a 99px
   radius and 0.8rem type. A share is not a badge, it is the row's second
   figure, so this undoes the pill wherever the share lands inside a table. */
.dist_share {
  display: inline-block;
  min-width: var(--dist-share-width);
  margin-left: 8px;
  padding: 0;
  border-radius: 0;
  text-align: right;
  font-size: var(--dist-share-size);
  font-weight: 500;
  line-height: inherit;
  font-variant-numeric: tabular-nums;
  color: var(--color-content-muted);
}

/* The magnitude cue, drawn on the row rather than in a column of its own: the
   filled part is the row's share of the whole the display is about.
   `--bar-width` comes from bar_width_style in ApplicationHelper, so every
   display that draws one draws the same number on the same scale, and the
   ranked list, the grid row and the activity card all carry one identical
   rule. On a <tr> it paints behind the cells and spans the grid, which is
   what makes it a length you can compare across rows. */
.dist_bar {
  background:
    linear-gradient(
      to right,
      var(--color-chart-bar) var(--bar-width, 0%),
      var(--dist-track) var(--bar-width, 0%)
    ) bottom left / 100% var(--dist-bar-height, 100%) no-repeat;
}

/* Spend with no category. Hatched rather than tinted: a solid bar would read as
   one more category, and this is the absence of one. Its text is NOT muted —
   the hatch and the words "Sem categoria" already say "not filed", and muted
   ink on the hatch measured 4.12:1, under AA. Unfiled money is also the money
   most worth reading (doc/design/dashboard.org §8.2), so it gets full ink:
   13.3:1 on the track, 8.82:1 on the hatch itself. */
.dist_bar_unfiled {
  background:
    repeating-linear-gradient(
      -45deg,
      var(--color-chart-uncategorized) 0 6px,
      transparent 6px 12px
    ) bottom left / var(--bar-width, 0%) var(--dist-bar-height, 100%) no-repeat,
    /* the same track every filled row sits on, so the hatch is a fraction of
       the same whole rather than a stripe floating on the page */
    linear-gradient(var(--dist-track), var(--dist-track));
}

/* The ranked list: one dimension, with a hierarchy. The container's side
   padding plus the chip's own comes to --dist-row-x, so the names start on the
   same x as the first column of the grid that renders in this slot instead. */
.category_breakdown {
  padding: 8px 8px 20px;
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.breakdown_group {
  border: none;
}

details.breakdown_group {
  border: none;
}

.breakdown_row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: var(--dist-row-y) 12px;
  border-radius: 6px;
  list-style: none;
  background-color: var(--color-surface-0);   /* the track the bar is drawn on */
}

/* It never expands — there is nothing underneath it — so it is a plain row,
   not a <summary>. */
.breakdown_uncategorized {
  background-color: var(--color-surface-0);
}

summary.breakdown_row::-webkit-details-marker { display: none; }
summary.breakdown_row { list-style-type: none; cursor: pointer; }

/* Only the rows that actually do something respond to the pointer. A hover on
   a row that cannot be opened promises an interaction that is not there. */
summary.breakdown_row:hover {
  box-shadow: inset 0 0 0 1px var(--color-separators);
}

.breakdown_name {
  font-size: var(--dist-name-size);
  font-weight: 500;
  color: var(--color-content);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.breakdown_value {
  display: flex;
  align-items: baseline;
  font-size: var(--dist-name-size);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  color: var(--color-content);
  text-align: right;
  white-space: nowrap;
  flex-shrink: 0;
  margin-left: 12px;
}

.breakdown_children {
  padding-bottom: 8px;
}

.breakdown_child {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  padding: 4px 12px;
}

.breakdown_child_name {
  font-size: var(--dist-detail-size);
  font-weight: 500;
  color: var(--color-content-muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.breakdown_child_value {
  display: flex;
  align-items: baseline;
  font-size: var(--dist-detail-size);
  font-weight: 500;
  font-variant-numeric: tabular-nums;
  color: var(--color-content-muted);
  white-space: nowrap;
  flex-shrink: 0;
  margin-left: 12px;
}

/* The grand total, on the same 2px rule and the same 700 as every <tfoot> in
   the app: it is the one number allowed to outweigh the rows above it. */
.breakdown_footer {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  padding: 16px 12px 0;
  border-top: 2px solid var(--color-separators);
  margin-top: 8px;
  font-size: var(--dist-name-size);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--color-content);
}

/********************************* Link-as-button *****************************/
/* .button and .button.secondary let link_to render as a primary/secondary    *
 * button without being inside a <form>. Same sizing as form buttons.         */
.button {
  display: inline-block;
  padding: 9px 22px;
  border-radius: 5px;
  font-size: 0.9375rem;
  font-weight: 600;
  font-family: inherit;
  line-height: 1.5;
  text-decoration: none;
  cursor: pointer;
  transition: background 0.15s, border-color 0.15s, color 0.15s;
  background: var(--color-brand-0);
  border: 1.5px solid var(--color-brand-0);
  color: var(--color-surface-2);
}

.button:hover {
  background: var(--color-brand-1);
  border-color: var(--color-brand-1);
  color: var(--color-surface-2);
  text-decoration: none;
}

.button.secondary {
  background: transparent;
  border-color: var(--color-brand-0);
  color: var(--color-brand-0);
}

.button.secondary:hover {
  background: color-mix(in srgb, var(--color-brand-2) 30%, transparent);
  color: var(--color-brand-0);
}

/********************************* Aside panels *******************************/
aside {
  display: flex;
  flex-direction: column;
  gap: 16px;
}

aside > div:first-child {
  background: var(--color-accent-0);  /* corporate blue — distinguishes the aside from the green nav */
  border-radius: 8px;
  padding: 24px;
  box-shadow: 0 2px 8px rgba(0,0,0,0.12);
}

aside > div:first-child p:first-child {
  font-size: 0.68rem;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.75);  /* white-alpha label on blue — ~8:1 */
  margin-bottom: 10px;
}

aside > div:first-child p:nth-child(2) {
  font-size: 2rem;
  font-weight: 700;
  letter-spacing: -0.03em;
  color: var(--color-surface-2);  /* pure white — 3.76:1 on #5B7FA6 (large text: ≥ 3:1 AA) */
  margin-bottom: 4px;
  font-variant-numeric: tabular-nums;
}

aside > div:first-child p:last-child {
  font-size: 0.8rem;
  font-weight: 500;
  color: rgba(255, 255, 255, 0.75);  /* white-alpha subtitle on blue — ~8:1 */
}


/********************************* Button strip ********************************/
/* .actions is a flex strip of link_to / button_to actions.
   button_to wraps a <button> in a <form>; dissolve the form into the flex
   flow so it participates directly in the strip layout.                       */
/* ── A table that is wider than its card ────────────────────────────────────
   An opt-in container, never a global `table { overflow-x: auto }`.

   `main section` clips with overflow: hidden, so a table wider than the card
   does not merely look cramped — its right-hand columns become *unreachable*.
   At 375px the receipts table is 888px inside a 423px card, which put
   "Registrar despesa" permanently out of reach.

   This is a stopgap, not the answer. interface-system.org §3.4 is right that a
   farmer cannot discover a sideways scroll on a phone, and §4.2 specifies the
   real fix: a declared column priority that drops columns and restacks the row
   below 760px. Until that ships, reachable-by-scrolling beats invisible.

   tabindex makes it scrollable from the keyboard; without it a scroll
   container with no focusable child cannot be reached at all. */
.table_scroll {
  overflow-x: auto;
  overscroll-behavior-x: contain;
}

.table_scroll:focus-visible {
  outline: 2px solid var(--color-brand-1);
  outline-offset: -2px;
}

/* The row that sits directly above a list: the filters that act on that list,
   and the one action the page exists for. Page-level filters live here rather
   than in the app header, so the header's contents stop changing shape per
   page — doc/design/interface-system.org §3.1. */
.list_toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 10px 16px;
  min-width: 0;
}

/*************** Choosing one of N — the tab strip and the chip row ***********
   Two shapes, one vocabulary. Five dialects used to say "you are here" in
   unrelated visual languages; a farmer who learned one was taught nothing by
   the next. See doc/design/selection-controls.org for the argument and for
   what was rejected.

   The line between the two is NOT "does the URL change" — the archive's chips
   change it and the period panel's dimension tabs do not. It is what the
   options ARE:

     .tab_strip  the options are different COLLECTIONS — different records,
                 different columns, different verbs. Switching is a move, and a
                 collection may carry a count of what is waiting in it.
     .chip_row   the options are ONE collection, narrowed or read differently —
                 same rows, same columns, same verbs, fewer of them or a
                 different reading. Never a count: the list below says how many.

   What makes them one system rather than two: the same ink ramp (muted idle →
   brand-1 hover → brand-0 active), the same 500→600 weight step, the same
   0.12s ease, the same focus ring, and the same behaviour on a phone (the
   touch target grows, the words never leave). They differ on exactly two
   things, and both carry meaning: the active MARK (an underline for a move, a
   fill for a narrowing) and one step on the type scale, because a strip that
   switches the page outranks the one that filters it.                       */

.tab_strip {
  display: flex;
  flex-wrap: wrap;
  gap: 0 20px;
  margin-bottom: 20px;
  border-bottom: 1px solid var(--color-separators);
}

.tab_strip :is(a, label) {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 10px 2px;
  margin-bottom: -1px;
  border-bottom: 2px solid transparent;
  font-size: 0.9375rem;
  font-weight: 600;
  line-height: 1.5;
  color: var(--color-content-muted);   /* 6.20:1 on surface-0 · 6.55:1 on surface-1 */
  text-decoration: none;
  cursor: pointer;
  transition: color 0.12s, border-color 0.12s;
}

/* Hover is brand-1, never brand-0: hovering a tab used to paint it the exact
   colour of the active one, so the page briefly lied about where you were. */
.tab_strip :is(a, label):hover {
  color: var(--color-brand-1);         /* 5.50:1 on surface-0 · 5.81:1 on surface-1 */
  text-decoration: none;
}

/* Radios so the switch works without JS and is a control the browser already
   understands; the input itself is never the affordance. */
.tab_strip input[type="radio"] {
  position: absolute;
  opacity: 0;
  pointer-events: none;
}

.tab_strip a[aria-current="page"],
.tab_strip label:has(input:checked) {
  color: var(--color-brand-0);         /* 6.82:1 on surface-0 · 7.68:1 on white */
  border-bottom-color: var(--color-brand-0);
}

/* The count of work waiting in the collection this tab opens. Identical to
   .nav_badge, deliberately: the rail's "a conferir" count and this one are the
   same number, so they are the same object. Amber says "a queue", not "an
   alarm" (white on accent-1 = 4.85:1 — AA). */
.tab_strip .tab_count {
  min-width: 1.7em;
  padding: 1px 6px;
  border-radius: 99px;
  background: var(--color-accent-1);
  color: #fff;
  font-size: 0.8rem;                   /* the AGENTS.md secondary-text floor */
  font-weight: 700;
  line-height: 1.5;
  text-align: center;
  font-variant-numeric: tabular-nums;
}

.chip_row {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 6px;
  min-width: 0;
}

/* The button arm carries [type="button"] to out-specify the generic
   `form button` / `form button:last-child` primary-button rules above — the
   period panel's option chips are <button>s inside its filter form, and
   without this the last chip in each row renders as if it were selected. */
.chip_row :is(a, label),
.chip_row button[type="button"] {
  display: inline-flex;
  align-items: center;
  padding: 5px 14px;
  border-radius: 99px;
  /* A visible idle border, which the archive's chips did not have. An
     unselected option drawn as bare grey text reads as a caption, not as
     something you may press — and this audience opens the app a few times a
     week (doc/design/audience-not-power-users). */
  border: 1.5px solid var(--color-separators);
  background: var(--color-surface-2);
  font-family: inherit;
  font-size: 0.875rem;
  font-weight: 500;
  line-height: 1.5;
  color: var(--color-content-muted);   /* 6.98:1 on surface-2 */
  white-space: nowrap;
  text-decoration: none;
  cursor: pointer;
  transition: border-color 0.12s, background 0.12s, color 0.12s;
}

.chip_row :is(a, label):hover,
.chip_row button[type="button"]:hover {
  border-color: var(--color-brand-1);
  background: var(--color-surface-2);
  color: var(--color-brand-1);         /* 6.20:1 on surface-2 */
  text-decoration: none;
}

.chip_row input[type="radio"] {
  position: absolute;
  opacity: 0;
  pointer-events: none;
}

/* One filled chip, so "the one that is on" is never in doubt. .pf_active is
   the period panel's marker: those chips stage a choice for "Aplicar" rather
   than navigating, so they cannot carry aria-current. */
.chip_row a[aria-current="page"],
.chip_row label:has(input:checked),
.chip_row button[type="button"].pf_active {
  background: var(--color-brand-0);
  border-color: var(--color-brand-0);
  color: #fff;                         /* 7.68:1 on brand-0 — AAA */
  font-weight: 600;
}

.chip_row button[type="button"].pf_active:hover {
  background: var(--color-brand-1);
  border-color: var(--color-brand-1);
  color: #fff;
}

.tab_strip :is(a, label):focus-visible,
.chip_row :is(a, label):focus-visible,
.chip_row button[type="button"]:focus-visible {
  outline: 2px solid var(--color-brand-1);
  outline-offset: 2px;
}

/* ── Phones ──────────────────────────────────────────────────────────────
   Only the touch target grows. The archive's chips used to collapse to bare
   unlabelled dots here (font-size: 0) because the app header had no room for
   three words; in the page body it does, and three dots were a guess for an
   audience that is not in the tool every day. Nothing in either family ever
   drops its label or scrolls sideways.                                      */
@media (max-width: 768px) {
  .tab_strip :is(a, label) {
    padding: 12px 2px;
  }

  .chip_row :is(a, label),
  .chip_row button[type="button"] {
    padding: 9px 14px;   /* ≥44px tall with the line box — pointer: coarse */
  }
}

.actions {
  display: flex;
  gap: 10px;
  margin-bottom: 16px;
  flex-wrap: wrap;
  align-items: center;
}

/* button_to generates <form class="button_to"> — make it invisible in layout */
.actions form {
  display: contents;
}

/* Buttons inside .actions inherit a.button sizing; default = secondary style  */
.actions button {
  display: inline-block;
  padding: 9px 22px;
  border-radius: 5px;
  font-size: 0.9375rem;
  font-weight: 600;
  font-family: inherit;
  cursor: pointer;
  transition: background 0.15s, border-color 0.15s, color 0.15s;
  background: transparent;
  border: 1.5px solid var(--color-brand-0);
  color: var(--color-brand-0);
}

.actions button:hover {
  background: color-mix(in srgb, var(--color-brand-2) 30%, transparent);
}

/********************************* Swatches ***********************************/
.swatches {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 6px;
  padding: 16px 20px;
}

.swatches span {
  display: block;
  height: 36px;
  border-radius: 4px;
  border: 1px solid var(--color-separators);
  position: relative;
}

.swatches span::after {
  content: attr(title);
  position: absolute;
  bottom: -18px;
  left: 0; right: 0;
  font-size: 0.6rem;
  color: var(--color-content-muted);
  text-align: center;
  white-space: nowrap;
}

.swatches_wrap { padding-bottom: 16px; }

/********************************* Quick actions (sidebar verb strip) *********/
/* Promote one, quiet two — interface-system.org §3.2.9.
 *
 * This strip used to render all three items as filled purple buttons at weight
 * 700 with a drop shadow, which made them the loudest objects in the rail:
 * louder than any nav item and louder than the notas badge. Two things were
 * wrong with that. Three obvious things is no obvious thing (the promote-one
 * rule the dashboard already follows), and it spent the rail's colour budget on
 * an affordance — a purple block saying "you could always do this", competing
 * with the one element that says "there is work waiting right now".
 *
 * So exactly one action is filled and the other two are ordinary rail rows.
 *
 * Not pinned with margin-top: auto either. Microsoft Fluent advises against a
 * pinned nav footer because it obscures nav content as the list grows, and our
 * rail is twelve items and growing. Unpinned, but still last: the caveat is
 * against a footer that claims the leftover height and can cover the nav, not
 * against the verbs coming last. The rule above them is the one IA §6b draws.
 */
#quick_actions {
  /* On the floor of the rail, not wherever the list happens to stop. The
     Fluent caveat above is against a footer that CLAIMS the leftover height
     and can cover the nav; an auto margin in a flex column collapses to zero
     the moment the rail overflows, so the verbs get pushed down by the list
     instead of hiding it. */
  margin-top: auto;
  padding: 12px 0 4px;
  border-top: 1px solid rgba(255,255,255,0.12);
}

#quick_actions h2 {
  /* inherits the nav section h2 rule — just override padding slightly */
  padding-bottom: 8px;
}

/* The two quiet ones inherit `body > nav section ul li a` wholesale: same
   weight, same colour, same icon column as Despesas or Relatórios. Nothing to
   declare — the absence of a rule here is the design. */
#quick_actions ul li {
  padding: 0;
}

/* The promoted one: a filled pill, inset from the rail edge so it reads as an
   object rather than as a row. */
#quick_actions ul li.qa_primary {
  padding: 2px 12px 4px;
}

#quick_actions ul li.qa_primary a {
  gap: 9px;
  padding: 9px 13px;
  border-left: none;
  border-radius: 8px;
  background: var(--color-brand-2);
  /* #1A2B1A on #A8C96B = 8.00:1 ✅ AAA. Measured, not assumed: the obvious
     pairing --color-brand-0 on --color-brand-2 is only 4.11:1 and FAILS AA at
     this size, which is exactly what these annotations exist to catch. */
  color: var(--color-content);
  font-size: 0.84rem;
  font-weight: 700;
  transition: background 0.15s;
}

#quick_actions ul li.qa_primary a:hover {
  /* Lighter, not darker: on a dark rail a lift reads as hover, and it raises
     the text contrast rather than eroding it — #B5D181 = 8.84:1 ✅ AAA. */
  background: color-mix(in srgb, var(--color-brand-2) 85%, #FFFFFF);
  color: var(--color-content);
}

#quick_actions ul li.qa_primary a .icon {
  /* The rail's 20px icon column belongs to the rows; inside a pill the icon
     sits tight against its label. An explicit width is required — the shared
     .icon rule sizes the box, and `auto` on an empty masked span is 0. */
  --icon-size: 1.1rem;
  width: var(--icon-size);
}

/* Collapsed nav — the pill keeps its shape, the rows keep the shared centring
   rule from the sidebar block above. */
body:not(.nav_open) #quick_actions ul li.qa_primary {
  padding: 2px 8px 4px;
}

body:not(.nav_open) #quick_actions ul li.qa_primary a {
  justify-content: center;
  padding: 9px 0;
}

/********************************* Mobile action bar **************************/
#mobile_actions { display: none; }

/********************************* Responsive *********************************/
/* Desktop-first: base styles target ≥1280px. Queries narrow for smaller viewports. */

/* Large desktops and below — ≤1280px */
@media (max-width: 1280px) {
}

/* ── The header ladder ──────────────────────────────────────────────────────
   Three things share this row: the title, the period pill and the activity
   pill. They shed in that order. The pills are last because the pill is what
   tells the farmer which window the numbers on screen belong to — losing it is
   worse than losing the page's own name, which the rail already shows.
   See doc/design/interface-system.org §3.1.                                  */

/* ≤1100px — the subtitle goes first. It is the longest and the least load
   bearing: it restates the frame that the pill beside it already names. */
@media (max-width: 1100px) {
  body > header hgroup p { display: none; }
}

/* ≤900px — two rows: title above, pills below, both left-aligned. This is not
   a failure state. Letting the header grow to 92px costs far less than
   truncating the one control that says what period is being shown. */
@media (max-width: 900px) {
  /* auto, not a second magic number: on a page with no pills this is one row
     of title, and on a narrow phone with a long custom range it is three. The
     row takes what the content needs and the dropdown panels follow it (see
     .hdr_panel at ≤768). */
  body { --header-height: auto; }

  body > header {
    flex-wrap: wrap;
    align-content: center;
    row-gap: 6px;
    min-height: 60px;
    padding-top: 8px;
    padding-bottom: 8px;
  }

  /* Forces the wrap: the title takes the whole first row, the pills fall to
     the second in their natural order. */
  body > header hgroup { flex: 1 0 100%; }
}

/* Laptops and below — ≤1024px */
@media (max-width: 1024px) {
  .content_grid { grid-template-columns: 1fr; }

  /* Reset explicit grid placement so the aside flows below the sections. */
  .content_grid > aside {
    grid-column: auto;
    grid-row: auto;
  }

}

/* Tablets and below — ≤768px */
@media (max-width: 768px) {
  /* The title used to be dropped outright here. That left a blank 60px band on
     every page without a period pill, and — worse — the rail is icon-only at
     this width too, so nothing on screen said what page the farmer was looking
     at. interface-system.org §3.1 asks for two rows down to the smallest
     screen rather than a title-less header; this is that.
     The subtitle stays hidden (see ≤1100px). */

  .kpi_row { grid-template-columns: 1fr; }
  .kpi_row article { padding: 14px 16px; }
  .kpi_row .kpi_value { font-size: 1.4rem; }

  .category_breakdown { padding: 4px 4px 16px; }

  /* #mobile_actions replaces the sidebar quick actions on small screens */
  #quick_actions { display: none; }

  #mobile_actions {
    display: flex;
    position: fixed;
    bottom: 0; left: 0; right: 0;
    background: var(--color-surface-2);
    border-top: 1px solid var(--color-separators);
    box-shadow: 0 -2px 8px 0 var(--color-separators);
    z-index: 100;
  }

  #mobile_actions a {
    flex: 1;
    display: flex;
    flex-direction: row;
    align-items: center;
    justify-content: center;
    gap: 6px;
    padding: 12px 4px;
    font-size: 0.8125rem;
    font-weight: 600;
    color: var(--color-content-muted);
    white-space: nowrap;
  }

  #mobile_actions a:hover,
  #mobile_actions a:first-child { color: var(--color-brand-0); }

  #mobile_actions a span { font-size: 1.1rem; line-height: 1; }

  main { padding-bottom: 80px; }
}

/* ── Category tree — shared depth indentation ──────────────────────────────── */
/* Any element with data-depth is indented by 1.25rem per level.              */
/* Used in: categories#index (.category_tree li) and ELI category checkboxes  */
/* (fieldset label) so both places stay consistent without extra classes.      */

[data-depth="0"] { padding-left: 0; }
[data-depth="1"] { padding-left: 1.25rem; }
[data-depth="2"] { padding-left: 2.5rem; }
[data-depth="3"] { padding-left: 3.75rem; }

/* Large phones and below — ≤480px */
@media (max-width: 480px) {
  /* The share used to be dropped here. It is half of what a distribution row
     says — "R$ 4.750,00" alone answers no question a farmer has — and at
     0.8125rem it costs ~44px on a 335px row. It stays to the smallest phone. */
}

/* Small phones — ≤375px */
@media (max-width: 375px) {
}
