/* FUJI VPN panel — maroon ink on a white ground.
   Token names mirror the app's res/values/colors.xml so the two stay legible
   side by side.

   The page and the cards are the same white paper, so a card is held apart by
   its border and its shadow rather than by a fill. --soft-fill is kept for the
   parts that are genuinely inset — table headers, the edit row, credential
   rows, inputs — because without it the structure would go with the grey.

   There is no night palette, and that is deliberate rather than an omission.
   The panel is a white surface on purpose, so it stays white on a machine set
   to dark; `color-scheme: light` and the matching meta tag tell the browser the
   same thing, which is also what stops Chrome's forced-dark mode from
   recolouring it. */

:root {
  --maroon: #800000;
  --maroon-dark: #5c0000;
  --maroon-grad-start: #9e1b1b;
  --maroon-grad-end: #5c0000;
  --canvas: #ffffff;
  --surface: #ffffff;
  --soft-fill: #f6f4f5;
  --soft-press: #efe7e9;
  --soft-ink: #2b1216;
  --soft-hairline: #f0eef1;
  --line: #e4e1e5;
  --muted: #8a7f84;
  --ring: #33800000;
  --ok: #1e8e5a;
  --warn: #b26a00;
  --bad: #b3261e;
  --radius: 14px;
  --shadow: 0 1px 2px rgba(43, 18, 22, 0.06), 0 8px 24px rgba(128, 0, 0, 0.07);
  --shadow-lift: 0 2px 6px rgba(43, 18, 22, 0.07), 0 18px 44px rgba(128, 0, 0, 0.1);
  color-scheme: light;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--canvas);
  color: var(--soft-ink);
  font: 15px/1.55 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
}

a { color: var(--maroon); }
code { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 0.9em; }

.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

.muted { color: var(--muted); }
.small { font-size: 13px; }
.inline { display: inline; }
.right { text-align: right; }

/* ---------------------------------------------------------------- top bar */

.topbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 13px 20px;
  background: linear-gradient(135deg, var(--maroon-grad-start), var(--maroon-grad-end));
  color: #fff;
}

.brand {
  display: flex;
  align-items: center;
  gap: 10px;
  color: #fff;
  text-decoration: none;
  font-weight: 700;
  letter-spacing: 0.02em;
}

.brand-mark {
  display: grid;
  place-items: center;
  width: 30px;
  height: 30px;
  border-radius: 9px;
  background: rgba(255, 255, 255, 0.16);
  font-weight: 800;
}

.topnav { display: flex; gap: 16px; }
.topnav a {
  color: rgba(255, 255, 255, 0.88);
  text-decoration: none;
  font-size: 14px;
  font-weight: 600;
}
.topnav a:hover { color: #fff; }

/* ---------------------------------------------------------------- layout */

.wrap {
  max-width: 1140px;
  margin: 0 auto;
  padding-block: 24px 64px;
  padding-inline: 20px;
}

h1 { font-size: 21px; margin: 0; color: var(--maroon); }
h2 { font-size: 17px; margin: 0 0 12px; color: var(--maroon); }

.card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 20px;
  margin-bottom: 18px;
}

.card-narrow { max-width: 420px; margin: 40px auto; }

/* ------------------------------------------------------- page head + stats */

.page-head {
  display: flex;
  align-items: flex-end;
  gap: 16px;
  flex-wrap: wrap;
  margin-bottom: 18px;
}
.page-head-main { flex: 1; min-width: 0; }

.stats { display: flex; gap: 18px; flex-wrap: wrap; margin-top: 6px; }
.stat { font-size: 13px; color: var(--muted); }
.stat b { color: var(--soft-ink); font-size: 15px; font-variant-numeric: tabular-nums; }
.stat.is-attn b { color: var(--warn); }

/* -------------------------------------------------------------- toolbar */

/* The search box and the filter chips are the only controls on the page that
   need script. With none, they would sit there doing nothing — so they are
   hidden until the `js` class says the handlers are attached. */
.tools { display: none; gap: 10px; flex-wrap: wrap; align-items: center; margin-bottom: 14px; }
.js .tools { display: flex; }

.search {
  flex: 1 1 220px;
  min-width: 0;
  display: flex;
  align-items: center;
  gap: 8px;
  background: var(--soft-fill);
  border: 1px solid var(--soft-hairline);
  border-radius: 10px;
  padding: 9px 12px;
  color: var(--muted);
}
.search input {
  flex: 1;
  min-width: 0;
  margin: 0;
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  font-size: 14px;
  color: var(--soft-ink);
  outline: none;
}

