/* ==========================================================================
   Poruch OAuth — the design system, as much of it as this app uses.

   Copied from `core/main/app/assets/stylesheets/design_system.css`, not shared
   through a gem. The two apps are separate repositories, so a path gem does
   not reach across; a git-sourced gem would make every CSS change two pull
   requests and a ref bump, for one file. If a shared gem is ever wanted, the
   token block below is what it should hold — everything else here is either
   universal enough to re-derive or specific enough to have been adapted.

   WHAT IS COPIED, AND WHAT IS NOT

   Section 1 is the whole `:root` block, byte-identical. That is deliberate and
   it is the one part of this file nobody may edit locally: it is the contract
   with the drawn screens, and a drift in one token is a drift on every page of
   both apps. It therefore names tokens no rule here uses — `--chrome-*`,
   `--side-width`, `--panel-head-h`. Deleting them would make the block
   diffable-but-unequal against core's, which is worse than carrying eight
   unused custom properties.

   Sections 2 through 5 — base, buttons, forms, notices — are copied verbatim
   too, header numbering aside, and each is copied WHOLE. Twenty-odd of their
   rules have nothing on these nine screens to style: `.btn-sm`, `.empty`,
   `.form-inline`, `.witness`. They stay for the same reason the unused tokens
   do — a section that has been pruned can no longer be diffed against core's,
   and the day somebody needs `.form-hint` here is not the day to go and fetch
   it. Prune nothing; copy a whole section or none of it.

   Section 6, the gate, is ADAPTED; see its own comment.

   Nothing else is copied. Core's file is 2036 lines and this app has nine
   screens, not one of which is a table, a board, a builder, a queue, an audit
   trail or a two-column surface. Importing the toolbar, band, surface, table,
   board, audit, builder, queue, rail, page-tabs and pager sections would mean
   the next person cannot tell which rules here are load bearing. They are not
   here because they have nothing to style.

   THE STATIC ERROR PAGES

   `public/*.html` cannot reach this file: they are served by the file server
   when the app has already failed, and a 500 page that depends on the app
   booting is not a 500 page. They therefore inline the handful of tokens each
   one needs, in the gate's shape, and say so in their own comments. That is a
   second copy of part of section 1, and `spec/design_system_spec.rb` fails if
   the two stop agreeing. The alternative, a `config.exceptions_app`, routes the
   error through the router and the application that just raised. Static files
   it is, for all six of them.
   ========================================================================== */


/* --------------------------------------------------------------------------
   1. Tokens
   -------------------------------------------------------------------------- */

:root {
  /* Surfaces. --bg is the page, --surface is anything raised off it. */
  --bg: #f4f4fb;
  --bg-sunken: #ececf5;
  --surface: #ffffff;
  --surface-head: #dcdcf0;

  /* Ink */
  --fg: #455060;
  --fg-strong: #303742;
  --fg-muted: #7c8797;
  --fg-faint: #a8b0bd;

  /* Lines */
  --line: #bcc3ce;
  --line-soft: #d4d8e0;
  --line-strong: #9fa9b9;

  /* Primary — Spectre's indigo, unchanged. It is the only accent. */
  --primary: #4f4fbb;
  --primary-hover: #4343ad;
  --primary-line: #4646b5;
  --primary-wash: #eeeefa;

  /* The toolbar. Near-black navy: the chrome must not compete with the work. */
  --chrome: #001a33;
  --chrome-hover: #002b54;
  --chrome-active: #00355e;
  --chrome-fg: #c1c1c1;
  --chrome-fg-strong: #f0f0f0;

  /* Signals */
  --ok: #2f9e41;
  --ok-wash: #e6f5e9;
  --warn: #b07800;
  --warn-wash: #fdf3dd;
  --bad: #c2410c;
  --bad-wash: #fbeae1;

  /* Keys and code — monospace on a warm wash, so an identifier never reads
     as prose. */
  --code-fg: #d73e48;
  --code-bg: #fcf2f2;

  --highlight: #ffe9b3;

  /* Type. 0.8rem of a 16px root = 12.8px. Dense on purpose: these screens are
     read as tables of facts, not as articles. */
  --font: -apple-system, system-ui, BlinkMacSystemFont, "Segoe UI", Roboto,
    "Helvetica Neue", sans-serif;
  --mono: "SF Mono", "Segoe UI Mono", "Roboto Mono", Menlo, Courier, monospace;
  --fs: 0.8rem;
  --fs-sm: 0.7rem;
  --fs-lg: 0.9rem;
  --fs-h1: 0.9rem;
  --fs-h2: 1.15rem;
  --fs-h3: 0.95rem;
  --lh: 1.2rem;

  /* Space. One .26rem step, doubled and tripled — Spectre's unit scale. */
  --u1: 0.26rem;
  --u2: 0.52rem;
  --u3: 0.78rem;
  --u4: 1.04rem;
  --u5: 1.3rem;
  --u6: 1.56rem;
  --u8: 2.08rem;
  --u10: 2.6rem;

  --radius: 0.3em;
  --hair: 0.05rem;

  --shadow: 0 0.1rem 0.3rem rgba(48, 55, 66, 0.14);
  --shadow-head: 0 0.1rem 0.2rem rgba(48, 55, 66, 0.16);

  /* The panel head sticks to the top of the right-hand column, and the day
     separator of a timeline stands just under it. One number, used twice. */
  --panel-head-h: 2.3rem;

  --side-width: 22rem;
  /* Written twice on purpose: a custom property cannot appear in a media
     condition, so section 6's `@media (max-width: 1120px)` carries the
     literal. The token is not dead — it is the name of the number. */
  --side-collapse: 1120px;

  /* The page head is sticky and two things stick underneath it, so its height
     is a declared number rather than three guesses that drift apart. The head
     is given it as a `height` — a min-height would be a floor and not a
     promise, and the two things stick at the number whatever the head does.

     4rem is 64px, and the tallest head this file can produce is 62.34px: the
     0.52rem padding pair, a 20.2px crumb line (19.2, plus 1px when the last
     crumb is a `code` chip), the 0.1rem lead gap and a 23.92px title. The
     remaining 1.66px is the slack, and it is the reason the crumb row and the
     title are both held to one line below. */
  --head-h: 4rem;
}

