/* ===================================================================
   Design system — Blueprint
   -------------------------------------------------------------------
   The look is Palantir's Blueprint (Apache-2.0, blueprintjs.com),
   rebuilt here rather than pulled in as a dependency: this app needs
   about forty rules out of a framework that ships thousands, and it has
   no React to hang Blueprint's components off. What is replicated is the
   part that makes the look — the palette, the 2px radius, the density,
   and the way edges are drawn with inset shadows instead of borders.

   Four things carry that language:

   1. **Greys, not white.** Light mode sits on #F6F7F9 with white cards;
      dark mode sits on #252A31 with #383E47 cards. Neither is pure.
   2. **Edges are shadows.** `inset 0 0 0 1px rgba(17,20,24,.2)` rather
      than `border: 1px solid`. A shadow does not take up layout space,
      so a focused control can thicken its edge without moving anything
      next to it.
   3. **Dense.** 14px base, 10px grid, 30px controls. The whole point of
      this language is fitting a working record on one screen.
   4. **One intent colour.** Cobalt #2D72D2, and red only for
      destructive. Everything else is grey and reads as structure.

   Density vs. thumbs: Blueprint targets a desktop workstation, and this
   app is opened on a phone. Controls are 30px on a fine pointer and
   grow to 40px under `@media (pointer: coarse)` — the look stays, the
   tap target comes back.
   =================================================================== */

:root {
  /* Blueprint greyscale */
  --black: #111418;
  --dark-gray1: #1c2127;
  --dark-gray2: #252a31;
  --dark-gray3: #2f343c;
  --dark-gray4: #383e47;
  --dark-gray5: #404854;
  --gray1: #5f6b7c;
  --gray2: #738091;
  --gray3: #8f99a8;
  --gray4: #abb3bf;
  --gray5: #c5cbd3;
  --light-gray1: #d3d8de;
  --light-gray2: #dce0e5;
  --light-gray3: #e5e8eb;
  --light-gray4: #edeff2;
  --light-gray5: #f6f7f9;
  --white: #ffffff;

  /* Intents. Cobalt is the only one used for interaction; red is only
     ever destructive. Blueprint's green and orange are deliberately
     absent — nothing here is a status board. */
  --blue1: #184a90;
  --blue2: #215db0;
  --blue3: #2d72d2;
  --blue4: #4c90f0;
  --blue5: #8abbff;
  --red2: #ac2f33;
  --red3: #cd4246;
  --red4: #e76a6e;
  --red5: #fa999c;

  /* Semantic tokens — light */
  --bg: var(--light-gray5);
  --bg-card: var(--white);
  --bg-nav: var(--white);
  --bg-sunken: var(--light-gray4);
  --text: var(--dark-gray1);
  --text-muted: var(--gray1);
  --text-disabled: var(--gray3);
  --primary: var(--blue3);
  --primary-hover: var(--blue2);
  --primary-active: var(--blue1);
  --primary-text: var(--white);
  --danger: var(--red3);
  --danger-hover: var(--red2);
  --flag-overdue: var(--red3);

  /* Edges and elevation, Blueprint's way: shadows, not borders. */
  --edge: rgba(17, 20, 24, 0.2);
  --edge-strong: rgba(17, 20, 24, 0.4);
  --divider: rgba(17, 20, 24, 0.15);
  --elevate-0: 0 0 0 1px rgba(17, 20, 24, 0.15), 0 1px 1px rgba(17, 20, 24, 0.2);
  --elevate-1: 0 0 0 1px rgba(17, 20, 24, 0.1), 0 1px 1px rgba(17, 20, 24, 0.2),
               0 2px 6px rgba(17, 20, 24, 0.2);
  --input-edge: inset 0 0 0 1px var(--edge), inset 0 1px 1px rgba(17, 20, 24, 0.12);
  --input-focus: 0 0 0 1px var(--primary), 0 0 0 3px rgba(45, 114, 210, 0.3),
                 inset 0 1px 1px rgba(17, 20, 24, 0.2);
  --button-face: linear-gradient(to bottom, rgba(255, 255, 255, 0.8), rgba(255, 255, 255, 0));
  --button-edge: inset 0 0 0 1px var(--edge), 0 1px 1px rgba(17, 20, 24, 0.1);

  --radius: 2px;
  --grid: 10px;
  --control-height: 30px;
  --control-height-small: 24px;
}