.chips { display: flex; gap: 6px; flex-wrap: wrap; }
.chip {
  font: inherit;
  font-size: 12.5px;
  font-weight: 700;
  padding: 6px 12px;
  border-radius: 999px;
  background: var(--surface);
  color: var(--muted);
  border: 1px solid var(--line);
  cursor: pointer;
}
.chip:hover { border-color: var(--maroon); color: var(--maroon); }
.chip.is-on {
  background: var(--maroon);
  color: #fff;
  border-color: transparent;
}

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

.tbl-scroll { overflow-x: auto; }

.acc {
  width: 100%;
  min-width: 660px;
  border-collapse: collapse;
  font-size: 14px;
}
.acc th {
  text-align: left;
  padding: 10px 14px;
  font-size: 10px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--muted);
  background: var(--soft-fill);
  border-bottom: 1px solid var(--soft-hairline);
  white-space: nowrap;
}
.acc td {
  padding: 13px 14px;
  border-bottom: 1px solid var(--soft-hairline);
  vertical-align: middle;
}
.acc tr:last-child td { border-bottom: 0; }

.acct-name { font-weight: 700; }
.acct-note { font-size: 12px; color: var(--muted); margin-top: 2px; }
.num { font-variant-numeric: tabular-nums; }
.empty { margin: 0; padding: 22px 14px; color: var(--muted); text-align: center; }

.acts { display: flex; gap: 6px; justify-content: flex-end; }

/* Status reads as a dot and a word. A filled pill on every row made the table
   loud, and the exceptions — expired, suspended — are what should stand out. */
.st {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  font-weight: 700;
  font-size: 13px;
  white-space: nowrap;
}
.st .dot { width: 7px; height: 7px; border-radius: 999px; background: currentColor; }
.st-ok { color: var(--ok); }
.st-warn { color: var(--warn); }
.st-bad { color: var(--bad); }

/* Expiry: the countdown, and under it how much of the granted window is left.
   The bar is a glance, the number is the answer. */
.exp { min-width: 104px; }
.exp-t { font-weight: 700; font-variant-numeric: tabular-nums; }
.bar {
  height: 4px;
  border-radius: 999px;
  background: var(--soft-press);
  margin-top: 6px;
  overflow: hidden;
}
.bar i { display: block; height: 100%; border-radius: 999px; background: var(--ok); }
.bar.is-warn i { background: var(--warn); }
.bar.is-bad i { background: var(--bad); }

/* ------------------------------------------------------------ icon buttons */

/* Inline SVG rather than an icon font or a sprite: it needs no new file and no
   build step, and currentColor means the icon takes the button's maroon — or
   its white, on the red delete button — with no extra rule. The label lives in
   title and aria-label, because the glyph alone is not a name. */
.ico {
  display: grid;
  place-items: center;
  width: 30px;
  height: 30px;
  padding: 0;
  border-radius: 8px;
  background: var(--soft-fill);
  color: var(--maroon);
  border: 1px solid var(--ring);
  cursor: pointer;
}
.ico:hover { background: var(--soft-press); }
.ico svg { display: block; }
.ico-danger { background: var(--bad); color: #fff; border-color: transparent; }
.ico-danger:hover { background: var(--bad); filter: brightness(1.12); }

/* ---------------------------------------------------------------- forms */

label {
  display: block;
  font-size: 13px;
  font-weight: 600;
  color: var(--soft-ink);
}

input, select {
  display: block;
  width: 100%;
  margin-top: 6px;
  padding: 11px 13px;
  font: inherit;
  font-weight: 400;
  color: var(--soft-ink);
  background: var(--soft-fill);
  border: 1px solid var(--soft-hairline);
  border-radius: 10px;
  outline: none;
  transition: border-color 0.15s, background 0.15s;
}

input:focus, select:focus {
  background: var(--surface);
  border-color: var(--maroon);
  box-shadow: 0 0 0 3px var(--ring);
}

input::placeholder { color: var(--muted); }

.stack { display: grid; gap: 14px; }

/* The expiry number and its unit are one answer — "30 days" — so they sit on
   one line. Stacked, they read as two separate questions, and the number alone
   means nothing without the unit beside it. */
.expiry-row {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 8px;
  margin-top: 6px;
}
.expiry-row input, .expiry-row select { margin-top: 0; }
.expiry-row select { width: auto; }

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 11px 18px;
  font: inherit;
  font-weight: 700;
  color: #fff;
  background: linear-gradient(135deg, var(--maroon-grad-start), var(--maroon-grad-end));
  border: 0;
  border-radius: 10px;
  cursor: pointer;
  text-decoration: none;
  text-align: center;
  transition: filter 0.15s, transform 0.05s;
}
.btn:hover { filter: brightness(1.08); }
.btn:active { transform: translateY(1px); }

