/*
 * GALIL website styling.
 *
 * The palette and geometry are lifted from the C++ menu - src/render/ui.h and
 * src/render/ui_widgets.cpp - so the site and the overlay read as one product.
 * See docs/auth-platform/design-system.md; if a value changes in ui.h, change
 * it here.
 *
 * TYPE: two voices. The monospace face is the DISPLAY voice - wordmark,
 * eyebrows, labels, counts, identifiers - because this product's entire
 * vernacular is offsets, hardware ids and build strings. The UI sans is for
 * prose only. That inversion is the page's personality; it is not decoration.
 *
 * STRUCTURE: everything is a panel with a chrome strip, the same component the
 * overlay draws. The site's design system is the product's design system.
 *
 * One hand-written stylesheet, no framework, no external requests at all -
 * which is what lets the CSP run with nothing relaxed. No inline style
 * attributes exist in the views either: `style-src 'self'` without
 * 'unsafe-inline' makes the browser drop them silently.
 */

:root {
  /* Palette - ui.h */
  --chrome: #08080c;   /* chrome_bg()        8,  8, 12 */
  --body:   #0c0b10;   /* settings_bg()     12, 11, 16 */
  --card:   #0e0e12;   /* card_bg()         14, 14, 18 */
  --input:  #16161c;   /* combo_box_u32()   22, 22, 28 */
  --track:  #26262c;   /* slider_track_u32()38, 38, 44 */
  --border: #3a3a42;   /* matcha_input_text border      */
  --accent: #b861ff;   /* g_accent      0.72,0.38,1.00 */
  --text:   #ebebeb;   /* text_main()           0.92   */
  --muted:  #808085;   /* text_muted()  0.50,0.50,0.52 */

  /* Semantic - login_ui.cpp / HUD.cpp */
  --ok:     #78db8c;
  --warn:   #e6c86e;
  --danger: #f06e78;

  /* Derived. --card and --body differ by two points per channel, so a fill
     alone is invisible; the edge does the separating, as it does in the menu. */
  --edge:       rgba(58, 58, 66, .55);
  --edge-lit:   rgba(184, 97, 255, .30);
  --accent-dim: rgba(184, 97, 255, .12);
  --accent-mid: rgba(184, 97, 255, .20);

  /* Geometry - ui.h constants */
  --r-card: 10px;      /* g_card_rounding   */
  --r-input: 8px;      /* matcha_input_text */
  --r-pill: 14px;      /* main_tab_button   */
  --h-control: 38px;
  --pad-body: 20px;    /* g_body_pad_x      */
  --gap-card: 12px;    /* g_card_gap        */
  --h-header: 48px;    /* draw_header       */
  --inset: 20px;       /* g_chrome_text_inset_x */

  /* Type */
  --sans: "Segoe UI", system-ui, -apple-system, sans-serif;
  --mono: ui-monospace, "Cascadia Mono", Consolas, "SF Mono", monospace;

  color-scheme: dark;
}

/* The menu has no light mode; adding one here would break the visual link. */

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

/*
 * Footer placement. Without this the footer sits directly under the content on
 * a short page, leaving a slab of background beneath it that reads as a bug.
 */
html { height: 100%; }
body {
  margin: 0;
  min-height: 100%;
  display: flex;
  flex-direction: column;
  background: var(--body);
  color: var(--text);
  font: 15px/1.6 var(--sans);
  -webkit-font-smoothing: antialiased;
}
main { flex: 1 0 auto; }
footer { margin-top: auto; }

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

/* Always visible. Never outline:none. */
:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: 4px;
}

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

/* ==========================================================================
   Type
   ========================================================================== */
h1, h2, h3 { margin: 0; font-weight: 600; }
h1 { font-size: 28px; letter-spacing: -.4px; }
h2 { font-size: 17px; letter-spacing: -.1px; }

/* One rhythm everywhere. A trailing paragraph never adds space inside a
   panel, which is what made card padding look uneven. */
p { margin: 0 0 12px; }
p:last-child { margin-bottom: 0; }

/* A measure. Prose that runs the full width of a 960px panel is unreadable
   and is most of why the text read as "all over the place". */
.band-head p, .fact p, .step p, .panel-body p, .sub { max-width: 66ch; }

.sub { color: var(--muted); margin: 6px 0 24px; }
.muted, .dim { color: var(--muted); }
.small { font-size: 13px; }
.mono { font-family: var(--mono); font-size: 13px; }

/*
 * The eyebrow. Mono, uppercase, widely tracked - the label style the overlay
 * uses for every section it draws.
 */
.eyebrow {
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 1.6px;
  text-transform: uppercase;
  color: var(--muted);
}
.eyebrow .lit { color: var(--accent); }

/* ==========================================================================
   Header / footer chrome
   ========================================================================== */
