/* Finish Line Adjusters — claims portal.
   One stylesheet, no build step, no CDN.

   ------------------------------------------------------------------
   BRAND
   ------------------------------------------------------------------
   #3f63c8 is the Finish Line Adjusters blue, taken from
   finishlineadjusters.com. It is the primary throughout: the header,
   buttons, links, tabs and focus rings.

   It was chosen for us, but it happens to be usable: 5.5:1 against
   white, which clears WCAG AA for normal text in both directions —
   blue text on white and white text on blue. The darker step is 7.3:1.
   Neither is a coincidence worth relying on if the brand color ever
   changes: re-check it, because a brand color that fails contrast has
   to be paired with a darker text-only variant rather than used as-is.

   ------------------------------------------------------------------
   THE STAGING BANNER IS DELIBERATELY NOT BRAND-COLORED
   ------------------------------------------------------------------
   config.php's own comment says the environment is shown "so nobody
   edits a live claim thinking they are on staging". Now that the
   header is brand blue, an amber banner is not merely different — it
   is the one thing on the page that is not the brand, plus diagonal
   hazard stripes. It cannot be mistaken for chrome.
   ------------------------------------------------------------------ */

/* ==================================================================
   SURFACE TOKENS — 2026-09-16
   ==================================================================
   ⚠ NOTHING IS PURE WHITE OR PURE BLACK. This is read all day by
   people who do not get to look away from it, and #fff against #000 is
   the highest-contrast pair a screen can make — which is exactly the
   problem over eight hours. Every surface is a step off white and every
   ink a step off black.

   Four surfaces, not two, because a panel on a page needs to sit on
   something and an inset (a table head, a disabled field, a code block)
   needs to sit INSIDE something:

       --ground   the page behind everything
       --surface  a panel, a card, a row
       --sunk     an inset within a panel
       --line / --line-soft   a real division, and a division that is
                              only there so the eye can group

   Three inks, so that "less important" is a step down rather than a
   different hue: --ink, --ink-soft, --ink-faint.

   ⚠ THE ACCENT AND THE SEMANTIC COLOURS ARE SEPARATE AND MUST STAY
   SEPARATE. --accent is "this is the thing to press / where you are".
   ok / warn / danger are "this is how it went". The moment a success
   message borrows the accent, or a primary button borrows green, the
   page stops being able to say either one.

   These are TOKENS SO THE DASHBOARD AND ADMIN SCREENS CAN FOLLOW. The
   claim screen is the first to use them; nothing else has moved yet,
   and the old brand variables below are kept pointing at them so the
   rest of the application does not change colour in the same commit.
   ================================================================== */

/* ==================================================================
   THE PALETTE — ONE SET, LIGHT ONLY (2026-09-16)
   ==================================================================
   ⚠ DARK MODE IS GONE, AND ITS REMOVAL IS THE FIX RATHER THAN A
   SIMPLIFICATION.

   There were two palettes and a component only ever took one of them
   per property. That is where the unreadable pills came from: a pale
   pink ground from the light set under light ink from the dark set,
   on a screen nobody testing in daylight ever saw. A second palette is
   a second thing to keep in step, forever, and this is an internal
   tool on office monitors.

   So: no prefers-color-scheme, no data-theme, no dark token set.

   ⚠ AND `color-scheme: light` IS DECLARED, which is the half that is
   easy to forget. Without it a browser set to dark still renders the
   FORM CONTROLS and SCROLLBARS dark — a dark select and a dark
   scrollbar on a white page — because those are drawn by the browser
   and not by this stylesheet. The declaration is what makes the page
   hold its own appearance whatever the machine is set to.

   ------------------------------------------------------------------
   THE SKY TINT DOES THE SEPARATING
   ------------------------------------------------------------------
   Panel headers and table header rows take --sky with --sky-line
   beneath them. That blue band is what tells one box from the next,
   which is why the borders around them can stay faint: separation by
   tint rather than by a hard rule reads quieter and survives a page
   with nine panels on it.

   ------------------------------------------------------------------
   SEMANTIC IS NOT ACCENT
   ------------------------------------------------------------------
   --accent is "press this / you are here". ok / warn / danger are
   "this is how it went". Each semantic colour is a TRIPLE — ink,
   ground and border — because taking two and hard-coding the third is
   exactly how the borders stayed pale when everything else moved.
   ================================================================== */

:root {
  color-scheme: light;

  --ground:      #eef1f5;
  --surface:     #ffffff;
  --sky:         #e9f2fb;
  --sky-line:    #c9deef;

  --line:        #d3dce6;
  --line-soft:   #e6ebf1;

  --ink:         #17273a;
  --ink-soft:    #4a5b70;
  /* ⚠ #5e6d82, NOT #74849a. The lighter value measured 3.36-3.81:1
     depending on the ground, and this token is not only for labels —
     .faint renders INLINE AS BODY TEXT ("nobody", "+ field adjusters",
     the em dash in a voided invoice row), so the small-text exemption
     does not apply to it. #5e6d82 clears 4.5:1 on all three grounds. */
  --ink-faint:   #5e6d82;

  --accent:      #2f6fb5;
  --accent-soft: #e3eff9;
  --accent-line: #bcd8ef;

  --ok:      #1c7048;  --ok-bg:     #e8f5ee;  --ok-line:     #bfe2ce;
  --warn:    #a35b00;  --warn-bg:   #fdf2e0;  --warn-line:   #f0d5a8;
  --danger:  #b42d22;  --danger-bg: #fdeceb;  --danger-line: #f3ccc8;

  /* Text on a saturated fill. One palette means one answer: white.
     The two-ink split (--on-brand / --on-fill) existed only because
     the fills flipped with the theme. They no longer flip; both names
     are kept because other rules still say them. */
  --on-brand:    #ffffff;
  --on-fill:     #ffffff;
  --accent-ink:  #ffffff;

  /* ⚠ --brand IS THE COMPANY BLUE AND IS NOT --accent. It is
     #3f63c8 from finishlineadjusters.com, it is what the header bar
     is, and Finish_Line_Logo_White.svg was derived as a knockout FOR
     that bar. Repainting the header would make the supplied mark wrong
     rather than merely different. --accent is the interface blue and
     is used everywhere else. Say the word if the header should follow
     the accent and the logo be regenerated with it. */
  --brand:       #3f63c8;
  --brand-dark:  #33529f;
  --brand-deep:  #2a4585;
  --brand-soft:  var(--accent-soft);
  --brand-line:  var(--accent-line);
  --brand-ring:  rgba(47, 111, 181, .35);

  /* A panel quieter than its neighbours, and a table row under the
     cursor. */
  --surface-quiet: #f8fafc;
  --surface-hover: #f4f7fb;

  /* ⚠ --sunk IS NEUTRAL AND IS NOT --sky. It was aliased to the tint
     for a moment, which put a blue wash on every "retired" tag and
     every quiet pill — states that mean "switched off", and blue is
     the one thing they must not look like. The sky tint is for HEADER
     BANDS; this is for an inset that should recede without colouring. */
  --sunk:          #f0f3f7;

  /* Kept and repointed: other screens still name these. */
  --bg:        var(--ground);
  --panel:     var(--surface);
  --warn-ink:  var(--warn);

  /* The remaining literals, named. Each was a component setting its
     own colour: the staging banner's hazard stripes, the two
     white-with-alpha inks the header bar uses on its own blue, and the
     hairline under the pinned summary bar. */
  --stripe:        rgba(217, 130, 43, .16);
  --on-brand-soft: rgba(255, 255, 255, .88);
  --on-brand-line: rgba(255, 255, 255, .70);

  /* ⚠ A FILL ON THE BAR COMES WITH ITS OWN INK, AND --on-brand-line IS
     NEVER A BACKGROUND (2026-10-01). It is a LINE — an underline, a
     border. Used as a fill it composites over --brand to #c5d0ee, a
     near-white chip, and white ink on that is 1.54:1. That happened
     THREE times: the "you are here" chip, the badge, and then every
     hover and open button in the bar, which nobody saw until the
     dropdowns stopped being clipped. Each fill below names the ink
     that reads on it; use the pair, never one half.

       --on-brand-press  hover / open      ink --on-accent   7.37:1
       --on-brand-chip   "you are here"    ink --on-brand-chip-ink
                                                             5.96:1 */
  --on-brand-press:    var(--brand-dark);
  --on-brand-chip:     rgba(255, 255, 255, .70);
  --on-brand-chip-ink: var(--brand-deep);

  /* The STAGING tag's fill. It was --warn-line used as a background —
     the same line-as-fill shape bin/css_pairs.php now refuses. */
  --warn-chip:         var(--warn-line);

  /* ⚠ --on-accent WAS USED IN FOUR PLACES AND DEFINED IN NONE.
     Found while consolidating the top bar.

     A var() with no definition and no fallback makes the WHOLE
     declaration invalid at computed-value time — it does not fall back
     to anything sensible. So:

       .topnav a:hover { color: var(--on-accent) }      did nothing
       .topbar .linkbtn:hover { color: ... }            did nothing
       .topbar :focus-visible { outline: 3px solid ... } DID NOT RENDER

     That last one matters: the comment above it says focus has to be
     visible against blue and not just against white, and it has not
     been. Keyboard users have had no visible focus ring anywhere in
     the header.

     It is full-strength white — the same ink as --on-brand, which is
     what "the strong ink for this bar" means. Kept as its own name
     rather than replacing the four call sites, because the call sites
     are asking for "the ink that reads on the accent/brand fill" and
     that is a different question from "the brand's own foreground". */
  --on-accent:     #ffffff;
  --shadow-sm:     0 1px 0 rgba(0, 0, 0, .04);

  /* ⚠ NUMBERS, DATES, MONEY AND CLAIM NUMBERS ARE MONOSPACED WITH
     TABULAR FIGURES. A column of money in a proportional face does not
     line up, and a claim number is read a character at a time. */
  --mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas,
          "Liberation Mono", monospace;
}

/* Money, dates, claim numbers. One class, used everywhere a figure has
   to line up with the figure above it. */
.num, .claimbar-ref, .rail-count {
  font-variant-numeric: tabular-nums;
  font-family: var(--mono);
}
.faint { color: var(--ink-faint); }
.r { text-align: right; }

/* Links carry the brand. Visited is not differentiated: on an internal
   application every link is one you have followed, and a second color
   would be noise rather than information. */
/* ⚠ LINK TEXT TAKES --accent, NOT --brand. --brand is the FILL behind
   white text on the header bar; --accent is the interface blue that
   reads as text on a page. They are close but they are not the same
   job, and using the fill colour as text is how a link ends up at the
   wrong weight against the ground. */
a { color: var(--accent); }
a:hover { color: var(--brand-dark); }

/* One focus style everywhere, and it is never removed. Keyboard users
   have to be able to see where they are. */
:focus-visible {
  outline: 3px solid var(--brand-ring);
  outline-offset: 1px;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font: 16px/1.5 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
        "Helvetica Neue", Arial, sans-serif;
  -webkit-text-size-adjust: 100%;
}

/* --- staging banner ------------------------------------------- */

