/* The shell's parts: masthead, nav, the impersonation banner, cards, forms,
 * flashes, the error page. Role tokens only -- see base.css's header.
 *
 * **No class here is named after a colour.** `.cta`, never `.coral-button`; a
 * class named after a pigment becomes a lie the moment the pigment changes, and
 * renaming classes across every template is exactly the "edit every line" this
 * architecture exists to avoid. A test asserts it.
 *
 * The brand's own patterns, followed rather than invented:
 *
 *   "White cards with soft shadows ... on the sand background"
 *   "A vertical coral accent stripe (0.08in wide) on the left edge marks the
 *    single most important card"
 *   "Eyebrows / section labels: bold, ALL CAPS, coral, ~3pt letter spacing"
 *   "sand background, corner mark, page numbers"  (content-slide chrome)
 *
 * The masthead is sand with the coral corner mark, which is the brand's content
 * pattern -- not a full-width navy bar. Navy is reserved for the one thing that
 * must be impossible to miss: the impersonation banner.
 */

/* --- skip link ------------------------------------------------------------ */

.skip-link {
  position: absolute;
  left: var(--space-4);
  top: calc(var(--space-4) * -4);
  z-index: 10;
  padding: var(--space-2) var(--space-4);
  background: var(--color-surface);
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow-raised);
  transition: top 120ms ease-out;
}
.skip-link:focus { top: var(--space-4); }

/* --- masthead and nav ----------------------------------------------------- */

.masthead {
  background: var(--color-canvas);
  border-bottom: 1px solid var(--color-border);
}

.masthead__inner {
  max-width: var(--layout-content-max);
  margin: 0 auto;
  min-height: var(--layout-masthead-height);
  padding: var(--space-3) var(--space-5);
  display: flex;
  align-items: center;
  gap: var(--space-5);
  flex-wrap: wrap;
}

/* The corner mark. `assets/noon_corner_mark.png` is the light-background variant,
   inserted as a file and never redrawn -- SKILL.md's heading for that section is
   literally "Logo -- insert only, never reproduce". */
.masthead__mark { display: block; height: var(--space-6); width: auto; }

.masthead__title {
  font-size: var(--font-size-h3);
  font-weight: var(--weight-medium);
  color: var(--color-heading);
  margin: 0;
}

.nav { margin-left: auto; }

.nav__list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  gap: var(--space-5);
  flex-wrap: wrap;
}
.nav__list li + li { margin-top: 0; }

.nav__link {
  display: inline-block;
  padding: var(--space-2) 0;
  color: var(--color-heading);
  font-weight: var(--weight-medium);
  text-decoration: none;
  border-bottom: 3px solid transparent;
}
.nav__link:hover { border-bottom-color: var(--color-border-strong); }

/* The one nav accent. Coral marks where you are, which is the scarce-and-important
   case the accent exists for. */
.nav__link[aria-current="page"] {
  border-bottom-color: var(--color-accent);
  font-weight: var(--weight-bold);
}

/* --- the impersonation banner (S8.5) ------------------------------------- */
/* Present on every authenticated page while impersonating, and there is no close
   control and no rule anywhere that can hide it. If it cannot render, the feature
   fails closed -- that is a server-side guard, not a CSS one, but nothing here may
   undermine it. Navy so it cannot be mistaken for page content; coral stripe so it
   cannot be mistaken for chrome. */

.banner {
  background: var(--color-panel);
  color: var(--color-panel-text);
  border-left: var(--accent-stripe) solid var(--color-accent);
}

.banner__inner {
  max-width: var(--layout-content-max);
  margin: 0 auto;
  padding: var(--space-3) var(--space-5);
  display: flex;
  align-items: baseline;
  gap: var(--space-4);
  flex-wrap: wrap;
}

.banner__label {
  font-size: var(--font-size-eyebrow);
  font-weight: var(--weight-bold);
  letter-spacing: var(--letter-spacing-eyebrow);
  text-transform: uppercase;
  color: var(--color-accent);
}

.banner__detail { font-size: var(--font-size-small); color: var(--color-panel-muted); }

/* --- eyebrow -------------------------------------------------------------- */

.eyebrow {
  font-size: var(--font-size-eyebrow);
  font-weight: var(--weight-bold);
  letter-spacing: var(--letter-spacing-eyebrow);
  text-transform: uppercase;
  color: var(--color-accent);
  margin: 0 0 var(--space-2);
}

/* --- cards ---------------------------------------------------------------- */

.card {
  background: var(--color-surface);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-card);
  padding: var(--space-5);
}

/* Marks the single most important card. Deliberately not offered per-card in a
   list: the stripe means "this one", and three of them mean nothing. */