.chrome {
  background: var(--chrome);
  border-bottom: 1px solid var(--edge);
  height: var(--h-header);
  display: flex;
  align-items: center;
  padding: 0 var(--inset);
  gap: 8px;
  position: sticky;
  top: 0;
  z-index: 10;
}

/* draw_header()'s rhythm: accent wordmark, muted bullet, plain page name. */
.brand {
  font-family: var(--mono);
  color: var(--accent);
  font-weight: 700;
  font-size: 14px;
  letter-spacing: 1.5px;
}
.brand:hover { text-decoration: none; }
.brand-sep { color: var(--track); font-size: 13px; }
.brand-page { font-family: var(--mono); color: var(--muted); font-size: 12px; letter-spacing: .6px; }

.chrome nav { margin-left: auto; display: flex; align-items: center; gap: 14px; min-width: 0; }
/*
 * `:not(.btn)`, because `.chrome nav a` outranks `.btn` on specificity and
 * would otherwise strip a button in the bar of its padding and leave the text
 * touching its own border.
 */
.chrome nav a:not(.btn) {
  color: var(--muted);
  font-size: 13px;
  padding: 4px 0;
  position: relative;
  white-space: nowrap;
}
.chrome nav a:not(.btn):hover,
.chrome nav a.active { color: var(--text); text-decoration: none; }

/* The current page. main_tab_button's active state, flattened to an underline
   because a pill in a 48px bar reads as a button you can press. */
.chrome nav a.on { color: #fff; }
.chrome nav a.on::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: -2px;
  height: 2px;
  background: var(--accent);
  border-radius: 1px;
}

.nav-sep { width: 1px; height: 18px; background: var(--edge); flex: none; }

/* On a phone the nav scrolls sideways rather than wrapping the bar onto a
   second row. No hamburger, no drawer, no script. */
@media (max-width: 720px) {
  .chrome { padding: 0 12px; gap: 6px; }
  .chrome .brand-sep, .chrome .brand-page { display: none; }
  .chrome nav { gap: 12px; overflow-x: auto; scrollbar-width: none; }
  .chrome nav::-webkit-scrollbar { display: none; }
}

footer {
  background: var(--chrome);
  border-top: 1px solid var(--edge);
  padding: 16px var(--inset);
  display: flex;
  align-items: center;
  gap: 10px;
  color: var(--muted);
  font-family: var(--mono);
  font-size: 12px;
}
.dot { width: 6px; height: 6px; border-radius: 50%; background: var(--accent); flex: none; }
footer .right { margin-left: auto; }
footer .build { color: var(--accent); }

/* ==========================================================================
   Layout
   ========================================================================== */
main { max-width: 960px; margin: 0 auto; padding: 32px var(--pad-body) 64px; width: 100%; }
main.wide { max-width: 1080px; }
main.narrow { max-width: 420px; }
.minimal main { margin-top: 12vh; }

.page-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 16px;
  margin-bottom: 20px;
}
.page-head .sub { margin-bottom: 0; }

.grid { display: grid; grid-template-columns: 1fr 1fr; gap: var(--gap-card); }
.grid .full { grid-column: 1 / -1; }
@media (max-width: 760px) { .grid { grid-template-columns: 1fr; } }

.stack > * + * { margin-top: 10px; }

/* ==========================================================================
   Panels
   ========================================================================== */
.card {
  background: var(--card);
  border: 1px solid var(--edge);
  border-radius: var(--r-card);
  padding: 16px;
  margin-bottom: var(--gap-card);
}
.card-flush { padding: 8px 10px; }
.card-title { font-size: 16px; font-weight: 600; margin: 0; }

.card-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 14px;
}

/* The overlay's card_separator(). */
.sep { height: 1px; background: var(--track); border: 0; margin: 16px 0; }

/*
 * A panel that announces itself the way the overlay's sections do: a mono
 * label strip above the content, with the accent dot.
 */
.panel {
  background: var(--card);
  border: 1px solid var(--edge);
  border-radius: var(--r-card);
  overflow: hidden;
}
.panel-strip {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 10px 16px;
  background: var(--chrome);
  border-bottom: 1px solid var(--edge);
}
.panel-strip .dot { width: 5px; height: 5px; }
.panel-body { padding: 18px 16px; }
.panel-body > p:first-child { margin-top: 0; }
.panel-body > p:last-child { margin-bottom: 0; }

/* ==========================================================================
   Rows, pills, meters
   ========================================================================== */
.row { display: flex; justify-content: space-between; align-items: baseline; gap: 16px; padding: 4px 0; }
.row dt, .row .label { color: var(--muted); font-size: 13px; }
.row dd, .row .value { margin: 0; color: var(--text); text-align: right; }
.value.mono, .rows dd.mono { font-family: var(--mono); font-size: 13px; }
.value.warn { color: var(--warn); }
.value.danger { color: var(--danger); }
.value.ok { color: var(--ok); }
.rows { margin: 0; }
.rows .row { padding: 6px 0; }
.rows dt { color: var(--muted); font-size: 13px; }
.rows dd { margin: 0; text-align: right; }

