/* =============================================================================
   UORA console stylesheet
   web/assets/css/app.css — load third, and only on a signed-in page:

     <link rel="stylesheet" href="/assets/css/tokens.css">
     <link rel="stylesheet" href="/assets/css/base.css">
     <link rel="stylesheet" href="/assets/css/app.css">

   What is here, and only what is here: the handful of blocks the four consoles
   share which base.css does not already provide. base.css already gives us
   .card, .table, .chip, .kv, .notice, .timeline, .countdown, .countdown-card,
   .filelist, .modal, .tabs, .empty, .skeleton, .form and the header/nav
   furniture the shell reuses. Nothing below re-states any of that; each block is
   an addition to it, and where base.css nearly covers a case the rule here is
   the difference and no more.

   Blocks:
     1. Console chrome      the pieces app-shell.js builds: console label,
                            account menu, and the panels it renders on refusal
                            or failure
     2. Case header         the identity block at the top of a case page
     3. Action cards        what the case payload says this party may do now
     4. Timeline additions  actor and channel lines on base.css's .timeline
     5. Service log         the wide, per-attempt table
     6. Wizard stepper      the claim wizard's progress rail
     7. Document list       issued artefacts, in bundle order

   Rules that are not negotiable, and are checked in review:
     - Every colour is a var(--token) from tokens.css. There is no hex literal in
       this file and there is not going to be one.
     - Every spacing value is a --s-* step. The scale exists so density can be
       tuned in one place.
     - Nothing communicates state by colour alone. A done step carries a mark, a
       failed attempt carries a word, a served document says "Served".
     - Wide content scrolls inside its own container. The page never scrolls
       horizontally, down to 360px.
   ============================================================================= */

/* ==================================================== 1. console chrome ==== */

/* The header is base.css's .site-header; the shell adds .app-header so the two
   consoles that need a different measure can ask for one. The administration
   case board runs at --shell-wide, and its chrome has to reach the same edge or
   the navigation floats in from nowhere. */
.app-header[data-console="admin"] .site-header__inner {
  max-width: var(--shell-wide);
}

/* The collapsed-navigation button must not appear above the breakpoint, where
   the navigation itself is already the control: a second control for the same
   thing is a second stop in the tab order that does nothing.

   base.css says `.site-header__toggle { display: none }` at line 478 and then
   `.btn { display: inline-flex }` at line 666. Same specificity, and the later
   rule wins, so the button is shown at every width — on the public site too,
   which uses the same markup. This raises the specificity for the consoles until
   base.css is corrected at source; when it is, these two rules become redundant
   and should be deleted rather than kept. */
.app-header .site-header__toggle {
  display: none;
}

@media (max-width: 720px) {
  .app-header .site-header__toggle {
    display: inline-flex;
  }
}

/* The lockup, trimmed to its ink.
   uora-logo-horizontal-dark.svg has a 920x210 viewBox whose artwork ends at
   x=578.9 — a third of the file is empty space, and left as it is the divider
   after the mark sits some 40px further right than it looks like it should. The
   box below is that measurement carried over: at the 26px height base.css gives
   header brand images, the artwork's right edge falls at 71.7px, so 76px clears
   it with a little air and clips nothing. If the asset is ever redrawn, this
   width is remeasured with getBBox() rather than guessed. */
.app-header__logo {
  display: inline-flex;
  align-items: center;
  overflow: hidden;
  flex: 0 0 auto;
  width: 76px;
}

.app-header__logo img {
  flex: 0 0 auto;
  max-width: none;
}

.app-header__logo:focus-visible {
  outline: var(--focus-outline-width) solid var(--accent);
  outline-offset: var(--focus-outline-offset);
  border-radius: var(--r-xs);
}

/* Which console this is. A quiet label, not a second wordmark: the reader has
   already been told what the product is by the lockup beside it. */
.app-header__console {
  padding-inline-start: var(--s-3);
  border-inline-start: var(--hairline) solid var(--border2);
  font-size: var(--fs-caption);
  font-weight: var(--fw-ui);
  letter-spacing: var(--tr-micro);
  text-transform: uppercase;
  color: var(--text2);
  white-space: nowrap;
}

/* ---- account menu ---- */

.app-account {
  position: relative;
}

