/* 03-forms.css. Entering a number: the crumb trail, link and button colours, focus rings,
   fieldsets, flash messages, the weekend count grid, and the single entry forms. */

/* THE CRUMB TRAIL above an entry screen's heading. Orientation, not
   navigation. The sidebar is where somebody GOES and it is already the loudest
   thing on the left of the page; this only says where they already are, so it
   is a step down from body, muted, and pressed close under the heading it
   belongs to rather than floating as a band of its own. Nothing above it: it is
   the first thing inside main and main already brings its own top padding, and
   a margin there would push the page's title down for no one's benefit.

   It wraps rather than overflows, because the last crumb is a metric label or a
   Mass name and those run long: "Offertory in LGL, cash and check" is wider
   than a 390px phone on its own. */
.crumbs {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.1rem 0.4rem;
  margin: 0 0 0.6rem;
  font-size: var(--step--1);
  color: var(--muted);
}
/* The page's own link colour, so a crumb behaves like every other link in the
   app and nobody has to learn a second one. */
.crumbs a { color: var(--emerald); }
/* The separator says nothing, which is why the markup hides it from a screen
   reader, so it is painted lighter than the words on either side of it.
   --field is the lightest value in the palette that is still a mark rather than
   a ghost: 3.26:1 on parchment, against the muted text's 5.59:1. */
.crumbs [aria-hidden="true"] { color: var(--field); }
/* The page you are already on is not a place you can go, so it must not look
   like one. Muted, the same weight as the trail around it, and deliberately not
   the link colour. */
.crumbs [aria-current="page"] { color: var(--muted); }

h1 { font-size: var(--step-2); margin: 0 0 0.25rem; color: var(--navy); }
h2 { font-size: var(--step-1); margin: 0 0 0.5rem; color: var(--navy); }
.lede { color: var(--muted); font-size: var(--step--1); margin: 0 0 1.5rem;
        line-height: 1.5; }
