/* Decision 9 — INTER THROUGHOUT, one variable file.
   Three Source Serif files went with this one: what a second family used to
   signal (a heading is not a table cell), weight and size signal instead.
   Inter 4.1, SIL Open Font License — the licence ships beside the font. */
@font-face {
  font-family: "Inter";
  font-style: normal; font-weight: 100 900; font-display: swap;
  src: url("../fonts/inter/InterVariable.2bf3d951bf9d.woff2") format("woff2");
}

/* Fundo La Campana brand reskin of the Django admin (master_build_plan.md §1.15).
   Overrides the admin's CSS variables to the brand palette. Light-only for
   brand consistency in the office.

   THIS BLOCK IS THE LANGUAGE. Twenty-nine decisions were settled on rendered
   screens on 18 August 2026, each measured rather than eyeballed; the values
   and the evidence are in mockups/flc-tokens.css and
   mockups/design-language-live.html. A screen reads its colours, its type and
   its spacing from the names below. A template that declares its own palette
   is outside the language however well the language is written down, which is
   why accounts/tests_design_language.py refuses a new one, and why
   accounts/tests_contraste.py measures the roles instead of trusting a
   comment — two comments in here were wrong on 18 August. */

:root {
  color-scheme: light;

  /* ── SURFACES ──────────────────────────────────────────── Decisions 1, 12
     Cards sit ON the page — never a white sheet floating on cream. Measured:
     on a sheet a card separates from what it sits on by 0; on the page, 5.2.
     Warm at roughly a third of the old tan's saturation. */
  --body-bg: #f5f2ed;            /* the page behind everything    was #f7f4ee */
  --border-color: #e4e1db;       /* the hairline round a card     was #e4ded0 */
  --hairline-color: #ece9e3;     /* the softer rule inside a card was #ece7db */
  --darkened-bg: #e4e1da;        /* CREAM header = you READ it    was #efe9dc */
  --selected-row: #faf8f4;       /* a footer row, a grid heading  was #fdf7e6 */
  --selected-bg: #e9f0f8;        /* the blue wash                 was #eef3f9 */
  /* The card, and the header that says «you TYPE into this one». Blue is the
     default; the cream --darkened-bg above says the card is read-only. These
     two came up from orden_form.css, which declared them privately because
     "they have no brand equivalent" — true until Decision 2 gave them one. */
  --card-bg: #ffffff;
  --card-header: #f2f6fb;

  /* ── TEXT ─────────────────────────────────────────────────── Decision 13
     Twelve values replacing the app's forty-two, each measured against the
     surface it sits on. Nothing below 4.5:1. */
  --body-fg: #111111;            /* everything you read    18.9:1  was #1c2b3a */
  --body-loud-color: #111111;
  --body-quiet-color: #33434f;   /* labels, second lines   10.2:1             */
  --link-fg: #075a8c;            /* clickable text          7.4:1             */
  --error-fg: #9b130f;           /* wrong, in words         7.4:1  Django's own
                                    name; without this the admin's error text
                                    keeps Django's default, outside the 23 */
  --flc-muted: #76746d;          /* nothing yet, disabled   4.7:1   NEW        */
  --flc-on-gold: #3d2a00;        /* the only ink gold takes 7.0:1   NEW        */
  /* THE THREE INKS THAT HAD NO NAME. The palette's table has fifteen cells and
     twelve of them were reachable by name; green, red and gold could only be
     written as a literal, which is exactly how a screen ends up with its
     fourth near-green. You cannot ask nineteen templates to read the shared
     names for an ink that no shared name exists for. */
  --flc-ink-green: #245d1d;      /* «done» in words         7.6:1  NEW        */
  --flc-ink-red: #9b130f;        /* «wrong» in words        7.4:1  NEW        */
  --flc-ink-gold: #6e4d00;       /* «missing» in words      7.3:1  NEW        */
  /* The two SECOND INKS. Blue and neutral each do two jobs and one ink slot
     cannot hold both: a link is not a status, and a field label is not a
     status either. Collapse them and a mark starts reading as pressable. */
  --flc-status-blue: #0d528c;    /* status text on a blue wash                 */
  --flc-status-slate: #454f57;   /* status text on a grey wash                 */

  --header-color: #ffffff;
  --header-branding-color: #ffffff;
  --header-bg: #144b8b;
  --header-link-color: #ffffff;

  --breadcrumbs-fg: #33434f;
  --breadcrumbs-link-fg: #075a8c;
  --breadcrumbs-bg: #f5f2ed;

  /* Decision 16: a link UNDERLINES and does not change colour. Django paints
     a:hover from this name, so it points at the same blue and the underline
     rule further down does the work. */
  --link-hover-color: var(--link-fg);
  --link-selected-fg: #144b8b;

  /* ── BRAND ───────────────────────────────────── unchanged; one of each  */
  --primary: #144b8b;            /* navy */
  --primary-fg: #ffffff;
  --secondary: #075a8c;          /* the interface blue: focus rings and blue
                                    accents. The arc keeps #0867a1 to itself
                                    -- brand, and nowhere else (Decision 23) */
  --accent: #f6ab08;             /* gold */

  /* Semantic action colors (design spec): Guardar = green, Editar = gold,
     Eliminar = red. Wired into Django's button vars below. */
  /* Decision 14. The green that was here put white at 3.55:1 — under the 4.5
     the language requires — and got past twice on 18 August because it WAS a
     house colour: the palette guards ask which colours exist, not which one
     plays which role. accounts/tests_contraste.py measures the role, and names
     the old value so a revert is recognised. This one is 5.71:1 and was
     already in cinta.css. */
  --save-green: #2c7524;
  --delete-red: #e01e19;
  /* --edit-yellow and --edit-yellow-hover went with Decision 10: gold MARKS
     things and never DOES things, so nothing "edits" in gold any more and the
     name described nothing. Where gold still marks -- the rail on the open
     sidebar item, the login button Jordan ruled keeps it -- the rule reads
     --accent, which is the brand gold.
     --delete-red-hover went with the 88% rule. */

  --button-bg: #144b8b;
  /* Decision 16: hover is the SAME solid at 88%, computed — never a second
     named colour. --save-green-hover was picked to sit under the OLD green and
     ended up ABOVE the new one, so Guardar went pale under the pointer while
     the other three darkened. A named hover is a second copy of a decision,
     and second copies drift; the rule cannot.
     color-mix, not filter: brightness(.88) — the filter darkens the LABEL too,
     dropping white to a light grey, and that takes the red button from 5.94:1
     to 4.50, right on the floor. Measured, not assumed. */
  --button-hover-bg: color-mix(in srgb, var(--button-bg) 88%, black);
  --button-fg: #ffffff;
  /* Program-wide button convention (design spec): green = save/save-and-send
     (Django's primary "default" action), gold = edit, red = delete. The tokens
     themselves are defined above at their locked spec values. */
  --default-button-bg: var(--save-green);        /* Guardar = green */
  --default-button-hover-bg: color-mix(in srgb, var(--default-button-bg) 88%, black);
  --delete-button-bg: var(--delete-red);         /* Eliminar = red */
  --delete-button-hover-bg: color-mix(in srgb, var(--delete-button-bg) 88%, black);
  --close-button-bg: #33434f;
  --close-button-hover-bg: color-mix(in srgb, var(--close-button-bg) 88%, black);

  /* ── THE FIVE MEANINGS, as washes ─────────────────────────── Decision 14
     Django's own message and alert colours, moved onto the palette. */
  --alert-bg: #fef3dd;                /* gold  — missing, partial  was #fff6e0 */
  --message-success-bg: #eaf6e8;      /* green — done, closed      was #e9f4e4 */
  --message-warning-bg: #fef3dd;      /* gold                      was #fdf3dd */
  --message-error-bg: #fbe6e5;        /* red   — wrong, void       was #fdeceb */

  /* ── TYPE ────────────────────────────────────────── Decisions 7, 9, 13
     ONE family. What a second family used to signal, weight and size signal.
     --font-family-serif is kept as a NAME because three per-screen stylesheets
     read it; it no longer names a second family. */
  --font-family-primary: "Inter", system-ui, -apple-system, sans-serif;
  --font-family-serif: "Inter", system-ui, -apple-system, sans-serif;
  --font-family-monospace: ui-monospace, SFMono-Regular, Menlo, monospace;

  /* ── SHAPE + SPACING ────────────────────────── Decisions 3, 4, 7 (level B)
     Cards 6px, anything pressed 999px, and five spacing steps — not a scale
     invented per screen. */
  --flc-r-card: 6px;
  --flc-r-pill: 999px;
  --flc-sp-hair: 4px;      /* label to its box; inside a table cell */
  --flc-sp-tight: 8px;     /* two controls that belong together     */
  --flc-sp-card: 12px;     /* inside a card                         */
  --flc-sp-field: 14px;    /* between fields on a row               */
  --flc-sp-block: 20px;    /* between cards and sections            */
  --flc-t-title: 25px;
  --flc-t-card: 14px;
  --flc-t-body: 13px;
  --flc-t-data: 12px;
  --flc-t-label: 10px;
  --flc-lh-data: 1.35;
  --flc-lh-prose: 1.5;

  /* NOT a spacing step — a coupling. The sidebar is fixed and out of flow, so
     everything after it in the DOM is offset by exactly its width. Two numbers
     that must never drift apart, the same problem --flc-shell-top solves for
     the arc. */
  --flc-sidebar-w: 210px;

  /* ── HOW WIDE IS A PAGE ─────────────────────────────── Decision 23, 19 Aug
     THE KIND OF SCREEN DECIDES, and that is the rule rather than a dodge.
     There were three numbers in the code and none of them was written down:
     940px on the record, 1400px on the grids under a class called `ancha`, and
     no cap at all on the lists. Three people answered the same question
     separately. These names are that answer, stated once.

       READ or FILL   a record, a guided form. It is a document: it caps and
                      centres, so a label and its value stay near each other.
       GRID           a loading table you type into. It is both a form and a
                      wide table, which is why `ancha` had to exist at all.
       LIST           a changelist. No cap: measured, the two lists used daily
                      need 1186-1188px, so any cap under that hides columns
                      behind a sideways scrollbar.

     The numbers are the ones already in production. Nothing measured says they
     are wrong, and changing them would be change for its own sake. */
  --flc-w-read: 940px;
  --flc-w-grid: 1400px;
}