/* --------------------------------------------------------------------------
   2. Base
   -------------------------------------------------------------------------- */

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

html {
  font-size: 16px;
  line-height: 1.5;
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--fg);
  font-family: var(--font);
  font-size: var(--fs);
  line-height: var(--lh);
  text-rendering: optimizeLegibility;
}

a {
  color: var(--primary);
  text-decoration: none;
}

a:hover {
  text-decoration: underline;
}

h1,
h2,
h3,
h4 {
  margin: 0;
  color: var(--fg-strong);
  font-weight: 600;
  line-height: 1.3;
}

h2 {
  font-size: var(--fs-h2);
}

h3 {
  font-size: var(--fs-h3);
}

p {
  margin: 0 0 var(--u2);
}

p:last-child {
  margin-bottom: 0;
}

ul,
ol {
  margin: 0;
  padding: 0;
  list-style: none;
}

hr {
  border: 0;
  border-top: var(--hair) solid var(--line-soft);
  margin: var(--u4) 0;
}

code,
.key {
  padding: 0.1rem var(--u1);
  border-radius: var(--radius);
  background: var(--code-bg);
  color: var(--code-fg);
  font-family: var(--mono);
  font-size: 85%;
  white-space: nowrap;
}

time {
  font-variant-numeric: tabular-nums;
}

.num {
  font-family: var(--mono);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

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

.faint {
  color: var(--fg-faint);
}

.small {
  font-size: var(--fs-sm);
}

.strong {
  color: var(--fg-strong);
  font-weight: 600;
}

.right {
  text-align: right;
}

.nowrap {
  white-space: nowrap;
}

mark {
  background: var(--highlight);
  color: inherit;
}

/* A value as it moved. Used in the audit column and in any builder row that
   has to say what a draft changes — one vocabulary, so a reader learns it
   once. */
ins,
del {
  padding: 0 var(--u1);
  border-radius: var(--radius);
}

ins {
  background: var(--ok-wash);
  color: #1d6b2b;
  text-decoration: none;
}

del {
  background: var(--bad-wash);
  color: #92320a;
}

del + ins,
ins + del {
  margin-left: var(--u1);
}

/* --------------------------------------------------------------------------
   3. Buttons
   -------------------------------------------------------------------------- */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--u1);
  padding: var(--u2) var(--u3);
  border: var(--hair) solid var(--line-strong);
  border-radius: var(--radius);
  background: var(--bg);
  color: var(--primary);
  cursor: pointer;
  font-family: inherit;
  font-size: var(--fs);
  line-height: var(--lh);
  text-align: center;
  transition: background 0.15s, border-color 0.15s, color 0.15s;
  white-space: nowrap;
}

.btn:hover {
  border-color: var(--primary);
  background: var(--primary-wash);
  text-decoration: none;
}

.btn-primary {
  border-color: var(--primary-line);
  background: var(--primary);
  color: #fff;
}