.btn-ghost {
  color: var(--maroon);
  background: var(--soft-fill);
  border: 1px solid var(--ring);
}
.btn-ghost:hover { filter: none; background: var(--soft-press); }

.btn-danger { background: var(--bad); }
.btn-tiny { padding: 6px 11px; font-size: 13px; border-radius: 8px; }
.btn[disabled] { opacity: 0.5; cursor: not-allowed; }

/* Only rendered with script: without it the form it opens is already on the
   page, below the table, and a button that does nothing is worse than none. */
.sheet-open { display: none; }
.js .sheet-open { display: inline-flex; }

/* ------------------------------------------------------------- edit row */

/* The child combinator is load-bearing: the device list is a table inside this
   cell, and a plain descendant selector put the edit row's fill, border and
   radius on every one of its cells as well. */
.edit-row > td { background: var(--soft-fill); }
.edit-form {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(170px, 1fr));
  gap: 14px;
  align-items: end;
}
.edit-actions { grid-column: 1 / -1; display: flex; gap: 8px; }

/* The device list nested inside an account's edit row. Its header row repeats
   the table header styling above it, so it is scaled down to read as a sub-list
   rather than a second table. */
.edit-sub { margin: 22px 0 8px; font-size: 15px; }

.dev-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 13px;
  background: var(--surface);
  border-radius: 10px;
  overflow: hidden;
}
.dev-table th, .dev-table td {
  text-align: left;
  padding: 8px 12px;
  border-bottom: 1px solid var(--soft-hairline);
}
.dev-table tr:last-child td { border-bottom: 0; }
.dev-table th {
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 0.07em;
  color: var(--muted);
  text-align: left;
}

/* ---------------------------------------------------------------- alerts */

.alert {
  padding: 11px 14px;
  border-radius: 10px;
  font-size: 14px;
  font-weight: 600;
  margin-bottom: 16px;
}
.alert-error { color: var(--bad); background: rgba(179, 38, 30, 0.08); }
.alert-ok    { color: var(--ok);  background: rgba(30, 142, 90, 0.08); }

/* ------------------------------------------------------------- login gate */

.gate { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; }
.gate-title { margin: 0; flex: 1; min-width: 0; }
.gate-form { display: flex; align-items: center; gap: 12px; }

.switch { position: relative; display: inline-block; width: 46px; height: 26px; flex: none; cursor: pointer; }
.switch input {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  margin: 0;
  opacity: 0;
  cursor: pointer;
}
.switch-track {
  position: absolute;
  inset: 0;
  background: var(--soft-press);
  border-radius: 999px;
  transition: background 0.15s;
  pointer-events: none;
}
.switch-track::after {
  content: "";
  position: absolute;
  top: 3px;
  left: 3px;
  width: 20px;
  height: 20px;
  border-radius: 999px;
  background: #fff;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25);
  transition: transform 0.15s;
}
.switch input:checked + .switch-track { background: var(--ok); }
.switch input:checked + .switch-track::after { transform: translateX(20px); }
.switch input:focus-visible + .switch-track { box-shadow: 0 0 0 3px var(--ring); }

/* ------------------------------------------------------------ new account */

/* Without script this is an ordinary card at the end of the page and the tabs
   are radios the browser switches on its own, so the whole form still works.
   With script it becomes the slide-over, and the radios keep doing the tabs. */
.sheet {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 20px;
  margin-bottom: 18px;
}

.js .sheet {
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  z-index: 50;
  width: min(400px, 100%);
  margin: 0;
  padding: 20px;
  border: 0;
  border-left: 1px solid var(--line);
  border-radius: 0;
  box-shadow: var(--shadow-lift);
  overflow-y: auto;
  visibility: hidden;
  transform: translateX(100%);
  transition: transform 0.22s ease, visibility 0.22s;
}
body.sheet-open .sheet { visibility: visible; transform: none; }
body.sheet-open { overflow: hidden; }