.pill {
  display: inline-block;
  padding: 3px 10px;
  border-radius: var(--r-pill);
  font-family: var(--mono);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: .4px;
  white-space: nowrap;
}
.pill-pro    { background: var(--accent-dim); color: var(--accent); }
.pill-basic  { background: var(--track);      color: var(--muted); }
.pill-ok     { background: rgba(120, 219, 140, .14); color: var(--ok); }
.pill-warn   { background: rgba(230, 200, 110, .14); color: var(--warn); }
.pill-danger { background: rgba(240, 110, 120, .14); color: var(--danger); }

.meter-head {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 12px; margin-bottom: 8px;
}
.meter-title { font-size: 13px; color: var(--muted); }
.meter-value { font-family: var(--mono); font-size: 15px; font-weight: 600; }
.meter-value.warn { color: var(--warn); }
.meter-value.danger { color: var(--danger); }
.meter-foot { font-family: var(--mono); font-size: 11px; margin: 8px 0 0; }
.warnish { color: var(--warn); }

/* A real <progress>: the value is an attribute, so it survives the CSP and
   announces itself to a screen reader without ARIA gymnastics. */
progress.meter {
  -webkit-appearance: none;
  appearance: none;
  display: block;
  width: 100%;
  height: 6px;
  border: 0;
  border-radius: 3px;
  background: var(--track);
  overflow: hidden;
}
progress.meter::-webkit-progress-bar { background: var(--track); border-radius: 3px; }
progress.meter::-webkit-progress-value { background: var(--accent); border-radius: 3px; }
progress.meter::-moz-progress-bar { background: var(--accent); border-radius: 3px; }
progress.meter-warn::-webkit-progress-value { background: var(--warn); }
progress.meter-warn::-moz-progress-bar { background: var(--warn); }
progress.meter-dim::-webkit-progress-value { background: var(--border); }
progress.meter-dim::-moz-progress-bar { background: var(--border); }

/* ==========================================================================
   Forms
   ========================================================================== */
label { display: block; color: var(--muted); font-size: 13px; margin: 14px 0 6px; }

/*
 * Matches by EXCLUSION, not by listing types. `<input name="username">` has no
 * type attribute - it defaults to text, but `input[type="text"]` does not match
 * it, so the licence and username fields were rendering as unstyled browser
 * defaults next to a correctly styled password field.
 */
input:not([type="checkbox"]):not([type="radio"]):not([type="hidden"]):not([type="submit"]):not([type="button"]):not([type="file"]),
select, textarea {
  width: 100%;
  height: var(--h-control);
  padding: 0 12px;
  background: var(--input);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: var(--r-input);
  font: inherit;
}
input, select, textarea { transition: border-color .12s ease, box-shadow .12s ease; }
textarea { height: auto; padding: 10px 12px; }
input:focus, select:focus, textarea:focus {
  border-color: var(--accent);
  outline: none;
  box-shadow: 0 0 0 3px var(--accent-dim);
}
input::placeholder { color: #55555c; }
input.mono, #license, #code { font-family: var(--mono); letter-spacing: .5px; }

.form-narrow { max-width: 380px; }
.field-row { display: flex; gap: 10px; align-items: flex-end; flex-wrap: wrap; }
.field-row > .grow { flex: 1; min-width: 160px; }
.actions-row { display: flex; gap: 10px; flex-wrap: wrap; }

/* --------------------------------------------------------------------------
   Native control normalisation
   --------------------------------------------------------------------------
   Everything a browser draws for itself, drawn by us instead. The chevron is
   an inline SVG data URI, which the CSP permits because img-src allows data:.
   -------------------------------------------------------------------------- */
select {
  -webkit-appearance: none;
  -moz-appearance: none;
  appearance: none;
  padding-right: 34px;
  cursor: pointer;
  background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5L6 6.5L11 1.5' fill='none' stroke='%23808085' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 12px center;
  background-size: 11px 8px;
}
select:hover { border-color: var(--border); }
/* The open list is drawn by the OS; these are the only two properties it honours. */
select option { background: var(--input); color: var(--text); }

/* Spinners are a worse control than typing the number. */
input[type="number"] { -moz-appearance: textfield; appearance: textfield; }
input[type="number"]::-webkit-outer-spin-button,
input[type="number"]::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }

input[type="checkbox"], input[type="radio"] { accent-color: var(--accent); }

textarea { resize: vertical; min-height: 88px; }

/* Chrome paints autofilled fields a hard blue-white. The inset shadow is the
   only way to override it; the long transition stops the flash on load. */
