/* HaughtAI styles — the Apex layer on the HaughtStudio design system.
 *
 * Plain CSS, served as-is. No build step, no preprocessor, no bundler -- the
 * target machine has no Node.js, and a build step would be a hard blocker.
 *
 * `studio.css` is a verbatim copy of HaughtStudio's stylesheet
 * (web_App/static/css/app.css), the design system behind studio.haughtai.com.
 * It defines the tokens, the two-column app shell (`.app` / `.drawer` / `.main`
 * / `.topbar` / `.view`) and the shared components. This file is the Apex layer:
 * it re-points the account and marketing components at those tokens so every
 * page shares the Studio look -- near-black `--bg`, layered `--card` surfaces,
 * `--purple-300` accents, and the violet -> blue `--grad` kept for primary
 * actions.
 *
 * MOBILE FIRST. Most visitors arrive on a phone, so the styles below are
 * written for a narrow screen and then widened with `min-width` queries --
 * never the other way round. The two rules that follow from that:
 *
 *   * Navigation is **one drawer at every width**, opened by the hamburger.
 *     Below 900px it slides in over the page; above it, it is part of the
 *     layout and the same button collapses it out of the way. Every
 *     destination lives there exactly once, so nothing is offered twice and
 *     nothing is reachable only on one size of screen.
 *   * Every control is at least 44px tall, which is the smallest target a
 *     finger hits reliably, and text inputs are 16px so a phone browser does
 *     not zoom the page when one is focused.
 *
 * NO JAVASCRIPT. Every destination is a plain link and every form a plain POST,
 * and the drawer toggle only reveals what the page already carries: without the
 * script the drawer is on screen on a desktop and every page reaches its own
 * next steps (the account page carries Access and the way out).
 *
 * Autoplaying video is a plain <video> element, and `prefers-reduced-motion`
 * swaps the hero video for its poster image rather than trying to pause it.
 * The hero video is also dropped below 900px: it is the single largest asset
 * on the site and most of the visitors who would load it are on a metered
 * connection.
 */

:root {
  /* Apex-only tokens. Everything else comes from studio.css (:root), which
   * loads first. (The `--tabbar-*` pair that lived here went with the bottom
   * bar; nothing clears a fixed bar any more, so there is nothing to state.) */
}

/* --- Accents ------------------------------------------------------------ */
/* One colour per app, plus the states that already carry one. A class here
 * only *declares* the colour, through three custom properties, and the
 * component rules below read it back -- so a single class tints a chip, a pill,
 * a hero badge or an app's mark without a paired selector for each. It is the
 * same trick HaughtStuff uses for its kind chips (persona purple, skill gold,
 * connector blue), and it is what turns a page of pills from a row of grey
 * labels into a set of families.
 *
 * The apps keep the colour they carry everywhere else: HaughtStudio the brand
 * purple, HaughtCity the accent's blue, HaughtStuff the gold. Every tinted
 * surface is a *soft* wash behind coloured text rather than a saturated block,
 * so the page stays dark and the brand gradient stays reserved for the one
 * primary action -- the colour is louder than before, not the fill. */

.tint-studio { --tint: var(--purple-300); --tint-soft: rgba(169, 140, 240, 0.16); --tint-line: rgba(169, 140, 240, 0.34); }
.tint-city   { --tint: var(--accent-2);   --tint-soft: rgba(91, 154, 245, 0.16);  --tint-line: rgba(91, 154, 245, 0.34); }
.tint-stuff  { --tint: var(--gold);       --tint-soft: rgba(240, 194, 75, 0.15);  --tint-line: rgba(240, 194, 75, 0.36); }
.tint-ok     { --tint: var(--ok);         --tint-soft: rgba(70, 177, 123, 0.15);  --tint-line: rgba(70, 177, 123, 0.36); }
.tint-warn   { --tint: var(--warn);       --tint-soft: rgba(226, 163, 60, 0.15);  --tint-line: rgba(226, 163, 60, 0.38); }
.tint-danger { --tint: var(--danger);     --tint-soft: rgba(229, 72, 77, 0.14);   --tint-line: rgba(229, 72, 77, 0.36); }

/* --- App shell: one drawer, every width --------------------------------- */
/* The drawer is the whole navigator, on a phone and on a desktop. Below 900px
 * studio.css parks it off-canvas and slides it in for `body.drawer-open`; above
 * that it is in the layout, and `body.drawer-collapsed` takes it out again so
 * the content gets the window width. Both states are driven by the same
 * hamburger in the top bar -- see `static/js/drawer.js` -- so there is one
 * control to learn rather than two navigators to keep in step. */

/* The hamburger is the one control that is always present. It was hidden above
 * 900px while the sidebar was permanently on screen; now it is how the sidebar
 * is put away, so it is drawn at every width. It is a `<label>` for the
 * hidden checkbox at the top of `<body>`, so it opens the drawer with no
 * script at all. */
#hamburger {
  display: inline-grid;
  width: 40px;
  height: 40px;
  place-items: center;
  border: 0;
  border-radius: 10px;
  background: transparent;
  color: var(--text-dim);
  cursor: pointer;
  flex: 0 0 auto;
}
#hamburger .icon { width: 22px; height: 22px; }
#hamburger:hover { background: rgba(255, 255, 255, 0.07); color: var(--text); }
#hamburger:active { background: rgba(255, 255, 255, 0.06); color: var(--text); }

/* The checkbox is visually hidden but still the thing a keyboard focuses, so
 * its ring has to be drawn on the label the eye can see. */
.drawer-toggle:focus-visible ~ .main #hamburger {
  outline: 2px solid var(--purple-300);
  outline-offset: 2px;
}

/* Collapsing the sidebar gives the whole window to the page. `display: none`
 * rather than a transform: the drawer is in flow here, so a transform would
 * leave its column behind as an empty gutter. */
@media (min-width: 901px) {
  body.drawer-collapsed .drawer { display: none; }
}

/* The close control lives inside the drawer (top-right), not on the top bar,
 * so it stays reachable after the drawer slides over the bar that opened it.
 * Like the hamburger it is a label, so it closes the drawer without a script.
 * It is a phone-only convenience: on a desktop the drawer sits beside the
 * topbar, whose hamburger is still in reach. */
.drawer-close {
  display: none;
  position: absolute;
  top: 8px;
  right: 8px;
  width: 40px;
  height: 40px;
  place-items: center;
  border: 0;
  border-radius: 10px;
  background: transparent;
  color: var(--text-dim);
  cursor: pointer;
}
.drawer-close .icon { width: 20px; height: 20px; }
.drawer-close:hover { background: rgba(255, 255, 255, 0.07); color: var(--text); }
.drawer-close:active { background: rgba(255, 255, 255, 0.06); color: var(--text); }

.drawer-scrim { display: none; }

@media (max-width: 900px) {
  .drawer-close { display: inline-grid; }
  .drawer-scrim {
    position: fixed;
    inset: 0;
    z-index: 85; /* below the drawer (90) */
    background: rgba(0, 0, 0, 0.52);
  }
  /* studio.css parks the drawer off-canvas and has no rule of its own for
   * revealing it without a script, so the checked checkbox does that here.
   * The scrim is a label for the same checkbox, which is what makes tapping
   * outside close the drawer with scripting off. */
  .drawer-toggle:checked ~ .drawer { transform: none; }
  .drawer-toggle:checked ~ .drawer-scrim { display: block; }
}

/* --- Navigation metrics, matched to HaughtStuff ------------------------- */
/* The drawer, top bar and nav rows here were the older, roomier set from the
 * Studio design system; HaughtStuff (`static/css/app.css`) tightened them. The
 * two apps share the same chrome -- a visitor moves between them through the
 * drawer and the brand mark -- so a 16px difference in sidebar width, or 2px in
 * every row, makes the pair read as two different products.
 *
 * The values below are copied from HaughtStuff's stylesheet. studio.css is left
 * alone on purpose: it is a verbatim copy of HaughtStudio's stylesheet, so an
 * edit there would be overwritten by the next copy and would push the change
 * onto a deployment that did not ask for it. This is the Apex layer, and this
 * block is the whole of the divergence -- delete it and the old metrics return.
 *
 * The two shell tokens come first: every rule below is measured against them,
 * and `--drawer-w` also sizes the drawer on a phone
 * (`width: min(86vw, var(--drawer-w))` in studio.css). */
:root {
  --drawer-w: 256px;  /* was 272px */
  --topbar-h: 52px;   /* was 56px */
}

.brand {
  padding: 12px 12px 10px;   /* was 14px 14px 12px */
  /* The brand is an anchor here and a plain block in HaughtStuff's drawer, so
   * without this the name carries a link underline there is nothing to click
   * *to* -- it already points at the page you are on when you open the drawer. */
  text-decoration: none;
}

.drawer-body {
  padding: 0 9px 12px;       /* was 0 10px 16px */
}

.drawer-foot {
  padding: 9px;              /* was 10px */
}

