/* ────────────────────────────────────────────────────────────────────────────
   Tessera — customer portal

   The operator console next door is a dark instrument panel: dense, amber and
   teal, built for someone diagnosing a fault at 2am. This is the opposite room.
   A customer visits to check on their organisation and get on with their day,
   so the register here is closer to well-set stationery than to a control
   surface — warm paper, a generous measure, hairline rules, and one accent
   colour used sparingly.

   The two planes deliberately share no accent colour. Nobody should ever be
   momentarily unsure which one they are looking at.

   The one convention carried over from the console: anything a machine
   produced is set in mono. Identifiers, limits, addresses, timestamps.
   ──────────────────────────────────────────────────────────────────────────── */

@import url("fonts.css");

:root {
  --paper:      #FBFAF8;
  --card:       #FFFFFF;
  --sunken:     #F4F2EE;
  --rule:       #E4E1DB;
  --rule-soft:  #EFEDE8;

  --ink:        #16181D;
  --ink-muted:  #5B6170;
  --ink-faint:  #8A8F9C;

  --accent:     #2F4B7C;
  --accent-ink: #FFFFFF;
  --accent-wash:#EDF1F7;

  --good:       #2E6F5E;
  --caution:    #8A5A11;
  --bad:        #A8342C;
  --bad-wash:   #FBEEED;

  --radius:     4px;
  --measure:    64rem;

  --font-ui:   "Archivo", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  --font-mono: "JetBrains Mono", ui-monospace, "SF Mono", Menlo, Consolas, monospace;

  color-scheme: light;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --paper:      #14161B;
    --card:       #1A1D24;
    --sunken:     #20242C;
    --rule:       #2C313B;
    --rule-soft:  #23272F;

    --ink:        #E8E9ED;
    --ink-muted:  #A2A9B8;
    --ink-faint:  #6F7787;

    --accent:     #8AA9DC;
    --accent-ink: #10131A;
    --accent-wash:#1E2531;

    --good:       #6FC2AC;
    --caution:    #D9A24B;
    --bad:        #E88078;
    --bad-wash:   #2B1E1E;

    color-scheme: dark;
  }
}

:root[data-theme="dark"] {
  --paper:      #14161B;
  --card:       #1A1D24;
  --sunken:     #20242C;
  --rule:       #2C313B;
  --rule-soft:  #23272F;
  --ink:        #E8E9ED;
  --ink-muted:  #A2A9B8;
  --ink-faint:  #6F7787;
  --accent:     #8AA9DC;
  --accent-ink: #10131A;
  --accent-wash:#1E2531;
  --good:       #6FC2AC;
  --caution:    #D9A24B;
  --bad:        #E88078;
  --bad-wash:   #2B1E1E;
  color-scheme: dark;
}

*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font-ui);
  font-size: 15px;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
}

.v, code, pre, input, select, textarea, td.num, th.num {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
}

a { color: var(--accent); text-underline-offset: .18em; }

:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* ── Shell ──────────────────────────────────────────────────────────────── */

.masthead {
  border-bottom: 1px solid var(--rule);
  background: var(--card);
}
.masthead-inner {
  max-width: var(--measure);
  margin: 0 auto;
  padding: .85rem 1.5rem;
  display: flex;
  align-items: center;
  gap: 1rem;
}
.wordmark {
  font-weight: 700;
  letter-spacing: .14em;
  text-transform: uppercase;
  font-size: .9rem;
  text-decoration: none;
  color: var(--ink);
}
.masthead .right { margin-left: auto; display: flex; align-items: center; gap: .6rem; }

.orgpick {
  display: inline-flex;
  align-items: center;
  gap: .45rem;
  padding: .28rem .6rem;
  border: 1px solid var(--rule);
  border-radius: 999px;
  background: var(--sunken);
  font-size: .82rem;
}
.orgpick select {
  border: 0; background: none; padding: 0;
  font-family: var(--font-ui); font-size: .82rem; color: var(--ink);
  font-weight: 600; cursor: pointer;
}
.orgpick .role {
  font-family: var(--font-mono);
  font-size: .66rem;
  text-transform: uppercase;
  letter-spacing: .08em;
  color: var(--ink-faint);
}

