/* IRA PI/PA Portal.

   The look is deliberately the IRA Customer Portal's, so the two halves of the
   same programme feel like one product (#11). Tokens, fonts and the header and
   footer treatment are carried over from that project's app.css unchanged:
   Nunito Sans headings, Open Sans body, Focus blue #034ea2, Focus green
   #00ab4e. #034ea2 is also the Focus Toolbox standard's app-bar blue, so the
   two conventions agree on the one colour that matters.

   What is new here is the CRM shell: a left-hand pane of record types (#11, #17), which
   the customer-facing portal has no need for. See "Sidebar" below. */
:root {
  --blue: #034ea2; --blue-dark: #033f83; --green: #00ab4e; --green-dark: #00913f;
  --ink: #343434; --muted: #5f6b76; --line: #d9e1e8; --bg: #f5f7fa;
  --card: #ffffff; --warn-bg: #fff7e6; --warn-line: #e6c26e; --err: #c0392b;
  --tint: #eaf3ff;
  --sidebar-w: 15rem; --sidebar-w-narrow: 4.25rem;
}
* { box-sizing: border-box; }
body { margin: 0; font: 16px/1.6 "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
       color: var(--ink); background: var(--bg); display: flex;
       min-height: 100vh; flex-direction: column; }
h1, h2, h3, .brand-sub { font-family: "Nunito Sans", Arial, Helvetica, sans-serif; }
.wrap { max-width: 1240px; margin: 0 auto; padding: 0 1.25rem; width: 100%; }