.btn-primary:hover {
  border-color: var(--primary-hover);
  background: var(--primary-hover);
  color: #fff;
}

.btn-danger {
  border-color: var(--bad);
  color: var(--bad);
}

.btn-danger:hover {
  background: var(--bad-wash);
  border-color: var(--bad);
}

.btn-link {
  border-color: transparent;
  background: transparent;
}

.btn-link:hover {
  border-color: transparent;
  background: rgba(79, 79, 187, 0.08);
}

.btn-sm {
  padding: var(--u1) var(--u2);
  font-size: var(--fs-sm);
}

.btn[disabled],
.btn.is-disabled {
  border-color: var(--line);
  background: var(--bg-sunken);
  color: var(--fg-faint);
  cursor: not-allowed;
  pointer-events: none;
}

.btn-group {
  display: inline-flex;
}

.btn-group .btn {
  border-radius: 0;
  margin-left: calc(-1 * var(--hair));
}

.btn-group .btn:first-child {
  border-radius: var(--radius) 0 0 var(--radius);
  margin-left: 0;
}

.btn-group .btn:last-child {
  border-radius: 0 var(--radius) var(--radius) 0;
}

/* --------------------------------------------------------------------------
   4. Forms
   -------------------------------------------------------------------------- */

.form-group {
  margin-bottom: var(--u3);
}

.form-group:last-child {
  margin-bottom: 0;
}

.form-label {
  display: block;
  margin-bottom: var(--u1);
  color: var(--fg-strong);
  font-weight: 600;
}

.form-label .req {
  color: var(--bad);
}

.form-hint {
  margin-top: var(--u1);
  color: var(--fg-muted);
  font-size: var(--fs-sm);
}

.form-input,
.form-select,
textarea.form-input {
  display: block;
  width: 100%;
  padding: var(--u2) var(--u2);
  border: var(--hair) solid var(--line-strong);
  border-radius: var(--radius);
  background: var(--surface);
  color: var(--fg-strong);
  font-family: inherit;
  font-size: var(--fs);
  line-height: var(--lh);
}

.form-input:focus,
.form-select:focus {
  border-color: var(--primary);
  box-shadow: 0 0 0 0.1rem rgba(79, 79, 187, 0.2);
  outline: none;
}

textarea.form-input {
  min-height: 4.5rem;
  resize: vertical;
}

.form-input[readonly] {
  background: var(--bg-sunken);
  color: var(--fg-muted);
}

.form-check {
  display: flex;
  align-items: center;
  gap: var(--u2);
  padding: var(--u1) 0;
  cursor: pointer;
}

/* One field per row. Always.

   A form is filled top to bottom and a single column is one path for the eye
   instead of a zigzag; it also means adding a field in the middle of a section
   moves nothing sideways further down. There is no grid to derive, no width to
   configure, and nothing to explain.

   The row is one field — the control inside it is still sized to what it
   holds. A date picker stretched across half a screen is a lie about how much
   a date is, so the two kinds of value that are never long get a width of
   their own, and a boolean gets none at all because it is a checkbox. */
.form-input-narrow {
  max-width: 10rem;
}

/* NOT a layout of fields: a strip of controls in a panel foot — add an option,
   grant a competence, assign a role — and the from/to pair of one filter,
   which is two halves of a single thing rather than two things. */
.form-inline {
  display: flex;
  flex-wrap: wrap;
  gap: var(--u2);
}

.form-inline .form-group {
  flex: 1 1 12rem;
  margin-bottom: 0;
}

/* Colour on a value that is not a chip and not a whole notice: the one
   digest that no longer matches, the one count that is over. Both examples
   are bad news, and so is every caller — the optimistic twin was written and
   never used, so it is not here. */
.is-bad { color: var(--bad); }

.form-error {
  margin-top: var(--u1);
  color: var(--bad);
  font-size: var(--fs-sm);
}

.form-group.has-error .form-input,
.form-group.has-error .form-select {
  border-color: var(--bad);
}

.form-actions {
  display: flex;
  align-items: center;
  gap: var(--u2);
  margin-top: var(--u4);
  padding-top: var(--u3);
  border-top: var(--hair) solid var(--line-soft);
}

.form-actions .spacer {
  flex: 1 1 auto;
}

/* --------------------------------------------------------------------------
   5. Notices
   -------------------------------------------------------------------------- */

.notice {
  padding: var(--u2) var(--u3);
  border-left: 0.2rem solid var(--fg-faint);
  border-radius: var(--radius);
  background: var(--bg-sunken);
}

.notice-ok {
  border-left-color: var(--ok);
  background: var(--ok-wash);
}