.tabs {
  border-bottom: 1px solid var(--rule);
  background: var(--card);
}
.tabs-inner {
  max-width: var(--measure);
  margin: 0 auto;
  padding: 0 1.5rem;
  display: flex;
  gap: .25rem;
  overflow-x: auto;
}
.tabs a {
  padding: .7rem .8rem;
  font-size: .85rem;
  color: var(--ink-muted);
  text-decoration: none;
  border-bottom: 2px solid transparent;
  white-space: nowrap;
}
.tabs a:hover { color: var(--ink); }
.tabs a[aria-current="page"] {
  color: var(--ink);
  font-weight: 600;
  border-bottom-color: var(--accent);
}

main { max-width: var(--measure); margin: 0 auto; padding: 2rem 1.5rem 5rem; }

.page-head { margin-bottom: 1.6rem; }
.page-head h1 {
  margin: 0;
  font-size: 1.5rem;
  font-weight: 600;
  letter-spacing: -.015em;
}
.page-head p { margin: .3rem 0 0; color: var(--ink-muted); max-width: 46rem; }

/* ── Sections: a statement's hairline headers ───────────────────────────── */

section + section { margin-top: 2.4rem; }
/* A note or card placed before the first section still needs clearance from
   that section's hairline rule. */
.note + section, .card + section, .page-head + section { margin-top: 2rem; }
main > .note + section { margin-top: 2rem; }

.section-head {
  display: flex;
  align-items: baseline;
  gap: 1rem;
  padding-bottom: .5rem;
  border-bottom: 1px solid var(--rule);
  margin-bottom: 1rem;
}
.section-head h2 {
  margin: 0;
  font-size: .72rem;
  font-weight: 700;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--ink-muted);
}
.section-head .right { margin-left: auto; }

.card {
  background: var(--card);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  padding: 1.15rem 1.25rem;
}
.card + .card { margin-top: .9rem; }

/* ── The capacity ledger ────────────────────────────────────────────────────
   Usage against limits, set as a statement rather than a row of progress bars.
   Every rented platform shows this; almost all of them show it as coloured
   bars that say nothing a number would not. A ledger reads exactly, aligns on
   the decimal, and does not imply precision the figures do not have. */

.ledger { width: 100%; border-collapse: collapse; }
.ledger th {
  text-align: left;
  font-size: .68rem;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--ink-faint);
  font-weight: 700;
  padding: 0 0 .5rem;
  border-bottom: 1px solid var(--rule);
}
.ledger th.num, .ledger td.num { text-align: right; }
.ledger td {
  padding: .62rem 0;
  border-bottom: 1px solid var(--rule-soft);
}
.ledger tr:last-child td { border-bottom: 0; }
.ledger .item { font-weight: 500; }
.ledger .sub { display: block; font-size: .76rem; color: var(--ink-faint); font-family: var(--font-ui); }
.ledger .limitless { color: var(--ink-faint); font-style: italic; font-family: var(--font-ui); font-size: .82rem; }

/* A hairline share indicator: present, but subordinate to the number. */
.share {
  display: block;
  height: 2px;
  margin-top: .35rem;
  background: var(--rule);
  border-radius: 1px;
  overflow: hidden;
}
.share i { display: block; height: 100%; background: var(--accent); }
.share.warn i { background: var(--caution); }
.share.full i { background: var(--bad); }

/* ── Tables ─────────────────────────────────────────────────────────────── */

table.list { width: 100%; border-collapse: collapse; font-size: .88rem; }
table.list th {
  text-align: left;
  font-size: .66rem;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--ink-faint);
  font-weight: 700;
  padding: .5rem .75rem;
  border-bottom: 1px solid var(--rule);
  white-space: nowrap;
}
table.list td {
  padding: .68rem .75rem;
  border-bottom: 1px solid var(--rule-soft);
  vertical-align: middle;
}
table.list tr:last-child td { border-bottom: 0; }
table.list th.num, table.list td.num { text-align: right; }
.table-wrap { overflow-x: auto; }

/* ── Tags ───────────────────────────────────────────────────────────────── */