/* Dark is Blueprint's signature: the palette is built for it, and the
   greys were chosen to sit under it. Applied by system preference
   unless [data-theme] says otherwise. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --bg: var(--dark-gray2);
    --bg-card: var(--dark-gray4);
    --bg-nav: var(--dark-gray4);
    --bg-sunken: var(--dark-gray1);
    --text: var(--light-gray5);
    --text-muted: var(--gray4);
    --text-disabled: var(--gray2);
    --primary: var(--blue4);
    --primary-hover: var(--blue5);
    --primary-active: var(--blue3);
    --primary-text: var(--white);
    --danger: var(--red4);
    --danger-hover: var(--red5);
    --flag-overdue: var(--red4);
    --edge: rgba(17, 20, 24, 0.4);
    --edge-strong: rgba(17, 20, 24, 0.6);
    --divider: rgba(255, 255, 255, 0.15);
    --elevate-0: 0 0 0 1px rgba(17, 20, 24, 0.4), 0 1px 1px rgba(17, 20, 24, 0.4);
    --elevate-1: 0 0 0 1px rgba(17, 20, 24, 0.2), 0 1px 1px rgba(17, 20, 24, 0.4),
                 0 2px 6px rgba(17, 20, 24, 0.4);
    --input-edge: inset 0 0 0 1px rgba(17, 20, 24, 0.5), inset 0 1px 1px rgba(17, 20, 24, 0.5);
    --input-focus: 0 0 0 1px var(--primary), 0 0 0 3px rgba(76, 144, 240, 0.3),
                   inset 0 1px 1px rgba(17, 20, 24, 0.5);
    --button-face: linear-gradient(to bottom, rgba(255, 255, 255, 0.05), rgba(255, 255, 255, 0));
    --button-edge: inset 0 0 0 1px rgba(17, 20, 24, 0.4), 0 1px 1px rgba(17, 20, 24, 0.4);
  }
}

[data-theme="dark"] {
  --bg: var(--dark-gray2);
  --bg-card: var(--dark-gray4);
  --bg-nav: var(--dark-gray4);
  --bg-sunken: var(--dark-gray1);
  --text: var(--light-gray5);
  --text-muted: var(--gray4);
  --text-disabled: var(--gray2);
  --primary: var(--blue4);
  --primary-hover: var(--blue5);
  --primary-active: var(--blue3);
  --primary-text: var(--white);
  --danger: var(--red4);
  --danger-hover: var(--red5);
  --flag-overdue: var(--red4);
  --edge: rgba(17, 20, 24, 0.4);
  --edge-strong: rgba(17, 20, 24, 0.6);
  --divider: rgba(255, 255, 255, 0.15);
  --elevate-0: 0 0 0 1px rgba(17, 20, 24, 0.4), 0 1px 1px rgba(17, 20, 24, 0.4);
  --elevate-1: 0 0 0 1px rgba(17, 20, 24, 0.2), 0 1px 1px rgba(17, 20, 24, 0.4),
               0 2px 6px rgba(17, 20, 24, 0.4);
  --input-edge: inset 0 0 0 1px rgba(17, 20, 24, 0.5), inset 0 1px 1px rgba(17, 20, 24, 0.5);
  --input-focus: 0 0 0 1px var(--primary), 0 0 0 3px rgba(76, 144, 240, 0.3),
                 inset 0 1px 1px rgba(17, 20, 24, 0.5);
  --button-face: linear-gradient(to bottom, rgba(255, 255, 255, 0.05), rgba(255, 255, 255, 0));
  --button-edge: inset 0 0 0 1px rgba(17, 20, 24, 0.4), 0 1px 1px rgba(17, 20, 24, 0.4);
}

[data-theme="light"] {
  --bg: var(--light-gray5);
  --bg-card: var(--white);
  --bg-nav: var(--white);
  --bg-sunken: var(--light-gray4);
  --text: var(--dark-gray1);
  --text-muted: var(--gray1);
  --text-disabled: var(--gray3);
  --primary: var(--blue3);
  --primary-hover: var(--blue2);
  --primary-active: var(--blue1);
  --danger: var(--red3);
  --danger-hover: var(--red2);
  --flag-overdue: var(--red3);
  --edge: rgba(17, 20, 24, 0.2);
  --edge-strong: rgba(17, 20, 24, 0.4);
  --divider: rgba(17, 20, 24, 0.15);
  --elevate-0: 0 0 0 1px rgba(17, 20, 24, 0.15), 0 1px 1px rgba(17, 20, 24, 0.2);
  --elevate-1: 0 0 0 1px rgba(17, 20, 24, 0.1), 0 1px 1px rgba(17, 20, 24, 0.2),
               0 2px 6px rgba(17, 20, 24, 0.2);
  --input-edge: inset 0 0 0 1px var(--edge), inset 0 1px 1px rgba(17, 20, 24, 0.12);
  --input-focus: 0 0 0 1px var(--primary), 0 0 0 3px rgba(45, 114, 210, 0.3),
                 inset 0 1px 1px rgba(17, 20, 24, 0.2);
  --button-face: linear-gradient(to bottom, rgba(255, 255, 255, 0.8), rgba(255, 255, 255, 0));
  --button-edge: inset 0 0 0 1px var(--edge), 0 1px 1px rgba(17, 20, 24, 0.1);
}

/* Coarse pointer: keep the language, give the thumb something to hit. */
@media (pointer: coarse) {
  :root {
    --control-height: 40px;
    --control-height-small: 32px;
  }
}