input:-webkit-autofill,
input:-webkit-autofill:hover,
input:-webkit-autofill:focus {
  -webkit-text-fill-color: var(--text);
  -webkit-box-shadow: 0 0 0 1000px var(--input) inset;
  box-shadow: 0 0 0 1000px var(--input) inset;
  caret-color: var(--accent);
  transition: background-color 9999s ease-out;
}

input, textarea, select { caret-color: var(--accent); }

/* Keyboard focus stays obvious even though :focus removes the outline. */
input:focus-visible, select:focus-visible, textarea:focus-visible {
  box-shadow: 0 0 0 3px var(--accent-mid);
}

::selection { background: rgba(184, 97, 255, .32); color: #fff; }

/* Scrollbars. The default light-grey Windows bar on a near-black page is the
   single most obvious "unstyled web page" tell. */
* { scrollbar-width: thin; scrollbar-color: var(--track) transparent; }
::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb {
  background: var(--track);
  border-radius: 6px;
  border: 2px solid var(--body);
}
::-webkit-scrollbar-thumb:hover { background: var(--border); }
::-webkit-scrollbar-corner { background: transparent; }

/* ==========================================================================
   Buttons
   ========================================================================== */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: var(--h-control);
  padding: 0 18px;
  border: 1px solid var(--edge);
  border-radius: var(--r-input);
  font: inherit;
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
  background: rgba(255, 255, 255, .04);
  color: var(--text);
  transition: background .12s ease, border-color .12s ease;
  white-space: nowrap;
}
.btn:hover { background: rgba(255, 255, 255, .08); border-color: var(--border); text-decoration: none; }
.btn-block { width: 100%; }

/* login_ui.cpp primary: accent at .82 rest, .92 hover, 1.0 active */
.btn-primary {
  background: rgba(184, 97, 255, .82);
  border-color: transparent;
  color: #14061f;
}
.btn-primary:hover { background: rgba(184, 97, 255, .92); border-color: transparent; }
.btn-primary:active { background: rgb(184, 97, 255); }

.btn-danger { background: rgba(240, 110, 120, .14); border-color: rgba(240,110,120,.3); color: var(--danger); }
.btn-danger:hover { background: rgba(240, 110, 120, .24); }

.btn:disabled, .btn[aria-disabled="true"] {
  background: rgba(255, 255, 255, .03);
  border-color: var(--edge);
  color: #5c5c63;
  cursor: not-allowed;
}
.btn-sm { height: 28px; padding: 0 12px; font-size: 13px; }

/* ==========================================================================
   Notices
   ========================================================================== */
.notice {
  border-radius: var(--r-input);
  border: 1px solid transparent;
  padding: 11px 14px;
  margin: 0 0 16px;
  font-size: 14px;
}
.notice-error { background: rgba(240, 110, 120, .10); border-color: rgba(240,110,120,.3); color: var(--danger); }
.notice-ok    { background: rgba(120, 219, 140, .10); border-color: rgba(120,219,140,.3); color: var(--ok); }
.notice-info  { background: rgba(255, 255, 255, .04); border-color: var(--edge); color: var(--muted); }

/* ==========================================================================
   Tables
   ========================================================================== */
table { width: 100%; border-collapse: collapse; font-size: 14px; }
th {
  text-align: left;
  font-family: var(--mono);
  color: var(--muted);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: .8px;
  text-transform: uppercase;
  padding: 10px 10px;
  border-bottom: 1px solid var(--track);
}
td { padding: 11px 10px; border-bottom: 1px solid rgba(38, 38, 44, .5); }
tr:last-child td { border-bottom: 0; }
.table-wrap { overflow-x: auto; }
tr.is-current td { background: rgba(184, 97, 255, .05); }

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

/* ==========================================================================
   Tabs
   ========================================================================== */