.tag {
  display: inline-block;
  font-family: var(--font-mono);
  font-size: .66rem;
  letter-spacing: .05em;
  text-transform: uppercase;
  padding: .14rem .45rem;
  border-radius: 2px;
  background: var(--sunken);
  color: var(--ink-muted);
  border: 1px solid var(--rule);
}
.tag.accent { background: var(--accent-wash); color: var(--accent); border-color: transparent; }
.tag.good   { color: var(--good); }
.tag.bad    { color: var(--bad); }
.tag.you    { background: var(--accent); color: var(--accent-ink); border-color: transparent; }

/* ── Forms ──────────────────────────────────────────────────────────────── */

.field { margin-bottom: 1.1rem; }
.field label {
  display: block;
  font-size: .8rem;
  font-weight: 600;
  margin-bottom: .3rem;
}
.field .hint { font-size: .8rem; color: var(--ink-faint); margin-top: .3rem; line-height: 1.45; }
.field .err  { font-size: .8rem; color: var(--bad); margin-top: .3rem; }

input[type=text], input[type=email], input[type=password], input[type=number], select, textarea {
  width: 100%;
  padding: .55rem .65rem;
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  background: var(--card);
  color: var(--ink);
  font-size: .9rem;
}
input::placeholder { color: var(--ink-faint); }
input[aria-invalid="true"] { border-color: var(--bad); }

.btn {
  font-family: var(--font-ui);
  font-size: .85rem;
  font-weight: 600;
  padding: .5rem 1rem;
  border-radius: var(--radius);
  border: 1px solid var(--rule);
  background: var(--card);
  color: var(--ink);
  cursor: pointer;
}
.btn:hover:not(:disabled) { background: var(--sunken); }
.btn:disabled { opacity: .5; cursor: not-allowed; }
.btn.primary { background: var(--accent); border-color: var(--accent); color: var(--accent-ink); }
.btn.primary:hover:not(:disabled) { filter: brightness(1.1); }
.btn.danger  { color: var(--bad); border-color: color-mix(in srgb, var(--bad) 35%, transparent); }
.btn.small   { font-size: .76rem; padding: .3rem .6rem; }
.btn-row { display: flex; gap: .6rem; align-items: center; flex-wrap: wrap; }

/* ── Notes ──────────────────────────────────────────────────────────────── */

.note {
  border: 1px solid var(--rule);
  border-left: 3px solid var(--ink-faint);
  border-radius: var(--radius);
  background: var(--card);
  padding: .85rem 1rem;
  font-size: .88rem;
}
.note h3 { margin: 0 0 .25rem; font-size: .9rem; font-weight: 600; }
.note p  { margin: 0; color: var(--ink-muted); }
.note.info    { border-left-color: var(--accent); }
.note.good    { border-left-color: var(--good); }
.note.caution { border-left-color: var(--caution); }
.note.bad     { border-left-color: var(--bad); background: var(--bad-wash); }
.note + .note { margin-top: .7rem; }

.secret {
  font-family: var(--font-mono);
  font-size: .84rem;
  word-break: break-all;
  background: var(--sunken);
  border: 1px dashed var(--rule);
  border-radius: var(--radius);
  padding: .7rem .8rem;
  margin: .6rem 0;
}

.codes {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(9rem, 1fr));
  gap: .4rem;
  font-family: var(--font-mono);
  font-size: .84rem;
  margin: .7rem 0;
}
.codes span {
  background: var(--sunken);
  border: 1px solid var(--rule);
  border-radius: 2px;
  padding: .3rem .5rem;
  text-align: center;
}

.empty { padding: 2.2rem 1rem; text-align: center; color: var(--ink-faint); }
.empty h3 { margin: 0 0 .3rem; color: var(--ink-muted); font-size: .95rem; }
.empty p { margin: 0 auto; max-width: 32rem; font-size: .88rem; }

/* ── Entry screens ──────────────────────────────────────────────────────── */

