/*
 * A signal box, not a library (§10).
 *
 * This hub is opened in the middle of doing something else, by someone who already knows which
 * door they want. Density and scanability first: contract numbers in monospace because they are the
 * primary identifier and are read in a column of a hundred and forty, one accent for the jump you
 * are in, and a muted rose reserved for the things that cannot be undone.
 *
 * The accent is amethyst, and the ground it sits on is a void grey that carries a trace of the same
 * violet. Atmosphere is allowed here but not indulged: a nebula wash behind the page, fixed so it
 * does not travel while scrolling, at an opacity that survives being looked at all day. Nothing in
 * it animates and nothing in it carries meaning — the moment colour has to *say* something, it is
 * the expiry board or a destructive button, and both of those have to stay legible against it.
 */

:root {
  --ink: #1a1723;
  --ink-soft: #5d5672;
  --ink-faint: #8b83a1;
  --ground: #f7f5fa;
  --panel: #ffffff;
  --line: #e2deea;
  --line-strong: #c6bfd6;
  --accent: #6d3fa8;
  --accent-soft: #f1ebfa;
  --danger: #8f2f3f;
  --danger-soft: #fbecee;
  --good: #2c6a4a;

  /* The nebula. Two washes rather than one, so the gradient has somewhere to go. */
  --nebula-one: rgba(126, 74, 191, 0.07);
  --nebula-two: rgba(70, 92, 168, 0.05);
  --glow: rgba(109, 63, 168, 0.28);
  --glow-deep: rgba(76, 29, 149, 0.22);
  --mark-edge: #4c1d95;

  --mono: ui-monospace, "SF Mono", "JetBrains Mono", Menlo, Consolas, monospace;
  --sans: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", sans-serif;

  color-scheme: light dark;
}

/*
  The void. This is the mode the hub actually lives in — it sits open all day beside a terminal.

  The greys are not neutral: every one of them carries a little violet, so the amethyst accent reads
  as the same family rather than as a sticker on slate. Contrast against --ground is kept above 7:1
  for --ink and above 4.5:1 for --ink-soft, because a dim purple interface is exactly where that
  slips without anybody noticing until they are reading a column of contract numbers at five.
*/
@media (prefers-color-scheme: dark) {
  :root {
    --ink: #e9e6f2;
    --ink-soft: #a9a2c0;
    --ink-faint: #7b7496;
    --ground: #131118;
    --panel: #1b1824;
    --line: #2c2739;
    --line-strong: #3f3854;
    --accent: #b794f6;
    --accent-soft: #241d33;
    --danger: #e38f9e;
    --danger-soft: #2d1b21;
    --good: #6fbb92;

    --nebula-one: rgba(151, 99, 222, 0.22);
    --nebula-two: rgba(74, 99, 192, 0.16);
    --glow: rgba(183, 148, 246, 0.55);
    --glow-deep: rgba(109, 40, 217, 0.75);
    --mark-edge: #6d28d9;
  }
}

* { box-sizing: border-box; }

/*
  The nebula wash.

  Fixed attachment so it belongs to the window rather than to the document: it must not slide up
  behind a long table of contracts, which turns a background into motion. Two off-centre radial
  gradients over the flat ground, no image, no extra request, nothing to animate.
*/
body {
  margin: 0;
  background:
    radial-gradient(60rem 40rem at 78% -8%, var(--nebula-one), transparent 68%),
    radial-gradient(48rem 34rem at 8% 6%, var(--nebula-two), transparent 62%),
    var(--ground);
  background-attachment: fixed;
  color: var(--ink);
  font: 14px/1.5 var(--sans);
  min-height: 100vh;
}

a { color: var(--ink); text-decoration-color: var(--line-strong); text-underline-offset: 2px; }
a:hover { text-decoration-color: var(--accent); }

/* ---- Chrome ---- */

/*
  Translucent, so the wash behind the page carries through the chrome instead of stopping at it.
  colour-mix rather than a second palette: one accent to change, and the bar follows it.
*/
.bar {
  display: flex;
  align-items: center;
  gap: 1.5rem;
  padding: 0 1.25rem;
  height: 3rem;
  background: color-mix(in srgb, var(--panel) 86%, var(--accent));
  border-bottom: 1px solid var(--line);
}