/* Ghost, because the account control must never be the loudest thing on a case
   page — the party's next action is. The hairline is the one addition: without
   it a ghost button carrying an address reads as a label rather than a menu. */
.app-account__toggle {
  border-color: var(--border2);
}

.app-account__toggle[aria-expanded="true"] {
  background: var(--bg-3);
  color: var(--text);
}

.app-account__who {
  display: block;
  max-width: 200px;
}

.app-account__menu {
  position: absolute;
  inset-block-start: calc(100% + var(--s-2));
  inset-inline-end: 0;
  z-index: var(--z-dropdown);
  min-width: 240px;
  max-width: min(320px, calc(100vw - var(--s-6)));
  padding: var(--s-4);
  background: var(--bg-2);
  border: var(--hairline) solid var(--border2);
  border-radius: var(--r);
  box-shadow: var(--shadow-lg);
}

.app-account__menu > * + * {
  margin-block-start: var(--s-2);
}

/* The signed-in address in full. The button beside it truncates on a narrow
   viewport, so this is the copy that is always legible. */
.app-account__email {
  font-size: var(--fs-body-sm);
  font-weight: var(--fw-label);
  color: var(--text);
  overflow-wrap: anywhere;
}

.app-account__menu .divider {
  margin-block: var(--s-3);
}

@media (max-width: 720px) {
  .app-header__console {
    display: none;
  }

  .app-account__who {
    max-width: 108px;
  }
}

/* ---- refusal and failure panels ---- */

/* Rendered by app-shell.js in place of the page when the session cannot be
   verified or the role is absent. It replaces the page's own <h1>, and supplies
   one, so the document still has exactly one. */
.app-panel {
  margin-block-start: var(--s-7);
  padding: var(--s-7);
}

.app-panel > * + * {
  margin-block-start: var(--s-4);
}

.app-panel__title {
  font-family: var(--font-display);
  font-size: var(--fs-h1);
  font-weight: var(--fw-title);
  letter-spacing: var(--tr-title);
  line-height: var(--lh-heading);
}

/* ======================================================= 2. case header ==== */

/* The identity block at the top of every case page: which case this is, between
   whom, what state it is in, and what falls due next. The deadline sits in its
   own rail rather than in the run of facts, because it is the one fact on the
   page that expires. */
.case-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--s-6);
  flex-wrap: wrap;
  padding-block-end: var(--s-5);
  margin-block-end: var(--s-6);
  border-block-end: var(--hairline) solid var(--border);
}

.case-head__main {
  flex: 1 1 320px;
  min-width: 0;
}

/* The case number. Tabular with zero tracking so a column of them aligns, and
   selectable as one unit because it is quoted in correspondence and in court. */
.case-head__no {
  display: block;
  font-family: var(--font-mono);
  font-size: var(--fs-small);
  font-variant-numeric: tabular-nums;
  letter-spacing: var(--tr-num);
  color: var(--accent);
}

.case-head__title {
  margin-block-start: var(--s-1);
  font-family: var(--font-display);
  font-size: var(--fs-h1);
  font-weight: var(--fw-title);
  letter-spacing: var(--tr-title);
  line-height: var(--lh-heading);
}

/* Chips, parties and the rules version, on one wrapping line. */
.case-head__meta {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  flex-wrap: wrap;
  margin-block-start: var(--s-3);
  font-size: var(--fs-small);
  color: var(--text2);
}

.case-head__parties {
  margin-block-start: var(--s-3);
  font-size: var(--fs-body-sm);
  color: var(--text);
}

.case-head__versus {
  padding-inline: var(--s-2);
  color: var(--text3);
}

/* Holds a .countdown-card from base.css, and nothing else. */
.case-head__rail {
  flex: 0 1 260px;
  min-width: 220px;
}

/* base.css sets .countdown as a baseline row, which is right in a table cell or
   a sentence. In a rail the two halves have to stack, or "2 days, 4 hours" wraps
   mid-phrase. The absolute time stays directly beneath the relative one: a
   document may cite the absolute, and the two must be read together. */
.case-head__rail .countdown {
  flex-direction: column;
  align-items: flex-start;
  gap: var(--s-1);
}

@media (max-width: 560px) {
  .case-head__rail {
    flex: 1 1 100%;
  }
}