.entry {
  min-height: 100vh;
  display: grid;
  place-items: center;
  padding: 1.5rem;
}
.entry-card {
  width: 100%;
  max-width: 24rem;
  background: var(--card);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  padding: 1.8rem 1.6rem 1.6rem;
}
.entry-card .wordmark { display: block; margin-bottom: .2rem; }
.entry-card .tagline {
  font-size: .82rem;
  color: var(--ink-faint);
  margin-bottom: 1.6rem;
}
.entry-foot {
  margin-top: 1.2rem;
  padding-top: 1rem;
  border-top: 1px solid var(--rule-soft);
  font-size: .82rem;
  color: var(--ink-muted);
  display: flex;
  justify-content: space-between;
  gap: .75rem;
  flex-wrap: wrap;
}

/* ── Utility ────────────────────────────────────────────────────────────── */

.muted { color: var(--ink-muted); }
.faint { color: var(--ink-faint); }
.tiny  { font-size: .8rem; }
.right { margin-left: auto; }
.row   { display: flex; align-items: center; gap: .6rem; flex-wrap: wrap; }
.stack { display: flex; flex-direction: column; gap: .3rem; }
.grid2 { display: grid; gap: 1rem; grid-template-columns: repeat(auto-fit, minmax(19rem, 1fr)); }
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

@media (max-width: 40rem) {
  main { padding: 1.4rem 1rem 4rem; }
  .masthead-inner, .tabs-inner { padding-left: 1rem; padding-right: 1rem; }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: .01ms !important; transition-duration: .01ms !important; }
}

/* Which sign-in door this is. The login error cannot say, so the page must. */
.plane-hint {
  margin: .4rem 0 1.5rem;
  font-size: .8rem;
  line-height: 1.5;
  opacity: .7;
}

/* ── Machines and networks ──────────────────────────────────────────────────
   Added for the machine and network screens. Same register as the rest of the
   portal: hairlines, one accent, mono for anything a machine produced. */

/* Rows that lead somewhere. The whole row is the target, not just the name --
   a customer aiming at a five-character link on a phone is a customer missing. */
table.list tr.clickable { cursor: pointer; }
table.list tr.clickable:hover { background: var(--sunken); }
table.list tr.clickable:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: -2px;
}

table.list .mname { font-weight: 500; }
table.list .sub {
  display: block;
  font-size: .74rem;
  color: var(--ink-faint);
  font-family: var(--font-ui);
  margin-top: .1rem;
}

/* Status, and where it is heading when those differ. */
.statuscell { display: flex; align-items: center; gap: .45rem; flex-wrap: wrap; }
.statuscell .headed {
  font-size: .76rem;
  color: var(--ink-faint);
  font-family: var(--font-ui);
  display: inline-flex;
  align-items: center;
  gap: .25rem;
}
.statuscell .arrow { opacity: .6; }
.statusline { display: flex; align-items: center; gap: .5rem; flex-wrap: wrap; justify-content: flex-end; }

/* A machine mid-change. The pulse is the only motion in the portal, and it
   earns its place: it is the difference between "working on it" and "stuck". */
.tag.accent { position: relative; }
.tag.accent::after {
  content: "";
  display: inline-block;
  width: 5px; height: 5px;
  margin-left: .35rem;
  border-radius: 50%;
  background: currentColor;
  animation: breathe 1.6s ease-in-out infinite;
  vertical-align: middle;
}
@keyframes breathe { 0%, 100% { opacity: 1; } 50% { opacity: .2; } }

.backlink {
  display: inline-block;
  font-size: .82rem;
  color: var(--ink-muted);
  text-decoration: none;
  margin-bottom: .5rem;
}
.backlink:hover { color: var(--accent); }

/* ── Size picker ────────────────────────────────────────────────────────────
   Cards rather than a dropdown: choosing a size is a comparison, and a select
   hides every option but one at the moment the comparison matters. */
.sizes { display: grid; gap: .6rem; grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr)); }
.size { position: relative; display: block; cursor: pointer; }
.size input { position: absolute; opacity: 0; width: 0; height: 0; }
.size-body {
  display: block;
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  padding: .7rem .8rem;
  background: var(--card);
}
.size:hover .size-body { border-color: var(--ink-faint); }
.size input:checked + .size-body {
  border-color: var(--accent);
  background: var(--accent-wash);
  box-shadow: inset 0 0 0 1px var(--accent);
}
.size input:focus-visible + .size-body { outline: 2px solid var(--accent); outline-offset: 2px; }
.size-name  { display: block; font-weight: 600; font-size: .9rem; }
.size-spec  { display: block; font-size: .76rem; color: var(--ink-muted); margin-top: .2rem; }
.size-price { display: block; font-size: .74rem; color: var(--ink-faint); margin-top: .3rem; }

