/* ---------------------------------------------------------------------------
   Additions specific to the proposal request form. tokens.css and style.css are
   shared with the other apps on this host and are not edited here - anything
   that belongs to the house style goes there, and only what is peculiar to this
   form goes in this file.

   No colour, radius, spacing or font value is written literally below; they all
   come from the tokens. That is what keeps the four apps looking like one.
--------------------------------------------------------------------------- */

/* ------------------------------------------------------------------ sidebar */

.sidebar nav { display: flex; flex-direction: column; gap: var(--space-1); }

.navlink {
  all: unset;
  display: block;
  cursor: pointer;
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius);
  font-family: var(--font);
  font-size: var(--text-base);
  color: #cfd9ea;
}
.navlink:hover { background: rgba(255, 255, 255, 0.08); color: #ffffff; }
.navlink.current { background: var(--blue); color: #ffffff; font-weight: var(--weight-medium); }

.sidebar .who {
  margin-block-start: auto;
  border-block-start: 1px solid rgba(255, 255, 255, 0.14);
  padding-block-start: var(--space-4);
}
.sidebar .who .name { color: #ffffff; font-size: var(--text-sm); font-weight: var(--weight-medium); margin: 0; }
.sidebar .who .role { color: #9fb2ce; font-size: var(--text-xs); margin: 0 0 var(--space-3); }
.sidebar .who button { inline-size: 100%; }

/* -------------------------------------------------------------------- forms */

/* Four columns on a wide screen. Fields declare how many they span, so the
   layout is described where each field is rather than in a media query per
   section. */
.form-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 0 var(--space-4);
}
.form-grid .span2 { grid-column: span 2; }
.form-grid .span4 { grid-column: span 4; }

/* The asterisk is decoration; the real requirement is stated in the action bar
   and enforced by the server. */
.req { color: var(--burgundy); font-weight: var(--weight-bold); }

textarea { resize: vertical; min-block-size: 60px; }
input[type="number"] {
  inline-size: 100%;
  padding: var(--space-2) var(--space-3);
  border: 1px solid #d5dde7;
  border-radius: var(--radius);
  font-family: var(--font);
  font-size: var(--text-base);
  color: var(--ink);
  background: #ffffff;
}

.toolbar-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  align-items: center;
  margin-inline-start: auto;
}
.toolbar-actions input[type="text"] { inline-size: 220px; }
.toolbar-actions select { inline-size: auto; }

/* The client's budget closes the services card, ruled off above so it reads as
   context for the lines rather than as another service row. The rule is on the
   leading edge because it now follows them. */
.budget-trail {
  padding-block-start: var(--space-3);
  margin-block-start: var(--space-4);
  border-block-start: 1px solid var(--line-soft);
}

/* ------------------------------------------------------- the approval screen */

/* The handful of facts a head needs to recognise which proposal this is.
   One cell per pair, label above value: an email address is longer than any
   label and has to be free to wrap inside its own cell rather than run over the
   next one. */
.approve-facts {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr));
  gap: var(--space-3) var(--space-4);
  margin-block: var(--space-4);
}

/* min-inline-size:0 because a grid item defaults to its content's minimum
   width, which for an unbroken address is the whole address. */
.approve-facts .fact { min-inline-size: 0; }

.approve-facts dt {
  margin-block-end: 0.125rem;
  font-size: 0.8125rem;
  color: var(--ink-soft);
}

.approve-facts dd {
  margin: 0;
  font-weight: 600;
  color: var(--ink);
  overflow-wrap: anywhere;
}

/* The proposal that will actually be sent. A .filerow like the earlier versions
   below it would put opening the document - the thing this screen exists to make
   possible - on the same footing as a row of metadata. So: its own card, and a
   button rather than a link. */
.proposal-card {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
  margin-block-end: var(--space-3);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--bg);
}

/* min-inline-size:0 for the same reason as .fact above: a long file name would
   otherwise refuse to wrap and push the button off the card. */
.proposal-card .meta {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--space-3);
  min-inline-size: 0;
  font-size: var(--text-sm);
}

.proposal-card .meta strong { overflow-wrap: anywhere; }
.proposal-card .hint { margin: 0; }

/* Styled to match button.primary in style.css rather than sharing it: that file
   is common to the four apps on this host and is not edited from here, and its
   rule is scoped to `button`, which this is not - it has to be an anchor to
   carry an href the browser can open in a new tab. */