/* ===== Base ===== */
*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  /* Blueprint's stack: the platform's own UI face, never a webfont. */
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen,
    Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", sans-serif;
  font-size: 14px;
  line-height: 1.28581;
  letter-spacing: 0;
  color: var(--text);
  background: var(--bg);
  min-height: 100vh;
  -webkit-font-smoothing: antialiased;
}

p { margin: 0 0 var(--grid); line-height: 1.5; }
a { color: var(--primary); text-decoration: none; }
a:hover { color: var(--primary-hover); text-decoration: underline; }
a:focus-visible,
button:focus-visible,
summary:focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: 2px;
}

h1, h2, h3 {
  color: var(--text);
  font-weight: 600;
  line-height: 1.2;
  margin: 0;
}

/* A section label, used over every run of rows in the app. Blueprint's
   quiet uppercase heading: it names the run without competing with the
   rows under it. One definition, so every list is headed the same way. */
.section-group,
.action-group h2,
.risk-group h2 {
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.4px;
  text-transform: uppercase;
  color: var(--text-muted);
  margin: 0 0 6px;
}
.section-group,
.action-group { margin-top: 24px; }
.action-group h2 a { color: inherit; }
.action-group h2 a:hover { color: var(--primary); text-decoration: none; }

.muted { color: var(--text-muted); }

/* One column, one pair of edges. Everything on a screen — cards, fields,
   buttons, the prompt box — is the width of this and lines up flush left
   and flush right. A form capped at its own measure inside a wider column
   was the single loudest inconsistency in the app: on the problem screen
   the add-fact box stopped half way across while every card beside it ran
   to the edge. 720px is the compromise that width has to be: wide enough
   that a paragraph of model commentary is not a ribbon, narrow enough
   that a line of it is still readable. */
.container {
  max-width: 720px;
  margin: 0 auto;
  padding: 20px 16px 64px;
}

/* ===== Navbar =====
   Blueprint's navbar: 50px, its own elevation, and it stays put. The
   app is a working surface — losing the nav on scroll costs a scroll
   back up every time. */
.navbar {
  height: 50px;
  padding: 0 15px;
  background: var(--bg-nav);
  box-shadow: var(--elevate-0);
  display: flex;
  align-items: center;
  justify-content: space-between;
  position: sticky;
  top: 0;
  z-index: 20;
}
.navbar .brand {
  font-size: 16px;
  font-weight: 600;
  letter-spacing: -0.2px;
  color: var(--text);
  text-decoration: none;
}
.navbar .brand:hover { color: var(--primary); text-decoration: none; }

.nav-links { display: flex; align-items: center; gap: 2px; }

/* Nav items are Blueprint minimal buttons: no face until you touch
   them, so the bar reads as one surface rather than a row of objects. */