/* Decision 9 deleted a rule here. «Type system (Option B)» put Source Serif
   back on headings, nav and card titles after the body default went sans. With
   one family there is nothing to put back: the same names now resolve to Inter
   either way, and a heading is separated from a table cell by weight and size.
   Three per-screen stylesheets still read --font-family-serif; the name stays,
   the second family does not. */

/* The signature 4-color arc rule under the header. THE ARC IS BRAND, NOT
   INTERFACE: it keeps all four of its own colours, two of which appear nowhere
   else, the same exemption the printed sheet's brand marks have. 8px since
   18 August — clearly a band rather than a hairline, without becoming
   furniture; 12px was too much. */
#header {
  border-bottom: 8px solid transparent;
  border-image: linear-gradient(90deg, #e01e19, #f6ab08 42%, #7fb529 70%, #0867a1) 1;
}

/* Brand wordmark. */
#site-name a { color: #fff; font-weight: 600; letter-spacing: .01em; }

/* Module cards: white surface, brand hairline, rounded, subtle hover lift. */
.module {
  border: 1px solid var(--border-color);
  border-radius: 6px;
  overflow: hidden;
  background: #ffffff;
}
.module caption,
.module h2 { background: #f2f6fb; color: #144b8b; }

/* A wide tabular inline was UNREACHABLE, not merely ugly, and this file is why.
   The `overflow: hidden` just above buys the rounded corners on every .module
   card -- but a tabular inline IS a .module, so any column past the right edge
   was clipped away with NO scrollbar to bring it back. Jordan (2026-08-04, on
   Safari) could see four of Fertirriego's ten columns and had no way to reach
   the other six: not the browser's doing, ours.

   The changelist already had its own `#changelist .results { overflow-x: auto }`
   further down; this is the same treatment for the inlines on a change form.
   Only the horizontal axis is released -- overflow-y stays hidden so the card
   keeps its rounded corners, and neither dropdown is clipped by it: the native
   <select> is drawn by the OS, and select2 hangs its list off <body>. */
.inline-group .tabular > fieldset.module { overflow-x: auto; }

/* App-group section links (INVENTARIO, MASTERDATA, …) inherit the white
   --header-link-color meant for the dark top bar, but their caption sits on a
   LIGHT background — force brand navy so they're readable (was white-on-white). */
.module caption a.section,
.module caption a:link,
.module caption a:visited { color: #144b8b; }

/* Decision 16: a link underlines under the pointer and does NOT change colour.
   Django leaves a:link with no underline and only shifts its colour on :hover
   -- which is the signal lost on anyone who cannot separate those two blues. */
a:focus, a:hover { text-decoration: underline; }

/* DECISION 15 -- A NUMBER BOX. Right-aligned, with tabular figures, so units
   stack and one digit too many shows up on its own. The unit goes in the column
   head, never repeated in the cell. There were 27 boxes across ten templates
   and 20 of the 27 were left-aligned; that is exactly why the rule lives here
   and not on each screen.
   `inputmode="decimal"` is the selector because it is what marks a number box
   in this program: type="number" is not used -- its value attribute must carry
   a dot, which is the trap «34.000» opened. */
input[inputmode="decimal"] {
  text-align: right;
  font-variant-numeric: tabular-nums;
}

/* DECISION 19 -- WHAT A SCREEN SAYS WHEN THERE IS NOTHING ON IT.
   This carries more weight here than it would elsewhere: production has no
   orders, no slips, no irrigation programmes and no fuel fills, so on half
   these screens the empty state is not an edge case -- it is the FIRST thing
   anyone sees, and on some of them the only thing for weeks.

   It answers three things in order: WHAT IS NOT HERE, WHAT THAT MEANS, and HOW
   IT GETS FILLED. If the third has no answer the screen is not empty, it is
   broken, and that is a different thing.

   NEVER RED AND NEVER A WARNING. Nothing has gone wrong: the work simply has
   not happened yet. It is muted #76746d, already one of the twenty-three, at
   reading size and not shrunken.

   THE ACTION DOES NOT GO IN THE BOX: it stays in the header where it always
   lives (Decision 6), so it does not move when the list fills up.

   There is a FOURTH kind: empty because the work is DONE -- «Nada pendiente» --
   which is not the same as empty because it has not started. It reads
   differently. */
/* IT GOES ON WHITE, and that is not decoration: measured, muted #76746d clears
   4.68:1 on the white card and clears the floor on NO other surface in the
   language -- 4.19 on the page, 4.31 on the blue «you type here» header, 4.41
   on the neutral wash. Decision 19 says "muted on the card" and it has to be
   read literally: the empty row of an admin list was landing on the page
   colour, at 4.19. */
.flc-vacio {
  color: var(--flc-muted);
  background: var(--card-bg);
  font-size: var(--flc-t-body);
  line-height: var(--flc-lh-prose);
  font-weight: 400;
  padding: var(--flc-sp-field) var(--flc-sp-card);
  border-radius: var(--flc-r-card);
}
/* The first sentence -- what is not here -- one notch heavier so it reads
   first. Not a stronger colour: the whole state is muted. */
.flc-vacio b { font-weight: 600; color: inherit; }
/* Inside a table it takes the whole row: the card already supplies the corner. */
td.flc-vacio { border-radius: 0; }

/* Rounded, pill-friendly buttons matching the brand. */
.button, input[type=submit], input[type=button], .submit-row input, a.button {
  border-radius: 999px;
}

/* Object tools -- Historial, Ver en el sitio, Agregar, el +. Decision 10: gold
   MARKS things and never DOES things, so the whole edit family is navy, which
   is what the language says a control that OPENS something looks like.
   Match Django's own .object-tools a:link/:visited specificity so this wins the
   cascade. */
.object-tools a:link, .object-tools a:visited {
  background-color: var(--button-bg); color: var(--button-fg);
}
.object-tools a:focus, .object-tools a:hover {
  background-color: var(--button-hover-bg); color: var(--button-fg);
}

/* Segunda acción: mismo tamaño, más callada. El borde reemplaza al relleno, y
   el padding baja 1px para compensarlo -- sin eso este botón queda 2px más
   alto que el primario y la fila se ve torcida. */
.object-tools a.flc-btn-secondary:link,
.object-tools a.flc-btn-secondary:visited {
  background-color: #ffffff;
  color: var(--button-bg);
  border: 1px solid var(--button-bg);
  padding: var(--flc-sp-hair) var(--flc-sp-field);
  background-image: none;
}
/* An outlined button has no solid to darken, so the 88% does not apply: it
   lights up with the neutral wash, the same as a row. */
.object-tools a.flc-btn-secondary:focus,
.object-tools a.flc-btn-secondary:hover {
  background-color: var(--selected-row);
  color: var(--button-bg);
}

/* Selected nav / current section in navy. */
.selector-chosen h2 { background: var(--primary); }

/* Login card gets the brand treatment (mockups/login-final.html): no navy
   header, a 5px rainbow arc pinned to the very top of the viewport, a single
   centered white card (Django's own .login #container box is neutralized so
   ours is the only visible card), and a gold "Ingresar" pill. */
body.login::before {
  content: "";
  position: fixed;
  top: 0; left: 0; right: 0;
  height: 8px;
  background: linear-gradient(90deg, #e01e19, #f6ab08 42%, #7fb529 70%, #0867a1);
  z-index: 20;
}
body.login { background: var(--body-bg); }

/* Neutralize Django's own login.css container box so only our card shows. */
body.login #container {
  background: transparent;
  border: 0;
  border-radius: 0;
  box-shadow: none;
  width: auto;
  min-width: 0;
  margin: 0;
}
body.login #content { padding: 0; }
/* Django base.css floats #content-main; neutralize it so the form flows inside the card. */
body.login #content-main { float: none; width: 100%; }

.flc-login-card {
  max-width: 400px;
  margin: 6vh auto 0;
  background: #fff;
  border: 1px solid var(--border-color);
  border-radius: 6px;
  padding: var(--flc-sp-block) var(--flc-sp-block) var(--flc-sp-block);
  box-shadow: 0 8px 30px rgba(20, 43, 60, .10);
  /* Border-box so the card's total width is exactly 400px like the mockup (padding doesn't add on top). */
  box-sizing: border-box;
}
.flc-login-logo { display: block; width: 190px; margin: var(--flc-sp-hair) auto var(--flc-sp-block); }
.flc-login-title {
  font-family: var(--font-family-serif);
  text-align: center;
  color: #144b8b;
  font-size: 22px;
  font-weight: 700;
  margin: 0 0 var(--flc-sp-block);
}
/* Footer line beneath the card, per mockups/login-final.html. Deliberately not
   given the serif token — it's fine print, so it follows the sans body font. */
.flc-login-foot {
  text-align: center;
  color: var(--body-quiet-color);
  font-size: 11.5px;
  letter-spacing: .02em;
  margin: var(--flc-sp-field) 0 var(--flc-sp-block);
}

body.login .form-row { padding: 0; border: 0; margin-bottom: var(--flc-sp-field); }
body.login .form-row label {
  display: block;
  font-size: 12px;
  font-weight: 600;
  color: #33434f;
  margin-bottom: var(--flc-sp-tight);
  letter-spacing: .02em;
}
body.login .form-row input[type=text],
body.login .form-row input[type=password] {
  width: 100%;
  font-size: 15px;
  color: var(--body-fg);
  border: 1px solid var(--border-color);
  border-radius: var(--flc-r-card);
  padding: var(--flc-sp-card) var(--flc-sp-field);
  background: #fff;
}
body.login .form-row input[type=text]:focus,
body.login .form-row input[type=password]:focus {
  outline: 2px solid var(--secondary);
  outline-offset: 0;
  border-color: var(--secondary);
}

/* GOLD pill submit — login stays gold (Task 2's deferred decision). */
body.login .submit-row { padding: 0; margin: 0; text-align: initial; }
body.login .submit-row input {
  width: 100%;
  font-family: var(--font-family-serif);
  font-size: 16px;
  font-weight: 700;
  cursor: pointer;
  background: var(--accent);
  color: var(--flc-on-gold);
  /* No border of its own: the gold already separates from the card's white,
     and the border it carried was a second gold nobody decided (Decision 14). */
  border: 0;
  border-radius: 999px;
  padding: var(--flc-sp-card) var(--flc-sp-block);
}
/* The 88% rule, not a lighter gold: the value that was here LIGHTENED the
   button under the pointer, the opposite of the other three. Darkened, the
   gold's ink sits at 5.42:1 -- measured, and measured again by
   tests_contraste.py. */
body.login .submit-row input:hover {
  background: color-mix(in srgb, var(--accent) 88%, black);
}

body.login .password-reset-link { text-align: center; margin-top: var(--flc-sp-field); font-size: 13px; }
body.login .password-reset-link a { color: #075a8c; font-weight: 500; }

/* Wide list (changelist) tables — Entregas and the four inventory lists carry
   many columns, so on a narrower window the table runs past the right edge.
   Django already scrolls it inside its own box (.results overflow-x:auto), but
   macOS/Electron overlay scrollbars stay invisible until you scroll, so those
   columns looked permanently cut off with no way to reach them ("the scrolling
   is messed up"). Styling ::-webkit-scrollbar forces a persistent, space-
   reserving bar under the rows — the missing affordance. Applies to every admin
   list. (Cell padding/font are left at Django's defaults on purpose: shrinking
   the font makes cells wrap less and the table WIDER, the opposite of helping.) */
/* List filters as an on-demand panel — the right-hand filter column is hidden
   by default so the data table spans the full width (paired with the left
   app-menu starting collapsed). flc_admin.js adds a "Filtros" button that sets
   .flc-filters-open on <body> to slide the panel out. Hiding it in CSS (not JS)
   means no flash of the panel on load in the common, closed state. When hidden,
   the flex sibling .changelist-form-container reclaims the panel's ~270px. */
body:not(.flc-filters-open) #changelist-filter { display: none; }

.flc-filters-toggle {
  border: 1px solid var(--border-color);
  background: #ffffff;
  color: #144b8b;
  border-radius: 999px;
  padding: var(--flc-sp-tight) var(--flc-sp-block);
  font-family: var(--font-family-primary);
  font-size: 13px;
  cursor: pointer;
}
.flc-filters-toggle:hover { background: var(--selected-row); }
.flc-filters-toggle.active {          /* panel open */
  background: #144b8b; color: #ffffff; border-color: #144b8b;
}
.flc-filters-toggle.has-active {      /* a filter is currently applied */
  border-color: #f6ab08; box-shadow: 0 0 0 2px rgba(246, 171, 8, .35);
}

/* One control strip: search left, actions right. Replaces four stacked bars
   (add buttons pulled up into the breadcrumb line, a bar holding only
   Filtros, the search form, and the date hierarchy). Renders on all 43
   changelists, so it must look deliberate when it holds only the add
   buttons -- which is the case on 4 of them. flc_admin.js moves #toolbar,
   #flc-filters-toggle and ul.object-tools into it. */
.flc-listbar {
  display: flex; align-items: center; gap: var(--flc-sp-card); flex-wrap: wrap;
  padding: var(--flc-sp-tight) var(--flc-sp-card); margin: 0;
  background: #ffffff; border-bottom: 1px solid var(--border-color);
}
/* Django's own #changelist { display:flex } (changelists.css) lays its two
   children -- the search/date/results column and, when filters exist, the
   filter nav -- out side by side as a row. flc_admin.js regroups exactly
   those two into a new .flc-changelist-row wrapper before adding the strip,
   so #changelist can drop to a plain block stack (strip on top, that row
   below) here without disturbing how the row's own children sit next to
   each other -- this rule is that same display:flex, just moved one level
   down onto the wrapper that now owns it.

   The "body" prefix is not decoration: base_site.html's {% block extrastyle
   %} chain loads flc_brand.css BEFORE change_list.html appends
   changelists.css (verified live -- the rendered <link> order is base.css,
   nav_sidebar.css, flc_brand.css, THEN changelists.css), so a bare
   "#changelist" here has equal specificity to Django's and LOSES on source
   order. Same trick as body:not(.flc-filters-open) #changelist-filter
   above. */
body #changelist { display: block; }
.flc-changelist-row { display: flex; align-items: flex-start; justify-content: space-between; }
/* Django's responsive.css (same breakpoint, verified in the venv copy) drops
   #changelist's OWN flex row to a column below 767px so the filter panel
   stacks under the table instead of squeezing beside it. That rule still
   targets "#changelist" by id, but #changelist is no longer the flex
   container -- .flc-changelist-row is (see the "body #changelist: block"
   rule above) -- so Django's selector no longer matches anything relevant
   and the stacking is lost. This restores it on the element that now
   actually owns the row layout, at the same breakpoint. */
@media (max-width: 767px) {
  .flc-changelist-row { flex-direction: column; align-items: stretch; }
}

/* Owner request: with the Filtros panel open, its right edge stopped ~40px
   short of #main's own right edge. Traced (not guessed) to #content's OWN
   padding (installed admin/css/base.css: "#content { padding: 20px 40px; }")
   -- #changelist-filter was already flush against ITS card's inner edge (the
   1px gap the owner measured, 1359 vs 1360, is just #changelist's own 1px
   border from the .module rule above); it's #changelist itself -- which
   carries class="module" (change_list.html: <div class="module{% if
   cl.has_filters %} filtered{% endif %}" id="changelist">) -- that stops
   40px short of #main's edge, inset by #content's padding like everything
   else inside it.

   #changelist has no explicit width (block, width:auto), so cancelling that
   padding with a matching negative margin-right doesn't just visually bleed
   it into the padding strip -- it grows #changelist's own computed width by
   exactly that much, and since .flc-changelist-row's two children are a
   fixed-width flex item (#changelist-filter) and a flex:1 1 auto one
   (.changelist-form-container, the table's wrapper), 100% of that reclaimed
   width lands on the table, per the owner's ask. Scoped to #changelist
   itself, not just .flc-changelist-row, so .flc-listbar (the search/
   Filtros/add-buttons strip, also a direct child of #changelist) widens in
   step and its own right edge keeps lining up with the row below it --
   widening only the row would leave the strip's edge sitting 40px short of
   the now-flush panel underneath it, a visible jog between the two.

   Only meaningful, and only safe, at the widths where #content's padding is
   actually 40px AND the panel is still a fixed-width flex column beside the
   table. Verified against the installed admin/css/responsive.css: it drops
   that padding to 15px 20px 20px (right: 20px) at <=1024px, and to a flat
   15px at <=767px -- where .flc-changelist-row above also stacks the panel
   under the table instead of beside it, so there is no leftover flex-basis
   gap to reclaim there at all. A single hardcoded -40px would have overshot
   #content's own (narrower) padding at both smaller tiers and pushed the
   card past #main's edge into a horizontal scrollbar -- exactly the kind of
   negative margin that "happens to look right at one width" this was
   written to avoid. Below 768px this rule does not apply, by design. */
/* ONE value now, not two. Django's #content padding was 40px at the widest
   tier and 20px below it, so this rule had to carry both numbers to cancel it.
   Decision 23 (19 August, Jordan) put the page gutter on the language's scale
   at 20px everywhere it was 40, which collapses the two tiers into one.
   THIS IS A COUPLED CONSTANT, the same shape as the arc and --flc-shell-top:
   it cancels #content's OWN padding, so if that gutter ever moves again, this
   moves with it in the same commit or the filter panel overshoots #main's edge
   into a horizontal scrollbar. */
@media (min-width: 768px) {
  body.flc-filters-open #changelist { margin-right: calc(var(--flc-sp-block) * -1); }
}
/* #changelist's own .module rounding (border-radius: 6px + overflow: hidden,
   see the .module rule above) is what already clips the filter panel's dark
   background to a curve at its top-right/bottom-right corners today -- the
   panel itself is a bare <nav>, never rounded on its own. Pushed flush
   against #main's true right edge, those two corners now sit right at the
   content area's outer boundary, where a rounded card reads as if it's
   missing its usual margin of air outside the curve. Squared off only on
   the two corners that land there, only while open (closed, #changelist
   keeps all four corners rounded -- unaffected by everything above, since
   the margin rules only fire under .flc-filters-open). Left corners are
   untouched; they were never near an edge and this fix doesn't move them. */
body.flc-filters-open #changelist {
  border-top-right-radius: 0;
  border-bottom-right-radius: 0;
}

/* Django floats .object-tools, pulls it up 48px with a negative margin to
   sit beside the breadcrumbs, and gives #toolbar its own background and
   padding -- all three must be neutralised inside the strip or it will not
   lay out as a row. */
/* A flexible spacer, rather than margin-left:auto on one of the controls: the
   strip is assembled from three OPTIONAL pieces, so pinning the gap to any
   single one of them mis-aligns the rest on the lists that lack it -- a table
   with no add buttons would strand Filtros on the left. The spacer sits right
   after the search box and absorbs whatever room is going, so everything after
   it lands hard right whichever pieces exist. */
/* Django's changelists.css puts a 30px margin-left on the filter panel, which
   showed as a white gap between the table and the panel on every list with
   filters. The panel already reads as separate -- its own background and the
   card edge -- so the gap only made it look detached. */
body:not(.popup) #changelist-filter {
  margin-left: 0;
  /* A rule instead of the gap. Removing the 30px left the panel and the table
     reading as one mass; a hairline separates them without spending space. */
  border-left: 1px solid var(--border-color);
}
/* And the table gets its own edge, so it is bounded whether the panel is open
   or shut. Placed on .results (the scrolling wrapper) rather than the table,
   which can be wider than its container. */
body:not(.popup) #changelist .results { border: 1px solid var(--border-color); }

/* Vertical tightening (Jordan, 2026-07-29): ~60px sat above the strip doing
   nothing -- Django's #content padding plus a breadcrumb 39px tall for one
   line of text. Trimmed, not removed. #content is app-wide, so this lifts
   every admin page, not only the lists. */
body:not(.popup):not(.login) #content { padding-top: var(--flc-sp-tight); }
/* THE PAGE GUTTER, on the language's scale -- Decision 23, 19 August. Django
   ships 40px of side padding on every page and 40 is not one of the five steps
   (4 / 8 / 12 / 14 / 20). 20 is, and the 40px it replaces was never measured
   against anything: it is Django's default, inherited rather than chosen.
   The lists gain the difference, which is what they wanted -- measured, the two
   changelists people use daily need 1146-1148px.
   Scoped to the widest tier on purpose: below 1025px Django's own
   responsive.css already drops to 20px and then to 15px, and overriding those
   would be widening a screen that has no room to give. Verified in the
   installed copy, not assumed. */
@media (min-width: 1025px) {
  body:not(.popup):not(.login) #content { padding-left: var(--flc-sp-block); padding-right: var(--flc-sp-block); }
}
body:not(.popup):not(.login) .breadcrumbs { padding-top: var(--flc-sp-hair); padding-bottom: var(--flc-sp-hair); }

.flc-listbar-spacer { flex: 1 1 auto; }
.flc-listbar .object-tools { margin-top: 0; padding: 0; float: none; display: flex; gap: var(--flc-sp-tight); }
.flc-listbar #toolbar { background: none; border: 0; padding: 0; margin: 0; }

/* El aviso del filtro en vivo (flc_livefilter.js): «mostrando X de Y en esta
   página · Enter para buscar en todo». Tinta apagada, no es un error ni un
   estado vacío — sólo informa cuánto quedó a la vista. Sin color propio. */
.flc-livefilter-hint {
  color: var(--body-quiet-color); font-size: 12px;
  margin-left: var(--flc-sp-tight); align-self: center; white-space: nowrap;
}

/* A hairline between the add buttons and Filtros. They sit side by side but
   are not the same KIND of control: the gold pair creates records, Filtros
   only changes what you are looking at. Being outlined rather than filled
   separates them by weight; this separates them by grouping, so Filtros stops
   reading as a third button in the same set. Rendered by flc_admin.js only
   when both groups are actually present. */
.flc-listbar-divider {
  flex: 0 0 auto; width: 1px; align-self: stretch;
  margin: var(--flc-sp-hair) var(--flc-sp-hair); background: var(--border-color);
}

/* One row, one shape. Django ships the search field and its Buscar button at
   4px while every other control in this app is a pill, and the Filtros toggle
   came out 3-4px taller than both -- three radii and two heights in a strip
   that is supposed to read as a single row of controls. Heights are equalised
   here rather than left to each control's own padding, because they are set
   by three different stylesheets that know nothing about each other.

   The search field is selected as `#toolbar #searchbar`, not `.flc-listbar
   #searchbar`: Django's changelists.css sets its height with TWO ids
   (`#toolbar #searchbar`, specificity 2-0-1), which beats one id plus one
   class no matter which stylesheet loads last. Matching its id count is what
   wins, not source order. */
.flc-listbar #toolbar #searchbar,
.flc-listbar #toolbar input[type="submit"],
.flc-listbar .flc-filters-toggle,
.flc-listbar .object-tools a {
  box-sizing: border-box;
  height: 28px;
  border-radius: 999px;
  display: inline-flex; align-items: center;
}
/* A floor, so the field can never squeeze down to a circle when the strip
   wraps on a narrow window. */
.flc-listbar #toolbar #searchbar { padding: 0 var(--flc-sp-field); min-width: 150px; }
.flc-listbar #toolbar input[type="submit"] { padding: 0 var(--flc-sp-field); }
.flc-listbar .flc-filters-toggle { padding: 0 var(--flc-sp-block); }

/* The action row is only useful once a row is ticked, so it hides until then.
   Both rules require .flc-actions-managed, which flc_admin.js adds only after
   wiring the show/hide up: no JS, no class, and Django's always-visible row
   stays. That matters because «Anular» is the only bulk action with no button
   on the record itself. */
#changelist-form.flc-actions-managed > div.actions { display: none; }
#changelist-form.flc-actions-managed.flc-has-selection > div.actions { display: block; }

#changelist .results { overflow-x: auto; }
#changelist .results::-webkit-scrollbar { height: 14px; }
#changelist .results::-webkit-scrollbar-thumb {
  background: var(--darkened-bg);     /* the neutral solid; #9bb4cf was a
                                          sixth blue nobody had decided */
  border-radius: 8px;
  border: 4px solid transparent;     /* transparent border + padding-box clip =
                                          a slim floating pill on any row color */
  background-clip: padding-box;
}
#changelist .results::-webkit-scrollbar-thumb:hover {
  background: #144b8b;                /* brand navy on hover */
  background-clip: padding-box;
}
#changelist .results::-webkit-scrollbar-track { background: transparent; }