a.open-proposal {
  padding: var(--space-2) var(--space-4);
  border: 1px solid transparent;
  border-radius: var(--radius);
  background: var(--brand-accent);
  color: #ffffff;
  font-family: var(--font);
  font-size: var(--text-base);
  font-weight: var(--weight-medium);
  text-decoration: none;
  white-space: nowrap;
}

a.open-proposal:hover { background: var(--navy); color: #ffffff; }

/* Composing a reminder without leaving the client. Set into the proposals card
   rather than floating over it: it is about one row in the list above it, and a
   modal would hide the very thing being chased. */
.chase-box {
  margin-block-start: var(--space-4);
  padding: var(--space-4);
  border: 1px solid var(--line);
  border-inline-start: 3px solid var(--brand-accent);
  border-radius: 0 var(--radius) var(--radius) 0;
  background: var(--bg);
}

.chase-box .trail-head { margin-block-start: 0; }
.chase-box .mailpreview { margin-block-start: var(--space-3); }

/* ------------------------------------------------------- the client centre */

/* How many follow-ups are late, against Clients in the sidebar. A count and not
   a dot: "3" is worth walking over to, an unexplained dot is not. */
.navcount {
  display: inline-block;
  margin-inline-start: var(--space-2);
  padding: 0 var(--space-2);
  border-radius: 999px;
  background: var(--status-expired);
  color: #ffffff;
  font-size: var(--text-xs);
  font-weight: var(--weight-bold);
  line-height: 1.5;
}

/* A cell in the clients table stacks a name over its detail rather than running
   them together - a company name and an email address on one line is a line
   nobody reads to the end. */
#clients-body td > span,
#clients-body td > strong { display: block; }
#clients-body td .hint { margin: 0; }

.empty {
  color: var(--muted);
  font-size: var(--text-sm);
  padding: var(--space-4) 0 0;
  margin: 0;
}

/* One entry in the follow-up log. The leading edge carries the urgency, so a
   page of them can be scanned down the margin without reading a word. */
.followup {
  padding: var(--space-3) var(--space-4);
  margin-block-end: var(--space-2);
  border: 1px solid var(--line);
  border-inline-start: 3px solid var(--line);
  border-radius: var(--radius);
  background: var(--bg);
}

.followup.late { border-inline-start-color: var(--status-expired); }

/* Done is quieter, not hidden. The log is a record of what was said to a client,
   and something completed last month is still the reason the next thing exists. */
.followup.done { opacity: 0.62; }

.followup-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--space-2) var(--space-3);
  margin-block-end: var(--space-2);
}

.followup-head .hint { margin: 0; }

.followup-note {
  margin: 0;
  color: var(--ink);
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

.followup-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3);
  margin-block-start: var(--space-2);
}

.followup-actions .hint { margin: 0; }

/* The add-a-follow-up row sits above the log it writes into, so it needs a rule
   under it or the first entry reads as part of the form. */
.followup-add {
  padding-block-end: var(--space-3);
  margin-block-end: var(--space-4);
  border-block-end: 1px solid var(--line-soft);
}

/* Both lists sat flush against the button that adds to them - the first entry
   started at the exact pixel the button ended, so "Add follow-up" read as part
   of the entry beneath it rather than as the end of the form above it.

   The space belongs to the list rather than to the button, and :not(:empty) is
   why: with nothing logged yet there is no list to separate, and the empty
   message carries its own padding. So the gap appears exactly when there is
   something for it to separate. */
#followups:not(:empty),
#client-files:not(:empty),
#client-proposals:not(:empty) {
  margin-block-start: var(--space-4);
}

/* ------------------------------------------------------- what the client said */

/* One click per answer, rather than a dropdown and a save. The four states are
   short and mutually exclusive, which is exactly the case a row of buttons reads
   better than a select - and the answer is usually known the moment somebody
   opens this card. */
.reply-choices {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin-block: var(--space-3) var(--space-4);
}

.reply-choice {
  padding: var(--space-2) var(--space-4);
  border: 1px solid #d5dde7;
  border-radius: var(--radius);
  background: #ffffff;
  color: var(--body);
  font-family: var(--font);
  font-size: var(--text-sm);
  cursor: pointer;
}

.reply-choice:hover { background: var(--navy-soft); }