.card--lead { border-left: var(--accent-stripe) solid var(--color-accent); }

.card__title {
  font-size: var(--font-size-h2);
  margin: 0 0 var(--space-3);
}

.card-grid {
  display: grid;
  gap: var(--space-5);
  grid-template-columns: repeat(auto-fit, minmax(18rem, 1fr));
}

/* --- callout -------------------------------------------------------------- */
/* documents.md: "italic, slate, indented both sides, thin coral left border". */

.callout {
  border-left: 2px solid var(--color-accent);
  padding-left: var(--space-4);
  color: var(--color-text-muted);
  font-style: italic;
}

/* --- forms ---------------------------------------------------------------- */

.field { margin-bottom: var(--space-4); }

.field__label {
  display: block;
  margin-bottom: var(--space-2);
  font-weight: var(--weight-medium);
  color: var(--color-heading);
}

.field__input {
  width: 100%;
  padding: var(--space-3);
  font-family: var(--font-sans);
  font-size: var(--font-size-body);
  color: var(--color-text);
  background: var(--color-surface);
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-sm);
}
.field__input:focus-visible { border-color: var(--color-accent); }

.field__hint {
  display: block;
  margin-top: var(--space-2);
  font-size: var(--font-size-small);
  color: var(--color-text-muted);
}

/* One primary action per form, and it is the only large coral fill in the
   product. SKILL.md permits a "CTA band"; that permission is spent here. */
.button {
  display: inline-block;
  padding: var(--space-3) var(--space-5);
  font-family: var(--font-sans);
  font-size: var(--font-size-body);
  font-weight: var(--weight-medium);
  color: var(--color-panel-text);
  background: var(--color-accent);
  border: 1px solid var(--color-accent);
  border-radius: var(--radius-sm);
  cursor: pointer;
  text-decoration: none;
}
.button:hover { background: var(--color-accent-strong); border-color: var(--color-accent-strong); }

.button--quiet {
  color: var(--color-heading);
  background: transparent;
  border-color: var(--color-border-strong);
}
.button--quiet:hover { background: var(--color-surface-sunken); color: var(--color-heading); }

/* --- flashes -------------------------------------------------------------- */
/* No red anywhere: the palette has none, and coral is the brand's only warm
   accent. An error is a coral rule and ink text, not coral text -- "never use
   coral for body text". */

.flash {
  padding: var(--space-3) var(--space-4);
  margin-bottom: var(--space-5);
  background: var(--color-surface);
  border-left: var(--accent-stripe) solid var(--color-border-strong);
  border-radius: var(--radius-sm);
}
.flash--alert { border-left-color: var(--color-accent); }

/* --- the auth pages ------------------------------------------------------- */
/* One centred card on sand. Same shell, no nav (there is nobody to navigate). */

.auth {
  max-width: 26rem;
  margin: var(--space-8) auto;
  padding: 0 var(--space-5);
}

.auth__mark {
  display: block;
  height: var(--space-7);
  width: auto;
  margin: 0 auto var(--space-5);
}

/* --- footer --------------------------------------------------------------- */

.footer {
  border-top: 1px solid var(--color-border);
  margin-top: var(--space-8);
  flex: 0 0 auto;
}

.footer__inner {
  max-width: var(--layout-content-max);
  margin: 0 auto;
  padding: var(--space-4) var(--space-5);
  font-size: var(--font-size-small);
  color: var(--color-text-muted);
  display: flex;
  gap: var(--space-4);
  justify-content: space-between;
  flex-wrap: wrap;
}

/* --- the error page ------------------------------------------------------- */
/* Shows the correlation ID and nothing else (§12.1). It is read aloud down a
   phone, so it has to survive being spoken -- and the obvious answer, a monospace
   face, is refused: "All text uses DM Sans ... hierarchy comes from weight and
   size, never from mixing typefaces." So the legibility comes from letter spacing
   and tabular figures instead, which costs nothing and keeps one typeface. */

.error { text-align: center; padding: var(--space-8) var(--space-5); }

.error__reference {
  display: inline-block;
  margin-top: var(--space-5);
  padding: var(--space-2) var(--space-4);
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-sm);
  font-size: var(--font-size-small);
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.08em;
  color: var(--color-text-muted);
}

/* --- motion --------------------------------------------------------------- */
/* Two animated things in the whole stylesheet, and both respect the setting.
 *
 * The working state's ellipsis stops moving and shows three steady dots. The
 * seconds counter is NOT suppressed: it is information rather than decoration, it
 * is the one honest element in the affordance, and a reader who has asked for less
 * motion has not asked to be told less. */