.tabs { display: flex; gap: 6px; margin-bottom: 20px; flex-wrap: wrap; }
.tabs a {
  padding: 7px 14px;
  border-radius: var(--r-pill);
  color: var(--muted);
  font-size: 14px;
}
.tabs a:hover { background: rgba(255, 255, 255, .05); color: var(--text); text-decoration: none; }
.tabs a.active { background: rgba(255, 255, 255, .08); color: #fff; }

/* ==========================================================================
   Landing page
   ========================================================================== */
.lede {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 420px;
  gap: 40px;
  align-items: start;
  padding: 48px 0 64px;
}
@media (max-width: 900px) {
  .lede { grid-template-columns: 1fr; gap: 32px; padding: 24px 0 40px; }
}

.lede-word {
  font-family: var(--mono);
  font-size: clamp(52px, 9vw, 76px);
  font-weight: 700;
  letter-spacing: -2px;
  line-height: 1;
  margin: 14px 0 0;
  color: var(--text);
}
.lede-word .tail { color: var(--accent); }
.lede-copy { color: var(--muted); font-size: 17px; max-width: 44ch; margin: 16px 0 0; }
.lede .actions { display: flex; gap: 10px; flex-wrap: wrap; margin-top: 26px; }

/* The status rail: the product's own register, stated as fact. */
.rail {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 22px;
  margin-top: 30px;
  padding-top: 20px;
  border-top: 1px solid var(--edge);
  font-family: var(--mono);
  font-size: 12px;
  color: var(--muted);
}
.rail b { color: var(--text); font-weight: 600; }

/*
 * The client, in the hero.
 *
 * A capture rather than a drawing: it is the actual product, and the actual
 * product is the strongest thing this page can show. The PNG carries a real
 * alpha channel, so `drop-shadow` follows the panel's rounded silhouette -
 * `box-shadow` would trace the element box and leak square corners.
 *
 * It sits to the RIGHT of the wordmark and drops below the copy, so the eye
 * lands on the headline first and the menu second.
 */
.mock-shot {
  display: block;
  width: 100%;
  height: auto;
  margin-top: 54px;

  /* Depth first, then the accent bloom. Two shadows rather than one: a single
     large accent shadow reads as a smudge, a tight dark one under a wide
     coloured one reads as an object that is lit. */
  filter:
    drop-shadow(0 26px 44px rgba(0, 0, 0, .85))
    drop-shadow(0 0 46px rgba(184, 97, 255, .34));

  /* Tilted back, not spun: enough to read as an object in space, little
     enough that every label stays legible. */
  transform: perspective(1600px) rotateX(4deg) rotateY(-11deg) rotate(.4deg);
  transform-origin: 50% 40%;
  animation: mock-in .55s ease-out both;
}

@keyframes mock-in {
  from {
    opacity: 0;
    transform: perspective(1600px) rotateX(7deg) rotateY(-15deg) translateY(14px);
  }
  to {
    opacity: 1;
    transform: perspective(1600px) rotateX(4deg) rotateY(-11deg) rotate(.4deg);
  }
}

/* Flat and square-on once the hero stacks: a tilt only reads as depth when
   there is something beside it to be tilted away from. */
@media (max-width: 900px) {
  .mock-shot {
    margin-top: 0;
    transform: none;
    animation: none;
    filter: drop-shadow(0 18px 34px rgba(0, 0, 0, .8));
  }
}

/* ---- sections ---- */
.band { padding: 52px 0; border-top: 1px solid var(--edge); }
.band-head { margin-bottom: 24px; }
.band-head h2 { font-size: 22px; letter-spacing: -.3px; margin-top: 8px; }
.band-head p { color: var(--muted); margin: 8px 0 0; max-width: 60ch; }

.split { display: grid; grid-template-columns: 1fr 1fr; gap: var(--gap-card); }
@media (max-width: 760px) { .split { grid-template-columns: 1fr; } }

/* Rank comparison. The count is the headline: it is the real mechanism. */
.rank-panel .count {
  font-family: var(--mono);
  font-size: 40px;
  font-weight: 700;
  letter-spacing: -1.5px;
  line-height: 1;
}
.rank-panel .count small { font-size: 13px; font-weight: 400; color: var(--muted); letter-spacing: 0; }
.rank-panel .groups {
  font-family: var(--mono); font-size: 11px; color: var(--muted);
  margin-top: 12px; line-height: 1.9; overflow-wrap: anywhere;
}
.rank-panel .groups span { color: var(--text); }
.rank-panel.lit { border-color: var(--edge-lit); }

/* Steps. Numbered because this genuinely is a sequence. */
.steps { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--gap-card); counter-reset: step; }
@media (max-width: 760px) { .steps { grid-template-columns: 1fr; } }
.step { border-top: 2px solid var(--track); padding-top: 14px; }
.step:first-child { border-top-color: var(--accent); }
.step .n { font-family: var(--mono); font-size: 11px; color: var(--accent); letter-spacing: 1.2px; }
.step h3 { font-size: 15px; margin: 8px 0 6px; }
.step p { color: var(--muted); font-size: 14px; margin: 0; }

/* Facts: short, checkable claims about how access is enforced. */
.facts { display: grid; grid-template-columns: 1fr 1fr; gap: 2px; background: var(--edge); border: 1px solid var(--edge); border-radius: var(--r-card); overflow: hidden; }
@media (max-width: 760px) { .facts { grid-template-columns: 1fr; } }
.fact { background: var(--card); padding: 18px 20px; }
.fact h3 { font-size: 14px; margin-bottom: 6px; }
.fact p { color: var(--muted); font-size: 13.5px; margin: 0; }

.cta {
  display: flex; align-items: center; justify-content: space-between;
  gap: 20px; flex-wrap: wrap;
  border: 1px solid var(--edge-lit);
  border-radius: var(--r-card);
  background: linear-gradient(180deg, var(--accent-dim), transparent 70%), var(--card);
  padding: 28px;
  margin-top: 52px;
}
.cta h2 { font-size: 20px; letter-spacing: -.2px; }
.cta p { color: var(--muted); margin: 6px 0 0; }