/* ============================================================
   App shell (Plan 2): white topbar + arc + fixed navy sidebar.
   Everything here is scoped to body:not(.popup) so Django's picker
   windows -- which reuse this same base template -- stay bare.

   The sidebar is rendered from {% block header %} (see base_site.html)
   rather than {% block nav-sidebar %}, because Django's own admin/index.html
   and admin/app_index.html blank nav-sidebar out. That means the sidebar is
   no longer a flex sibling of #content inside #main -- it's fixed, pinned
   under the topbar+arc, and the content that follows it in the DOM
   (#main, and the breadcrumbs where present) is offset by its width instead.
   --flc-shell-top gives the sidebar's fixed top offset a single source of
   truth: it must equal the topbar's fixed height plus the arc's height.
   ============================================================ */
body:not(.popup) {
  /* MUST equal the topbar's height plus the arc's: the fixed sidebar hangs off
     it, so thickening the arc without moving this leaves the sidebar tucked
     under the arc. accounts/tests_contraste.py checks the sum, because this
     same requirement was written in a comment here and a comment cannot fail.
     Both moved together on 18 August: the arc went 5px → 8px (Decision 23). */
  --flc-shell-top: 74px; /* 66px topbar + 8px arc */
}
/* Django's own base.css pins #container to "height: 100%" (a *definite*
   height, not a floor) as part of a classic sticky-footer flex layout;
   its children only avoid visually clipping there because they're
   flex-shrink:0 and #container is overflow:visible. That's harmless for
   normal-flow content, but position:sticky's containing block is #container's
   own box (definite 100%-of-viewport height) -- NOT the taller area its
   overflowing children paint into -- so on any page taller than one
   viewport (i.e. almost every real changelist/change-form) a sticky
   descendant detaches the instant you scroll past that boundary. Swapping
   to min-height keeps the "at least fill the viewport" sticky-footer
   behaviour on short pages while letting the box legitimately grow with
   real content on long ones, which is what the sticky topbar below needs.
   (Confirmed via live measurement: with height:100%, a sticky child
   detached at ~1 viewport of scroll; with min-height:100% it stayed put
   through a simulated 2000px-tall page.) */