.notice-warn {
  border-left-color: var(--warn);
  background: var(--warn-wash);
}

.notice-bad {
  border-left-color: var(--bad);
  background: var(--bad-wash);
}

.notice .witness {
  margin-top: var(--u1);
  padding-left: var(--u4);
  list-style: none;
  color: var(--fg-muted);
  font-size: var(--fs-sm);
}

.notice h3 {
  margin-bottom: var(--u1);
  font-size: var(--fs);
}

.notice ul {
  list-style: disc;
  padding-left: var(--u5);
}

.empty {
  padding: var(--u8) var(--u5);
  border: var(--hair) dashed var(--line);
  border-radius: var(--radius);
  color: var(--fg-muted);
  text-align: center;
}

.empty .empty-icon {
  font-size: 2.2rem;
  line-height: 1;
}

.empty .empty-title {
  margin-top: var(--u3);
  color: var(--fg-strong);
  font-weight: 600;
}

/* --------------------------------------------------------------------------
   6. The gate — signing in, and being refused

   Every screen in this app is a gate. There is no toolbar and no band here,
   not as an exception but as the whole design: this app has no tenant, no
   company and no host of yours to print, by design, so there are no sections
   to offer and nothing else on the page to click.

   Adapted from core's section 21 in three ways, all of them consequences of
   that:

   - `.gate-company` and `.gate-host` are gone. They were drawn for a
     tenant-branded card ("Meridian Ventures", `meridian.poruch.local`) and this
     app has no data source for either. `.gate-title` and `.gate-lead` take
     their declarations and their place: the sentence the card is about, and
     the line under it.

   - `.gate-body` is new. Core's gate holds one sentence and one button, so it
     centres everything. Half the screens here hold a form, a list of scopes or
     an authorization code — things read line by line rather than at a glance —
     and centred text is wrong for all of them.

   - `.gate-actions` replaces core's `.gate-card .btn`. Core's gate offers one
     way forward; the consent screen offers two, and a rule that puts
     `margin-top: var(--u5)` on every button in the card cannot stack them.
   -------------------------------------------------------------------------- */

.gate {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 100vh;
  padding: var(--u5);
  background: var(--bg);
}

.gate-card {
  width: 100%;
  max-width: 24rem;
  padding: var(--u6);
  border: var(--hair) solid var(--line);
  border-top: 0.2rem solid var(--primary);
  border-radius: var(--radius);
  background: var(--surface);
  box-shadow: var(--shadow);
  text-align: center;
  /* Names, hosts and addresses here are other people's and as long as they like,
     so nothing in the card may run off it. Only breaks what would not fit. */
  overflow-wrap: anywhere;
}

.gate-card.is-refused {
  border-top-color: var(--bad);
}

.gate-mark {
  display: grid;
  place-items: center;
  width: 2.4rem;
  height: 2.4rem;
  margin: 0 auto;
  border-radius: var(--radius);
  background: var(--primary);
  color: #fff;
  font-size: var(--fs-h1);
  font-weight: 700;
}

.gate-card.is-refused .gate-mark {
  background: var(--bad);
}

.gate-title {
  margin-top: var(--u3);
  color: var(--fg-strong);
  font-size: var(--fs-h2);
  font-weight: 600;
}

.gate-lead {
  color: var(--fg-muted);
  font-size: var(--fs-sm);
}

/* Anything filled in or read line by line. The card's own copy is centred
   because it is one sentence; a form is not one sentence. */
.gate-body {
  margin-top: var(--u4);
  text-align: left;
}

/* The only vertical rhythm inside the card, so nothing within it carries a
   margin of its own — the same bargain core's `.surface-main > * + *` makes
   with the main column. */
.gate-body > * + * {
  margin-top: var(--u4);
}

/* Every action on a gate is the action. Full width, one under the other, in
   the order they are offered. The children are buttons or the forms that wrap
   them, so the gap is on the container rather than on the button. */
.gate-actions {
  display: grid;
  gap: var(--u2);
  margin-top: var(--u5);
}

.gate-actions .btn {
  width: 100%;
  justify-content: center;
}

.gate-foot {
  margin-top: var(--u4);
  padding-top: var(--u3);
  border-top: var(--hair) solid var(--line-soft);
  color: var(--fg-muted);
  font-size: var(--fs-sm);
  text-align: left;
}

/* A host stays whole on a line of its own while it fits. One that does not fit
   wraps and is never cut off: its end says whose it is, so
   `core.example.app.attacker.test` has to read to its last label. */
.gate-lead code,
.gate-foot code {
  display: inline-block;
  max-width: 100%;
  white-space: normal;
}
