/* ============================================================================
   DevPlan — the project state summary card
   Tokens only (see styles.css :root). No literal colour anywhere, which is also
   why there is no dark-mode block in this file: every colour below is a var()
   that styles.css already redefines for dark, so the card follows the theme for
   free. Adding a @media block here would give the card a SECOND opinion about
   dark mode and the two would drift.

   Audited at 375px. The spacing and the sizes came out of the approved design
   (six were drawn; this is the one that was chosen) and are deliberate:

   - The card is the only place on the client's screen with a raised surface and
     a large radius. That is the point — it is a different KIND of object from
     the questionnaire under it, written by a person, not filled in by one.
   - The four fact tiles are a 2x2 grid at every width. At 375px a 4-across row
     puts "Document requests unsatisfied" on four lines; 2x2 keeps it to two.
   - The detail is one collapsed disclosure. The home screen was cut down to
     three facts on purpose a week ago; this card adds a ring, a sentence and
     four tiles at rest and NOTHING else. Everything longer lives behind the
     button, which is why the button exists.

   UNREAD IS NEVER ONLY A COLOUR (WCAG 1.4.1). Four signals carry it, three of
   them non-colour: a dot, a "New"/"Unread" pill, a heavier name, and the words
   "Not read yet". Remove the colour from this file entirely and the state is
   still legible.
   ========================================================================= */

.sum {
  /* Six spacing values, declared once and used below — the same discipline
     .qn-q uses, and the reason the card reads as one rhythm rather than a pile
     of ad-hoc margins. */
  --sum-1: 4px;    /* inside a tile, inside a name line */
  --sum-2: 6px;    /* between tiles, between callout and the tiles above it */
  --sum-3: 12px;   /* the card's own internal rhythm: block to block */
  --sum-4: 16px;   /* the card's padding */

  display: block;
  /* No margin of its own. Both hosts already own the gap below it — #client-body
     is a .stack, and inside the operator's tenant card the rule below sets it —
     so a margin here would be a third opinion about the same space. */
  margin: 0;
  /* Inherited by every line of prose on the card, which is the point: all of it
     is authored, and one pasted URL in a blocker body — the likeliest thing in
     the world to appear there — otherwise sets the card's min-content width and
     the whole PAGE scrolls sideways at 375px. Measured: a 120-character URL took
     the document to 1256px before this line. Same token the rest of the app uses
     for the same reason (.qn-disc__text, .op-filename, .op-activity__what). */
  overflow-wrap: anywhere;
  padding: var(--sum-4);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-1);
}

/* The unread card is bordered a step stronger. Colour is the LAST of the four
   unread signals, never the only one — see the file header. */
.sum--unread { border-color: var(--border-strong); }

/* On the client's screen the card joins the reading column, and it does so by
   being named in the app's own two measure lists rather than by a copy here:
   client.css caps the column at 34rem centred, and styles.css re-caps it at
   62rem left-aligned from 980px up. A copy of only the first — which is what
   this file used to hold — left the card 544px wide and centred above a 992px
   questionnaire on a 1280px screen, indented 225px from everything below it:
   the "column looks like a mistake" failure, at the breakpoint nobody measured.
   One card, one measure, both breakpoints:
     client.css  → #client-body > .sum in the 34rem list
     styles.css  → .app-main #client-body > .sum in the 62rem list */

/* --------------------------------------------------------------- the head -- */

.sum__head {
  display: flex;
  gap: var(--sum-3);
  align-items: flex-start;
}

.sum__ring { flex: none; }
.sum__ring-track { fill: none; stroke: var(--border); stroke-width: 5; }
.sum__ring-bar {
  fill: none;
  stroke: var(--accent);
  stroke-width: 5;
  stroke-linecap: round;
}
/* Drawn inside the SVG rather than layered over it, so the number scales with
   the ring and can never fall out of register with it. */
.sum__ring-num {
  fill: var(--text);
  font-family: var(--font);
  font-size: 15px;
  font-weight: 650;
}
.sum__ring-pct { font-size: 9px; font-weight: 500; }

.sum__headtext { flex: 1 1 auto; min-width: 0; }

.sum__nameline {
  display: flex;
  align-items: center;
  gap: var(--sum-2);
  flex-wrap: wrap;
}

.sum__name {
  margin: 0;
  font-size: 1rem;
  font-weight: 500;
  line-height: 1.3;
  color: var(--text);
}
/* Unread signal 3 of 4: the name carries weight. Works in monochrome. */
.sum--unread .sum__name { font-weight: 700; }

/* Unread signal 1 of 4. aria-hidden in the markup: the words in .sum__state
   say the same thing for a screen reader, and a bullet read aloud is noise. */
.sum__dot {
  flex: none;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--accent);
}