body:not(.popup) #container {
  height: auto;
  min-height: 100%;
}
/* .flc-shell-top wraps the topbar+arc as one sticky unit -- see the comment
   in base_site.html's header block for why they're not each independently
   sticky (two adjacent sticky siblings collapsed the second one's height in
   testing). */
body:not(.popup) .flc-shell-top {
  position: sticky;
  top: 0;
  z-index: 30;
}
body:not(.popup) .flc-topbar {
  height: 66px;
  box-sizing: border-box;
  background: #ffffff;
  border-bottom: 1px solid var(--border-color);
  /* The logo fills the bar's content box, so the vertical padding IS the
     logo's size limit: 66 - 2*8 = 50px of logo. If the height changes again,
     --flc-shell-top above must change with it -- the sidebar hangs off it. */
  padding: var(--flc-sp-tight) var(--flc-sp-block);
  display: flex;
  align-items: center;
  gap: var(--flc-sp-field);
}
/* Logo + wordmark are one link home. It becomes a single flex ITEM of the
   topbar, so it re-creates the 16px gap internally that the two elements used
   to get from the topbar's own gap -- without this they collide. The negative
   margin + padding widen the hit area to the full block without shifting the
   layout, and text-decoration is suppressed because this reads as a logo, not
   as a link. */
