/*
 * app.css -- Proiektuak.
 *
 * The visual language is NOT invented here. It is extracted from the five
 * canvas artboards (Phone 390, DesktopFull 1280, DesktopSplit 1280,
 * RateCardWeek, MonthSchedule) and named. Changing a colour means changing it
 * here, once.
 *
 * Two deliberate deviations from the artboards, both for contrast:
 *   --muted is #5A5950, not the artboards' #7A7970. #7A7970 on the paper
 *   ground is about 3.3:1, and the artboards use it at 10-12px, which fails
 *   WCAG AA for small text. The hue is kept; the lightness is not.
 *   Blue and rust each carry two meanings in the artboards (remote/link,
 *   in-office/error). Kept as-is for now so the mockups and the shell agree,
 *   and parked in OPEN-ITEMS.md -- it needs a design decision, not a CSS one.
 */

:root {
  /* ground and paper */
  --paper: #e9e9e4;
  --surface-2: #f1f1ec;
  /* The two grounds the grant artboards add: a darker band for a grand total
     and a very light one for an epigrafe header. */
  --surface-3: #e8e3d7;
  --epi-bg: #fbfaf6;
  --card: #ffffff;
  --ink: #141413;
  --hairline: #141413;
  --rule: #c7c6bc;
  --field-focus: #f4f4ef;
  --fill: #fff6bf; /* by hand is yellow: a value still to fill, or a warning card */

  /* the dark panel, for the one figure that dominates a card */
  --panel: #14142b;
  --panel-rule: #23233f;
  --panel-label: #8a8ac8;
  --panel-figure: #f2f1e8;
  --panel-dim: #b7b6e0;

  /* meaning */
  --remote: #2a4fd6;
  --office: #b4372b;
  --link: #2a4fd6;
  --alarm: #b4372b;
  --warn-ink: #8a5a00; /* a warning that is not an error: ochre text (Cierre's "debe", "de 2025", "sin leer") */
  --pdf-bg: #525659;   /* behind a PDF page, the viewer's own grey */

  /* The dark panel's purple, darkened for use ON WHITE. #8A8AC8 is right on
     #14142B and about 2.6:1 on paper; this keeps the hue and reads properly. */
  --accent-purple: #4e4e8a;

  /* people */
  --paul: #2f5233;
  --done: #2f5233; /* done and sent: Cierre's «✓ Enviado» line and Ticket o factura's result */
  --done-bg: #eef2ec;
  --juan: #c08a2e;

  /* Eraman's departments, from the "Antolaketa · Turnos" canvas (2026-10-07), darkened where the
     canvas failed: white 12px text on each is 5.2-6.6:1. The activity is always written on the
     shift too, so colour is never the only thing telling them apart. */
  --dep-local-commerce: #357a51;
  --dep-food-delivery: #a3561a;
  --dep-bizieskola: #2a4fd6;
  --dep-projects: #1f6f74;
  --dep-admin: #6a5aa8;

  /* text weights */
  --muted: #5a5950;
  --muted-2: #55534a;
  --faint: #a3a296;
  --body: #33322c;

  /* type */
  /* The faces index.html has been loading since the beginning. These used to
     say Helvetica and Courier New, so the fonts were fetched on every page and
     never drawn with -- which is why the built pages never quite matched the
     artboards however carefully the spacing was copied. */
  --mono: "IBM Plex Mono", "Courier New", ui-monospace, SFMono-Regular, monospace;
  --sans: "IBM Plex Sans", Helvetica, Arial, sans-serif;
  --serif: Georgia, "Times New Roman", serif;

  --gutter: 14px;
}

* { box-sizing: border-box; }

/* A control with no font of its own takes the page's, not the browser's Arial (Paul, 2026-11-05). */
button, input, select, textarea { font-family: inherit; }

html, body {
  margin: 0;
  padding: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--sans);
  -webkit-text-size-adjust: 100%;
}

a { color: var(--link); }

/* --- micro label: Courier, uppercase, tracked. The artboards' signature. --- */
.micro {
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted);
}

/* --- shell ---------------------------------------------------------------- */

/* Wordmark and the read-only note stack on a phone and sit side by side from
   the tablet width up. Side by side at 375 they collide, and the collision is
   the first thing you see on the device this is mostly opened on. */
.masthead {
  /* One line at every width: the person icon sits beside the name of the site (Paul, 2026-11-12). */
  display: flex;
  flex-direction: row;
  justify-content: space-between;
  align-items: center;
  gap: 8px;
  padding: 11px var(--gutter) 9px;
  border-bottom: 1px solid var(--hairline);
}
@media (min-width: 560px) {
  .masthead {
    flex-direction: row;
    justify-content: space-between;
    align-items: baseline;
    gap: 12px;
  }
}
.masthead .wordmark {
  font-family: var(--serif);
  font-size: 19px;
  font-weight: 700;
}
/* The header's right side: Ajustes as a cog, and the person's own things
   under their name (2026-10-19). */
.masthead .mast-tools {
  display: flex;
  align-items: center;
  gap: 14px;
  margin-left: auto;
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}
.mast-tools a.mt-cog {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  color: var(--ink);
  text-decoration: none;
  padding: 3px 6px;
  border: 1px solid transparent;
}
.mast-tools a.mt-cog:hover,
.mast-tools a.mt-cog[aria-current="page"] { border-color: var(--hairline); }
.mast-tools .mt-ico { font-size: 14px; line-height: 1; }
.mast-tools .mt-user { position: relative; }
.mast-tools .mt-who {
  font: inherit;
  letter-spacing: inherit;
  text-transform: inherit;
  background: none;
  border: 1px solid transparent;
  padding: 3px 6px;
  cursor: pointer;
  color: var(--ink);
}
.mast-tools .mt-who:hover { border-color: var(--hairline); }
.mast-tools .mt-who { display: inline-flex; align-items: center; padding: 2px; line-height: 0; }
.mast-tools .mt-who svg { width: 22px; height: 22px; }
.mast-tools .mt-menu .mt-name { padding: 8px 12px; font-weight: 600; color: var(--ink); border-bottom: 1px solid var(--rule); }
.mast-tools .mt-menu {
  display: none;
  position: absolute;
  right: 0;
  top: calc(100% + 4px);
  z-index: 50;
  min-width: 180px;
  background: var(--card);
  border: 1px solid var(--hairline);
  flex-direction: column;
}
.mast-tools.is-open .mt-menu { display: flex; }
.mast-tools .mt-menu a {
  padding: 9px 12px;
  color: var(--ink);
  text-decoration: none;
  text-transform: none;
  letter-spacing: 0;
  font-family: var(--sans, inherit);
  font-size: 13px;
}
.mast-tools .mt-menu a + a { border-top: 1px solid var(--rule); }
.mast-tools .mt-menu a:hover { background: var(--field-focus); }
.mast-tools .mt-dep { display: flex; flex-direction: column; gap: 4px; padding: 9px 12px; border-top: 1px solid var(--rule);
  text-transform: none; letter-spacing: 0; font-family: var(--sans, inherit); font-size: 13px; color: var(--ink); }