.envbar {
  background: var(--warn-bg);
  color: var(--warn-ink);
  border-bottom: 3px solid var(--warn-line);
  padding: .5rem 1rem;
  font-size: .875rem;
  display: flex;
  gap: .75rem;
  align-items: baseline;
  flex-wrap: wrap;
  /* Hazard stripes. Nothing else in the application looks like this,
     which is the entire point. */
  background-image: repeating-linear-gradient(
    -45deg,
    var(--stripe) 0 10px,
    transparent 10px 20px
  );
}
/* ⚠ THIS BADGE WENT WHITE-ON-PALE-AMBER THE DAY --on-accent WAS
   DEFINED — found 2026-09-24 alongside the dropdown bug, and it is
   the same mistake: an ink meant for a SATURATED fill used on a PALE
   ground.

   It did not show up sooner because the rule had never rendered.
   --on-accent was used in four places and defined in none, so
   `color: var(--on-accent)` was invalid at computed-value time and the
   whole declaration was dropped — the badge simply inherited the
   banner's amber ink and looked right. Defining the token during the
   top-bar consolidation switched the rule ON, at 1.42:1, on the one
   element CLAUDE.md says must be impossible to miss: the word that
   tells somebody they are not editing a live claim.

   ⚠ --warn IS NOT THE ANSWER HERE, WHICH IS COUNTER-INTUITIVE. It is
   the right ink for --warn-bg (4.68:1, which is what the banner around
   this badge uses) and the wrong one for --warn-line, the darker
   ground the badge itself takes: measured 3.65:1, still a fail. The
   semantic pairing is per GROUND, not per family. --ink is 10.66:1 on
   it, and the badge is already shouting through weight, letter-spacing
   and the amber pill — it does not need the ink to shout as well. */
.envbar strong {
  letter-spacing: .1em;
  font-weight: 700;
  background: var(--warn-chip);
  color: var(--ink);
  padding: .05rem .45rem;
  border-radius: 3px;
}

/* --- header --------------------------------------------------- */

.topbar {
  background: var(--brand);
  color: var(--on-brand);
  border-bottom: 1px solid var(--brand-deep);
  padding: .75rem 1rem;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
}
.brand {
  display: inline-flex;
  align-items: center;
  gap: .5rem;
  text-decoration: none;
  color: var(--ink);
  font-weight: 600;
}
/* The header mark. NO PLATE — the header uses the white knockout SVG,
   which sits on the brand bar directly. See views/layout/head.php.

   The viewBox is 1600x1200 (4:3) and carries no width/height, so a
   height here sizes it and the width follows. */
.brand-logo {
  height: 32px;
  width: auto;
  display: block;
}
.topbar-right { display: flex; align-items: center; gap: .75rem; }
.whoami { color: var(--ink-soft); font-size: .9rem; }
.inline { display: inline; margin: 0; }

.linkbtn {
  background: none;
  border: 0;
  padding: 0;
  color: var(--ink-soft);
  font: inherit;
  font-size: .9rem;
  text-decoration: underline;
  cursor: pointer;
}
.linkbtn:hover { color: var(--ink); }

/* --- layout --------------------------------------------------- */

.wrap { max-width: 62rem; margin: 0 auto; padding: 1.5rem 1rem 3rem; }
.narrow { max-width: 26rem; margin: 3rem auto; }

.panel {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 1.5rem;
}

/* ⚠ A PANEL HEADER IS A BAND, NOT JUST A HEADING.
   The h2 (or the .pagehead holding it) is pulled out to the panel's own
   edges, given the sky tint and a sky line beneath, so a column of nine
   panels reads as nine boxes rather than one long page of text. The
   negative margins are what let a 1.5rem-padded panel carry a
   full-bleed band without every panel needing a wrapper element. */
.panel > h2:first-child,
.panel > .pagehead:first-child {
  margin: -1.5rem -1.5rem 1.25rem;
  padding: .7rem 1.5rem;
  background: var(--sky);
  border-bottom: 1px solid var(--sky-line);
  border-radius: 7px 7px 0 0;
}
.panel > h2:first-child { font-size: 1rem; }
.panel > .pagehead:first-child { align-items: center; }
.panel > .pagehead:first-child h2 { margin: 0; font-size: 1rem; }

/* A quiet panel keeps the band but drops the tint, so "quieter" is
   visible rather than merely asserted. */
.panel-quiet > h2:first-child,
.panel-quiet > .pagehead:first-child {
  background: var(--surface-quiet);
  border-bottom-color: var(--line-soft);
}

h1 { font-size: 1.35rem; margin: 0 0 .25rem; }
h2 { font-size: 1.05rem; margin: 1.75rem 0 .5rem; }
.sub { color: var(--ink-soft); font-size: .9rem; margin: 0 0 1.25rem; }

/* --- forms ---------------------------------------------------- */

.field { margin-bottom: 1rem; }
label, .field-label { display: block; font-size: .875rem; font-weight: 600; margin-bottom: .3rem; }

/* ⚠ TEXTAREA WAS MISSING FROM THIS LIST ENTIRELY.
   Every text area in the app was therefore rendering at the browser
   default of cols=20 -- about 190px -- inside containers three times
   that wide, with none of the border, padding or font of the inputs
   beside it. Making the note box taller did nothing about that,
   because the width was never set at all.

   `tel` and `search` were missing for the same reason: the selector
   named three input TYPES rather than covering the text-like controls,
   so a phone field sat at 190px next to a full-width name field in the
   same row. */
input[type=email],
input[type=password],
input[type=tel],
input[type=search],
input[type=text],
textarea {
  width: 100%;
  padding: .55rem .65rem;
  border: 1px solid var(--line);
  border-radius: 6px;
  font: inherit;
  background: var(--surface);
  color: var(--ink);
}
input:focus,
textarea:focus {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
  border-color: var(--accent);
}

textarea {
  display: block;
  /* Vertical only. Horizontal dragging inside a full-width box makes a
     text area narrower than its container, which is the problem this
     rule exists to fix. */
  resize: vertical;
  line-height: 1.5;
  /* The rows= attribute sets the starting height and stays the floor
     with script off; charcount.js grows it from there. */
  min-height: 4.5rem;
}

.btn {
  display: inline-block;
  width: 100%;
  padding: .6rem 1rem;
  background: var(--accent);
  color: var(--on-fill);
  border: 1px solid var(--accent);
  border-radius: 6px;
  font: inherit;
  font-weight: 600;
  cursor: pointer;
}
.btn:hover  { background: var(--brand-dark); border-color: var(--brand-dark); color: var(--on-fill); }
.btn:active { background: var(--brand-deep); border-color: var(--brand-deep); color: var(--on-fill); }

.hint { color: var(--ink-soft); font-size: .82rem; margin-top: .35rem; }

/* --- messages ------------------------------------------------- */

.flash, .alert {
  border-radius: 6px;
  padding: .7rem .9rem;
  margin-bottom: 1rem;
  font-size: .92rem;
  border: 1px solid transparent;
}
.flash-ok,   .alert-ok    { background: var(--ok-bg);     border-color: var(--ok-line); color: var(--ok); }
.flash-err,  .alert-err   { background: var(--danger-bg); border-color: var(--danger-line); color: var(--danger); }
.flash-warn, .alert-warn  { background: var(--warn-bg);   border-color: var(--warn-line); }

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

.meta { border-collapse: collapse; width: 100%; font-size: .92rem; }
.meta th, .meta td {
  text-align: left;
  padding: .45rem .5rem;
  border-bottom: 1px solid var(--line);
  vertical-align: top;
}
.meta th { width: 12rem; color: var(--ink-soft); font-weight: 600; }

.pill {
  display: inline-block;
  background: var(--sunk);
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: .1rem .6rem;
  font-size: .8rem;
  margin: 0 .25rem .25rem 0;
}

.todo { color: var(--ink-soft); font-size: .92rem; }
.todo li { margin-bottom: .3rem; }

/* --- footer --------------------------------------------------- */

.foot {
  border-top: 1px solid var(--line);
  padding: 1rem;
  text-align: center;
  color: var(--ink-soft);
  font-size: .82rem;
}

/* ==============================================================
   Roster (build step 2)
   ============================================================== */

/* --- header nav ----------------------------------------------- */

.topnav { margin-left: 1.25rem; display: flex; gap: 1rem; flex: 1; }
.topnav a {
  color: var(--ink-soft);
  text-decoration: none;
  font-size: .92rem;
  padding: .2rem 0;
  border-bottom: 2px solid transparent;
}
.topnav a:hover { color: var(--ink); border-bottom-color: var(--line); }

/* --- page header + toolbar ------------------------------------ */

.pagehead {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
}
.pagehead h1 { margin-bottom: .2rem; }

/* ==================================================================
   ⚠ THE ACTION SLOT IN A PAGE HEAD (2026-09-24)
   ==================================================================
   Some page heads carry one action and some carry two, so the right
   hand side is an .actions row rather than a bare <a>. Two things that
   are right inside a form are wrong here:

     margin-top: 1rem  — written to separate a submit row from the last
                         field above it. In a head it drops the buttons
                         below the heading they sit beside.
     .btn width: 100%  — the same rule .grid .btn already has to undo.
                         A head action is not "the one action this form
                         exists to perform"; it is a way onward, and two
                         of them would divide the slot between
                         themselves and stretch.

   ⚠ NO COLOURED BAR HERE, AND THERE MUST NOT BE ONE. A filled strip
   spanning the window reads as a section header for everything beneath
   it, and costs a row of vertical space the first panel wants. The
   sky band belongs to .panel > .pagehead:first-child, where it is
   separating one box from the next — a page head is not a box. */
.pagehead > .actions {
  margin-top: 0;
  flex: 0 0 auto;
}
.pagehead > .actions .btn,
.pagehead > .actions .btn-quiet,
.pagehead > .actions .btn-danger {
  width: auto;
  white-space: nowrap;
}

/* ------------------------------------------------------------------
   THE WAY BACK IS A BUTTON, NOT A GREY LINK
   ------------------------------------------------------------------
   It used to be small muted text at the very top of the page — easy to
   miss, easy to mis-click, and invisible to somebody who is not
   scanning for links. It is the control people use most and it was the
   quietest thing on the screen.

   Styled here rather than by editing every page, so all 25 of them
   upgrade at once and none can be left behind.
   ------------------------------------------------------------------ */
.crumb { margin: 0 0 1rem; }
.crumb a {
  display: inline-flex;
  align-items: center;
  gap: .4rem;
  padding: .5rem .9rem;
  background: var(--brand-soft);
  color: var(--brand-dark);
  border: 1px solid var(--brand-line);
  border-radius: 6px;
  font-size: .92rem;
  font-weight: 600;
  text-decoration: none;
}
.crumb a:hover {
  background: var(--brand);
  border-color: var(--brand);
  color: var(--on-brand);
  text-decoration: none;
}
.crumb a:focus-visible { outline: 3px solid var(--brand); outline-offset: 2px; }

/* The same control repeated at the FOOT of a long page, so nobody has
   to scroll back up to leave. Separated by a rule so it reads as the
   end of the page rather than as part of the last panel. */
.backfoot {
  margin: 2rem 0 .5rem;
  padding-top: 1.2rem;
  border-top: 1px solid var(--line);
}

.toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
  margin: 1rem 0 .75rem;
}