/* ==========================================================================
   Pricing
   ========================================================================== */
.tier { display: flex; flex-direction: column; }
.tier ul { flex: 1; }
.tier .btn { align-self: flex-start; }
.tier.featured { border-color: var(--edge-lit); }
/* The price is the loudest thing in the card, in the mono display voice. */
.tier .price { font-family: var(--mono); font-size: 34px; font-weight: 700; letter-spacing: -1px; margin: 6px 0 2px; }
.tier .price-alt { font-family: var(--mono); font-size: 12px; color: var(--muted); margin: 6px 0 0; }
.tier .price small { font-size: 13px; color: var(--muted); font-weight: 400; letter-spacing: 0; }
.tier ul { list-style: none; padding: 0; margin: 14px 0 0; }
.tier li { padding: 6px 0 6px 20px; color: var(--muted); font-size: 14px; position: relative; }
.tier li::before {
  content: ""; position: absolute; left: 4px; top: 13px;
  width: 5px; height: 5px; border-radius: 50%; background: var(--accent);
}

/* ==========================================================================
   Dashboard
   ========================================================================== */
.acct-hero {
  background:
    radial-gradient(120% 140% at 0% 0%, var(--accent-dim), transparent 62%),
    var(--card);
  border: 1px solid var(--edge-lit);
  border-radius: var(--r-card);
  padding: 22px;
  margin-bottom: 18px;
}
.acct-head { display: flex; align-items: center; gap: 16px; }

/* A letter, not an upload: no image host, no img-src to widen, nothing
   user-supplied being rendered. */
.monogram {
  flex: 0 0 auto;
  width: 54px; height: 54px;
  display: grid; place-items: center;
  border-radius: 50%;
  background: var(--accent-dim);
  border: 1px solid var(--edge-lit);
  color: var(--accent);
  font-family: var(--mono);
  font-size: 22px; font-weight: 700;
}
.identity { min-width: 0; }
.identity-name { font-size: 27px; font-weight: 600; margin: 0; letter-spacing: -.4px; overflow-wrap: anywhere; }
.identity-meta { margin: 7px 0 0; display: flex; align-items: center; gap: 10px; flex-wrap: wrap; font-size: 13px; }
.acct-rank { margin-left: auto; }
.rank-badge {
  display: inline-block;
  padding: 7px 18px;
  border-radius: var(--r-pill);
  font-family: var(--mono);
  font-size: 13px; font-weight: 700; letter-spacing: .8px;
  white-space: nowrap;
}
.rank-pro { background: var(--accent-dim); border: 1px solid var(--edge-lit); color: var(--accent); }
.rank-basic { background: var(--track); border: 1px solid var(--border); color: var(--muted); }
.acct-meter { margin-top: 22px; }

.tiles { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--gap-card); margin-bottom: 18px; }
@media (max-width: 760px) { .tiles { grid-template-columns: 1fr; } }
.tile {
  display: flex; flex-direction: column; gap: 5px;
  background: var(--card);
  border: 1px solid var(--edge);
  border-radius: var(--r-card);
  padding: 16px 18px;
  transition: border-color .12s ease;
}
.tile-label { font-family: var(--mono); font-size: 10px; color: var(--muted); text-transform: uppercase; letter-spacing: 1.2px; }
.tile-value { font-size: 21px; font-weight: 600; overflow-wrap: anywhere; letter-spacing: -.3px; }
.tile-value.mono { font-family: var(--mono); font-size: 19px; }
.tile-note { font-family: var(--mono); font-size: 11px; color: var(--muted); overflow-wrap: anywhere; }
a.tile-link { color: inherit; }
a.tile-link:hover { border-color: var(--edge-lit); text-decoration: none; }
a.tile-link:hover .tile-note { color: var(--accent); }

/* ==========================================================================
   Utilities
   ==========================================================================
   These exist because the CSP forbids inline style attributes.
   ========================================================================== */
.right { text-align: right; }
.inline { display: inline; }
.code {
  background: var(--input);
  border: 1px solid var(--border);
  border-radius: var(--r-input);
  padding: 12px 14px;
  font-family: var(--mono);
  font-size: 13px;
  word-break: break-all;
  user-select: all;
}
.mt-4  { margin-top: 4px; }
.mt-6  { margin-top: 6px; }
.mt-8  { margin-top: 8px; }
.mt-10 { margin-top: 10px; }
.mt-12 { margin-top: 12px; }
.mt-16 { margin-top: 16px; }

/* ==========================================================================
   Sections
   ==========================================================================
   The overlay labels a group of cards with a mono title and a rule. Same idea
   here: hierarchy from a label and a hairline rather than from bigger cards.
   ========================================================================== */