/* Header and footer -- carried over from the customer portal. */
.topbar { background: var(--blue); color: #fff; font-size: .85rem; }
.topbar .wrap { display: flex; justify-content: space-between; align-items: center;
                padding: .35rem 1rem; gap: 1rem; }
.topbar a { color: #fff; font-weight: 600; text-decoration: none; }
.topbar a:hover { text-decoration: underline; }
.site-header { background: var(--card); border-bottom: 3px solid var(--green); }
.site-header .wrap { display: flex; flex-wrap: wrap; align-items: center;
                     justify-content: space-between; gap: .6rem; padding: .7rem 1rem; }
.brand { display: flex; align-items: center; gap: .8rem; text-decoration: none; }
.brand-logo { height: 44px; width: auto; }
.brand-sub { color: var(--blue); font-weight: 800; font-size: 1.02rem;
             border-left: 1px solid var(--line); padding-left: .8rem; }
.env-pill { font-size: .78rem; font-weight: 700; text-transform: uppercase;
            letter-spacing: .04em; color: var(--blue); background: var(--tint);
            border-radius: 999px; padding: .18rem .7rem; }
.site-footer { background: var(--blue); color: #fff; margin-top: 0; }
.site-footer .wrap { padding: 1.1rem 1rem; }
.site-footer a { color: #fff; }
.site-footer .copyright { font-size: .85rem; opacity: .85; margin: .2rem 0 0; }
.site-footer p { margin: .2rem 0; }

/* Record navigation -- the CRM shell. A pane flush against the window's LEFT
   edge (Matt on #17), as tall as the page, with the content taking everything to
   its right. Its links stick to the top of the window while the content scrolls. */
.shell { flex: 1; display: flex; align-items: stretch; width: 100%; gap: 0; }
.sidebar { position: relative; align-self: stretch; flex: 0 0 var(--sidebar-w);
           width: var(--sidebar-w); min-height: calc(100vh - 6.5rem);
           padding: 1.4rem .6rem 1rem; display: flex; flex-direction: column;
           border-right: 1px solid var(--line); background: var(--card); }
.sidebar .pane-links { position: sticky; top: 1rem; }
.sidebar h2 { font-size: .78rem; text-transform: uppercase; letter-spacing: .06em;
              color: var(--muted); margin: 0 0 .6rem .7rem; font-weight: 700; }
.sidebar ul { list-style: none; margin: 0; padding: 0; display: flex;
              flex-direction: column; gap: .2rem; }
.sidebar a { display: flex; align-items: center; gap: .75rem; padding: .6rem .7rem;
             border-radius: 6px; text-decoration: none; color: var(--ink);
             font-weight: 600; font-size: .95rem; border-left: 3px solid transparent; }
.sidebar a:hover { background: #f2f7fd; color: var(--blue); }
.sidebar a:focus-visible { outline: 2px solid var(--blue); outline-offset: 1px; }
.sidebar a .icon { flex: 0 0 20px; width: 20px; height: 20px; color: var(--muted); }
.sidebar a:hover .icon { color: var(--blue); }
/* Exactly one item may carry this: the section being looked at. */
.sidebar a.is-active { background: var(--tint); color: var(--blue);
                       border-left-color: var(--blue); }
.sidebar a.is-active .icon { color: var(--blue); }
/* The line between groups of entries (#130): My queue | the records | Support
   tickets. A border, so it is drawn and never read aloud. */
.sidebar li.rail-divider { border-top: 1px solid var(--line); margin-top: .45rem;
                           padding-top: .45rem; }
/* The bottom padding keeps the last row clear of the fixed account menu. */
.content { flex: 1 1 auto; min-width: 0; padding: 1.6rem clamp(1rem, 3vw, 2.5rem) 6rem; }

/* Below 1024px the rail keeps the icons and drops the words. The link's
   aria-label carries the name, so the accessible name is unchanged. */
@media (max-width: 1024px) {
  .sidebar { flex-basis: var(--sidebar-w-narrow); width: var(--sidebar-w-narrow);
             padding-left: .4rem; padding-right: .4rem; }
  .sidebar h2 { display: none; }
  .sidebar a { justify-content: center; gap: 0; padding: .65rem .3rem; }
  .sidebar a .label { display: none; }
}

/* Page furniture -- carried over from the customer portal. */
h1 { color: var(--blue); font-size: 1.75rem; font-weight: 800; margin: .2rem 0 .9rem; }
h2 { color: var(--blue); font-size: 1.2rem; font-weight: 700; margin: 0 0 .5rem; }
.lede { color: var(--muted); max-width: 46rem; margin-top: 0; }
.card { background: var(--card); border: 1px solid var(--line); border-radius: 8px;
        padding: 1.25rem 1.5rem; margin: 1rem 0; box-shadow: 0 1px 3px rgba(3,78,162,.06); }
.page-head { display: flex; align-items: center; justify-content: space-between;
             flex-wrap: wrap; gap: .8rem; }
.button { display: inline-block; border: 2px solid var(--blue); background: #fff;
          color: var(--blue); padding: .55rem 1.4rem; border-radius: 4px; font: inherit;
          font-family: "Nunito Sans", sans-serif; font-weight: 700;
          text-decoration: none; cursor: pointer; }
.button:hover { background: #f2f7fd; }
.button.primary { background: var(--green); border-color: var(--green); color: #fff; }
.button.primary:hover { background: var(--green-dark); border-color: var(--green-dark); }
/* The decisions that are not Approve, at the head of an application (#151,
   Matt: "The buttons for 'assign', 'send back for more information', and
   'deny' are red buttons"). White on #b42318 is 6.5:1. A disabled one still
   turns grey: `.button:disabled` comes later in this file. */
.button.danger { background: #b42318; border-color: #b42318; color: #fff; }
.button.danger:hover { background: #8f1c13; border-color: #8f1c13; }
.small { font-size: .85rem; color: var(--muted); }
.hint { color: var(--muted); font-size: .9rem; margin: .3rem 0 0; }
.badge { display: inline-block; padding: .18rem .75rem; border-radius: 999px;
         font-size: .85rem; font-weight: 700; background: #e8edf1; }
.badge.type { background: var(--tint); color: var(--blue); font-weight: 600; }
.notice { background: var(--warn-bg); border: 1px solid var(--warn-line);
          border-radius: 6px; padding: .75rem .95rem; }
.notice.ok { background: #dff3e8; border-color: #9fd4bb; }

/* Empty states. Three different things look identical if you let them: a list
   with nothing in it, a list that failed to load, and a list you are not
   allowed to see. Each gets its own words. */
.state { text-align: center; padding: 2.4rem 1.4rem; }
.state .icon { width: 34px; height: 34px; color: var(--muted); opacity: .65; }
.state h2 { margin-top: .7rem; }
.state p { color: var(--muted); max-width: 34rem; margin: .3rem auto 0; }
.state.is-error { border-color: var(--warn-line); background: var(--warn-bg); }
.state.is-error h2 { color: #8a6116; }

/* Element 7 of the Focus Toolbox App Layout Standard: a control that changes
   something shows it is working. No control in this app changes anything yet;
   these rules ship with app/static/busy.js so the first one that does inherits
   both. */
.spinner { display: inline-block; width: .85em; height: .85em; border-radius: 50%;
           border: 2px solid currentColor; border-right-color: transparent;
           animation: spin .6s linear infinite; vertical-align: -.1em; }
@keyframes spin { to { transform: rotate(360deg); } }
[aria-busy="true"] { cursor: progress; }
[aria-disabled="true"] { opacity: .65; pointer-events: none; }
.field-error { color: var(--err); font-weight: 600; font-size: .9rem; margin: .4rem 0 0; }

/* The red dot on a rail entry that has work assigned to you (#73). It carries
   the number, because "how many" is the thing that decides whether to start
   now or later. No new colour: --err is the red the stylesheet already has.
   `margin-left: auto` pushes it to the far edge of the link, so it still reads
   as a badge when the words are hidden below 1024px and only the icon shows. */
.rail-dot { margin-left: auto; min-width: 1.35rem; height: 1.35rem; padding: 0 .35rem;
            display: inline-flex; align-items: center; justify-content: center;
            border-radius: 999px; background: var(--err); color: #fff;
            font-size: .72rem; font-weight: 700; line-height: 1; flex: none; }
/* Could not be read, so it must not look like a number and must not look like
   a zero (#73, AC 4.1). */
.rail-dot.unknown { background: var(--muted); }
/* The number just went UP while the page was open (#179): a short pulse, played
   twice and then still -- a badge that never stops moving is one people learn
   to ignore. queue-count.js adds `is-new` and takes it off when it ends. */
.rail-dot.is-new { animation: rail-dot-pulse .8s ease-out 2; }
@keyframes rail-dot-pulse {
  0%   { transform: scale(1);    box-shadow: 0 0 0 0 rgba(192, 57, 43, .55); }
  45%  { transform: scale(1.35); box-shadow: 0 0 0 .45rem rgba(192, 57, 43, 0); }
  100% { transform: scale(1);    box-shadow: 0 0 0 0 rgba(192, 57, 43, 0); }
}
/* With reduce motion on, nothing moves: the new number keeps a ring instead,
   until the person opens My queue (#179, criterion 2.2). */
.rail-dot.is-flagged { outline: 2px solid var(--err); outline-offset: 2px; }
@media (prefers-reduced-motion: reduce) {
  .rail-dot.is-new { animation: none; }
}

/* Search and lists of records (#8). */
/* The search bar (#17): one sleek row in the portal's own colours. A rounded
   field with a magnifier and the customer portal's #b9c4cd border, a soft Focus
   blue glow on focus, the Search button the same height and shape, and Clear as a
   quiet link rather than a second button. */
.search { display: flex; flex-wrap: wrap; align-items: center; gap: .6rem;
          margin: 1rem 0 1.3rem; max-width: 44rem; }
.search input[type="search"] { flex: 1 1 18rem; min-width: 0; box-sizing: border-box;
                               height: 2.75rem; font: inherit; font-weight: 400; color: var(--ink);
                               padding: 0 1rem 0 2.6rem; border: 1px solid #b9c4cd; border-radius: 999px;
                               background: #fff url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='18' height='18' viewBox='0 0 24 24' fill='none' stroke='%235f6b76' stroke-width='2' stroke-linecap='round'%3E%3Ccircle cx='11' cy='11' r='7'/%3E%3Cpath d='m20 20-3.5-3.5'/%3E%3C/svg%3E") no-repeat 1rem center;
                               box-shadow: 0 1px 2px rgba(3,78,162,.06);
                               transition: border-color .15s, box-shadow .15s; }
.search input[type="search"]::placeholder { color: #8a96a1; }
.search input[type="search"]:hover { border-color: #8fa3b4; }
.search input[type="search"]:focus-visible { outline: none; border-color: var(--blue);
                                             box-shadow: 0 0 0 3px rgba(3,78,162,.18); }
.search .button { box-sizing: border-box; height: 2.75rem; display: inline-flex;
                  align-items: center; padding: 0 1.4rem; border-radius: 999px; }
.search .clear { color: var(--muted); font-weight: 600; text-decoration: none; padding: 0 .3rem; }
.search .clear:hover { color: var(--blue); text-decoration: underline; }
.visually-hidden { position: absolute; width: 1px; height: 1px; overflow: hidden;
                   clip: rect(0 0 0 0); white-space: nowrap; }
.notice.sample { margin: 1rem 0; }
.result-count { margin: .2rem 0 0; }
/* position: relative (#131): a .visually-hidden header ("Actions") is absolutely
   positioned, and without a containing block here it escaped the scroll box and
   widened the whole page on a phone -- /teams by 36px, /settings/roles by 104px. */
.table-card { padding: 0; overflow-x: auto; position: relative; }
table.records { width: 100%; border-collapse: collapse; font-size: .95rem; }
table.records th, table.records td { text-align: left; padding: .65rem 1rem;
                                     border-bottom: 1px solid var(--line); vertical-align: top; }
table.records th { font-family: "Nunito Sans", Arial, sans-serif; font-size: .78rem;
                   text-transform: uppercase; letter-spacing: .05em; color: var(--muted);
                   background: #fafbfd; font-weight: 700; }
table.records tbody tr:last-child td { border-bottom: 0; }
table.records tbody tr:hover { background: #f8fbff; }
table.records .num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
.close-spelling { color: #8a6116; font-weight: 600; }
.pager { display: flex; align-items: center; justify-content: space-between; gap: .8rem;
         margin: .4rem 0 1rem; }
.back { margin: 0 0 .4rem; }
h2.section { margin-top: 1.8rem; }
dl.facts { display: grid; grid-template-columns: max-content 1fr; gap: .3rem 1.4rem; margin: 0; }
dl.facts dt { color: var(--muted); font-weight: 600; }
dl.facts dd { margin: 0; overflow-wrap: anywhere; }
/* Qualification status, four colours (#95): grey before anything happens,
   yellow the whole time it is in flight, green once it is approved, red once it
   is denied.

   Matt answered B to #95's question 3 -- "Yellow for all three. Red only when an
   application is Denied" -- so Submitted, Processing and Corrections required
   wear the same yellow as In progress. Red is kept for the one status that
   means stopped, which is what makes it worth noticing.
   The words are not ours to change: they are read from a pinned copy of
   IRA_Customer_Portal's file (#39). This is colour only.

   These declarations say what each status IS. They do not win on their own --
   see the override further down, which is what actually paints them. The
   selectors here are shared with #92 byte for byte so the two branches merge to
   one rule; #92's tests pin them.*/
.badge.status { font-weight: 700; white-space: nowrap; }
.badge.st-none, .badge.st-not_started { background: #eef1f4; color: var(--muted); }
.badge.st-in_progress, .badge.st-documents_submitted,
.badge.st-in_review, .badge.st-needs_more_info { background: var(--warn-bg); color: #8a6116; }
.badge.st-approved { background: #dff3e8; color: #0b6b36; }
.badge.st-denied { background: #fbe4e1; color: #9b2c20; }
/* Sign-in (#6). The account menu is Control Center's; element 5 of the Toolbox
   standard fixes where it sits and what its card looks like. */
.signed-in { opacity: .95; }
.signed-in .preview { font-weight: 700; }
/* The account menu and app switcher: a solid white card fixed to the LOWER
   LEFT of the window -- element 5 of the Toolbox standard, card and place
   (#fff, #e5e7eb border, soft shadow). Matt on #25 moved it back from the lower
   right (#17). Nothing in this stylesheet may hide it. */
.cc-dock { position: fixed; left: 1rem; bottom: 1rem; z-index: 50; padding: 6px 8px;
           background: #fff; border: 1px solid #e5e7eb; border-radius: 10px;
           box-shadow: 0 4px 16px rgba(0,0,0,.10); }

@media (max-width: 560px) { .brand-sub { display: none; } }

/* Qualification (#9). Tables, forms and the stage ladder. */
.table-wrap { overflow-x: auto; }
.grid { width: 100%; border-collapse: collapse; font-size: .95rem; }
.grid th { text-align: left; color: var(--muted); font-size: .8rem; text-transform: uppercase;
           letter-spacing: .04em; border-bottom: 2px solid var(--line); padding: .5rem .6rem; }
.grid td { border-bottom: 1px solid var(--line); padding: .6rem; vertical-align: top; }
.fields { display: grid; grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr));
          gap: .9rem 1.2rem; margin: .8rem 0 1rem; }
.field { display: flex; flex-direction: column; gap: .3rem; margin-bottom: .8rem; }
.field label { font-weight: 600; font-size: .92rem; }
.field input, .field textarea { font: inherit; padding: .5rem .6rem; border: 1px solid #b9c6d2;
                                border-radius: 4px; background: #fff; color: var(--ink); }
.field input:focus-visible, .field textarea:focus-visible { outline: 2px solid var(--blue); outline-offset: 1px; }
.actions { display: flex; flex-wrap: wrap; gap: .6rem; }
.ladder { display: flex; flex-wrap: wrap; gap: .4rem; list-style: none; padding: 0; margin: .8rem 0 0; }
.ladder li { font-size: .82rem; padding: .15rem .6rem; border-radius: 999px; background: #eef2f5;
             color: var(--muted); }
.ladder li.is-current { background: var(--blue); color: #fff; font-weight: 700; }
.badge.status { background: #eef2f5; color: var(--ink); }
.badge.status-needs_more_info { background: var(--warn-bg); color: #8a6116; }
.badge.status-in_review { background: var(--tint); color: var(--blue); }
.notice.is-problem { background: var(--warn-bg); border-color: var(--warn-line); margin-bottom: 1rem; }
.facts { display: grid; grid-template-columns: max-content 1fr; gap: .3rem 1rem; }
.facts dt { font-weight: 600; }
.facts dd { margin: 0; }
/* Confirming what kind of property this is (#40). */
.badge.status.st-pending_review { background: var(--warn-bg); color: #8a6116; }
.badge.status.st-confirmed { background: #dff3e8; color: #0b6b36; }
.badge.status.st-none { background: #eef1f4; color: var(--muted); }

/* WHAT ACTUALLY PAINTS A STATUS PILL (#95, second build).

   Matt, on the first build: "status tag column need color in my queue yet". He
   was right, and the rules near the top of this file were not the reason:
   `.badge.status` is redefined a few lines above with a background and a colour
   of its own. That is TWO classes, exactly as many as `.badge.st-*`, and it
   comes AFTER them -- so it won the cascade and every pill rendered grey, on My
   queue, Properties and Accounts alike, and had done since long before this
   ticket. Resolving the cascade over the old stylesheet gives #eef2f5 for all
   seven statuses, which is the grey he was looking at.

   Three classes wins wherever the rule sits, which is the trick the three
   type-check badges above already use. The colours are deliberately repeated
   rather than moved: the block at the top is where a person reads what a status
   means, and #92 shares those exact selectors, so moving them would break a
   branch that is in test beside this one. The two blocks must agree.

   It also survives a bundle merge. A bundle that re-applies a branch cut before
   a colour change can leave the older two-class rules sitting after the newer
   ones -- that happened on test-deploy/issue-92-95-and-93@9711ca6 and put
   Submitted and Processing back to blue. This cannot be undone by the order two
   branches happen to merge in.

   tests/test_issue_95.py resolves the cascade the way a browser does and
   asserts the winner, because a test that greps for the rule text passes while
   the page is grey -- which is how this shipped the first time. */
.badge.status.st-not_started { background: #eef1f4; color: var(--muted); }
.badge.status.st-in_progress, .badge.status.st-documents_submitted,
.badge.status.st-in_review, .badge.status.st-needs_more_info { background: var(--warn-bg); color: #8a6116; }
.badge.status.st-approved { background: #dff3e8; color: #0b6b36; }
.badge.status.st-denied { background: #fbe4e1; color: #9b2c20; }
/* A support ticket (#104): open is new work, closed is finished. In progress
   reuses the amber above. Two classes, like the rest of this block. */
.badge.status.st-open { background: var(--tint); color: var(--blue); }
.badge.status.st-closed { background: #eef1f4; color: var(--muted); }
.ticket-body { white-space: pre-wrap; }

/* Everything on an application (#29). */
.answers h3, .measure h3 { font-size: 1rem; margin: 1.1rem 0 .4rem; color: var(--ink); }
.answers h3:first-of-type, .measure:first-of-type h3 { margin-top: .4rem; }
/* A Program administrator's boxes under the answers (#99): the same box as
   every other field, sized to the answer rather than the whole row. */
.card dl.facts input[type=text] { font: inherit; padding: .35rem .5rem; border: 1px solid #b9c6d2;
  border-radius: 4px; width: 100%; max-width: 28rem; background: #fff; }
.card dl.facts input[type=text]:focus-visible { outline: 2px solid var(--blue); outline-offset: 1px; }
.card dl.facts dt label { cursor: pointer; }
.measure { border-top: 1px solid var(--line); padding-top: .4rem; }
.measure:first-of-type { border-top: 0; }
.measure .facts { margin-bottom: .4rem; }
.timeline { list-style: none; padding: 0; margin: 0; }
.timeline li { border-left: 3px solid var(--line); padding: .2rem 0 .7rem .8rem; }
.timeline li p { margin: .3rem 0 0; }
.permission.is-revoked { color: var(--muted); }
.status-link { text-decoration: none; }
.status-link:hover .badge, .status-link:focus-visible .badge { outline: 2px solid var(--blue); outline-offset: 1px; }

/* Emails about an application (#20). */
.messages { list-style: none; margin: 0; padding: 0; }
.messages li { border-bottom: 1px solid var(--line); padding: .6rem 0; }
.messages li p { margin: .2rem 0; }
.message-body { white-space: pre-wrap; font-family: inherit; margin: .4rem 0 0; }
.filters { margin: .6rem 0 1rem; }

/* Households' income-qualification statuses (#39). Three colours, not eight:
   the question a reviewer asks first is whether a case is finished. */
/* The income tag on an application (#53). "Not decided yet" wears the same grey
   every other undecided badge wears, because it is not an answer; market rate
   IS an answer, so it is coloured like one. */
.badge.income { font-weight: 700; white-space: nowrap; }
.badge.in-low { background: #dff3e8; color: #0b6b36; }
.badge.in-moderate { background: var(--tint); color: var(--blue); }
.badge.in-market_rate { background: #f3eefc; color: #5b3fa0; }
.badge.in-not_decided { background: #eef1f4; color: var(--muted); }

.badge.iq-open { background: var(--tint); color: var(--blue); }
.badge.iq-approved { background: #dff3e8; color: #0b6b36; }
.badge.iq-closed { background: #fbe4e1; color: #9b2c20; }

/* Contractor registration statuses (#25), in the same family as the qualification badges. */
.badge.st-draft { background: #eef1f4; color: var(--muted); }
.badge.st-submitted { background: var(--tint); color: var(--blue); }
.badge.st-declined { background: #fbe4e1; color: #9b2c20; }

/* Applications entered on the customer portal's test site, shown on the live site
   until households can sign in there (#28). The banner that stood above those
   records was removed by #41; the tag beside each record stays. */

/* The map link, beside the question it helps answer (#56). */
/* Room between the map button and the confirm button (#92, Matt: "Add spacing
   between google maps and confirm button"). */
.map-link { margin: .8rem 0 1.1rem; }

/* Double-click a row to open its record (#56). The class is added by rows.js
   once it has found a row with somewhere to go, so a page without JavaScript --
   or a list whose rows open nothing -- never shows a pointer that lies. */
table.records.is-openable tbody tr { cursor: pointer; }

/* The reservation review checklist (#31). One line per item, its answer first,
   so a reviewer picks up where the last one stopped without reading the lot. */
.card.sub { box-shadow: none; border: 1px solid var(--line); margin: 1rem 0; }
.checklist .readings { display: grid; grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); gap: 1rem; }
.checklist-section { margin-top: 1.6rem; }
.checklist-section h3 { margin-bottom: .2rem; }
.checklist ol.items { list-style: none; margin: 0; padding: 0; }
.checklist .item { border-top: 1px solid var(--line); padding: .8rem 0; }
.checklist .item-head { display: flex; gap: .6rem; align-items: baseline; }
.checklist .item-text { font-weight: 600; }
.checklist .item.is-failed { border-left: 3px solid #9b2c20; padding-left: .8rem; }
.checklist .item.is-done .item-text { font-weight: 400; }
.checklist .answered-by { color: var(--muted); }
.checklist .notice.flag { margin: .6rem 0; }
.checklist form.answer { display: flex; flex-wrap: wrap; gap: .5rem; margin-top: .5rem; }
.checklist form.answer input[type=text] { flex: 1 1 18rem; }
/* The federal income limits beside a decision (#26). */
/* Two columns of cards on the Income qualification review tab (#101, Matt's
   third look: "there can be two columns of card in main panel so user does not
   need to scroll as much"). Each card keeps its own height; the pair collapses
   to one column where two would not fit. */
.card-columns { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 1rem 1.2rem;
                align-items: start; margin: 1rem 0; }
.card-columns > .card, .card-stack > .card { margin: 0; }
/* A column of cards inside the grid (the decision and the limits it is made
   against), and a card too wide for half the panel, spanning both columns. */
.card-stack { display: grid; gap: 1rem 1.2rem; align-content: start; min-width: 0; }
/* A grid item's minimum width is its content's unless told otherwise, and a
   table's is its widest row -- so without this the right column pushes past
   the panel and the page scrolls sideways. */
.card-columns > *, .card-stack > * { min-width: 0; }
.card-columns .table-card { overflow-x: auto; }
.card-columns > .span-2 { grid-column: 1 / -1; }
/* Inside a half-width column the limits table's headings may wrap and its
   cells sit closer, so all three of its columns stay in view. */
.card-columns table.records th.num, .card-columns table.records th { white-space: normal; }
.card-columns table.records th, .card-columns table.records td { padding: .55rem .6rem; }
@media (max-width: 1100px) { .card-columns { grid-template-columns: 1fr; } }
/* The buildings inside Documents by unit sit two abreast when there is room. */
.dbu-buildings { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(30rem, 100%), 1fr)); gap: 1.2rem 1.5rem; }
.dbu-building > h3 { margin: .2rem 0 0; }
.dbu-building > h4 { margin: .8rem 0 .3rem; }
.card.federal-limits .table-card { margin-top: .9rem; padding: 0; box-shadow: none; }
.card.federal-limits .state { padding: 1.6rem 1rem; }

.badge.mark { font-weight: 700; white-space: nowrap; }
.badge.mk-none { background: #eef1f4; color: var(--muted); }
.badge.mk-done { background: #dff3e8; color: #0b6b36; }
.badge.mk-not_applicable { background: var(--tint); color: var(--blue); }
.badge.mk-failed { background: #fbe4e1; color: #9b2c20; }
/* A control that cannot do its job yet reads as unavailable, but keeps its
   focus and still answers when pressed (Toolbox standard, element 7). */
.button[aria-disabled="true"], .button:disabled { background: #eef1f4; border-color: var(--line);
  color: var(--muted); }
/* A truly disabled button (#141: Approve before the rule is met) cannot be
   pressed at all, and says so to the pointer too. */
.button:disabled { cursor: not-allowed; }

/* The reservation review panel (#47). It slides out from the RIGHT-HAND edge
   of the window, so the application stays readable while the list is ticked.

   Two things it must not disturb, both acceptance criteria: the record
   navigation stays flush against the LEFT edge (#17), and Control Center's
   account menu stays fixed in the lower left (element 5 of the Toolbox
   standard, Matt on #25). Neither is touched here -- the panel is fixed to the
   opposite edge and the only thing that ever moves is the content column's
   right padding, and then only on a window wide enough to spare it.

   Before app/static/panel.js runs, the panel is an ordinary block in the page:
   open, in flow, every check reachable. `.is-enhanced` is added by that script,
   and only then does it become a panel that can be shut. */
.review-open { display: inline-flex; align-items: center; gap: .55rem; }
.review-open .count { font-weight: 400; color: var(--muted); }
.review-panel { margin: 1rem 0; }
.review-panel .panel-head { display: flex; align-items: baseline;
                            justify-content: space-between; gap: 1rem; }
.review-panel .panel-head .close { display: none; }

.review-panel.is-enhanced {
  position: fixed; top: 0; right: 0; z-index: 40;
  width: min(34rem, 100vw); height: 100vh; margin: 0;
  display: flex; flex-direction: column;
  background: var(--card); border-left: 1px solid var(--line);
  box-shadow: -8px 0 24px rgba(3,78,162,.10);
  transform: translateX(100%); transition: transform .18s ease-out;
  overflow-y: auto; overscroll-behavior: contain;
  padding: 1.25rem 1.5rem 4rem;
}
.review-panel.is-enhanced .panel-head { display: flex; position: sticky; top: 0;
  background: var(--card); padding: .2rem 0 .6rem; margin: 0 0 .4rem;
  border-bottom: 1px solid var(--line); z-index: 1; }
.review-panel.is-enhanced .panel-head .close { display: inline-block; }
.review-panel.is-enhanced.is-open { transform: translateX(0); }
/* Shut, it is not scrolled into, tabbed into or read out. `inert` does this
   properly where the browser has it; this is the floor everywhere else. */
.review-panel.is-enhanced:not(.is-open) { visibility: hidden; }
.review-panel.is-enhanced:focus { outline: none; }
/* The card inside loses its own frame: the panel is the frame. Answers to check
   joined the checklist in a panel on #75, and takes the same treatment. */
.review-panel.is-enhanced .card.checklist,
.review-panel.is-enhanced .card.corrections { border: 0; box-shadow: none;
  padding: 0; margin: 0; background: transparent; }

/* Only a window with room to spare gives it up. Narrower, the panel sits over
   the page rather than squeezing the application into a column. */
@media (min-width: 1200px) {
  .shell.has-panel .content { padding-right: calc(min(34rem, 100vw) + 1.5rem); }
}
@media (prefers-reduced-motion: reduce) {
  .review-panel.is-enhanced { transition: none; }
}

/* The application's tabs (#75). Matt answered B to question 2: every review
   that was a card becomes its own tab, and the Information tab holds the
   application's own facts.

   They are ORDINARY LINKS, each with its own address, so a tab works with no
   JavaScript at all, can be opened in a new window, and a failed save can
   re-render on the tab it was made from. Nothing here is a script's job. */
.tabs { display: flex; flex-wrap: wrap; gap: .25rem; margin: 0 0 1rem;
        border-bottom: 1px solid var(--line); }
.tabs a { display: inline-flex; align-items: center; gap: .45rem;
          padding: .55rem .9rem; border: 1px solid transparent; border-bottom: 0;
          border-radius: .4rem .4rem 0 0; margin-bottom: -1px;
          color: var(--muted); text-decoration: none; font-weight: 600; }
.tabs a:hover { color: var(--ink); background: #f4f6f8; }
/* The open tab is joined to the page below it: it carries the frame and then
   paints over the shared border, so the two read as one surface. */
.tabs a[aria-current="page"] { color: var(--ink); background: var(--card);
  border-color: var(--line); border-bottom: 1px solid var(--card); }
.tabs a .count { font-weight: 400; color: var(--muted); }
/* The work tabs are numbered steps (#93, Matt's second look), and the number
   carries where the journey has got to -- the job #89's bar did above the
   tabs, which the numbers replace. Matt's third look chose the drawing: the
   number stays, and a coloured ring round it says its state -- green done,
   yellow still pending, grey not started, red when something is wrong. The
   shade is never the only carrier: the tab's title says the state in words. */
.tabs a[data-step]::before { content: attr(data-step); display: inline-flex;
  align-items: center; justify-content: center; flex: 0 0 auto;
  width: 1.35rem; height: 1.35rem; border-radius: 50%; box-sizing: border-box;
  border: 2px solid #b9c2cc; background: #fff; color: var(--muted);
  font-size: .74rem; font-weight: 700; line-height: 1; }
.tabs a[data-tone="done"]::before { border-color: var(--green); color: #0b6b36; background: #dff3e8; }
.tabs a[data-tone="pending"]::before { border-color: #d9a520; color: #7a5a0c; background: #fff4d6; }
.tabs a[data-tone="not_started"]::before { border-color: #b9c2cc; color: var(--muted); background: #fff; }
.tabs a[data-tone="problem"]::before { border-color: #c0392b; color: #8f2a20; background: #fbe4e1; }
.tabs a[data-state="current"] { color: var(--ink); }
.tabs a[data-state="not_coming"] { opacity: .65; text-decoration: line-through; }
/* A building application's own decisions, under its tabs (#165): what is
   pressed there acts on that tab's step. Left-aligned, like the tab it serves. */
.tab-actions { display: flex; flex-wrap: wrap; gap: .5rem; align-items: center;
               margin: 0 0 1rem; }

/* A check the procedure does not ask for on THIS application is shown, greyed,
   and says why -- never hidden. A missing document check that vanished would be
   indistinguishable from one nobody looked at (#47, criterion 3.3). */
.checklist .item.is-not-required .item-text { font-weight: 400; color: var(--muted); }
.badge.mk-not-required { background: #eef1f4; color: var(--muted); font-weight: 600; }
.checklist .why-not-required { color: var(--muted); font-style: italic; }
/* The six markup questions sit under the check they belong to, as a list. */
.checklist .item ul.guidance { margin: .4rem 0 0; padding-left: 1.1rem; color: var(--muted);
  font-size: .9rem; }
.checklist .item ul.guidance li { margin: .15rem 0; }
/* Pre-approval: two review queues, their clocks, and the errors (#33).

   The clock is the thing a reviewer scans for, so overdue is the only colour on
   the row and it sits beside the date rather than replacing it -- "how late" is
   the question, and hiding the date to show a badge answers a different one. */
.badge.stage { font-weight: 700; white-space: nowrap; }
.badge.sg-not_started { background: #eef1f4; color: var(--muted); }
.badge.sg-in_progress { background: var(--warn-bg); color: #8a6116; }
.badge.sg-review_1, .badge.sg-review_2 { background: var(--tint); color: var(--blue); }
.badge.sg-pre_approved { background: #dff3e8; color: #0b6b36; }
.badge.due-overdue { background: #fbe4e1; color: #9b2c20; font-weight: 700; }
.badge.due-check_on { background: #fbe4e1; color: #9b2c20; font-weight: 700; }
tr.is-overdue td { background: #fdf4f3; }
.queue-tabs { margin: .6rem 0 1rem; }
.pre-approval .gates { list-style: none; margin: .6rem 0 0; padding: 0; }
.pre-approval .gates li { padding: .35rem 0; display: flex; gap: .5rem; align-items: baseline; }
.pre-approval .gate-open { color: #0b6b36; font-weight: 700; }
.pre-approval .gate-shut { color: #9b2c20; font-weight: 700; }
.pre-approval .gate-unknown { color: #8a6116; font-weight: 700; }
.errors { list-style: none; margin: 0; padding: 0; }
.errors > li { border-top: 1px solid var(--line); padding: .8rem 0; }
.errors > li:first-child { border-top: 0; }
.errors .is-open { border-left: 3px solid #9b2c20; padding-left: .8rem; }
.errors .what { font-weight: 600; }
.errors .whom { color: var(--muted); }
.error-rows { display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); gap: 1rem; }
.reviewers { list-style: none; margin: 0; padding: 0; }
.reviewers > li { display: flex; flex-wrap: wrap; gap: .6rem; align-items: baseline;
  border-top: 1px solid var(--line); padding: .5rem 0; }
.reviewers > li:first-child { border-top: 0; }
.reviewers .removed { color: var(--muted); text-decoration: line-through; }

/* Whether a property's type has been checked, shown in the Addresses table
   instead of on a screen of its own (#52). */
.badge.check { font-weight: 600; white-space: nowrap; }
.badge.ck-confirmed { background: #dff3e8; color: #0b6b36; }
.badge.ck-pending_review, .badge.ck-none { background: var(--warn-bg); color: #8a6116; }

/* The Qualifications controls belong to the page (#55).

   They used to sit inside the multifamily section, which made them read as that
   table's controls. Now they sit under the page heading, above both tables, so
   they need the spacing of page furniture rather than of something inside a
   section -- and the first section heading below them must not crowd them. */
.filters.actions + .section { margin-top: 1.4rem; }
/* Dropdowns, at last, look like the boxes beside them (#54).

   Matt on #54: "also make the select dropdown match the rest of the theme. do
   not repeat this mistake again." Every `select` in the portal is covered by
   this one rule -- the assignment pop-up, the correction pop-up's entry list
   and the qualification screens all use the same control, so they are fixed
   together rather than one at a time. The arrow is drawn here rather than left
   to the browser so the control is the same height as a text box on every
   platform. */
.field select, .team-card select {
  font: inherit; padding: .5rem 2rem .5rem .6rem; border: 1px solid #b9c6d2;
  border-radius: 4px; background: #fff; color: var(--ink);
  -webkit-appearance: none; -moz-appearance: none; appearance: none;
  background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%235b6b7a' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right .5rem center;
  background-size: 1.1rem;
}
.field select:focus-visible, .team-card select:focus-visible { outline: 2px solid var(--blue); outline-offset: 1px; }
.field select:disabled, .team-card select:disabled { background-color: #eef1f4; color: var(--muted); }

/* Correcting and assigning, in a pop-up (#54).

   Before app/static/dialog.js runs this is an ordinary block at the foot of the
   page with its own heading, and the control that opens it is an in-page link
   that jumps to it -- so the forms work with no JavaScript at all, which is the
   same bargain the review panel makes. `.is-enhanced` is added by that script,
   and only then does it become something that covers the page. */
.dialog { margin: 1rem 0; }
.dialog .dialog-head { display: flex; align-items: baseline;
                       justify-content: space-between; gap: 1rem; }
.dialog .dialog-head .close { display: none; }
.dialog.is-enhanced {
  position: fixed; inset: 0; z-index: 50; margin: 0;
  display: none; align-items: flex-start; justify-content: center;
  background: rgba(15, 32, 48, .45); padding: 4vh 1rem;
  overflow-y: auto; overscroll-behavior: contain;
}
.dialog.is-enhanced.is-open { display: flex; }
.dialog.is-enhanced .dialog-card {
  background: var(--card); border-radius: 8px; border: 1px solid var(--line);
  box-shadow: 0 12px 32px rgba(3, 78, 162, .18);
  padding: 1.25rem 1.5rem 1.5rem; width: min(38rem, 100%);
}
.dialog.is-enhanced .dialog-head { position: sticky; top: 0; background: var(--card);
  padding-bottom: .6rem; margin-bottom: .6rem; border-bottom: 1px solid var(--line); }
.dialog.is-enhanced .dialog-head .close { display: inline-block; }
.dialog.is-enhanced:focus { outline: none; }
/* The page behind an open pop-up does not scroll under it. */
body.has-dialog { overflow: hidden; }

/* The one filter control that replaced each list's row of filter buttons (#95).
   The funnel says what it does; the words beside it say which filter is on, so
   a narrowed list never reads as the whole list. */
.filter-control { margin: .2rem 0 1rem; }
.filter-open { display: inline-flex; align-items: center; gap: .5rem;
               border-radius: 999px; padding: .45rem 1.1rem; }
.filter-open .icon { width: 1.15rem; height: 1.15rem; flex: none; }
.filter-current { font-weight: 700; }
/* Before dialog.js runs these are an ordinary block of links further down the
   page, which is what keeps every filter reachable with no JavaScript. */
.filter-choices { list-style: none; margin: 0; padding: 0;
                  display: flex; flex-direction: column; gap: .5rem; }
.filter-choices .button { display: block; text-align: left; }

/* What kind of record a row of My queue is (#95). The icon is the rail's own,
   and the entity is written beside it -- the picture is never the only way to
   tell one kind of work from another. */
.entity { display: inline-flex; align-items: center; gap: .45rem; white-space: nowrap; }
.entity .icon { width: 1.05rem; height: 1.05rem; flex: none; color: var(--muted); }

/* The row actions that open them. They are links, so they still work with no
   JavaScript; they are drawn as buttons because that is what they do. */
.row-actions { display: flex; flex-wrap: wrap; gap: .4rem; }
.row-actions .button { padding: .25rem .6rem; font-size: .85rem; }
.page-head .head-actions { display: flex; flex-wrap: wrap; gap: .5rem; align-items: center; }

/* One story of an application, in the side panel (#54). The kind of thing that
   happened is the only colour: the customer portal's own steps, what staff did,
   and the emails. */
.timeline li.tl-staff { border-left-color: var(--blue); }
.timeline li.tl-message { border-left-color: #0b6b36; }
.timeline li .badge.status { margin-right: .4rem; }
.timeline li p { white-space: pre-wrap; }
/* When it happened and who did it, first and readable (#72). It used to render
   through .small in muted grey under the title; the ticket asks for the time as
   primary information, so it leads the entry at full contrast. */
.tl-when { margin: 0 0 .25rem; font-size: .92rem; color: var(--ink); }
.timeline li .tl-when { font-weight: 600; }

/* The offer letter and the contractor's changes to a pre-approved project (#36).
   The comparison table is the point of the card: the approved version and the
   requested one, with only what actually differs marked. */
.badge.project { font-weight: 700; white-space: nowrap; }
.badge.ps-pre_approved { background: #dff3e8; color: #0b6b36; }
.badge.ps-not_pre_approved { background: #eef1f4; color: var(--muted); }
.badge.ps-cancelled { background: #fbe4e1; color: #9b2c20; }
.card.sub { border: 1px solid var(--line); box-shadow: none; margin-top: 1rem; }
.offers table.compare th[scope="row"] { text-align: left; font-weight: 600; white-space: nowrap; }
.offers table.compare tr.is-changed { background: var(--warn-bg); }
.offers ul.gates { list-style: none; padding: 0; margin: .5rem 0; }
.offers ul.gates li { padding: .35rem 0; border-bottom: 1px solid var(--line); }
.offers ul.gates li.is-not_built { color: var(--muted); }
.offers ul.changes li.is-rejected, .offers ul.changes li.is-withdrawn { opacity: .75; }
pre.letter { white-space: pre-wrap; word-wrap: break-word; font-family: inherit;
             background: #fbfcfd; border: 1px solid var(--line); border-radius: 6px;
             padding: 1rem; line-height: 1.55; }
/* The user-story and test table (#62). The story page lays the three columns
   out as facts rather than as a form, because most visits only read them.

   Scoped to that page (#98, Matt's comment with the screenshot): written bare,
   these rules reached every `dl.facts` on the portal, and the .9rem top margin
   on a <dt> with .2rem on its <dd> pushed the two columns of the grid out of
   step, so each label sat lower than its value. */
.story-page .facts { margin: 0; }
.story-page .facts dt { font-weight: 700; color: var(--muted); font-size: .85rem;
            margin-top: .9rem; }
.story-page .facts dt:first-child { margin-top: 0; }
.story-page .facts dd { margin: .2rem 0 0; }
.records td.num a { font-weight: 700; }

/* How far a building has got towards the 50% rule (#83).

   Four shades, not two: Matt answered question 2 with A, so a home nobody has
   documented is told apart from one that is documented and above the threshold.
   Reusing the tokens the status badges already use, so a qualified home is the
   same green as an approved record and a failing one the same red as a denied
   one -- and never colour alone: every ring carries its sentence beneath it and
   its counts in the legend. */
.iq-progress { display: flex; align-items: center; gap: .9rem; margin-top: .6rem; }
.iq-ring { flex: 0 0 auto; transform: rotate(-90deg); }
.iq-ring circle { fill: none; stroke-width: 5; }
.iq-ring .iq-track { stroke: #eef1f4; }
.iq-ring .iq-arc { stroke-linecap: butt; }
/* The four shades, named once (#88).

   #83 wrote these values into the ring and again into the legend. The unit
   circles are a third reader, and three copies of a colour are three chances to
   drift apart, so the values move into variables here and every rule reads
   them. Same colours as before -- no new palette and no fifth shade. */
:root {
  --iq-meets: var(--green);
  --iq-does_not: #c96a5f;
  --iq-not_known: #e6c26e;
  --iq-vacant: #d9e1e8;
}

.iq-ring .iq-arc.is-meets { stroke: var(--iq-meets); }
.iq-ring .iq-arc.is-does_not { stroke: var(--iq-does_not); }
.iq-ring .iq-arc.is-not_known { stroke: var(--iq-not_known); }
.iq-ring .iq-arc.is-vacant { stroke: var(--iq-vacant); }

/* One circle per unit (#88). They wrap rather than overflowing, so a
   forty-unit building reads at phone width without the page scrolling
   sideways. */
.iq-units { margin-top: .6rem; }
.iq-unit-list { list-style: none; padding: 0; margin: 0;
                display: flex; flex-wrap: wrap; gap: .35rem; }
.iq-unit { flex: 0 0 auto; width: 2.1rem; height: 2.1rem; border-radius: 50%;
           display: inline-flex; align-items: center; justify-content: center;
           font-size: .72rem; font-weight: 700; line-height: 1;
           color: #14310f; background: var(--iq-vacant);
           border: 1px solid rgba(0, 0, 0, .12); overflow: hidden; }
.iq-unit.is-meets { background: var(--iq-meets); color: #fff; }
.iq-unit.is-does_not { background: var(--iq-does_not); color: #fff; }
.iq-unit.is-not_known { background: var(--iq-not_known); color: #3a2f0b; }
.iq-unit.is-vacant { background: var(--iq-vacant); color: var(--muted); }
/* A circle with no record behind it carries no number, so it is drawn as an
   outline rather than a badge with nothing in it. */
.iq-unit.is-unnamed { border-style: dashed; }
.iq-unit-label { overflow: hidden; text-overflow: ellipsis; padding: 0 .15rem; }
/* The circles on a Properties list row (#94): the property page's .iq-home
   shades at a size a table row can hold, the first six and then a "+n". */
.iq-row { list-style: none; padding: 0; margin: 0;
          display: flex; flex-wrap: nowrap; gap: .25rem; align-items: center; }
.iq-row .iq-home { width: 1.6rem; height: 1.6rem; font-size: .68rem; }
.iq-more { flex: 0 0 auto; font-size: .78rem; font-weight: 700; color: var(--muted);
           padding-left: .15rem; cursor: help; }
.iq-ring .iq-count { transform: rotate(90deg); transform-origin: 21px 21px;
                     font-size: 11px; font-weight: 700; fill: var(--ink); }
.iq-said { margin: 0; color: var(--muted); font-size: .9rem; max-width: 34rem; }

/* The table-cell form: the ring small, the count in words beside it. */
.iq-cell { display: inline-flex; align-items: center; gap: .45rem; white-space: nowrap; }
.iq-short { font-weight: 700; }

.iq-legend { list-style: none; padding: 0; margin: .5rem 0 0;
             display: flex; flex-wrap: wrap; gap: .25rem 1rem;
             color: var(--muted); font-size: .88rem; }
.iq-key { display: inline-block; width: .7rem; height: .7rem; border-radius: 2px;
          margin-right: .35rem; vertical-align: middle; }
.iq-key.is-meets { background: var(--iq-meets); }
.iq-key.is-does_not { background: var(--iq-does_not); }
.iq-key.is-not_known { background: var(--iq-not_known); }
.iq-key.is-vacant { background: var(--iq-vacant); }

/* One circle per home on the property page (#87). The four shades are the
   ring's own, reused rather than redefined: a fifth palette would be free to
   drift from it. The grid wraps instead of scrolling, so a forty-home building
   still reads on a phone (criterion 19). */
.iq-homes { margin-top: .6rem; }
.iq-grid { list-style: none; padding: 0; margin: 0;
           display: flex; flex-wrap: wrap; gap: .4rem; }
.iq-home { width: 2.1rem; height: 2.1rem; border-radius: 50%;
           display: flex; align-items: center; justify-content: center;
           font-size: .78rem; font-weight: 700; color: #2b3640;
           border: 1px solid rgba(0, 0, 0, .12);
           /* Every circle answers "which home is this?" on hover (#87), so the
              cursor has to say there is something to hover. A circle that is a
              link keeps the pointer. */
           cursor: help; }
.iq-home a { cursor: pointer; }
.iq-home a { display: flex; align-items: center; justify-content: center;
             width: 100%; height: 100%; border-radius: 50%; color: inherit;
             text-decoration: none; }
.iq-home a:hover, .iq-home a:focus { text-decoration: underline; }
.iq-home.is-meets { background: var(--green); color: #fff; }
.iq-home.is-does_not { background: #c96a5f; color: #fff; }
.iq-home.is-not_known { background: #e6c26e; }
.iq-home.is-vacant { background: #d9e1e8; }
.iq-home.is-no_route { background: #fff; border: 2px dashed #9aa7b3; }

/* The residential service offerings a contractor is ticked for (#84). Matt on
   the first build: the flat column of checkboxes "look awful. This should be
   ... two columns broken out into residential service offerings". Two columns
   where there is room, one where there is not -- the same auto-fit idiom
   `.fields` and `.checklist .readings` already use, so it collapses on a
   narrow window instead of overflowing. */
.offerings { display: grid; grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
             gap: .2rem 1.4rem; }
.offerings .check { margin: 0; }

/* Progress by building (#92): every building on the property, one row each.
   Name on the left, the circles and their state in the middle, the links on
   the right; the row wraps to one column where there is no room, like every
   other grid in this file. The building being looked at is marked with the
   portal's blue on its edge, not with a colour of its own. */
.progress-by-building .pbb-head { display: flex; flex-wrap: wrap; align-items: baseline;
                                  justify-content: space-between; gap: .2rem 1rem; }
.progress-by-building .pbb-head h2 { margin: 0; }
.progress-by-building .pbb-head p { margin: 0; }
.pbb-rows { list-style: none; padding: 0; margin: .8rem 0 0; display: grid; gap: .6rem; }
.pbb-row { display: grid; grid-template-columns: minmax(11rem, 1fr) minmax(14rem, 2fr) auto;
           gap: .4rem 1.2rem; align-items: start;
           border: 1px solid var(--line); border-left: 4px solid var(--line);
           border-radius: 8px; padding: .7rem .9rem; }
.pbb-row.is-current { border-left-color: var(--blue); background: #fbfdff; }
.pbb-state .badge { margin-bottom: .35rem; }
.pbb-state .iq-homes { margin-top: .3rem; }
.pbb-line { margin: .35rem 0 0; color: var(--ink); font-size: .92rem; }
.pbb-line.small { font-size: .85rem; color: var(--muted); }
/* The 50% rule's own line: a divider above it and its name in front (#92). */
.pbb-line.pbb-rule { border-top: 1px solid var(--line); margin-top: .55rem; padding-top: .45rem; }
.pbb-rule-label { font-weight: 700; color: var(--blue); margin-right: .35rem; }
.type-checked { margin: -.3rem 0 .6rem; }
/* What the record says on a decided building, and the documents by unit. */
.pbb-line.pbb-decision { font-weight: 600; }
.pbb-docs { border-top: 1px solid var(--line); margin-top: .55rem; padding-top: .45rem; }
.pbb-docs-head { margin: 0; font-weight: 700; font-size: .85rem; color: var(--muted);
                 text-transform: uppercase; letter-spacing: .02em; }
.pbb-doc-list { list-style: none; padding: 0; margin: .25rem 0 0; font-size: .9rem; }
.pbb-doc-list li { margin: .15rem 0; }
.pbb-doc-list .badge { font-size: .75rem; padding: .1rem .55rem; margin: 0 0 0 .3rem; }
.pbb-doc-unit { display: inline-block; min-width: 4.5rem; font-weight: 600; }
.pbb-line .badge { margin: 0; }
.pbb-links { display: flex; flex-direction: column; gap: .4rem; align-items: stretch; }
.pbb-links .button { padding: .3rem .7rem; font-size: .88rem; text-align: center; }
.progress-by-building > .iq-legend { margin-top: .8rem; }
@media (max-width: 900px) {
  .pbb-row { grid-template-columns: 1fr; }
  .pbb-links { flex-direction: row; flex-wrap: wrap; }
}

/* The map button and the type icon in "Confirm the type" (#92). */
.button.map-button { display: inline-flex; align-items: center; gap: .4rem; }
.icon.inline { width: 1.1em; height: 1.1em; }
.type-icon { display: inline-flex; vertical-align: -.2em; margin-right: .4rem; color: var(--blue); }
.icon.type { width: 1.2em; height: 1.2em; }
.iq-key.is-meets { background: var(--green); }
.iq-key.is-does_not { background: #c96a5f; }
.iq-key.is-not_known { background: #e6c26e; }
.iq-key.is-vacant { background: #d9e1e8; }



/* Icon-only controls in the application's head (#93). Matt asked for Timeline
   and Email as clickable icons rather than worded buttons. The name is never
   only in the glyph: every one of these carries an aria-label and a title, so
   it is readable aloud and nameable on hover. Square, so a row of them reads
   as a row of controls rather than ragged buttons. */
.button.icon-only { display: inline-flex; align-items: center; justify-content: center;
                    width: 2.5rem; height: 2.5rem; padding: 0; }
.button.icon-only .icon { width: 20px; height: 20px; }
.button.icon-only:hover .icon { color: var(--blue); }

/* The 50% rule's target, drawn IN the row of circles (#93, question 2 answer
   A): a divider straight after the last unit the rule requires. It replaces a
   sentence, so it must be legible on its own -- hence the accent colour and the
   full height of a circle. It is aria-hidden because the same fact reaches a
   screen reader through the list's own label. */
.iq-unit-divider { flex: 0 0 auto; width: 0; align-self: stretch;
                   margin: 0 .35rem; border-left: 2px solid var(--blue); }

/* Matt's fourth look at #92: a named circle opens its unit's documents, the
   50% rule sits behind an (i), and the documents carry an icon for their type. */
.iq-home .pbb-open { display: flex; align-items: center; justify-content: center;
                     width: 100%; height: 100%; border-radius: 50%; color: inherit;
                     text-decoration: none; cursor: pointer; }
.iq-home .pbb-open:hover, .iq-home .pbb-open:focus-visible { outline: 2px solid var(--blue); outline-offset: 2px; }
.pbb-info { display: inline-block; margin-left: .35rem; vertical-align: middle; font-weight: 400; }
.pbb-rule-lines { position: absolute; z-index: 5; background: var(--card); border: 1px solid var(--line);
                  border-radius: 8px; padding: .5rem .8rem; margin-top: .3rem; box-shadow: 0 6px 18px rgba(0,0,0,.08);
                  font-size: .9rem; max-width: 34rem; }
.pbb-head h2 { position: relative; }
.pbb-rule-lines .pbb-rule { border-top: 0; margin: .15rem 0; padding: 0; }
.pbb-info summary { list-style: none; cursor: help; display: inline-flex; align-items: center;
                    color: var(--muted); }
.pbb-info summary::-webkit-details-marker { display: none; }
.pbb-info summary:hover, .pbb-info[open] summary { color: var(--blue); }
.pbb-info .icon { width: 1.1rem; height: 1.1rem; }
.pbb-info[open] .pbb-rule { margin-top: .3rem; }
.pbb-open-building { color: var(--blue); text-decoration: underline; cursor: pointer; }
.doc-list { list-style: none; padding: 0; margin: .3rem 0 0; display: grid; gap: .4rem; }
.doc { display: flex; align-items: flex-start; gap: .55rem; }
.doc-icon { flex: 0 0 auto; color: var(--blue); }
.icon.doc { width: 1.6rem; height: 1.6rem; }
.doc-body { display: flex; flex-direction: column; gap: .05rem; }
.dialog-links { margin: .8rem 0 0; }

/* Approving a unit's documents from its pop-up (#92, Matt's fifth look). */
.dialog-actions { margin-top: .8rem; display: flex; flex-wrap: wrap; gap: .5rem; align-items: center; }
.dialog-actions form { margin: 0; }

/* My queue: a decision on every row (#103). The controls sit in their own
   column and wrap; a refused decision is a line under its row, not a banner at
   the top of the page that could be about any of forty rows. */
.records td.queue-actions { white-space: normal; }
.records td.queue-actions .queue-buttons { display: flex; flex-wrap: wrap; gap: .35rem; align-items: center; }
.records td.queue-actions .button, .records td.queue-actions form .button { padding: .25rem .6rem; font-size: .85rem; }
.records td.queue-actions form { display: inline; }
.records tr.row-error td { padding-top: 0; }
.records tr.row-error .notice { margin: 0 0 .5rem; }
.records tr.row-unread td { cursor: default; }
.records tr.row-unread .notice { margin: 0; }
.queue-section { margin-top: 1.6rem; }
.queue-section h2 { margin-bottom: .2rem; }
.queue-section .count { font-weight: 400; color: var(--muted); font-size: .95rem; margin-left: .4rem; }
.queue-units li { margin: .5rem 0; }
.queue-units .queue-buttons { display: flex; flex-wrap: wrap; gap: .35rem; margin-top: .25rem; }
/* The property head's decision buttons (#103, criterion 2.2). */
.head-actions .head-decision { font-size: .9rem; }
.column-filters .field { margin-bottom: .6rem; }
.column-filters .actions { display: flex; flex-wrap: wrap; gap: .5rem; }

/* What the household was told (#110). Warnings carry the site's own warning
   colours; "could not check" and "checked later" stay plain on purpose, so
   neither can be mistaken for a warning -- or for a pass. */
.told { list-style: none; padding: 0; margin: .4rem 0 .8rem; display: grid; gap: .5rem; }
.told li { padding: .5rem .7rem; border: 1px solid var(--line, #dde3ea); border-radius: 6px; }
.told li > div { margin-top: .2rem; }
.told-warn li { background: var(--warn-bg); border-color: var(--warn-line); }

/* What the owner signed and told us (#113). */
.grants-flag { border-width: 2px; }
.grants-flag a { margin-left: .4rem; white-space: nowrap; }
.signed-declarations h3 { margin: 1rem 0 .4rem; font-size: 1rem; }
.signed-declarations h3.signed-head { margin-top: 1.2rem; }
.signed-statements { margin: 0; padding-left: 1.4rem; display: grid; gap: .5rem; }
.signed-statements li { overflow-wrap: anywhere; }
.signed-statements .statement-answer { display: block; }
.signed-statements li.is-flagged { background: var(--warn-bg); border-radius: 4px; padding: .3rem .5rem; }
.signed-declarations img.signature { display: block; max-width: min(100%, 360px); height: auto;
  background: #fff; border: 1px solid var(--line); border-radius: 4px; padding: .3rem; }
.signed-earlier { margin-top: 1rem; }
.signed-earlier summary { cursor: pointer; font-weight: 600; }
.signed-earlier .signed-one { border-top: 1px solid var(--line); margin-top: .8rem; padding-top: .8rem; }
.signed-declarations dl.facts, .company-details dl.facts {
  grid-template-columns: minmax(0, max-content) minmax(0, 1fr); }
.signed-declarations .badge { white-space: normal; }
@media (max-width: 600px) {
  .signed-declarations dl.facts, .company-details dl.facts { grid-template-columns: minmax(0, 1fr); }
  .signed-declarations dl.facts dd, .company-details dl.facts dd { margin-bottom: .4rem; }
}

/* Ownership claims (#118): the two ends a claim can reach besides Confirmed,
   and the evidence list, which reads as lines rather than bullets. */
.badge.status.st-rejected { background: #fbe4e1; color: #9b2c20; }
.badge.status.st-withdrawn { background: #eef0f3; color: #4a5361; }
ul.plain { list-style: none; padding-left: 0; margin: 0; }
ul.plain li { padding: .25rem 0; overflow-wrap: anywhere; }
#decision fieldset { border: 0; padding: 0; margin: 0; min-width: 0; }

/* The qualification page (#134): the route it is reviewed on, the property in
   one line above its buildings, and the reference cards folded beneath. */
.review-route { display: flex; flex-wrap: wrap; align-items: baseline; gap: .5rem; margin: .25rem 0 .75rem; }
.progress-by-building .pbb-head .pbb-summary { flex-basis: 100%; margin-top: .25rem; }
.progress-by-building .pbb-summary .badge { margin-left: .5rem; }
details.card.fold > summary { cursor: pointer; font-weight: 700; color: var(--blue); font-size: 1.1rem; }
details.card.fold[open] > summary { margin-bottom: .75rem; }
details.card.fold > .card { box-shadow: none; border: 0; padding-left: 0; padding-right: 0; margin-bottom: 0; }

/* The email viewing pop-up (#133): what was kept about one email. */
.email-facts { display: grid; grid-template-columns: max-content minmax(0, 1fr); gap: .35rem .9rem; margin: 0 0 1rem; }
.email-facts dt { font-weight: 600; }
.email-facts dd { margin: 0; overflow-wrap: anywhere; }

/* The unit selected on a building's application page (#136): its documents and
   the Confirm under its building's row, across the whole row. */
.pbb-selected { grid-column: 1 / -1; border-top: 1px solid var(--line);
  margin-top: .4rem; padding-top: .7rem; min-width: 0; }
.pbb-selected-head { display: flex; align-items: baseline; justify-content: space-between;
  gap: 1rem; flex-wrap: wrap; }
.pbb-selected-head h3 { margin: 0; }
.pbb-selected-actions { display: flex; flex-wrap: wrap; gap: .6rem 1rem; align-items: end;
  margin-top: .6rem; }
.pbb-selected-actions form { display: flex; flex-wrap: wrap; gap: .5rem; align-items: end; }
.pbb-selected-actions select { max-width: 100%; }
/* #142: Confirm and Deny side by side; the unit's one status pill above. */
.pbb-decide { display: flex; flex-wrap: wrap; gap: .5rem; }
.pbb-unit-status { margin: .2rem 0 .4rem; }
.page-head h1 .badge { font-size: .8rem; vertical-align: middle; margin-left: .4rem; }
.iq-home.is-selected { outline: 3px solid var(--blue); outline-offset: 2px; }
.pbb-open-building.is-selected { font-weight: 700; }

/* Teams as cards (#141): several abreast on a desktop, one at phone width.
   #147: always open -- the name and the people, nothing else. */
.team-cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(19rem, 100%), 1fr));
  gap: 1rem 1.2rem; align-items: start; margin-bottom: 1.2rem; }
.team-cards > .card { margin: 0; min-width: 0; padding: 0 1.2rem .6rem; }
.team-card-head { display: flex; align-items: center; gap: .6rem; padding: 1rem 0 .6rem; }
.team-name { font-weight: 700; font-size: 1.1rem; color: var(--blue); flex: 1; min-width: 0;
  overflow-wrap: anywhere; }
.team-name[data-rename] { cursor: text; }
.team-name[data-rename]:focus-visible { outline: 2px solid var(--blue); outline-offset: 2px; border-radius: 4px; }
.team-name-input { font: inherit; width: 100%; padding: .2rem .4rem; border: 1px solid #b9c6d2;
  border-radius: 6px; }
.team-members { list-style: none; margin: 0; padding: 0; }
.team-members li { display: flex; flex-wrap: wrap; align-items: center; gap: .3rem .5rem;
  padding: .5rem 0; border-top: 1px solid var(--line); overflow-wrap: anywhere; }
.team-members li[draggable="true"] { cursor: grab; }
.team-members li.is-dragging { opacity: .45; }
.team-members li[hidden] { display: none; }
.team-grip { color: var(--muted); display: inline-flex; flex: none; }
.team-grip .icon { width: 16px; height: 16px; }
.team-who { flex: 1 1 0; min-width: 0; }
.team-trash { margin: 0; flex: none; }
.team-add-open { flex: none; }
/* #147: the card's plus opens a row at the foot of its list. */
.team-add-row .team-add { flex: 1; }
.team-add { display: flex; gap: .5rem; align-items: center; margin: 0; }
.team-add input { flex: 1; min-width: 0; max-width: 100%; font: inherit; padding: .4rem .6rem;
  border: 1px solid #b9c6d2; border-radius: 6px; }
.team-add input:focus-visible { outline: 2px solid var(--blue); outline-offset: 1px; }
.team-card.is-drop-target { outline: 2px dashed var(--blue); outline-offset: 2px; }
/* The Assign button that sits in a card rather than a page head (#141). */
.card-assign { margin: -.2rem 0 .8rem; }


/* A contractor registration's three steps (#143). */
.reg-steps { display: flex; flex-wrap: wrap; gap: .25rem; list-style: none; padding: 0; margin: .4rem 0 1rem; }
.reg-step { display: flex; align-items: center; gap: .45rem; padding: .35rem .8rem .35rem .4rem;
            border-radius: 999px; background: #eef2f5; color: var(--muted); font-size: .9rem; }
.reg-step-dot { display: inline-flex; align-items: center; justify-content: center; width: 1.6rem;
                height: 1.6rem; border-radius: 50%; background: #fff; border: 2px solid var(--line);
                font-weight: 700; font-size: .8rem; }
.reg-step.is-done { background: var(--tint); color: var(--blue); }
.reg-step.is-done .reg-step-dot { border-color: var(--blue); color: var(--blue); }
.reg-steps--contractor .reg-step.is-done { background: #dff3e8; color: #0b6b36; }
.reg-steps--contractor .reg-step.is-done .reg-step-dot { background: var(--green); border-color: var(--green); color: #fff; }
.reg-steps--contractor .reg-step.is-done .reg-step-label { text-decoration: line-through; }
.reg-step.is-current { font-weight: 700; color: var(--ink); background: #fff; box-shadow: inset 0 0 0 2px var(--blue); }
.reg-step.tone-waiting { background: var(--warn-bg); box-shadow: inset 0 0 0 2px var(--warn-line); color: #8a6116; }
.reg-step.tone-waiting .reg-step-dot { border-color: var(--warn-line); color: #8a6116; }
.reg-step.tone-approved { background: #dff3e8; box-shadow: inset 0 0 0 2px var(--green); color: #0b6b36; }
.reg-step.tone-approved .reg-step-dot { background: var(--green); border-color: var(--green); color: #fff; }
.reg-step.tone-declined { background: #fbe4e1; box-shadow: inset 0 0 0 2px var(--err); color: #9b2c20; }
.reg-step.tone-declined .reg-step-dot { background: var(--err); border-color: var(--err); color: #fff; }

/* A rebuilt invitation email (#143). */
/* Give the 700px Focus email room inside its viewing pop-up. */
.dialog.is-enhanced .dialog-card:has(.email-frame) { width: min(50rem, 100%); }
.email-frame { width: 100%; min-height: 48rem; border: 1px solid var(--line); border-radius: 6px; background: #f4f4f4; }

/* Every column filterable in a list's filter pop-up (#143). */
.column-filter-fields { border-top: 1px solid var(--line); margin-top: 1rem; padding-top: .6rem;
  display: grid; grid-template-columns: repeat(auto-fill, minmax(min(14rem, 100%), 1fr)); gap: .4rem 1rem; }
.column-filter-fields h3, .column-filter-fields .column-filter-count,
.column-filter-fields > .button { grid-column: 1 / -1; }
.column-filter-fields h3 { margin: 0; font-size: 1rem; }
.column-filter-fields > .button { justify-self: start; }

/* Properties: the filter leads search at every width (#152). */
.property-list-tools { display: flex; align-items: center; gap: .5rem; margin-bottom: 1rem; min-width: 0; }
.property-list-tools > .filter-open { flex: 0 0 auto; }
.property-list-tools .search { flex: 1; min-width: 0; margin: 0; flex-wrap: nowrap; gap: .35rem; }
.property-list-tools .search input[type="search"] { flex: 1 1 0; width: 0; }
.sort-header { color: inherit; display: inline-block; text-decoration: none; }
.sort-header:hover { text-decoration: underline; }
.sort-header:focus-visible { outline: 2px solid var(--blue); outline-offset: 3px; }
/* The same header as a button, on every list sorted in the browser (#196):
   it reads as the header word it replaced, not as a button. */
button.sort-header { background: none; border: 0; padding: 0; font: inherit;
  font-weight: inherit; text-align: inherit; cursor: pointer; }

/* The progress bar on a building's application (#151): two steps side by
   side, each with its words and a track that fills. Green once done. */
.iq-progress { display: grid; grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr));
  gap: .6rem; list-style: none; padding: 0; margin: .8rem 0 1rem; }
.iq-progress-step a { display: block; padding: .6rem .8rem; border: 1px solid var(--line);
  border-radius: 6px; background: var(--card); color: var(--ink); text-decoration: none; }
.iq-progress-step a:hover { border-color: var(--blue); }
.iq-progress-label { display: block; font-weight: 700; }
.iq-progress-detail { display: block; font-size: .9rem; color: var(--muted); margin: .1rem 0 .45rem; }
.iq-progress-track { display: block; height: .5rem; border-radius: 999px; background: #e8edf1; overflow: hidden; }
.iq-progress-fill { display: block; height: 100%; background: var(--blue); }
.iq-progress-step.is-done a { border-color: var(--green); background: #f0faf4; }
.iq-progress-step.is-done .iq-progress-detail { color: #0b6b36; font-weight: 700; }
.iq-progress-step.is-done .iq-progress-fill { background: var(--green); }

/* A team's name, clickable to rename it in place (#151). */
.team-name[data-rename] { cursor: text; border-bottom: 1px dashed transparent; }
.team-name[data-rename]:hover, .team-name[data-rename]:focus-visible { border-bottom-color: var(--blue); }
.team-name-input { font: inherit; font-weight: 700; padding: .1rem .35rem; min-width: 10rem;
  max-width: 100%; border: 2px solid var(--blue); border-radius: 4px; }

/* What a household wrote back with an answer (#171): their words, set apart
   from ours, line breaks kept. */
.household-note { margin: .3rem 0 .5rem; padding: .5rem .8rem; border-left: 3px solid var(--line);
  background: var(--bg); white-space: pre-line; overflow-wrap: anywhere; }

/* A bundled test on the Tests page (#196): one segment per step, gray for
   Not run, green for Completed, red for Bug or failed. Each segment is a link
   to its step's pop-up and shows the newest result on hover or focus. */
.test-progress { display: flex; gap: 3px; list-style: none; padding: 0; margin: .3rem 0;
  min-width: 10rem; }
.test-seg { position: relative; flex: 1 1 0; }
.test-seg > a { display: block; height: .9rem; border-radius: 3px; background: #c4ccd4; }
.test-seg.seg-approved > a { background: var(--green); }
.test-seg.seg-denied > a { background: var(--err); }
/* Blocked (#203): amber, the color a waiting record takes elsewhere. */
.test-seg.seg-blocked > a { background: #d9a43a; }
.badge.status.st-blocked { background: var(--warn-bg); color: #8a6116; }
.test-seg > a:hover, .test-seg > a:focus-visible { outline: 2px solid var(--blue); outline-offset: 2px; }
.seg-tip { display: none; position: absolute; z-index: 30; left: 50%; top: 1.35rem;
  transform: translateX(-50%); width: max-content; max-width: 18rem; padding: .45rem .6rem;
  background: var(--ink); color: #fff; font-size: .8rem; line-height: 1.4; border-radius: 4px;
  white-space: normal; overflow-wrap: anywhere; pointer-events: none; }
.test-seg:hover .seg-tip, .test-seg > a:focus-visible + .seg-tip { display: block; }
.dialog .test-progress { margin: .4rem 0 1rem; }
/* A step id stays on one line in its test's pop-up (#202 added a Role column). */
.test-steps td:first-child { white-space: nowrap; }
.test-tabs [role="tablist"] { border-bottom: 1px solid var(--line); padding-bottom: .25rem; }
.test-tabs [role="tab"] { font: inherit; font-weight: 600; background: none; cursor: pointer;
  border: 1px solid transparent; border-radius: 6px 6px 0 0; padding: .35rem .8rem; color: var(--muted); }
.test-tabs [role="tab"][aria-selected="true"] { color: var(--ink); border-color: var(--line);
  border-bottom-color: var(--card); background: var(--card); }
.test-results { list-style: none; padding: 0; margin: 0 0 .8rem; }
.test-results li { padding: .5rem 0; border-bottom: 1px solid var(--line); }

/* #207: the test pane. Scott answered A -- one wide pane, the steps listed on
   the left and the chosen step on the right. Only the Tests page's test
   pop-ups are widened; every other pop-up keeps its 38rem. */
.dialog.is-enhanced.test-pane .dialog-card { width: min(78rem, 100%); }
.pane { display: grid; grid-template-columns: minmax(15rem, 23rem) minmax(0, 1fr);
  gap: 1.25rem; align-items: start; }
.pane-list ol { list-style: none; margin: 0; padding: 0; border: 1px solid var(--line);
  border-radius: 6px; }
.dialog.is-enhanced .pane-list ol { position: sticky; top: 3.5rem; max-height: 68vh; overflow-y: auto; }
.pane-list li + li { border-top: 1px solid var(--line); }
.pane-item { display: grid; grid-template-columns: auto 1fr; gap: .1rem .6rem;
  padding: .55rem .7rem; color: var(--ink); text-decoration: none; }
.pane-item:hover { background: var(--bg); }
.pane-item:focus-visible { outline: 2px solid var(--blue); outline-offset: -2px; }
.pane-item[aria-current="step"] { background: var(--tint); box-shadow: inset 3px 0 0 var(--blue); }
.pane-key { font-weight: 600; white-space: nowrap; }
.pane-role { justify-self: end; color: var(--muted); }
.pane-action { grid-column: 1 / -1; color: var(--muted); line-height: 1.35; }
.pane-state { grid-column: 1 / -1; }
.pane-step + .pane-step { margin-top: 1.5rem; padding-top: 1.5rem; border-top: 1px solid var(--line); }
.dialog.is-enhanced .pane-step + .pane-step { margin-top: 0; padding-top: 0; border-top: 0; }
.pane-step-head { display: flex; align-items: baseline; gap: .75rem; flex-wrap: wrap; }
.pane-step-head h3 { margin: 0; }
.pane-facts { display: grid; grid-template-columns: max-content 1fr; gap: .35rem 1rem; margin: .8rem 0; }
.pane-facts dt { font-weight: 600; color: var(--muted); }
.pane-facts dd { margin: 0; }
.pane-form-row { display: grid; grid-template-columns: minmax(10rem, 14rem) 1fr; gap: 0 1rem; }
.pane-nav { display: flex; align-items: center; gap: .5rem; flex-wrap: wrap;
  margin-top: 1rem; padding-top: .8rem; border-top: 1px solid var(--line); }
.pane-nav .pane-own { margin-left: auto; }
.unblocked { color: var(--green-dark); }
.tag-ready { display: inline-block; font-size: .75rem; font-weight: 600; padding: .05rem .45rem;
  border-radius: 999px; border: 1px solid var(--green); color: var(--green-dark); vertical-align: middle; }
.row-title { color: inherit; }
.row-title:hover, .row-title:focus-visible { color: var(--blue); }
/* The step's own page (#207): the step and its form side by side. */
.step-layout { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 1rem; align-items: start; }
.step-layout > .card { margin-top: 0; }
.step-walk { display: flex; gap: .5rem; }
@media (max-width: 760px) {
  .pane, .step-layout, .pane-form-row { grid-template-columns: 1fr; }
  .dialog.is-enhanced .pane-list ol { position: static; max-height: 40vh; }
}

/* The SPECTRUM export at the top right of Qualifications (#194): an icon
   button that downloads, with how many households are new beside its name.
   The count is part of the button's accessible name, so it reads aloud too. */
.button.with-icon { display: inline-flex; align-items: center; gap: .45rem; }
.button.with-icon .icon { width: 20px; height: 20px; flex: none; }
.button.with-icon .count { font-weight: 400; padding: 0 .45rem; border-radius: 999px;
                           background: rgba(255, 255, 255, .22); white-space: nowrap; }
.page-head .head-actions .small { color: var(--blue); }

/* Check against DOE rules (#198): a POST, because it writes a timeline line,
   that reads as the link beside Open and Redact. */
.inline-form { display: inline; margin: 0; }
button.linklike { background: none; border: 0; padding: 0; font: inherit;
  color: var(--blue); text-decoration: underline; cursor: pointer; }
button.linklike:focus-visible { outline: 2px solid var(--blue); outline-offset: 2px; }
.hpxml-outcome { display: flex; gap: .6rem; align-items: center; flex-wrap: wrap; }
.hpxml-problems code { white-space: normal; word-break: break-all; }
/* #180, third look: "move export button to right". A page head's actions stay
   hard right even when they wrap under the title, and the Applications list's
   tick box is a narrow first column. */
.page-head .head-actions { margin-left: auto; justify-content: flex-end; }
table.records th.select-cell, table.records td.select-cell { width: 2.2rem; padding-right: 0; }
table.records td.select-cell input[type="checkbox"] { width: 1.1rem; height: 1.1rem; cursor: pointer; }

/* The Approve drawer on Reservation review (#206): one tick box per check,
   the wording beside it, and anything about the check underneath. */
.approve-drawer fieldset { border: 0; padding: 0; margin: 0 0 1rem; }
.approve-drawer legend { font-weight: 600; margin-bottom: .25rem; }
.approve-drawer .ticks { list-style: none; padding: 0; margin: 0; }
.approve-drawer .ticks li { display: grid; grid-template-columns: auto 1fr; gap: .15rem .5rem;
  align-items: start; margin: .5rem 0; }
.approve-drawer .ticks li > input { margin-top: .3rem; }
.approve-drawer .ticks li > :not(input):not(label) { grid-column: 2; margin: 0; }
/* Tests (#210). The "By phase" / "All tests" switch: two ordinary links on the
   left under the heading, the chosen one filled. */
.view-switch { display: inline-flex; margin: 0 0 .75rem; border: 1px solid var(--line);
               border-radius: .4rem; overflow: hidden; background: var(--card); }
.view-switch a { padding: .35rem .9rem; color: var(--muted); text-decoration: none;
                 font-weight: 600; font-size: .9rem; }
.view-switch a + a { border-left: 1px solid var(--line); }
.view-switch a:hover { color: var(--ink); background: #f4f6f8; }
.view-switch a[aria-current="true"] { color: #fff; background: var(--blue); }
/* The phase number on /tests is plain text in the body color, never a blue
   underlined link -- the row still opens on click or double-click (#207). */
#phases-list .test-phase td.num a,
#phases-list .test-phase td.num a:hover,
#phases-list .test-phase td.num a:focus { color: var(--ink); text-decoration: none; }

/* The Account box (#211): a text box like the answer boxes above it, with
   the matching accounts listed under it as it is typed into. */
.combobox { position: relative; max-width: 28rem; }
.combobox-list { position: absolute; z-index: 20; left: 0; right: 0; top: 100%;
  margin: .2rem 0 0; padding: .25rem 0; list-style: none; background: #fff;
  border: 1px solid #b9c6d2; border-radius: 4px; max-height: 16rem; overflow-y: auto;
  box-shadow: 0 4px 14px rgba(0, 0, 0, .12); }
.combobox-list li { padding: .35rem .6rem; cursor: pointer; }
.combobox-list li[aria-selected="true"], .combobox-list li[role=option]:hover { background: #e8f0f8; }
.combobox-list .combobox-none { color: var(--muted); cursor: default; }
.combobox input[readonly] { background: #f3f5f7; color: var(--muted); }
.combobox [data-combobox-said] { color: #b3261e; margin: .3rem 0 0; }
/* The incomplete clock under the email form in the Email pop-up (#211). */
.dialog-section { border-top: 1px solid var(--line); margin-top: 1.2rem; padding-top: .6rem; }
.dialog-section h3 { margin: .2rem 0 .5rem; }
.dialog-section form { margin-top: .8rem; }