.nav-link {
  display: inline-flex;
  align-items: center;
  height: var(--control-height);
  padding: 0 10px;
  border: none;
  border-radius: var(--radius);
  background: none;
  color: var(--text-muted);
  font: inherit;
  font-size: 14px;
  cursor: pointer;
  text-decoration: none;
  white-space: nowrap;
}
.nav-link:hover {
  background: rgba(143, 153, 168, 0.15);
  color: var(--text);
  text-decoration: none;
}
.nav-link:active { background: rgba(143, 153, 168, 0.3); }

.hamburger {
  display: none;
  height: var(--control-height);
  padding: 0 10px;
  border: none;
  border-radius: var(--radius);
  background: none;
  color: var(--text);
  font-size: 16px;
  line-height: 1;
  cursor: pointer;
}
.hamburger:hover { background: rgba(143, 153, 168, 0.15); }

/* ===== Cards =====
   Blueprint's card: a 2px rectangle lifted off the background by a
   shadow that doubles as its edge. One row shape for the whole app —
   the problem list, the action list, a fact, a risk category. */
.card {
  position: relative;
  background: var(--bg-card);
  border-radius: var(--radius);
  box-shadow: var(--elevate-0);
  padding: 12px 15px;
  margin-bottom: 8px;
}
.card:last-child { margin-bottom: 0; }

.card-list { list-style: none; margin: 0; padding: 0; }
/* An empty list says so in a line of prose. That is a message, not a card. */
.card-list > li.muted {
  padding: 10px 0;
  background: none;
  box-shadow: none;
  font-size: 13px;
}

/* The whole card is the link.
   The row's primary link stretches an invisible layer over the card, so
   a tap anywhere on it goes where the title went. It stays a real
   anchor — focus ring, middle-click, copy link address all still work,
   and no JS is involved. Anything else interactive in the card must be
   lifted above that layer or the card swallows it. */
.card-title,
.action-title {
  display: block;
  color: var(--text);
  text-decoration: none;
  font-weight: 600;
  font-size: 14px;
  word-break: break-word;
}
.card-title::after,
.action-title::after,
.section-edit::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
}
.card .row-buttons { position: relative; z-index: 1; }

/* Only the cards that go somewhere react to being touched. A card that
   is a set of controls — a fact, a risk category, a comment — must not
   light up as though it were a target. */
.card:has(.card-title, .action-title, .section-edit):hover {
  box-shadow: var(--elevate-1);
}
.card:hover .card-title,
.card:hover .action-title { color: var(--primary); }
/* Touch has no hover, so the press itself has to answer. */
.card:has(.card-title, .action-title, .section-edit):active {
  box-shadow: var(--elevate-0);
  background: var(--bg-sunken);
}
.card:focus-within { box-shadow: var(--elevate-1); }

.card-preview {
  margin: 4px 0 0;
  font-size: 13px;
  color: var(--text-muted);
  line-height: 1.4;
}
.card-list .card > p.muted { margin: 4px 0 0; font-size: 12px; }

/* ===== Buttons =====
   Blueprint's button: a grey face with a gradient sheen, an inset edge,
   and a drop shadow of one pixel. Pressing it flattens the sheen and
   darkens the face — the whole affordance is in the lighting. */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  height: var(--control-height);
  min-height: var(--control-height);
  padding: 0 10px;
  border: none;
  border-radius: var(--radius);
  background-color: var(--bg-card);
  background-image: var(--button-face);
  box-shadow: var(--button-edge);
  color: var(--text);
  font-family: inherit;
  font-size: 14px;
  font-weight: 400;
  line-height: 1;
  text-align: center;
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
  vertical-align: middle;
}
.btn:hover {
  background-color: var(--bg-sunken);
  background-image: none;
  color: var(--text);
  text-decoration: none;
  box-shadow: var(--button-edge);
}
.btn:active {
  background-color: var(--light-gray1);
  background-image: none;
  box-shadow: inset 0 0 0 1px var(--edge), inset 0 1px 2px rgba(17, 20, 24, 0.2);
}
[data-theme="dark"] .btn:active { background-color: var(--dark-gray5); }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .btn:active { background-color: var(--dark-gray5); }
}