.nav-row {
  gap: 10px;                 /* was 11px */
  padding: 7px 10px;         /* was 9px 11px */
  /* A nav row is an anchor here and a button in HaughtStuff's drawer. Both are
   * drawn as the same pill, so the underline a browser gives an anchor is
   * removed -- the `.active` background is what says which row you are on. */
  text-decoration: none;
}

.section-label {
  margin: 14px 10px 5px;     /* was 18px 11px 7px */
}

/* The brand tile is the placeholder logo over the gradient, which stays as the
 * fallback for when the image has not loaded. */
.brand-mark {
  background: var(--grad);
}
.brand-text { display: flex; flex-direction: column; }

/* The topbar's brand is the phone's page identity; above 900px the sidebar
 * already states it, so the bar shows the page title there instead. */
.topbar-brand {
  display: flex;
  align-items: center;
  gap: 9px;
  text-decoration: none;
  color: var(--text);
  flex: 0 0 auto;
  min-width: 0;
  /* Stretch to the bar's full height so the whole corner is the tap target,
   * not just the 28px of mark and wordmark inside it. */
  align-self: stretch;
}
.topbar-brand .brand-mark { width: 28px; height: 28px; flex-basis: 28px; border-radius: 9px; }
.topbar-brand-name {
  font-weight: 700;
  font-size: 0.9375rem;
  letter-spacing: -0.01em;
  white-space: nowrap;
}
.topbar-title { display: none; }
.topbar-account {
  max-width: 34vw;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  display: block;
}

@media (min-width: 901px) {
  .topbar-brand { display: none; }
  .topbar-title { display: block; }
  .topbar-account { max-width: none; }
}

/* On a phone the bar holds three things in 360px: the hamburger, the brand and
 * the handle. The email was a fourth, and the account page states it anyway, so
 * it is the one that goes. */
@media (max-width: 900px) {
  .topbar-account { display: none; }
}

.drawer-foot .btn { width: 100%; }

/* The last row of the drawer: the way out of the account, under a rule rather
 * than in the nav, where it used to sit among the legal pages. It is a link
 * rather than a second button because the foot holds one action and this is the
 * exit beside it. */
.drawer-exit {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 44px;
  margin-top: 10px;
  border-top: 1px solid var(--line);
  color: var(--text-faint);
  font-size: 0.8125rem;
  text-decoration: none;
}
.drawer-exit:hover, .drawer-exit:focus-visible { color: var(--danger); }

/* The active nav row keeps Studio's fill but gains the brand wash, so "where am
 * I" is answered by colour as well as by a slightly lighter box. No rail down
 * the left edge: the wash already says which row it is, and the inset stripe
 * read as a border on the drawer rather than on the row. */
.nav-row.active {
  background: var(--grad-soft);
  color: var(--text);
}
.nav-row.active .icon { color: var(--purple-300); opacity: 1; }

/* Pages draw their own full-width sections; inside the fixed-width detail pane
 * the marketing `.wrap` wrappers would add a second, narrower gutter. */
.view-inner .wrap { max-width: none; padding-inline: 0; }
.view-inner .panel-page { padding: 0; }

/* --- Base type ---------------------------------------------------------- */

h1, h2, h3, h4 { margin: 0 0 0.5em; font-weight: 650; letter-spacing: -0.01em; line-height: 1.2; }
h1 { font-size: clamp(1.6rem, 4.4vw, 2.05rem); }
h2 { font-size: clamp(1.25rem, 3vw, 1.6rem); }
h3 { font-size: 1.15rem; }
p { margin: 0 0 1rem; }

/* A page's own heading block. Tighter than studio.css's default, because on a
 * phone the topbar sits directly above it and two large gaps read as a hole in
 * the page. */
.page-head { margin-bottom: 6px; }
.page-head h1 { font-size: clamp(1.5rem, 5vw, 1.75rem); }

/* Display type keeps Studio's heavy weight; the old editorial italic is gone. */
.display { font-weight: 650; letter-spacing: -0.02em; }
.display-xl {
  /* Sized in `rem` with a `vw` crutch: on a 360px phone the headline still fits
   * four words to a line rather than one. */
  font-size: clamp(1.95rem, 8vw, 3.1rem);
  font-weight: 700;
  letter-spacing: -0.03em;
  line-height: 1.05;
  margin: 0 0 0.55em;
  max-width: 22ch;
}
.display, .display-xl { text-wrap: balance; }

a:hover { text-decoration: none; }

code {
  font-family: var(--mono);
  font-size: 0.9em;
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: 6px;
  padding: 0.1em 0.4em;
}

.narrow { max-width: 640px; }
.muted { color: var(--text-dim); }
.small { font-size: 0.875rem; }
.mono { font-family: var(--mono); }

.skip-link {
  position: absolute; left: -9999px; top: 0;
  background: var(--purple-500); color: #fff;
  padding: 0.5rem 1rem; z-index: 100;
  border-radius: 0 0 8px 0;
}
.skip-link:focus { left: 0; }

/* --- Buttons ------------------------------------------------------------ */
/* Mirrors studio.css `.btn`: the same surfaces, radius and gradient primary. */

.button {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  padding: 0.7rem 1.1rem;
  border: 1px solid var(--line-strong);
  border-radius: 11px;
  background: var(--card-2);
  color: var(--text);
  font: inherit; font-size: 0.9375rem; font-weight: 550;
  text-decoration: none; cursor: pointer;
  /* A button label is one line. Wrapping it turns the control into a blob. */
  white-space: nowrap;
  transition: background 0.15s ease, filter 0.15s ease, transform 0.15s ease;
}
.button:hover { background: var(--card-3); }
.button:active { transform: translateY(1px); }

/* One rule, not a per-component one: nothing a finger has to hit is smaller
 * than this. */
@media (max-width: 900px) {
  .button, .btn { min-height: 44px; }
}

.button-primary {
  background: var(--grad); border-color: transparent; color: #fff;
  font-weight: 650;
  box-shadow: 0 8px 22px rgba(110, 90, 230, 0.25);
}
.button-primary:hover { filter: brightness(1.06); }

.button-quiet { background: transparent; border-color: transparent; color: var(--text-dim); }
.button-quiet:hover { background: rgba(255, 255, 255, 0.05); color: var(--text); }

.button-danger { border-color: rgba(229, 72, 77, 0.35); color: var(--danger); background: rgba(229, 72, 77, 0.08); }
.button-danger:hover { background: rgba(229, 72, 77, 0.16); }

.button-large { padding: 0.9rem 1.5rem; font-size: 1rem; border-radius: var(--radius); }
.button-block { display: flex; width: 100%; }

/* For a control that sits inside a row of its own (a key's Revoke), where the
 * default size would dominate the content beside it. Only the padding and type
 * shrink: the 44px minimum under 900px still applies. */
.button-small { padding: 0.45rem 0.8rem; font-size: 0.875rem; border-radius: 9px; }

.button-row { display: flex; gap: 0.75rem; flex-wrap: wrap; align-items: center; }
.inline-form { display: inline-flex; align-items: flex-end; gap: 0.5rem; flex-wrap: wrap; margin: 0; }

/* The connector's price: one number, so the field does not need the row. */
.mcp-cost { margin-top: 1.25rem; padding-top: 1.1rem; border-top: 1px solid var(--line); }
.mcp-cost .inline-form { align-items: center; }
.mcp-cost label { margin-right: 0.15rem; }
.mcp-cost input[type="number"] { width: auto; min-width: 7rem; }

/* One server's card. It borrows ``.card`` for the surface and overrides only
 * what the access page needs: the same padding as the account page's setting
 * cards, so the page does not switch card languages between "your key" and
 * "your servers", and a hairline above the price control to separate a
 * different kind of action from the credential buttons above it. */
.mcp-card { padding: 18px 20px; gap: 0; }
.mcp-card + .mcp-card { margin-top: 0.9rem; }

/* The server's name and its state on one line: "is this working" is the first
 * thing the card answers, and a fact row of its own for a single pill spent a
 * whole line doing it. */
.mcp-card-head {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.6rem;
  margin-bottom: 0.25rem;
}
.mcp-card-head h3 { margin: 0; font-size: 1.05rem; }

/* What the actions on a card do. A list rather than a paragraph: two or three
 * outcomes read faster as lines, and the destructive one gets named in the same
 * breath as the safe one instead of being buried mid-sentence. */
.cred-hints {
  list-style: none;
  margin: 0.9rem 0 0;
  padding: 0;
  display: grid;
  gap: 0.35rem;
  color: var(--text-dim);
  font-size: 0.875rem;
  line-height: 1.5;
}
.cred-hints li { position: relative; padding-left: 0.95rem; }
.cred-hints li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.62em;
  width: 4px;
  height: 4px;
  border-radius: 50%;
  background: var(--line-strong);
}
.cred-hints strong { color: var(--text); font-weight: 600; }

/* An action group: side by side when there is room, stacked and full width
 * when there is not, which is the case on every phone. */
.action-group { display: flex; flex-direction: column; gap: 0.6rem; align-items: stretch; }
.action-group .button { width: 100%; }
@media (min-width: 620px) {
  .action-group { flex-direction: row; flex-wrap: wrap; align-items: center; }
  .action-group .button { width: auto; }
}