.bar__mark {
  font-weight: 600;
  letter-spacing: 0.02em;
  text-decoration: none;
  color: var(--accent);
}

.bar__nav { display: flex; align-items: center; gap: 0.15rem; }

/*
  Real targets rather than a row of text.
 
  The bar was six underlined words a pixel apart; where you were took reading to work out, and
  clicking the wrong one was easy. Padding makes each one a thing you can hit, and the current
  section is marked rather than inferred.
*/
.bar__nav a {
  color: var(--ink-soft);
  text-decoration: none;
  padding: 0.35rem 0.6rem;
  border-radius: 3px;
  line-height: 1;
}

.bar__nav a:hover { color: var(--ink); background: var(--accent-soft); }

/* Where you are. Colour AND weight AND a rule under it: any one of the three alone is a thing
   somebody has to notice, and this is meant to be answered without looking for it. */
.bar__nav a.is-here {
  color: var(--accent);
  font-weight: 600;
  background: var(--accent-soft);
  box-shadow: inset 0 -2px 0 var(--accent);
}

/* Between an engineer's own doors and the tools that administer them. */
.bar__rule {
  width: 1px;
  height: 1.1rem;
  margin: 0 0.5rem;
  background: var(--line-strong);
}

.bar__who {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: 0.75rem;
  color: var(--ink-soft);
}

.wrap { max-width: 64rem; margin: 0 auto; padding: 1.75rem 1.25rem 4rem; }

.foot {
  max-width: 64rem;
  margin: 0 auto;
  padding: 0 1.25rem 2rem;
  color: var(--ink-faint);
  font-size: 12px;
}

/* ---- The gate: sign-in and everything before you are through ---- */

/*
  One box, in the middle of the window, under the product's own name.

  These pages have no navigation to offer, so they do not carry the bar — which on a wide screen left
  a wordmark alone in a corner and the form pinned to the top-left of a great deal of nothing.

  `min-height: 100dvh` rather than `100vh`: on a phone the address bar is part of the viewport by the
  vh measure, so a centred box sits visibly low and shifts when the bar retracts.
*/
/*
  Anchored from the top, not centred.

  Centring puts the box where the *content* balances, so the sign-in page and the six-digit page —
  one being two fields shorter than the other — landed at different heights, and the mark jumped down
  the screen at the exact moment you were asked to type something. Measuring from the top means every
  page in this sequence puts its mark, its name and its first field in the same place, and only what
  is underneath changes.

  `min-height: 100dvh` rather than `100vh`: on a phone the address bar counts towards vh, so the page
  is taller than the window and shifts as the bar retracts.
*/
.gate {
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: clamp(1.25rem, 7vh, 6rem) 1.25rem 1rem;
}

/*
  A container, so the brand can be sized against this column rather than against the window.

  The wordmark is asked to be at least as wide as the box below it. In viewport units that is only
  true at one window size; in container units it is true at every one, and the relationship survives
  somebody changing the column width later.
*/
.gate__column {
  width: min(26rem, 100%);
  container-type: inline-size;
}

.gate__brand {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.9rem;
  margin-bottom: 1.8rem;
  color: var(--accent);
}

/*
  Sized in container units so it spans the column at any width. The multiplier is measured rather
  than guessed — see the note in the gate styles above — and the letter-spacing is part of the
  measurement, not decoration applied after it.
*/
.gate__name {
  font-size: 11.5cqw;
  font-weight: 600;
  letter-spacing: 0.055em;
  line-height: 1.1;
  color: var(--ink);
  white-space: nowrap;
}

/*
  The mark takes its colour from .gate__brand, so there is one place to change it.

  Sized here rather than only in the markup so a narrow window can have a smaller one. The stroke is
  in the drawing's own units, so it thickens with the figure rather than staying a hairline in a
  larger space.
*/
.mark {
  display: block;

  /*
    Against the column, but capped against the window.

    At 78cqw alone the mark is 316px, and on a 713-pixel-high laptop that put the Sign in button 109
    pixels below the fold — a sign-in page you have to scroll to use, which is a worse failure than a
    small mark. Measured at three window heights rather than assumed. The cap only binds on short
    windows; on a tall one the column decides, which is what keeps it in proportion to the box.
  */
  width: min(78cqw, 32dvh);
  height: auto;

  /*
    The glow. Two drop-shadows rather than one: a tight halo that reads as light coming off the line
    itself, and a wide faint one that lifts the whole figure off the ground. drop-shadow follows the
    alpha of the drawing, so it traces the star rather than boxing it, which is the reason for it
    over box-shadow.

    Two colours, matching the two strokes: a tight halo in the accent, which reads as light coming off
    the bright core, and a wider bloom in the deeper purple of the edge. One glow in one colour read
    as a lamp behind the figure; two read as the line itself being lit.

    Static. Nothing on these pages animates (§10), and a pulsing sigil above a password field is a
    distraction at exactly the wrong moment.
  */
  filter: drop-shadow(0 0 0.3rem var(--glow)) drop-shadow(0 0 1.15rem var(--glow-deep));
}