/* ======================================================= 3. action cards === */

/* What this party may do now. The set comes from `available_actions` in the case
   payload — the FSM decides it, never the browser — so this grid may hold one
   card, several, or none at all. */
.actions {
  display: grid;
  gap: var(--s-4);
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
}

/* Used with .card, and with .card--action on the one the party is expected to
   take next. Column layout so every foot lines up whatever the prose above it. */
.action-card {
  display: flex;
  flex-direction: column;
  gap: var(--s-3);
}

.action-card__body {
  font-size: var(--fs-body-sm);
  color: var(--text2);
  line-height: var(--lh-body);
}

/* What follows from doing it, or from not doing it. Stated plainly and set apart
   from the description, because it is the part a party will later say they were
   not told. The rule carries the emphasis; the word "irreversible" or the
   deadline carries the meaning. */
.action-card__consequence {
  padding-inline-start: var(--s-3);
  border-inline-start: 2px solid var(--accent-line);
  font-size: var(--fs-small);
  color: var(--text2);
  line-height: var(--lh-body);
}

.action-card__foot {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  flex-wrap: wrap;
  margin-block-start: auto;
  padding-block-start: var(--s-3);
}

/* A refusal the API returned for this action: 409 guard_failed carries the
   reason the Rules require, and it belongs beside the control it refused. */
.action-card__refusal {
  font-size: var(--fs-small);
  color: var(--warn);
}

/* =================================================== 4. timeline additions = */

/* base.css provides .timeline, .timeline__item and its three states,
   .timeline__when, .timeline__title, .timeline__body and .timeline__attachments.
   Two things the journal shows that it has no line for: */

/* Who did it and on which channel. Kept off .timeline__body so the entry's own
   words and the record of who entered them do not run together. */
.timeline__meta {
  display: flex;
  align-items: center;
  gap: var(--s-2);
  flex-wrap: wrap;
  margin-block-start: var(--s-2);
  font-size: var(--fs-caption);
  color: var(--text3);
}

.timeline__meta > * + *::before {
  content: '·';
  margin-inline-end: var(--s-2);
  color: var(--border3);
}

/* The journal is hash-chained. Where an entry's digest is shown it is shown as
   what it is: a long hexadecimal string that must not reflow. */
.timeline__digest {
  font-family: var(--font-mono);
  font-size: var(--fs-caption);
  letter-spacing: var(--tr-num);
  color: var(--text3-quiet);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 22ch;
}

/* ======================================================== 5. service log === */

/* Every attempt on every document: party, channel, destination, outcome. Service
   is effected on transmission, not on delivery, so all four stamps are shown and
   none of them is dropped for width — the table keeps its measure and the
   .table-wrap around it scrolls. */
.service-log {
  min-width: 760px;
}

.service-log td {
  vertical-align: top;
}

/* The contractual contact details the claimant supplied and declared. They
   appear in the Service Log document that goes into the court bundle, so they
   are shown here in full rather than masked, and set to break rather than to be
   cut off. */
.service-log__destination {
  font-family: var(--font-mono);
  font-size: var(--fs-caption);
  letter-spacing: var(--tr-num);
  overflow-wrap: anywhere;
}

/* Sent, delivered, read, failed — stacked in one cell, each labelled, so an
   attempt that was transmitted but never delivered reads as exactly that. */
.service-log__stamps {
  display: flex;
  flex-direction: column;
  gap: var(--s-1);
  font-size: var(--fs-caption);
  font-variant-numeric: tabular-nums;
  letter-spacing: var(--tr-num);
  color: var(--text2);
}

.service-log__stamp-label {
  display: inline-block;
  min-width: 68px;
  color: var(--text3);
}

.service-log__error {
  font-size: var(--fs-caption);
  color: var(--danger);
}

/* A copy served on a second channel is not a second service. Marked, quietly. */
.service-log__copy {
  font-size: var(--fs-caption);
  color: var(--text3);
}

/* ===================================================== 6. wizard stepper === */

/* The claim wizard's progress rail. It reports where the claimant is; it does
   not decide what they may reach — the API validates each step and the wizard
   renders what it is told. */