.reply-choice.picked {
  border-color: var(--brand-accent);
  background: var(--blue-soft);
  color: var(--navy);
  font-weight: var(--weight-medium);
}

/* How long it has been quiet. Two levels rather than one, because a week of
   silence and a month of it call for different conversations, and a single
   colour would say the same thing about both. */
.quiet-soft,
.quiet-hard {
  display: inline-block;
  margin-block-start: 2px;
  font-size: var(--text-xs);
  font-weight: var(--weight-medium);
}

.quiet-soft { color: var(--status-due-soon); }
.quiet-hard { color: var(--status-expired); }

/* The two halves of the document trail. A quiet label rather than a heading:
   they divide one card, and an <h3> here would compete with the card's own. */
.trail-head {
  margin-block: var(--space-4) var(--space-2);
  font-size: var(--text-xs);
  font-weight: var(--weight-medium);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--muted);
}

#client-sent .trail-head:first-child { margin-block-start: 0; }

/* --------------------------------------------------------- seniority rows */

/* Which seniorities a recruitment line is hiring, one per row. A grid rather
   than repeated labelled fields, so three of them read as a small table. */
.seniority-head,
.seniority-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 7.5rem 9rem auto;
  gap: var(--space-2);
  align-items: center;
}

.seniority-head {
  margin-block-end: var(--space-1);
  font-size: 0.8125rem;
  color: var(--ink-soft);
}

.seniority-row { margin-block-end: var(--space-2); }

/* ------------------------------------------------------------ service rows */

/* One row per requested service. The workbook had three fixed slots sharing a
   single fee cell; this grid grows instead, and each line carries its own
   pricing model and fee. */
.service-row {
  display: grid;
  grid-template-columns: 1fr 1.6fr 1fr 0.8fr auto;
  gap: 0 var(--space-3);
  padding: var(--space-3);
  margin-block-end: var(--space-3);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--bg);
}
.service-row .field { margin-block-end: var(--space-2); }
.service-row .span-all { grid-column: 1 / -1; margin-block-end: 0; }

/* The Remove button has to sit on the same baseline as the inputs beside it,
   which have a label above them. */
.service-row .row-remove { display: flex; align-items: flex-end; padding-block-end: 2px; }
.service-row .row-remove button { white-space: nowrap; }

.service-row [data-field="custom_service_name"] { margin-block-start: var(--space-2); }

/* Recruitment seniority and fee multiple. Two columns on their own line, set off
   from the rest of the row so it is obvious they belong to this one service and
   are not part of the standard pricing. They are display:none when hidden, so a
   non-recruitment row keeps its original five-column layout exactly. */
.service-row .recruitment {
  grid-column: span 2;
  margin-block-start: var(--space-2);
  padding-block-start: var(--space-3);
  border-block-start: 1px dashed var(--line);
}
.service-row .recruitment .hint { margin-block-start: var(--space-1); }

#add-service { margin-block-start: var(--space-2); }

/* ------------------------------------------------------------------ totals */

.totals {
  margin-block-start: var(--space-5);
  padding-block-start: var(--space-4);
  border-block-start: 1px solid var(--line);
  max-inline-size: 420px;
  margin-inline-start: auto;
}
.totals-row {
  display: flex;
  justify-content: space-between;
  gap: var(--space-4);
  font-size: var(--text-sm);
  padding-block: var(--space-1);
  color: var(--body);
}
.totals-row.grand {
  margin-block-start: var(--space-2);
  padding-block-start: var(--space-2);
  border-block-start: 1px solid var(--line);
  font-size: var(--text-lg);
  color: var(--navy);
  font-weight: var(--weight-bold);
}
.totals .hint { text-align: end; }

/* One line per requested service, above the subtotal. Indented and lighter than
   the totals themselves so the eye still lands on the figure that matters. */
.totals-row.item {
  align-items: baseline;
  padding-block: var(--space-1);
  color: var(--body);
}
.totals-row.item .item-name { display: block; }
.totals-row.item .item-line {
  display: block;
  font-size: var(--text-xs);
  color: var(--muted);
}
#total-lines {
  padding-block-end: var(--space-2);
  margin-block-end: var(--space-2);
  border-block-end: 1px solid var(--line-soft);
}
#total-lines:empty { display: none; }

/* -------------------------------------------------------------- action bar */