/* --- Text bits ---------------------------------------------------------- */

.eyebrow {
  text-transform: uppercase; letter-spacing: 0.14em;
  font-size: 0.7rem; font-weight: 650;
  color: var(--tint, var(--purple-300)); margin: 0 0 0.9rem;
}

.lede { font-size: 1.0625rem; color: var(--text-dim); max-width: 62ch; }

.tick-list { list-style: none; margin: 0 0 1.25rem; padding: 0; }
.tick-list li { position: relative; padding-left: 1.5rem; margin-bottom: 0.4rem; color: var(--text-dim); }
.tick-list li::before { content: "\2713"; position: absolute; left: 0; color: var(--ok); font-weight: 700; }

/* Numbered instructions, where the order is the point -- the key page's
 * "copy this, then paste it there". */
.steps { margin: 1.15rem 0 0; padding-left: 1.25rem; color: var(--text-dim); }
.steps li { margin-bottom: 0.4rem; }

.prose p, .prose li { max-width: 68ch; }
.prose h2 { margin-top: 2rem; }

/* --- Notices ------------------------------------------------------------ */

.notice {
  border: 1px solid var(--line);
  border-left: 3px solid var(--purple-500);
  background: var(--card);
  border-radius: var(--radius-sm);
  padding: 0.9rem 1.1rem;
  margin: 1.25rem 0;
}
.notice p:last-child { margin-bottom: 0; }
.notice-warn { border-left-color: var(--warn); }
.notice-good { border-left-color: var(--ok); }

.key-value {
  word-break: break-all;
  background: var(--bg);
  padding: 0.6rem 0.75rem;
  border-radius: var(--radius-sm);
  border: 1px solid var(--line-strong);
  font-family: var(--mono);
}

/* --- Hero --------------------------------------------------------------- */

.hero {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  padding: 2rem 0 1.75rem;
  border-bottom: 1px solid var(--line);
}

.hero-bg { position: absolute; inset: 0; z-index: -1; }

/* The looping video is decorative; its <source> file is a placeholder
 * (static/video/hero_loop.mp4) and is replaced with real footage later. */
.hero-video {
  width: 100%; height: 100%;
  object-fit: cover;
  opacity: 0.30;
}

/* On a phone the video is replaced by its poster, as a still. It is the
 * largest asset on the site, most visitors are on a metered connection, and a
 * muted loop behind a scrim is texture either way -- so the bandwidth buys
 * nothing there. Above 900px the motion is worth having. */
@media (max-width: 900px) {
  .hero-video { display: none; }
  .hero-bg {
    background: url("../img/logo_placeholder_hero.6dcddc2865e5.png") center / cover no-repeat;
  }
}

/* Three passes: fade into the page at the bottom, hold the text column dark on
 * the left, and add one soft brand glow (the Studio gradient's endpoints). */
.hero-scrim {
  position: absolute; inset: 0;
  background:
    linear-gradient(180deg, rgba(11, 9, 18, 0.35) 0%, rgba(11, 9, 18, 0.86) 60%, var(--bg) 100%),
    linear-gradient(90deg, rgba(11, 9, 18, 0.85) 0%, rgba(11, 9, 18, 0.25) 65%, transparent 100%),
    radial-gradient(40rem 30rem at 20% 20%, rgba(124, 92, 230, 0.24), transparent 70%);
}
/* A still backdrop needs more scrim than a moving one, or the headline fights
 * the image behind it. */
@media (max-width: 900px) {
  .hero-scrim {
    background:
      linear-gradient(180deg, rgba(11, 9, 18, 0.72) 0%, rgba(11, 9, 18, 0.92) 55%, var(--bg) 100%),
      radial-gradient(34rem 26rem at 25% 15%, rgba(124, 92, 230, 0.30), transparent 70%);
  }
}

.hero-inner { max-width: 760px; }
.hero-actions { display: flex; flex-direction: column; gap: 0.6rem; margin: 1.5rem 0 0; }
.hero-actions .button { width: 100%; }

@media (min-width: 620px) {
  .hero-actions { flex-direction: row; flex-wrap: wrap; }
  .hero-actions .button { width: auto; }
}

.hero-badges {
  display: flex; flex-wrap: wrap; gap: 0.5rem;
  list-style: none; margin: 1.5rem 0 0; padding: 0;
}
.hero-badges li {
  font-size: 0.8125rem; font-weight: 550;
  padding: 0.3rem 0.75rem;
  border: 1px solid var(--tint-line, var(--line));
  border-radius: 999px;
  background: var(--tint-soft, var(--card-2));
  color: var(--tint, var(--text-dim));
}

@media (min-width: 820px) {
  .hero { padding: 3.5rem 0 3rem; }
}

/* A jump nav for the marketing sections. On a phone it is one swipeable row
 * rather than three wrapped lines of chips: a horizontal scroller keeps the
 * section names on one visual line, which is the whole point of a jump nav. */
.section-nav {
  display: flex;
  gap: 0.5rem;
  list-style: none;
  margin: 0 0 1.75rem;
  padding: 6px 0 2px;
  overflow-x: auto;
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior-x: contain;
}
.section-nav::-webkit-scrollbar { display: none; }
/* A jump-nav chip is a tap target, not a label, so it gets the same 44px floor
 * as every other control -- and the extra padding gives the finger something to
 * aim at now that the row scrolls. */
.section-nav .chip {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding-inline: 1rem;
  font-size: 0.875rem;
}

/* No motion allowed: drop the video and show its poster as a still backdrop. */
@media (prefers-reduced-motion: reduce) {
  .hero-video { display: none; }
  .hero-bg {
    background: url("../img/logo_placeholder_hero.6dcddc2865e5.png") center / cover no-repeat;
  }
}

/* --- Sections ----------------------------------------------------------- */

.section { padding: 2.5rem 0; border-bottom: 1px solid var(--line); }
/* An inset panel. The inline padding is smaller than the page gutter on a
 * phone, because the panel already sits inside that gutter and two of them
 * together would leave the text on a very narrow column. */
.section-alt {
  background: var(--surface);
  border-radius: var(--radius-lg);
  padding-block: 2rem;
  padding-inline: 1rem;
}
.section-head { max-width: 62ch; margin-bottom: 1.75rem; }
.section-head .lede { margin-bottom: 0; }

@media (min-width: 820px) {
  .section { padding: 4.5rem 0; }
  .section-alt { padding-block: 3.5rem; padding-inline: 1.5rem; }
  .section-head { margin-bottom: 2.5rem; }
}

/* --- Bento grid --------------------------------------------------------- */
/* One column on a phone, which is the whole grid. It widens in steps rather
 * than being shrunk from a desktop layout. */

.bento {
  display: grid;
  grid-template-columns: 1fr;
  gap: 0.875rem;
}

.tile {
  position: relative;
  display: flex; flex-direction: column; gap: 1rem;
  padding: 1.25rem;
  border-radius: var(--radius-lg);
  border: 1px solid var(--line);
  background: var(--card);
  box-shadow: var(--shadow);
  overflow: hidden;
}

.tile-media {
  border-radius: var(--radius);
  overflow: hidden;
  border: 1px solid var(--line);
  background: var(--bg);
  aspect-ratio: 16 / 10;
}
.tile-media video,
.tile-media img { display: block; width: 100%; height: 100%; object-fit: cover; }

/* As with the hero: a looping video is texture, and on a phone the still says
 * the same thing without the decoding cost. Each tile names its own poster,
 * because the video element's `poster` attribute goes away with it. */
@media (max-width: 900px) {
  .tile-media video { display: none; }
  .tile-media-studio { background: url("../img/logo_placeholder_studio.6dcddc2865e5.png") center / cover no-repeat; }
}

.tile-body { display: flex; flex-direction: column; justify-content: center; flex: 1; }
.tile-kicker {
  text-transform: uppercase; letter-spacing: 0.13em;
  font-size: 0.68rem; font-weight: 650; color: var(--tint, var(--purple-300));
  margin: 0 0 0.5rem;
}
.tile-title { font-size: 1.2rem; margin: 0 0 0.4rem; font-weight: 650; letter-spacing: -0.01em; }
.tile-text { color: var(--text-dim); font-size: 0.9375rem; margin: 0; }

.tile-accent {
  border-color: var(--tint-line, rgba(139, 92, 246, 0.5));
  background:
    radial-gradient(24rem 14rem at 85% -20%, var(--tint-soft, rgba(124, 92, 230, 0.16)), transparent 70%),
    var(--card);
  box-shadow: 0 0 0 1px var(--tint-soft, rgba(139, 92, 246, 0.22)), var(--shadow);
}

.chips { display: flex; flex-wrap: wrap; gap: 0.5rem; list-style: none; margin: 0.25rem 0 0; padding: 0; }
.chip {
  padding: 0.3rem 0.75rem;
  border-radius: 999px;
  border: 1px solid var(--tint-line, var(--line));
  background: var(--tint-soft, var(--card-2));
  font-size: 0.8125rem; color: var(--tint, var(--text-dim));
}
a.chip { text-decoration: none; }
a.chip:hover { border-color: var(--tint, var(--line-strong)); color: var(--tint, var(--text)); }