/* Unread signal 2 of 4. */
.sum__new {
  padding: 1px 6px;
  font-size: .625rem;
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--accent-sunk);
  background: var(--accent-wash);
  border-radius: var(--radius-sm);
}

.sum__sub {
  margin: 3px 0 0;
  font-size: .75rem;
  line-height: 1.4;
  color: var(--text-muted);
}

/* Unread signal 4 of 4, and the only one that survives being read aloud. */
.sum__state {
  margin: 2px 0 0;
  font-size: .75rem;
  color: var(--text-muted);
}
.sum--unread .sum__state { color: var(--text); font-weight: 500; }

/* -------------------------------------------------------------- the stale -- */
/* summary_current.stale: a round was published after this summary was written,
   so the FIGURES are live and the PROSE is not. The card says which half to
   trust instead of quietly presenting stale wording as current — see the last
   comment block of 015_project_summary.sql.

   Deliberately not another red box. The worst-blocker callout below is about the
   engagement; this is about the card itself, and two alarms of equal weight
   would flatten the difference. Words carry it, so it survives greyscale; the
   triangle is non-text and owes only 3:1. */

.sum__stale {
  display: flex;
  gap: 8px;
  margin: var(--sum-3) 0 0;
  padding: 8px 10px;
  font-size: .75rem;
  line-height: 1.45;
  color: var(--text);
  background: var(--surface-2);
  border-left: 2px solid var(--danger);
  border-radius: var(--radius);
}
.sum__stale-icon {
  flex: none;
  margin-top: 2px;
  width: 14px;
  height: 14px;
  fill: var(--danger);
}

/* ------------------------------------------------------------ the verdict -- */
/* First thing after the head, and the widest measure on the card: it is one
   sentence and it carries the weight of the whole summary. */

.sum__verdict {
  margin: var(--sum-3) 0 0;
  font-size: .875rem;
  line-height: 1.5;
  color: var(--text);
}

/* -------------------------------------------------------------- the facts -- */

.sum__facts {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--sum-2);
  margin-top: var(--sum-3);
}

.sum__fact {
  padding: 8px 10px;
  background: var(--surface-2);
  border-radius: var(--radius);
}

.sum__fv {
  font-size: 1.0625rem;
  font-weight: 650;
  line-height: 1.2;
  /* Four figures in a 2x2 grid line up column-wise or they look broken. */
  font-variant-numeric: tabular-nums;
}

.sum__fl {
  margin-top: 1px;
  font-size: .75rem;
  line-height: 1.3;
  color: var(--text-muted);
}

/* ------------------------------------------------------ the worst blocker -- */
/* One blocker, promoted out of the collapsed detail, because the whole reason
   the array is ordered is that its first element is the one that matters. */

.sum__worst {
  display: flex;
  gap: 8px;
  margin-top: var(--sum-2);
  padding: 8px 10px;
  color: var(--danger);
  background: var(--danger-wash);
  border: 1px solid var(--danger);
  border-radius: var(--radius);
}

.sum__worst-icon {
  flex: none;
  margin-top: 2px;
  width: 14px;
  height: 14px;
  fill: currentColor;
}

/* A flex item will not shrink below its min-content width unless told to, and
   overflow-wrap alone does not settle it for a nested block. Both of the card's
   two icon-plus-text rows need it or a long word pushes them out of the card. */
.sum__worst-body,
.sum__next-body { min-width: 0; }

/* The design set this label in the warning colour. Measured against this app's
   tokens rather than the mock's, --danger on --danger-wash is 4.45:1 — under AA
   for 11px bold text, which is not large text at any weight. So the WORDS take
   --text (12.2:1) and the red is carried by the triangle beside them, the border
   and the fill, all of which only owe 3:1 as non-text. Nothing is lost at a
   glance and the label is legible to everybody. */
.sum__worst-label {
  font-size: .6875rem;
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--text);
}

/* The blocker's own title, on its own line.
   It used to be joined to the body with a space, which read as one broken
   sentence because a title carries no full stop: "...which category this is
   being filed under It appears nowhere in your file...". Semibold rather than
   bold, so it separates from the body without competing with the uppercase
   label above it. */
.sum__worst-title {
  margin-top: 2px;
  font-size: .8125rem;
  font-weight: 600;
  line-height: 1.4;
  color: var(--text);
}

.sum__worst-text {
  margin-top: 1px;
  font-size: .8125rem;
  line-height: 1.45;
  color: var(--text);
}

/* Only when both are present: the title supplies the gap otherwise. */
.sum__worst-title + .sum__worst-text { margin-top: 3px; }

/* ------------------------------------------------------------- the detail -- */
/* Collapsed by default and separated by a rule, so at rest the card ends at the
   Next action and the button below the rule reads as "there is more". */