.stepper {
  display: flex;
  align-items: flex-start;
  gap: var(--s-2);
  margin-block-end: var(--s-6);
  padding: 0;
  list-style: none;
}

.stepper__step {
  display: flex;
  align-items: center;
  gap: var(--s-2);
  flex: 1 1 0;
  min-width: 0;
  font-size: var(--fs-small);
  color: var(--text3);
}

/* The connector. Drawn on the step rather than between steps so the last one
   does not trail a line into nothing. */
.stepper__step:not(:last-child)::after {
  content: '';
  flex: 1 1 auto;
  height: var(--hairline);
  min-width: var(--s-3);
  background: var(--border2);
}

.stepper__n {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  width: 24px;
  height: 24px;
  border-radius: var(--r-pill);
  border: var(--hairline) solid var(--border2);
  background: var(--bg-2);
  font-size: var(--fs-caption);
  font-variant-numeric: tabular-nums;
  letter-spacing: var(--tr-num);
  color: var(--text2);
}

.stepper__label {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* A completed step. The tick inside .stepper__n is markup, not a background
   image: colour is never the only thing that says a step is done. */
.stepper__step--done .stepper__n {
  background: var(--ok-soft);
  border-color: var(--ok-line);
  color: var(--ok);
}

.stepper__step--done {
  color: var(--text2);
}

.stepper__step--done:not(:last-child)::after {
  background: var(--ok-line);
}

/* The step being filled in. aria-current="step" is the carrier; these rules only
   make it visible. */
.stepper__step[aria-current="step"] {
  color: var(--text);
  font-weight: var(--fw-ui);
}

.stepper__step[aria-current="step"] .stepper__n {
  background: var(--accent-soft);
  border-color: var(--accent-line);
  color: var(--accent);
}

/* Under 560px a horizontal rail either scrolls or lies. It becomes a column. */
@media (max-width: 560px) {
  .stepper {
    flex-direction: column;
    align-items: stretch;
    gap: var(--s-3);
  }

  .stepper__step {
    flex: 0 0 auto;
  }

  .stepper__step:not(:last-child)::after {
    display: none;
  }
}

/* ===================================================== 7. document list ==== */

/* Issued artefacts, in the bundle order of Rules 12.4 — the order the API
   returns them in, which is the order they are filed in. Distinct from
   base.css's .filelist, which is evidence a party is staging for upload: these
   are documents the platform has issued and, in most cases, served. */
.doclist {
  display: flex;
  flex-direction: column;
  gap: var(--s-2);
  padding: 0;
  list-style: none;
}

.doclist__item {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--s-2) var(--s-4);
  padding: var(--s-3) var(--s-4);
  background: var(--bg-2);
  border: var(--hairline) solid var(--border);
  border-radius: var(--r);
  transition: border-color var(--t) var(--ease);
}

.doclist__item:hover {
  border-color: var(--border2);
}

/* The document number — D-04, COS-02. Fixed measure so the titles beside them
   start on one line. */
.doclist__no {
  font-family: var(--font-mono);
  font-size: var(--fs-caption);
  font-variant-numeric: tabular-nums;
  letter-spacing: var(--tr-num);
  color: var(--text3);
  min-width: 6ch;
}

.doclist__main {
  min-width: 0;
}

.doclist__title {
  font-size: var(--fs-body-sm);
  font-weight: var(--fw-label);
  color: var(--text);
}

.doclist__meta {
  display: flex;
  align-items: center;
  gap: var(--s-2);
  flex-wrap: wrap;
  margin-block-start: var(--s-1);
  font-size: var(--fs-caption);
  font-variant-numeric: tabular-nums;
  letter-spacing: var(--tr-num);
  color: var(--text3);
}

/* The SHA-256 printed in the document's own footer and recited on the
   verification page. Truncated on screen, never altered: the title attribute and
   the verification page carry the whole of it. */
.doclist__hash {
  font-family: var(--font-mono);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 20ch;
}

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

@media (max-width: 560px) {
  /* The row becomes two lines: number and title, then the actions beneath. The
     number top-aligns with the title it labels rather than floating against the
     middle of a wrapped block. */
  .doclist__item {
    grid-template-columns: auto minmax(0, 1fr);
    align-items: start;
  }

  .doclist__actions {
    grid-column: 1 / -1;
  }
}