.btn-primary {
  background-color: var(--primary);
  background-image: var(--button-face);
  color: var(--primary-text);
  box-shadow: inset 0 0 0 1px rgba(17, 20, 24, 0.2), 0 1px 1px rgba(17, 20, 24, 0.2);
}
.btn-primary:hover {
  background-color: var(--primary-hover);
  background-image: none;
  color: var(--primary-text);
}
.btn-primary:active {
  background-color: var(--primary-active);
  background-image: none;
}

.btn-danger {
  background-color: var(--danger);
  background-image: var(--button-face);
  color: var(--white);
  box-shadow: inset 0 0 0 1px rgba(17, 20, 24, 0.2), 0 1px 1px rgba(17, 20, 24, 0.2);
}
.btn-danger:hover { background-color: var(--danger-hover); background-image: none; color: var(--white); }

/* Minimal: no face at all until touched. For the secondary action in a
   row, where a full button face would give it equal weight. */
.btn-quiet {
  background: none;
  box-shadow: none;
  color: var(--text-muted);
}
.btn-quiet:hover {
  background: rgba(143, 153, 168, 0.15);
  box-shadow: none;
  color: var(--text);
}
.btn-quiet:active { background: rgba(143, 153, 168, 0.3); box-shadow: none; }

.btn-small {
  height: var(--control-height-small);
  min-height: var(--control-height-small);
  padding: 0 7px;
  font-size: 12px;
}
/* Square, so a one-glyph button is not a wide slab. */
.btn-icon { width: var(--control-height-small); padding: 0; }

.btn:disabled,
.btn[disabled] {
  background: rgba(143, 153, 168, 0.15);
  background-image: none;
  box-shadow: none;
  color: var(--text-disabled);
  cursor: not-allowed;
}

/* ===== Forms =====
   One field style for the whole app. There used to be three — one
   inside a form, one in the filter bar, one on the login card — which
   is what made the screens look assembled rather than designed. */
label {
  display: block;
  font-size: 14px;
  font-weight: 600;
  margin: 0 0 5px;
  color: var(--text);
}

input[type="text"],
input[type="email"],
input[type="password"],
input[type="date"],
input[type="datetime-local"],
input[type="search"],
input[type="tel"],
input[type="number"],
select,
textarea {
  width: 100%;
  height: var(--control-height);
  padding: 0 10px;
  border: none;
  border-radius: var(--radius);
  background: var(--bg-card);
  box-shadow: var(--input-edge);
  color: var(--text);
  font-family: inherit;
  font-size: 14px;
  line-height: normal;
  vertical-align: middle;
}
/* Native appearance is kept on purpose. Stripping it takes the select's
   chevron and the date field's calendar button with it, and a dropdown
   that looks like a text box is a dropdown nobody opens. */
select { padding-right: 6px; }
input[type="search"] { -webkit-appearance: none; appearance: none; }
textarea {
  height: auto;
  min-height: 60px;
  padding: 8px 10px;
  line-height: 1.5;
  resize: vertical;
}
input::placeholder, textarea::placeholder { color: var(--text-disabled); }
input:focus, select:focus, textarea:focus {
  outline: none;
  box-shadow: var(--input-focus);
}

.form-group { margin-bottom: 15px; }

/* Django's `as_p` wraps each field in a <p>; this is the label-over-field
   stack every form in the app uses. It takes the column width like
   everything else — no measure of its own, because a form is never the
   only thing on its screen and a second edge is what reads as untidy. */
.stacked-form p { margin: 0 0 15px; }
.stacked-form ul { list-style: none; margin: 0; padding: 0; }

.helptext {
  display: block;
  margin-top: 5px;
  font-size: 12px;
  color: var(--text-muted);
}
/* Emitted by Django's own form rendering, not by any template here. */
.errorlist {
  list-style: none;
  margin: 5px 0 0;
  padding: 0;
  font-size: 12px;
  color: var(--danger);
}

/* A form's actions, and a row of actions under a heading. Both are a
   run of buttons with room above them — the gap is what stops a Save
   reading as part of the field it follows. */