.scrim {
  position: fixed;
  inset: 0;
  z-index: 40;
  background: rgba(43, 18, 22, 0.4);
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.22s, visibility 0.22s;
}
body.sheet-open .scrim { opacity: 1; visibility: visible; }

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

.tabs { display: flex; gap: 4px; background: var(--soft-fill); padding: 4px; border-radius: 10px; margin-bottom: 16px; }
.tabs label {
  flex: 1;
  text-align: center;
  font-size: 13px;
  font-weight: 700;
  padding: 7px 10px;
  border-radius: 8px;
  color: var(--muted);
  cursor: pointer;
}
.tabinput { position: absolute; width: 1px; height: 1px; margin: 0; opacity: 0; }
#tab-manual:checked ~ .tabs label[for="tab-manual"],
#tab-trial:checked ~ .tabs label[for="tab-trial"] {
  background: var(--surface);
  color: var(--maroon);
  box-shadow: var(--shadow);
}
#tab-manual:focus-visible ~ .tabs label[for="tab-manual"],
#tab-trial:focus-visible ~ .tabs label[for="tab-trial"] {
  outline: 2px solid var(--maroon);
  outline-offset: 2px;
}

.pane { display: none; }
#tab-manual:checked ~ .pane[data-pane="manual"],
#tab-trial:checked ~ .pane[data-pane="trial"] { display: grid; }

/* ----------------------------------------------------- generated credentials */

/* Monospace and selectable because these get read off the screen and typed
   into a phone by hand. */
.cred {
  margin: 16px 0 4px;
  border: 1px solid var(--soft-hairline);
  border-radius: 12px;
  background: var(--soft-fill);
  overflow: hidden;
}
.cred-row {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 13px 14px;
  flex-wrap: wrap;
}
.cred-row + .cred-row { border-top: 1px solid var(--soft-hairline); }
.cred-label {
  flex: 0 0 78px;
  font-size: 10px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.07em;
  color: var(--muted);
}
.cred-row code {
  flex: 1;
  min-width: 0;
  font-size: 16px;
  font-weight: 700;
  user-select: all;
  word-break: break-all;
}

.facts {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 16px;
  margin: 20px 0 0;
}
.facts dt {
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--muted);
  font-weight: 700;
  margin-bottom: 3px;
}
.facts dd { margin: 0; font-weight: 700; }

/* ---------------------------------------------------------------- sign in */

.signin { display: grid; gap: 12px; }
.signin .btn { width: 100%; }

/* ---------------------------------------------------------------- footer */

.foot {
  padding: 20px;
  text-align: center;
  font-size: 12px;
  color: var(--muted);
}

/* ----------------------------------------------------------------- mobile */

/* The panel gets opened from a phone at least as often as from a desk — it is
   where you go when someone messages you that their account stopped working —
   so below this width the table stops being a table. Six columns on a phone is
   either a sideways scroll or six unreadable slivers. Each account becomes its
   own card instead: the name and its status on the top line, the rest as
   labelled rows, the actions along the bottom where a thumb can reach them.

   The header row goes, because every value now carries its own label. Those
   labels are generated content, which assistive technology does read — and
   they have to carry it here, since display:block on a table drops the header
   association whether or not the header is on screen. */