.section-head { display: flex; align-items: center; gap: 12px; margin: 26px 0 12px; }
.section-head:first-child { margin-top: 0; }
.section-head hr { flex: 1; height: 1px; border: 0; background: var(--edge); margin: 0; }

/* ==========================================================================
   Checkout
   ========================================================================== */
.plan-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--gap-card); }
.coin-row  { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--gap-card); }
@media (max-width: 760px) {
  .plan-grid, .coin-row { grid-template-columns: 1fr; }
}

/* A choice is a card you press. It is a link, so it works with the keyboard
   and the middle mouse button for free. */
.choice {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 16px;
  background: var(--card);
  border: 1px solid var(--edge);
  border-radius: var(--r-card);
  color: inherit;
  transition: border-color .12s ease, background .12s ease;
}
.choice:hover { border-color: var(--edge-lit); background: #101016; text-decoration: none; }
.choice-lit { border-color: var(--edge-lit); }
.choice-name { font-size: 15px; font-weight: 600; }
.choice-price { font-family: var(--mono); font-size: 24px; font-weight: 700; letter-spacing: -.6px; }
.choice-price small { font-size: 12px; font-weight: 400; color: var(--muted); letter-spacing: 0; }
.choice-note { color: var(--muted); font-size: 13px; }

/* Numbered because paying genuinely is a sequence. */
.steps-num { margin: 0; padding-left: 18px; color: var(--muted); font-size: 14px; }
.steps-num li { padding: 3px 0; }
.steps-num li::marker { color: var(--accent); font-family: var(--mono); font-size: 12px; }

/* ==========================================================================
   Empty states
   ==========================================================================
   A headed table with no rows reads as a bug. A sentence reads as an answer.
   ========================================================================== */
.empty {
  padding: 28px 20px;
  text-align: center;
  color: var(--muted);
  font-size: 14px;
  border: 1px dashed var(--border);
  border-radius: var(--r-card);
}

/* On a phone a six-column table cannot be read sideways, so each row becomes
   its own small card. The markup does not change - only the display roles. */
@media (max-width: 620px) {
  .table-wrap table, .table-wrap thead, .table-wrap tbody,
  .table-wrap th, .table-wrap td, .table-wrap tr { display: block; }
  .table-wrap thead { display: none; }
  .table-wrap tr {
    border: 1px solid var(--edge);
    border-radius: var(--r-card);
    margin-bottom: 8px;
    padding: 8px 12px;
  }
  /* Label left, value right - and anything else in the cell, like the kind
     dot, stays beside its value rather than drifting into the gap. */
  .table-wrap td { border: 0; padding: 4px 0; display: flex; justify-content: flex-end; align-items: baseline; gap: 8px; }
  .table-wrap td.right { text-align: left; }

  /* The column name travels with the cell, so a stacked row still says what
     each value is. Only cells that carry a label get one. */
  .table-wrap td[data-label]::before {
    content: attr(data-label);
    margin-right: auto;
    color: var(--muted);
    font-family: var(--mono);
    font-size: 11px;
    letter-spacing: .8px;
    text-transform: uppercase;
  }
}

/* ==========================================================================
   Admin
   ========================================================================== */
.stat-value {
  font-family: var(--mono);
  font-size: 30px;
  font-weight: 700;
  letter-spacing: -1px;
  line-height: 1.1;
}
.stat-value small { font-size: 12px; font-weight: 400; color: var(--muted); letter-spacing: 0; }

/*
 * NO sticky table header.
 *
 * `.table-wrap` is an `overflow-x: auto` box, which makes it the sticky
 * containing block - so `top: var(--h-header)` offset the header cells
 * DOWNWARD inside the wrapper, parking their opaque background exactly on top
 * of the first data row and hiding it. On the sessions page that swallowed the
 * current session entirely. The tables here are short; they do not need one.
 */

/* ==========================================================================
   Auth panel
   ==========================================================================
   draw_login(): a 380px window, a chrome strip over a body, one radius, no
   border. The same component, at web scale.
   ========================================================================== */
.auth {
  max-width: 400px;
  margin: 0 auto;
  background: var(--card);
  border: 1px solid var(--edge);
  border-radius: var(--r-card);
  overflow: hidden;
  box-shadow: 0 24px 60px -28px rgba(0, 0, 0, .9);
}
.auth-strip {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 12px 16px;
  background: var(--chrome);
  border-bottom: 1px solid var(--edge);
}
.auth-body { padding: 4px 16px 20px; }
.auth-body > p:first-child { margin-top: 12px; }
.auth-foot { max-width: 400px; margin: 14px auto 0; text-align: center; }

/* A feature list where every line is included, so the mark is a tick rather
   than the accent dot used for neutral bullets. */
.ticks { list-style: none; padding: 0; margin: 14px 0 0; }
.ticks li { position: relative; padding: 6px 0 6px 22px; color: var(--muted); font-size: 14px; }
.ticks li::before {
  content: "";
  position: absolute;
  left: 4px; top: 12px;
  width: 8px; height: 4px;
  border-left: 1.5px solid var(--accent);
  border-bottom: 1.5px solid var(--accent);
  transform: rotate(-45deg);
}
.rank-panel .ticks li { color: var(--text); }

/* ---------------------------------------------------------------------------
 * Admin feature tree
 *
 * One row per control, nested by indentation, with a single Save for the page.
 *
 * The disclosure is a hidden checkbox plus a sibling selector rather than
 * <details>/<summary>. A summary that contains a <select> eats clicks on it to
 * toggle itself, which would make the control beside a feature name unusable.
 * The checkbox carries no `name`, so it is never submitted with the form.
 *
 * Depth comes from a class, not a custom property: style-src runs without
 * 'unsafe-inline', so a style="--d:2" attribute is dropped by the browser and
 * the indentation would silently not happen.
 * ------------------------------------------------------------------------ */
.ftree { display: flex; flex-direction: column; }

.frow {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 118px 100px 118px 118px;
  align-items: center;
  gap: 10px;
  padding: 5px 10px;
  border-top: 1px solid var(--edge);
}

.fhead {
  border-top: 0;
  color: var(--muted);
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: .6px;
  text-transform: uppercase;
  padding-bottom: 8px;
}
.fhead .fname { padding-left: 22px; }

/* The row's own controls sit at the natural height for a dense list; the
   38px form control elsewhere on the site would make 83 rows unreadable. */
.frow select {
  height: 30px;
  padding: 0 26px 0 9px;
  font-size: 13px;
  background-position: right 9px center;
  margin: 0;
}

.fname {
  display: flex;
  align-items: baseline;
  gap: 8px;
  min-width: 0;
  color: var(--text);
  font-size: 13px;
  margin: 0;
}
.fname-toggle { cursor: pointer; }
.fname-toggle:hover .flabel { color: var(--accent); }

.flabel { flex: none; }
.fdesc {
  color: var(--muted);
  font-size: 12px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  min-width: 0;
}
.fcount {
  flex: none;
  font-family: var(--mono);
  font-size: 10px;
  color: var(--muted);
  background: var(--track);
  border-radius: var(--r-pill);
  padding: 1px 6px;
}

/* A caret that turns, drawn from a border like the .ticks mark rather than
   pulled from an icon font the site does not ship. */
.fchev {
  flex: none;
  width: 14px;
  height: 14px;
  position: relative;
}
.fchev::before {
  content: "";
  position: absolute;
  left: 3px; top: 4px;
  width: 5px; height: 5px;
  border-right: 1.5px solid var(--muted);
  border-bottom: 1.5px solid var(--muted);
  transform: rotate(-45deg);
  transition: transform .12s ease;
}
.fchev-none::before { display: none; }

.fx { display: none; }
.fx:checked ~ .frow .fchev::before { transform: rotate(45deg); }
.fname-toggle:hover .fchev::before { border-color: var(--accent); }

/* Collapsed. Descendants live inside .fkids, which is a SIBLING of the
   checkbox and of the row - so this reaches exactly this node's subtree and
   nothing after it. A flat tree with only depth classes could not express
   that: the same selector would hide every later feature too. */
.fx:not(:checked) ~ .fkids { display: none; }

/* Indentation. Only to d3 - the catalogue is two deep, and anything past that
   is a database someone has hand-edited, which renders flat rather than
   walking off the side of the card. */
.d0 > .frow .fname { padding-left: 0; }
.d1 > .frow .fname { padding-left: 20px; }
.d2 > .frow .fname { padding-left: 40px; }
.d3 > .frow .fname { padding-left: 60px; }

.d1 > .frow, .d2 > .frow, .d3 > .frow { background: rgba(0, 0, 0, .16); }

.fsave {
  position: sticky;
  bottom: 0;
  display: flex;
  align-items: center;
  gap: 12px;
  margin-top: 12px;
  padding: 12px var(--pad-body);
  background: var(--chrome);
  border: 1px solid var(--edge);
  border-radius: var(--r-card);
}

@media (max-width: 900px) {
  /* The two effect columns are the first to go: they are derived from the two
     to their left, so an admin can work them out. */
  .frow { grid-template-columns: minmax(0, 1fr) 110px 92px; }
  .frow .pill:nth-last-child(-n+2) { display: none; }
  .fhead span:nth-last-child(-n+2) { display: none; }
}

@media (max-width: 620px) {
  .frow { grid-template-columns: minmax(0, 1fr) 96px; }
  .frow select[name^="rank__"] { display: none; }
  .fhead span:nth-child(3) { display: none; }
  .fdesc { display: none; }
}