/* Tablet: two columns. */
@media (min-width: 700px) {
  .bento { grid-template-columns: repeat(2, 1fr); }
  .span-3, .span-4, .span-6 { grid-column: span 2; }
}

/* Desktop: six columns, so tiles can be 1/6, 1/3, 1/2 or 2/3 wide. */
@media (min-width: 1000px) {
  .bento { grid-template-columns: repeat(6, 1fr); gap: 1.25rem; }
  .span-2 { grid-column: span 2; }
  .span-3 { grid-column: span 3; }
  .span-4 { grid-column: span 4; }
  .span-6 { grid-column: span 6; }
  .tile { padding: 1.6rem; }
}

/* --- Pricing ------------------------------------------------------------ */
/* The three tiers are one column on a phone, so each reads top to bottom
 * without a horizontal scroll, and the recommended one is marked by more than
 * position alone. */

.pricing { padding: 2.5rem 0; border-bottom: 1px solid var(--line); }

.plan-grid {
  display: grid; grid-template-columns: 1fr;
  gap: 1rem; margin: 1.75rem 0 1rem;
}

.plan {
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  background: var(--card);
  padding: 1.35rem;
  display: flex;
  flex-direction: column;
}
.plan h3 { font-size: 1.05rem; margin: 0; }
.plan-price { font-size: 2rem; font-weight: 700; letter-spacing: -0.02em; margin: 0.35rem 0 0.15rem; }
.plan-price .plan-period { font-size: 0.875rem; font-weight: 550; color: var(--text-dim); letter-spacing: 0; }
.plan-note { color: var(--text-dim); font-size: 0.9375rem; margin: 0 0 1.1rem; }
.plan .tick-list { flex: 1; }
/* The action sits on the card's bottom edge whatever the list lengths are, so
 * the three buttons line up on a desktop. */
.plan-action { margin-top: 0.25rem; }

.plan-badge {
  display: inline-flex; align-items: center; align-self: flex-start;
  font-size: 0.7rem; text-transform: uppercase;
  letter-spacing: 0.12em; font-weight: 650; margin: 0 0 0.6rem;
  padding: 0.22rem 0.6rem; border-radius: 999px;
  color: var(--tint, var(--purple-300));
  background: var(--tint-soft, transparent);
  border: 1px solid var(--tint-line, transparent);
}
/* The recommended tier wears the brand gradient, the one other place besides a
 * primary action where it is allowed -- and the reason the card reads as the
 * destination rather than the third of three. */
.plan-badge-grad {
  background: var(--grad);
  border-color: transparent;
  color: #fff;
}
.plan-featured {
  border-color: rgba(139, 92, 246, 0.5);
  background:
    radial-gradient(26rem 15rem at 85% -15%, rgba(124, 92, 230, 0.20), transparent 70%),
    var(--card);
  box-shadow: 0 30px 70px -40px rgba(139, 92, 246, 0.9);
}
.pricing-note { margin-top: 1rem; }

@media (min-width: 820px) {
  .pricing { padding: 4.5rem 0; }
}
@media (min-width: 860px) {
  .plan-grid { grid-template-columns: repeat(3, 1fr); gap: 1.25rem; }
  .plan { padding: 1.6rem; }
  /* The signup chooser offers two of the three tiers, so the same grid runs at
   * two columns rather than leaving a third empty. */
  .plan-grid-two { grid-template-columns: repeat(2, 1fr); }
}

/* --- Closing ------------------------------------------------------------ */

.closing { padding: 2.5rem 0 3rem; }
.closing-inner { max-width: 640px; }

/* --- Cards and lists ---------------------------------------------------- */

.card-grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: 1.25rem; margin: 1.5rem 0;
}

.card {
  border: 1px solid var(--line); border-radius: var(--radius);
  background: var(--card); padding: 1.5rem;
  display: flex; flex-direction: column;
}
.card h2 { font-size: 1.2rem; margin-bottom: 0.25rem; }
.card .button { margin-top: auto; align-self: flex-start; }
/* A locked card is dimmed but still readable: the user needs to know what they
 * are missing in order to want it. */
.card-locked { opacity: 0.72; }

/* One MCP server on the connectors page, folded into a summary row. The row
 * carries the name and the state of that server's key, so a list of servers
 * can be scanned for the one needing attention without opening each in turn --
 * the same job the state pills do on the account page. The list owns the
 * spacing between cards so a single connector has the same margin whether or
 * not there are others. */
.connector-list {
  display: grid;
  gap: 1rem;
  margin: 1rem 0;
}
.connector {
  margin: 0;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--card);
}
/* A connector borrows `.disclosure` for the chevron and the fold behaviour, but
 * it is a bordered card, not a bare section heading: its summary needs the
 * card's inner padding, not the section-heading padding. This selector is
 * deliberately more specific than `.disclosure > summary`, which is declared
 * later in this file and would otherwise flatten the padding back out. */
.disclosure.connector > summary { padding: 0.85rem 1rem; }
/* The name and its pill travel together on the left; the chevron already owns
 * the right-hand end of the row (see .disclosure > summary::after). */
.connector-head {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.6rem;
  min-width: 0;
}
.connector-head h3 { margin: 0; font-size: 1.0625rem; }
.connector-body { padding: 0 1rem 1rem; }
/* The rule above the facts moved to the summary, so the body opens straight
 * onto the values rather than onto a second divider. */
.connector-body .facts { margin-top: 0; }

/* The "New connector" control and the form it opens. The control is a <summary>
 * wearing `.button`, so it looks like a button and still opens with scripting
 * off; the panel below is a card, matching a connector's shape. */
.connector-create { margin: 0.25rem 0 1rem; }
/* `.disclosure > summary` is a section heading. This one is a button, so its
 * padding and alignment are overridden rather than inherited. */
.disclosure.connector-create > summary {
  display: inline-flex;
  justify-content: flex-start;
  padding: 0.7rem 1.1rem;
}
.disclosure.connector-create > summary::after {
  width: 8px; height: 8px;
  border-right: 2px solid currentColor;
  border-bottom: 2px solid currentColor;
  transform: rotate(45deg) translate(-1px, -1px);
}
.disclosure.connector-create[open] > summary::after {
  transform: rotate(-135deg) translate(-1px, -1px);
}
.connector-create-body {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--card);
  padding: 1rem;
  margin-top: 0.85rem;
}
.connector-form { display: flex; flex-direction: column; gap: 1rem; margin: 0; }
.connector-create-body .notice { margin: 0 0 1rem; }
.connector-publish { margin-top: 0.25rem; }
.connector-publish-copy strong { display: block; }
.connector-publish-copy .hint { display: block; margin-top: 2px; }

.locked-reason { color: var(--warn); font-size: 0.9375rem; margin: 1rem 0 0; }

/* --- Apps list ---------------------------------------------------------- */
/* Each app is its own card: an icon, its copy, the features the plan grants,
 * and a single action. On a phone the action drops to its own full-width line,
 * because a gradient button sharing a row with two lines of text is a target
 * nobody can hit accurately. */

.list.apps-list {
  border: 0;
  background: transparent;
  overflow: visible;
  display: grid;
  gap: 12px;
}
.apps-list .list-row {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--card);
}
.apps-list .list-row:hover { background: var(--card); }
/* The row is colour-coded by app, so the list reads as three families rather
 * than three identical cards. The rule is drawn as a left edge -- a stripe of
 * colour down the near side -- rather than a wash across the whole card, which
 * would fight the text on top of it. */
.apps-list .app-row { border-left: 3px solid var(--tint, var(--line)); }

.app-row {
  flex-wrap: wrap;
  gap: 14px;
  padding: 18px;
  cursor: default;
  align-items: flex-start;
}
.app-row .avatar {
  color: var(--tint, var(--purple-300));
  background: var(--tint-soft, var(--card-3));
  border: 1px solid var(--tint-line, var(--line));
}
.app-row .list-row-main { display: flex; flex-direction: column; gap: 5px; flex: 1 1 60%; min-width: 0; }
.app-row .list-row-title { font-size: 1.0625rem; }
/* The whole action line, so the button is not squeezed beside the copy. */
.app-row .list-row-end { flex: 1 1 100%; }
.app-row .list-row-end .button { width: 100%; }

@media (min-width: 760px) {
  .app-row { padding: 18px 20px; align-items: center; flex-wrap: nowrap; }
  .app-row .list-row-end { flex: 0 0 auto; }
  .app-row .list-row-end .button { width: auto; }
}

.app-features { margin: 6px 0 0; }
.app-features .chip { gap: 9px; }
/* A granted capability and one behind the paywall are the two states worth
 * telling apart at a glance, so each chip wears its own colour and the word
 * after it dims to the same hue. */