.tabs { display: flex; gap: .25rem; }
.tab {
  display: inline-block;
  padding: .35rem .8rem;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--panel);
  color: var(--ink-soft);
  text-decoration: none;
  font-size: .88rem;
}
.tab:hover  { color: var(--ink); }
.tab.is-on  { background: var(--brand); border-color: var(--brand); color: var(--on-brand); }

.searchform { display: flex; align-items: center; gap: .4rem; }
.searchform input[type="search"] {
  padding: .4rem .6rem;
  border: 1px solid var(--line);
  border-radius: 6px;
  font: inherit;
  font-size: .92rem;
}

/* --- data grid ------------------------------------------------ */

/* The state checkbox grid on the public application form. Two-letter
   codes in columns rather than fifty-three stacked rows. */
.stategrid {
  display: grid; gap: .25rem .75rem;
  grid-template-columns: repeat(auto-fill, minmax(4.5rem, 1fr));
}
.stategrid .check { margin: 0; font-size: .92rem; }

/* Three across, where .row2 is two. */
.row3 { display: grid; gap: 0 1rem; grid-template-columns: repeat(3, 1fr); }
@media (max-width: 40rem) { .row3 { grid-template-columns: 1fr; } }

/* Package position box. Narrow on purpose — it takes a number, not a
   sentence, and a full-width input in a table cell reads as a place to
   type a name. */
.posbox {
  width: 3.5rem; text-align: center; padding: .25rem .35rem;
  font-variant-numeric: tabular-nums;
}

/* Claim list pager. The count line is the important half: it says
   which claims these are out of how many, so a page is never mistaken
   for the whole list. Hidden in print by the @media print block. */
.pager {
  display: flex; flex-wrap: wrap; align-items: center;
  justify-content: space-between; gap: .5rem 1rem;
  margin: .85rem 0 .25rem;
}
.pager-count { margin: 0; color: var(--ink-soft); font-size: .92rem; }
.pager-count strong { color: var(--ink); font-weight: 600; }
.pager-links { display: flex; align-items: center; gap: .75rem; margin: 0; }
.pager-where { color: var(--ink-soft); font-size: .92rem; white-space: nowrap; }

.grid {
  width: 100%;
  border-collapse: collapse;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 8px;
  overflow: hidden;
  font-size: .92rem;
}
.grid th, .grid td {
  text-align: left;
  padding: .6rem .7rem;
  border-bottom: 1px solid var(--line);
  vertical-align: top;
}
/* ⚠ THE SKY BAND IS WHAT SEPARATES ONE BOX FROM THE NEXT, which is why
   the rules between rows can stay faint. A header row that is only a
   bolder font disappears the moment the table is long enough to scroll
   its head off. */
.grid thead th {
  background: var(--sky);
  border-bottom: 1px solid var(--sky-line);
  font-size: .8rem;
  text-transform: uppercase;
  letter-spacing: .03em;
  color: var(--ink-soft);
}
/* A SORTABLE HEADING (2026-10-22, the documents lists) reads as a
   heading, not a blue link: the header's own ink, underlined only on
   hover or keyboard focus. No background of its own, so it sits on the
   sky band like any heading. */
.grid thead th a.sorthead { color: inherit; text-decoration: none; }
.grid thead th a.sorthead:hover,
.grid thead th a.sorthead:focus-visible { text-decoration: underline; }
/* The body's own rules are the soft border; the sky line above is the
   only hard division in the table. */
.grid tbody td { border-bottom-color: var(--line-soft); }
.grid tbody tr:last-child td { border-bottom: 0; }
.grid tbody tr:hover { background: var(--surface-hover); }
.grid-tight th, .grid-tight td { padding: .4rem .6rem; }

/* ==================================================================
   ⚠ A BUTTON IN A TABLE CELL IS A ROW ACTION, NOT THE ACTION THE
      FORM EXISTS TO PERFORM — 2026-09-24
   ==================================================================
   `.btn` carries `width: 100%`, which is right for the one blue button
   at the bottom of a form and catastrophic in a `<td>`: a percentage
   width resolves against the cell, so EVERY button in a cell is drawn
   exactly as wide as its own column.

   Two of them in one cell is therefore 200% of that cell. In the QA
   queue the cell is `td.nowrap` — Take and Review cannot wrap onto
   two lines — so they ran side by side past the right-hand edge and
   `.grid`'s own `overflow: hidden` (there to clip the header band to
   the rounded corner) CUT THEM OFF. Take was half a button and Review
   was not on the screen at all. It reads as a missing feature, which
   is how it was reported: "nothing carries a reviewer from the queue
   to approving".

   This was already known one component at a time — `.tasklist .task
   .btn` and `.taskcontrol .btn` both set `width: auto` locally, and
   `.btn-draft` sets it a third time. Those are three copies of this
   rule written after three separate sightings. It belongs once, here,
   where a `.grid` cell is the general case. */
.grid .btn,
.grid .btn-quiet,
.grid .btn-danger {
  width: auto;
  white-space: nowrap;
  padding: .35rem .7rem;
  font-size: .88rem;
}

/* ==================================================================
   ⚠ A WIDE TABLE SCROLLS ITSELF. IT MAY NOT CLIP, AND IT MAY NOT
      WIDEN THE PAGE — 2026-09-24
   ==================================================================
   Those are the only two things an unwrapped .grid can do, and the
   list pages do both:

     `.grid` is `width: 100%` with `overflow: hidden`. Auto table
     layout uses max(specified, min-content), so a table whose columns
     cannot fit GROWS PAST .wrap and the whole document gets a
     horizontal scrollbar — measured at 975px (the roster, on one long
     email address) and 1246px (Admin > States, three <select>s a row)
     against the 960px .wrap gives it.

     Meanwhile anything overflowing a CELL is clipped by that same
     `overflow: hidden`, silently, with no scrollbar anywhere to hint
     that something is missing.

   So the table goes inside a scroller, and the box moves with it: the
   border and the rounded corners are the WRAPPER's now, and the table
   inside is borderless. That is what lets the table exceed the wrapper
   and be scrolled to rather than cut off. `overflow-x: auto` shows no
   scrollbar at all when the table fits, so it costs nothing on the
   narrow ones.

   ⚠ THE EXISTING PHONE RULE (`.claimwork .grid`, max-width 60rem)
   STAYS. It does the same job by turning the table itself into a block
   scroller, which works but loses `width: 100%` — fine on a phone,
   wrong on a desktop, which is why it is behind a media query. This
   wrapper is width-independent and is what new list pages should use.

   @media print flattens it below, with the rest of the chrome. */
.tablewrap {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  max-width: 100%;
  /* ⚠ THE CONTAINING BLOCK FOR ANYTHING ABSOLUTE INSIDE (2026-10-01).
     .visually-hidden is position:absolute; with nothing positioned here
     its box escaped the scroller and widened the PAGE — the roster was
     887px wide at 820, and 14 table pages scrolled sideways at 390. */
  position: relative;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 8px;
}
/* ⚠ overflow: VISIBLE, not hidden. The table's own `overflow: hidden`
   exists to clip the sky header band to the rounded corner — the
   wrapper does that now. Left on, it would go on silently swallowing
   anything that overflowed a cell INSIDE the scroller, which is the
   failure this whole block is here to end. Visible and wrong beats
   invisible and wrong. */
.tablewrap > .grid {
  border: 0;
  border-radius: 0;
  overflow: visible;
  margin: 0;
}

/* A retired person stays legible -- grayed, never hidden. They are
   still on old claims and still have to be findable. */
.is-retired td { color: var(--ink-soft); background: var(--surface-quiet); }

.nowrap { white-space: nowrap; }
.empty {
  background: var(--panel);
  border: 1px dashed var(--line);
  border-radius: 8px;
  padding: 2rem;
  text-align: center;
  color: var(--ink-soft);
}

/* --- tags ----------------------------------------------------- */

.tag {
  display: inline-block;
  border-radius: 4px;
  padding: .05rem .4rem;
  font-size: .72rem;
  text-transform: uppercase;
  letter-spacing: .03em;
  background: var(--sunk);
  border: 1px solid var(--line);
  color: var(--ink-soft);
  vertical-align: middle;
}
.tag-off  { background: var(--sunk); }
.tag-warn { background: var(--warn-bg); border-color: var(--warn-line); color: var(--warn); }
.tag-ok     { background: var(--ok-bg);     border-color: var(--ok-line); color: var(--ok); }
.tag-danger { background: var(--danger-bg); border-color: var(--danger-line); color: var(--danger); }

/* --- forms ---------------------------------------------------- */

.row2 { display: grid; grid-template-columns: 1fr 1fr; gap: 0 1rem; }
@media (max-width: 34rem) { .row2 { grid-template-columns: 1fr; } }

/* A BAD FIELD IS NOT ALWAYS AN <input>. This named the one element
   type and left select and textarea unmarked, so the peril, the
   description of loss and the type of loss could all carry an error
   with nothing on the box to show it. */
.field.has-err input,
.field.has-err select,
.field.has-err textarea,
li.has-err input { border-color: var(--danger); }
.err { color: var(--danger); font-size: .85rem; margin: .25rem 0 0; }

/* The list of everything that needs fixing, at the top of a form that
   refused to save. Each row links to the box it is about. */
.errlist { margin: .4rem 0 .2rem; padding-left: 1.2rem; }
.errlist li { margin: .25rem 0; }
.errlist a { color: inherit; }

.checklist { list-style: none; margin: 0; padding: 0; }
.checklist li { margin-bottom: .6rem; }
.checklist .hint { margin: .15rem 0 0 1.6rem; }

.check { display: flex; align-items: center; gap: .5rem; cursor: pointer; }
.check input { width: 1rem; height: 1rem; }
.check.is-locked { cursor: not-allowed; color: var(--ink-soft); }

.actions {
  display: flex;
  align-items: center;
  gap: .75rem;
  flex-wrap: wrap;
  margin-top: 1rem;
}
.actions .hint { flex-basis: 100%; margin: 0; }

/* ------------------------------------------------------------------
   PRIMARY vs QUIET — the rule, so the next button is not a guess
   ------------------------------------------------------------------
   .btn is Finish Line blue and is the ONE action a form exists to
   perform: Assign, Save note, Upload, Post reserves, Add note.

   .btn-quiet is everything else on the same screen:
     - filters and searches ("Search", "Show this period")
     - alternatives to the primary ("Mark as being reviewed", sitting
       under "Approve and email a setup link")
     - repeated row actions ("Done" on every task, "Take" on every
       queue row) -- a page of blue buttons has no primary at all
     - navigation dressed as a button ("Add party" is a link to another
       screen, not a commit)

   The test that found the four missed ones: a FORM with no .btn in it
   is a form whose primary action was left quiet.
   ------------------------------------------------------------------ */
.btn-quiet {
  background: var(--panel);
  color: var(--ink);
  border: 1px solid var(--line);
}
.btn-quiet:hover { background: var(--brand-soft); border-color: var(--brand-line); }
.btn-danger { background: var(--danger); border-color: var(--danger); color: var(--on-fill); }
.btn:disabled,
.btn-danger:disabled { opacity: .45; cursor: not-allowed; }

.panel-quiet { background: var(--surface-quiet); }
.panel h2:first-child { margin-top: 0; }