.form-buttons,
.row-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  margin: 20px 0 0;
}
/* Adjacent margins collapse, so this is the gap, not an addition to the
   field's 15px. Stated as its own rule because it is load-bearing: a bare
   <button> after a field inherits only that field's margin and reads as
   part of it. */
.stacked-form .form-buttons { margin-top: 20px; }
.row-actions { margin: 12px 0 20px; }
.form-buttons form, .row-actions form { margin: 0; }
.inline { display: inline; margin: 0; }

/* ===== Filter bar ===== */
.filters {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-bottom: 20px;
}
.filters input[type="search"] { flex: 1; min-width: 140px; width: auto; }
.filters .btn { height: var(--control-height); min-height: var(--control-height); }

/* ===== Page header ===== */
.page-head {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 10px;
  margin-bottom: 15px;
}
.page-head h1 { font-size: 20px; font-weight: 600; }
.page-head .btn { margin-left: auto; align-self: center; }

/* ===== Back link =====
   The one way back, on every screen that is not in the nav bar. */
.back-link {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  margin-bottom: 12px;
  font-size: 12px;
  color: var(--text-muted);
  text-decoration: none;
}
.back-link:hover { color: var(--primary); text-decoration: none; }

/* ===== Tags =====
   Blueprint's tag: a small solid rectangle, not a pill. `.badge` is the
   minimal variant — translucent grey — and `.flag-quiet` is the same
   thing used as a status on a heading row. */
.badge,
.flag-quiet {
  display: inline-flex;
  align-items: center;
  padding: 2px 6px;
  border-radius: var(--radius);
  background: rgba(143, 153, 168, 0.2);
  color: var(--text-muted);
  font-size: 12px;
  font-weight: 400;
  letter-spacing: 0;
  text-transform: none;
  white-space: nowrap;
}
/* Overdue is the only colour in a list, so it is a filled tag rather
   than coloured text — at 12px, colour alone is too quiet to count. */
.flag { font-weight: 600; }
.flag-overdue {
  display: inline-flex;
  align-items: center;
  padding: 2px 6px;
  border-radius: var(--radius);
  background: var(--danger);
  color: var(--white);
  font-size: 12px;
  font-weight: 600;
  white-space: nowrap;
}

/* ===== Callouts =====
   Flash messages and inline notices. A tinted block with a left keyline,
   Blueprint's callout shape. */
.messages { margin-bottom: 15px; }
.alert,
.notice {
  padding: 10px 12px;
  border-radius: var(--radius);
  background: rgba(143, 153, 168, 0.15);
  border-left: 3px solid var(--gray3);
  font-size: 13px;
  line-height: 1.5;
  margin-bottom: 10px;
}
.alert-success { border-left-color: var(--primary); }
.alert-info { border-left-color: var(--gray3); }
.alert-error,
.alert-warning,
.notice-danger {
  background: rgba(205, 66, 70, 0.15);
  border-left-color: var(--danger);
  color: var(--text);
}

/* ===================================================================
   Screens
   =================================================================== */

/* ===== Problem: statement and solution =====
   The card holds prose and nothing else; its label sits above it like
   every other section label on the screen. The prose *is* the link to
   the editor, stretched over the whole card — so the card opens without
   a second "Edit" door on it. It is set as body text rather than as an
   anchor: a paragraph rendered in accent blue would read as a link to
   somewhere else, and the affordance is the card lifting on hover. */
.context-section { padding: 12px 15px; }
.section-edit {
  display: block;
  color: var(--text);
  text-decoration: none;
  font-size: 14px;
  line-height: 1.5;
}
.section-edit:hover { color: var(--text); text-decoration: none; }
.context-block { margin: 0; font-size: 14px; line-height: 1.5; }

/* ===== Facts and operating principles =====
   Cards, but not clickable ones: three controls each and no single
   destination. */
.block-list { margin-bottom: 15px; }
.block p { margin: 0 0 8px; line-height: 1.5; }
.block-actions {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 4px;
}
/* A row that has run out of room breaks rather than squeezing its
   controls past their own labels. */
.block-actions > * { flex: 0 0 auto; }
.block-actions form { margin: 0; }
/* The arrows are one control in two halves: joined, and kept together
   when the row wraps. Each is its own form (a POST, not a link), so the
   joined edges are addressed through the form — the button is never
   :first-child of one, the CSRF input is. */