.sum__more {
  margin-top: var(--sum-3);
  border-top: 1px solid var(--border);
}
/* The button comes from client.js disclosure() and arrives as .qn-disc, which
   already gives it the tap height, the glyph slot and the focus ring. Only the
   colour differs: on this card the disclosure is the one thing to press, so it
   is accent-tinted from the start rather than muted-until-hovered.

   --accent-sunk, NOT --accent. --accent is the button-fill and link token: at
   14px on --surface it measures 2.95:1 in light and 2.71:1 in dark, which fails
   AA for text and is WORSE than the muted default it replaced (5.55 / 5.81).
   --accent-sunk is the readable accent in both themes — 9.36:1 light, and it is
   already the pill's colour — so the design's intent survives the audit. */
.sum__more .qn-disc { color: var(--accent-sunk); }
.sum__more .qn-disc:hover { color: var(--text); }

.sum__sect { margin: 4px 0 14px; }
.sum__sect:last-child { margin-bottom: 4px; }

.sum__sh {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-bottom: 6px;
  font-size: .6875rem;
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--text-muted);
}
.sum__sh-rule { flex: 1 1 auto; height: 1px; background: var(--border); }

.sum__list,
.sum__blockers {
  margin: 0;
  font-size: .8125rem;
  line-height: 1.5;
  color: var(--text);
}
.sum__list { padding-left: 18px; }
.sum__blockers { padding-left: 22px; }
.sum__list li,
.sum__blockers li { margin-bottom: 6px; }
/* A bullet is decoration and owes 3:1; a blocker's NUMBER is its rank in the
   order, which is the one thing the array's order means, so it is real text and
   owes 4.5:1. --text-faint gives 3.07:1 and --text-muted 5.55:1 — hence the two
   different tokens for what looks like the same thing. */
.sum__list li::marker { color: var(--text-faint); }
.sum__good li::marker { color: var(--ok); }
.sum__blockers li::marker {
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
}
/* The worst one's number is the only coloured marker in the list. */
.sum__blockers li.sum__b--top::marker { color: var(--danger); font-weight: 700; }
.sum__b-title { font-weight: 650; }

/* Two tags, both text-first: a border and a word, never a colour alone. */
.sum__tag {
  margin-left: 4px;
  padding: 0 4px;
  font-size: .625rem;
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
  white-space: nowrap;
  border-radius: 3px;
  color: var(--text-muted);
  border: 1px solid var(--border-strong);
}
.sum__tag--worst { color: var(--danger); border-color: var(--danger); }
.sum__tag--done  { color: var(--ok); border-color: var(--ok); }

/* How the percentage is worked out. Sits at the bottom of the detail because
   somebody will ask, and the honest answer is short. */
.sum__calc {
  margin: var(--sum-3) 0 4px;
  padding: 8px 10px;
  font-size: .75rem;
  line-height: 1.5;
  color: var(--text-muted);
  background: var(--surface-2);
  border-radius: var(--radius);
}
.sum__calc b { color: var(--text); font-weight: 650; }

/* --------------------------------------------------------- the next action -- */

.sum__next {
  display: flex;
  gap: 8px;
  margin-top: var(--sum-3);
  padding-top: var(--sum-3);
  border-top: 1px solid var(--border);
}
.sum__next-icon {
  flex: none;
  margin-top: 3px;
  width: 15px;
  height: 15px;
  color: var(--accent);
}
.sum__next-label {
  font-size: .6875rem;
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--text-muted);
}
.sum__next-text {
  font-size: .8125rem;
  line-height: 1.5;
  color: var(--text);
}

/* ------------------------------------------------------------- the button -- */

.sum__btns {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: var(--sum-3);
}

/* A quiet failure, in words, under the button that failed. Not a banner: the
   read receipt is a nicety, and a red block across the card would say the
   summary itself went wrong. */
.sum__err {
  margin: 6px 0 0;
  font-size: .8125rem;
  line-height: 1.4;
  color: var(--danger);
}

/* ------------------------------------------------- inside the operator card -- */
/* Read-only, nested inside .op-tenant, which is itself a bordered card. A card
   inside a card at the same elevation reads as a rendering bug, so here the
   summary drops its shadow and its own surface and keeps only the rule that
   separates it from the tenant name above. */

.op-tenant .sum {
  margin: var(--sum-3) 0;
  padding: var(--sum-3) 0 0;
  background: none;
  border: 0;
  border-top: 1px solid var(--border);
  border-radius: 0;
  box-shadow: none;
}
/* The operator's unread signal cannot be a border here, so the dot, the pill,
   the weight and the words carry it alone — which was always the requirement. */
.op-tenant .sum--unread { border-top-color: var(--border-strong); }
