/* Site Monitor customer portal — the same dark ground and the same brand as the
   appliance UI it opens, deliberately: a customer who signs in here and clicks
   through to their dashboard should not notice a seam.

   --brand is CHROME ONLY — the wordmark and the active-tab rule. It is never a
   data colour and never a status colour, for the reason given in the
   appliance's own stylesheet: the terracotta is close enough to the "out"
   series orange that a branded element inside a chart would read as data.
   Status uses the reserved status colours. */

:root {
  color-scheme: dark;
  --page:      #181818;
  --surface:   #1a1a19;
  --surface-2: #232321;
  --text:      #f2f2f2;
  --text-2:    #c3c2b7;
  --muted:     #898781;
  --grid:      #2c2c2a;
  --border:    rgba(255, 255, 255, 0.10);

  --brand:     #c06a44;
  --brand-ink: #f2f2f2;

  --good:      #0ca30c;
  --warning:   #fab219;
  --critical:  #d03b3b;
  --accent:    #3987e5;
  --radius:    10px;
}

* { box-sizing: border-box; }

html, body {
  margin: 0; padding: 0;
  background: var(--page); color: var(--text);
  font: 15px/1.45 system-ui, -apple-system, "Segoe UI", sans-serif;
}

a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; }

main { padding: 16px 18px 40px; max-width: 1100px; }
h1 { font-size: 20px; margin: 4px 0 10px; }

/* ---------- top navigation ---------- */

.topnav {
  display: flex; align-items: center; gap: 2px;
  padding: 0 10px; background: var(--surface);
  border-bottom: 1px solid var(--border);
  overflow-x: auto; white-space: nowrap;
}
.topnav a { color: var(--text-2); padding: 13px 14px; font-weight: 500;
  border-bottom: 2px solid transparent; }
.topnav a:hover { color: var(--text); text-decoration: none; }
.topnav a.active { color: var(--text); border-bottom-color: var(--accent); }
.topnav .brand { display: flex; align-items: baseline; gap: 5px; padding-right: 16px;
  border-bottom: none; }

/* THE BAR HAS THREE PARTS: brand, .navlinks (the pages), .whoami (the personal
   actions). The links are in a box of their own rather than being flat siblings
   of the bar, and that is what makes the phone layout possible: .navlinks is
   the part that MAY wrap, and .whoami is its SIBLING, so nothing in the links
   can displace Sign out. It is the appliance's own structure and its own
   reasoning — see internal/web/templates/base.html and the nav comment in
   templates/base.html here.
   The 2px gap is the one .topnav used to apply between the links when they were
   its direct children; it is restated here so the desktop bar is unchanged. */
.topnav .navlinks { display: flex; align-items: center; flex-wrap: wrap; gap: 2px;
  min-width: 0; }

.topnav .whoami { margin-left: auto; display: flex; align-items: center; gap: 8px;
  padding-left: 12px; }
/* "My account" is a LINK styled as a button, sitting inside the actions cluster
   rather than among the tabs. Without this it would get half of each: .btn's
   four-sided border loses its bottom edge to `.topnav a`'s 2px transparent
   tab underline, which reads as a button with a missing side. The current page
   is marked with aria-current rather than .active, because out here the tab
   underline has nothing to underline. */
.topnav .whoami a.btn { border: 1px solid var(--border); color: var(--text); }
.topnav .whoami a.btn:hover { border-color: var(--muted); text-decoration: none; }
.topnav .whoami a.btn[aria-current="page"] { border-color: var(--accent); }

/* The wordmark: "Site" light, "Monitor" in the brand terracotta, the
   attribution small and muted. Identical treatment to the appliance UI. */
.bm { color: var(--brand-ink); font-weight: 600; letter-spacing: .01em; }
.bt { color: var(--brand); font-weight: 600; letter-spacing: .01em; }
.bp { color: var(--muted); font-size: 11px; }

.wordmark { margin-bottom: 18px; font-size: 20px; }
.wordmark .bp { display: block; font-size: 11px; letter-spacing: .04em; text-transform: uppercase; }