/* ── Allowance, shown before the form ───────────────────────────────────────
   A form that fails on submit because of a limit the customer could have been
   shown is a form that wasted their time. */
.headroom-card { padding: .9rem 1rem; }
.headroom { display: grid; gap: .9rem; grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr)); }
.headroom-item { display: flex; flex-direction: column; gap: .1rem; }
.headroom-item .k {
  font-size: .68rem;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--ink-faint);
  font-weight: 600;
}
.headroom-item .vv  { font-size: .95rem; font-weight: 500; }
.headroom-item .sub { font-size: .72rem; color: var(--ink-faint); font-family: var(--font-ui); }

.stackform { max-width: 34rem; }
.attach select { min-width: 12rem; }

/* Detail pages put their controls in the section header; on a narrow screen
   that header wraps and the buttons need room to breathe. */
@media (max-width: 40rem) {
  .section-head { flex-wrap: wrap; }
  .section-head .right { margin-left: 0; width: 100%; }
  .statusline { justify-content: flex-start; }
  .sizes { grid-template-columns: 1fr; }

  /* The tab bar grew past the width of a phone when Machines and Networks were
     added, and the last four sections simply fell off the right-hand edge with
     no way to reach them. Scroll it instead of hiding it. */
  .tabs-inner {
    overflow-x: auto;
    flex-wrap: nowrap;
    scrollbar-width: none;
    -webkit-overflow-scrolling: touch;
  }
  .tabs-inner::-webkit-scrollbar { display: none; }
  .tabs a { white-space: nowrap; flex: none; }

  /* Detail pages put controls in the section header; give them room. */
  .attach { width: 100%; }
  .attach select { flex: 1; min-width: 0; }

  /* The masthead ran 13px past the right edge of a phone, which made the whole
     page scroll sideways. The signed-in address is the part that can go: it is
     confirmation, not navigation, and the organisation name beside it already
     says which account you are in. */
  .masthead-inner { flex-wrap: wrap; row-gap: .4rem; }
  .masthead .right .v { display: none; }
  .orgpick { min-width: 0; }
  .orgpick strong { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
}

/* Stacked blocks on a form page need air between them; without this the
   allowance card, the caution and the form read as one undifferentiated slab. */
.card + .note,
.note + .card,
.headroom-card + .note { margin-top: 1rem; }

/* ── Machine terminal ────────────────────────────────────────────────────────
   The only way into a machine today, so it gets room rather than a corner. */
.modal-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(12, 16, 22, .72);
  display: grid;
  place-items: center;
  padding: 1.5rem;
  z-index: 60;
}
.modal {
  background: var(--card);
  color: var(--ink);
  border: 1px solid var(--rule);
  border-radius: var(--radius, 4px);
  max-width: min(96vw, 1100px);
  width: 100%;
  max-height: 92vh;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
.modal-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: .8rem 1rem;
  border-bottom: 1px solid var(--rule);
}
.modal-head h2 { margin: 0; font-size: .95rem; }
.console-status {
  padding: .5rem 1rem;
  font-size: .78rem;
  color: var(--ink-muted);
  border-bottom: 1px solid var(--rule-soft);
}
.console-status.connected { color: var(--good); }
/* The framebuffer is dark whatever the page theme is; a terminal that inverts
   with the site would just look broken. */
.console-frame {
  flex: 1;
  min-height: 24rem;
  background: #0b0f14;
  overflow: hidden;
}
.console-frame canvas { display: block; }
.fp { font-size: .74rem; }
@media (max-width: 40rem) {
  .modal-backdrop { padding: 0; }
  .modal { max-height: 100vh; border-radius: 0; border: 0; }
}

/* Key selection on the create form. */
.checklist { display: flex; flex-direction: column; gap: .5rem; margin-bottom: .5rem; }
.checklist .check { display: flex; gap: .55rem; align-items: baseline; font-weight: 400; }
.checklist .check input { margin: 0; }