.mast-tools .mt-sel { font: inherit; padding: 4px 6px; border: 1px solid var(--hairline); background: var(--card); color: var(--ink); }

nav.tabs {
  display: flex;
  gap: 0;
  overflow-x: auto;
  border-bottom: 1px solid var(--hairline);
  background: var(--surface-2);
  scrollbar-width: none;
}
nav.tabs::-webkit-scrollbar { display: none; }

nav.tabs a {
  flex: 0 0 auto;
  padding: 11px 13px;
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--muted-2);
  text-decoration: none;
  border-right: 1px solid var(--rule);
  min-height: 44px;
  display: flex;
  align-items: center;
}
nav.tabs a[aria-current="page"] {
  background: var(--ink);
  color: var(--panel-figure);
}
nav.tabs a:hover:not([aria-current="page"]) { background: var(--card); }
/* Section icons (style C, solid; app.js SECTION_ICONS). They take the tab's own colour. */
.tab-ico { width: 14px; height: 14px; flex: none; display: block; }
nav.tabs a .tab-ico { margin-right: 7px; }
.mast-tools a.mt-cog .tab-ico { width: 13px; height: 13px; }
nav.subs a .tab-ico { width: 13px; height: 13px; margin-right: 6px; }

/* Full width, every page. This was capped at 1280px and centred, so a wide
   screen put the content in a column with empty space either side while
   /planning -- a `full` route -- ran edge to edge. A small side gutter stays,
   because a card flush against the window frame reads as broken rather than
   as full width; `full` routes still get zero, since they draw their own
   borders. */
main {
  padding: 12px 18px 28px;
  max-width: none;
  margin: 0;
}

/* --- card ----------------------------------------------------------------- */

.card {
  background: var(--card);
  border: 1px solid var(--hairline);
  margin-bottom: 16px;
}
.card > .card-head {
  padding: 10px 12px;
  border-bottom: 1px solid var(--hairline);
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 10px;
  flex-wrap: wrap;
}
.card > .card-body { padding: 12px; }

/* --- blocked: an empty page that says why is a useful page ---------------- */

.blocked {
  border: 1px solid var(--rule);
  border-left: 3px solid var(--alarm);
  background: var(--surface-2);
  padding: 11px 13px;
  margin-bottom: 16px;
}
.blocked .why {
  font-size: 13.5px;
  line-height: 1.55;
  color: var(--body);
  margin: 5px 0 0;
  max-width: 62ch;
}

/* --- provenance and state, the two shared components ---------------------- */
/*
 * Rule 2 of the brief. Plan, actual and distribution are three different
 * numbers and must never be averaged into one, so a figure cannot be rendered
 * without saying which it is. Both components exist from the first commit even
 * though most pages show nothing yet -- adding them later means auditing every
 * figure already on screen.
 */

.figure {
  display: inline-flex;
  flex-direction: column;
  gap: 1px;
  vertical-align: top;
}
.figure .amount {
  font-family: var(--mono);
  font-size: 15px;
  white-space: nowrap;
}
.figure .kind {
  font-family: var(--mono);
  font-size: 9.5px;
  letter-spacing: 0.07em;
  text-transform: uppercase;
}
.figure.is-plan .kind { color: var(--remote); }
.figure.is-actual .kind { color: var(--ink); }
.figure.is-distribution .kind { color: var(--juan); }
.figure.is-none .amount { color: var(--faint); }
.figure.is-none .kind { color: var(--faint); }

/* The state badge sits ON the figure, not in a footnote. Small, but present on
   every single number: a figure that looks final and is not is worse than one
   that admits it. */
.figure .state { align-self: flex-start; margin-top: 2px; font-size: 8.5px; padding: 1px 4px; }

/* Three figures side by side, with a visible boundary and no total. */
.figures {
  display: flex;
  flex-wrap: wrap;
  gap: 0;
  border: 1px solid var(--rule);
  background: var(--card);
}
.figures > .figure {
  flex: 1 1 33%;
  min-width: 108px;
  padding: 9px 11px;
  border-right: 1px solid var(--rule);
}
.figures > .figure:last-child { border-right: none; }

.state {
  display: inline-block;
  font-family: var(--mono);
  font-size: 9.5px;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  padding: 2px 6px;
  border: 1px solid currentColor;
  white-space: nowrap;
}
.state.is-provisional { color: var(--office); }
.state.is-final { color: var(--muted-2); }
.state.is-unknown { color: var(--faint); }

/* --- tables --------------------------------------------------------------- */

.grid { width: 100%; border-collapse: collapse; font-size: 13px; }
.grid th, .grid td {
  border: 1px solid var(--rule);
  padding: 7px 9px;
  text-align: left;
  vertical-align: top;
}
.grid th {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--muted);
  font-weight: 700;
  background: var(--surface-2);
}
.grid td.num { font-family: var(--mono); text-align: right; white-space: nowrap; }
.grid td.num.is-long { white-space: normal; word-break: break-all; text-align: left; max-width: 60ch; font-size: 11.5px; }
.grid .code { font-family: var(--mono); font-weight: 700; }
/* A description that still needs writing has to look unlike one that is
   written, or the placeholder reads as content. */
.grid .desc.warn { color: var(--alarm); font-style: normal; }
.grid .desc {
  font-style: italic;
  color: var(--muted-2);
  font-size: 12.5px;
  line-height: 1.5;
  max-width: 46ch;
}

.share { font-family: var(--mono); font-size: 12px; white-space: nowrap; }
.share .paul { color: var(--paul); font-weight: 700; }
.share .juan { color: var(--juan); font-weight: 700; }

.tag {
  font-family: var(--mono);
  font-size: 9.5px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--muted);
  border: 1px solid var(--rule);
  padding: 1px 5px;
}

.scroller { overflow-x: auto; -webkit-overflow-scrolling: touch; }

.err {
  font-family: var(--mono);
  font-size: 12.5px;
  line-height: 1.5;
  color: var(--alarm);
  border: 1px solid var(--alarm);
  padding: 10px 12px;
  background: var(--card);
}

/* --- a full-viewport route ------------------------------------------------
 * The app locks to the window and one pane scrolls inside it. The whole chain
 * needs `min-height: 0`: a flex item will not shrink below its content by
 * default, so without it .split grows past the viewport and the PAGE scrolls
 * however much overflow you set further down. That is the entire trick.
 */
html.is-full, html.is-full body { height: 100%; overflow: hidden; }
html.is-full body { display: flex; flex-direction: column; }
html.is-full .masthead,
html.is-full nav.tabs { flex: 0 0 auto; }
html.is-full main {
  flex: 1 1 auto;
  min-height: 0;
  /* min-width too, and for the same reason as min-height: a flex item's
     automatic minimum size is its CONTENT on BOTH axes. Without this, main
     grew to 1103px inside a 1024px body and the right pane hung off the edge
     of the window. overflow:hidden then hid the evidence rather than fixing
     it. */
  min-width: 0;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  padding: 0;
  /* max-width: 100%, not none. min-width:0 was not enough on its own: as the
     widest item in body's flex column, main was still sizing itself to its own
     content and hanging 79px off the right of a 1024px window, with
     overflow:hidden quietly hiding the evidence. Measured, not guessed. */
  max-width: 100%;
}
html.is-full main > div { flex: 1 1 auto; min-height: 0; min-width: 0; display: flex; flex-direction: column; }