/* ---------- controls ---------- */

.btn {
  background: var(--surface-2); color: var(--text);
  border: 1px solid var(--border); border-radius: 8px;
  padding: 10px 14px; font: inherit; cursor: pointer; min-height: 40px;
}
.btn:hover { border-color: var(--muted); }
.btn.sm { padding: 6px 10px; min-height: 32px; font-size: 13px; }
.btn.primary { background: var(--brand); border-color: var(--brand); color: var(--brand-ink);
  font-weight: 600; }
.inlineform { display: inline; }

label { display: block; margin: 12px 0 4px; color: var(--text-2); font-size: 13px; }
input[type=email], input[type=password], input[type=text] {
  width: 100%; padding: 11px 12px; background: var(--surface-2); color: var(--text);
  border: 1px solid var(--border); border-radius: 8px; font: inherit;
}
input:focus { outline: 2px solid var(--accent); outline-offset: 1px; }

.signin { max-width: 380px; margin: 8vh auto 0; padding: 0 18px; }
.signin .btn { width: 100%; margin-top: 18px; }

/* ---------- tables ---------- */

/* .tablewrap is a wide table's own scroll container. Every table with more than
   about four columns is inside one, so that a table too wide for the screen
   scrolls SIDEWAYS INSIDE ITS OWN BOX instead of forcing the whole document
   wider than the viewport — which is what it was doing, and which clipped the
   page's own headings and paragraphs on the left once the document was scrolled
   right. It is the appliance's .tablewrap, named and behaving the same way.
   On a wide screen it never engages: an auto overflow with nothing overflowing
   shows no scrollbar and changes nothing. The rule that actually makes the
   table wider than its box, rather than squeezing six columns into 358px, is
   width: max-content in the handset block at the foot of this file. */
.tablewrap { overflow-x: auto; }

table.grid { border-collapse: collapse; width: 100%; font-size: 14px; }
table.grid th, table.grid td {
  text-align: left; padding: 9px 10px;
  border-bottom: 1px solid var(--grid); vertical-align: top;
}
table.grid th { color: var(--muted); font-weight: 500; font-size: 12px;
  text-transform: uppercase; letter-spacing: .04em; }

.dim { color: var(--muted); font-size: 12px; }
.ok { color: var(--good); }
.warn { color: var(--warning); }
.bad { color: var(--critical); }

.dot { display: inline-block; width: 8px; height: 8px; border-radius: 50%;
  margin-right: 6px; vertical-align: middle; }
.dot.up { background: var(--good); }
.dot.down { background: var(--muted); }

.chip { background: var(--surface-2); border: 1px solid var(--border);
  border-radius: 999px; padding: 3px 10px; font-size: 12px; color: var(--text-2); }

.note { color: var(--text-2); font-size: 13px; max-width: 70ch; }

.flash { background: var(--surface); border: 1px solid var(--border);
  border-left: 3px solid var(--good); border-radius: 6px;
  padding: 9px 12px; margin: 10px 0; font-size: 14px; }
.flash.error { border-left-color: var(--critical); }

/* A generated one-time password, shown once on the Users page. Monospaced and
 * large enough to be read off the screen and typed correctly by somebody
 * standing next to the administrator — which is the only delivery channel this
 * product has, so legibility here is a functional requirement and not a
 * flourish. user-select:all makes one click select the whole string. */
code.otp { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 18px; letter-spacing: 1px; background: var(--surface-2);
  border: 1px solid var(--border); border-radius: 4px; padding: 4px 8px;
  user-select: all; }

/* ---------- the reseller surface (/_v) ----------
 *
 * Shares this stylesheet rather than carrying its own, because it is the same
 * product's chrome and a second file would drift. --brand stays CHROME ONLY:
 * nothing below uses it to carry a value — an expired licence is .chip.bad and
 * a healthy one is plain, so a reader is never asked to distinguish "the brand"
 * from "a reading". */