@media (prefers-reduced-motion: reduce) {
  .skip-link { transition: none; }
  .working__dots span { animation: none; opacity: 1; }
}

/* --- the admin console's second-level nav (dev_6) ------------------------- */
/* Distinct from the shell's nav, which is the investor's and is built from live
 * entitlements. This one is the operator's and is a fixed list of pages. */

.subnav {
  border-bottom: 1px solid var(--color-border);
  margin-bottom: var(--space-5);
}

.subnav__list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  gap: var(--space-5);
  flex-wrap: wrap;
}
.subnav__list li + li { margin-top: 0; }

.subnav__link {
  display: inline-block;
  padding: var(--space-2) 0;
  color: var(--color-text-muted);
  text-decoration: none;
  border-bottom: 3px solid transparent;
}
.subnav__link:hover { color: var(--color-heading); }
.subnav__link[aria-current="page"] {
  color: var(--color-heading);
  font-weight: var(--weight-bold);
  border-bottom-color: var(--color-accent);
}

/* --- wide tables --------------------------------------------------------- */
/* The access matrix is as wide as the number of documents, so it scrolls inside
 * its own box. The page body must never scroll sideways -- on a laptop that turns
 * "tick the third column" into a hunt. */

/* The users filter bar. Wraps rather than scrolls: an operator on a laptop should
   see every control at once, because a filter they cannot see is a filter still
   applied that they think is not. Role tokens only (ADR-034) -- no literals. */
.filters {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: var(--space-3);
  margin-bottom: var(--space-3);
}

.filters .field { margin: 0; flex: 1 1 12rem; }
.filters p { margin: 0; display: flex; align-items: center; gap: var(--space-3); }

.filters__summary {
  margin: 0 0 var(--space-4);
  color: var(--color-text-muted);
  font-size: var(--font-size-small);
}

.filters__summary small {
  display: block;
  color: var(--color-text-muted);
}

.table-scroll {
  overflow-x: auto;
  margin-bottom: var(--space-5);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  background: var(--color-surface);
}

.table-scroll table { border-collapse: collapse; }
.table-scroll th[scope="row"] {
  text-align: left;
  font-weight: var(--weight-medium);
  color: var(--color-heading);
  white-space: nowrap;
}

/* --- checkboxes and selects ---------------------------------------------- */
/* `accent-color` is the one-line way to brand a native control, and a native
 * checkbox is the right control here: it is keyboard-operable, it announces its
 * state to a screen reader, and it needs no JavaScript -- which matters on the
 * page that decides what every investor can see. */

input[type="checkbox"] {
  width: 1.15rem;
  height: 1.15rem;
  accent-color: var(--color-accent);
  cursor: pointer;
}

select.field__input {
  /* Inherits the text field's look; the browser draws the arrow. */
  appearance: auto;
}

/* A form inside a table cell should not add vertical space to the row. */
td > form { display: inline; margin: 0; }
td > form + form { margin-left: var(--space-2); }

/* --- the impersonation banner's exit (dev_7) ----------------------------- */
/* The banner is navy and its one control has to read as a control on that
 * ground. Coral is already the accent there, so the button keeps its default
 * fill and only needs to stop stretching. */

.banner__exit { margin: 0 0 0 auto; }

/* --- the tool frame (dev_9) ----------------------------------------------- */
/* The Comparison Tool is a whole application inside a page, so it gets the full
 * width of the content column and a tall viewport. `min-height` rather than a
 * fixed height: its own layout is responsive and a fixed frame would give it a
 * second scrollbar inside the page's. */

.tool-frame {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-card);
  overflow: hidden;
  /* The working state is laid over the frame rather than beside it (dev_20), so
     the states occupy the same rectangle an investor is already looking at. */
  position: relative;
}

/* When the tool is CONFIRMED not to be answering, the frame itself goes. Leaving a
   blank iframe under the message would put the thing being described back on
   screen next to the description of it -- and would leave a focusable, empty
   document in the tab order for anyone using a keyboard or a screen reader.

   It does not go for the ceiling's provisional stall, and that is the point of
   the distinction: the ceiling is guessing, a slow link can reach it on a tool
   that is one second from painting, and taking the frame away from that reader
   would be worse than the blank frame dev_20 exists to replace. The guess keeps
   the frame and gets taken back if the tool arrives. */
.tool-frame.is-stalled .tool-frame__frame { display: none; }

.tool-frame__frame {
  display: block;
  width: 100%;
  /* The tool scrolls internally -- a Streamlit app is built to, and its header
     sticks -- so this is how much of it a reader sees at once rather than how tall
     it is. Enough that the first decision and its chart are both visible without
     scrolling the frame. */
  min-height: 85vh;
  border: 0;
}