/* The collapse handle. Three bars drawn with borders rather than an icon font
   or an SVG: the sidebar has no icon set (a rail was considered and rejected),
   and one glyph is not worth introducing a dependency for. */
body:not(.popup) .flc-nav-toggle-btn {
  flex: 0 0 auto; width: 34px; height: 34px; padding: 0;
  background: transparent; border: 1px solid transparent; border-radius: 6px;
  cursor: pointer; display: flex; align-items: center; justify-content: center;
}
body:not(.popup) .flc-nav-toggle-btn:hover { background: var(--selected-row); }
body:not(.popup) .flc-nav-toggle-btn:focus-visible {
  outline: 2px solid var(--accent); outline-offset: 1px;
}
body:not(.popup) .flc-burger,
body:not(.popup) .flc-burger::before,
body:not(.popup) .flc-burger::after {
  display: block; width: 17px; height: 0; content: "";
  border-top: 2px solid var(--body-fg); border-radius: 2px;
}
body:not(.popup) .flc-burger { position: relative; }
body:not(.popup) .flc-burger::before { position: absolute; top: -6px; }
body:not(.popup) .flc-burger::after { position: absolute; top: 4px; }
body:not(.popup) .flc-topbar-home {
  display: flex; align-items: center; gap: var(--flc-sp-field);
  /* Kept small so the hover block stays inside the 66px bar: the logo is
     50px, and 50 + 2*6 = 62px. Grow this and it spills past the bar's edges. */
  margin: calc(var(--flc-sp-tight) * -1) calc(var(--flc-sp-card) * -1); padding: var(--flc-sp-tight) var(--flc-sp-card);
  border-radius: 6px; text-decoration: none;
}
body:not(.popup) .flc-topbar-home:hover { background: var(--selected-row); }
body:not(.popup) .flc-topbar-home:focus-visible {
  outline: 2px solid var(--accent); outline-offset: 1px;
}
/* Fills the bar's content box. The source PNG is 96x91, so this is still a
   downscale and stays crisp; going larger means raising the bar's height. */