.card {
  background: #202020; border: 1px solid #333; border-radius: 6px;
  padding: 16px 18px; margin: 0 0 16px;
}
.card h1 { margin: 0 0 6px; }
.card h2 { margin: 0 0 8px; font-size: 16px; }
h2 { font-size: 17px; margin: 24px 0 8px; }
.muted { color: #9a938c; }
.small { font-size: 13px; }
.mono { font-family: ui-monospace, Menlo, Consolas, monospace; font-size: 12.5px; }
.lab { display: block; font-weight: 600; margin: 0 0 3px; font-size: 14px; }
table.grid { border-collapse: collapse; width: 100%; font-size: 14px; margin: 0 0 16px; }
table.grid th, table.grid td {
  text-align: left; padding: 7px 10px; border-bottom: 1px solid #333; vertical-align: top;
}
table.grid th {
  color: #9a938c; font-weight: 600; font-size: 12px;
  text-transform: uppercase; letter-spacing: .05em;
}
.chip.bad { color: #d05a4a; border-color: #d05a4a; }
input[type=date], input[type=text], input[type=password] {
  padding: 8px 10px; background: #141414; color: #e8e4e0;
  border: 1px solid #3a3a3a; border-radius: 4px; font: inherit;
}

/* ---------- the inline refusal on the add-contact form ----------
 *
 * A validation refusal shown BESIDE the field that caused it rather than as a
 * flash at the top of the page, because the webhook refusals are two or three
 * sentences of instruction and the field they are about is most of a screen
 * further down. Bordered on the left in the critical colour like .flash.error,
 * so the two read as the same kind of thing — but wider than .note, because
 * these sentences are long and are shown verbatim. */
.addrerr {
  max-width: 70ch; font-size: 13px; color: var(--text);
  background: var(--surface); border: 1px solid var(--border);
  border-left: 3px solid var(--critical); border-radius: 6px;
  padding: 9px 12px; margin: 6px 0 0;
}

/* ---------- the public marketing landing page ----------
 *
 * Ported alongside the copy it styles. --brand IS CHROME ONLY here as
 * everywhere else: it carries the wordmark, the rule beside it and the bullet
 * glyphs, and it never encodes a value — there is no status, no badge and no
 * reading on this page for it to be confused with, and there must not be one
 * added. */
.landing { max-width: 76ch; }

.lhero { margin: 10px 0 30px; }
.lhero h1 { font-size: 30px; line-height: 1.2; margin: 14px 0 12px; max-width: 30ch; }

/* The wordmark on the front page: "Matrix" light, "Technosphere" in the brand
 * terracotta, then a short brand-coloured rule and the product name. Larger
 * than the nav's version because here it is the first thing on the page. */
.loginmark { display: flex; align-items: center; gap: 8px; margin: 0;
  font-size: 15px; letter-spacing: .02em; flex-wrap: wrap; }
.loginmark .rule { display: inline-block; width: 26px; height: 2px;
  background: var(--brand); opacity: .75; }
.loginmark .prod { color: var(--text-2); font-size: 13px; letter-spacing: .06em;
  text-transform: uppercase; }

.lead { color: var(--text-2); font-size: 16px; max-width: 68ch; margin: 0 0 14px; }
.lead.small { font-size: 14px; }
.help { color: var(--muted); font-size: 13px; max-width: 70ch; }

.lcta { display: flex; gap: 10px; flex-wrap: wrap; margin: 20px 0 0; }
.lcta .btn { text-decoration: none; display: inline-block; }
.lcta .btn:hover { text-decoration: none; }

/* The five silent failures. A brand-coloured marker and generous spacing,
 * because each item is a paragraph and a tight list of paragraphs is unread. */
.lsil { list-style: none; padding: 0; margin: 14px 0 28px; }
.lsil li {
  position: relative; padding: 0 0 0 20px; margin: 0 0 18px;
  color: var(--text-2); font-size: 14.5px; max-width: 70ch;
}
.lsil li::before {
  content: ""; position: absolute; left: 0; top: 8px;
  width: 7px; height: 7px; border-radius: 50%; background: var(--brand);
}
.lsil b { color: var(--text); }

.lcols { columns: 2; column-gap: 28px; padding-left: 18px; margin: 10px 0 28px;
  color: var(--text-2); font-size: 14px; }
.lcols li { margin: 0 0 7px; break-inside: avoid; }

.lfoot { margin: 34px 0 0; padding: 22px 0 0; border-top: 1px solid var(--border); }
.lfoot p { max-width: 70ch; }

@media (max-width: 620px) {
  .lhero h1 { font-size: 24px; }
  .lcols { columns: 1; }
}

/* ================================================================
   HANDSET  (max-width: 560px)
   ================================================================

   THIS BREAKPOINT IS THE APPLIANCE'S BREAKPOINT, deliberately, and not a
   second opinion about where a phone starts. internal/web/static/style.css
   carries a heavily commented (max-width: 560px) block; its reasoning for the
   number applies here unchanged: 560 sits above every portrait phone (320-430
   CSS px, 540 on the widest foldables) and below every tablet (768). A
   landscape phone is ~844px wide and deliberately does NOT land here — it has
   the width for the ordinary bar. Two surfaces of one product folding at two
   different widths is how they stop reading as one product.

   Before this block the narrowest query in this file was 620px and it covered
   two landing-page rules, so the SIGNED-IN portal — the part a paying customer
   uses — had no handset treatment at all. What the owner saw on a 400px screen
   was the whole document scrolled sideways: the wordmark read "nitor by Matrix
   Technosphere", the heading read "ppliances", the paragraphs began mid-word,
   and "Open dashboard" was off the right-hand edge.

   THE CAUSE WAS NOT THE NAV. It was the appliances table: six columns whose
   min-content width exceeded the viewport, which made the DOCUMENT that wide,
   which is why text was clipped on the LEFT as well. The fix is to make the
   tables stop setting the document's width — cards here, scroll containers
   elsewhere — and NOT overflow-x: hidden on body, which would hide the symptom
   by making the overflowing content unreachable instead of scrollable.

   This block is ADDITIVE: it widens no existing query and changes no rule
   outside itself. It is placed LAST because most of what it overrides has the
   same specificity, so source order is what decides.
   ================================================================ */
@media (max-width: 560px) {

  /* ---- nav: two rows instead of a sideways scroll ----

     The bar's three parts are brand, .navlinks and .whoami (see the note at
     .topnav). On a phone the row cannot hold them, and the old arrangement —
     every link a flat sibling, the bar overflow-x: auto, .whoami pushed right
     with margin-left: auto — is the exact arrangement that hid Sign out off
     the right-hand end of the appliance's nav. A scroll region is where the
     control you need goes to hide: there is no affordance saying it is there.

     So the BAR WRAPS and .navlinks takes the whole second row. Row 1 is then
     brand + the personal actions, which is the one arrangement that cannot
     push Sign out off-screen; row 2 is the links, packed by .navlinks's own
     flex-wrap.

     overflow-x goes back to visible BECAUSE the content now wraps instead of
     overflowing — an auto overflow here would be a scroll region with nothing
     to scroll, and it is the thing that caused the original bug.

     KNOWN WART, stated rather than hidden: `order: 2` moves .navlinks below
     .whoami visually but not in the DOM, so Tab goes brand -> links (row 2)
     -> My account / Sign out (row 1). Fixing it properly means emitting
     .whoami before .navlinks, which would need `order` on the desktop bar too
     — a change to the layout this block is forbidden to regress. CSS
     reordering is the only lever available here. The appliance's own block
     records the same wart for the same reason. */
  .topnav {
    flex-wrap: wrap;
    overflow-x: visible;
    padding: 0 8px;
    align-items: center;
  }
  .topnav .navlinks {
    order: 2;                  /* below the actions row - see the wart above */
    flex: 1 0 100%;            /* its own full-width row, so it has room to pack */
    gap: 0;
    border-top: 1px solid var(--grid);   /* chrome: separates the two rows */
  }
  /* Row 1 is brand + actions. The brand is the ONLY shrinkable thing on it,
     which is what makes the actions cluster un-displaceable: any width
     shortage is taken from the wordmark and never from Sign out. The shrink
     factor is deliberately huge rather than 1, because shrinkage is shared in
     proportion to factor x base size and 1 against 1 would have the controls
     absorb most of any shortage. */
  .topnav > .brand {
    flex-shrink: 100;
    min-width: 0;
    overflow: hidden;
    padding: 13px 6px 13px 0;
    font-size: 14px;
  }
  /* "by Matrix Technosphere" drops out: ~150px recovered, and what remains is
     the whole product name rather than a truncated wordmark — which is what
     the owner was looking at. It is still in the brand link's title attribute
     and on every page's <title>, and the landing page gives it in full.
     .attrib and not .bp, because the reseller nav puts a short SURFACE LABEL
     ("reseller") in the same slot and that one says which of three surfaces
     you are on — which is worth more than the 60px it costs. */
  .topnav .brand .bp.attrib { display: none; }
  /* SECOND LINE OF DEFENCE. The cluster keeps its place at the right-hand end,
     but if a narrower screen or a longer label ever exceeds the row anyway, it
     wraps its own children onto another line — the bar gets taller — instead
     of running off the edge. Shrinking here costs height, never
     reachability. */
  .topnav .whoami {
    padding-left: 0;
    gap: 6px;
    flex-wrap: wrap;
    justify-content: flex-end;
    flex-shrink: 1;
    min-width: 0;
  }
  /* The signed-in email is kept, not hidden: on a shared handset "which
     account is this" is worth a line. It is clamped instead, so the one thing
     that can take width from Sign out is the part of an address nobody reads. */
  .topnav .whoami .chip {
    max-width: 34vw;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  /* .btn.sm is 32px tall on purpose for dense table rows. On a touchscreen it
     has to meet the 44px floor this file holds everywhere else. */
  .topnav .whoami .btn.sm,
  .topnav .whoami a.btn {
    min-height: 44px;
    padding: 11px 12px;
  }
  /* Tighter sides only - 13px top and bottom keeps every tab at 44px
     (13 + 19 + 13 + the 2px transparent underline every .topnav a carries). */
  .topnav .navlinks a { padding: 13px 10px; }

  /* ---- the appliances table becomes a card per appliance ----

     This is the page's whole purpose and the one table that must NOT be a
     sideways scroll: "Open dashboard" is how a customer reaches their own
     appliance, and behind a swipe with no affordance it is unreachable in
     practice. So each row becomes a card with its status, its last check-in,
     its licence and a full-width button.

     The appliance's stylesheet chose scrolling for ITS tables and said why: a
     stacked table needs every cell to carry its column name, and those tables
     had no data-label attributes. This one was given them (see the note in
     templates/appliances.html), which is what makes the better form available
     here. The CSS does no guessing: a cell with data-label gets a label, a
     cell without one does not.

     The label is a BLOCK-FLOW inline-block and the cell stays display: block —
     it is not a flex or grid container, and that is on purpose. These cells
     contain mixed inline content and <br> (the cellular note, the version
     line); in a flex container every text node becomes its own flex item and a
     <br> becomes a blockified one, which pulls the cell apart. Normal inline
     flow handles them correctly. */
  table.grid.cards,
  table.grid.cards > tbody { display: block; width: 100%; }
  /* The header row is hidden rather than removed from the markup: it is what
     makes this a real table on every wider screen, and on a narrow one its
     words are on the cards as labels. */
  table.grid.cards > thead { display: none; }
  table.grid.cards > tbody > tr {
    display: block;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 10px 12px;
    margin: 0 0 12px;
  }
  table.grid.cards > tbody > tr > td {
    display: block;
    padding: 6px 0;
    border-bottom: 1px solid var(--grid);
    overflow-wrap: anywhere;   /* nothing in a card may widen the document */
  }
  table.grid.cards > tbody > tr > td:last-child { border-bottom: none; }
  /* The column name, in the same muted uppercase the <th> uses on a wide
     screen, so the card is recognisably the same table. A fixed width lines
     the values up down the card; a value that wraps continues at the left
     margin, which is the one cosmetic cost of staying in normal flow. */
  table.grid.cards td[data-label]::before {
    content: attr(data-label);
    display: inline-block;
    min-width: 11ch;
    margin-right: 8px;
    color: var(--muted);
    font-weight: 500;
    font-size: 11.5px;
    text-transform: uppercase;
    letter-spacing: .04em;
  }
  /* The appliance id is the card's heading. It needs no label: it is first and
     it is largest, which is what "Appliance" would have said. */
  table.grid.cards td.ttl {
    font-size: 16px;
    padding: 2px 0 8px;
  }
  /* The controls, at the foot of the card, full width and stacked. Full width
     rather than inline because this is the control the page exists for and a
     thumb should not have to find it; stacked because "Open dashboard" and
     "Remove" must not end up adjacent and the same size. The <br> between them
     is for the table form and is not needed once each is a block. */
  table.grid.cards td.act { padding: 8px 0 0; }
  table.grid.cards td.act br { display: none; }
  table.grid.cards td.act .inlineform { display: block; }
  table.grid.cards td.act .btn {
    display: block;
    width: 100%;
    min-height: 44px;
    padding: 13px 14px;
    margin: 8px 0 0;
    text-align: center;
  }

  /* ---- every other wide table: scroll sideways, do not fold ----

     Each is already inside .tablewrap (overflow-x: auto), but table
     { width: 100% } meant it never actually overflowed: it squeezed six or
     seven columns into ~350px and wrapped every cell to four lines instead,
     while its min-content width pushed the DOCUMENT wider than the viewport.
     width: max-content with min-width: 100% is the fix — a table wider than
     the screen now scrolls inside its own box, and a narrow one still fills
     it.

     Scrolling and not cards, for the reason the appliance's block gives: these
     tables have no data-label attributes, and stacking them in CSS alone would
     produce rows of unlabelled values, which is worse than scrolling. The
     appliances table is the exception because it was given the labels. */
  .tablewrap {
    -webkit-overflow-scrolling: touch;
    overscroll-behavior-x: contain;
  }
  .tablewrap > table {
    width: max-content;
    min-width: 100%;
  }
  /* The key/value tables that are NOT in a wrapper (My account, the release
     confirmation): two short columns that fit, but a 32-hex certificate serial
     or a long address would otherwise widen the document all by itself.
     THE VALUE BREAKS; THE LABEL DOES NOT, and that distinction is the whole
     point of this rule. It used to name `th` as well, and that was the bug the
     owner photographed: once a long unbreakable value had taken the width, the
     label column was free to shrink to nothing, and `overflow-wrap: anywhere`
     let it keep shrinking all the way down to one character per line — "Email"
     came down the page as E / ma / il. A <th> here is a short label by
     construction, so leaving it breakable bought nothing and cost that. It
     still wraps normally at spaces; it just cannot be guillotined mid-word. */
  main > table.grid td { overflow-wrap: anywhere; }
  /* The serial, readable but no longer 300px of unbreakable monospace. */
  code.otp { font-size: 15px; overflow-wrap: anywhere; }

  /* ---- page chrome and tap targets ----
     44px is the floor for everything touchable. 13px 14px is the padding this
     codebase standardises on to get there. */
  main { padding: 12px 12px 28px; }
  h1 { font-size: 19px; }
  .btn,
  .btn.sm {
    min-height: 44px;
    padding: 13px 14px;
  }
  .btn.sm { font-size: 13px; }
  input[type=email],
  input[type=password],
  input[type=text],
  input[type=date],
  select {
    min-height: 44px;
    padding: 13px 12px;
  }
  select { width: 100%; }
  .signin { margin-top: 5vh; padding: 0 14px; }
}