.app-features .chip.on {
  color: var(--ok);
  background: rgba(70, 177, 123, 0.13);
  border-color: rgba(70, 177, 123, 0.34);
}
.app-features .chip.off {
  color: var(--warn);
  background: rgba(226, 163, 60, 0.13);
  border-color: rgba(226, 163, 60, 0.34);
}
.app-features .chip .state { color: inherit; opacity: 0.72; font-size: 0.75rem; }

.app-row .locked-reason { margin: 8px 0 0; }

.feature-states { list-style: none; margin: 1rem 0 1.25rem; padding: 0; font-size: 0.9375rem; }
.feature-states li {
  display: flex; justify-content: space-between; gap: 1rem;
  padding: 0.55rem 0; border-bottom: 1px solid var(--line);
}
.feature-states li:last-child { border-bottom: 0; }
.feature-states .state { color: var(--text-dim); font-size: 0.875rem; white-space: nowrap; }
.feature-states li.on .state { color: var(--ok); }
.feature-states li.off .state { color: var(--text-dim); }

/* --- Account page ------------------------------------------------------- */

/* Account sections: a consistent gap above each block, so a heading never
 * collides with the content above it. */
.acct-section { margin-top: 2rem; }
.acct-section > h2 { margin: 0 0 1rem; }
.acct-section > .page-lede { margin-top: 0; margin-bottom: 1.25rem; }

/* A section that folds away. The account page is long, and on a phone that
 * means a lot of scrolling to reach the one thing being looked for; every
 * section starts closed so the page opens as a short list of headings. The
 * browser reveals a closed section by itself when a link points inside it, so
 * a jump link still lands on its target. */
.disclosure > summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  min-height: 44px;
  padding: 0.35rem 0;
  cursor: pointer;
  list-style: none;
}
.disclosure > summary::-webkit-details-marker { display: none; }
.disclosure > summary > h2 {
  margin: 0;
  font-size: clamp(1.2rem, 3vw, 1.45rem);
}
.disclosure > summary::after {
  content: "";
  flex: 0 0 auto;
  width: 10px; height: 10px;
  border-right: 2px solid var(--text-faint);
  border-bottom: 2px solid var(--text-faint);
  transform: rotate(45deg) translate(-2px, -2px);
  transition: transform 0.18s ease;
}
.disclosure[open] > summary::after { transform: rotate(-135deg) translate(-2px, -2px); }
.disclosure > summary:focus-visible { outline: 2px solid var(--purple-500); outline-offset: 2px; border-radius: 8px; }

/* One column on a phone. The auto-fit grid only earns its keep once two
 * columns of real content fit side by side. */
.split {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1.25rem;
  align-items: start;
  margin: 0;
}
@media (min-width: 780px) {
  .split { grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); }
}

/* A card that follows a ``.split`` sits outside its grid, so the gap the split
 * uses between its own children does not reach it and it would abut the row
 * above with no space at all. The same value is restated here rather than
 * wrapped in a second container, so the two card groups read as one rhythm. */
.split + .setting-card { margin-top: 1.25rem; }

/* Cards in the account grid: stacked on a phone, with the trailing control
 * beside the text once there is room for both. */
.setting-card { align-items: stretch; gap: 14px; padding: 16px; }
.setting-card > .body > :first-child { margin-top: 0; }
.setting-card > .body > :last-child { margin-bottom: 0; }
.setting-card .button-row { flex: 0 0 auto; margin: 0; }
.setting-card .button-row .button { width: 100%; }

@media (min-width: 620px) {
  .setting-card { align-items: center; gap: 20px; padding: 18px 20px; }
  .setting-card .button-row .button { width: auto; }
}

.facts { margin: 0.25rem 0 0.75rem; }
.facts dt {
  font-size: 0.8125rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-faint);
  margin-top: 1rem;
}
/* The first label sits under whatever introduced it -- a card heading or a
 * border -- so it must not also carry the gap that separates two facts. */
.facts > dt:first-of-type { margin-top: 0; }
.facts dd { margin: 0.3rem 0 0; }
/* Two facts in a row (an address and a key) read as one block, not as two
 * paragraphs with a hole between them. */
.facts dd + dt { margin-top: 0.9rem; }

.empty-state {
  border: 1px dashed var(--line-strong);
  border-radius: var(--radius);
  padding: 16px 18px;
  margin: 0 0 1.25rem;
  color: var(--text-dim);
  font-size: 0.9375rem;
}

/* --- API keys ----------------------------------------------------------- */
/* A list rather than a table. Four columns of metadata do not fit a phone, and
 * a table that reflows into cards needs the same markup as a list anyway. */

.key-rows { list-style: none; margin: 0 0 1.25rem; padding: 0; display: grid; gap: 10px; }
/* One line, even on a phone: the row's identity (name + prefix + date) on the
 * left and its one control on the right. The control is ``.button-small``, so
 * it takes a name's width rather than the row's, and stacking the row to give
 * it a line of its own only made each key three lines tall for no gain. */
.key-row {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--card);
  padding: 12px 14px;
  display: flex;
  align-items: center;
  gap: 14px;
}
.key-row .key-row-main { flex: 1; min-width: 0; }
.key-row .key-name { font-weight: 600; font-size: 1rem; }
/* The prefix and the date are separate items so a narrow row wraps between them
 * instead of breaking the date in half. No separator character: a middot would
 * have to sit on a line of its own when the pair wraps, and the mono/spaced
 * distinction already reads as two facts. */
.key-row .key-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 0.15rem 0.5rem;
  align-items: baseline;
  color: var(--text-dim);
  font-size: 0.875rem;
}
.key-row .key-meta .mono { color: var(--text); }
.key-row form { margin: 0; flex: 0 0 auto; }
.key-row .button { width: auto; }

@media (min-width: 620px) {
  .key-row { padding: 14px 16px; gap: 18px; }
}

/* --- Account summary ---------------------------------------------------- */
/* The one card at the top of the account page: who you are, what you have, and
 * what to do about it, readable without scrolling past the fold. */

.acct-summary {
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  background:
    radial-gradient(28rem 16rem at 12% -20%, rgba(124, 92, 230, 0.20), transparent 70%),
    var(--card);
  padding: 1.25rem;
  margin-bottom: 0.5rem;
}
.acct-summary .acct-who {
  font-size: 0.9375rem;
  color: var(--text-dim);
  margin: 0 0 0.9rem;
  overflow-wrap: anywhere;
}
.acct-summary .acct-who strong { color: var(--text); font-weight: 600; }
.acct-summary .acct-tags { display: flex; flex-wrap: wrap; gap: 0.5rem; margin: 0 0 1rem; }

@media (min-width: 620px) {
  .acct-summary { padding: 1.5rem; }
}

/* A summary with nothing to act on below it is centred in the card: the
 * heading, the lede and the states stack as one column instead of a
 * left-aligned block with an empty right half. This is the phone's shape, and
 * on a phone it stays that shape. */
.acct-summary-center { text-align: center; }
.acct-summary-center .page-head { justify-content: center; }
.acct-summary-center .acct-tags { justify-content: center; }
/* The states are centred as pairs rather than spread: ``space-between`` over
 * the full column would strand each value at the right edge, reading as a
 * second column of figures when the rest of the card is one centred stack. */
.acct-summary-center .acct-status { margin-bottom: 0; max-width: none; }
.acct-summary-center .acct-status li { justify-content: center; }

/* The one action in that card, and the route to the access page on a phone:
 * Access is not one of the bar's four destinations, and the drawer that holds
 * it needs a script, so the account page is how it is reached without one. */
.acct-actions { justify-content: center; margin-top: 1.25rem; }

/* The account and access headers, once there is width for two columns.
 *
 * Stacked, each of these cards spent a band per fact -- who it is, the plan, a
 * line per credential state, the link out -- and stood taller than anything it
 * had to say. Side by side they read as one board: the account on the left,
 * the states it is being asked about on the right, each pair spread across its
 * own column so the values line up for comparison the way they cannot when
 * they are centred one under another.
 *
 * The centring above is what a card with an empty right half does to hide it.
 * The half is no longer empty here, so the text goes back to the edge it reads
 * from and the empty band under the states stops existing. ``acct-summary-main``
 * is the left column, a wrapper rather than loose children so the states stay
 * in the column they are pinned to.
 *
 * Only the two- and three-state headers take this mark: the usage and earnings
 * cards are one row of pills and have no second column to give. */
@media (min-width: 620px) {
  .acct-summary-board {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: start;
    column-gap: 2.5rem;
    text-align: left;
  }
  .acct-summary-board .page-head { justify-content: flex-start; }
  .acct-summary-board .acct-tags { justify-content: flex-start; }
  .acct-summary-board .acct-status { min-width: 14rem; max-width: 22rem; margin-top: 0.15rem; }
  .acct-summary-board .acct-status li { justify-content: space-between; }
  .acct-summary-board .acct-actions { justify-content: flex-start; margin-top: 1rem; }
}

/* The credential states in the header: "do I have a working key?" answered
 * without opening anything below it. */