.block-move { display: flex; }
.block-move form:first-child .btn-icon {
  border-top-right-radius: 0;
  border-bottom-right-radius: 0;
}
.block-move form:last-child .btn-icon {
  border-top-left-radius: 0;
  border-bottom-left-radius: 0;
}

.principle-title { font-weight: 600; margin: 0 0 4px; font-size: 14px; }
.principle-body { margin: 0 0 8px; font-size: 13px; color: var(--text-muted); line-height: 1.5; }

/* ===== Actions ===== */
.action-row {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
}
.action-main { flex: 1; min-width: 0; }
.action-meta { margin: 3px 0 0; font-size: 12px; color: var(--text-muted); }
.row-buttons {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  justify-content: flex-end;
}
.row-buttons > * { flex: 0 0 auto; }
.row-buttons form { margin: 0; }

/* Done crosses an action out instead of deleting it, so it has to look
   finished without disappearing: struck through and faded, still a real
   link, still reopenable. */
.done-list { margin-top: 8px; }
.card.action-done { opacity: 0.6; }
.action-done .action-title { text-decoration: line-through; }
.action-done .row-buttons { opacity: 1; }

/* ===== Risk appetite =====
   A category is a card holding one control. The heading row is a flex
   row and the dropdown is pushed to its end, so seven of them line up
   in a column against the right-hand edge — which is how the set is
   read, since one appetite only means something next to the others.

   The flex row is load-bearing, not decoration: `margin-left: auto`
   has nothing to push against without it, and the select drops under
   the label. */
.risk-group { padding: 10px 15px; }
.risk-group h2 {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 0;
}
/* The category's definition, under its heading row and clear of the
   dropdown's column. */
.risk-group > p.muted {
  margin: 4px 0 0;
  padding-right: 140px;
  font-size: 12px;
  line-height: 1.4;
}
/* The heading is a label for the control beside it, so it sheds the
   global label styling — block, 14px, own weight — to stay a heading. */
.risk-group h2 label {
  display: inline;
  margin: 0;
  font: inherit;
  letter-spacing: inherit;
  text-transform: inherit;
  color: inherit;
  cursor: pointer;
}
.risk-group select {
  margin-left: auto;
  width: auto;
  min-width: 130px;
}
/* Save lines up under the column of dropdowns rather than under the
   category names: it belongs to the controls, not to the labels. */
.risk-form .form-buttons { justify-content: flex-end; }

/* ===== Comment =====
   Prose from the model, and the prompt that produced it. The card
   carries no link, so it is content rather than a target — no hover, no
   stretch layer. */
.advice { margin-top: 24px; }
.comment-card { margin-top: 12px; padding: 15px; }
.comment-meta {
  margin: 0 0 8px;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.4px;
  text-transform: uppercase;
  color: var(--text-muted);
}

/* The model answers in markdown, so the card holds prose with structure in
   it — headings, bullets, the occasional quote — rather than one run of
   text. Blueprint is a component language and has no prose style; this is
   the smallest set of rules that keeps model output looking like part of
   the app instead of a README dropped into it. The rendering itself is in
   problems/markdown.py. */
.comment-body { font-size: 14px; line-height: 1.55; }
.comment-body > :first-child { margin-top: 0; }
.comment-body > :last-child { margin-bottom: 0; }
.comment-body p { margin: 0 0 var(--grid); }

/* Headings inside prose, which is not the same thing as a section label:
   the uppercase rule up the file would turn a sentence into a shout.
   Weight and the space above carry them instead. */
.comment-body h3,
.comment-body h4,
.comment-body h5,
.comment-body h6 {
  font-size: 14px;
  font-weight: 600;
  line-height: 1.3;
  margin: 18px 0 6px;
}
.comment-body h3 { font-size: 15px; }

.comment-body ul,
.comment-body ol { margin: 0 0 var(--grid); padding-left: 22px; }
.comment-body li { margin-bottom: 4px; }
.comment-body li:last-child { margin-bottom: 0; }
.comment-body li > ul,
.comment-body li > ol { margin: 4px 0 0; }
.comment-body strong { font-weight: 600; }