/* --- the working state, and "not answering" (dev_20, ADR-044) ------------- */
/* One affordance, two outcomes. The tool slot is the first consumer; document
 * delivery and admin actions are the next, which is why nothing below is named
 * after the tool.
 *
 * **The degradation rule is the first two selectors and it is worth reading
 * slowly.** `[data-working]` is hidden by default and revealed only under
 * `html.js`, which `working.js` sets as the LAST thing it does on a successful
 * init. So JavaScript off, a 404 on the file, or a throw anywhere during setup
 * all land in the same place: the page as it was before dev_20, plus the static
 * sentence below, which is true in every state. The alternative ordering --
 * visible by default, hidden by script -- fails the other way, and an overlay
 * stuck over a tool that is working perfectly well is the worse failure.
 */

[data-working] { display: none; }
.js [data-working] { display: block; }

.working {
  padding: var(--space-6) var(--space-5);
  color: var(--color-text-muted);
  font-size: var(--font-size-body);
  text-align: center;
}

.working--overlay {
  position: absolute;
  inset: 0;
  /* Opaque: the frame underneath is mid-load and whatever it is doing is not a
     thing to show a reader half-finished. */
  background: var(--color-surface);
  z-index: 1;
}
.js .working--overlay {
  display: flex;
  align-items: center;
  justify-content: center;
}

/* **A CONFIRMED "not answering" stops being an overlay.** By then the frame it was
   laid over is hidden, so an absolutely-positioned box has nothing left to be the
   height of and collapses to zero -- which would make the one state this work
   exists for the one state nobody can see. Back into normal flow, where it gives
   the card its height like any other panel.

   Keyed on `is-stalled`, which the script puts on the host for a CONFIRMED stall
   only. The ceiling's provisional one deliberately withholds it: that stall is a
   guess, the frame stays rendered underneath, and if the tool paints a second
   later the overlay is simply hidden and the tool is there. Generic on purpose --
   `is-stalled`, not `.tool-frame` -- because the next consumers are not frames. */
.is-stalled .working--overlay {
  position: static;
  min-height: var(--layout-masthead-height);
}

/* Last, so it wins over the two reveal rules above without `!important`. The
   script hides the whole element on success by setting `hidden`. */
[data-working][hidden],
.js [data-working][hidden] { display: none; }

.working__busy {
  margin: 0;
  display: inline-flex;
  align-items: baseline;
  gap: var(--space-2);
}
.working__busy[hidden] { display: none; }

/* The counter. Tabular figures so the line does not twitch sideways as the number
   changes once a second -- the same reasoning as the error page's reference. */
.working__elapsed {
  font-variant-numeric: tabular-nums;
  font-size: var(--font-size-small);
}

/* Three dots, generated here rather than written into the markup: they are
   decoration, they are `aria-hidden`, and a reader never needs them translated. */
.working__dots { display: inline-block; letter-spacing: 0.08em; }
.working__dots span::before { content: "."; }
.working__dots span { animation: working-dot 1.2s infinite; opacity: 0.25; }
.working__dots span:nth-child(2) { animation-delay: 0.2s; }
.working__dots span:nth-child(3) { animation-delay: 0.4s; }

@keyframes working-dot {
  0%, 60%, 100% { opacity: 0.25; }
  30% { opacity: 1; }
}

.working__stalled { max-width: var(--layout-measure); margin: 0 auto; text-align: left; }
.working__stalled[hidden] { display: none; }
.working__stalled p { margin: 0 0 var(--space-2); }
.working__stalled p:last-child { margin-bottom: 0; color: var(--color-text); }

/* The no-script sentence. Visible on every load, hidden the moment the live state
   takes over -- so it never contradicts the thing above it. */
.tool-frame__note {
  margin-top: var(--space-4);
  max-width: var(--layout-measure);
  font-size: var(--font-size-small);
  color: var(--color-text-muted);
}
.js .tool-frame__note { display: none; }

/* The signed-in block (h485). Two lines, the address above Sign out, right-aligned in the
   masthead corner. The standard pins the ORDER and the words; the placement is ours
   because the portal has no sidebar to put it at the bottom of. */
.masthead__account {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 0.25rem;
  line-height: 1.3;
}
.masthead__account-email {
  font-size: var(--font-size-small);
  color: var(--color-text-muted);
  /* An address is long and must not push the nav around; it wraps rather than truncating,
     because a truncated address cannot answer the question the line exists to answer. */
  overflow-wrap: anywhere;
}
