:root {
  --bg: #14161a;
  --panel: #1c1f26;
  --panel-2: #232733;
  --border: #333a49;
  --text: #e6e9ef;
  --muted: #9aa4b8;
  --accent: #4f8cff;
  --danger: #e5534b;
  --ok: #3fb950;
  --warn: #d29922;
  --radius: 8px;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font: 14px/1.5 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
}

.topbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 12px 20px;
  background: #0f1115;
  border-bottom: 1px solid var(--border);
}

.brand { display: flex; align-items: center; gap: 10px; font-weight: 600; }

.dot {
  width: 12px; height: 12px; border-radius: 50%;
  background: linear-gradient(135deg, var(--accent), #9b6bff);
}

.topbar-right { display: flex; align-items: center; gap: 12px; font-size: 13px; }

/* An inline, non-modal warning inside a card.
   Distinct from a form field error: nothing is wrong with what was typed, the
   account is simply in a state that needs a step or two to resolve. */
.callout {
  background: #2a2413;
  border: 1px solid #4a3f16;
  color: #f0e2b6;
  border-radius: 8px;
  padding: 10px 12px;
  margin-top: 12px;
  font-size: 13px;
}
.callout p { margin: 0; }

.view { max-width: 1000px; margin: 0 auto; padding: 24px 20px 60px; }


h1 { font-size: 22px; margin: 0 0 4px; }
h2 { font-size: 16px; margin: 0 0 12px; }
h3 { font-size: 14px; margin: 0 0 8px; color: var(--muted); text-transform: uppercase; letter-spacing: .04em; }

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

.muted { color: var(--muted); }
.mono { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }
.small { font-size: 12px; }
.row { display: flex; gap: 10px; flex-wrap: wrap; align-items: center; }
.spread { display: flex; justify-content: space-between; align-items: center; gap: 12px; flex-wrap: wrap; }
.stack { display: flex; flex-direction: column; gap: 10px; }

label {
  display: block;
  font-size: 11px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 6px;
}

/* A label that wraps its own control describes an action ("Enable passkey
   sign-in"), not a field, so it keeps normal case and size. */
label.check,
label.radio,
label.inline-check {
  font-size: 13px;
  letter-spacing: normal;
  text-transform: none;
  margin-bottom: 0;
}

/* A labelled box reads as one row: the box, then the words it turns on. */
label.check {
  display: flex;
  align-items: center;
  gap: 8px;
}

input, select, textarea {
  width: 100%;
  padding: 8px 10px;
  background: var(--panel-2);
  border: 1px solid var(--border);
  border-radius: 6px;
  color: var(--text);
  font: inherit;
}

/* A checkbox is not a text field. Without this it inherits `width: 100%` and the
   field styling above, so the box fills the line, shoves its own label onto the next
   one, and sits away from the words it belongs to. */
input[type="checkbox"],
input[type="radio"] {
  width: auto;
  padding: 0;
  margin: 0;
  background: none;
  border: 0;
  accent-color: var(--accent);
}

textarea { min-height: 120px; resize: vertical; font-family: ui-monospace, Menlo, monospace; font-size: 12px; }

button,
a.button {
  padding: 8px 14px;
  background: var(--accent);
  color: #06101f;
  border: 0;
  border-radius: 6px;
  font: inherit;
  font-weight: 600;
  cursor: pointer;
}

button.secondary,
a.button.secondary { background: var(--panel-2); color: var(--text); border: 1px solid var(--border); }
button.danger { background: transparent; color: var(--danger); border: 1px solid var(--danger); }
button.link { background: none; color: var(--accent); padding: 2px 4px; font-weight: 500; }
button:disabled { opacity: .5; cursor: not-allowed; }

table { width: 100%; border-collapse: collapse; }
th, td { text-align: left; padding: 9px 8px; border-bottom: 1px solid var(--border); vertical-align: top; }
th { font-size: 12px; color: var(--muted); text-transform: uppercase; letter-spacing: .04em; }
tbody tr:hover { background: #1f232c; }

.pill { display: inline-block; padding: 1px 8px; border-radius: 999px; font-size: 11px; border: 1px solid var(--border); color: var(--muted); }
.pill.owner { color: var(--ok); border-color: #24502c; }
.pill.write { color: var(--accent); border-color: #24406f; }
.pill.read { color: var(--muted); }
.pill.admin { color: var(--warn); border-color: #5a4715; }

.banner { padding: 10px 12px; border-radius: 6px; margin-bottom: 12px; font-size: 13px; }
.banner.error { background: #3a1d1b; border: 1px solid #6b2b27; color: #ffc9c5; }
.banner.ok { background: #16301c; border: 1px solid #24502c; color: #b7f0c2; }
.banner.info { background: #1a2436; border: 1px solid #27405f; color: #cfe0ff; }

pre {
  background: #0f1115;
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 12px;
  overflow-x: auto;
  font-size: 12px;
  margin: 0;
}

.bucket-row { cursor: pointer; }
.bucket-row.selected { background: #1f2735; }
.empty { color: var(--muted); padding: 14px 8px; font-style: italic; }
.breadcrumb { margin-bottom: 10px; font-size: 13px; }

/* Layout utilities. The client sets classes rather than inline `style`
   attributes, because the Content-Security-Policy forbids inline styles. */
.section-heading { margin-top: 18px; }
.spaced-top { margin-top: 12px; }
.mb-xs { margin-bottom: 2px; }
.grow { flex: 1 1 160px; min-width: 0; }
.fixed-160 { width: 160px; flex: 0 0 160px; }
.narrow { max-width: 480px; margin: 40px auto; }
.tight { margin-bottom: 2px; }
.spaced { margin-left: 8px; }
/* A label whose control sits beside its words. `gap` does nothing without a flex or
   grid display, so the box and the text used to touch. */
.inline-check { display: flex; align-items: center; gap: 8px; margin: 0; }
.checkbox { width: auto; }
.section { margin-top: 18px; }

.divider { border: 0; border-top: 1px solid var(--border); margin: 18px 0 14px; }
.wrap { word-break: break-all; }
.pill.danger { color: var(--danger); border-color: #6b2b27; }

/* ---------------------------------------------------------------------------
   Authentication pages

   The passkey option sits in its own bordered box below the password form, so it
   reads as an alternative route in rather than part of the password flow.
   --------------------------------------------------------------------------- */

.auth-card { margin-bottom: 16px; }
.auth-card h1 { margin-bottom: 2px; }
.auth-card > p.muted { margin-top: 0; }

.auth-actions { margin-top: 18px; }

button.primary.block,
button.passkey.block,
button.secondary.block {
  display: block;
  width: 100%;
  padding: 12px 16px;
}

/* The passkey entry point: a distinct, slightly recessed surface. */
.passkey-box {
  padding: 14px;
  background: var(--surface-2, rgba(255, 255, 255, 0.02));
  border: 1px solid var(--border);
}

button.passkey {
  font-weight: 600;
  letter-spacing: 0.01em;
}

/* Password requirements, ticked live as the invitee types. */
.requirements {
  margin: 4px 0 2px;
  padding: 12px 14px;
  border: 1px solid var(--border);
  border-radius: 8px;
}
.requirements-title {
  font-size: 12px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 8px;
}
.requirements ul { margin: 0; padding-left: 18px; }
.requirements .rule { margin: 4px 0; }
.requirements .rule.ok { color: var(--ok, #7fd18a); }
.requirements .rule.ok::marker { color: var(--ok, #7fd18a); }

.invited { margin: 12px 0 16px; }
.invite-mark { margin-right: 2px; }
.invite-invalid { color: var(--danger); }

/* A divider that separates the password form from the passkey box. */
.auth-card .divider { margin: 16px 0; }

/* ---------------------------------------------------------------------------
   Button feedback

   Every action button reacts to hover, to being pressed, and to keyboard focus.
   A button that does nothing visible on hover reads as decoration, and for
   destructive actions like Revoke or Delete the hover state is the last chance
   to signal what is about to happen.
   --------------------------------------------------------------------------- */

button,
a.button {
  transition: background-color 120ms ease, border-color 120ms ease,
              color 120ms ease, transform 60ms ease, box-shadow 120ms ease;
  cursor: pointer;
}

/* The hover is the same for a link styled as a button, so the two behave alike rather
   than nearly alike. */
button:hover:not(:disabled),
a.button:hover {
  border-color: var(--accent, #6ea8fe);
  filter: brightness(1.18);
}

button:active:not(:disabled),
a.button:active {
  transform: translateY(1px);
  filter: brightness(0.94);
}

button:focus-visible {
  outline: 2px solid var(--accent, #6ea8fe);
  outline-offset: 2px;
}

button:disabled {
  cursor: not-allowed;
  opacity: 0.55;
}

/* A short-lived acknowledgement after a successful copy. */
button.copied {
  color: var(--ok, #7fd18a);
  border-color: var(--ok, #7fd18a);
}

/* Destructive actions lean red on hover, so the warning lands before the click. */
button.danger:hover:not(:disabled) {
  border-color: var(--danger, #e5534b);
  background: rgba(229, 83, 75, 0.14);
  filter: none;
}

/* ---------------------------------------------------------------------------
   Modal dialogs
   --------------------------------------------------------------------------- */

.modal-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(6, 8, 12, 0.72);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
  z-index: 50;
}

.modal-dialog {
  background: var(--surface, #161a22);
  border: 1px solid var(--border, #2a303c);
  border-radius: 10px;
  padding: 22px 24px;
  width: 100%;
  max-width: 460px;
  max-height: 88vh;
  overflow-y: auto;
  box-shadow: 0 18px 48px rgba(0, 0, 0, 0.55);
}

.modal-title { margin: 0 0 12px; font-size: 19px; }

/* The QR sits on its own light plate: QR codes need light-on-dark contrast to
   scan reliably, and a dark theme would otherwise invert or dim it. */
img.qr {
  display: block;
  margin: 12px auto;
  padding: 10px;
  background: #ffffff;
  border-radius: 8px;
}

.backup-codes {
  white-space: pre-line;
  line-height: 1.9;
  padding: 14px 16px;
  border: 1px dashed var(--border, #2a303c);
  border-radius: 8px;
  margin: 12px 0;
  user-select: all;
}

.grow { flex: 1; }

/* ---------------------------------------------------------------------------
   Add API key dialog

   Mirrors the OCI console's three ways to add a key: generate a pair, choose a
   public key file, or paste one.
   --------------------------------------------------------------------------- */

.key-panel { margin-top: 16px; }
.key-panel textarea { width: 100%; font-family: var(--mono, ui-monospace, monospace); font-size: 13px; }

/* Radio rows read as a chooser rather than as form fields. */
label.radio {
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 6px 0;
  cursor: pointer;
  font-size: 14px;
}
label.radio input { width: auto; margin: 0; accent-color: var(--accent, #6ea8fe); }
label.radio:hover { color: var(--accent, #6ea8fe); }

/* Drop target, matching the console's "Drop a file or select one". */
.dropzone {
  border: 1px dashed var(--border, #2a303c);
  border-radius: 8px;
  padding: 20px 22px;
  cursor: pointer;
  transition: border-color 120ms ease, background-color 120ms ease;
}
.dropzone:hover,
.dropzone.over {
  border-color: var(--accent, #6ea8fe);
  background: rgba(110, 168, 254, 0.07);
}
.dropzone-title { font-weight: 600; margin-bottom: 4px; }
input.hidden { display: none; }

/* Download tiles, side by side as in the console. */
.downloads {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 12px;
  margin: 14px 0;
}
@media (max-width: 560px) { .downloads { grid-template-columns: 1fr; } }

.download-box {
  border: 1px solid var(--border, #2a303c);
  border-radius: 8px;
  padding: 14px 16px;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.download-title { font-weight: 600; }
.download-box button.download { margin-top: auto; }

button.download:hover:not(:disabled) {
  border-color: var(--accent, #6ea8fe);
  background: rgba(110, 168, 254, 0.12);
}

/* ---------------------------------------------------------------------------
   Change Password dialog
   --------------------------------------------------------------------------- */

/* A password field with its reveal toggle inside the field's right edge. */
.with-reveal { position: relative; display: block; }
.with-reveal input { width: 100%; padding-right: 44px; }
.with-reveal button.reveal {
  position: absolute;
  right: 4px;
  top: 50%;
  transform: translateY(-50%);
  width: 34px;
  height: 34px;
  padding: 0;
  background-color: var(--muted);
  border: 0;
  border-radius: 6px;
  cursor: pointer;
  /* Eye, then eye-with-slash once revealed. A mask rather than a background
     image so `background-color` drives the colour and hover needs no second
     asset. */
  -webkit-mask: var(--eye) center / 18px 18px no-repeat;
  mask: var(--eye) center / 18px 18px no-repeat;
  --eye: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z'/%3E%3Ccircle cx='12' cy='12' r='3'/%3E%3C/svg%3E");
}
.with-reveal button.reveal.revealed {
  --eye: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94'/%3E%3Cpath d='M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19'/%3E%3Cline x1='1' y1='1' x2='23' y2='23'/%3E%3C/svg%3E");
}
.with-reveal button.reveal:hover:not(:disabled) {
  background-color: var(--text);
  filter: none;
}

/* Inline form errors, so a mismatch is reported where the form is. */
.form-error {
  color: var(--danger, #e5534b);
  font-size: 13px;
  min-height: 18px;
  margin-top: 10px;
}
.form-error:empty { min-height: 0; margin-top: 0; }

/* ---------------------------------------------------------------------------
   Fly-out menus.

   These are `<details>` elements, so they toggle without script, but the panel is
   positioned absolutely and must not sit in the flow: a menu that expands inside a
   table row reflows the table and wraps its items onto several lines.
   --------------------------------------------------------------------------- */
.row-menu { position: relative; display: inline-block; }

.row-menu > summary {
  list-style: none;
  cursor: pointer;
  user-select: none;
  padding: 2px 8px;
  border: 1px solid transparent;
  border-radius: 6px;
  color: var(--muted);
  line-height: 1.2;
}
/* The disclosure triangle is drawn by the browser; the console uses an ellipsis. */
.row-menu > summary::-webkit-details-marker { display: none; }
.row-menu > summary::marker { content: ""; }
.row-menu > summary:hover,
.row-menu[open] > summary {
  background: var(--panel-2);
  border-color: var(--border);
  color: var(--text);
}

.row-menu > .menu {
  position: absolute;
  top: calc(100% + 4px);
  right: 0;
  z-index: 30;
  display: flex;
  flex-direction: column;
  min-width: 220px;
  max-height: 60vh;
  overflow-y: auto;
  padding: 6px;
  background: var(--panel-2);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: 0 14px 36px rgba(0, 0, 0, .5);
}
/* The Actions button sits at the left of the page, so its panel opens rightwards;
   a row's menu is in the last column and opens leftwards. */
.row-menu.actions > .menu { right: auto; left: 0; }

.row-menu > .menu > button,
.row-menu > .menu > a {
  display: block;
  width: 100%;
  padding: 8px 10px;
  border: 0;
  border-radius: 6px;
  background: none;
  color: var(--text);
  font: inherit;
  font-weight: 500;
  text-align: left;
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
}
.row-menu > .menu > button:hover:not(:disabled),
.row-menu > .menu > a:hover { background: #2c3242; }
.row-menu > .menu > button.danger { color: var(--danger); }
.row-menu > .menu > button.danger:hover:not(:disabled) { background: #3a1d1b; }
.row-menu > .menu > button:disabled { color: var(--muted); }

/* ---------------------------------------------------------------------------
   Top-level navigation.

   The landing page is the buckets page; account and administrative housekeeping
   live behind their own buttons rather than on it. Tabs, not call-to-action
   buttons, so the current page reads as a location rather than an action.
   --------------------------------------------------------------------------- */
.topnav { display: flex; align-items: center; gap: 4px; }

/* A tab is a button in the application and a link on a page rendered by the server,
   such as the usage guide. They have to look the same. */
.topnav button.tab,
.topnav a.tab {
  display: inline-block;
  padding: 6px 10px;
  background: none;
  border: 1px solid transparent;
  border-radius: 6px;
  color: var(--muted);
  font-weight: 500;
  font-size: 14px;
  letter-spacing: normal;
  text-transform: none;
  text-decoration: none;
  margin-bottom: 0;
  cursor: pointer;
}
.topnav button.tab:hover,
.topnav a.tab:hover { background: var(--panel-2); color: var(--text); }
.topnav button.tab.active,
.topnav a.tab.active {
  background: var(--panel-2);
  border-color: var(--border);
  color: var(--text);
}

/* ---------------------------------------------------------------------------
   The Actions trigger.

   It is the only way into the selection-wide operations, and as muted text it did
   not read as something to click. It is a button, with a caret that says a menu
   comes out of it.
   --------------------------------------------------------------------------- */
.row-menu.actions > summary {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 8px 14px;
  background: var(--panel-2);
  border: 1px solid var(--border);
  border-radius: 6px;
  color: var(--text);
  font-weight: 600;
}
.row-menu.actions > summary::after {
  content: "▾";
  font-size: 10px;
  line-height: 1;
  color: var(--muted);
}
.row-menu.actions > summary:hover,
.row-menu.actions[open] > summary {
  background: #2c3242;
  border-color: #46506b;
}

/* ---------------------------------------------------------------------------
   The upload bar.

   "Upload objects" is a `<label>`, because clicking a button cannot open a file
   dialog — but nothing styled it, so it rendered as a form caption rather than as
   the button it is.
   --------------------------------------------------------------------------- */
/* One row of controls: the box, then the words that belong to it, all on the same
   baseline. Each control is an inline-flex pair rather than a caption stacked over a
   field, which is what made this bar unreadable. */
.toolbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px 14px;
  margin-bottom: 12px;
}

.toolbar input[type="search"] { flex: 1 1 320px; max-width: 460px; }

.field-inline {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin: 0;
  font-size: 13px;
  letter-spacing: normal;
  text-transform: none;
  color: var(--muted);
  white-space: nowrap;
}
.field-inline input { width: auto; flex: 0 1 240px; }

label.button {
  display: inline-flex;
  align-items: center;
  padding: 8px 14px;
  background: var(--accent);
  color: #06101f;
  border-radius: 6px;
  font-weight: 600;
  cursor: pointer;
  /* The base `label` rule is for form captions. This is not one. */
  font-size: 14px;
  letter-spacing: normal;
  text-transform: none;
  margin-bottom: 0;
}
label.button:hover { background: #6ea8fe; }

/* A role picker sized to its contents rather than filling the cell. */
.role-select { width: auto; min-width: 130px; }

/* Invite voucher controls: compact, because they sit in a table cell per account.
   A single digit needs about a digit's width, so the box between the buttons is sized
   for one rather than for a field — the buttons belong next to the number they change. */
.voucher-cell {
  flex-wrap: nowrap;
  gap: 2px;
  justify-content: center;
  align-items: center;
}
button.compact { padding: 4px 8px; line-height: 1; }

/* The balance between the buttons reads as a value, not as something to fill in: the
   buttons are the only action, so the box does not invite typing. */
.voucher-count {
  width: 30px;
  padding: 6px 0;
  text-align: center;
  background: transparent;
  border-color: transparent;
  cursor: default;
}
.voucher-count:focus { outline: none; }

/* ---------------------------------------------------------------------------
   The usage guide.

   A document rather than an application screen: one column, generous line height, and
   code that can be selected and pasted as written.
   --------------------------------------------------------------------------- */
/* What is left is only what an anchor brings with it. Everything visual comes from the
   button rules above, so the two cannot drift apart. */
a.button {
  display: inline-flex;
  align-items: center;
  text-decoration: none;
}

.guide-body {
  max-width: 860px;
  margin: 0 auto;
  padding: 28px 20px 60px;
}
.guide-body h1 { font-size: 28px; margin-bottom: 10px; }
.guide-body .lead { font-size: 15px; color: var(--text); margin-bottom: 14px; }
.guide-section { margin-top: 30px; }
.guide-section h2 {
  font-size: 18px;
  color: var(--text);
  text-transform: none;
  letter-spacing: normal;
  border-bottom: 1px solid var(--border);
  padding-bottom: 6px;
  margin-bottom: 12px;
}
.guide-section .note { color: var(--muted); font-size: 14px; margin: 10px 0; }
.guide-section a { color: var(--accent); }
/* Commands are the point of the page, so they read as the most prominent thing on it. */
.guide-body pre {
  background: #0f1115;
  border: 1px solid var(--border);
  border-left: 3px solid var(--accent);
  border-radius: 6px;
  padding: 12px 14px;
  overflow-x: auto;
  margin: 10px 0;
}
.guide-body code { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 12.5px; }
.guide-body p code {
  background: var(--panel-2);
  border: 1px solid var(--border);
  border-radius: 4px;
  padding: 1px 5px;
}
.guide-footer { max-width: 860px; margin: 0 auto; padding: 0 20px 40px; }
.guide-footer a { color: var(--accent); }