/* A quote is set off by a rule down its left edge, drawn as a shadow like
   every other edge in the app. */
.comment-body blockquote {
  margin: 0 0 var(--grid);
  padding: 2px 0 2px 12px;
  box-shadow: inset 2px 0 0 var(--divider);
  color: var(--text-muted);
}

.comment-body code {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 12px;
  padding: 1px 4px;
  border-radius: var(--radius);
  background: var(--bg-sunken);
  box-shadow: inset 0 0 0 1px var(--edge);
}
.comment-body pre {
  margin: 0 0 var(--grid);
  padding: 10px 12px;
  overflow-x: auto;
  border-radius: var(--radius);
  background: var(--bg-sunken);
  box-shadow: inset 0 0 0 1px var(--edge);
}
.comment-body pre code { padding: 0; background: none; box-shadow: none; }
/* Tables, because the model reaches for one every time it is asked for a
   verdict per principle or per risk category. The cells hold sentences
   rather than numbers, so three columns do not fit a phone at any density
   worth having: the table keeps a readable minimum width and the wrapper
   scrolls sideways under it rather than crushing the words. Edges are
   shadows here too — a collapsed border would put a 1px line back into the
   layout. */
.comment-body .table-scroll {
  margin: 0 0 var(--grid);
  overflow-x: auto;
}
.comment-body table {
  width: 100%;
  min-width: 480px;
  border-collapse: collapse;
  font-size: 13px;
}
.comment-body th,
.comment-body td {
  padding: 7px 10px;
  text-align: left;
  vertical-align: top;
  line-height: 1.45;
  box-shadow: inset 0 -1px 0 var(--divider);
}
.comment-body th {
  font-weight: 600;
  box-shadow: inset 0 -1px 0 var(--edge-strong);
}
.comment-body tbody tr:last-child th,
.comment-body tbody tr:last-child td { box-shadow: none; }
.comment-body .md-center { text-align: center; }
.comment-body .md-right { text-align: right; }

.comment-body hr {
  height: 1px;
  margin: 16px 0;
  border: none;
  background: var(--divider);
}

/* Closed by default: the prompt is long, and it is there to be copied
   rather than read. Opening it is also the fallback when the clipboard
   API is unavailable — http on a LAN address, which is how this is
   served. */
.prompt-box { margin: 12px 0; }
.prompt-box summary {
  display: inline-flex;
  align-items: center;
  height: var(--control-height-small);
  font-size: 12px;
  color: var(--text-muted);
  cursor: pointer;
  list-style: none;
}
.prompt-box summary::-webkit-details-marker { display: none; }
.prompt-box summary::before { content: "▸"; margin-right: 5px; }
.prompt-box[open] summary::before { content: "▾"; }
.prompt-box summary:hover { color: var(--primary); }
.prompt-box textarea {
  margin-top: 6px;
  background: var(--bg-sunken);
  font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  font-size: 12px;
  line-height: 1.5;
  white-space: pre-wrap;
}

/* ===== Login ===== */
.login-wrap {
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 32px 16px;
  background: var(--bg);
}
.login-card {
  width: 100%;
  max-width: 360px;
  padding: 24px;
  background: var(--bg-card);
  border-radius: var(--radius);
  box-shadow: var(--elevate-1);
}
.login-title {
  margin: 0 0 24px;
  font-size: 20px;
  font-weight: 600;
  text-align: center;
  color: var(--text);
}

/* ===== Responsive ===== */
@media (max-width: 640px) {
  .hamburger { display: inline-flex; align-items: center; }

  .nav-links {
    display: none;
    flex-direction: column;
    align-items: stretch;
    position: absolute;
    top: 50px;
    left: 0;
    right: 0;
    padding: 5px;
    gap: 2px;
    background: var(--bg-nav);
    box-shadow: var(--elevate-1);
    z-index: 19;
  }
  .nav-links.nav-open { display: flex; }
  .nav-link { width: 100%; justify-content: flex-start; height: 40px; }

  .container { padding: 15px 12px 48px; }
  .page-head { gap: 8px; }
  /* Title and buttons stop competing for one line: the buttons take
     their own, still as a row. */
  .action-main { flex: 1 1 100%; }
  .action-row .row-buttons { justify-content: flex-start; }
}