body:not(.popup) .flc-topbar-logo { width: 50px; height: 50px; object-fit: contain; }
body:not(.popup) .flc-topbar-name {
  font-family: var(--font-family-serif);
  font-weight: 700; font-size: 17px; color: var(--body-fg);
  /* Optical, not geometric, centring. flex align-items:center lines up the
     BOXES, and the box centre is not the letterform centre. Re-measured on the
     rendered page when Decision 9 swapped Source Serif for Inter, because the
     old -1.8px was Source Serif's asymmetry (18 vs 6) and Inter's is its own:
     at bold 17px the ink runs 12 up and 3 down inside a 16/4 line box, which
     parks it 1.5px BELOW the logo's centre. Only the wordmark needs this --
     the breadcrumb and username come in under 0.7px, which is invisible. */
  transform: translateY(-1.5px);
}
/* TWO LOCATION INDICATORS, ON PURPOSE — Decision 23, 19 August. The topbar
   ends in the page's name and, three pixels below it, so does the breadcrumb.
   That repetition is deliberate and is written down here so it does not read
   as an oversight, the same way the arc's own colours are.
   They do different jobs, and measuring settled it: .flc-shell-top is STICKY
   and the breadcrumb is STATIC, so after 900px of scroll the topbar sits at
   y=0 and the breadcrumb is at y=-826, gone. On a forty-row grid the topbar is
   the only thing still saying where you are; the breadcrumb is a path you can
   climb, and a path is only useful at the top. Only the LAST segment repeats.
   Worth knowing if this is ever reopened: of the breadcrumb's two links,
   «Inicio» reaches Datos maestros, which is the real index, but «Aplicaciones»
   reaches Django's own app index -- a live page no designed path leads to. */
body:not(.popup) .flc-topbar-crumb {
  font-family: var(--font-family-serif);
  font-size: 15px; font-weight: 600; color: var(--body-quiet-color);
  margin-left: var(--flc-sp-block); padding-left: var(--flc-sp-block); border-left: 1px solid var(--border-color);
}
body:not(.popup) .flc-topbar-spacer { margin-left: auto; }
body:not(.popup) .flc-username { font-size: 13px; color: var(--body-quiet-color); }
body:not(.popup) .flc-avatar {
  width: 31px; height: 31px; border-radius: 50%;
  background: var(--selected-bg); border: 1px solid var(--border-color);
  display: flex; align-items: center; justify-content: center;
  font-weight: 700; color: #144b8b; font-size: 12px;
}
/* Ghost/outline button -- deliberately NOT a coloured pill, so it reads as a
   quiet utility action next to the brand mark rather than competing with it. */