.note { border-left: 3px solid var(--warn-line); padding-left: .6rem; }

/* A setup link has to be selectable in one gesture and must not be
   truncated -- it is copied by hand and a clipped token is useless. */
.copyable {
  display: block;
  margin-top: .5rem;
  padding: .55rem .7rem;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 6px;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: .82rem;
  word-break: break-all;
  user-select: all;
}

.todo .is-done { color: var(--ink); }

/* Present for screen readers, absent from the page. */
.visually-hidden {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

/* ==============================================================
   Managed lists (build step 3)
   ============================================================== */

.listblurb { margin-top: .6rem; }

/* The stack-order warning is louder than an ordinary alert on purpose:
   reordering document_type silently changes every package assembled
   afterwards, and that consequence is invisible from this page. */
.stackwarn { border-left: 4px solid var(--warn-line); }
.stackwarn p { margin: .4rem 0 0; font-size: .9rem; }

.panel-confirm { border: 2px solid var(--warn-line); }

.stackpreview {
  margin: .75rem 0 0;
  padding-left: 1.2rem;
  font-size: .92rem;
}
.stackpreview li { margin-bottom: .3rem; }

/* The position badge answers "what comes out first" without making
   anyone read the sort numbers and sort them in their head. */
.stackpos {
  display: inline-block;
  min-width: 1.9rem;
  text-align: center;
  background: var(--sunk);
  border: 1px solid var(--line);
  border-radius: 4px;
  padding: 0 .3rem;
  font-size: .8rem;
  font-variant-numeric: tabular-nums;
  color: var(--ink-soft);
  margin-right: .4rem;
}

.col-sort { width: 7rem; }
.col-pos  { width: 5.5rem; }
.col-sort input { width: 5rem; font-variant-numeric: tabular-nums; }

.grid input[type="text"],
.grid input[type="number"],
.grid select {
  padding: .35rem .45rem;
  border: 1px solid var(--line);
  border-radius: 5px;
  font: inherit;
  font-size: .9rem;
  background: var(--panel);
}
.grid input.wide { width: 100%; }
.row-err td { background: var(--danger-bg); }

.row3 { display: grid; grid-template-columns: 2fr 1fr 1fr; gap: 0 1rem; }
@media (max-width: 48rem) { .row3 { grid-template-columns: 1fr; } }

.linkbtn-danger { color: var(--danger); }

/* Holds the out-of-table retire forms. HTML forbids nested forms, so
   each Retire button reaches its own form by id; the form itself must
   still be in the document but must not take up space. */
.offscreen {
  position: absolute;
  width: 1px; height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
}

/* ---------------- claim notes ----------------
   The busiest surface on a claim, so it is styled to be scannable:
   author and timestamp on their own line, body indented under it,
   actions quiet until wanted. */

.notelist { list-style: none; margin: 1rem 0 0; padding: 0; }

.note {
  border-top: 1px solid var(--line, #e3e3e0);
  padding: .85rem 0;
}
.note:last-child { padding-bottom: 0; }

.notemeta { margin: 0 0 .35rem; font-size: .9em; }
.notemeta .hint { margin-left: .5rem; }
.notemeta .tag  { margin-left: .5rem; }

/* pre-wrap so a pasted note keeps its shape without needing <pre>,
   and break-word so a long claim number or URL cannot widen the page. */
.notebody {
  white-space: pre-wrap;
  overflow-wrap: break-word;
  margin: 0;
}

.noteactions { margin: .4rem 0 0; font-size: .9em; }
.noteactions .inline { display: inline; margin-left: .75rem; }

/* Money inputs on the limits grid: right-aligned and narrow, so a
   column of figures reads as a column of figures. */
input.money { text-align: right; max-width: 12rem; font-variant-numeric: tabular-nums; }

/* ---------------- contact type notes ----------------
   All three descriptions are shown at once rather than following the
   dropdown: with no client-side script the hint cannot react to the
   select, and the difference between a claimant attorney and defense
   counsel is exactly what somebody filling the form needs to read. */

.typenotes { margin: .75rem 0 0; font-size: .92em; }
.typenotes dt { font-weight: 600; margin-top: .5rem; }
.typenotes dt.is-on::after { content: " — selected"; font-weight: 400; opacity: .65; }
.typenotes dd { margin: .15rem 0 0 1rem; opacity: .8; }

/* Two buttons in a panel heading (post reserves / payments). */
.headactions { display: inline-flex; gap: .5rem; }

/* ---------------- dashboard ----------------
   Tiles are counts of things to DO, not statistics, so the warning
   states are part of the meaning rather than decoration. Color is
   never the only signal — every tile is also a labeled number, and
   every urgent row on the page carries words as well as a tint. */

/* ==================================================================
   THE DASHBOARD — A STAT STRIP AND TWO COLUMNS (2026-09-24)
   ==================================================================
   It was one 62rem column of full-width panels, several of which were
   a heading and a single sentence of prose about data the page already
   had. On a 1600px monitor that is a narrow ribbon of text with two
   thirds of the window empty, and the thing somebody actually has to
   do is four scrolls down.

   ⚠ THE DASHBOARD OPTS INTO .wrap-wide, which until now only
   claim/view.php did. The reasoning there was that 62rem is right for
   ONE COLUMN OF PROSE AND FORMS and wrong for a screen that is
   genuinely two-dimensional. This page is the other one: it is a
   board, not a document, and every panel on it is a list.

   Nothing else moves. .wrap itself is untouched, so the roster, the
   admin screens and the claim forms keep their measure.
   ================================================================== */

/* ---- the stat strip ----
   ⚠ ONE LINE PER TILE, FIGURE BESIDE LABEL, NOT STACKED. The old
   .tile put a 1.7rem number on its own line above a small label, which
   is a poster for one number. Nine of them across the top of a working
   screen is a wall of shouting with no ranking, and it pushed the
   first real row of work below the fold.

   auto-fit rather than a fixed count, so the strip is one row at 1600,
   fewer at 1280 and two columns on a phone, with no breakpoint to
   maintain. 150px is about the width of "statute inside 60 days" at
   .8rem plus a three-digit figure. */
.statstrip {
  list-style: none;
  margin: 0 0 1.25rem;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: .5rem;
}
.stat {
  display: flex;
  align-items: baseline;
  gap: .45rem;
  padding: .45rem .65rem;
  border: 1px solid var(--line);
  border-radius: 6px;
  background: var(--surface);
  font-size: .82rem;
  min-width: 0;
}
.statnum {
  font-family: var(--mono);
  font-variant-numeric: tabular-nums;
  font-size: 1.05rem;
  font-weight: 700;
  line-height: 1.2;
  color: var(--ink);
}
.statlabel { color: var(--ink-soft); min-width: 0; }

/* ⚠ A ZERO IS DIMMED, NOT HIDDEN. "No claims with a passed statute"
   is worth being able to read at a glance, and a tile that disappeared
   when it went to zero would make the strip reflow every day and teach
   nobody where to look. Dimming says "nothing here" without taking the
   place away. */
.stat.is-zero { background: var(--surface-quiet); border-color: var(--line-soft); }
.stat.is-zero .statnum  { color: var(--ink-faint); }
.stat.is-zero .statlabel { color: var(--ink-faint); }

/* Attention takes the semantic tokens, and ONLY when the figure means
   something has to happen. Everything else stays neutral -- if three
   tiles are coloured they are the three to look at. */
.stat.is-warn   { background: var(--warn-bg);   border-color: var(--warn-line); }
.stat.is-warn   .statnum { color: var(--warn); }
.stat.is-danger { background: var(--danger-bg); border-color: var(--danger-line); }
.stat.is-danger .statnum { color: var(--danger); }
.stat a { color: inherit; }

/* ---- the two columns ----
   1.35:1. The left holds tables of claims -- four and five columns
   with a name and two dates in them -- and the right holds compact
   lists that are a reference and a line of context. A 50/50 split
   would wrap the claim tables and leave the queues with half a column
   of white space each.

   ⚠ THE BREAKPOINT IS 1100px AND IT IS ABOUT THE LEFT COLUMN, not
   about tablets. Below it the left column falls under ~630px, which is
   where a claim row (claim number, insured, loss + age, statute +
   countdown) starts wrapping the insured's name onto two lines. One
   column is better than two cramped ones. */
.dashgrid {
  display: grid;
  grid-template-columns: 1.35fr 1fr;
  gap: 1.25rem;
  align-items: start;
}
/* The space BETWEEN panels (2026-10-01). .panel carries no margin, so
   stacked panels touched on both dashboards. A gap on the column spaces
   whatever is in it, and the grid's own 1.25rem is matched. */
.dashcol { min-width: 0; display: flex; flex-direction: column; gap: 1.25rem; }

@media (max-width: 68.75rem) {
  .dashgrid { grid-template-columns: 1fr; }
}
/* NOTHING ON THE RIGHT (2026-10-02): public/index.php decides that in
   PHP and leaves the right column out of the markup. The left one then
   takes the page, capped at 52rem -- the measure of a list read top to
   bottom, worst first. Start-aligned under the page head; it shrinks
   below 52rem with the window, so the fold above needs no copy. */
.dashgrid.dashgrid-single { grid-template-columns: minmax(0, 52rem); }

/* ---- the compact lists in the narrow column ----
   A queue row is a link, a name and one line of context. A <table>
   would give it four column rules and a header band for three words. */
.minilist { list-style: none; margin: 0; padding: 0; }
.minilist > li {
  padding: .5rem 0;
  border-bottom: 1px solid var(--line-soft);
}
.minilist > li:last-child { border-bottom: 0; padding-bottom: 0; }
.minilist > li:first-child { padding-top: 0; }
.minilist .minitop {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: .5rem;
}
.minilist .miniwho {
  display: block;
  color: var(--ink-soft);
  font-size: .9rem;
  overflow-wrap: anywhere;
}
.minilist .minimeta {
  display: block;
  color: var(--ink-faint);
  font-size: .82rem;
}

/* A panel header's right-hand side: the count, or the way to the full
   list. .panel > .pagehead:first-child already lays this out and gives
   it the sky band; this only keeps the link from looking like body
   text inside it. */
.panel > .pagehead:first-child .headlink {
  font-size: .85rem;
  font-weight: 600;
  white-space: nowrap;
}

/* The money panel's figures. Mono so the columns line up without a
   table. */
.figlist { list-style: none; margin: 0; padding: 0; }
.figlist > li {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: .75rem;
  padding: .4rem 0;
  border-bottom: 1px solid var(--line-soft);
}
.figlist > li:last-child { border-bottom: 0; }
.figlist .fig {
  font-family: var(--mono);
  font-variant-numeric: tabular-nums;
  font-weight: 700;
  white-space: nowrap;
}

.tiles {
  list-style: none; margin: 0 0 1.25rem; padding: 0;
  display: flex; flex-wrap: wrap; gap: .75rem;
}
.tile {
  flex: 1 1 9rem; min-width: 9rem;
  border: 1px solid var(--line, #e3e3e0); border-radius: 6px;
  padding: .7rem .85rem; background: var(--surface);
}
.tilenum   { display: block; font-size: 1.7rem; line-height: 1.1; font-weight: 700;
             font-variant-numeric: tabular-nums; }
.tilelabel { display: block; font-size: .82rem; opacity: .75; margin-top: .15rem; }

.tile-warn { border-color: var(--warn-line); background: var(--warn-bg); }
.tile-bad  { border-color: var(--danger-line); background: var(--danger-bg); }

/* Statute urgency on a claim row. Tinted background plus the words
   already in the cell -- never color alone. */
tr.sol-soon   > td { background: var(--warn-bg); }
tr.sol-passed > td { background: var(--danger-bg); }
tr.sol-none   > td { background: var(--sunk); }

/* Pager on the full-history view. */
.pager { display: flex; align-items: center; gap: 1rem; margin-top: .9rem; }

/* ---------------- search ---------------- */

.topsearch { margin-left: auto; margin-right: .75rem; }
.topsearch input { width: 12rem; max-width: 30vw; }

.searchbig { display: flex; gap: .5rem; margin: 0 0 1.25rem; }
.searchbig input { flex: 1 1 auto; font-size: 1.05rem; padding: .55rem .7rem; }

/* ---------------- printable claim summary ---------------- */

.sumhead {
  display: flex; justify-content: space-between; align-items: flex-start;
  gap: 1rem; border-bottom: 2px solid var(--line, #e3e3e0);
  padding-bottom: .6rem; margin-bottom: 1rem;
}
.sumhead h1 { margin: 0; }
.sumorg { text-align: right; font-size: .9em; }

.printable section { margin-bottom: 1.4rem; }
.printable section h2 {
  font-size: 1.05rem; border-bottom: 1px solid var(--line, #e3e3e0);
  padding-bottom: .2rem; margin-bottom: .5rem;
}
.printable h3 { font-size: .95rem; margin: .8rem 0 .3rem; }

.sumnarrative { white-space: pre-wrap; overflow-wrap: break-word; margin: .3rem 0 .6rem; }
.sumclaimant { margin-bottom: 1rem; }
.sumfoot {
  border-top: 1px solid var(--line, #e3e3e0);
  padding-top: .4rem; margin-top: 1.5rem; font-size: .8em; opacity: .7;
}

/* ---------------- print ----------------
   The summary is the only page laid out for paper, but these rules are
   global so that printing any page produces something sane rather than
   a navigation bar and a wall of buttons. */

@media print {
  /* Chrome and Firefox drop backgrounds by default; say so explicitly
     so the tinted statute rows do not print as gray blocks. */
  * { background: transparent !important; color: #000 !important;
      box-shadow: none !important; }

  .topbar, .envbar, .foot, .topnav, .topsearch, .topbar-right,
  .crumb, .actions, .noprint, .pager, .tabs, .toolbar, .searchform,
  .searchbig, form { display: none !important; }

  /* A form is hidden above, but the summary has none — this keeps any
     future read-only content inside one visible. */
  .printable form { display: block !important; }

  body { font-size: 10.5pt; }
  .wrap { max-width: none; margin: 0; padding: 0; }

  .panel { border: 0 !important; padding: 0 !important; margin: 0 0 1rem !important; }

  /* Keep a claimant and their demands together, and never split a
     table row across a page. */
  .sumclaimant, tr, .meta tr { page-break-inside: avoid; }
  section { page-break-inside: auto; }
  h1, h2, h3 { page-break-after: avoid; }

  thead { display: table-header-group; }   /* repeat headers per page */

  .grid, .meta { width: 100%; border-collapse: collapse; }
  .grid th, .grid td, .meta th, .meta td {
    border-bottom: 1px solid #bbb !important; padding: 3px 4px !important;
  }

  /* A scroller cannot be printed — whatever is scrolled out of view
     simply would not come out of the printer. Flattened. */
  .tablewrap { overflow: visible !important; border: 0 !important; }

  .hint { opacity: 1 !important; font-size: .85em; }
  .tag, .pill { border: 1px solid #666 !important; padding: 0 3px !important; }

  a[href] { text-decoration: none; }
  @page { margin: 14mm; }
}

/* ---------------- header on brand ----------------
   The top bar became brand blue, so everything sitting in it needs to
   read against blue rather than against white. Grouped here rather
   than edited into the original rules so the brand change is one
   reviewable block. */

.topbar a,
.topbar .whoami { color: var(--accent-ink); }


.topnav a {
  color: var(--on-brand-soft);
  border-bottom: 2px solid transparent;
  padding-bottom: 2px;
}
.topnav a:hover {
  color: var(--on-accent);
  border-bottom-color: var(--on-brand-line);
}

/* The header search sits on blue: keep the field white so it still
   reads as somewhere you type. */
.topsearch input {
  background: var(--surface);
  border: 1px solid var(--brand-deep);
  color: var(--ink);
  border-radius: 4px;
  padding: .3rem .5rem;
}
.topsearch input::placeholder { color: var(--ink-soft); }

/* Sign out is a form button in the header. */
.topbar .linkbtn {
  color: var(--on-brand-soft);
  text-decoration: underline;
}
.topbar .linkbtn:hover { color: var(--on-accent); }

/* Focus has to be visible against blue too, not just against white. */
.topbar :focus-visible {
  outline: 3px solid var(--on-accent);
  outline-offset: 1px;
}

/* Panel headings pick up a brand rule, which is the "accent" the rest
   of the page gets without turning everything blue. */
.panel > h2:first-child,
.pagehead h1 { border-left: 0; }

.tile-brand { border-color: var(--brand-line); background: var(--brand-soft); }

/* Print: the brand bar must not waste toner, and it is hidden anyway
   by the existing @media print block. Stated so nobody adds it back. */

/* ---------------- claim tabs ----------------
   A real navigation, not a script toy: each tab is a link to a URL
   that can be bookmarked and reloaded. The active one is brand-filled
   so it reads as "where you are" rather than "another button". */

/* The same treatment as .rail-count, so a count means the same thing
   wherever it appears. It was a translucent black, which is the one
   kind of colour that cannot be checked for contrast because it
   depends on whatever happens to be behind it. */
.tabcount {
  background: var(--sky); color: var(--ink-soft);
  border: 1px solid var(--sky-line); border-radius: 10px;
  padding: 0 .4rem; font-size: .8em; font-weight: 700;
}

/* Time logged against a note, shown on the note itself. */
.tag-time {
  background: var(--brand-soft);
  border: 1px solid var(--brand-line);
  color: var(--brand-dark);
  font-variant-numeric: tabular-nums;
}

/* Report money columns line up. */
.money-cell { text-align: right; font-variant-numeric: tabular-nums; }

/* Copy button, injected next to a .copyable by assets/copy.js. It only
   ever exists when the clipboard API does, so there is no styling here
   for a disabled-forever state. */
.btn-copy { margin-top: .4rem; }

/* The report workflow's step strip. Purely a "where is this" readout —
   it is never a control, so nothing here is clickable. */
.flowsteps {
  display: flex;
  flex-wrap: wrap;
  gap: .35rem;
  list-style: none;
  margin: 0 0 1rem;
  padding: 0;
  font-size: .8rem;
}
.flowstep {
  padding: .25rem .55rem;
  border: 1px solid var(--line);
  border-radius: 999px;
  color: var(--ink-soft);
  background: var(--panel);
}
.flowstep.is-done { color: var(--ink); border-color: var(--brand-line); }
.flowstep.is-now  {
  color: var(--on-brand);
  background: var(--brand);
  border-color: var(--brand-deep);
  font-weight: 600;
}
.tightlist { margin: .4rem 0 .6rem; padding-left: 1.1rem; }
.tightlist li { margin-bottom: .25rem; }
tr.is-mine { background: var(--brand-soft); }
.alert-quiet { background: var(--panel); border-color: var(--line); }
.notebody { white-space: pre-wrap; font: inherit; margin: .4rem 0 0; }

/* Character counts, injected under a textarea by assets/charcount.js.
   Quiet until it matters: the same color as a hint, and only red once
   the field is actually over its limit. */
.charcount {
  margin: .25rem 0 0;
  font-size: .78rem;
  color: var(--ink-soft);
  font-variant-numeric: tabular-nums;
}
.charcount.is-over { color: var(--danger); font-weight: 600; }

/* Note formatting buttons, injected above a rich textarea by
   assets/charcount.js. They only ever exist when script does, so there
   is no styling here for a disabled state. */
.richbar { display: flex; gap: .3rem; margin-bottom: .35rem; }
.btn-rich {
  width: auto;
  min-width: 2.2rem;
  padding: .25rem .5rem;
  font-size: .9rem;
  line-height: 1.2;
}

/* The per-claim note number. Said out loud — "per note 32" — so it
   reads as an identifier rather than as decoration. */
.noteno {
  display: inline-block;
  margin-right: .4rem;
  padding: .1rem .45rem;
  border: 1px solid var(--brand-line);
  border-radius: 4px;
  background: var(--brand-soft);
  font-size: .78rem;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--brand-dark);
}

/* Superseded versions of a note. Indented and quiet: it is history,
   not the file. */
.notehistory { margin-top: .5rem; font-size: .92rem; }
.notehistory > summary { cursor: pointer; color: var(--ink-soft); font-size: .82rem; }
.notehistory .revision {
  margin: .5rem 0 .5rem .8rem;
  padding-left: .7rem;
  border-left: 3px solid var(--line);
}

/* Only bold, italic and underline can appear in a note body. Stated
   here so nothing else picks up styling by accident. */
.notebody b { font-weight: 700; }
.notebody i { font-style: italic; }
.notebody u { text-decoration: underline; }

/* Tasks — the diary. A row is a thing to do plus a way to finish it,
   so it lays out as content and one button. */
.tasklist { list-style: none; margin: .4rem 0 1rem; padding: 0; }

/* THE ADJUSTER'S HOME (2026-10-01): rows that are ONE link each, through to
   the thing she has to do. No fill of their own — the ink is the page's,
   the hover is an underline on the claim reference. */
/* THE RAIL'S ACTIONS, IN PLACE (2026-10-01): add a note, add a task, upload.
   Each panel is hidden until it is the URL's :target, which the rail's
   same-page link sets. No script. */
.inplace-panel { display: none; }
.inplace-panel:target { display: block; }
.inplace-panel .pagehead { align-items: center; }

.dashlist { list-style: none; margin: .4rem 0 0; padding: 0; }
.dashlist > li + li { border-top: 1px solid var(--line-soft); }
.dashrow {
  display: flex; align-items: center; gap: .75rem;
  padding: .55rem .1rem; color: inherit; text-decoration: none;
}
.dashrow-text { flex: 1 1 auto; min-width: 0; }
.dashrow:hover .dashrow-ref, .dashrow:focus-visible .dashrow-ref { text-decoration: underline; }
.dashrow-quote { display: block; margin-top: .15rem; color: var(--ink-soft); font-style: italic; }
.dashrow .btn { width: auto; white-space: nowrap; flex: 0 0 auto; }
.tasklist .task {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 1rem;
  padding: .55rem .7rem;
  border: 1px solid var(--line);
  border-radius: 6px;
  margin-bottom: .4rem;
  background: var(--panel);
}
.tasklist .task.is-late  { border-color: var(--danger-line); background: var(--danger-bg); }
.tasklist .task.is-today { border-color: var(--warn-line); background: var(--warn-bg); }
.tasklist .task .btn { width: auto; white-space: nowrap; }
.danger-head { color: var(--danger); }
.addtask > summary { cursor: pointer; color: var(--brand); font-size: .9rem; }
.addtask { margin-top: .6rem; }

/* Reschedule and Withdraw on each open task (views/claim/_task_controls.php).
   <details>, not script, like Add a task. Quiet until opened: they are the
   less common actions beside Done. */
.taskcontrols { display: flex; flex-wrap: wrap; gap: .25rem 1.25rem; margin-top: .35rem; }
.taskcontrol > summary { cursor: pointer; color: var(--brand); font-size: .85rem; }
.taskcontrol[open] { flex-basis: 100%; }
.taskcontrol form { margin: .4rem 0 .6rem; max-width: 26rem; }
.taskcontrol .btn { width: auto; }
.tag-danger { background: var(--danger-bg); color: var(--danger); border-color: var(--danger-line); }

/* Choosing which notes go in the report package. */
.notepick { list-style: none; margin: .5rem 0; padding: 0; }
.notepick li {
  padding: .5rem .6rem;
  border: 1px solid var(--line);
  border-radius: 6px;
  margin-bottom: .35rem;
  background: var(--surface);
}
.notepick .notebody { margin-top: .3rem; }
.tag-brand { background: var(--brand-soft); border-color: var(--brand-line); color: var(--brand-dark); }

/* An unallocated receipt, or an invoice paid short. */
tr.row-warn { background: var(--warn-bg); }

/* The unsaved-draft offer, injected above a textarea by charcount.js.
   Deliberately loud: it is offering somebody their own lost work back,
   and a quiet version would be scrolled past. */
.draftbar {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: .6rem;
  margin-bottom: .5rem;
  padding: .6rem .75rem;
  background: var(--warn-bg);
  border: 1px solid var(--warn-line);
  border-radius: 6px;
  font-size: .9rem;
}
.btn-draft { width: auto; padding: .35rem .7rem; font-size: .88rem; }

/* The two halves of the timesheet entry form. They are one form —
   the entry type decides which kind it is — but time and an expense
   are different actions with different required fields, and a single
   undivided row of boxes read as "fill all of these in". */
.entrygroup {
  margin: 0 0 1rem;
  padding: .9rem 1rem .4rem;
  border: 1px solid var(--line);
  border-radius: 6px;
  background: var(--panel);
}
.entrygroup > legend {
  padding: 0 .45rem;
  font-size: .9rem;
  color: var(--ink);
}

/* ------------------------------------------------------------------
   DROP ZONE  (built by upload.js; nothing renders it server-side)
   ------------------------------------------------------------------
   The box exists whether or not anything is being dragged, because a
   target that only appears once you are already dragging cannot be
   discovered — you have to know it is there to find out it is there.
   ------------------------------------------------------------------ */
.dropzone {
  border: 2px dashed var(--line);
  border-radius: 8px;
  background: var(--surface-quiet);
  padding: 14px 16px;
  transition: border-color .12s, background-color .12s;
}

.dropzone-prompt {
  margin: 0 0 10px;
  color: var(--ink-soft);
  font-size: .95rem;
}
.dropzone-prompt strong { color: var(--ink); }

/* Dragging over it. Deliberately unmissable: the whole point of the
   state is answering "will it take it if I let go here". */
.dropzone.is-over {
  border-color: var(--brand);
  border-style: solid;
  background: var(--brand-soft);
  box-shadow: 0 0 0 3px var(--brand-ring);
}
.dropzone.is-over .dropzone-prompt strong { color: var(--brand-dark); }

.dropzone-status {
  margin: 10px 0 0;
  font-size: .9rem;
  color: var(--ok);
  overflow-wrap: anywhere;   /* a long filename must not widen the panel */
}
.dropzone-status:empty { display: none; }

.dropzone-status.is-warn { color: var(--warn-ink); }
.dropzone-status.is-err  { color: var(--danger); font-weight: 600; }

@media print { .dropzone { border: 0; padding: 0; background: none; } }

/* ------------------------------------------------------------------
   REASSIGNING A NOTE — admin only, so it is folded away by default.
   ------------------------------------------------------------------
   A <details> rather than a button: it is an administrator's
   correction, not part of working a claim, and it should not compete
   for attention with Edit and Remove on every note on the page.
   ------------------------------------------------------------------ */
.notereassign {
  margin: 10px 0 0;
  border-top: 1px dashed var(--line);
  padding-top: 8px;
}
.notereassign > summary {
  cursor: pointer;
  color: var(--ink-soft);
  font-size: .88rem;
}
.notereassign > summary:hover { color: var(--brand-dark); }
.notereassign[open] > summary { color: var(--ink); font-weight: 600; }
.notereassign form { margin-top: 10px; }

/* ------------------------------------------------------------------
   Two-step verification — public/mfa.php, mfa_enroll.php, account.php
   ------------------------------------------------------------------ */
.recoverycodes { columns: 2; column-gap: 2.5rem; margin: .75rem 0 1rem; padding-left: 1.75rem; }
.recoverycodes li { margin: .25rem 0; break-inside: avoid; }
.recoverycodes code { font-size: 1.05rem; letter-spacing: .06em; }
.qr { margin: .6rem 0 .4rem; }
.qr svg { display: block; max-width: 100%; height: auto; }
.totpkey { font-size: 1.05rem; letter-spacing: .08em; word-break: break-all; }
ol.steps > li { margin-bottom: 1.1rem; }
fieldset.field { border: 0; padding: 0; margin: 0 0 1rem; min-width: 0; }
fieldset.field legend { font-weight: 600; margin-bottom: .4rem; padding: 0; }
fieldset.field .check { align-items: baseline; flex-wrap: wrap; margin: .5rem 0; }

/* ==================================================================
   THE CLAIM SCREEN — three zones (2026-09-16)
   ==================================================================
   A pinned summary bar, a left rail that is the only navigation, and
   one work area showing one section. Replaces a tab strip over a
   single scrolling column.

   No script anywhere in here: the rail is links, the active one is
   marked server-side with aria-current, and the responsive behaviour
   is two media queries.
   ================================================================== */

/* ---- ZONE 1 — the summary bar ----------------------------------- */

/* ⚠ PINNED, so it cannot scroll away. The thing people get wrong on a
   busy morning is reading the wrong claim, and the old page put the
   claim number at the top of a column that moved. */
.claimbar {
  position: sticky;
  top: 0;
  z-index: 20;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: .6rem .85rem;
  margin-bottom: 1rem;
  box-shadow: var(--shadow-sm);
}

.claimbar-main {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: .5rem .7rem;
}

.claimbar-ref     { font-size: 1.15rem; font-weight: 700; color: var(--ink); }
.claimbar-insured { font-size: 1.02rem; color: var(--ink); }
.claimbar-flags   { margin-left: auto; display: flex; gap: .35rem; flex-wrap: wrap; }

/* Line 2 — the small labelled facts. */
.claimbar-facts {
  display: flex;
  flex-wrap: wrap;
  gap: .1rem 1.5rem;
  margin: .5rem 0 0;
  padding: .5rem 0 0;
  border-top: 1px solid var(--line-soft);
}
.claimbar-facts > div { display: flex; flex-direction: column; gap: .05rem; }
.claimbar-facts dt {
  font-size: .68rem;
  text-transform: uppercase;
  letter-spacing: .04em;
  color: var(--ink-faint);
}
.claimbar-facts dd { margin: 0; font-size: .9rem; color: var(--ink); }
/* The quiet second line under a fact ("$110.50 not yet invoiced").
   The color is set HERE, not left to .faint: `.claimbar-facts dd`
   sets --ink and outranks a bare class, so .faint alone does nothing. */
.claimbar-facts dd.claimbar-sub { font-size: .76rem; color: var(--ink-faint); }

/* ---- the layout -------------------------------------------------- */

.claimlayout {
  display: grid;
  grid-template-columns: 216px minmax(0, 1fr);
  gap: 1.25rem;
  align-items: start;
}

/* ---- ZONE 2 — the rail ------------------------------------------- */

/* Quiet, narrow, small type, NO ICONS. An icon beside "Coverage and
   reserves" is decoration that has to be learned; the words are
   already the shortest true label. */
.rail {
  position: sticky;
  top: 5.5rem;
  font-size: .86rem;
}

.rail-group { padding: .45rem 0; }
.rail-group + .rail-group { border-top: 1px solid var(--line-soft); }

.rail-head {
  margin: 0 0 .3rem;
  padding: 0 .5rem;
  font-size: .68rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .06em;
  color: var(--ink-faint);
}

.rail-list { list-style: none; margin: 0; padding: 0; }

.rail-link {
  display: flex;
  align-items: center;
  gap: .5rem;
  padding: .32rem .5rem .32rem .65rem;
  border-left: 3px solid transparent;   /* the edge bar lives here */
  border-radius: 0 5px 5px 0;
  color: var(--ink-soft);
  text-decoration: none;
  line-height: 1.35;
}
.rail-link:hover { background: var(--sunk); color: var(--ink); }

/* ⚠ THE CURRENT SECTION IS MARKED TWICE — aria-current in the HTML for
   anybody not looking at it, and a left edge bar for anybody who is.
   Colour alone would say it to neither. */
.rail-link.is-on,
.rail-link[aria-current="page"] {
  background: var(--accent-soft);
  border-left-color: var(--accent);
  color: var(--ink);
  font-weight: 600;
}

/* Focus has to be visible and must not be the same as "current". */
.rail-link:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: -2px;
}

.rail-label { flex: 1 1 auto; }

.rail-count {
  flex: 0 0 auto;
  min-width: 1.35rem;
  padding: 0 .3rem;
  text-align: center;
  font-size: .72rem;
  border-radius: 999px;
  background: var(--sunk);
  color: var(--ink-faint);
  border: 1px solid var(--line-soft);
}
/* A count that wants doing something about today. */
.rail-count.is-flag {
  background: var(--danger-bg);
  color: var(--danger);
  border-color: var(--danger);
  font-weight: 700;
}

.rail-action { color: var(--accent); }
.rail-action:hover { color: var(--accent); }

/* ---- ZONE 3 — the work area -------------------------------------- */

.claimwork { min-width: 0; }

.seclead {
  margin: 0 0 .5rem;
  font-size: .72rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .06em;
  color: var(--ink-faint);
}

/* Loss and Exposure, side by side on the Summary. */
.twocol {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 1.25rem;
  align-items: start;
}
.twocol-col { min-width: 0; }

/* ---- the attention strip ----------------------------------------- */

/* ⚠ THERE IS NO EMPTY STATE. _attention.php prints nothing at all when
   nothing is true, so there is no "all clear" box to learn to skip. */
.attention {
  list-style: none;
  margin: 0 0 1rem;
  padding: 0;
  border: 1px solid var(--line);
  border-radius: 8px;
  overflow: hidden;
  background: var(--surface);
}
.attention li {
  padding: .5rem .8rem .5rem .75rem;
  border-left: 4px solid var(--line);
  font-size: .92rem;
  color: var(--ink);
}
.attention li + li { border-top: 1px solid var(--line-soft); }
.attention-danger { border-left-color: var(--danger); background: var(--danger-bg); }
.attention-warn   { border-left-color: var(--warn);   background: var(--warn-bg); }

/* ---- pills ------------------------------------------------------- */

.pill-quiet  { background: var(--sunk);      color: var(--ink-soft); border-color: var(--line); }
.pill-danger { background: var(--danger-bg); color: var(--danger);   border-color: var(--danger); }
.pill-warn   { background: var(--warn-bg);   color: var(--warn);     border-color: var(--warn); }

tr.is-void td { color: var(--ink-faint); text-decoration: line-through; }

/* ==================================================================
   TABLET AND PHONE
   ==================================================================
   ⚠ THE RAIL BECOMES A CHIP ROW, NOT A HAMBURGER. A menu behind a
   button needs script and hides where you are; a scrolling row of chips
   keeps the current section visible and costs nothing.

   ⚠ AND THE SUMMARY BAR DROPS ITS SECOND LINE RATHER THAN SHRINKING
   IT. Eight labelled figures wrapped onto six lines of a phone is not a
   summary — it is the thing you scroll past to reach the work. The
   claim number, the insured and the status stay.
   ================================================================== */

@media (max-width: 60rem) {
  .claimlayout { grid-template-columns: minmax(0, 1fr); gap: .85rem; }

  .claimbar-facts { display: none; }

  .rail {
    position: static;
    display: flex;
    gap: .4rem;
    overflow-x: auto;
    padding-bottom: .35rem;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: thin;
  }
  .rail-group {
    display: flex;
    gap: .4rem;
    padding: 0;
    border: 0;
    flex: 0 0 auto;
  }
  .rail-group + .rail-group { border-top: 0; }
  .rail-head { display: none; }

  .rail-list { display: flex; gap: .4rem; }
  .rail-list li { flex: 0 0 auto; }

  .rail-link {
    border: 1px solid var(--line);
    border-left-width: 1px;
    border-radius: 999px;
    padding: .3rem .7rem;
    background: var(--surface);
    white-space: nowrap;
  }
  .rail-link.is-on,
  .rail-link[aria-current="page"] {
    border-color: var(--accent);
    border-left-width: 1px;
    background: var(--accent-soft);
  }

  .twocol { grid-template-columns: minmax(0, 1fr); gap: .85rem; }
}

/* 400px and down: the flag pills wrap under the claim number rather
   than pushing the insured's name off the edge. */
@media (max-width: 26rem) {
  .claimbar-flags { margin-left: 0; width: 100%; }
  .claimbar-ref   { font-size: 1.05rem; }
  .claimbar       { padding: .5rem .6rem; }
}

/* ⚠ AT PHONE WIDTH A WIDE TABLE MUST SCROLL ITSELF, NOT THE PAGE.
   The invoices list is seven columns and the reserve grid is one column
   per coverage; without this they widen the document and every screen
   gets a horizontal scrollbar, including the ones with nothing wide on
   them. Scoped to the work area and to .grid — the two-column .meta
   tables are already narrow, and making those scroll would be worse
   than leaving them. */
@media (max-width: 60rem) {
  .claimwork .grid {
    display: block;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
  }
}

/* Belt and braces: nothing on the claim screen may widen the document
   itself. A single overflowing element used to mean the summary bar
   scrolled sideways away from its own claim number. */
.claimlayout, .claimwork, .claimbar { max-width: 100%; }
.claimwork img, .claimwork pre { max-width: 100%; }

/* ==================================================================
   THE CLAIM SCREEN USES THE WINDOW — .wrap-wide (2026-09-16)
   ==================================================================
   ⚠ WHY 105rem / 1680px, AND NOT "AS WIDE AS IT GOES".

   .wrap is 62rem (992px) and that is RIGHT for every other screen —
   they are one column of prose, forms and lists, and 62rem keeps a
   line of text at a readable measure. It is wrong here: the rail eats
   216px of it, and what remains splits into Loss and Exposure at about
   350px each, which wraps a person's name onto three lines.

   The arithmetic at 1680:

       1680 - 64 (gutters) - 216 (rail) - 20 (gap) = 1380 work area
       two columns of (1380 - 20) / 2              =  680 each
       680px at .95rem                             ≈ 85-95 characters

   85-95 characters is the top of the comfortable range. Past that the
   columns keep growing, the measure passes the point where the eye
   reliably finds the next line, and — worse on this screen — the
   distance from the rail to the right edge of the work area grows
   until the two zones stop reading as one page. So it stops.

   ⚠ ONLY ONE PAGE OPTS IN. public/claim/view.php sets $wide; every
   other screen keeps 62rem and is untouched by this.
   ================================================================== */

.wrap-wide {
  max-width: 105rem;
  /* A gutter that grows with the window instead of staying at 1rem.
     At 1280 this is ~32px a side; at 1920 it is capped at 40px, by
     which point the 105rem ceiling is doing the centring anyway. */
  padding-left:  clamp(1rem, 2.5vw, 2.5rem);
  padding-right: clamp(1rem, 2.5vw, 2.5rem);
}

/* ⚠ THE FACTS GO ON ONE LINE ONCE THERE IS ROOM FOR THEM.
   Seven facts wrapping to a second row pushes the work area down and
   makes the bar look like a paragraph. Above 75rem there is room, so
   they stop wrapping and share the space instead; each one may shrink,
   and the values ellipsize rather than the row breaking. */
@media (min-width: 75rem) {
  .claimbar-facts {
    flex-wrap: nowrap;
    gap: .1rem 2rem;
  }
  .claimbar-facts > div { min-width: 0; }
  .claimbar-facts dd {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }
  /* The carrier and the adjuster are the two that run long, so they
     get the slack and the short numeric facts keep their natural
     width. */
  .claimbar-facts > div:nth-child(1),
  .claimbar-facts > div:nth-child(2) { flex: 1 1 auto; min-width: 7rem; }
  .claimbar-facts > div:nth-child(n+3) { flex: 0 0 auto; }
}

/* Real room for the two columns once the window is wide. Below this
   they stay as they were. */
@media (min-width: 90rem) {
  .claimlayout { gap: 1.75rem; }
  .twocol      { gap: 1.75rem; }
}

/* ---- the note editor --------------------------------------------- */

/* ⚠ THE MIRROR IS HIDDEN, NOT REMOVED. The <textarea> is still what
   posts; the editor writes into it. display:none would take it out of
   the form submission on some browsers, so it is moved out of sight
   instead and left in the document. */
textarea.is-mirrored {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px; border: 0;
  overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%);
  white-space: nowrap;
}

.richedit {
  min-height: 14rem;
  max-height: 70vh;
  overflow-y: auto;
  padding: .55rem .7rem;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 6px;
  color: var(--ink);
  font: inherit;
  line-height: 1.5;
}
.richedit:focus-visible,
.richedit:focus {
  outline: 2px solid var(--accent);
  outline-offset: -1px;
  border-color: var(--accent);
}
.richedit:empty::before {
  content: attr(data-placeholder);
  color: var(--ink-faint);
}
/* Lists need their markers back — the reset elsewhere strips them. */
.richedit ul, .notebody ul { list-style: disc;    margin: .4rem 0 .4rem 1.4rem; padding: 0; }
.richedit ol, .notebody ol { list-style: decimal; margin: .4rem 0 .4rem 1.4rem; padding: 0; }
.richedit li, .notebody li { margin: .15rem 0; }

/* A finished task: present, and visibly not waiting for anybody. */
.tasklist .task.is-closed { background: var(--surface-quiet); border-color: var(--line-soft); }
.tasklist .task.is-closed > div > strong { color: var(--ink-soft); font-weight: 600; }

/* ==================================================================
   THE CONSOLIDATED TOP BAR — six items and one user menu
   ==================================================================
   It was seventeen top-level links wrapping onto two rows, plus a
   second row for the account links. Now: three plain links, four
   grouped menus, and the person's own menu on the right.

   ⚠ NOTHING HERE SETS A COLOUR LITERAL. Every value is a token, per
   the one-palette rule. The bar is --brand, so its inks are the
   --on-brand pair the header already established.

   ⚠ EVERY MENU IS <details>/<summary>. Click to open, never hover;
   keyboard-operable and screen-reader-announced natively; fully usable
   with scripting off. nav.js only adds Escape and click-outside.
   ================================================================== */

/* THE ROW MUST NOT WRAP. That is the entire point of the change, so it
   is asserted rather than hoped for.

   ⚠ nowrap ALONE WOULD OVERFLOW, NOT WRAP — which is a different bug,
   not a fix. So there are three parts: nowrap stops the second row,
   overflow-x lets a pathological case scroll instead of overlapping
   the search box, and the 70rem breakpoint below means the full row
   only ever renders where it actually fits.

   THE BREAKPOINT IS DERIVED, NOT PICKED. The widest bar is the
   manager's and admin's: seven items with two badges, plus the brand,
   the search box and the user menu. Measured by summing labels,
   padding, gaps, carets and badges at .95rem, that comes to about
   1090px — so it fits at 1280 with roughly 190px spare and at 1600
   with 510px, and does NOT fit at 1024. 70rem (1120px) is just above
   the requirement, so below it the collapsed button takes over rather
   than a row quietly running off the edge.

   ⚠ THAT IS A CALCULATION, NOT A MEASUREMENT. There is no browser on
   this host, so nobody has looked at it. The arithmetic is in the
   commit; check it in a real window before trusting it, and if the
   row is tight at 1280 the honest fix is to raise the breakpoint
   rather than to shrink the labels. */
.topnav {
  margin-left: 1.25rem;
  display: flex;
  flex-wrap: nowrap;
  align-items: center;
  gap: .25rem;
  flex: 1;
  min-width: 0;
  /* ⚠ NO overflow-x HERE, EVER (removed 2026-09-28). It was a
     "backstop" so a too-wide row would scroll rather than overlap —
     and it hid every menu. A box that scrolls on one axis cannot stay
     visible on the other (overflow-y computes to auto), so .topnav
     became a one-line box that CLIPPED every dropdown hanging below
     it: click Setup, the <details> opened, the panel was cut off, and
     nothing appeared to happen. The breakpoint below is what keeps the
     row from overflowing; the browser sweep checks it at 1024 and 1280. */
}

.topnav-link,
.navgroup-btn {
  display: inline-flex;
  align-items: center;
  gap: .35rem;
  white-space: nowrap;
  padding: .35rem .6rem;
  border-radius: 5px;
  font-size: .95rem;
  color: var(--on-brand-soft);
  border-bottom: 0;
  cursor: pointer;
}

.topnav-link:hover,
.navgroup-btn:hover,
.navgroup[open] > .navgroup-btn {
  color: var(--on-accent);
  background: var(--on-brand-press);
}

/* WHERE YOU ARE, on the item and on the group that holds it. Two
   different jobs: the item is a filled chip because it is exactly the
   page; the group is underlined because it merely contains it. */
/* ⚠ THE FILL IS NEARLY WHITE, SO THE INK ON IT CANNOT BE WHITE —
   2026-09-24, found by the same sweep as the dropdown bug.

   --on-brand-line is rgba(255,255,255,.70). Over the brand bar that
   composites to rgb(197,208,238) — a pale chip, not a saturated one.
   --on-accent on it measured 1.54:1: the "you are here" marker was
   the one thing in the bar you could not read, on the bar's own
   current page.

   The two halves of this rule want different answers now, so they are
   two rules: the chip on the BAR takes --brand-deep (5.97:1, and it
   reads as the brand rather than as body text), while the one in a
   dropdown is on white and keeps --ink. The token block on .navmenu
   above would have made a shared declaration resolve correctly in the
   menu anyway — but only by accident of both wanting the same value,
   and they no longer do. */
.topnav-link.is-current {
  background: var(--on-brand-chip);
  color: var(--on-brand-chip-ink);
  font-weight: 600;
}
.navmenu-item.is-current {
  background: var(--accent-soft);
  color: var(--ink);
  font-weight: 600;
}
.navgroup.is-here > .navgroup-btn {
  color: var(--on-accent);
  box-shadow: inset 0 -2px 0 0 var(--on-accent);
}

/* ---- the groups ---- */

.navgroup { position: relative; }

/* The default triangle is inconsistent between browsers and reads as a
   form control rather than a menu. Replaced with our own caret. */
.navgroup > summary { list-style: none; }
.navgroup > summary::-webkit-details-marker { display: none; }
.navgroup > summary::after {
  content: "";
  width: .35rem; height: .35rem;
  border-right: 2px solid currentColor;
  border-bottom: 2px solid currentColor;
  transform: rotate(45deg) translateY(-1px);
  opacity: .8;
}
.navgroup[open] > summary::after { transform: rotate(225deg) translateY(1px); }

.navmenu {
  position: absolute;
  top: calc(100% + .35rem);
  left: 0;
  z-index: 60;
  min-width: 13rem;
  padding: .3rem;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 7px;
  box-shadow: 0 6px 18px var(--shadow-sm);
  display: flex;
  flex-direction: column;
  gap: .1rem;
}
.navmenu-right { left: auto; right: 0; }

/* ==================================================================
   ⚠ A PANEL THAT HANGS OFF THE BAR IS A PAGE SURFACE, AND IT SAYS
      SO IN TOKENS RATHER THAN IN SELECTORS — 2026-09-24
   ==================================================================
   The comment that used to sit here said the menu's inks are the
   page's and not the bar's. That was the INTENT. It was not the
   EFFECT, and the difference cost the user menu entirely:

       .topbar a   { color: var(--accent-ink)   }   (0,1,1)
       .topnav a   { color: var(--on-brand-soft)}   (0,1,1)
       .navmenu-item { color: var(--ink)        }   (0,1,0)

   Both bar rules outrank the menu's own, so every <a> in a dropdown
   rendered in the bar's near-white ink ON THE WHITE PANEL. Measured:
   #ffffff on #ffffff, 1.00:1. Directory, My license, Security and My
   earnings were blank rectangles. It read as a rendering glitch rather
   than a colour bug because the group menus' items were unreadable on
   HOVER too (.topnav a:hover is (0,2,1) and beats .navmenu-item:hover
   at (0,2,0)), and because Sign out looked fine — it is a <button>,
   so `.topbar a` never matched it at all.

   ⚠ THE FIX IS NOT ANOTHER, HEAVIER SELECTOR. That is a race, and
   the next rule added to the bar re-enters it: this is the third time
   a header ink has landed somewhere it was not meant to. So the PANEL
   REDEFINES THE BAR'S INK TOKENS TO THE PAGE'S. A custom property is
   resolved against the element the declaration lands on, not against
   the element the selector was written for — so `.topbar a` still
   wins inside a menu and still says var(--accent-ink), and
   var(--accent-ink) is now the page's ink there. Specificity stops
   being able to matter.

   Each mapping is the bar token's OPPOSITE NUMBER on a white panel,
   chosen so the bar rule and the panel rule agree on an answer:

       --on-brand-soft  the bar's quiet ink   ->  --ink   (what
                        .navmenu-item asks for itself, so whichever
                        rule wins the result is identical)
       --on-accent      the bar's strong ink  ->  --ink
       --accent-ink     ditto, .topbar a      ->  --ink
       --on-brand-line  the bar's own wash    ->  --sky

   ⚠ --on-accent CARRIES THE FOCUS RING, which is the half that was
   invisible rather than merely ugly: `.topbar :focus-visible` draws a
   3px outline in it, so a keyboard user tabbing INTO an open menu had
   a white ring on a white panel and no idea where they were. That is
   fixed by the same four lines, which is the argument for doing this
   in tokens — a selector fix would have repaired the text and left
   the ring.

   Applies to both panels that hang off the bar: a group's dropdown,
   and the whole bar folded into one panel at phone width. */
.navmenu,
.navwrap[open] .navwrap-inner {
  --on-brand-soft: var(--ink);
  --on-accent:     var(--ink);
  --accent-ink:    var(--ink);
  --on-brand-line: var(--sky);
  /* the bar's fills, same idea: on a white panel a press is the sky
     wash and a chip is the accent tint, both under the page's ink */
  --on-brand-press:    var(--sky);
  --on-brand-chip:     var(--accent-soft);
  --on-brand-chip-ink: var(--ink);
}

/* ⚠ AND THE BAR'S GEOMETRY LEAKS BY THE SAME ROUTE. `.topnav a` also
   sets a 2px transparent bottom border and padding-bottom: 2px — the
   underline it grows on hover — and those beat .navmenu-item's own
   padding for the same specificity reason, squashing every item in a
   group's dropdown against the bottom of its box. Tokens cannot answer
   a length, so this one is a selector, kept next to the reason. */
.topnav .navmenu-item {
  border-bottom: 0;
  padding: .4rem .55rem;
}

/* ⚠ AND THE PLAIN LINKS — Claims, New claim, Reports (2026-09-28).
   The same leak, missed the first time: `.topnav a` (padding .2rem 0)
   beat `.topnav-link` (padding .35rem .6rem), so the three links had NO
   side padding while the <summary> group buttons beside them kept
   theirs. With the bar's .25rem gap the links nearly touched and read as
   one run of words, then a properly spaced list. This restores the
   geometry `.topnav-link, .navgroup-btn` already declare together, so
   every item in the row is spaced the same. */
.topnav .topnav-link {
  border-bottom: 0;
  padding: .35rem .6rem;
}

.navmenu-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: .75rem;
  padding: .4rem .55rem;
  border-radius: 5px;
  color: var(--ink);
  font-size: .92rem;
  text-decoration: none;
  white-space: nowrap;
}
.navmenu-item:hover { background: var(--sky); color: var(--ink); }

.navmenu-form { margin: 0; }
.navmenu-signout {
  width: 100%;
  text-align: left;
  background: none;
  border: 0;
  font: inherit;
  cursor: pointer;
  color: var(--ink);
  text-decoration: none;
}
.navmenu-signout:hover { background: var(--sky); }

/* ---- badges ----
   The same chip as .tabcount and .rail-count, so a number means the
   same thing wherever it appears. On the blue bar it needs the bar's
   inks; inside a white menu it needs the page's. */
.navcount {
  background: var(--sky);
  color: var(--ink-soft);
  border: 1px solid var(--sky-line);
  border-radius: 10px;
  padding: 0 .4rem;
  font-size: .78em;
  font-weight: 700;
  line-height: 1.5;
}
/* Same pale fill, same correction: a badge nobody can read is a
   number that is not there. --brand-deep, 5.97:1. */
.navgroup-btn .navcount {
  background: var(--on-brand-chip);
  color: var(--on-brand-chip-ink);
  border-color: transparent;
}

/* ---- the user menu ---- */
.navme-btn { gap: .4rem; }
.navme-name { max-width: 12rem; overflow: hidden; text-overflow: ellipsis; }

/* ---- the phone collapse ----
   At 70rem and below the whole bar folds into one "Menu" button — the
   one place a menu-behind-a-button is right, because the alternative on
   a 400px screen is a bar that is entirely unusable. Above 70rem this
   wrapper is not rendered at all: the menus sit directly in the bar
   (.navbar-wide), never inside a closed <details>. */
/* Above 70rem: the menus in the bar directly (.navbar-wide), and the
   phone wrapper is not rendered at all. See views/layout/head.php. */
.navbar-wide { display: flex; flex: 1; min-width: 0; }
.navwrap { display: none; }
.navwrap > summary { list-style: none; }
.navwrap > summary::-webkit-details-marker { display: none; }

@media (max-width: 70rem) {
  .navbar-wide { display: none; }
  .navwrap { display: block; position: relative; flex: 0 0 auto; }
  .navwrap > summary {
    display: inline-flex;
    align-items: center;
    padding: .35rem .6rem;
    border-radius: 5px;
    color: var(--on-brand-soft);
    cursor: pointer;
    white-space: nowrap;
  }
  .navwrap > summary:hover,
  .navwrap[open] > summary { background: var(--on-brand-press); color: var(--on-accent); }
  .navwrap-inner { display: block; }

  /* Open, the bar becomes a panel under the button rather than a row
     that would need horizontal scrolling to read. */
  .navwrap[open] .navwrap-inner {
    position: absolute;
    top: calc(100% + .35rem);
    left: 0;
    z-index: 60;
    min-width: 14rem;
    padding: .3rem;
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: 7px;
    box-shadow: 0 6px 18px var(--shadow-sm);
  }
  .navwrap[open] .topnav {
    margin-left: 0;
    flex-direction: column;
    align-items: stretch;
    gap: .1rem;
  }
  /* On the white panel the bar's inks are wrong again. */
  .navwrap[open] .topnav-link,
  .navwrap[open] .navgroup-btn { color: var(--ink); }
  .navwrap[open] .topnav-link:hover,
  .navwrap[open] .navgroup-btn:hover { background: var(--sky); color: var(--ink); }
  .navwrap[open] .topnav-link.is-current { background: var(--accent-soft); color: var(--ink); }
  .navwrap[open] .navgroup.is-here > .navgroup-btn {
    color: var(--ink); box-shadow: inset 2px 0 0 0 var(--accent);
  }
  .navwrap[open] .navgroup-btn .navcount {
    background: var(--sky); color: var(--ink-soft); border-color: var(--sky-line);
  }
  /* Nested menus open in place rather than floating off a narrow
     screen. */
  .navwrap[open] .navmenu {
    position: static;
    border: 0;
    box-shadow: none;
    padding: 0 0 .2rem .75rem;
    min-width: 0;
  }

  /* The search box is the first thing to go: it has a page of its own,
     and the claim number can be typed there. */
  .topsearch { display: none; }
}

/* The bar is hidden in print already; stated so nobody adds it back. */
@media print { .navwrap, .navme { display: none; } }

/* The library's "which category?" step (library/upload.php): a short
   list of choices, each one a button. No colour set here. */
.choicelist { list-style: none; padding: 0; margin: 0 0 1rem; }
.choicelist li { display: flex; flex-wrap: wrap; align-items: center; gap: .6rem; margin: .5rem 0; }

/* The library's upload progress (upload.js, data-progress) and its review
   list (library/upload.php). Layout only — no colour set here. */
.uploadprogress { margin: .75rem 0; }
.uploadprogress progress { display: block; width: 100%; height: 1rem; }
.batchlist td { vertical-align: top; }
.batchlist input[type=text] { min-width: 14rem; }
.batchdesc { margin-top: .4rem; }
.batchdesc summary { cursor: pointer; }