@media (max-width: 720px) {
  .tbl-scroll { overflow-x: visible; }

  /* The rows are cards now, so the card that wrapped the table would be a card
     around cards. It goes, and the rows stand on the page directly. */
  .card-table { background: none; border: 0; box-shadow: none; padding: 0; }
  .card-table .empty { padding: 22px 0; }

  .acc { min-width: 0; border-collapse: separate; }
  .acc thead { display: none; }
  .acc tbody,
  .acc tr,
  .acc td { display: block; }

  .acc tr[data-account] {
    display: grid;
    grid-template-columns: 1fr auto;
    gap: 0 12px;
    padding: 14px 16px;
    margin-bottom: 12px;
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: 12px;
    box-shadow: var(--shadow);
  }
  .acc tr[data-account] td { padding: 0; border: 0; }

  /* Name and status share the top line — the first thing you check when an
     account is reported broken. */
  .acc tr[data-account] td:nth-child(1) { grid-column: 1; align-self: center; min-width: 0; }
  .acc tr[data-account] td:nth-child(2) { grid-column: 2; justify-self: end; align-self: center; }
  .acct-name { overflow-wrap: anywhere; }

  /* The rest are label-over-value rows. Only the first carries a hairline, so
     the block reads as one set of details rather than as four stacked lines. */
  .acc tr[data-account] td:nth-child(3),
  .acc tr[data-account] td:nth-child(4),
  .acc tr[data-account] td:nth-child(5) {
    grid-column: 1 / -1;
    display: grid;
    grid-template-columns: 84px 1fr;
    gap: 10px;
    align-items: center;
    padding-top: 8px;
  }
  .acc tr[data-account] td:nth-child(3) {
    margin-top: 12px;
    padding-top: 12px;
    border-top: 1px solid var(--soft-hairline);
  }
  .acc tr[data-account] td:nth-child(3)::before,
  .acc tr[data-account] td:nth-child(4)::before,
  .acc tr[data-account] td:nth-child(5)::before {
    content: attr(data-label);
    font-size: 10px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.07em;
    color: var(--muted);
  }
  .acc tr[data-account] .exp { min-width: 0; }

  .acc tr[data-account] td:nth-child(6) {
    grid-column: 1 / -1;
    margin-top: 14px;
    padding-top: 12px;
    border-top: 1px solid var(--soft-hairline);
  }
  .acc tr[data-account] .acts { justify-content: flex-end; }

  /* The edit form follows its account as a card of its own. Child combinator
     for the same reason as above — the device table lives inside this cell. */
  .acc tr.edit-row { margin: 0 0 12px; }
  .acc tr.edit-row > td {
    padding: 16px;
    background: var(--soft-fill);
    border: 1px solid var(--line);
    border-radius: 12px;
  }
  .edit-form { grid-template-columns: 1fr; }
  .edit-actions .btn { flex: 1; }

  /* Setting display on the rows above would otherwise beat the user agent's
     [hidden] rule — which would leave filtered-out accounts on screen and the
     edit forms open under the wrong row. */
  .acc tr[data-account][hidden],
  .acc tr.edit-row[hidden] { display: none; }

  /* The device list under an edit form becomes labelled rows too. */
  .dev-table thead { display: none; }
  .dev-table,
  .dev-table tbody,
  .dev-table tr,
  .dev-table td { display: block; }
  .dev-table tr {
    display: grid;
    grid-template-columns: 1fr auto;
    gap: 2px 10px;
    padding: 11px 12px;
  }
  .dev-table tr + tr { border-top: 1px solid var(--soft-hairline); }
  .dev-table td { padding: 0; border: 0; }
  .dev-table td:nth-child(1) { grid-column: 1; overflow-wrap: anywhere; }
  .dev-table td:nth-child(2),
  .dev-table td:nth-child(3) {
    grid-column: 1;
    display: grid;
    grid-template-columns: 72px 1fr;
    gap: 8px;
    font-size: 12px;
  }
  .dev-table td:nth-child(2)::before,
  .dev-table td:nth-child(3)::before {
    content: attr(data-label);
    font-size: 10px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.07em;
    color: var(--muted);
  }
  .dev-table td:nth-child(4) { grid-column: 2; grid-row: 1 / span 3; align-self: center; }

  /* Targets sized for a thumb rather than a pointer. The icons were 30px,
     which a mouse hits comfortably and a thumb does not. */
  .ico { width: 40px; height: 40px; border-radius: 10px; }
  .ico svg { width: 18px; height: 18px; }

  .page-head { align-items: stretch; }
  .page-head .sheet-open { width: 100%; }
  .stats { gap: 8px 18px; }

  .tools { flex-direction: column; align-items: stretch; }
  .search { flex: none; padding: 12px; }
  .chip { padding: 9px 14px; }

  /* The gate title takes the full width and the switch sits under it, with
     Save pushed to the far edge — a row that would otherwise cram a heading,
     a switch and a button across 360px. */
  .gate { flex-direction: column; align-items: stretch; gap: 12px; }
  .gate-form { justify-content: space-between; }

  .sheet { width: 100%; }
}

@media (max-width: 640px) {
  .wrap { padding-block: 18px 48px; padding-inline: 14px; }
  .card { padding: 16px; }
  .page-head { align-items: stretch; }
  .sheet { padding: 16px; }
  .topbar { padding: 12px 16px; }
}