/* Sticks to the bottom of the viewport. What is still outstanding sits next to
   the button that is blocked by it, so the answer to "why can't I submit" is in
   the same place as the question. */
.actionbar {
  position: sticky;
  inset-block-end: 0;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
  margin-block-start: var(--space-4);
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  box-shadow: 0 -2px 10px rgba(0, 32, 96, 0.07);
}
.actionbar .outstanding {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
  min-inline-size: 0;
}
.actionbar .gaps { font-size: var(--text-xs); color: var(--muted); }
.actionbar-buttons {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  align-items: center;
  margin-inline-start: auto;
}
.savestate { font-size: var(--text-xs); color: var(--muted); white-space: nowrap; }

/* Workflow buttons are built from whatever moves the server says this user may
   make, so there can be one or four of them. */
.workflow { display: flex; flex-wrap: wrap; gap: var(--space-2); }

/* The note a request is sent back with. Pre-wrap, because the approver's line
   breaks are part of what they wrote. */
#change-request p { margin: var(--space-2) 0 0; white-space: pre-wrap; }
#change-request .hint { white-space: normal; }

/* ----------------------------------------------------------- send to client */

/* One uploaded file, or one past send. */
.filerow {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--space-3);
  padding: var(--space-2) var(--space-3);
  margin-block-end: var(--space-2);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--bg);
  font-size: var(--text-sm);
}
.filerow .hint { margin: 0; }
.filerow .err-text { flex-basis: 100%; }

/* The email preview. Renders the content, not the real email markup - the CSP
   is default-src 'none', so the actual HTML cannot be framed or injected, and
   loosening the policy to preview an email would be the wrong trade. */
.mailpreview {
  margin-block-start: var(--space-5);
  padding: var(--space-4);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--navy-soft);
}
.mailpreview-label {
  margin: 0 0 var(--space-2);
  font-size: var(--text-xs);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--muted);
}
.mailpreview-subject {
  margin: 0 0 var(--space-3);
  font-weight: var(--weight-bold);
  color: var(--navy);
  font-size: var(--text-lg);
}
/* pre-wrap: the author's own line breaks are part of what they wrote. */
.mailpreview-p {
  margin: 0 0 var(--space-3);
  white-space: pre-wrap;
  font-size: var(--text-sm);
  line-height: 1.65;
  color: var(--body);
}
.mailpreview-sig {
  margin: var(--space-4) 0 0;
  white-space: pre-wrap;
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  color: var(--navy);
}
.mailpreview-attach {
  margin: var(--space-4) 0 0;
  padding-block-start: var(--space-3);
  border-block-start: 1px solid #cdd9ec;
  font-size: var(--text-xs);
  color: var(--muted);
}

#send-blockers ul { margin: var(--space-2) 0 0; padding-inline-start: var(--space-5); }
#send-blockers li { margin-block-end: var(--space-1); }

.templaterow {
  padding: var(--space-3) 0;
  border-block-end: 1px solid var(--line-soft);
}
.templaterow:last-child { border-block-end: none; }
.templaterow h4 { margin: 0 0 var(--space-2); color: var(--navy); display: inline-block;
                  margin-inline-end: var(--space-3); }

input[type="file"] {
  inline-size: 100%;
  padding: var(--space-2) var(--space-3);
  border: 1px dashed #c3d3e6;
  border-radius: var(--radius);
  background: var(--bg);
  font-family: var(--font);
  font-size: var(--text-sm);
  color: var(--body);
}

/* ------------------------------------------------------------- responsive */

@media (max-width: 1100px) {
  .service-row { grid-template-columns: 1fr 1fr; }
  .service-row .row-remove { justify-content: flex-start; }
}

@media (max-width: 900px) {
  .form-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .form-grid .span4 { grid-column: span 2; }
  .service-row { grid-template-columns: 1fr; }
  .totals { max-inline-size: none; margin-inline-start: 0; }
  .toolbar-actions { margin-inline-start: 0; }
  .toolbar-actions input[type="text"] { inline-size: 100%; }
}

@media (max-width: 620px) {
  .form-grid { grid-template-columns: minmax(0, 1fr); }
  .form-grid .span2, .form-grid .span4 { grid-column: span 1; }
  .actionbar-buttons { margin-inline-start: 0; inline-size: 100%; }
  .actionbar-buttons button { flex: 1; }
}
