:root{
  --void:#080A0F; --panel:#0C1119; --raised:#131A24; --slate:#455A64;
  --cyan:#00E5FF; --amber:#FF9100; --crimson:#FF2D46; --green:#3FD18A;
  --hi:#E7EDF2; --mid:#CDD6DC; --low:#8899A3; --dim:#607681; --hair:#1B2430;
  --inter:'Inter',-apple-system,'Segoe UI',sans-serif;
  --mono:'JetBrains Mono','SF Mono',Consolas,monospace;
}
/* THE FACES. Self-hosted: see src/fonts.js for what these files are, where they
   came from and under what licence (SIL OFL 1.1, text served at /fonts/OFL.txt and linked from every page's footer).
   The tokens above name 'Inter' and 'JetBrains Mono' with a system fallback
   stack, which is what renders for the moment before a face arrives (swap) and
   if one never does. A page in the fallback stack is a MISSING FILE and the fix
   is the file: do not widen the CSP to a font CDN (src/index.js says why). */
@font-face{font-family:'Inter';font-style:normal;font-weight:200 600;font-display:swap;
  src:url(/fonts/inter-latin.woff2?v=ec182189) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
@font-face{font-family:'JetBrains Mono';font-style:normal;font-weight:400 500;font-display:swap;
  src:url(/fonts/jetbrains-mono-latin.woff2?v=e66a93fa) format('woff2');unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}

*{box-sizing:border-box;margin:0;padding:0}

/* The 44px grid is the brand's background and the one thing that makes a bare
   page read as GNexusOS before a single component is on it. */
body{background:var(--void);color:var(--mid);font-family:var(--inter);font-size:15px;line-height:1.66;
  background-image:linear-gradient(rgba(255,255,255,.022) 1px,transparent 1px),
                   linear-gradient(90deg,rgba(255,255,255,.022) 1px,transparent 1px);
  background-size:44px 44px;-webkit-font-smoothing:antialiased;
  display:flex;flex-direction:column;min-height:100vh}
main{flex:1 0 auto;padding:36px 0 56px}
.wrap{max-width:1080px;margin:0 auto;padding:0 24px}

h1,h2,h3{color:var(--hi);font-weight:600;letter-spacing:-.018em}
h1{font-weight:200;font-size:clamp(27px,5vw,42px);letter-spacing:-.02em;margin-top:14px}
h2{font-size:22px}
h3{font-size:16.5px}
/* Prose is styled on the ELEMENT, not on a ".sub"/".lead" class: a class a
   later page would have to remember is a class that drifts, and the component
   set below is deliberately closed. */
main p{color:var(--low);max-width:62ch;margin-top:12px}
a{color:var(--mid);text-decoration:none;transition:color .18s ease}
a:hover{color:var(--hi)}

/* THE EYEBROW. "//" in cyan, the label in mono caps. Rendered by layout.js's
   page(), never hand-written on a page. */
/* --low, with .note and .table th: every one of --dim's uses in this sheet is
   11px text, and 11px --dim is below WCAG AA on both surfaces (see .note). The
   token itself is NOT changed -- :root is assets/site.css's own block, byte for
   byte, which spec A4 and test/css.test.js pin -- so --dim is now declared and
   unused here, which is the correct outcome of sharing a palette with a page
   that uses it at other sizes. */
.eyebrow{font-family:var(--mono);font-weight:500;font-size:11px;letter-spacing:.22em;text-transform:uppercase;color:var(--low)}
.eyebrow .n{color:var(--cyan)}

/* The hairline header. The lockup is the brand's image (src/brand.js), and the
   .lockup type rules below are for its ALT text: a blocked or failed image must
   still read as the brand, in the brand's mono, and not as an empty box. */
header{position:sticky;top:0;z-index:10;background:rgba(8,10,15,.82);backdrop-filter:blur(10px);border-bottom:1px solid var(--hair)}
/* padding-top/bottom and NOT the "padding:10px 0" shorthand: this element
   carries .wrap too, and the shorthand silently zeroed .wrap's 24px side
   padding, putting the lockup flush against the left edge of a phone. */
.nav{display:flex;align-items:center;justify-content:space-between;gap:14px;flex-wrap:wrap;min-height:60px;padding-top:10px;padding-bottom:10px}
.lockup{font-family:var(--mono);font-weight:500;font-size:14px;letter-spacing:.08em;color:var(--hi)}
/* block: an inline image sits on the text baseline and leaves a descender gap
   under it, which pushes the lockup off the header's centre line. */
.lockup img{display:block}
header nav,footer nav{display:flex;align-items:center;gap:16px;flex-wrap:wrap;
  font-family:var(--mono);font-size:12px;letter-spacing:.06em}
footer{border-top:1px solid var(--hair);padding:28px 0 44px}

/* --------------------------------------------------------------------------
   THE COMPONENT SET, AND IT IS CLOSED AT NINE: .panel, .field, .table, .note,
   .ok, .err, button.quiet, .eyebrow (above) and .cta (below), plus hairline
   borders and cyan as the single accent. A component nobody renders is a
   component that will drift, so a later task that needs a tenth adds it here
   AND to the list in test/css.test.js -- nothing here is built ahead of a page
   that uses it. (.raised was the one orphan and was removed for that reason.)
   -------------------------------------------------------------------------- */

/* They carry their own top margin because THERE IS NO INLINE STYLE ANYWHERE:
   "style-src 'self'" blocks a style attribute as surely as it blocks a <style>
   block, so spacing has to live in this file. */
/* overflow-x:auto is what lets a .table INSIDE a panel be wider than a phone:
   see the .table comment below. */
.panel{background:var(--panel);border:1px solid var(--hair);border-radius:3px;padding:24px;margin-top:28px;overflow-x:auto}

/* A <select> IS AN INPUT AND IS STYLED WITH ONE, not as a tenth component class:
   the set below is closed at nine and this is the same control in a different
   shape. The machine list's "move this licence to..." is the one place the portal
   has a choice to make (src/pages/devices.js), and without this rule it rendered
   in the user agent's own colours -- a white slab on a near-black panel, seen by
   eye at 380px and 1280px. color-scheme is what carries the dark surface into the
   OPEN dropdown, which the page's own CSS cannot reach. */
input,select{background:var(--panel);border:1px solid var(--hair);border-radius:3px;color:var(--hi);
  font-family:var(--inter);font-size:15px;padding:13px 16px;outline:none;transition:border-color .18s ease}
select{color-scheme:dark}
input:focus,select:focus{border-color:var(--cyan)}
.field{margin-top:18px}
.field label{display:block;font-size:13px;color:var(--low);margin-bottom:7px}
/* WIDTH 100%, NOT the marketing hero's min(340px,80vw). That page has one
   centred input; a portal form has four labelled fields and must be usable at
   380px wide. Do not reintroduce a fixed width here. */
.field input,.field select{width:100%}
/* A CHECKBOX IS NOT A TEXT FIELD. Without this the registration form's terms
   box took the rule above and rendered as a FULL-WIDTH WHITE SLAB on its own
   line, with the sentence it belongs to orphaned underneath -- seen by eye at
   1280px and 380px, not by any assertion. It is an ATTRIBUTE SELECTOR and not a
   tenth component class on purpose: the set is closed at nine, and this is a
   correction to .field, not a new thing for a page to render. accent-color is
   what makes the checked state the brand's cyan instead of the user agent's
   blue, which is the only colour on the page nothing else chooses. */
.field input[type="checkbox"]{width:auto;padding:0;margin:4px 0 0;flex:none;accent-color:var(--cyan)}
/* And the sentence BESIDE the box, not under it. .field label is display:block,
   so a consent sentence long enough to wrap -- which "I accept the Terms and
   the Privacy Policy." is at 380px -- put its second line hard against the left
   margin, below the box, reading as a separate paragraph. Two rows, so the
   wrapped text hangs under the text and not under the box.
   THE SENTENCE MUST BE ONE ELEMENT INSIDE THE LABEL, which is why the page wraps
   it in a <span>: a flex container makes each child a flex item, and with the
   bare text and two <a>s as children the sentence came out as five columns --
   "I accept the | Terms | and the | Privacy Policy | ." -- which is worse than
   what this rule was added to fix. Seen by eye at 380px.
   :has() is the scope: only a label that CONTAINS a checkbox becomes a row, and
   a browser without it falls back to the untidy wrap, not to that. */
.field label:has(input[type="checkbox"]){display:flex;gap:9px}

button{background:rgba(0,229,255,.10);border:1px solid var(--cyan);color:#EAF6FF;border-radius:3px;
  font-family:var(--mono);font-weight:500;font-size:13px;letter-spacing:.06em;padding:13px 22px;cursor:pointer;
  transition:background .18s ease}
button:hover{background:rgba(0,229,255,.18)}
/* A QUIET BORDER AND NO FILL, for a destructive action, so "remove this
   machine" is never the brightest thing on the page. Crimson arrives only on
   hover, once the pointer is already on it.

   --dim AND NOT --slate, AND THAT IS THE SAME ACCESSIBILITY FIX .note GOT, AT
   THE OTHER BAR. Measured from the sheet's own bytes: --slate #455A64 is
   2.61:1 on a panel, below the 3:1 WCAG asks of the boundary that identifies a
   CONTROL (1.4.11, non-text contrast). --dim #607681 is 3.97:1 on a panel and
   3.67:1 on --raised, so it clears it. This button has no fill, so the border
   IS the control: without it there is a word and nothing saying it can be
   pressed, and the word is --low, deliberately quiet.

   NOTE THE TWO DIFFERENT BARS, because --dim failing one and passing the other
   looks like a contradiction and is not: small TEXT wants 4.5:1, which is why
   .note, .table th and .eyebrow moved OFF --dim; a non-text BOUNDARY wants
   3:1, which --dim clears. test/css.test.js computes both from the sheet. */
button.quiet{background:none;border-color:var(--dim);color:var(--low)}
button.quiet:hover{background:none;border-color:var(--crimson);color:var(--mid)}

/* Hairline row separators and NO ZEBRA FILL: a striped table is a second
   surface colour the brand does not have. Ids and timestamps are mono, keyed
   off the ELEMENTS a page already uses for them (code, time) rather than a
   class each later page has to remember. */
/* A .table MUST LIVE INSIDE A .panel. The panel is the scroll container
   (overflow-x:auto above); the table is a real table (display:table) at
   width:100%. A .table OUTSIDE a .panel scrolls the DOCUMENT sideways at phone
   width, which is the bug this arrangement replaces: a four-column machine list
   is wider than 380px, the whole page scrolls, and the sticky header's
   right-hand nav goes off the screen with it -- seen by eye at 380px.
   The first attempt made the TABLE its own scroll container with display:block.
   That fixed the phone and broke the desktop: on a display:block table the
   width:100% belongs to the block box while the anonymous table inside stays
   width:auto and shrinks to its content, so at 1280px a two-column table ended
   at x=272 inside a 1131px box. display:table keeps width:100% meaning the
   table. word-break:break-all on code (below) is NOT what stops the overflow:
   the page still measured 405 > 380 with it present. */
.table{display:table;width:100%;border-collapse:collapse;margin-top:18px}
.table th,.table td{border-top:1px solid var(--hair);padding:11px 14px 11px 0;text-align:left;vertical-align:top;font-size:14px}
/* --low, for .note's reason: 11px column headings are text a customer reads to
   understand the table, and --dim does not pass AA at this size. */
.table th{font-family:var(--mono);font-weight:500;font-size:11px;letter-spacing:.12em;text-transform:uppercase;color:var(--low)}
.table td{color:var(--low)}
.table code,.table time{font-family:var(--mono);font-size:12.5px;color:var(--mid)}
/* A fingerprint is 64 characters with nowhere to break; without this it
   decides the width of the page at 380px. */
.table code{word-break:break-all}

/* A LINK STYLED AS A BUTTON, for "go to this page". A navigation link that
   POSTs a form is the wrong shape, and a GET form with a real button leaves a
   trailing "?" on the address. The values are index.html's .nav .cta rule, copied:
   mono 12px at .08em, 8px 16px, a 3px radius, and the border turning cyan on
   hover. The marketing rule is scoped to its nav and is not shared with this
   file, which is the same accepted cost as the tokens above.
   inline-block so the padding is a box and not a smear across the line.

   THE BORDER IS --dim AND index.html's IS --slate, AND THAT IS THE ONE VALUE
   THAT IS NO LONGER A COPY. Same reason as button.quiet above: --slate is
   2.61:1 on a panel, below the 3:1 a control's boundary needs, and this control
   has no fill either -- "Pair a machine" and "Download for macOS" are a word
   and a box, and the box is the box. Fixing button.quiet and leaving this is
   the defence-in-two-places-out-of-three shape this branch has paid for three
   times. index.html is the published contract and an operator review gate
   (A18), so it is NOT edited here; the divergence is open-consequence 75. */
.cta{display:inline-block;font-family:var(--mono);font-size:12px;letter-spacing:.08em;color:var(--hi);
  border:1px solid var(--dim);padding:8px 16px;border-radius:3px;transition:border-color .18s ease}
.cta:hover{border-color:var(--cyan)}

/* The one-line explanation under a form.

   --low AND NOT --dim, AND THAT IS AN ACCESSIBILITY FIX AND NOT A TASTE ONE.
   Measured in a browser from the computed values: --dim #607681 at 11px is
   4.15:1 on --void and 3.97:1 on --panel, and WCAG AA wants 4.5:1 for text under
   18.66px. --low #8899A3 is 6.72:1 and 6.43:1.

   WHAT MADE IT IMPORTANT RATHER THAN COSMETIC IS WHAT A .note CARRIES. This is
   where the portal puts the ANTI-PHISHING WARNINGS -- "IF SOMEBODY ELSE SENT YOU
   THIS CODE, THIS IS THEIR MACHINE: DO NOT PAIR IT. IT WOULD TAKE YOUR LICENCE'S
   ONE ACTIVATION" and "NOBODY SHOULD EVER SEND YOU A PAIRING CODE" -- on the one
   screen whose brightest element is the cyan "Yes, pair it" button, and whose
   file header argues for three pages that the human reading the description is
   the entire defence against device-code phishing. The visual hierarchy was the
   inverse of the security argument.

   IT IS STILL QUIETER THAN BODY TEXT: 11px mono, uppercase, letter-spaced,
   against body copy's 15px Inter. The quietness was never the colour's job
   alone. */
.note{font-family:var(--mono);font-size:11px;letter-spacing:.06em;color:var(--low);margin-top:14px}
.ok{color:var(--green)}
.err{color:var(--crimson)}