body:not(.popup) .flc-logout { margin: 0; }
body:not(.popup) .flc-logout-btn {
  font-family: var(--font-family-primary); font-size: 12px; font-weight: 600;
  color: var(--body-quiet-color); background: transparent;
  border: 1px solid var(--border-color); border-radius: 999px;
  padding: var(--flc-sp-hair) var(--flc-sp-field); cursor: pointer; white-space: nowrap;
}
body:not(.popup) .flc-logout-btn:hover {
  color: #144b8b; border-color: #144b8b; background: var(--selected-row);
}
body:not(.popup) .flc-arc {
  height: 8px; border: 0; margin: 0;
  background: linear-gradient(90deg, #e01e19, #f6ab08 42%, #7fb529 70%, #0867a1);
}

/* Sidebar -- fixed under the topbar+arc; see the note above the shell block
   header for why it isn't laid out via #main's flex row anymore. */
body:not(.popup) .flc-sidebar {
  position: fixed;
  left: 0;
  top: var(--flc-shell-top);
  bottom: 0;
  width: var(--flc-sidebar-w);
  overflow-y: auto;
  background: #144b8b; padding: var(--flc-sp-card) 0;
  display: flex; flex-direction: column; gap: 0;
}
/* DECISION 18 -- THE NAVY BAR IS THE ONLY DARK SURFACE, and it gets THREE
   tints, not a ramp. The twenty-three are designed for light surfaces, so this
   one needs its own text scale, and measuring it is what settled it: of the six
   tints that were here, FOUR did not reach 4.5:1 on the navy. And they cannot
   be separated by lightening them -- every value that passes the floor lands
   between 4.55 and 4.60. On a navy bar you get a legible ramp or a wide ramp,
   never both.

     #ffffff  the open item                            8.72
     #b7cbe4  everything else that is live -- item,    5.26
              child and caption alike
     #6f8cb3 / #5d7aa1   «Próximamente» only

   A CHILD IS NOT A DIMMER PARENT. On navy, "dim enough to read as subordinate"
   lands below the contrast floor, so hierarchy comes from the rail, the indent
   and the size. The caption is separated by caps, size and letter-spacing for
   the same reason.

   The «Próximamente» pair stays under 4.5 ON PURPOSE: those items carry
   aria-disabled="true" and the contrast minimum does not apply to a disabled
   control. Stated so it does not read as an oversight. */
/* Collapsed. The class lives on <html>, not <body>, because the inline script
   that applies it runs in <head> before <body> exists -- see base_site.html.
   visibility:hidden is not decoration: transform alone leaves the links
   off-screen but still in the tab order, so a keyboard user would tab into a
   menu they cannot see. It is delayed by the transition duration so the slide
   is still visible on the way out. */
html.flc-nav-collapsed body:not(.popup) .flc-sidebar {
  transform: translateX(-100%);
  visibility: hidden;
}
body:not(.popup) .flc-sidebar {
  transform: translateX(0);
  visibility: visible;
  transition: transform .16s ease, visibility 0s linear 0s;
}
html.flc-nav-collapsed body:not(.popup) .flc-sidebar {
  transition: transform .16s ease, visibility 0s linear .16s;
}
html.flc-nav-collapsed body:not(.popup):not(.login) #main,
html.flc-nav-collapsed body:not(.popup):not(.login) .breadcrumbs {
  margin-left: 0;
}
body:not(.popup):not(.login) #main,
body:not(.popup):not(.login) .breadcrumbs { transition: margin-left .16s ease; }
body:not(.popup) .flc-nav-caption {
  font-size: 10px; letter-spacing: .1em; text-transform: uppercase;
  color: #b7cbe4; padding: var(--flc-sp-field) var(--flc-sp-block) var(--flc-sp-hair);
}
body:not(.popup) .flc-nav-item {
  display: block; width: 100%; text-align: left; box-sizing: border-box;
  font-family: var(--font-family-serif); font-size: 14px;
  padding: var(--flc-sp-tight) var(--flc-sp-block); color: #b7cbe4;
  border: 0; border-left: 3px solid transparent; background: none; cursor: pointer;
}
body:not(.popup) a.flc-nav-item:hover,
body:not(.popup) .flc-nav-toggle:hover { color: #fff; background: rgba(255,255,255,.06); }
body:not(.popup) .flc-nav-item.is-active {
  color: #fff; background: rgba(255,255,255,.12);
  border-left-color: var(--accent); font-weight: 600;
}
body:not(.popup) .flc-nav-soon { color: #6f8cb3; cursor: default; }
body:not(.popup) .flc-nav-soon em {
  display: block; font-style: normal; font-size: 10px;
  letter-spacing: .06em; text-transform: uppercase; color: #5d7aa1;
}
body:not(.popup) .flc-nav-toggle { display: flex; align-items: center; }
body:not(.popup) .flc-caret {
  margin-left: auto; width: 0; height: 0;
  border-left: 4px solid currentColor;
  border-top: 4px solid transparent; border-bottom: 4px solid transparent;
}
body:not(.popup) [data-flc-open] .flc-caret { transform: rotate(90deg); }
/* Collapsed by default; flc_shell.js and the server-set data-flc-open reveal it. */
body:not(.popup) .flc-nav-children {
  display: none;
  /* The rail down an open group: ONE of the three things carrying hierarchy,
     with the indent and the size, because colour cannot carry it here without
     falling below the floor. */
  margin-left: calc(3px + var(--flc-sp-block));   /* lands on the parent's text */
  border-left: 1px solid rgba(255, 255, 255, .20);
}
body:not(.popup) [data-flc-open] .flc-nav-children { display: block; }
body:not(.popup) .flc-nav-child {
  display: block; font-size: 12.5px; color: #b7cbe4;
  /* The indent is not a gap on the rhythm scale — with the rail and the
     size it is one of the three things carrying hierarchy (Decision 18),
     so it is sized against the parent's text, not snapped to a step. */
  padding: var(--flc-sp-hair) var(--flc-sp-block) var(--flc-sp-hair) 38px;
  border-left: 3px solid transparent;
}
body:not(.popup) .flc-nav-child:hover { color: #fff; background: rgba(255,255,255,.06); }
body:not(.popup) .flc-nav-child.is-active {
  color: #fff; background: rgba(255,255,255,.12);
  border-left-color: var(--accent); font-weight: 600;
}

/* The sidebar is fixed and out of flow, so offset the elements that follow
   it in the DOM by its width: Django's #main (wraps the page content on
   every page) and, where present -- changelists, change forms, and the
   app-index pages -- the breadcrumbs. (The admin home/dashboard blanks its
   own breadcrumbs block, so there's nothing to offset there.) */
/* :not(.login) is required here too: the login page's body class is "login",
   never "popup", so body:not(.popup) alone still matched it and Django
   renders <div class="main" id="main"> there as well -- offsetting the
   centred login card 210px off-centre to the right. */
body:not(.popup):not(.login) #main { margin-left: var(--flc-sidebar-w); }
body:not(.popup):not(.login) .breadcrumbs { margin-left: var(--flc-sidebar-w); }

/* ============================================================
   Datos maestros page (Plan 3). All rules are namespaced .flc-dm-*
   so nothing here can reach another admin screen.
   ============================================================ */
.flc-dm-head {
  display: flex; align-items: flex-end; justify-content: space-between;
  gap: var(--flc-sp-block); flex-wrap: wrap; margin: 0 0 var(--flc-sp-block);
}
.flc-dm-head h1 {
  font-family: var(--font-family-serif); margin: 0;
  font-size: 27px; font-weight: 700; color: #144b8b;
}
.flc-dm-lead {
  margin: var(--flc-sp-hair) 0 0; font-size: 13.5px;
  color: var(--body-quiet-color); max-width: 54ch;
}
.flc-dm-search { position: relative; flex: 0 0 320px; max-width: 320px; }
.flc-dm-search input {
  width: 100%; box-sizing: border-box; font-size: 14px; color: var(--body-fg);
  border: 1px solid var(--border-color); border-radius: 999px;
  /* The left padding is room for the icon (left:14px, 16px wide), not a gap. */
  padding: var(--flc-sp-card) var(--flc-sp-field) var(--flc-sp-card)
           calc(14px + 16px + var(--flc-sp-card));
  background: #fff;
}
.flc-dm-search input:focus { outline: 2px solid var(--secondary); border-color: var(--secondary); }
.flc-dm-search svg {
  position: absolute; left: 14px; top: 50%; transform: translateY(-50%);
  width: 16px; height: 16px; color: var(--body-quiet-color);
}

/* Four across; the fixed 210px sidebar means the content box is narrower than
   the viewport, so the breakpoints sit higher than a full-width grid's would. */
.flc-dm-grid {
  display: grid; grid-template-columns: repeat(4, 1fr);
  gap: var(--flc-sp-block); align-items: stretch;
}
@media (max-width: 1400px) { .flc-dm-grid { grid-template-columns: repeat(3, 1fr); } }
@media (max-width: 1100px) { .flc-dm-grid { grid-template-columns: repeat(2, 1fr); } }

.flc-dm-card {
  background: #fff; border: 1px solid var(--border-color);
  border-radius: 6px; overflow: hidden;
}
.flc-dm-card > h2 {
  font-family: var(--font-family-serif); margin: 0;
  background: #f2f6fb; color: #144b8b; font-size: 16px; font-weight: 700;
  padding: var(--flc-sp-card) var(--flc-sp-field); border-bottom: 1px solid var(--border-color);
}
.flc-dm-rows { padding: var(--flc-sp-tight) var(--flc-sp-tight) var(--flc-sp-card); }
.flc-dm-row { display: flex; align-items: center; gap: var(--flc-sp-tight); border-radius: 4px; }
.flc-dm-row:hover { background: var(--selected-row); }
.flc-dm-name {
  flex: 1; font-size: 14px; font-weight: 500; color: var(--link-fg);
  padding: var(--flc-sp-tight); display: flex; align-items: baseline; gap: var(--flc-sp-tight); border-radius: 4px;
}
.flc-dm-name:hover { text-decoration: underline; }
/* Not-yet-built module. Muted and non-interactive: it keeps .flc-dm-name's
   layout so it lines up with the real rows, but drops the link colour, the
   hover underline and the pointer, because there is nothing to click. */
.flc-dm-soon { color: var(--body-quiet-color); cursor: default; }
.flc-dm-soon:hover { text-decoration: none; }
.flc-dm-soon em {
  font-style: normal; font-size: 10px; letter-spacing: .06em;
  text-transform: uppercase; color: var(--body-quiet-color); opacity: .8;
}
.flc-dm-count {
  color: var(--body-quiet-color); font-size: 11.5px;
  font-variant-numeric: tabular-nums;
}
.flc-dm-add {
  flex: 0 0 auto; width: 27px; height: 27px; box-sizing: border-box;
  border-radius: 999px; border: 1px solid var(--border-color); background: #fff;
  color: #144b8b; font-size: 18px; line-height: 1; font-weight: 700;
  display: flex; align-items: center; justify-content: center; opacity: .55;
}
/* The «+» opens an add form: navy, not gold (Decision 10). */
.flc-dm-row:hover .flc-dm-add {
  opacity: 1; border-color: var(--button-bg);
  background: var(--button-bg); color: var(--button-fg);
}
.flc-dm-empty {
  display: none; color: var(--body-quiet-color);
  padding: var(--flc-sp-block); text-align: center;
}
/* Shown when the user has no cards at all (no role group), not toggled by
   flc_datos_maestros.js -- unlike .flc-dm-empty, which starts hidden and is
   only revealed by a search with zero matches. */
.flc-dm-no-cards {
  display: block; color: var(--body-quiet-color);
  padding: var(--flc-sp-block); text-align: center;
}

/* Avisos. Ancho completo con filete a la izquierda -- deliberadamente NO una
   píldora: es la forma, no el color, la que lo separa de los botones. El texto
   y el enlace usan los mismos tokens que el resto de la aplicación. */
.flc-alert {
  display: flex; align-items: center; gap: var(--flc-sp-card);
  background: var(--alert-bg);
  border-left: 4px solid var(--accent);
  border-radius: 0;
  padding: var(--flc-sp-card) var(--flc-sp-field); margin: 0;
  /* Flush to the table, separated by a hairline instead of a gap -- the strip
     above it closes the same way, so the banner sits between two matching
     rules rather than floating in a stray few pixels. */
  border-bottom: 1px solid var(--border-color);
  color: var(--body-fg); font-size: 14px;
}
.flc-alert-action { margin-left: auto; color: var(--link-fg); }

/* ── THE CHIP ROW ─────────────────────────────────────────── Decision 20
   The one filter used most on a screen, when it has five values or fewer;
   everything else stays in the slide-out panel. It lived in ordenes_lista.css
   while exactly one screen drew it. It is the language's now, because the
   moment a second screen wants it a per-screen copy is a second answer.

   A CHIP IS A CONTROL, NOT A MARK (Decision 17). It is pressed and the list
   changes, so it wears the navy that every other pressable thing wears — never
   a status colour. The stock screen used to call its vencido/agotado pills
   `.flc-chip` too, which is the collision this comment exists to prevent
   coming back: same name, opposite meanings, and the reader cannot tell which
   one a `.flc-chip` in a template is. */
.flc-barra-lista {
  display: flex; gap: var(--flc-sp-tight); align-items: center; flex-wrap: wrap;
  margin: 0 0 var(--flc-sp-tight);
}
.flc-barra-lista .rotulo { font-size: 11.5px; color: var(--body-quiet-color); }
.flc-chip {
  padding: var(--flc-sp-hair) var(--flc-sp-card);
  border-radius: var(--flc-r-pill); font-size: 12.5px; background: #fff;
  border: 1px solid var(--border-color); color: var(--body-fg);
  text-decoration: none; line-height: 1.3;
}
/* No underline: the shared a:hover rule is for LINKS, and a chip is a
   control. Decision 16 gives a link an underline precisely so it does not
   have to change colour; a chip already answers by filling in. */
.flc-chip:hover {
  border-color: var(--primary); color: var(--primary); text-decoration: none;
}
.flc-chip.activo {
  background: var(--primary); border-color: var(--primary);
  color: var(--primary-fg); font-weight: 700;
}
.flc-chip.activo:hover { color: var(--primary-fg); text-decoration: none; }
.flc-pista {
  font-size: 11.5px; color: var(--body-quiet-color);
  margin-left: var(--flc-sp-tight);
}

/* ── A SECOND-CHOICE DOOR IN THE TOOL ROW ──────────────────── Decision 6
   Django paints EVERY anchor in .object-tools as a filled pill, so a path that
   is deliberately secondary comes out looking exactly as important as the
   primary ones — which is how this row ended up with four solids the moment a
   fourth door was added back. Decision 6 says weight carries importance: one
   solid per area, everything else outlined.

   Outlined in the SAME navy, because colour says what happens and these all
   open something. Only the weight changes. Caught by rendering the row, not by
   reading the template — the class was there and did nothing. */
.object-tools a.flc-quieto,
.object-tools a.flc-quieto:link,
.object-tools a.flc-quieto:visited,
a.button.flc-quieto,
a.button.flc-quieto:link,
a.button.flc-quieto:visited {
  background: var(--card-bg);
  color: var(--button-bg);
  border: 1px solid var(--button-bg);
}
.object-tools a.flc-quieto:hover,
a.button.flc-quieto:hover {
  background: var(--selected-row);
  color: var(--button-bg);
}

/* ══════════════════════════════════════════════════════════════════════════
   EL PANEL DE CARGA CON PROGRESO — universal en toda puerta de subida.

   El parcial templates/admin/flc_carga_progreso.html lo dibuja; el JS
   accounts/static/admin/js/flc_carga_progreso.js lo maneja. Vive acá, en la
   hoja de marca que ya carga cada pantalla del admin, y no en una hoja por
   pantalla: es la casa más honesta y chica (el plan, tarea 1).

   Colores del vocabulario de pasos (Decisión 14): hecho=verde · acá=azul ·
   luego=apagado. La barra es azul —el color de «acá, trabajando». Espacios de
   la escala de cinco pasos (Decisión 7). Ni un color ni un espacio nuevo.
   ══════════════════════════════════════════════════════════════════════════ */
.flc-cargap {
  max-width: 560px;
  background: var(--card-bg);
  border: 1px solid var(--border-color);
  border-radius: var(--flc-r-card);
  overflow: hidden;
}
.flc-cargap[hidden] { display: none; }

.flc-cargap-titulo {
  margin: 0;
  background: var(--darkened-bg);   /* el crema que dice «acá se LEE» */
  font-size: 13px;
  padding: var(--flc-sp-tight) var(--flc-sp-field);
  font-weight: 700;
}

/* LA BARRA — una sola, grande, lo que uno mira. Mientras el navegador conoce
   los bytes de la subida el relleno es un porcentaje de verdad; en la lectura
   sigue moviéndose con el barrido para que la pantalla se vea viva, sin fingir
   una cuenta de páginas. */
.flc-cargap-barra {
  margin: var(--flc-sp-field) var(--flc-sp-field) var(--flc-sp-hair);
  height: 12px;
  border-radius: var(--flc-r-pill);
  background: var(--selected-bg);   /* #e9f0f8, el lavado azul */
  overflow: hidden;
  position: relative;
}
.flc-cargap-barra i {
  display: block;
  height: 100%;
  width: 0;                         /* el JS la mueve */
  background: var(--primary);       /* #144b8b, navy */
  border-radius: var(--flc-r-pill);
  position: relative;
  overflow: hidden;
  transition: width .2s linear;
}
.flc-cargap-barra i::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: var(--flc-r-pill);
  background: linear-gradient(90deg, transparent 0%,
              rgba(255, 255, 255, .35) 50%, transparent 100%);
  animation: flc-cargap-sweep 1.4s linear infinite;
}
@keyframes flc-cargap-sweep {
  from { transform: translateX(-100%); }
  to   { transform: translateX(100%); }
}
.flc-cargap-linea {
  margin: 0;
  padding: 0 var(--flc-sp-field) var(--flc-sp-hair);
  color: var(--body-quiet-color);
  font-size: 12.5px;
  font-weight: 700;
}

/* la cinta de pasos: hecho=verde · acá=azul · luego=apagado */
.flc-cargap-pasos { padding: var(--flc-sp-hair) 0; }
.flc-cargap-paso {
  display: flex;
  gap: var(--flc-sp-tight);
  padding: var(--flc-sp-tight) var(--flc-sp-field);
  align-items: flex-start;
}
.flc-cargap-punto {
  flex: 0 0 20px;
  height: 20px;
  border-radius: var(--flc-r-pill);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 11px;
  font-weight: 700;
}
.flc-cargap-paso.hecho .flc-cargap-punto { background: #eaf6e8; color: var(--flc-ink-green); }
.flc-cargap-paso.aca   .flc-cargap-punto { background: var(--selected-bg); color: var(--flc-status-blue); }
.flc-cargap-paso.luego .flc-cargap-punto { background: var(--body-bg); color: var(--flc-muted); }
.flc-cargap-que { flex: 1; min-width: 0; }
.flc-cargap-que b { display: block; font-size: 12.5px; }
.flc-cargap-paso.hecho .flc-cargap-que b { color: var(--flc-ink-green); }
.flc-cargap-paso.aca   .flc-cargap-que b { color: var(--flc-status-blue); }
.flc-cargap-paso.luego .flc-cargap-que b { color: var(--flc-muted); font-weight: 400; }
.flc-cargap-nota { color: var(--flc-muted); font-size: 11.5px; }

.flc-cargap-pie {
  margin: 0;
  padding: var(--flc-sp-tight) var(--flc-sp-field);
  border-top: 1px solid var(--hairline-color);
  color: var(--flc-muted);
  font-size: 12px;
  line-height: 1.55;
}
.flc-cargap-pie b { color: var(--body-quiet-color); }

/* la falla: si la subida no llega (red caída, 500, el lector apagado) el panel
   no deja una barra que miente — lo dice en palabras y devuelve el formulario.
   Rojo porque algo SALIÓ MAL, no apagado (que es «todavía no pasó»). */
.flc-cargap-falla {
  margin: 0;
  padding: var(--flc-sp-tight) var(--flc-sp-field);
  border-top: 1px solid var(--hairline-color);
  color: var(--error-fg);
  font-size: 12.5px;
  line-height: 1.5;
  font-weight: 700;
}
.flc-cargap-falla[hidden] { display: none; }

/* Achicar los iconos de acción de un autocompletar (agregar · editar · ver ·
   limpiar) EN TODO EL PROGRAMA (Jordan, 2026-09-03: «shrink them out throughout
   the whole program, some get too big»). No cambia el ESTILO —son los mismos
   iconos de Django—, sólo el tamaño. Django los dibuja como <img> dentro de
   `.related-widget-wrapper-link`; se bajan de su tamaño por defecto a 15px. */
.related-widget-wrapper-link img { width: 15px; height: 15px; }