.acct-status {
  list-style: none;
  margin: 0 0 1rem;
  padding: 0;
  display: grid;
  gap: 0.4rem;
  max-width: 28rem;
}
.acct-status li {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
  font-size: 0.9375rem;
}
.acct-status-name { color: var(--text-dim); }
.acct-status-state { font-weight: 550; }
.acct-status-state.is-ok { color: var(--ok); }
.acct-status-state.is-warn { color: var(--warn); }

/* One kind of credential inside the access page. Each is its own disclosure --
 * `.disclosure acct-section`, the account page's own -- so the three read as
 * siblings and fold away independently.
 *
 * The head is the first element *inside* the disclosure, and it is where the
 * section's ``id`` lives: a browser only auto-opens a closed disclosure when a
 * jump link points at an element inside its content, so the ``id`` can never
 * sit on the `<details>` itself or on its `<summary>`. */
.cred-sub-head {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.6rem;
  padding-bottom: 0.5rem;
  border-bottom: 1px solid var(--line);
  margin-bottom: 0.9rem;
  min-height: 1.9rem;
}
/* The state sits at the far end of the rule, so the three subsections can be
 * scanned for the one that needs attention. */
.cred-sub-head .pill { margin-left: auto; }
.cred-sub-head .muted { font-size: 0.875rem; }

/* A head that holds nothing but the pill has no rule to scan along, and a line
 * under a lone badge reads as a stray divider. ``:has`` is the only way to ask
 * "is this element empty apart from the pill" from CSS; a browser without it
 * leaves the rule, which is the same page it renders today. */
.cred-sub-head:has(> .pill:only-child) {
  border-bottom: 0;
  padding-bottom: 0;
  margin-bottom: 0.6rem;
  min-height: 0;
}
.cred-sub-note {
  color: var(--text-dim);
  font-size: 0.9375rem;
  max-width: 68ch;
  margin: 0 0 1rem;
}

/* --- A secret, shown masked --------------------------------------------- */
/* Reads as a password input: one bordered box holding the value and a reveal
 * control, with the copy action on its own full-width line below.
 *
 * The masked preview and the real value are both rendered by the server;
 * which one is visible is decided by a hidden checkbox, so the eye works with
 * scripting off. Only the copy button needs a script -- see
 * templates/partials/key_field.html. */

.key-display {
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  margin: 0.35rem 0 0.75rem;
}

.key-field {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  min-height: 48px;
  padding: 0.4rem 0.4rem 0.4rem 0.85rem;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-sm);
  background: var(--bg);
}

.key-text {
  flex: 1;
  min-width: 0;
  font-family: var(--mono);
  font-size: 0.8125rem;
  letter-spacing: 0.02em;
  color: var(--text);
  /* A 44-character key has no space to wrap at, so it has to be told where it
   * may break. */
  overflow-wrap: anywhere;
}

/* Exactly one of the two is shown, whichever way the checkbox is set. */
.key-secret { display: none; }
.key-toggle:checked ~ .key-field .key-preview { display: none; }
.key-toggle:checked ~ .key-field .key-secret { display: inline; }

.key-eye {
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  /* 44px, like every other control a finger has to hit. */
  width: 44px;
  height: 44px;
  border-radius: 9px;
  color: var(--text-dim);
  cursor: pointer;
}
.key-eye:hover { background: rgba(255, 255, 255, 0.06); color: var(--text); }

/* One icon or the other, never both: the eye is "reveal", the struck-through
 * eye is "hide what is currently showing". */
.key-eye .eye-hide { display: none; }
.key-toggle:checked ~ .key-field .key-eye .eye-show { display: none; }
.key-toggle:checked ~ .key-field .key-eye .eye-hide { display: block; }

/* The checkbox is off-screen, so the label has to carry the focus ring. Its
 * own `:focus-visible` never fires -- it is clipped, not hidden from the
 * keyboard. */
.key-toggle:focus-visible ~ .key-field .key-eye {
  outline: 2px solid var(--purple-500);
  outline-offset: 2px;
}

/* Full width and gradient on a phone. This is the one action anyone opens this
 * card to take, and on a phone it has to be unmissable. On a wider screen it
 * sits beside the value (see ``.key-display``) and takes its natural width, so
 * it stops reading as a banner across the card. */
.key-copy { width: 100%; }
.key-copy.is-copied {
  background: var(--ok);
  border-color: transparent;
  color: #06130c;
  box-shadow: none;
}
.key-copy.is-failed {
  background: var(--card-3);
  border-color: var(--line-strong);
  color: var(--warn);
  box-shadow: none;
}

/* One line once there is room: the masked value and the copy control side by
 * side, which is the shape a password manager taught everyone to expect. Below
 * this the copy button keeps its full width, because on a phone it is the
 * action the card exists for and it has to be unmissable.
 *
 * The row rules live *here*, after the base rules above, rather than beside
 * ``.key-display``: a media query does not add specificity, so a later
 * ``width: 100%`` would beat this one on source order. */
@media (min-width: 560px) {
  .key-display { flex-direction: row; align-items: stretch; }
  .key-field { flex: 1; }
  .key-copy { width: auto; flex: 0 0 auto; min-width: 9.5rem; }
}

/* The key-name field and its button: stacked and full width on a phone, on one
 * line once there is room for a field worth typing in. */
.key-create { display: flex; flex-direction: column; align-items: stretch; gap: 0.6rem; }
.key-create .button { width: 100%; }

/* ``.setting-card`` is a row -- text left, control right -- which is right for a
 * single control and wrong for a form: on a phone the description column is
 * squeezed to a few words wide while the field keeps its own width. A card that
 * puts its control below the text instead. */
@media (max-width: 619px) {
  .setting-card-stacked { flex-direction: column; align-items: stretch; }
}

@media (min-width: 560px) {
  .key-create { flex-direction: row; align-items: center; }
  .key-create .button { width: auto; }
  .view-inner .key-create input[type="text"] { width: auto; min-width: 14rem; }
}

/* Danger card closes the page. */
.danger-card { border-color: rgba(229, 72, 77, 0.3); }
.danger-card h2 { margin-top: 0; color: var(--danger); }

.pill {
  display: inline-flex; align-items: center;
  padding: 0.15rem 0.6rem; border-radius: 999px;
  border: 1px solid var(--tint-line, var(--line));
  background: var(--tint-soft, var(--card-2));
  font-size: 0.875rem; color: var(--tint, var(--text-dim));
}

.small-heading { font-size: 0.8125rem; text-transform: uppercase; letter-spacing: 0.06em; color: var(--text-faint); margin: 1.5rem 0 0.25rem; }

.danger-heading { color: var(--danger); margin-top: 3rem; }

/* --- Sign in ------------------------------------------------------------ */
/* The page is a stack of cards with a labelled rule between each pair: the
 * Google button, then the password form, then the sign-up form. Nothing is
 * nested inside a card that belongs to another job, so a reader never has to
 * work out where one ends and the next begins. On a phone this is a
 * thumb-and-a-tap page, so the cards are full width and the buttons are too. */

.signin-card { padding: 1.25rem; gap: 1.1rem; }
.signin-card .signin-lede { color: var(--text-dim); font-size: 0.9375rem; margin: 0; }

/* A form is a stack of labelled fields. `.field` carries no margin of its own
 * -- studio.css draws only the gap between a label and its input -- so without
 * this the fields would sit flush against each other. */
.auth-form { display: flex; flex-direction: column; gap: 1rem; margin: 0; }
/* `.card .button` claims `margin-top: auto` for the one-action cards in a
 * grid; inside a form the button belongs directly under the last field. */
.auth-form .button { margin-top: 0.25rem; }
.auth-form .remember {
  display: flex; align-items: center; gap: 0.5rem;
  color: var(--text-dim); font-size: 0.9375rem;
}

.field-error { margin: 0; color: var(--danger); font-size: 0.8125rem; }
.auth-links { margin: 0; }
.auth-links a { color: var(--text-dim); }
.auth-links a:hover { color: var(--text); }

/* A rule with a word in the middle of it, naming what the two things it
 * separates have to do with each other -- "or" between two ways in, "New to
 * HaughtAI?" between the two errands the page serves. */
.auth-divider {
  display: flex; align-items: center; gap: 0.75rem;
  margin: 0;
  color: var(--text-faint);
  font-size: 0.75rem; text-transform: uppercase; letter-spacing: 0.08em;
}
.auth-divider::before, .auth-divider::after {
  content: ""; flex: 1 1 auto; height: 1px; background: var(--line-strong);
}
/* Between two cards the line steps back: the label is the message, and a rule
 * as loud as the card borders either side would read as a third card. */
.auth-divider-between { margin: 1.25rem 0; }
.auth-divider-between::before, .auth-divider-between::after { background: var(--line); }

/* The second card is where the page stops being a sign-in page: a lighter
 * surface says so before the heading is read. */
.auth-create-card { background: var(--card-2); }

.auth-create > summary {
  cursor: pointer;
  list-style: none;
  display: flex; align-items: center; justify-content: space-between; gap: 1rem;
  font-size: 1.0625rem; font-weight: 600;
}
.auth-create > summary::-webkit-details-marker { display: none; }
/* The disclosure marker, drawn here because `display: flex` on the summary
 * discards the browser's own triangle in every engine. */