/* The page's own heading, inside the box rather than floating above it. */
.gate .page-head { margin-bottom: 1rem; }
.gate .page-head h1 { font-size: 1.15rem; }

/* A narrow column is already narrow; the extra cap only fights it. */
.gate .panel--narrow { max-width: none; }

/* The notice under the box on the sign-in page, which had a hand-written width on it. */
.gate .notice { margin: 1.25rem 0 0; }

/* margin-top: auto keeps it at the bottom of the window rather than trailing the box, so the height
   of the page above it never moves it. */
.gate__foot {
  margin-top: auto;
  padding: 2.5rem 1.25rem 1.5rem;
  color: var(--ink-faint);
  font-size: 12px;
  text-align: center;
}

/* ---- Structure ---- */

.page-head { margin-bottom: 1.25rem; }
.page-head p { margin: 0; color: var(--ink-soft); }
.page-head__name { color: var(--ink); }

/* Sign-in, enrolment, errors: pages with no bar above them and nowhere to go up to, so they keep a
   plain heading rather than a trail of one. Styled to match .trail so they are the same size. */
.page-head h1 { margin: 0 0 0.3rem; font-size: 1.35rem; font-weight: 600; line-height: 1.25; }

/* ---- The title, which is also the trail ---- */

/*
  One line that says what this page is by saying where it sits: "Jumps → 10010".

  The steps above are links at title size, which is the point — the way back out should be as easy
  to hit as the title is to read, not six-point grey above it. They are lighter than the last step
  so the line still reads as a title with an emphasis at the end rather than as a row of equals.
*/
.trail {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.45rem;
  margin: 0 0 0.3rem;
  font-size: 1.35rem;
  font-weight: 600;
  line-height: 1.25;
}

/*
  Underlined before it is hovered, not after.

  A grey word at title size reads as part of the title; nothing about it says it can be clicked, and
  hover is not a discovery mechanism — it only tells you about the thing you had already guessed.
  The rule is faint enough to stay out of the way of reading the line.
*/
.trail__up {
  color: var(--ink-soft);
  font-weight: 400;
  text-decoration: underline;
  text-decoration-color: var(--line-strong);
  text-decoration-thickness: 1px;
  text-underline-offset: 4px;
  border-radius: 3px;
  padding: 0 0.15rem;
}

.trail__up:hover {
  color: var(--accent);
  text-decoration-color: var(--accent);
}
.trail__sep { color: var(--ink-faint); font-weight: 400; }
.trail__here { color: var(--ink); }

.panel {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 3px;
  padding: 1.25rem;
}

.panel--narrow { max-width: 30rem; }
.panel + .panel { margin-top: 1rem; }

.section { margin-top: 2rem; }
.section > h2 { margin: 0 0 0.75rem; font-size: 1rem; font-weight: 600; }

/* The sync plan: three columns that are read against each other, so they sit side by side until
   there is no room, and each keeps its own heading rather than being one long list. */
.dns-plan {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr));
  gap: 1rem;
  margin-top: 1rem;
}

.dns-plan h3 { margin: 0 0 .35rem; font-size: 13px; font-weight: 600; color: var(--ink-soft); }
.dns-plan p { margin: 0; word-break: break-word; }
.dns-plan .empty { padding: 0; font-size: 13px; }

/* One adopted-name form per row: the label, the jump it would go to, and the button, on one line. */
.adopt { display: flex; align-items: center; gap: .4rem; margin-top: .4rem; }
.adopt select { width: auto; flex: 1 1 auto; min-width: 0; }

/* ---- Tables ---- */