/* --- desktop, matching the 1280 artboards --------------------------------- */

@media (min-width: 900px) {
  :root { --gutter: 40px; }
  .masthead { padding: 16px var(--gutter) 13px; }
  .masthead .wordmark { font-size: 22px; }
  nav.tabs a { padding: 12px 17px; font-size: 11.5px; }
  main { padding: 12px 20px 30px; }
  .grid { font-size: 13.5px; }
}

/* --- /projects/new: the creation form ------------------------------------
 * Built from the schema, so the number of fields is not known here. A grid
 * that reflows is the only layout that survives a column being added.
 */
.np { display: flex; flex-direction: column; gap: 14px; min-width: 0; }
.np-head { display: flex; align-items: baseline; gap: 14px; flex-wrap: wrap;
  border-bottom: 1px solid var(--hairline); padding-bottom: 10px; }
.np-kicker { font-size: 10px; letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--muted-2); }
.np-from { font-size: 13px; }
.np-status { margin-left: auto; color: var(--muted-2); }
.np-status.bad { color: #a8452f; }

.np-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
  gap: 12px 16px; }
.np-field { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.np-field.wide { grid-column: 1 / -1; }
.np-label { display: flex; align-items: baseline; gap: 8px; }
.np-label .mono { font-size: 10px; letter-spacing: 0.05em; color: var(--body); }
/* Which figures the proposal answered and which are yours. Said on the field,
   because a form that looks uniformly filled hides the half you still owe. */
.np-src { font-size: 9px; color: #a8452f; }
.np-src.on { color: #2d6b5c; }
.np-in { border: 1px solid var(--hairline); background: var(--panel-figure, #fff);
  padding: 6px 8px; font: inherit; font-size: 13px; width: 100%;
  box-sizing: border-box; min-width: 0; }
.np-in[type="checkbox"] { width: auto; }
.np-note { min-height: 92px; resize: vertical; font-size: 12px; line-height: 1.5; }

.np-tog { align-self: flex-start; }
.np-more { border-top: 1px solid var(--hairline); padding-top: 12px; }
.np-actions { display: flex; align-items: center; gap: 16px; }
.np-create { border: 1px solid var(--ink); background: var(--ink);
  color: var(--card); padding: 9px 20px; font: inherit;
  font-size: 13px; font-weight: 500; cursor: pointer; }
/* One main button, two sizes (Paul, 2026-11-05): big on a page, compact inside a window or panel. */
.fl-wiz .np-create, .fl-veil .np-create, .ui-veil .np-create, .cm-veil .np-create, .sm-veil .np-create, .pl-veil .np-create,
.cd-overlay .np-create, .gr-overlay .np-create, .sv-mod .np-create, .cz-pv .np-create, .tn-panel .np-create,
.cz-right .np-create, .drw-body .np-create { padding: 6px 12px; }
.np-create:hover { opacity: 0.85; }
.np-create[disabled] { opacity: 0.5; cursor: default; }

/* A button that reads as a link. pages.css has ix-linkbtn for the artboard
   pages; this is the same idea in the house style, for app.css's own pages. */
.linkbtn { border: none; background: none; padding: 0; font: inherit;
  font-size: 12px; color: var(--muted-2); cursor: pointer;
  text-decoration: underline; text-underline-offset: 2px; }
.linkbtn:hover { color: var(--ink); }
/* The form labels use it too, so it cannot live only in months.css. */
.mono { font-family: var(--mono); }

/* --- the subsection bar ---------------------------------------------------
 * The second row of the nav. Quieter than the first on purpose: it is a
 * qualifier on the section above it, not a competing set of destinations.
 * Hidden outright for a section with no subsections rather than left empty,
 * because an empty bar reads as something that failed to load.
 */
nav.subs {
  display: flex;
  align-items: stretch;
  background: var(--card);
  border-bottom: 1px solid var(--rule);
  padding-left: 18px;
  overflow-x: auto;
  scrollbar-width: none;
}
nav.subs[hidden], nav.tabs[hidden] { display: none; }
nav.subs::-webkit-scrollbar { display: none; }
nav.subs a {
  flex: 0 0 auto;
  padding: 10px 15px;
  font-size: 13px;
  color: var(--muted-2);
  text-decoration: none;
  white-space: nowrap;
  display: flex;
  align-items: center;
}
nav.subs a[aria-current="page"] {
  color: var(--ink);
  font-weight: 700;
  box-shadow: inset 0 -2px 0 0 var(--ink);
}
nav.subs a:hover:not([aria-current="page"]) { color: var(--ink); }

html.is-full nav.subs { flex: 0 0 auto; }

@media (min-width: 900px) {
  nav.subs { padding-left: 20px; }
}

/* ==========================================================================
 * Projects: cards, and one project's page.
 *
 * Same language as the departments dashboard, because they answer the same
 * shape of question -- a strip of totals, then a card per thing, then the
 * thing's own page. What differs is the subject: a department runs in
 * periods, a project runs to a contract.
 * ========================================================================== */
.pj { display: flex; flex-direction: column; gap: 14px; min-width: 0; }
.pj-strip-card { margin-bottom: 0; }
.pj-strip {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  gap: 12px;
}
.pj-kpi { border: 1px solid var(--hairline); padding: 10px 12px; min-width: 0; }
.pj-kpi-label {
  font-size: 10px; letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--muted-2);
}
.pj-kpi-value {
  font-family: var(--serif); font-size: 23px; font-weight: 700;
  margin: 4px 0 2px; line-height: 1.1;
}
.pj-kpi-note { font-size: 11px; color: var(--muted-2); }

.pj-cards {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  gap: 14px;
}
.pj-card { cursor: pointer; margin-bottom: 0; display: flex; flex-direction: column; gap: 7px; }
.pj-card:hover { background: var(--card); }
.pj-card-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.pj-code {
  font-size: 9px; letter-spacing: 0.06em; padding: 1px 5px;
  border: 1px solid #2A4FD6; color: #2A4FD6; white-space: nowrap;
}
.pj-health {
  font-size: 9px; letter-spacing: 0.04em; padding: 1px 6px;
  border: 1px solid; white-space: nowrap;
}
/* Grist's own health strings drive these; anything unrecognised is neutral
   rather than guessed at, because the formula can change without this file. */
.pj-h-bad  { color: #a8452f; border-color: #a8452f; }
.pj-h-done { color: #6b6558; border-color: #6b6558; }
.pj-h-idle { color: #A3A296; border-color: #A3A296; }
.pj-h-ok   { color: #2d6b5c; border-color: #2d6b5c; }
.pj-h-none { color: #A3A296; border-color: var(--hairline); }

.pj-name { font-family: var(--serif); font-size: 17px; font-weight: 700; line-height: 1.2; }
.pj-sub { font-size: 11.5px; color: var(--muted-2); }

/* Received against contracted. The one thing you want from across the room. */
.pj-bar { height: 5px; background: var(--hairline); margin-top: 2px; }
.pj-bar-fill { height: 100%; }
.pj-bar-note { font-size: 9px; color: var(--muted-2); }

.pj-figs { display: grid; grid-template-columns: 1fr 1fr; gap: 3px 12px; margin-top: 2px; }
.pj-fig { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; }
.pj-fig-l { font-size: 10.5px; color: var(--muted-2); }
.pj-fig-v { font-size: 12.5px; font-variant-numeric: tabular-nums; }

.pj-warn {
  font-size: 11px; line-height: 1.5; color: #a8452f;
  border-left: 2px solid #a8452f; padding-left: 8px; margin: 2px 0 0;
}

/* --- one project ---------------------------------------------------------- */
.pj-d { display: flex; flex-direction: column; gap: 14px; min-width: 0; }
.pj-d-top { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.pj-d-name { font-family: var(--serif); font-size: 22px; font-weight: 700; }

/* The check the page leads with: claimed against cash plus internal hours. */
.pj-rec { margin-bottom: 0; border-left: 3px solid #2d6b5c; }
.pj-rec.bad { border-left-color: #a8452f; }
.pj-rec-head { display: flex; align-items: baseline; gap: 12px; margin-bottom: 8px; }
.pj-rec-sum { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; }
.pj-rec-n { font-size: 15px; font-variant-numeric: tabular-nums; }
.pj-rec-n.strong { font-weight: 700; }
.pj-rec-op { font-size: 10.5px; color: var(--muted-2); }

/* --- budget against actual, and the justification pieces ------------------ */
.pb { min-width: 640px; }
.pb-row {
  display: grid; grid-template-columns: 2.4fr 1fr 1fr 1fr; gap: 8px;
  padding: 4px 6px; border-bottom: 1px solid #eeebe3; align-items: baseline;
}
.pb-row.pe { grid-template-columns: 74px 2.4fr 1fr 1fr 100px; }
.pb-head {
  border-bottom: 1px solid #c0cac5; font-size: 10px; letter-spacing: 0.06em;
  text-transform: uppercase; color: var(--muted-2);
}
.pb-c { font-size: 12px; min-width: 0; }
.pb-c.num { text-align: right; font-variant-numeric: tabular-nums; }
.pb-c.neg { color: #a8452f; }
.pb-h { background: #faf8f2; font-weight: 700; }
.pb-l .pb-n { padding-left: 16px; color: var(--body); }
.pb-l.sub .pb-n { font-style: italic; }
.pb-tot { border-top: 1px solid #c0cac5; font-weight: 700; background: #f4f1ea; }
.pb-tag {
  font-family: var(--mono); font-size: 8.5px; font-style: normal;
  letter-spacing: 0.04em; margin-left: 6px; padding: 0 4px; border: 1px solid;
  color: var(--muted-2);
}
.pb-tag.ok { color: #2d6b5c; border-color: #2d6b5c; }
.pb-tag.no { color: #a8452f; border-color: #a8452f; }
.pb-note {
  font-size: 10.5px; line-height: 1.5; color: var(--muted-2);
  padding: 2px 6px 6px 22px; border-bottom: 1px solid #eeebe3; max-width: 92ch;
}

/* A horizontal scroller for a table wider than its card. It lives in app.css,
   not in a per-tenant stylesheet, because app.js uses it on the project pages
   and those are served to both co-ops -- it was in cash.css, which only Eraman
   loads, and then a regex cleanup of that file removed it altogether. Three
   uses, defined nowhere. */
.cf-scroll { overflow-x: auto; max-width: 100%; scrollbar-width: thin; }

/* ==========================================================================
   Design mode -- only ever present with ?design in the URL
   ==========================================================================
   Chrome for rearranging the real page in place. In app.css rather than a file
   of its own because it is small, and because a stylesheet that loads only
   sometimes is a stylesheet that is sometimes missing.

   The first version gave four fixed elements a drag handle, which is the same
   mistake in a new costume: deciding in advance what is worth moving. Nothing
   here decides that. Whatever is under the cursor is a candidate. */

/* What the cursor is over, and what it is called. */
.dz-hover {
  position: absolute; z-index: 8990; pointer-events: none;
  outline: 1px solid rgba(42, 79, 214, .75);
  background: rgba(42, 79, 214, .06);
}
.dz-tag {
  position: absolute; z-index: 8991; pointer-events: none;
  background: #2A4FD6; color: #fff; padding: 1px 6px; white-space: nowrap;
  font-family: var(--mono); font-size: 9.5px; letter-spacing: .03em;
}

/* What is picked up. Dashed, so it reads as held rather than merely hovered. */
.dz-sel-on {
  outline: 2px dashed #B4372B !important;
  outline-offset: 1px;
  cursor: grab;
}
.dz-drag { opacity: .4; }

/* Where it will land. A line, not a box: it goes BETWEEN two things. */
.dz-insert {
  position: absolute; z-index: 8992; pointer-events: none;
  height: 3px; background: #B4372B;
}

/* Removed: hidden and named in the report, not deleted. The output is a
   statement of what should change, so a mis-click costs a reload not a deploy. */
.dz-gone { display: none !important; }

.dz-gutter {
  position: absolute; z-index: 8993; width: 11px; margin-left: -5px;
  cursor: col-resize;
  background: linear-gradient(90deg, transparent 4px, #2A4FD6 4px, #2A4FD6 7px, transparent 7px);
  opacity: .45;
}
.dz-gutter:hover { opacity: 1; }

.dz-panel {
  position: fixed; right: 12px; bottom: 12px; z-index: 9000;
  width: 350px; max-height: 66vh; overflow: auto;
  background: #fff; border: 1px solid #141413; padding: 10px 12px;
  box-shadow: 0 6px 22px rgba(20, 20, 19, .22);
  font-family: var(--sans); font-size: 12px; color: #141413;
}
.dz-h { display: flex; justify-content: space-between; align-items: center; }
.dz-x { border: none; background: none; font-size: 18px; cursor: pointer; line-height: 1; }
.dz-p { color: var(--muted); margin: 5px 0 8px; font-size: 11.5px; line-height: 1.5; }
.dz-sel {
  border: 1px solid var(--rule); background: var(--surface-2);
  padding: 6px 8px; margin-bottom: 8px; font-size: 12px;
}
.dz-path { font-family: var(--mono); font-size: 10px; color: var(--muted); }
.dz-kill {
  border: none; background: #B4372B; color: #fff; font: inherit; font-size: 12px;
  line-height: 1; cursor: pointer; padding: 1px 6px; float: right;
}
.dz-out {
  font-family: var(--mono); font-size: 10.5px; line-height: 1.55;
  white-space: pre-wrap; margin: 0; color: var(--body);
  background: var(--surface-2); padding: 8px; border: 1px solid var(--rule);
}
.dz-act { display: flex; gap: 8px; margin-top: 8px; }
.dz-act button {
  font: inherit; font-size: 11px; padding: 4px 10px; cursor: pointer;
  background: #141413; color: #fff; border: 1px solid #141413;
}
.dz-act button:last-child { background: #fff; color: #141413; }
.dz-said { font-family: var(--mono); font-size: 10.5px; color: var(--paul); }

/* The breadcrumb. Clicking lands on the innermost element under the cursor,
   which is almost never what you meant to grab -- click the Caja hoy card and
   you get the words "Caja hoy". Walking up is how every inspector fixes it. */
.dz-path { display: block; margin-top: 3px; line-height: 1.7; }
.dz-path a {
  font-family: var(--mono); font-size: 10px; color: var(--link);
  text-decoration: none; border-bottom: 1px dotted currentColor;
}
.dz-path a.here { color: var(--alarm); font-weight: 700; border-bottom-style: solid; }
.dz-sep { color: var(--faint); }
.dz-dim { font-family: var(--mono); font-size: 9.5px; color: var(--muted); }
.dz-keys { display: block; margin-top: 4px; }

/* --- the login ------------------------------------------------------------
 *
 * One card on the page's own paper, in the page's own type. A login screen
 * that looks like a different product than the thing behind it is the oldest
 * phishing tell there is, so this deliberately looks like the rest.
 */
/* Panel B (Paul, 2026-10-02): the app's own navy panel with the co-op's logo,
 * name, one line and address on the left; the form on the page's paper on the
 * right. Same colours and type as every page behind it. On a phone the panel
 * folds to the top. The masthead and nav are hidden while it shows
 * (body.lg-page) so the page is the login and nothing else. */
body.lg-page .masthead, body.lg-page .tabs, body.lg-page .subs { display: none; }
body.lg-page main#view { padding: 0; max-width: none; }
.lg-wrap {
  display: grid; grid-template-columns: minmax(300px, 40%) 1fr;
  min-height: 100vh; font-family: var(--sans);
}
.lg-panel {
  background: var(--panel, #14142b); color: var(--panel-figure, #f2f1e8);
  padding: 7vh 4vw; display: flex; flex-direction: column;
  justify-content: space-between; gap: 32px;
}
.lg-logo { width: 190px; max-width: 70%; line-height: 0; }
.lg-logo svg, .lg-logo img { width: 100%; height: auto; display: block; }
.lg-org, .lg-host, .lg-forgot, .lg-lab {
  font-family: var(--mono); text-transform: uppercase; letter-spacing: .06em;
  font-size: 12px;
}
.lg-org { color: var(--panel-label, #8a8ac8); margin-top: 36px; }
.lg-name { font-size: 40px; font-weight: 600; line-height: 1.1; margin-top: 4px; }
.lg-blurb { color: var(--panel-dim, #b7b6e0); font-size: 17px; line-height: 1.5; max-width: 22em; }
.lg-host { color: var(--panel-label, #8a8ac8); }
.lg-side { background: var(--epi-bg, #fbfaf6); display: flex; align-items: center; justify-content: center; padding: 6vh 24px; }
.lg-form { display: flex; flex-direction: column; gap: 16px; width: 100%; max-width: 380px; color: var(--ink, #141413); }
.lg-h { margin: 0 0 8px; font-size: 26px; font-weight: 600; line-height: 1.2; }
.lg-f { display: flex; flex-direction: column; gap: 6px; }
.lg-lab { color: var(--muted, #5a5950); }
.lg-pw { position: relative; }
.lg-in {
  font: inherit; font-size: 16px; padding: 11px 12px;
  border: 1.5px solid var(--ink, #141413); background: #fff; color: inherit;
  border-radius: 0; min-width: 0; width: 100%; box-sizing: border-box;
}
.lg-pw .lg-in { padding-right: 64px; }
.lg-eye {
  position: absolute; right: 8px; top: 50%; transform: translateY(-50%);
  font-family: var(--mono); font-size: 11px; text-transform: uppercase; letter-spacing: .06em;
  background: none; border: 0; color: var(--muted, #5a5950); cursor: pointer; padding: 6px;
}
.lg-in:focus { outline: 2px solid var(--panel-label, #8a8ac8); outline-offset: 1px; }
.lg-go {
  width: 100%; height: 48px; border: 0; border-radius: 0; cursor: pointer;
  background: var(--ink, #141413); color: var(--panel-figure, #f2f1e8); font: inherit; font-size: 17px;
}
.lg-go:disabled { opacity: .6; cursor: default; }
.lg-forgot {
  align-self: flex-start; color: var(--panel-label, #8a8ac8);
  text-decoration: underline; text-underline-offset: 4px; background: none; border: 0; padding: 0; cursor: pointer;
}
.lg-note { margin: 0; font-family: var(--mono); font-size: 12px; color: var(--panel-label, #8a8ac8); }
.lg-msg { margin: 0; min-height: 1.2em; font-size: 14px; }
.lg-msg.bad { color: var(--alarm, #B4372B); }
.lg-p { margin: 0; font-size: 15px; line-height: 1.5; color: var(--body, #33322c); }
@media (max-width: 720px) {
  .lg-wrap { grid-template-columns: 1fr; grid-template-rows: auto 1fr; }
  .lg-panel { padding: 32px 24px 26px; gap: 0; }
  .lg-logo { width: 150px; }
  .lg-org { margin-top: 22px; }
  .lg-name { font-size: 32px; }
  .lg-panel .lg-blurb, .lg-panel .lg-host { display: none; }
  .lg-side { align-items: flex-start; padding: 32px 24px; }
  .lg-foothost { display: block !important; color: var(--faint, #a3a296); margin-top: 40px; }
}
.lg-foothost { display: none; }

/* --- who can get in -------------------------------------------------------
 *
 * Five columns, because the two halves of identity -- what you may do and
 * whether you can get in -- have to be readable on one line. A row with
 * something missing is marked, since "role but no password" is the state
 * people report as a broken site.
 */
.us { display: flex; flex-direction: column; gap: 12px; }
.us-h { margin: 0; font-family: var(--serif, Georgia, serif); font-weight: 400; }
.us-lede, .us-note, .us-orphan { margin: 0; max-width: 62ch; }
.us-orphan { color: var(--alarm, #B4372B); }
.us-key { display: flex; flex-wrap: wrap; gap: 4px 18px; }
.us-keyrow { display: flex; align-items: baseline; gap: 7px; }
.us-role {
  font-family: var(--mono, monospace); font-size: 10px; letter-spacing: 0.06em;
  text-transform: uppercase;
}
.us-msg { margin: 0; min-height: 1.2em; }
.us-msg.bad { color: var(--alarm, #B4372B); }

.us-table { display: flex; flex-direction: column; border-top: 1px solid var(--line, #141413); }
.us-row {
  /* Every row is its own grid, so no column may size to its content: an `auto`
     last column (the action links, absent on rows without a username) gave each
     row different column widths and nothing lined up with the head (2026-10-06). */
  display: grid;
  grid-template-columns: minmax(200px, 1.5fr) minmax(130px, 1fr) minmax(120px, 0.8fr) minmax(160px, 1fr) 290px;
  gap: 12px; align-items: center;
  padding: 8px 0; border-bottom: 1px solid var(--thin, #EEEBE3);
}
.us-head { font-family: var(--mono, monospace); font-size: 10px;
  letter-spacing: 0.06em; text-transform: uppercase; color: var(--muted-2); }
.us-head span { white-space: nowrap; }
.us-name { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.us-why { color: var(--alarm, #B4372B); }
.us-snag { background: rgba(180, 55, 43, 0.04); }
.us-in, .us-sel {
  font: inherit; font-size: 13px; padding: 4px 6px;
  border: 1px solid var(--thin, #EEEBE3); background: #fff; color: inherit;
  border-radius: 0; min-width: 0; width: 100%; box-sizing: border-box;
}
.us-in:focus, .us-sel:focus { outline: 2px solid var(--remote, #2A4FD6); outline-offset: 1px; }
.us-key-col { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.us-acts { display: flex; gap: 8px; justify-content: flex-end; white-space: nowrap; }
.us-link { max-width: 520px; }
.us-url { font-family: var(--mono, monospace); font-size: 12px; }
/* users section, 2026-10-02: invite, edit, passwords, e-mail, permissions */
.us-top { display: flex; justify-content: space-between; align-items: flex-start; gap: 16px; flex-wrap: wrap; }
.us-edit { font-size: 11px; }
.us-mail { color: var(--muted, #5a5950); overflow: hidden; text-overflow: ellipsis; }
.us-acts { flex-wrap: wrap; row-gap: 4px; }
.us-dim { opacity: .5; }
.us-bad { color: var(--alarm, #B4372B); }
.us-perms { margin-top: 28px; display: flex; flex-direction: column; gap: 10px; }
.us-h2 { margin: 0; font-family: var(--serif, Georgia, serif); font-weight: 400; font-size: 20px; }
.us-pwrap { overflow-x: auto; }
.us-pgrid { display: grid; gap: 6px 8px; align-items: center; min-width: 900px; }
.us-ph { font-family: var(--mono, monospace); text-transform: uppercase; letter-spacing: .06em; color: var(--muted, #5a5950); }
.us-prole { font-family: var(--mono, monospace); font-size: 13px; }
.us-pfixed { color: var(--faint, #a3a296); }
.us-psel[data-lv='none'] { color: var(--alarm, #B4372B); }
.us-psel[data-lv='read'] { color: var(--accent-purple, #4e4e8a); }
.us-pact { display: flex; justify-content: flex-end; }
.us-dlg { max-width: 440px; display: flex; flex-direction: column; gap: 12px; }
.us-f .us-in, .us-f .us-sel { width: 100%; box-sizing: border-box; }
.us-chk { display: flex; align-items: center; gap: 6px; font-size: 14px; }
.lg-forgotbox { display: flex; flex-direction: column; gap: 8px; }
.lg-forgotgo { align-self: flex-start; }

@media (max-width: 900px) {
  .us-row { grid-template-columns: 1fr 1fr; gap: 6px 10px; }
  .us-head { display: none; }
  .us-acts { justify-content: flex-start; }
}

/* Money > facturas recibidas (invoice reader review), 2026-10-06 */
.inv-row { cursor: pointer; }
.inv-row.open td { background: rgba(0,0,0,0.05); }
.inv-st { font-size: 12px; padding: 1px 8px; border-radius: 10px; background: #eee; white-space: nowrap; }
.inv-needs_review { background: #fde7c4; }
.inv-approved, .inv-paid { background: #d6f0dd; }
.inv-rejected, .inv-duplicate { background: #eee; color: #777; }
.inv-detail { display: grid; grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr); gap: 20px; margin-top: 18px; }
.inv-doc { width: 100%; height: 78vh; border: 1px solid #ddd; background: #fff; }
.inv-form { display: grid; grid-template-columns: 1fr 1fr; gap: 8px 14px; margin: 10px 0; }
.inv-field { display: flex; flex-direction: column; gap: 2px; }
.inv-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin-top: 10px; }
@media (max-width: 900px) { .inv-detail { grid-template-columns: 1fr; } .inv-doc { height: 60vh; } }

/* Inicio: the other homes a person may see, one click away (2026-10-19). */
.homes-menu { display: flex; align-items: stretch; flex: 0 0 auto; }
.homes-btn { background: none; border: 0; padding: 10px 15px; font: inherit; font-size: 13px;
  color: var(--muted-2); cursor: pointer; white-space: nowrap; }
.homes-btn:hover { color: var(--ink); }
.homes-list { position: fixed; z-index: 50; display: flex; flex-direction: column;
  min-width: 190px; background: var(--card, #fff); border: 1px solid #141413; padding: 4px 0; }
.homes-list[hidden] { display: none; }
.homes-list a { padding: 6px 12px; white-space: nowrap; }

/* edit2: an empty page, drawn rather than reported. */
.empty-box { display: flex; flex-direction: column; align-items: center; gap: 10px; padding: 36px 16px; color: var(--muted); text-align: center; }
.empty-art { width: 260px; max-width: 70%; height: auto; color: var(--ink); opacity: .75; }
.empty-msg { margin: 0; font-size: 14px; max-width: 46ch; }

/* Hilarri: the stone of an idea, proposal or project (hilarri.js). In the Proyectos list it is only
   the mark; on the record's page it sits before the name and opens a white box saying what it is. */
.hl-mark { display: block; flex: none; }
/* Before the record's name; centred, so the name and its tags keep their shared baseline. */
.fl-rhead-l > .hl-wrap { align-self: center; margin-right: -6px; }
.hl-wrap { position: relative; display: inline-flex; flex: none; cursor: help; color: var(--ink); }
.hl-wrap:focus-visible { outline: 2px solid var(--ink); outline-offset: 3px; }
.hl-tip {
  display: none; position: absolute; left: 0; top: calc(100% + 8px); z-index: 60;
  width: 320px; max-width: calc(100vw - 32px); flex-direction: column; gap: 7px;
  background: var(--card); border: 1px solid var(--hairline); padding: 12px 14px;
  font: 400 13px/1.45 var(--serif, Georgia, serif); color: var(--ink); white-space: normal; cursor: auto;
}
/* A bridge over the gap, so the box does not close on the way to its link. */
.hl-tip::before { content: ''; position: absolute; left: 0; right: 0; top: -9px; height: 9px; }
.hl-wrap:hover .hl-tip, .hl-wrap:focus-within .hl-tip, .hl-wrap.is-open .hl-tip { display: flex; }
.hl-tip b { font: 400 11px var(--mono); letter-spacing: 0.06em; text-transform: uppercase; }
.hl-tip a { color: var(--ink); text-decoration: underline; align-self: flex-start; }

/* --- ui.alert / ui.confirm / ui.ask: the app's own pop-up (app.js, Paul 2026-11-03) ---
   In place of the browser's boxes. The card of every other dialog (white, 1px hairline, no
   radius), a Courier kicker, the text, then Cancelar as a link and the answer as the black
   button; rust when it deletes or cannot be undone. Over conciliación's dark panel it wears
   the panel's tokens. Above Cierre's window (z 70). */
.ui-veil { position: fixed; inset: 0; z-index: 90; background: rgba(20, 20, 19, 0.38);
  display: flex; align-items: center; justify-content: center; padding: 16px; }
.ui-box { background: var(--card); color: var(--ink); border: 1px solid var(--hairline);
  width: min(420px, 100%); max-height: 90vh; overflow-y: auto;
  padding: 16px 18px; display: flex; flex-direction: column; gap: 12px; }
.ui-k.bad { color: var(--alarm); }
.ui-t { margin: 0; font-size: 14px; line-height: 1.45; white-space: pre-line; }
.ui-in { font: inherit; font-size: 14px; padding: 7px 9px; border: 1px solid var(--rule);
  background: var(--card); color: var(--ink); }
.ui-in:focus { outline: none; border-color: var(--hairline); }
.ui-act { display: flex; align-items: center; justify-content: flex-end; gap: 16px; margin-top: 2px; }
.ui-ok { border: 1px solid var(--ink); background: var(--ink); color: var(--panel-figure);
  padding: 8px 18px; font: inherit; font-size: 13px; cursor: pointer; }
.ui-ok:hover { opacity: 0.85; }
.ui-ok.ui-danger { background: var(--alarm); border-color: var(--alarm); color: #fff; }
.ui-ok:focus-visible, .ui-no:focus-visible { outline: 2px solid var(--link); outline-offset: 2px; }
.ui-dark .ui-box { background: var(--panel); color: var(--panel-figure); border-color: var(--panel-label); }
.ui-dark .ui-k { color: var(--panel-label); }
.ui-dark .ui-k.bad { color: #e08a7f; }
.ui-dark .ui-no { color: var(--panel-dim); }
.ui-dark .ui-no:hover { color: var(--panel-figure); }
.ui-dark .ui-in { background: transparent; color: var(--panel-figure); border-color: var(--panel-label); }
.ui-dark .ui-in:focus { border-color: var(--panel-figure); }
.ui-dark .ui-ok { background: var(--panel-figure); border-color: var(--panel-figure); color: var(--panel); }
.ui-dark .ui-ok.ui-danger { background: var(--alarm); border-color: var(--alarm); color: #fff; }

/* Drawers (app.js openDrawer): a page over the page, from the right, over most of the screen. */
[data-drawer] { cursor: pointer; }
[data-drawer]:hover { border-color: var(--ink); }
.drw-mask { position: fixed; inset: 0; background: rgba(20, 20, 19, .35); opacity: 0; transition: opacity .2s; z-index: 900; }
.drw { position: fixed; top: 0; right: 0; bottom: 0; width: min(80vw, 1400px); background: var(--paper);
  border-left: 1px solid var(--ink); box-shadow: -12px 0 32px rgba(20, 20, 19, .18); display: flex; flex-direction: column;
  transform: translateX(100%); transition: transform .22s ease-out; z-index: 901; }
.drw-mask.is-in { opacity: 1; }
/* A panel that only asks one thing at a time (panels.js `narrow`). */
.drw.is-narrow { width: min(520px, 100%); }
/* One PDF alone (panels.js `pdf`): 40 % of the window, the page at the drawer's width. */
.drw.is-pdf { width: 40vw; }
.drw.is-pdf .drw-body { display: flex; flex-direction: column; padding: 12px 16px 0; overflow: hidden; }
.drw.is-pdf .drw-title { font-size: 20px; }
.drw-pdf { flex: 1; width: 100%; border: 0; }
/* 40 % of the screen (2026-11-08): one thing to read or answer; the whole width on a phone */
.drw.is-40 { width: max(40vw, 440px); max-width: 100%; }
@media (max-width: 900px) { .drw.is-40 { width: 100%; } }
.drw.is-in { transform: none; }
/* A second panel beside the open drawer (openBeside in app.js): the drawer moves left by the panel's width. */
.drw.is-shifted { right: max(40vw, 440px); transition: transform .22s ease-out, right .22s ease-out; }
.drw.is-narrow.is-shifted { right: min(520px, 100%); }
.drw.drw-beside { z-index: 902; }
.drw.drw-narrow { width: 40vw; }
.drw-head { display: flex; align-items: center; justify-content: flex-end; gap: 14px; padding: 8px 12px;
  border-bottom: 1px solid var(--rule); background: var(--card); }
.drw-full { font: 12px var(--mono); letter-spacing: .04em; color: var(--ink); }
.drw-x { border: 1px solid var(--ink); background: var(--card); width: 30px; height: 30px; cursor: pointer; font-size: 14px; }
.drw-frame { flex: 1; width: 100%; border: 0; background: var(--paper); }
html.has-drawer body { overflow: hidden; }
html.is-embed .masthead, html.is-embed #tabs, html.is-embed #subs { display: none !important; }
/* Whatever spills out of a page inside a drawer scrolls (Paul, 2026-11-09: "i need to be able to scroll here.
   make this a function across all drawers"). A page that fits and scrolls its own panels (conciliar) is unchanged. */
html.is-embed.is-full main { overflow-y: auto; }
/* On a phone every drawer rises from the bottom, like Inicio's sheets (Paul, 2026-11-12: "make all drawers for a worker
   come in from below"), the whole width and most of the height, whatever its size on a computer. */
@media (max-width: 900px) {
  .drw, .drw.is-narrow, .drw.is-pdf, .drw.is-40 { top: auto; left: 0; right: 0; width: 100vw; height: 92vh; height: 92dvh; max-width: none;
    border-left: 0; border-top: 1px solid var(--ink); box-shadow: 0 -12px 32px rgba(20, 20, 19, .18); transform: translateY(100%); }
  .drw.is-in { transform: none; }
  .drw.is-shifted { right: 0; }
}

/* the waiting animation (app.js bici()): three stacked layers, ratio 170:92 */
.bici { display: flex; align-items: center; gap: 14px; color: var(--muted); font-size: 13px; }
.bici-pic { position: relative; flex: none; aspect-ratio: 170 / 92; }
.bici-pic img { position: absolute; inset: 0; width: 100%; height: 100%; }
.bici.is-pequeno { display: inline-flex; gap: 8px; }
.bici.is-pequeno .bici-pic { width: 34px; }
.bici.is-mediano { padding: 10px 0; }
.bici.is-mediano .bici-pic { width: 92px; }
.bici.is-grande { flex-direction: column; justify-content: center; padding: 36px 0; width: 100%; box-sizing: border-box; grid-column: 1 / -1; }
.bici.is-grande .bici-pic { width: 187px; }
/* a whole page waiting (structure.js loading()): the large bike in the middle of the page */
.bici-page { min-height: 55vh; display: flex; align-items: center; justify-content: center; }

/* Facturas recibidas › Proveedor: the supplier search (2026-11-03) */
.inv-field { position: relative; }
.sup-list { position: absolute; left: 0; right: 0; top: 100%; z-index: 20; background: var(--card); border: 1px solid var(--ink); max-height: 260px; overflow-y: auto; }
.sup-opt { display: flex; justify-content: space-between; gap: 10px; width: 100%; padding: 6px 8px; background: none; border: 0; border-top: 1px solid var(--rule); font: inherit; text-align: left; cursor: pointer; }
.sup-opt:hover { background: var(--paper); }
.sup-new { display: block; color: #8B5A00; min-height: 0; }

/* A date field never runs past its box (Paul, 2026-11-12, «Nuevo turno» on an iPhone; the same as captura on 2026-11-08):
   an iPhone draws it wider than the box unless told not to. Every page's date fields. */
input[type="date"] { box-sizing: border-box; max-width: 100%; min-width: 0; }
@media (max-width: 899px) {
  input[type="date"] { -webkit-appearance: none; appearance: none; text-align: left; }
  input[type="date"]::-webkit-date-and-time-value { text-align: left; }
}

/* A PDF on a phone (app.js pdfBox): its pages as images the width of the screen, scrolling inside their box. */
.pdf-pages { display: flex; flex-direction: column; gap: 8px; overflow-y: auto; min-height: 0; flex: 1; width: 100%; max-width: 100%; }
.pdf-page { display: block; width: 100%; height: auto; border: 1px solid var(--rule); background: var(--card); }
.pdf-open { align-self: flex-start; }

/* The dice in the header (app.js diceButton, Paul 2026-11-12): to the right of the person icon; it rolls, then a tip opens. */
.mast-tools .mt-dice { display: inline-flex; align-items: center; justify-content: center; padding: 2px; line-height: 0; border: 1px solid transparent;
  background: none; color: var(--ink); cursor: pointer; margin-left: 6px; }
.mast-tools .mt-dice:hover { border-color: var(--hairline); }
.mast-tools .mt-dice svg { width: 22px; height: 22px; }
.mt-dice.is-roll svg { animation: tip-roll .7s cubic-bezier(.3, .1, .3, 1); }
@keyframes tip-roll { from { transform: rotate(0deg) scale(1); } 50% { transform: rotate(400deg) scale(1.25); } to { transform: rotate(720deg) scale(1); } }
@media (prefers-reduced-motion: reduce) { .mt-dice.is-roll svg { animation: none; } }
.tip-body { display: flex; flex-direction: column; gap: 16px; font-size: 15px; line-height: 1.5; }
.tip-body p { margin: 0; }
.tip-again { align-self: stretch; min-height: 46px; border: 1px solid var(--ink); background: var(--ink); color: var(--card); font: inherit;
  font-family: var(--mono); font-size: 12px; text-transform: uppercase; letter-spacing: .06em; cursor: pointer; }
/* The header stays one line on a phone with the dice beside the person icon: the site's name shrinks a little and never wraps. */
@media (max-width: 899px) {
  .masthead .wordmark { white-space: nowrap; font-size: clamp(14px, 4.1vw, 19px); min-width: 0; overflow: hidden; text-overflow: ellipsis; }
  .masthead .mast-tools { flex: none; }
}
.tip-k { font-family: var(--mono); font-size: 11px; text-transform: uppercase; letter-spacing: .08em; color: var(--muted); margin-bottom: -10px; }

/* Dinero › resumen (Paul, 2026-11-12): three cards; late in red, not yet due quiet, charges in progress plain. */
.rs-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 12px; align-items: start; }
/* Paul, 2026-11-12: the two lists side by side, Caja y rentabilidad flat beneath them, Ojo the whole height on the right. */
.rs-grid.is-four { grid-template-areas: "a b c" "d d c"; }
.rs-grid .rs-a { grid-area: a; } .rs-grid .rs-b { grid-area: b; } .rs-grid .rs-d { grid-area: d; }
.rs-grid .rs-c { grid-area: c; align-self: stretch; }
/* Arrows as in Cierre's hours (Paul, 2026-11-12): ↗ up in blue, ↘ down in ochre, the change beside it. */
.rs-arrow { font-size: 17px; line-height: 1; text-align: center; }
.rs-grid .is-up { color: var(--remote); }
.rs-grid .is-down { color: var(--warn-ink); }
.rs-trend { display: flex; gap: 6px; align-items: baseline; font-size: 13px; margin-top: 2px; white-space: nowrap; }
.rs-caja .st-table th, .rs-caja .st-table td { white-space: nowrap; }
.rs-trend .rs-when { color: var(--muted); }
.rs-caja { display: grid; grid-template-columns: minmax(0, 0.8fr) minmax(0, 1.2fr); gap: 16px; align-items: start; }
/* A name stays on one line; what does not fit ends in … (Paul, 2026-11-12), the whole name on hover. */
.st-table td.rs-n { max-width: 0; width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rs-table td { white-space: nowrap; }
.rs-grid .st-charge-t { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
.rs-grid .st-sec { padding-top: 10px; padding-bottom: 10px; }
.rs-grid .rs-kpis .st-kpi { padding: 6px 10px; }
.rs-grid .rs-kpis .st-kpi-v { font-size: 18px; }
.rs-grid .rs-table td { padding-top: 3px; padding-bottom: 3px; }
@media (max-width: 1500px) { .rs-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } .rs-grid.is-four { grid-template-areas: "a b" "d d" "c c"; } }
.rs-table .rs-sub { color: var(--muted); font-size: 13px; white-space: nowrap; }
.st-table td.rs-n { cursor: pointer; }
.st-table td.rs-n.is-whole { max-width: none; width: auto; overflow: visible; }
.rs-caja .rs-kpis { flex-wrap: nowrap; }
.rs-caja .rs-kpis .st-kpi { min-width: 0; }
.rs-grid td.rs-n:hover, .rs-title:hover, .rs-morelink:hover { text-decoration: underline; }
.rs-title, .rs-morelink { color: inherit; text-decoration: none; }
.rs-grid .rs-go { cursor: pointer; }
.rs-grid .rs-go:hover { border-color: var(--ink); }
.rs-table .rs-group td { font-weight: 700; padding-top: 12px; }
.rs-table .is-vencida .num, .rs-table .is-vencida td:first-child { color: var(--alarm); }
.rs-table .is-antigua .num, .rs-table .is-antigua td:first-child { color: var(--alarm); font-weight: 700; }
.rs-table .is-porvencer td { color: var(--muted); }
.rs-table .rs-more td, .rs-morelink { color: var(--muted); }
.st-table .rs-total td { font-weight: 700; border-top: 1px solid var(--ink); }
@media (max-width: 900px) { .rs-grid { grid-template-columns: 1fr; } .rs-grid.is-four { grid-template-areas: "a" "b" "c" "d"; } .rs-caja { grid-template-columns: 1fr; } }

/* Dinero › cobros (Paul, 2026-11-12): who owes on the left, the chosen client's invoices on the right. */
.cb-split { display: grid; grid-template-columns: minmax(280px, 380px) minmax(0, 1fr); gap: 16px; align-items: start; }
.cb-tools { display: flex; gap: 8px; align-items: center; margin: 8px 0; }
.cb-table .st-row { cursor: pointer; }
.cb-table .is-on td { font-weight: 700; }
.cb-name { color: inherit; }
@media (max-width: 900px) { .cb-split { grid-template-columns: 1fr; } }
/* Resumen keeps its shape whatever the data (Paul, 2026-11-12): on a wide screen the grid fills the window, the two
   lists share the top row's height and Caja y rentabilidad sits at the bottom. */
@media (min-width: 1501px) {
  .rs-grid.is-four { min-height: calc(100vh - 170px); grid-template-rows: 1fr auto; }
  .rs-grid.is-four .rs-a, .rs-grid.is-four .rs-b { align-self: stretch; }
}
.rs-caja .rs-kpis .st-kpi:first-child { flex: 1.7 1 0; }
.rs-caja .rs-kpis .st-kpi { flex: 1 1 0; }