.auth-create > summary::after {
  content: "";
  width: 0.5rem; height: 0.5rem;
  border-right: 2px solid currentColor;
  border-bottom: 2px solid currentColor;
  color: var(--text-faint);
  transform: rotate(45deg);
  transition: transform 120ms ease;
}
.auth-create[open] > summary::after { transform: rotate(-135deg); }
.auth-create[open] > summary { margin-bottom: 1.1rem; }

.signin-terms { margin: 1.25rem 0 0; }

@media (min-width: 620px) {
  /* The cards stop growing at a comfortable form width, so everything that
   * sits against them -- the rules between them, the terms line under them,
   * and the note that stands in for the Google button when it is not
   * configured -- is held to the same column. Left to fill the view they
   * would centre their text nowhere near the cards' own centre. */
  .signin-card { max-width: 460px; padding: 1.5rem; }
  .auth-divider-between,
  .signin-terms,
  .auth-col { max-width: 460px; }
}

/* Inputs mirror studio.css `.input`: `--surface`, `--line-strong`, and the
 * purple focus ring. */
input[type="text"],
input[type="email"],
input[type="password"],
input[type="number"],
textarea,
select {
  width: 100%;
  min-height: 44px;
  padding: 0.7rem 0.85rem;
  border-radius: var(--radius-sm);
  border: 1px solid var(--line-strong);
  background: var(--surface);
  color: var(--text);
  font: inherit; font-size: 0.9375rem;
  outline: none;
}

/* iOS zooms the whole page when a field smaller than 16px takes focus, which
 * leaves the visitor looking at a magnified slice of the form. A phone gets the
 * size the platform wants; the desktop keeps the smaller step. */
@media (max-width: 900px) {
  input[type="text"],
  input[type="email"],
  input[type="password"],
  input[type="number"],
  textarea,
  select { font-size: 16px; }
}

input[type="text"]:focus,
input[type="email"]:focus,
input[type="password"]:focus,
input[type="number"]:focus,
textarea:focus,
select:focus {
  border-color: var(--purple-500);
  box-shadow: 0 0 0 3px rgba(124, 92, 230, 0.18);
}
::placeholder { color: var(--text-faint); }

label { color: var(--text-faint); font-size: 0.8125rem; }

/* --- Usage page --------------------------------------------------------- */
/* The account's own reading of its two budgets. The header, the cards and
 * the lists are the account page's components, deliberately: this page is a
 * sibling of that one, not a new surface with its own vocabulary. What is new
 * is only the meter, the two-column figures, and the rule that draws the
 * grants list's groups apart. */

/* The page's sections fold away with the account page's own disclosure --
 * `.disclosure acct-section`, taken straight from that page, because this is
 * its sibling rather than a new surface. Nothing new is defined for them here. */

/* The usage header, tightened: the plan, its expiry and the two balances share
 * one wrapping row of pills instead of stacking heading, lede, tags and a list.
 * The card is the page's summary, and a summary that pushes the first section
 * below the fold on a phone is not one. */
.usage-summary { padding: 1rem 1.25rem; }
.usage-summary .page-head { margin-bottom: 2px; }
.usage-summary .acct-who { margin-bottom: 0.65rem; }
.usage-summary .acct-tags { margin-bottom: 0; gap: 0.4rem; }
.usage-summary .acct-tags .pill { font-size: 0.8125rem; }
/* The balances sit on their own line under the plan row, a little apart so the
 * two rows read as distinct. Qualified by `.usage-summary` because the base
 * `.acct-summary .acct-tags` shorthand sets ``margin: 0 0 1rem`` -- a
 * two-class selector that would otherwise win and pin ``margin-top`` to 0. */
.usage-summary .usage-balances { margin-top: 0.9rem; }
/* The label reads as a caption beside its pill, not as another pill. */
.acct-plan-label {
  align-self: center;
  color: var(--text-dim);
  font-size: 0.8125rem;
}

.usage-card { gap: 0; }
.usage-card-head {
  display: flex; align-items: center; flex-wrap: wrap; gap: 0.6rem;
  justify-content: space-between;
}
.usage-card-head h3 { margin: 0; font-size: 1rem; }

/* How much of an allowance is gone. Purely a second reading of the numbers
 * printed below it, never their only statement: the meter is decoration for
 * a sighted reader, so the figure is always in the list as well. */
.usage-meter {
  height: 8px;
  margin: 0.85rem 0 0.25rem;
  border-radius: 999px;
  background: var(--card-3);
  overflow: hidden;
}
.usage-meter > span {
  display: block;
  height: 100%;
  border-radius: 999px;
  background: var(--grad);
  /* A width animated in is noise on a page nobody edits; the value is a fact
   * that arrived before the first paint. */
  transition: none;
}
/* The two states that ask for attention, in the same colours the pills use
 * for a warning and a refusal. */
.usage-meter.is-warn > span { background: var(--warn); }
.usage-meter.is-bad > span { background: var(--danger); }

.usage-card .facts { margin-bottom: 0.5rem; }

/* What the plan grants: one card holding three lists, the groups separated by
 * a rule. The groups are ranges of one list rather than sections with their own
 * names, so the break is drawn instead of labelled. */
.usage-card .feature-states { margin: 0; }
.grant-rule { border: 0; border-top: 1px solid var(--line); margin: 0.9rem 0; }

/* A window and its figure. Two columns, tight rows: the label reads as a
 * caption and the number as the answer, which is how the eye takes it. */
.usage-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.875rem;
  margin: 0.75rem 0 0;
}
.usage-table th,
.usage-table td { padding: 0.45rem 0; text-align: left; border-bottom: 1px solid var(--line); }
.usage-table tbody tr:last-child th,
.usage-table tbody tr:last-child td { border-bottom: 0; }
.usage-table th { font-weight: 500; color: var(--text-dim); }
.usage-table thead th {
  font-size: 0.75rem; text-transform: uppercase; letter-spacing: 0.06em;
  color: var(--text-faint);
}
.usage-table td { text-align: right; font-variant-numeric: tabular-nums; }

.usage-history-scroll {
  max-height: min(40rem, 70vh);
  overflow: auto;
  overscroll-behavior: contain;
  scrollbar-gutter: stable;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
}
.usage-history-count { margin: 0.6rem 0 0; color: var(--text-faint); font-size: 0.75rem; white-space: nowrap; }
.usage-pagination {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  margin-top: 0.6rem;
}
.usage-page-link { color: var(--text); text-decoration: none; }
.usage-page-link:hover { color: var(--purple-300); }
/* A ledger, so it is set denser than the other `.usage-table`s: this is the
 * one table read by scanning rows, and every row is the same five fields. */
.connector-history-table { margin: 0; font-size: 0.8125rem; line-height: 1.3; }
.connector-history-table th,
.connector-history-table td { padding: 0.32rem 0.55rem; }
.connector-history-table thead th {
  position: sticky;
  top: 0;
  z-index: 1;
  padding-top: 0.4rem;
  padding-bottom: 0.4rem;
  background: var(--card-2);
  font-size: 0.6875rem;
  white-space: nowrap;
}
.connector-history-table th:first-child { width: 14%; }
.connector-history-table th:nth-child(2) { width: 22%; }
.connector-history-table th:nth-child(3) { width: 40%; }
.connector-history-table th:nth-child(4) { width: 9%; }
.connector-history-table th:last-child,
.connector-history-table td:last-child { text-align: right; }
.connector-history-table td:first-child,
.connector-history-table td:nth-child(2),
.connector-history-table td:nth-child(3),
.connector-history-table td:nth-child(4) { text-align: left; }
.connector-history-table td:first-child {
  white-space: nowrap;
  color: var(--text-dim);
  font-size: 0.75rem;
}
/* The path (``/mcp/<uuid>``) is what the page shows, so a row is one line;
 * the full address is in the cell's tooltip and the ellipsis is only a guard
 * for a host or route long enough to overflow its column anyway. */