table { width: 100%; border-collapse: collapse; }
th, td { text-align: left; padding: 0.5rem 0.75rem; border-bottom: 1px solid var(--line); }
th { font-size: 12px; text-transform: uppercase; letter-spacing: 0.04em; color: var(--ink-faint); font-weight: 600; }
td.num, th.num, .mono { font-family: var(--mono); }
tr:last-child td { border-bottom: 0; }
.table-wrap { overflow-x: auto; }

/* These tables are read across a row, in quantity. A hover band is the cheapest help there is. */
tbody tr:hover { background: var(--accent-soft); }

/* ---- Breadcrumbs ---- */

/*
  Where you are, and the way back out, on any page that is not reachable from the bar.
 
  Above the title rather than inside it: the title says what this page is, and it should still read
  as a title when the trail above it is ignored. The last step is the current page and is not a link
  — a link to where you already are is a small lie that costs a click to discover.
*/
.crumbs {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.4rem;
  margin-bottom: 0.3rem;
  font-size: 13px;
}

.crumbs a { color: var(--ink-soft); text-decoration: none; }
.crumbs a:hover { color: var(--accent); text-decoration: underline; text-underline-offset: 2px; }
.crumbs__sep { color: var(--ink-faint); }
.crumbs__here { color: var(--ink-faint); }

/* ---- Forms ---- */

.field { margin-bottom: 0.9rem; }
.field label { display: block; margin-bottom: 0.25rem; color: var(--ink-soft); font-size: 13px; }

input[type=text], input[type=email], input[type=password], input[type=search], textarea, select {
  width: 100%;
  padding: 0.45rem 0.55rem;
  background: var(--ground);
  color: var(--ink);
  border: 1px solid var(--line-strong);
  border-radius: 2px;
  font: inherit;
}

input:focus, textarea:focus, select:focus { outline: 2px solid var(--accent); outline-offset: -1px; }

.check { display: flex; align-items: center; gap: 0.5rem; margin-bottom: 0.9rem; color: var(--ink-soft); }
.check input { width: auto; }

.actions { display: flex; gap: 0.5rem; align-items: center; margin-top: 1rem; }
.inline-form { display: inline; }

.btn {
  padding: 0.4rem 0.8rem;
  border: 1px solid var(--line-strong);
  border-radius: 2px;
  background: var(--panel);
  color: var(--ink);
  font: inherit;
  cursor: pointer;
}

.btn:hover { border-color: var(--accent); }
/*
  Panel, not a fixed colour, for the label: the accent is dark in daylight and light in the void, and
  the panel colour inverts with it. One declaration that stays legible in both rather than two that
  have to be kept in step.
*/
.btn--primary { background: var(--accent); color: var(--panel); border-color: var(--accent); }
.btn--primary:hover { filter: brightness(1.12); }
.btn--danger { color: var(--danger); border-color: var(--danger); background: transparent; }
.btn--danger:hover { background: var(--danger-soft); }
.btn--quiet { border-color: transparent; background: transparent; color: var(--ink-soft); padding: 0.4rem 0.5rem; }
.btn--quiet:hover { color: var(--ink); border-color: var(--line-strong); }

/* ---- Notices ---- */

.notice { padding: 0.7rem 0.9rem; border-radius: 2px; border-left: 3px solid var(--line-strong); background: var(--ground); margin-bottom: 1rem; }
.notice p { margin: 0; }
.notice--error { border-left-color: var(--danger); background: var(--danger-soft); }
.notice--ok { border-left-color: var(--good); }
.notice--note { border-left-color: var(--accent); background: var(--accent-soft); }

/* A token shown exactly once. It must be selectable and unmistakable. */
.token {
  display: block;
  font-family: var(--mono);
  font-size: 12px;
  word-break: break-all;
  padding: 0.6rem;
  background: var(--ground);
  border: 1px dashed var(--line-strong);
  border-radius: 2px;
  margin: 0.5rem 0;
}

.tag { display: inline-block; padding: 0.1rem 0.4rem; border: 1px solid var(--line-strong); border-radius: 2px; font-size: 12px; color: var(--ink-soft); }
.tag--warn { color: var(--danger); border-color: var(--danger); }
.tag--ok { color: var(--good); border-color: var(--good); }

.empty { color: var(--ink-faint); padding: 1rem 0; }