.help { background: #fff; border-left: 3px solid var(--gold); padding: 0.6rem 0.8rem; color: var(--muted); }
.muted { color: var(--muted); font-size: 0.87em; }

.card { background: #fff; border: 1px solid var(--line); border-radius: 6px; padding: 1rem; margin-bottom: 1rem; }
.total { font-size: var(--step-1); font-weight: 600; margin: 0.3rem 0; }
.ok { color: var(--ok); }
.warn { color: var(--warn); }
.warn-inline { color: var(--warn); font-size: 0.85em; }

table { border-collapse: collapse; width: 100%; margin: 0.5rem 0; }
th, td { text-align: left; padding: 0.45rem 0.5rem; border-bottom: 1px solid var(--line); vertical-align: top; }
th { font-size: var(--step--1); text-transform: uppercase; letter-spacing: 0.03em; color: var(--muted); }
tr.superseded td, tr.voided td { color: var(--muted); text-decoration: line-through; }
a { color: var(--emerald); }
a:hover { color: var(--navy); }

/* A LINK THAT CARRIES ITS OWN BACKGROUND MUST SET ITS OWN HOVER COLOUR.
   The rule above turns any link navy on hover, which is correct on parchment and
   invisible everywhere else. It hits the three .button links, including
   "Continue to Microsoft" on the sign-in page, which is the first control every
   person who has never signed in touches: navy label on an emerald button.
   Class beats type, so these win over a:hover without needing :not().

   The brand USED to need the same treatment in the opposite direction, white on
   the navy masthead. The masthead is gone as of 2026-08-21 and the brand sits on
   a white sidebar, so that rule became white on white: 1.00:1, caught by
   scripts/check_contrast.py on the first run after the change and not by any
   test. Its colour is carried by the two spans inside it now, which have their
   own, so it sets none of its own and inherits nothing harmful. */
.brand:hover .brand-org, .brand:focus-visible .brand-org { color: var(--emerald); }
.brand:hover .brand-app, .brand:focus-visible .brand-app { color: var(--emerald); }
a.button:hover, a.button:focus-visible { color: #fff; background: #003a22; }

input, select, textarea {
  font: inherit; padding: 0.4rem 0.5rem; border: 1px solid var(--field);
  border-radius: 4px; background: #fff; max-width: 100%;
}
fieldset { border-color: var(--field); }
input[type="number"], input[inputmode="numeric"], input[inputmode="decimal"] { width: 7rem; }

/* There was no focus style anywhere in this file, so every focus indicator was
   the browser default, which differs across the office desktop, the meeting
   laptop and a phone, and has almost nothing to sit against on a maroon button
   (ink on the accent is 1.48:1). :where() keeps specificity at zero so nothing
   above has to be reordered. */
:where(a, button, .button, input, select, textarea):focus-visible {
  outline: 3px solid var(--accent);
  outline-offset: 2px;
}
button:focus-visible, .button:focus-visible {
  outline-color: var(--ink);
  box-shadow: 0 0 0 2px #fff;
}
/* Which row you are on, working down five Masses by keyboard. */
table.entry tr:focus-within td, table.entry tr:focus-within th { background: #faf7ee; }

/* Touch only. A global 44px would add about 60px to the weekend grid and grow
   the inline correction form on the office desktop, where compactness is what
   lets the typist see the whole sheet at once. */
@media (pointer: coarse) {
  input, select, textarea, button, .button { min-height: 44px; }
}
label { display: block; margin-bottom: 0.9rem; }
label.check { display: flex; gap: 0.5rem; align-items: center; }
fieldset { border: 1px solid var(--line); border-radius: 4px; margin-bottom: 0.9rem; }

/* A fieldset whose ticks are not the thing deciding. The Access screen keeps an
   admin's boxes on screen and saved, because a role is not forever, but an
   admin holds every family by role and ten empty squares under a sentence about
   ticking read as a denial. Dimmed, and the row says so in words above. */
fieldset.inert { background: #fbfbf9; border-style: dashed; }
fieldset.inert .check { opacity: 0.6; }
.stack { max-width: 28rem; }

button, .button {
  font: inherit; display: inline-block; padding: 0.5rem 0.9rem;
  background: var(--emerald); color: #fff; border: 0; border-radius: 4px;
  cursor: pointer; text-decoration: none;
}
form.inline { display: flex; gap: 0.3rem; align-items: center; }
form.inline input[type="text"] { width: 9rem; }
.person { background: #fff; border: 1px solid var(--line); border-radius: 6px; padding: 1rem; margin-bottom: 1rem; }
.recorded { font-weight: 600; }

.flashes { list-style: none; padding: 0; margin: 0 0 1rem; }
.flash { padding: 0.6rem 0.8rem; border-radius: 4px; margin-bottom: 0.4rem; background: #fff; border-left: 4px solid var(--muted); }
.flash.ok { border-left-color: var(--ok); }
.flash.error { border-left-color: var(--danger); }
/* Saved, but worth a look. Distinct from error, which means not saved. */
.flash.note { border-left-color: var(--warn); }

.nav-weekends { display: flex; gap: 1rem; margin: 0 0 1rem; }
/* Four links in a single column used a seventh of the page and left the rest
   empty. Across, in as many columns as fit, same auto-fit rule as .cardgrid and
   the same min() guard so a phone gets one column rather than an overflow. */
.metric-list {
  list-style: none; padding: 0; display: grid; gap: 0.1rem 1.5rem;
  grid-template-columns: repeat(auto-fit, minmax(min(14rem, 100%), 1fr));
}
.metric-list li { padding: 0.3rem 0; }

footer { border-top: 1px solid var(--line); padding: 1rem; text-align: center; }
footer p { color: var(--muted); font-size: var(--step--1); margin: 0; }

/* The weekend count grid, shaped like the paper sheet. */
/* th.mass AS WELL AS td.mass, which is the whole of why this screen did not fit
   a phone. The row header is a <th scope="row" class="mass"> for the screen
   reader, so neither of these rules had ever matched it: the date span stayed
   inline and nowrap kept it on one line, making "Saturday 5:00 PM Vigil Sat 15
   Aug" a single 298px cell inside a 390px window. The rule was written to put
   the date on its own line and had simply never run. */
table.entry td.mass, table.entry th.mass { white-space: nowrap; }
table.entry td.mass span, table.entry th.mass span { display: block; }
table.entry tr.totals td, table.entry tr.totals th { border-top: 2px solid var(--navy); background: #fff; }
/* Matched to table.entry above it. The per-metric note on the weekend sheet
   sat at 40rem under a table running the full page width, so the box you type
   the explanation in was visibly half the width of the thing it explains. */
label.block { max-width: 46rem; }
label.block textarea { width: 100%; }

/* Single-entry forms: label above its field, every field the same shape. */
.stack label { display: block; margin-bottom: 1.1rem; font-weight: 600; }
.stack label input,
.stack label select,
.stack label textarea {
  display: block;
  margin-top: 0.3rem;
  font-weight: 400;
}
/* min-width is applied after max-width and wins, so 24rem overflowed a 375px
   phone sideways. That select is the confession session picker, the one screen
   the two priests ever touch. .stack is already capped at 28rem, so desktop is
   unchanged. */
.stack select { width: 100%; max-width: 100%; }
.stack textarea { width: 100%; }
/* EVERY FIELD FILLS ITS COLUMN. Eric, 2026-08-22: "yeah... for some reason, box
   go wide, text go half that... slop :( same here and here and too many other
   places to keep screenshotting."
   He is describing this: `.stack` is a 28rem column with block labels, so every
   label spanned 504px, while the global `input[inputmode="numeric"]` rule
   pinned the amount to 7rem and the date sat at 12rem. Four fields in one
   column at 126px, 216px, 504px and 504px, each under a label the full width.
   The select and the textarea were already 100%; now they all are, so the
   column has one edge instead of four. The width lives on the CONTAINER, which
   is the thing that knows how wide the form should be. */
.stack input, .stack select, .stack textarea { width: 100%; max-width: 100%; }

form.periodpick { margin-bottom: 1rem; }
form.periodpick label { display: inline-flex; gap: 0.5rem; align-items: center; margin: 0; }

/* Money and counts align on their digits. A jittering column is what hides a
   transposed digit from somebody checking their typing against paper. Works on
   the system stack with no font added. */
.recorded, .total, .tile-value, .barvalue,
table.entry td, table.entry th[scope="row"],
.entries td, .chart .barvalue { font-variant-numeric: tabular-nums; }

/* Cap the prose, not the container: these sentences are the whole instruction
   layer for four people who will have forgotten the interface. footer p is
   centred and would become a left-anchored block, so it is excluded. */
main > p, .card > p, .lede, .help, .muted { max-width: 62ch; }
footer p { max-width: none; }

/* An empty figure is a different shape, not a dimmer one. Dimness disappears
   across a meeting table, and a greyed number is still a number once somebody
   reads it aloud. */
.tile-empty {
  display: block; font-size: var(--step-0); font-weight: 400; line-height: 1.2;
  color: var(--muted); font-style: italic; padding: 0.35rem 0;
}
.no-total {
  display: block; font-size: var(--step--1); font-weight: 400; color: var(--warn);
}



/* Two things side by side inside one card, where stacking them would leave the
   card mostly empty. Generic on purpose: the instruction beside its form, a
   figure beside its caveats. Both halves wrap to stacked below about 46rem of
   card, where side by side squeezes both. */
.spread {
  display: flex; flex-wrap: wrap; align-items: flex-start; gap: 0.8rem 2.5rem;
}
.spread > * { flex: 1 1 20rem; min-width: 0; }
.spread > p { margin-top: 0; }