.connector-history-table td:nth-child(3) {
  font-family: var(--mono);
  font-size: 0.625rem;
  color: var(--text-dim);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
/* A full-size badge would be as tall as two lines of the row it marks. */
.connector-history-table td:nth-child(4) { white-space: nowrap; }
.connector-history-table td:nth-child(4) .pill {
  padding: 0 0.4rem;
  font-size: 0.625rem;
  line-height: 1.5;
}
.connector-history-table tbody tr:nth-child(even) { background: rgba(255, 255, 255, 0.025); }
.connector-history-table tbody tr:hover { background: var(--card-2); }
.connector-history-table tbody tr:last-child td { border-bottom: 0; }

/* --- Earnings page ------------------------------------------------------ */
/* The mirror of the usage page, reusing its components -- header, cards, the
 * scroll region and the pagination -- because it is the same kind of ledger
 * read the same way. What is new is only the totals row under the per-connector
 * table, which is the one figure the eye should land on. */
.earnings-total th,
.earnings-total td {
  border-top: 1px solid var(--line-strong);
  border-bottom: 0;
  padding-top: 0.75rem;
  color: var(--text);
  font-weight: 600;
}
/* Five money columns is one too many for a phone, so the table reflows like the
 * connector history above it: a stacking card per connector rather than a
 * horizontally scrolling grid. */
@media (max-width: 620px) {
  .earnings-connector th[scope="row"] { font-weight: 600; }
}

@media (max-width: 620px) {
  .usage-history-scroll { max-height: 60vh; }
  .connector-history-table thead {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    clip-path: inset(50%);
    white-space: nowrap;
  }
  .connector-history-table tbody { display: grid; gap: 0.4rem; padding: 0.45rem; }
  .connector-history-table tbody tr {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    gap: 0.35rem 0.85rem;
    padding: 0.55rem 0.7rem;
    border: 1px solid var(--line);
    border-radius: var(--radius-sm);
    background: var(--card-2);
  }
  .connector-history-table tbody tr:nth-child(even) { background: var(--card-2); }
  .connector-history-table tbody tr:hover { background: var(--card-3); }
  .connector-history-table th,
  .connector-history-table td { border: 0; padding: 0; }
  .connector-history-table td {
    min-width: 0;
    text-align: left;
    white-space: normal;
    overflow-wrap: anywhere;
  }
  .connector-history-table td::before {
    display: block;
    margin-bottom: 0.15rem;
    color: var(--text-faint);
    font-size: 0.6875rem;
    font-weight: 600;
    text-transform: uppercase;
  }
  .connector-history-table td:first-child {
    grid-column: 1 / -1;
    grid-row: 1;
    display: flex;
    justify-content: space-between;
    gap: 0.75rem;
    color: var(--text-dim);
    font-size: 0.75rem;
  }
  .connector-history-table td:first-child::before {
    content: attr(data-label);
    flex: 0 0 auto;
  }
  /* Connector on the left, its visibility badge on the right, then the
   * endpoint address on a line of its own because no phone can share a row
   * with a full URL. The charge closes the card. */
  .connector-history-table td:nth-child(2) { grid-column: 1; grid-row: 2; }
  .connector-history-table td:nth-child(4) {
    grid-column: 2;
    grid-row: 2;
    text-align: right;
    align-self: start;
  }
  .connector-history-table td:nth-child(3) { grid-column: 1 / -1; grid-row: 3; }
  /* The path may wrap on a phone: the card has no column to overflow into. */
  .connector-history-table td:nth-child(3) {
    white-space: normal;
    overflow-wrap: anywhere;
  }
  .connector-history-table td:nth-child(2)::before,
  .connector-history-table td:nth-child(3)::before,
  .connector-history-table td:last-child::before { content: attr(data-label); }
  .connector-history-table td:nth-child(4)::before { content: none; }
  .connector-history-table td:last-child {
    grid-column: 1 / -1;
    grid-row: 4;
    text-align: right;
    font-variant-numeric: tabular-nums;
  }
}

/* --- Support tickets ---------------------------------------------------- */
/* The account's own requests. A receipt roll: the list is scanned, the detail
 * page is read once, and neither is a conversation -- replies happen by email,
 * which is why there is no reply box here to style.
 *
 * Everything is the account page's own vocabulary (`.list`, `.list-row`,
 * `.pill`, `.card`, `.notice`). What is new is only the message body: it is the
 * one place on the site that shows text somebody typed, with the line breaks
 * they typed it with. */

.ticket-actions { display: flex; flex-wrap: wrap; gap: 0.6rem; margin: 1.25rem 0; }
.ticket-list { margin: 1.25rem 0 0.75rem; }
/* The row is an <a>; studio.css gives it `color: inherit` but no underline
 * reset, and an underlined block reads as a paragraph of links. */
.ticket-row { text-decoration: none; }
/* The reference line is the scan key, so it must not be clamped away -- two
 * lines here means the subject above it wrapped, not that this is prose. */
.ticket-row .list-row-sub { -webkit-line-clamp: 1; }
.ticket-count { color: var(--text-faint); font-size: 0.8125rem; margin: 0; }
.ticket-tags { display: flex; flex-wrap: wrap; gap: 0.5rem; margin: 0 0 1.25rem; }
.ticket-card { margin-bottom: 1.25rem; }
.ticket-card h2 { margin-top: 0; }
/* `pre-wrap` is the whole point: an error paste or a stack trace collapsed to
 * one paragraph is unreadable. `anywhere` stops a long unbroken token (a key, a
 * URL) from widening the page on a phone. */
.ticket-message { white-space: pre-wrap; overflow-wrap: anywhere; margin: 0; }

/* --- Developer docs (devdocs/) ------------------------------------------ */

/* One column on a phone, where the rail is a list above the page; two from
 * 900px, where it is a sticky column beside the prose. The rail comes first in
 * the markup so a reader never meets a page without its map. `minmax(0, 1fr)`
 * on the body is what stops a long code line widening the grid: without it the
 * track grows to the widest unbreakable string and the whole page scrolls
 * sideways. */
.docs { display: grid; grid-template-columns: 1fr; gap: 1.5rem; align-items: start; }
.docs-rail { min-width: 0; }
.docs-body { min-width: 0; }
.docs-rail-title { margin: 0 0 0.75rem; font-size: 0.9375rem; font-weight: 650; letter-spacing: 0.01em; }
.docs-nav { display: flex; flex-direction: column; gap: 1px; margin: 0 0 1rem; }
.docs-link {
  display: block; padding: 0.375rem 0.625rem; border-radius: 8px;
  color: var(--text-dim, inherit); text-decoration: none; font-size: 0.875rem;
  line-height: 1.35;
}
.docs-link:hover { color: inherit; background: var(--surface-2, rgba(255, 255, 255, 0.05)); }
.docs-link.active { color: inherit; background: var(--surface-3, rgba(255, 255, 255, 0.09)); font-weight: 600; }

@media (min-width: 900px) {
  .docs { grid-template-columns: 230px minmax(0, 1fr); gap: 2.5rem; }
  .docs-rail {
    position: sticky; top: calc(var(--topbar-h) + 1rem);
    max-height: calc(100vh - var(--topbar-h) - 2rem); overflow-y: auto;
  }
}

/* The on-this-page chips reuse `.section-nav`; this only keeps them from
 * stretching the rail on a narrow screen by allowing a wrap. */
.docs-contents { flex-wrap: wrap; }

/* `pre` rather than `<code>` alone: every sample in the docs is multi-line, and
 * `overflow-x: auto` gives a phone its own horizontal scroll instead of a page
 * that scrolls sideways. `pre-wrap` is deliberately NOT set -- indentation in a
 * JSON or Python sample is meaning, and wrapping it invents line breaks. */
.code {
  margin: 1rem 0 1.5rem; padding: 0.875rem 1rem; border-radius: 10px;
  background: var(--surface-2, rgba(255, 255, 255, 0.05));
  border: 1px solid var(--border, rgba(255, 255, 255, 0.09));
  overflow-x: auto; white-space: pre;
  font-family: var(--mono, ui-monospace, SFMono-Regular, Menlo, monospace);
  font-size: 0.8125rem; line-height: 1.55; tab-size: 2;
}
/* A single-line value -- a URL, a header -- reads as code without becoming a
 * block that breaks the paragraph around it. */
.code-inline {
  font-family: var(--mono, ui-monospace, SFMono-Regular, Menlo, monospace);
  font-size: 0.875em; padding: 0.1em 0.35em; border-radius: 5px;
  background: var(--surface-2, rgba(255, 255, 255, 0.06));
}

/* Reference tables. `display: block` + overflow keeps a three-column table from
 * forcing the whole page wide on a phone; the table itself stays a table. */
.docs-table { display: block; width: 100%; overflow-x: auto; margin: 1rem 0 1.5rem; }
.docs-table table { width: 100%; border-collapse: collapse; font-size: 0.875rem; }
.docs-table th, .docs-table td {
  text-align: left; vertical-align: top; padding: 0.5rem 0.75rem;
  border-bottom: 1px solid var(--border, rgba(255, 255, 255, 0.09));
}
.docs-table th { font-weight: 600; white-space: nowrap; }
.docs-table td:first-child { white-space: nowrap; }

.docs-next { margin-top: 2.5rem; padding-top: 1.25rem; border-top: 1px solid var(--border, rgba(255, 255, 255, 0.09)); }

/* A worked example: outcome, pieces, steps. The left border is what separates
 * one from the next when six of them sit on one page. */
.workflow { margin: 0 0 2rem; padding: 0 0 0 1rem; border-left: 2px solid var(--border, rgba(255, 255, 255, 0.12)); }
.workflow h3 { margin: 0 0 0.5rem; }
.workflow-meta { display: flex; flex-wrap: wrap; gap: 0.375rem; margin: 0 0 0.75rem; }

/* --- Accessibility ------------------------------------------------------ */

:focus-visible { outline: 2px solid var(--purple-500); outline-offset: 2px; }

