/* Weblay dashboard. Vercel/Geist-inspired design system.
   Self-contained (no external fonts/CDN) to keep the single-binary,
   privacy-first story intact. Monochrome canvas, hairline borders,
   white primary button, Wolfigs-orange accent, semantic status colors. */

:root {
  /* Surfaces, near-black canvas with subtly lifted panels. */
  /* Not pure black. The sheet sits on this, and against #000 the frame read as
     a hole rather than a surface. This keeps black dominant while leaving the
     sheet about seven levels lighter, which is enough for it to lift. */
  --bg: #08080B;
  --bg-elevated: #0a0a0a;
  --panel: #0d0d0d;
  --panel-2: #141414;
  --panel-hover: #171717;

  /* Hairline borders. */
  --border: #1f1f1f;
  --border-strong: #2e2e2e;
  --border-focus: #3a3a3a;

  /* Text. */
  --text: #ededed;
  --text-dim: #a1a1a1;
  --text-faint: #8a8a8a;
  --text-invert: #0a0a0a;

  /* Accents & status. Wolfigs brand orange. */
  --accent: #F26222;
  --accent-strong: #d9500f;
  --accent-soft: rgba(242, 98, 34, 0.14);
  /* Glass. Two tiers: surfaces sit in the page and let the backdrop through;
     overlays float above it and need enough body to carry their own content.
     Every frosted surface in the app derives from these, so the whole UI can
     be retuned from here. */
  --glass:          rgba(20, 20, 23, .62);
  --glass-overlay:  rgba(20, 20, 23, .82);
  --glass-line:     rgba(255, 255, 255, .07);
  --glass-line-up:  rgba(255, 255, 255, .1);
  --glass-hi:       inset 0 1px 0 rgba(255, 255, 255, .045);
  --glass-blur:     blur(16px) saturate(140%);
  --glass-blur-up:  blur(30px) saturate(150%);
  /* The one solid fill every glass surface falls back to. */
  --glass-solid:    #141417;

  --success: #4ade80;
  --success-soft: rgba(74, 222, 128, 0.13);
  --warning: #f5c451;
  --danger: #ff6166;
  --danger-strong: #e5484d;
  --danger-soft: rgba(255, 97, 102, 0.12);

  /* Focus ring. */
  --ring: rgba(242, 98, 34, 0.55);

  /* Typography. */
  --font-sans: "Inter", "Inter var", -apple-system, BlinkMacSystemFont,
    "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  --font-mono: "Geist Mono", "SF Mono", ui-monospace, SFMono-Regular, Menlo,
    Consolas, "Liberation Mono", monospace;

  /* Radii. */
  --r-sm: 6px;
  --r-md: 8px;
  --r-lg: 12px;
  --r-xl: 16px;
  --r-full: 999px;

  /* Spacing scale (dense / dashboard). */
  --s-1: 4px;
  --s-2: 8px;
  --s-3: 12px;
  --s-4: 16px;
  --s-5: 20px;
  --s-6: 24px;
  --s-8: 32px;
  --s-10: 40px;
  --s-12: 48px;

  /* Elevation. */
  --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.5);
  --shadow-md: 0 8px 24px rgba(0, 0, 0, 0.55);
  --shadow-lg: 0 16px 48px rgba(0, 0, 0, 0.65);

  --topnav-h: 64px;
  /* The frame's inset from the viewport on the left, right and bottom. The top
     is the bar's own height, so it is not repeated here. */
  --stage-gap: 24px;
  /* The text column inside the frame. The frame fills the viewport; the reading
     measure does not, and is made by the frame's own padding. */
  --stage-measure: 1120px;
  /* The sheet's own ground. The area outside it keeps --bg, so the frame reads
     as flat and every bit of colour belongs to the sheet. */
  --stage-bg: #0c0c0f;
  /* How far the active tab flares out at the bottom to meet the sheet. Matches
     the tab's own top radius, so both corners of the tab turn through the same
     arc. */
  --tab-flare: 18px;
  /* The tab's top corners. Kept off --r-lg so the tab can be rounder than the
     cards without dragging every other component with it. */
  --tab-radius: 18px;
  /* Zero: the tabs meet edge to edge, the way a browser's do. The active tab's
     flare then reaches well over its neighbour, which is why the active tab is
     raised above the others rather than left to DOM order. */
  --tab-gap: 0px;
  /* Film grain, shared by the sheet and by the tab that grows out of it. */
  --grain-url: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.82' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)'/%3E%3C/svg%3E");
  /* A veil of the sheet's own colour laid over the grain, which is how the tab
     gets the same faint texture without a separate layer to animate. */
  /* Two things have to match at once: how grainy the tab is, and how dark.
     Alpha sets the grain, because the noise shows through at (1 - alpha), and
     .13 is the same strength the sheet's own grain layer uses. The colour then
     sets the tone. It is much darker than the sheet's base because the sheet is
     darkened further by the layers above it, so matching the base alone left the
     tab sitting nine levels too bright. */
  --stage-veil: rgba(1, 1, 4, .87);
  color-scheme: dark;
}

* { box-sizing: border-box; }

html { background: var(--bg); }

/* An app shell, not a document: the frame is fixed and the content scrolls
   inside it, so the bar and the active tab never move. The page must therefore
   not scroll at all, or a second scrollbar appears behind the frame. */
html, body { height: 100%; }
body { overflow: hidden; }

body {
  margin: 0;
  /* The ambient glow moved to the .bg layer, which can animate on the
     compositor; a gradient on body would repaint the whole page. */
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-sans);
  font-size: 14px;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  font-feature-settings: "cv02", "cv03", "cv04", "cv11";
}

::selection { background: rgba(242, 98, 34, 0.3); }

a { color: var(--text); text-decoration: none; }
a:hover { color: #fff; }

h1, h2, h3 { margin: 0; font-weight: 600; letter-spacing: -0.02em; }
h1 { font-size: 20px; }
h2 { font-size: 15px; }
p { margin: 0; }

code {
  font-family: var(--font-mono);
  font-size: 0.9em;
  background: var(--panel-2);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  padding: 1px 5px;
}

/* Scrollbar */
* { scrollbar-width: thin; scrollbar-color: #2a2a2a transparent; }
*::-webkit-scrollbar { width: 10px; height: 10px; }
*::-webkit-scrollbar-thumb { background: #262626; border-radius: 99px; border: 2px solid transparent; background-clip: padding-box; }
*::-webkit-scrollbar-thumb:hover { background: #333; background-clip: padding-box; }

/* ─── App shell ─────────────────────────────────────────────── */

/* The account bar: brand, product switcher, account.
 *
 * Deliberately unfilled. The bar is the frame around the stage, so giving it
 * its own panel fill would put two competing surfaces on top of each other and
 * flatten the tabs into it. The ground shows through instead, and the only lit
 * thing up here is the tab you are on. */
.cloudbar {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 40;
  height: var(--topnav-h);
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: end;
  gap: var(--s-4);
  padding: 0 var(--s-6);
}
.cb-left { display: flex; align-items: center; gap: var(--s-3); min-width: 0; height: 100%; padding-left: 16px; }
.cb-right { display: flex; align-items: center; justify-content: flex-end; height: 100%; }
.cb-brand { display: inline-flex; align-items: center; flex-shrink: 0; opacity: .96; transition: opacity .15s; }
.cb-brand:hover { opacity: 1; }
.cb-logo {
  height: 20px; width: auto; display: block;
  /* A pass of white light across the lockup. drop-shadow, not box-shadow: the
     logo is a transparent PNG, so the glow has to follow the ink rather than a
     rectangle around it. Once, a second after the bar appears, so it reads as
     the brand settling rather than something demanding attention. */
  animation: brandGlow 7s ease-in-out 1s infinite;
}
/* Loading starts the same breath immediately; only the wait before the first
   one differs, so the brand never jumps between two different rhythms. */
.busy .cb-logo { animation-delay: 0s; }

/* Both ends are a filter list of the same shape as the peak, at zero radius and
   zero alpha, rather than `none`. `none` is not interpolable with a filter list,
   so the browser cannot tween it and the glow snaps on instead of rising.
   The peak sits late in the cycle, which leaves most of it dark: one slow breath
   rather than a pulse. */
@keyframes brandGlow {
  0%, 52%, 100% { filter: drop-shadow(0 0 0 rgba(255, 255, 255, 0))
                          drop-shadow(0 0 0 rgba(255, 255, 255, 0)); }
  76%           { filter: drop-shadow(0 0 7px rgba(255, 255, 255, .5))
                          drop-shadow(0 0 18px rgba(255, 255, 255, .22)); }
}
@media (prefers-reduced-motion: reduce) {
  .cb-logo, .busy .cb-logo { animation: none; }
}
.cb-crumbs { display: flex; align-items: center; gap: var(--s-3); min-width: 0; font-size: 13px; }
.cb-crumbs .sep { color: var(--border-strong); font-weight: 300; }
.cb-crumbs .crumb-name { color: var(--text-dim); font-weight: 500; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 22ch; }
.cb-crumbs a.crumb-name:hover { color: var(--text); }

/* Tabs, drawn as tabs. The active one carries the stage's own fill and border
   and then covers that border with its last pixel, so the two read as one
   surface rather than as a button parked above a panel. */
.cb-tabs { display: flex; align-items: flex-end; gap: var(--tab-gap); height: 100%; }
.cb-tab {
  position: relative;
  z-index: 1;
  display: inline-flex; align-items: center; gap: 9px;
  height: 50px; padding: 0 26px;
  border: 1px solid transparent;
  border-bottom: 0;
  border-radius: var(--tab-radius) var(--tab-radius) 0 0;
  color: var(--text-faint);
  font-size: 13.5px; font-weight: 550; letter-spacing: -0.01em;
  white-space: nowrap;
  transition: color .15s, background-color .15s;
}
.cb-tab:hover { color: var(--text-dim); background: rgba(255, 255, 255, .04); }
/* The product mark is set from the 4:3 artwork, so only the width is given and
   the height follows. It is deliberately larger than the type: at 16px wide the
   23-unit corner radius lands on 0.9 of a pixel and the rounding cannot render,
   which turns the stair into hard squares and loses the mark. At 23px the cells
   are 5.75px and the curves come back. The home glyph is a plain 1:1 icon and
   keeps icon size. */
.cb-tab .cb-mk { width: 23px; height: auto; display: block; flex-shrink: 0; opacity: .55; transition: opacity .15s; }
.cb-tab svg { width: 18px; height: 18px; display: block; flex-shrink: 0; opacity: .55; transition: opacity .15s; }
.cb-tab:hover .cb-mk, .cb-tab:hover svg { opacity: .8; }
.cb-tab.on {
  color: var(--text);
  /* The same ground as the sheet below it, grain included. At the sheet's top
     edge the bloom has not risen yet, so the base colour matches exactly; the
     veil over the grain reproduces the sheet's texture at the same strength,
     which is what stops the tab reading as a flat patch on a grained surface. */
  background:
    linear-gradient(var(--stage-veil), var(--stage-veil)),
    var(--grain-url) repeat,
    var(--stage-bg);
  border-color: var(--glass-line);
  box-shadow: var(--glass-hi);
  /* Sit over the sheet's top border. Two pixels, not one: the border is 1px but
     lands on a fractional device pixel, so a 1px overlap left a bright sliver of
     it showing under the tab and read as a seam between the two. */
  margin-bottom: -2px;
  padding-bottom: 2px;
  /* In front of its neighbours: the flare spills past the gap on both sides,
     and it must cover them rather than be cut into by whichever happens to come
     later in the markup. */
  z-index: 2;
}
.cb-tab.on .cb-mk, .cb-tab.on svg { opacity: 1; }

.cb-tab.on::before,
.cb-tab.on::after {
  content: "";
  position: absolute;
  bottom: 0;
  width: var(--tab-flare);
  height: var(--tab-flare);
  pointer-events: none;
}
.cb-tab.on::before {
  left: calc(var(--tab-flare) * -1);
  background:
    radial-gradient(circle at 0 0,
      transparent calc(var(--tab-flare) - 0.5px),
      var(--glass-line) calc(var(--tab-flare) - 0.5px),
      var(--glass-line) calc(var(--tab-flare) + 0.5px),
      transparent calc(var(--tab-flare) + 0.5px)),
    linear-gradient(var(--stage-veil), var(--stage-veil)),
    var(--grain-url) repeat,
    var(--stage-bg);
  -webkit-mask-image: radial-gradient(circle at 0 0, transparent calc(var(--tab-flare) - 0.5px), #000 var(--tab-flare));
          mask-image: radial-gradient(circle at 0 0, transparent calc(var(--tab-flare) - 0.5px), #000 var(--tab-flare));
}
.cb-tab.on::after {
  right: calc(var(--tab-flare) * -1);
  background:
    radial-gradient(circle at 100% 0,
      transparent calc(var(--tab-flare) - 0.5px),
      var(--glass-line) calc(var(--tab-flare) - 0.5px),
      var(--glass-line) calc(var(--tab-flare) + 0.5px),
      transparent calc(var(--tab-flare) + 0.5px)),
    linear-gradient(var(--stage-veil), var(--stage-veil)),
    var(--grain-url) repeat,
    var(--stage-bg);
  -webkit-mask-image: radial-gradient(circle at 100% 0, transparent calc(var(--tab-flare) - 0.5px), #000 var(--tab-flare));
          mask-image: radial-gradient(circle at 100% 0, transparent calc(var(--tab-flare) - 0.5px), #000 var(--tab-flare));
}


.cb-tab.tab-home { padding: 0 20px; }
/* The mark is the product's identity, so it keeps its colour; only the type
   dims when the tab is not the one you are on. */
.cb-tab.on .cb-mk { filter: none; }

.usermenu { position: relative; }
.userchip {
  display: flex; align-items: center; gap: var(--s-2);
  padding: 5px 8px 5px 5px;
  border-radius: var(--r-full);
  border: 1px solid var(--border);
  background: var(--panel);
  cursor: pointer;
  transition: background .15s, border-color .15s;
}
.userchip:hover { background: var(--panel-hover); border-color: var(--border-strong); }
.avatar {
  width: 26px; height: 26px; border-radius: 50%;
  display: grid; place-items: center;
  font-size: 11px; font-weight: 650; color: #000;
  background: linear-gradient(140deg, #f7a072, #F26222);
  flex-shrink: 0;
}
.userchip .email { font-size: 13px; color: var(--text-dim); max-width: 180px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.userchip .chev { color: var(--text-faint); }

.menu {
  position: absolute; right: 0; top: calc(100% + 8px);
  min-width: 220px;
  background: var(--panel);
  border: 1px solid var(--border-strong);
  border-radius: var(--r-md);
  box-shadow: var(--shadow-md);
  padding: 6px;
  opacity: 0; transform: translateY(-4px) scale(.98);
  pointer-events: none;
  transition: opacity .14s, transform .14s;
}
.menu.open { opacity: 1; transform: none; pointer-events: auto; }
.menu .menu-head { padding: 8px 10px; border-bottom: 1px solid var(--border); margin-bottom: 6px; }
.menu .menu-head .n { font-size: 13px; font-weight: 600; }
.menu .menu-head .e { font-size: 12px; color: var(--text-faint); }
.menu button {
  width: 100%; display: flex; align-items: center; gap: 10px;
  background: transparent; border: 0; color: var(--text-dim);
  padding: 8px 10px; border-radius: var(--r-sm);
  font: inherit; font-size: 13px; text-align: left; cursor: pointer;
}
.menu button:hover { background: var(--panel-2); color: var(--text); }
.menu button svg { width: 15px; height: 15px; }

/* The stage: the fixed frame a product is displayed on.
 *
 * main is the frame itself rather than sitting inside one. That is what lets the
 * active tab meet its top edge with no wrapper element in any view, and now also
 * what makes the frame hold still: it is pinned to the viewport and scrolls its
 * own content, so the bar, the tab and the frame's edges never move.
 *
 * The reading measure is made by this element's horizontal padding rather than
 * by a narrower box inside it, so no view needs a wrapper to stay readable. */
main.view {
  position: fixed;
  top: var(--topnav-h);
  left: var(--stage-gap);
  right: var(--stage-gap);
  bottom: var(--stage-gap);
  overflow-y: auto;
  overflow-x: hidden;
  /* Reaching the end of the stage must not start scrolling anything behind it. */
  overscroll-behavior: contain;
  padding: var(--s-8)
           max(var(--s-6), calc((100vw - 2 * var(--stage-gap) - var(--stage-measure)) / 2))
           var(--s-12);
  /* Transparent on purpose. The sheet's ground and its bloom are painted by the
     .bg layer sitting exactly behind this box, so the gradient is the sheet's
     background rather than something showing through a film laid over it. */
  background: transparent;
  border: 1px solid var(--glass-line);
  border-radius: var(--r-xl);
  box-shadow: var(--glass-hi);
}

/* Admin / operations pages carry wide content (the architecture map + rail, wide
   tables), so they get a much larger cap and fill the viewport responsively. */
/* Admin and operations pages carry wide content (the architecture map and rail,
   wide tables), so they widen the column rather than changing the frame. */
main.view.wide { --stage-measure: 1560px; }

.back-link {
  display: inline-flex; align-items: center; gap: 6px;
  color: var(--text-faint); font-size: 13px; font-weight: 500;
  margin-bottom: var(--s-4);
}
.back-link:hover { color: var(--text); }
.back-link svg { width: 15px; height: 15px; transition: transform .15s; }
.back-link:hover svg { transform: translateX(-2px); }

.page-head { display: flex; align-items: flex-end; gap: var(--s-4); margin-bottom: var(--s-6); }
.page-head .grow { flex: 1; min-width: 0; }
.page-head h1 { font-size: 26px; }
.page-head .sub { color: var(--text-dim); font-size: 14px; margin-top: 4px; }

.section-title { display: flex; align-items: center; gap: 8px; margin: var(--s-8) 0 var(--s-3); }
.section-title h2 { color: var(--text); }
.section-title .hint { color: var(--text-faint); font-size: 12.5px; font-weight: 400; }

/* ─── Cards ─────────────────────────────────────────────────── */

/* Glass. Cards are translucent so the backdrop's light reads through them,
   which is what stops a card looking like a hole cut in the page. The blur is
   lighter than the sign-in card's: a dashboard can have a dozen of these on
   screen and backdrop-filter is per-element work.
   The inset highlight is what actually sells it as a pane rather than a tint. */
.card {
  background: var(--glass);
  -webkit-backdrop-filter: var(--glass-blur);
          backdrop-filter: var(--glass-blur);
  border: 1px solid var(--glass-line);
  border-radius: var(--r-lg);
  box-shadow: var(--glass-hi);
  overflow: hidden;
}
/* No blur support means the translucent fill would put the backdrop straight
   through the card, so everything falls back to the original solid panel. */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .card { background: linear-gradient(180deg, var(--panel), var(--bg-elevated)); }
}
.card + .card { margin-top: var(--s-3); }
.card-pad { padding: var(--s-5); }
.card-head { padding: var(--s-5) var(--s-5) 0; }
.card-head h2 { margin-bottom: 2px; }
.card-head .desc { color: var(--text-dim); font-size: 13px; }
.card-foot {
  display: flex; align-items: center; gap: var(--s-3);
  padding: var(--s-3) var(--s-5);
  border-top: 1px solid var(--border);
  background: rgba(255,255,255,.012);
}
.card-foot .grow { flex: 1; }
.card-foot .note { color: var(--text-faint); font-size: 12.5px; }

/* Interactive site cards */
.grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: var(--s-3); }
.site-card {
  display: block; padding: var(--s-5);
  background: linear-gradient(180deg, var(--panel), var(--bg-elevated));
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  transition: border-color .16s, transform .16s, box-shadow .16s;
  cursor: pointer;
}
.site-card:hover { border-color: var(--border-focus); transform: translateY(-2px); box-shadow: var(--shadow-md); }
.site-card:hover .go-arrow { transform: translateX(2px); color: var(--text); }
.site-card .sc-top { display: flex; align-items: center; gap: var(--s-3); }
.site-card .sc-icon {
  width: 28px; height: 28px; border-radius: 7px; flex-shrink: 0;
  display: grid; place-items: center; color: var(--text-dim);
  background: var(--panel-2); border: 1px solid var(--border);
}
.site-card .sc-icon svg { width: 15px; height: 15px; }
.site-card .sc-name { font-weight: 600; font-size: 15px; letter-spacing: -.01em; }
.site-card .go-arrow { margin-left: auto; color: var(--text-faint); transition: transform .16s, color .16s; }
.site-card .sc-meta { display: flex; flex-wrap: wrap; gap: 6px; margin-top: var(--s-4); }

/* ─── Buttons ───────────────────────────────────────────────── */

.btn {
  --h: 36px;
  display: inline-flex; align-items: center; justify-content: center; gap: 7px;
  height: var(--h); padding: 0 14px;
  border: 1px solid transparent; border-radius: var(--r-md);
  font: inherit; font-size: 13.5px; font-weight: 550; line-height: 1;
  cursor: pointer; white-space: nowrap; user-select: none;
  transition: background .15s, border-color .15s, color .15s, transform .06s, opacity .15s;
}
.btn:active { transform: scale(.975); }
.btn svg { width: 15px; height: 15px; }
.btn.sm { --h: 30px; padding: 0 11px; font-size: 12.5px; }
.btn.lg { --h: 42px; padding: 0 18px; font-size: 14px; }
.btn.block { width: 100%; }

.btn-primary { background: #fff; color: #000; }
.btn-primary:hover { background: #e6e6e6; }

.btn-secondary { background: var(--panel-2); color: var(--text); border-color: var(--border-strong); }
.btn-secondary:hover { background: var(--panel-hover); border-color: var(--border-focus); }

.btn-ghost { background: transparent; color: var(--text-dim); border-color: transparent; }
.btn-ghost:hover { background: var(--panel-2); color: var(--text); }

.btn-danger { background: transparent; color: var(--danger); border-color: rgba(255,97,102,.4); }
.btn-danger:hover { background: var(--danger-soft); border-color: var(--danger); }
.btn-danger-solid { background: var(--danger-strong); color: #fff; }
.btn-danger-solid:hover { background: #d13b40; }

.btn:disabled, .btn.loading { opacity: .6; pointer-events: none; }
.btn.loading { position: relative; color: transparent !important; }
.btn.loading::after {
  content: ""; position: absolute; width: 15px; height: 15px;
  border: 2px solid currentColor; border-right-color: transparent; border-radius: 50%;
  animation: spin .6s linear infinite;
  color: var(--text);
}
.btn-primary.loading::after { color: #000; }

.icon-btn {
  display: inline-grid; place-items: center;
  width: 32px; height: 32px; border-radius: var(--r-sm);
  background: transparent; border: 1px solid transparent; color: var(--text-faint);
  cursor: pointer; transition: background .15s, color .15s, border-color .15s;
}
.icon-btn:hover { background: var(--panel-2); color: var(--text); border-color: var(--border); }
.icon-btn svg { width: 16px; height: 16px; }

/* ─── Forms ─────────────────────────────────────────────────── */

.field { display: block; }
.field + .field { margin-top: var(--s-4); }
.field > label, .lbl { display: block; margin-bottom: 7px; font-size: 13px; font-weight: 500; color: var(--text); }
.field .help { margin-top: 6px; font-size: 12.5px; color: var(--text-faint); }

input[type="text"], input[type="email"], input[type="password"], input:not([type]), select, textarea {
  width: 100%; height: 38px;
  background: var(--panel-2);
  border: 1px solid var(--border-strong);
  color: var(--text);
  border-radius: var(--r-md);
  padding: 0 12px;
  font: inherit; font-size: 14px;
  transition: border-color .15s, box-shadow .15s, background .15s;
}
textarea { height: auto; padding: 10px 12px; resize: vertical; }
input::placeholder, textarea::placeholder { color: #5c5c5c; }
input:hover, select:hover, textarea:hover { border-color: var(--border-focus); }
input:focus, select:focus, textarea:focus {
  outline: none; border-color: var(--accent);
  background: var(--panel);
  box-shadow: 0 0 0 3px var(--accent-soft);
}
select { appearance: none; -webkit-appearance: none; cursor: pointer;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='none' stroke='%238a8a8a' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m4 6 4 4 4-4'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 10px center; padding-right: 32px; }

:focus-visible { outline: none; }
.btn:focus-visible, .icon-btn:focus-visible, .userchip:focus-visible, .site-card:focus-visible, a:focus-visible {
  outline: 2px solid var(--ring); outline-offset: 2px; border-radius: var(--r-md);
}

/* ─── Inline alerts ─────────────────────────────────────────── */

.alert {
  display: none; align-items: flex-start; gap: 9px;
  padding: 10px 12px; border-radius: var(--r-md); font-size: 13px;
  margin-bottom: var(--s-4);
}
.alert.show { display: flex; }
.alert svg { width: 16px; height: 16px; flex-shrink: 0; margin-top: 1px; }
.alert.error { background: var(--danger-soft); border: 1px solid rgba(255,97,102,.35); color: #ff9a9d; }
.alert.success { background: rgba(45,212,191,.12); border: 1px solid rgba(45,212,191,.35); color: #7fe7d8; }

/* Label row with a secondary link (e.g. "Forgot password?") */
/* Carries the same bottom margin as a bare label. The label inside this row is
   not a direct child of .field, so ".field > label" never matched it and the
   input sat noticeably tighter than one with a plain label above it. */
.field-row { display: flex; align-items: baseline; justify-content: space-between; gap: 12px;
  margin-bottom: 7px; }
.field-row > label { margin-bottom: 0; }
.field-link { font-size: 12.5px; color: var(--muted); text-decoration: none; }
.field-link:hover { color: var(--text); }

/* Password strength meter */
.pw-meter { margin-top: 9px; }
.pw-bars { display: grid; grid-template-columns: repeat(4, 1fr); gap: 5px; }
.pw-bars span {
  height: 4px; border-radius: 3px; background: rgba(255,255,255,.10);
  transition: background .2s ease;
}
.pw-meta { display: flex; justify-content: space-between; gap: 12px; margin-top: 6px; font-size: 12px; }
.pw-label { font-weight: 600; }
.pw-tip { color: var(--muted); text-align: right; }
/* Colour the filled bars + label by score (0 weak … 4 strong). */
.pw-meter[data-score="0"] .pw-bars span.on,
.pw-meter[data-score="1"] .pw-bars span.on { background: #ff6166; }
.pw-meter[data-score="2"] .pw-bars span.on { background: #f5a524; }
.pw-meter[data-score="3"] .pw-bars span.on { background: #4dd4ac; }
.pw-meter[data-score="4"] .pw-bars span.on { background: var(--success); }
.pw-meter[data-score="0"] .pw-label,
.pw-meter[data-score="1"] .pw-label { color: #ff9a9d; }
.pw-meter[data-score="2"] .pw-label { color: #f5a524; }
.pw-meter[data-score="3"] .pw-label,
.pw-meter[data-score="4"] .pw-label { color: #7fe7d8; }
.btn[disabled] { opacity: .5; pointer-events: none; }

/* ─── Tables ────────────────────────────────────────────────── */

.table-wrap { overflow-x: auto; }
table { width: 100%; border-collapse: collapse; font-size: 13.5px; }
thead th {
  text-align: left; padding: 10px var(--s-5);
  color: var(--text-faint); font-size: 11px; font-weight: 600;
  text-transform: uppercase; letter-spacing: .07em;
  background: rgba(255,255,255,.015);
  border-bottom: 1px solid var(--border);
}
tbody td { padding: 12px var(--s-5); border-bottom: 1px solid var(--border); vertical-align: middle; }
tbody tr:last-child td { border-bottom: 0; }
tbody tr { transition: background .12s; }
tbody tr:hover { background: rgba(255,255,255,.02); }
td .path { font-family: var(--font-mono); font-size: 12.5px; color: var(--text); }
.t-actions { text-align: right; white-space: nowrap; }
.t-actions .btn + .btn { margin-left: 6px; }
.col-actions { width: 1%; }
.num { font-variant-numeric: tabular-nums; }

/* Pages table, clickable path + inline history accordion */
.path-link {
  display: inline-flex; align-items: center; gap: 5px;
  color: var(--text); transition: color .12s;
}
.path-link:hover { color: var(--accent); }
.path-link svg { width: 12px; height: 12px; color: var(--text-faint); }
.path-link:hover svg { color: var(--accent); }

/* History drawer (slide-over from the right) */
#drawer-root { position: fixed; inset: 0; z-index: 120; pointer-events: none; }
#drawer-root.open { pointer-events: auto; }
.drawer-scrim {
  position: absolute; inset: 0; background: rgba(0,0,0,.6);
  opacity: 0; transition: opacity .22s ease;
}
#drawer-root.open .drawer-scrim { opacity: 1; }
.drawer {
  position: absolute; top: 0; right: 0; bottom: 0;
  width: min(420px, 92vw);
  background: var(--bg-elevated);
  border-left: 1px solid var(--border-strong);
  box-shadow: -24px 0 60px rgba(0,0,0,.5);
  display: flex; flex-direction: column;
  transform: translateX(100%); transition: transform .24s cubic-bezier(.4,0,.2,1);
}
#drawer-root.open .drawer { transform: translateX(0); }
.drawer-head {
  display: flex; align-items: flex-start; gap: 12px;
  padding: 18px 20px; border-bottom: 1px solid var(--border);
}
.drawer-heading { flex: 1; min-width: 0; }
.drawer-eyebrow {
  font-size: 11px; font-weight: 600; letter-spacing: .07em; text-transform: uppercase;
  color: var(--text-faint); margin-bottom: 4px;
}
.drawer-head h3 { font-size: 16px; font-weight: 600; margin: 0; }
.drawer-head h3 .mono { font-size: 14px; }
.drawer-body { flex: 1; overflow-y: auto; padding: 20px; }
.drawer-loading {
  display: flex; align-items: center; gap: 8px;
  color: var(--text-faint); font-size: 13px; padding: 20px 0;
}
.drawer-loading.err { color: var(--danger); }
.drawer-loading svg { width: 15px; height: 15px; }
.empty.sm { padding: 40px 10px; }

/* Working-draft card at the top of the history drawer */
.draft-card {
  border: 1px solid rgba(251,191,36,.3); background: rgba(251,191,36,.06);
  border-radius: 12px; padding: 14px; margin-bottom: 18px;
}
.draft-head { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.draft-when { color: var(--text-faint); font-size: 12px; }
.draft-note { color: var(--text-dim); font-size: 12.5px; margin: 8px 0 12px; }
.draft-actions { display: flex; gap: 8px; }
.tl-heading {
  font-size: 11px; font-weight: 600; letter-spacing: .07em; text-transform: uppercase;
  color: var(--text-faint); margin: 0 0 12px;
}

/* Revision timeline inside the drawer */
.timeline { list-style: none; margin: 0; padding: 0 0 0 6px; position: relative; }
.tl-item { position: relative; padding: 0 0 18px 22px; }
.tl-item::before {
  content: ""; position: absolute; left: 4px; top: 16px; bottom: -2px;
  width: 2px; background: var(--border);
}
.tl-item:last-child { padding-bottom: 0; }
.tl-item:last-child::before { display: none; }
.tl-node {
  position: absolute; left: 0; top: 7px;
  width: 10px; height: 10px; border-radius: 50%;
  background: var(--panel-2); border: 2px solid var(--border-strong);
}
.tl-item.live .tl-node {
  background: var(--success); border-color: var(--success);
  box-shadow: 0 0 0 4px var(--success-soft);
}
.tl-card {
  background: var(--panel); border: 1px solid var(--border);
  border-radius: var(--r-md); padding: 10px 12px;
}
.tl-item.live .tl-card { border-color: rgba(74,222,128,.35); }
.tl-row { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.tl-live { font-size: 12px; font-weight: 600; color: var(--success); }
.tl-time { color: var(--text-faint); font-size: 12.5px; margin-top: 6px; font-variant-numeric: tabular-nums; }

/* ─── Badges ────────────────────────────────────────────────── */

.badge {
  display: inline-flex; align-items: center; gap: 6px;
  height: 22px; padding: 0 9px;
  border-radius: var(--r-full);
  font-size: 12px; font-weight: 500;
  background: var(--panel-2); border: 1px solid var(--border);
  color: var(--text-dim);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.badge svg { width: 13px; height: 13px; flex-shrink: 0; }
.badge .dot { width: 6px; height: 6px; border-radius: 50%; background: currentColor; flex-shrink: 0; }
.badge.mono { font-family: var(--font-mono); font-size: 11.5px; }
.badge.success { color: var(--success); background: var(--success-soft); border-color: rgba(74,222,128,.25); }
.badge.accent  { color: var(--accent);  background: var(--accent-soft);  border-color: rgba(242,98,34,.28); }
.badge.neutral { color: var(--text-dim); }
.badge.warn    { color: #fbbf24; background: rgba(251,191,36,.12); border-color: rgba(251,191,36,.3); }
.badge.danger-badge { color: var(--danger); background: var(--danger-soft); border-color: rgba(255,97,102,.3); }

.status-cell { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }

/* ─── Override health ───────────────────────────────────────── */
.hstat {
  display: inline-flex; align-items: baseline; gap: 5px; padding: 6px 12px; border-radius: 999px;
  font-size: 12.5px; color: var(--text-dim); background: var(--panel-2); border: 1px solid var(--border);
}
.hstat b { font-size: 15px; color: var(--text); }
.hstat.success b { color: var(--success); }
.hstat.warn b { color: #fbbf24; }
.hstat.danger b { color: var(--danger); }
.hlist { display: flex; flex-direction: column; }
.hrow { padding: 14px 16px; border-bottom: 1px solid var(--border); }
.hrow:last-child { border-bottom: 0; }
.hrow-main { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.hconf { font-variant-numeric: tabular-nums; font-weight: 600; font-size: 12.5px; color: var(--text-dim); }
.hsel { font-family: var(--font-mono); font-size: 11.5px; color: var(--text-faint);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 100%; }
.hreasons { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }
.hreasons span { font-size: 11.5px; color: #fcd34d; background: rgba(251,191,36,.08);
  border: 1px solid rgba(251,191,36,.2); padding: 2px 8px; border-radius: 6px; }
.hmeta { font-size: 12px; color: var(--text-faint); }
.link-btn { display: inline-flex; align-items: center; gap: 6px; background: none; border: 0;
  color: var(--accent); cursor: pointer; font: inherit; font-size: 12px; padding: 0; }
.link-btn svg { width: 14px; height: 14px; flex: none; }
.link-btn:hover { text-decoration: underline; }

/* Grouped health: page groups + scope + category rows */
.hpage { border: 1px solid var(--border); border-radius: var(--r-lg); margin-bottom: 16px; overflow: hidden; background: var(--panel); }
.hpage-head { display: flex; align-items: center; gap: 10px; padding: 12px 16px; border-bottom: 1px solid var(--border); flex-wrap: wrap; }
.hpage-head .path { font-size: 13.5px; }
.hpage-count { margin-left: auto; font-size: 12px; color: var(--text-faint); }
.scope { font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .04em; padding: 3px 9px; border-radius: 999px; }
.scope.warn { color: #fbbf24; background: rgba(251,191,36,.12); }
.scope.danger { color: var(--danger); background: var(--danger-soft); }
.scope.success { color: var(--success); background: var(--success-soft); }
.revamp { margin: 12px 16px; padding: 14px; border: 1px solid rgba(255,97,102,.35); background: rgba(255,97,102,.07); border-radius: 10px; }
.revamp-head { display: flex; align-items: center; gap: 8px; color: var(--danger); }
.revamp-head svg { width: 16px; height: 16px; }
.revamp p { margin: 8px 0 12px; font-size: 13px; color: var(--text-dim); }
.revamp-actions { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.revamp-note { font-size: 12px; color: var(--text-faint); }
.hrow { padding: 13px 16px; border-bottom: 1px solid var(--border); }
.hrow:last-child { border-bottom: 0; }
.hrow-top { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.hconf { font-variant-numeric: tabular-nums; font-weight: 600; font-size: 12px; color: var(--text-dim); }
.hsel { font-family: var(--font-mono); font-size: 11.5px; color: var(--text-faint); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 100%; }
.hdesc { margin: 7px 0 0; font-size: 12.5px; color: var(--text-dim); line-height: 1.5; }
.hfoot { display: flex; align-items: center; gap: 12px; margin-top: 10px; flex-wrap: wrap; }
.hfoot .hmeta { flex: 1; min-width: 160px; }
.hactions { display: flex; gap: 8px; }
.hhealthy { display: flex; align-items: center; gap: 8px; color: var(--success); font-size: 13px; padding: 4px 2px; }
.hhealthy svg { width: 15px; height: 15px; }

/* Site alert banner (site detail) */
.site-alert { display: flex; align-items: center; gap: 12px; padding: 13px 16px; margin-bottom: 18px;
  border: 1px solid rgba(255,97,102,.3); background: rgba(255,97,102,.07); border-radius: var(--r-lg); }
.site-alert .sa-ico { color: var(--danger); display: inline-flex; }
.site-alert .sa-ico svg { width: 20px; height: 20px; }
.site-alert b { font-size: 14px; }
.site-alert .faint { font-size: 13px; margin-left: 4px; }

/* Site card alert (home) */
.site-card.has-alert { border-color: rgba(255,97,102,.35); }
.sc-alert { color: var(--danger); display: inline-flex; }
.sc-alert svg { width: 17px; height: 17px; }

/* ─── Code snippet with copy ────────────────────────────────── */

.snippet {
  position: relative;
  background: #060606;
  border: 1px solid var(--border-strong);
  border-radius: var(--r-md);
  padding: 14px 52px 14px 16px;
  font-family: var(--font-mono);
  font-size: 12.5px; line-height: 1.7;
  overflow-x: auto; white-space: pre;
}
.snippet .tok-tag { color: #ff8fa3; }
.snippet .tok-attr { color: var(--accent); }
.snippet .tok-str { color: var(--success); }
.snippet .copy {
  position: absolute; top: 8px; right: 8px;
}

/* ─── Install verification result ───────────────────────────── */
.verify-result { display: none; margin-top: 12px; }
.verify-result.show { display: flex; gap: 8px; align-items: flex-start; padding: 10px 12px; border-radius: var(--r-md); font-size: 13px; border: 1px solid var(--border); }
.verify-result .vi { display: inline-flex; flex: 0 0 auto; margin-top: 1px; }
.verify-result .vi svg { width: 16px; height: 16px; }
.verify-result.ok   { background: var(--success-soft); border-color: rgba(74,222,128,.35); color: #86efac; }
.verify-result.warn { background: rgba(251,191,36,.12); border-color: rgba(251,191,36,.3); color: #fbbf24; }
.verify-result.bad  { background: var(--danger-soft); border-color: rgba(255,97,102,.35); color: #ff9a9d; }

/* ─── Loading-indicator configurator ────────────────────────── */

.lseg { display: inline-flex; flex-wrap: wrap; gap: 4px; background: var(--panel-2); border: 1px solid var(--border); border-radius: var(--r-md); padding: 3px; }
.lseg button { border: 0; background: transparent; color: var(--text-dim); font: inherit; font-size: 13px; padding: 6px 13px; border-radius: 6px; cursor: pointer; }
.lseg button:hover { background: var(--panel-hover); color: var(--text); }
.lseg button.on { background: var(--accent-soft); color: var(--accent); font-weight: 550; }
.ldr-opts { display: flex; flex-direction: column; gap: 10px; margin: 14px 0 4px; }
.ldr-opts:empty { margin: 0; }
.lrow { display: flex; align-items: center; gap: 12px; }
.lrow-label { flex: 0 0 110px; font-size: 13px; color: var(--text-dim); }
.lrow .linput, .lrow .color-ctl .hex {
  background: var(--panel-2); border: 1px solid var(--border); border-radius: 7px;
  color: var(--text); padding: 6px 10px; outline: none; font: inherit; font-size: 13px;
}
.lrow .linput { flex: 1; }
.lrow .color-ctl { display: inline-flex; align-items: center; gap: 8px; }
.lrow .color-ctl input[type=color] { -webkit-appearance: none; appearance: none; width: 30px; height: 30px; padding: 0; border: 1px solid var(--border); border-radius: 7px; background: none; cursor: pointer; }
.lrow .color-ctl input[type=color]::-webkit-color-swatch-wrapper { padding: 2px; }
.lrow .color-ctl input[type=color]::-webkit-color-swatch { border: 0; border-radius: 5px; }
.lrow .color-ctl .hex { width: 96px; font-family: var(--font-mono); font-size: 12.5px; }

.ldr-preview { margin-top: 14px; border: 1px solid var(--border); border-radius: var(--r-md); overflow: hidden; }
.ldr-none { padding: 22px 16px; text-align: center; color: var(--text-faint); font-size: 13px; }
.ldr-preview.on { position: relative; height: 150px; background: #f4f4f5; }
.pv-page { position: absolute; inset: 0; background:
  repeating-linear-gradient(0deg, transparent 0 18px, rgba(0,0,0,.04) 18px 20px); }
.pv-bar { position: absolute; top: 0; left: 0; right: 0; height: 3px; background: color-mix(in srgb, var(--acc) 18%, transparent); overflow: hidden; z-index: 1; }
.pv-bar::before { content: ""; position: absolute; inset: 0 auto 0 0; width: 40%; background: var(--acc); animation: pv-slide 1.1s cubic-bezier(.4,0,.2,1) infinite; }
@keyframes pv-slide { 0% { left: -40%; } 50% { left: 30%; width: 55%; } 100% { left: 100%; } }
.pv-ov { position: absolute; inset: 0; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 12px; }
.pv-ov img { max-width: 120px; max-height: 40px; object-fit: contain; }
.pv-spin { width: 28px; height: 28px; border-radius: 50%; border: 3px solid color-mix(in srgb, var(--acc) 22%, transparent); border-top-color: var(--acc); animation: pv-spin .7s linear infinite; }
.pv-txt { font-size: 13px; font-weight: 500; }
@keyframes pv-spin { to { transform: rotate(360deg); } }
.pv-sk { position: absolute; inset: 0; padding: 22px; display: flex; flex-direction: column; gap: 12px; justify-content: center; }
.pv-sk span { height: 16px; border-radius: 6px; background: linear-gradient(100deg, rgba(0,0,0,.06) 30%, rgba(0,0,0,.12) 50%, rgba(0,0,0,.06) 70%); background-size: 200% 100%; animation: pv-shimmer 1.2s ease-in-out infinite; }
@keyframes pv-shimmer { 0% { background-position: 200% 0; } 100% { background-position: -200% 0; } }

/* ─── Tabs ──────────────────────────────────────────────────── */

.tabs {
  position: relative;
  display: flex;
  gap: 2px;
  border-bottom: 1px solid var(--border);
  margin: var(--s-6) 0;
  overflow-x: auto;
  scrollbar-width: none;
}
.tabs::-webkit-scrollbar { display: none; }
.tab {
  position: relative;
  display: inline-flex; align-items: center; gap: 7px;
  height: 40px; padding: 0 12px;
  background: transparent; border: 0;
  color: var(--text-dim); font: inherit; font-size: 14px; font-weight: 500;
  white-space: nowrap; cursor: pointer;
  transition: color .15s;
}
.tab:hover { color: var(--text); }
.tab.active { color: #fff; }
.tab:focus-visible { outline: 2px solid var(--ring); outline-offset: -6px; border-radius: 8px; }
.tab .count {
  min-width: 20px; height: 20px; padding: 0 6px;
  display: inline-grid; place-items: center;
  border-radius: var(--r-full);
  background: var(--panel-2); border: 1px solid var(--border);
  color: var(--text-dim); font-size: 11px; font-weight: 600;
  font-variant-numeric: tabular-nums;
}
.tab.active .count { color: var(--text); border-color: var(--border-strong); }
.tab-ink {
  position: absolute; bottom: -1px; left: 0;
  height: 2px; width: 0; border-radius: 2px;
  background: #fff; pointer-events: none;
  transition: transform .28s cubic-bezier(.16,1,.3,1), width .28s cubic-bezier(.16,1,.3,1);
}
.panel { animation: fade-up .3s cubic-bezier(.16,1,.3,1) both; }
.panel[hidden] { display: none; }
.panel .section-title:first-child { margin-top: 0; }

/* ─── Empty states ──────────────────────────────────────────── */

.empty { text-align: center; padding: var(--s-10) var(--s-6); }
.empty .ei {
  width: 46px; height: 46px; margin: 0 auto var(--s-4);
  display: grid; place-items: center; border-radius: 12px;
  background: var(--panel-2); border: 1px solid var(--border); color: var(--text-faint);
}
.empty .ei svg { width: 22px; height: 22px; }
.empty h3 { font-size: 15px; font-weight: 600; margin-bottom: 4px; }
.empty p { color: var(--text-faint); font-size: 13px; max-width: 340px; margin: 0 auto; }

/* ─── Toasts ────────────────────────────────────────────────── */

#toasts {
  position: fixed; bottom: 20px; right: 20px; z-index: 90;
  display: flex; flex-direction: column; gap: 10px; max-width: 380px;
}
.toast {
  display: flex; align-items: flex-start; gap: 10px;
  padding: 12px 14px; border-radius: var(--r-md);
  background: var(--panel); border: 1px solid var(--border-strong);
  box-shadow: var(--shadow-md); color: var(--text); font-size: 13.5px;
  animation: toast-in .28s cubic-bezier(.16,1,.3,1);
}
.toast.out { animation: toast-out .2s ease forwards; }
.toast .ti { width: 18px; height: 18px; flex-shrink: 0; margin-top: 1px; }
.toast.success .ti { color: var(--success); }
.toast.error .ti { color: var(--danger); }
.toast.info .ti { color: var(--accent); }
.toast .tt { font-weight: 600; }
.toast .td { color: var(--text-dim); font-size: 12.5px; margin-top: 2px; }

/* ─── Modal ─────────────────────────────────────────────────── */

#modal-root { position: fixed; inset: 0; z-index: 80; display: none; }
#modal-root.open { display: block; }
.modal-scrim {
  position: absolute; inset: 0; background: rgba(0,0,0,.6);
  backdrop-filter: blur(3px); -webkit-backdrop-filter: blur(3px);
  animation: fade-in .18s ease;
}
.modal {
  position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%);
  width: min(440px, calc(100vw - 32px));
  background: rgba(20, 20, 23, .82);
  -webkit-backdrop-filter: blur(30px) saturate(150%);
          backdrop-filter: blur(30px) saturate(150%);
  border: 1px solid rgba(255, 255, 255, .1);
  border-radius: var(--r-lg); box-shadow: var(--shadow-lg);
  padding: var(--s-6);
  animation: modal-in .22s cubic-bezier(.16,1,.3,1);
}
.modal h3 { font-size: 16px; margin-bottom: 8px; }
.modal p { color: var(--text-dim); font-size: 13.5px; }
.modal .modal-actions { display: flex; justify-content: flex-end; gap: 10px; margin-top: var(--s-6); }
.modal .warn-icon {
  width: 40px; height: 40px; border-radius: 10px; margin-bottom: var(--s-4);
  display: grid; place-items: center;
  background: var(--danger-soft); color: var(--danger); border: 1px solid rgba(255,97,102,.3);
}
.modal .warn-icon svg { width: 20px; height: 20px; }

/* ── First-run onboarding ─────────────────────────────────── */
.modal.intro { width: min(500px, calc(100vw - 32px)); text-align: left; }
.intro-badge {
  width: 42px; height: 42px; border-radius: 11px; margin-bottom: var(--s-4);
  display: grid; place-items: center;
  background: linear-gradient(135deg, rgba(242,98,34,.24), rgba(242,98,34,.08));
  color: var(--accent); border: 1px solid rgba(242,98,34,.32);
}
.intro-badge svg { width: 22px; height: 22px; }
.modal.intro h3 { font-size: 19px; }
.modal.intro > p { margin-bottom: var(--s-5); }

.steps { list-style: none; margin: 0 0 var(--s-5); padding: 0; display: grid; gap: 12px; }
.steps.compact { gap: 9px; }
.steps li { display: grid; grid-template-columns: 26px 1fr; gap: 12px; align-items: start; }
.step-n {
  width: 26px; height: 26px; border-radius: 50%; display: grid; place-items: center;
  font-size: 12.5px; font-weight: 700; color: var(--accent);
  background: var(--accent-soft); border: 1px solid rgba(242,98,34,.3);
}
.steps li > div { display: flex; flex-direction: column; gap: 2px; }
.steps li b { font-size: 13.5px; }
.steps li span:not(.step-n) { color: var(--text-dim); font-size: 12.5px; line-height: 1.5; }
.steps code { font-size: 11.5px; background: var(--bg-2, rgba(255,255,255,.06)); padding: 1px 5px; border-radius: 4px; }


/* ── Tooltip ──────────────────────────────────────────────── */
/* Frosted like every other floating surface, rather than the flat panel fill it
   used before, which read as belonging to an older version of the UI. */
.tip {
  position: fixed; z-index: 3000; transform: translate(-50%, -100%);
  background: var(--glass-overlay); color: var(--text);
  -webkit-backdrop-filter: var(--glass-blur-up);
          backdrop-filter: var(--glass-blur-up);
  border: 1px solid var(--glass-line-up);
  padding: 7px 11px; border-radius: 8px; font-size: 12px; line-height: 1.35;
  max-width: 240px; pointer-events: none;
  box-shadow: 0 12px 30px -10px rgba(0,0,0,.7), var(--glass-hi);
  opacity: 0; visibility: hidden; transition: opacity .12s ease; white-space: normal;
}
.tip.show { opacity: 1; visibility: visible; }
/* The arrow tracks the tooltip's own edge colour so the two cannot drift. */
.tip::after {
  content: ""; position: absolute; left: 50%; top: 100%; transform: translateX(-50%);
  border: 5px solid transparent; border-top-color: var(--glass-line-up);
}

/* First-run coaching bubble (accent, points down at its anchor) */
.coach {
  position: fixed; z-index: 3100; transform: translate(-50%, -100%) translateY(6px);
  display: flex; align-items: center; gap: 8px; max-width: 300px;
  background: var(--accent); color: #fff; border-radius: 9px; padding: 9px 10px 9px 12px;
  font-size: 12.5px; font-weight: 550; line-height: 1.4; box-shadow: 0 10px 30px rgba(0,0,0,.4);
  opacity: 0; transition: opacity .2s ease, transform .2s ease; pointer-events: auto;
}
.coach.show { opacity: 1; transform: translate(-50%, -100%); }
.coach::after {
  content: ""; position: absolute; left: 50%; top: 100%; transform: translateX(-50%);
  border: 6px solid transparent; border-top-color: var(--accent);
}
.coach-x { background: transparent; border: 0; color: #fff; opacity: .7; font-size: 16px; line-height: 1; cursor: pointer; padding: 0 2px; }
.coach-x:hover { opacity: 1; }

/* TOTP QR */
.qr-wrap { display: flex; justify-content: center; margin: 4px 0 14px; }
.qr { border-radius: 10px; background: #fff; padding: 10px; box-shadow: var(--shadow-lg); }
.manual-key { margin-bottom: var(--s-2); }
.manual-key > summary { cursor: pointer; color: var(--muted); font-size: 12.5px; list-style: none; user-select: none; }
.manual-key > summary::-webkit-details-marker { display: none; }
.manual-key > summary:hover { color: var(--text); }
.manual-key[open] > summary { color: var(--text); margin-bottom: 2px; }

/* ─── Auth screens ──────────────────────────────────────────── */

.auth { min-height: 100vh; display: grid; place-items: center; padding: var(--s-6); }
.auth-box { width: 100%; max-width: 380px; }
.auth-brand { display: flex; flex-direction: column; align-items: center; gap: 10px; margin-bottom: var(--s-6); }
.auth-brand .brand-logo { height: 30px; width: auto; display: block; }
.auth-brand .product {
  font-size: 13px; font-weight: 600; letter-spacing: .12em; text-transform: uppercase;
  color: var(--accent);
}
.auth-title { text-align: center; margin-bottom: var(--s-6); }
.auth-title h1 { font-size: 21px; }
.auth-title p { color: var(--text-dim); font-size: 13.5px; margin-top: 4px; }
.auth .card-pad { padding: var(--s-6); }
.auth-foot { text-align: center; margin-top: var(--s-5); color: var(--text-faint); font-size: 12.5px; }

/* ─── Skeletons ─────────────────────────────────────────────── */

.skel { background: linear-gradient(90deg, #141414 25%, #1e1e1e 37%, #141414 63%);
  background-size: 400% 100%; animation: shimmer 1.3s ease infinite; border-radius: 6px; }
.skel-line { height: 12px; margin: 8px 0; }
.skel-card { height: 120px; border-radius: var(--r-lg); }

/* ─── Utilities ─────────────────────────────────────────────── */

.row { display: flex; align-items: center; gap: var(--s-3); }
.row.wrap { flex-wrap: wrap; }
.grow { flex: 1; min-width: 0; }
.right { margin-left: auto; }
.muted { color: var(--text-dim); }
.faint { color: var(--text-faint); }
.mono { font-family: var(--font-mono); }
.truncate { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.stack-sm > * + * { margin-top: var(--s-3); }
.hide { display: none !important; }

.view { animation: fade-up .4s cubic-bezier(.16,1,.3,1) both; }
/* The stage fades but does not travel: sliding it up on entry would pull its
   top edge away from the active tab for the length of the animation, and the
   join between the two is the whole idea. Inner content still travels. */
main.view { animation: fade-in .32s ease both; }
@keyframes fade-in { from { opacity: 0; } to { opacity: 1; } }
.stagger > * { animation: fade-up .45s cubic-bezier(.16,1,.3,1) both; }
.stagger > *:nth-child(1) { animation-delay: .02s; }
.stagger > *:nth-child(2) { animation-delay: .06s; }
.stagger > *:nth-child(3) { animation-delay: .10s; }
.stagger > *:nth-child(4) { animation-delay: .14s; }
.stagger > *:nth-child(5) { animation-delay: .18s; }
.stagger > *:nth-child(6) { animation-delay: .22s; }

/* ─── Keyframes ─────────────────────────────────────────────── */

@keyframes spin { to { transform: rotate(360deg); } }
@keyframes shimmer { to { background-position: -200% 0; } }
@keyframes fade-in { from { opacity: 0; } }
@keyframes fade-up { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }
@keyframes modal-in { from { opacity: 0; transform: translate(-50%, -46%) scale(.97); } }
@keyframes toast-in { from { opacity: 0; transform: translateX(16px); } }
@keyframes toast-out { to { opacity: 0; transform: translateX(16px); } }

/* ─── Responsive ────────────────────────────────────────────── */

@media (max-width: 720px) {
  main.view { padding: var(--s-6) var(--s-4) var(--s-10); }
  .userchip .email { display: none; }
  .page-head h1 { font-size: 22px; }
  .grid { grid-template-columns: 1fr; }
  .card-foot { flex-wrap: wrap; }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: .01ms !important; animation-iteration-count: 1 !important; transition-duration: .01ms !important; }
  .view, .stagger > * { animation: none; }
}

/* --- Wolfigs admin panel --- */
.menu-head .role-tag {
  display: inline-block; margin-top: var(--s-2); padding: 1px 8px;
  font-size: 11px; font-weight: 600; color: var(--accent);
  background: var(--accent-soft); border-radius: var(--r-full);
}
.menu-link {
  display: flex; align-items: center; gap: var(--s-3); width: 100%;
  padding: var(--s-3) var(--s-4); background: none; border: 0; cursor: pointer;
  color: var(--text); text-decoration: none; font: inherit; text-align: left;
}
.menu-link:hover { background: var(--panel-hover); }
.stat-n { font-size: 28px; font-weight: 700; line-height: 1.1; color: var(--text); }
.stat-l { margin-top: var(--s-2); font-size: 13px; color: var(--text-dim); }
.tbl { width: 100%; border-collapse: collapse; font-size: 14px; }
.tbl thead th {
  text-align: left; padding: var(--s-3) var(--s-4); font-size: 12px;
  font-weight: 600; color: var(--text-dim); border-bottom: 1px solid var(--border);
}
.tbl td { padding: var(--s-3) var(--s-4); border-bottom: 1px solid var(--border); vertical-align: middle; }
.tbl tr:last-child td { border-bottom: 0; }
.tbl .right, .page-head .right { text-align: right; }
.tbl .u-name { font-weight: 600; color: var(--text); }
.tbl .u-email { font-size: 12px; color: var(--text-dim); }
.btn.sm.danger, .btn-ghost.danger { color: var(--danger); }
.checkgrid { display: grid; grid-template-columns: 1fr 1fr; gap: var(--s-2) var(--s-4); }
.checkrow { display: flex; align-items: center; gap: var(--s-2); font-size: 14px; color: var(--text); cursor: pointer; }
.checkrow input { accent-color: var(--accent); }
.modal.wide { max-width: 520px; width: 92%; }

/* Inline text button (e.g. "Use a recovery code" on the login challenge). */
.linkbtn { display: inline-flex; align-items: center; gap: 6px; background: none; border: 0;
  color: var(--accent); font: inherit; font-size: 13px; cursor: pointer; padding: 4px; }
.linkbtn svg { width: 14px; height: 14px; flex: none; }
.linkbtn:hover { color: var(--accent-strong); text-decoration: underline; }
.sec-methods { margin-top: 6px; }

/* Standalone spinner (e.g. signing-out screen) */
.spinner {
  width: 30px; height: 30px; border-radius: 50%;
  border: 3px solid var(--border-strong); border-top-color: var(--accent);
  animation: spin .8s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { .spinner { animation-duration: 1.8s; } }

/* ─── System architecture (admin infra map) ──────────────────── */
.infra-head { display: flex; align-items: center; gap: 12px; }
.infra-updated { color: var(--text-faint); font-size: 12.5px; font-variant-numeric: tabular-nums; }

.infra-legend {
  display: flex; flex-wrap: wrap; gap: 16px; align-items: center;
  margin: 0 0 16px; font-size: 12px; color: var(--text-dim);
}
.infra-legend span { display: inline-flex; align-items: center; gap: 6px; }
.infra-legend .ls { width: 9px; height: 9px; border-radius: 50%; }
.ls.ok { background: var(--success); } .ls.degraded { background: var(--warning); }
.ls.down { background: var(--danger); } .ls.info { background: #6b7280; }
.infra-legend .lf { width: 18px; height: 0; border-top: 2px solid; }
.lf.data { border-color: var(--accent); }
.lf.deploy { border-top-style: dashed; border-color: #6b7280; }

.arch-wrap { overflow: hidden; border: 1px solid var(--border); border-radius: var(--r-lg);
  background: linear-gradient(180deg, var(--panel), var(--bg-elevated)); padding: 20px; }
/* The map is a fixed 960×480 canvas scaled by JS (fitArch) to fill its column,
   from the top-left, so it fills the width and never clips. */
.arch { position: relative; margin: 0; transform-origin: top left; }
.arch-edges { position: absolute; inset: 0; overflow: visible; pointer-events: none; }
.arch-edge { fill: none; stroke: #6b7280; stroke-width: 1.6; opacity: .5; }
.arch-edge.data { stroke: var(--accent); opacity: .55; }
.arch-edge.deploy { stroke: #5b5b5b; stroke-dasharray: 5 5; opacity: .5; }
.arch-edge.data.live { stroke-dasharray: 5 7; animation: arch-flow 1s linear infinite; opacity: .9; }
@keyframes arch-flow { to { stroke-dashoffset: -12; } }

.arch-node {
  position: absolute; width: 168px; height: 64px;
  display: flex; align-items: center; gap: 10px; padding: 0 12px;
  background: var(--panel-2); border: 1px solid var(--border-strong);
  border-radius: var(--r-md); box-shadow: var(--shadow-sm);
  cursor: pointer; text-align: left; font: inherit; color: var(--text);
  transition: border-color .15s, transform .15s, box-shadow .15s; z-index: 1;
}
.arch-node:hover { border-color: var(--accent); transform: translateY(-1px); box-shadow: var(--shadow-md); }
.arch-node.sel { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent); }
.arch-node .an-ico { color: var(--text-dim); flex: none; }
.arch-node .an-ico svg { width: 20px; height: 20px; }
.an-body { display: flex; flex-direction: column; min-width: 0; gap: 1px; }
.an-label { font-size: 13px; font-weight: 600; line-height: 1.1; }
.an-sub { font-size: 11px; color: var(--text-faint); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 108px; }
.an-dot { position: absolute; top: 9px; right: 9px; width: 9px; height: 9px; border-radius: 50%; background: #6b7280; }
.an-dot.st-ok { background: var(--success); box-shadow: 0 0 0 3px var(--success-soft); }
.an-dot.st-degraded { background: var(--warning); box-shadow: 0 0 0 3px rgba(245,196,81,.16); }
.an-dot.st-down { background: var(--danger); box-shadow: 0 0 0 3px var(--danger-soft); animation: arch-blink 1s steps(2) infinite; }
.an-dot.st-info { background: #6b7280; }
.an-dot.st-unknown { background: #4b4b4b; animation: arch-pulse 1.2s ease-in-out infinite; }
@keyframes arch-blink { 50% { opacity: .35; } }
@keyframes arch-pulse { 50% { opacity: .4; } }
.an-chips { position: absolute; bottom: -9px; left: 12px; display: flex; gap: 5px; }
.an-chip {
  font-size: 9.5px; font-weight: 600; letter-spacing: .03em; text-transform: uppercase;
  padding: 1px 6px 1px 14px; border-radius: 999px; position: relative;
  background: var(--panel); border: 1px solid var(--border-strong); color: var(--text-dim);
}
.an-chip::before { content: ""; position: absolute; left: 5px; top: 50%; transform: translateY(-50%); width: 6px; height: 6px; border-radius: 50%; background: #6b7280; }
.an-chip.st-ok::before { background: var(--success); }
.an-chip.st-degraded::before { background: var(--warning); }
.an-chip.st-down::before { background: var(--danger); }

.infra-detail { margin-top: 16px; background: var(--panel); border: 1px solid var(--border); border-radius: var(--r-lg); padding: 16px 18px; min-height: 72px; }
.id-head { display: flex; align-items: center; gap: 10px; margin-bottom: 8px; }
.id-head .an-ico { color: var(--text-dim); } .id-head .an-ico svg { width: 18px; height: 18px; }
.id-head b { font-size: 14px; }
.id-tip { color: var(--text-dim); font-size: 13px; margin: 0 0 12px; max-width: 70ch; line-height: 1.5; }
.id-lines { display: grid; gap: 6px; }
.idl { display: flex; gap: 12px; font-size: 12.5px; }
.idl-k { color: var(--text-faint); min-width: 60px; font-family: var(--font-mono); font-size: 11.5px; text-transform: uppercase; letter-spacing: .04em; padding-top: 2px; }
.idl-v { display: inline-flex; align-items: center; gap: 7px; color: var(--text); }
.idl-v .an-dot { width: 8px; height: 8px; }

/* ─── Settings (vertical-nav account area) ───────────────────── */
.settings-layout { display: grid; grid-template-columns: 216px 1fr; gap: 24px; align-items: start; }
.settings-nav { display: flex; flex-direction: column; gap: 2px; position: sticky; top: 20px; }
.settings-nav .snav {
  display: flex; align-items: center; gap: 10px; padding: 9px 12px; border-radius: var(--r-md);
  color: var(--text-dim); font-size: 13.5px; font-weight: 500; border: 1px solid transparent;
  transition: background .12s, color .12s;
}
.settings-nav .snav svg { width: 17px; height: 17px; flex: none; opacity: .85; }
.settings-nav .snav:hover { background: var(--panel-2); color: var(--text); }
.settings-nav .snav.active { background: var(--panel-2); color: var(--text); border-color: var(--border-strong); }
.settings-nav .snav.active svg { color: var(--accent); opacity: 1; }
.settings-panel { min-width: 0; }
.settings-panel .card + .card { margin-top: 14px; }

.ro-row { display: flex; align-items: center; gap: 10px; }
.ro-row input { flex: 1; }

.sess-list, .notif-list { margin-top: 6px; }
.sess-row, .notif-row { display: flex; align-items: center; gap: 12px; padding: 12px 0; border-top: 1px solid var(--border); }
.sess-row:first-child, .notif-row:first-child { border-top: 0; }
.sess-row .grow, .notif-row > div { min-width: 0; }
.notif-ico { color: var(--text-faint); flex: none; } .notif-ico svg { width: 18px; height: 18px; }

@media (max-width: 720px) {
  .settings-layout { grid-template-columns: 1fr; gap: 14px; }
  .settings-nav { flex-direction: row; overflow-x: auto; position: static; gap: 6px; padding-bottom: 4px; }
  .settings-nav .snav { white-space: nowrap; }
  .settings-nav .snav span { display: inline; }
}

/* Toggle switch (notification prefs) */
.switch { position: relative; display: inline-block; width: 40px; height: 22px; flex: none; }
.switch input { opacity: 0; width: 0; height: 0; }
.switch .slider {
  position: absolute; inset: 0; cursor: pointer; border-radius: 999px;
  background: var(--panel-hover); border: 1px solid var(--border-strong);
  transition: background .18s, border-color .18s;
}
.switch .slider::before {
  content: ""; position: absolute; height: 16px; width: 16px; left: 2px; top: 2px;
  border-radius: 50%; background: #cfcfcf; transition: transform .18s, background .18s;
}
.switch input:checked + .slider { background: var(--accent); border-color: var(--accent); }
.switch input:checked + .slider::before { transform: translateX(18px); background: #fff; }
.switch input:focus-visible + .slider { box-shadow: 0 0 0 3px var(--ring); }

/* ============================================================= */
/* Platform controls, admin panel, and the support/feedback UI.  */
/* ============================================================= */

/* Missing badge alias + small spinner used by the widget/admin. */
.badge.danger { color: var(--danger); background: var(--danger-soft); border-color: rgba(255,97,102,.3); }
.spinner.sm { width: 20px; height: 20px; border-width: 2px; margin: 20px auto; }
.big-ico { display: inline-grid; place-items: center; width: 56px; height: 56px; border-radius: 999px;
  background: var(--panel-2); color: var(--text-dim); margin: 0 auto; }
.big-ico svg { width: 28px; height: 28px; }
.big-ico.danger { color: var(--danger); background: var(--danger-soft); }

/* Platform banner (announcement / read-only) above the top nav. */
.pbanner { display: flex; align-items: center; gap: 10px; padding: 9px 20px; font-size: 13.5px;
  border-bottom: 1px solid var(--border); background: var(--panel-2); color: var(--text-dim); }
.pbanner svg { width: 16px; height: 16px; flex: none; }
.pbanner.info { background: rgba(120,160,255,.10); color: #9db8ff; border-bottom-color: rgba(120,160,255,.2); }
.pbanner.warn { background: rgba(251,191,36,.12); color: #fbbf24; border-bottom-color: rgba(251,191,36,.28); }
.pbanner.critical { background: var(--danger-soft); color: var(--danger); border-bottom-color: rgba(255,97,102,.3); }

/* Admin: grouped sidebar nav + panel (mirrors the settings layout). */
.admin-layout { display: grid; grid-template-columns: 220px 1fr; gap: 24px; align-items: start; }
.admin-nav { display: flex; flex-direction: column; gap: 2px; position: sticky; top: 20px; }
.admin-navgroup { font-size: 11px; text-transform: uppercase; letter-spacing: .06em; color: var(--text-faint);
  font-weight: 600; padding: 12px 10px 4px; }
.admin-navgroup:first-child { padding-top: 0; }
.admin-nav .anav { display: flex; align-items: center; gap: 9px; padding: 8px 10px; border-radius: 8px;
  font-size: 13.5px; font-weight: 500; color: var(--text-dim); border: 1px solid transparent; }
.admin-nav .anav svg { width: 16px; height: 16px; opacity: .85; flex: none; }
.admin-nav .anav:hover { background: var(--panel-2); color: var(--text); }
.admin-nav .anav.active { background: var(--panel-2); color: var(--text); border-color: var(--border-strong); }
.admin-nav .anav.active svg { color: var(--accent); opacity: 1; }
.admin-panel { min-width: 0; }
.admin-panel .card + .card { margin-top: 14px; }

/* Operations home (admin landing): architecture + management entry, side by side. */
.ops-split { display: grid; grid-template-columns: minmax(0, 1fr) 300px; gap: 24px; align-items: start; }
.ops-main { min-width: 0; }           /* lets the wide arch map scroll inside its own box */
.ops-rail { position: sticky; top: 20px; }
.ops-railgrid { display: flex; flex-direction: column; gap: 8px; }
@media (max-width: 1080px) {
  .ops-split { grid-template-columns: 1fr; }
  .ops-rail { position: static; }
  .ops-railgrid { display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); }
}
.ops-sectionhead { display: flex; align-items: baseline; gap: 10px; margin: 0 0 12px; }
.ops-sectionhead h2 { margin: 0; font-size: 16px; }
.ops-sectionhead .muted { font-size: 12.5px; }
.ops-card { display: flex; align-items: center; gap: 12px; padding: 14px 15px; border-radius: 12px;
  background: linear-gradient(180deg, var(--panel), var(--bg-elevated)); border: 1px solid var(--border); transition: border-color .15s, transform .15s; }
.ops-card:hover { border-color: var(--border-strong); transform: translateY(-1px); }
.ops-card-ic { display: grid; place-items: center; width: 36px; height: 36px; border-radius: 9px;
  background: var(--panel-2); color: var(--accent); flex: none; }
.ops-card-ic svg { width: 18px; height: 18px; }
.ops-card-txt { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1; }
.ops-card-txt b { font-size: 14px; font-weight: 600; }
.ops-card-txt i { font-style: normal; font-size: 12px; color: var(--text-faint); line-height: 1.35; }
.ops-card-go { color: var(--text-faint); flex: none; }
.ops-card-go svg { width: 16px; height: 16px; }
.ops-card:hover .ops-card-go { color: var(--accent); }

/* Section intro header (title + one-line description + right-aligned actions). */
.admin-intro { display: flex; align-items: flex-end; gap: 16px; margin: 0 0 18px; }
.admin-intro h2 { margin: 0; font-size: 20px; }
.admin-intro p { margin: 3px 0 0; color: var(--text-dim); font-size: 13.5px; }

/* Overview stat groups. */
.stat-group { margin-bottom: 18px; }
.stat-group h3 { margin: 0 0 10px; font-size: 13px; text-transform: uppercase; letter-spacing: .04em; color: var(--text-faint); }
.stat-hint { color: var(--text-faint); font-size: 11.5px; margin-top: 4px; }

@media (max-width: 760px) {
  .admin-layout { grid-template-columns: 1fr; gap: 14px; }
  .admin-nav { position: static; flex-direction: row; flex-wrap: wrap; gap: 4px; }
  .admin-navgroup { display: none; }
  .stat-group .grid, .admin-panel .grid { grid-template-columns: repeat(2,1fr) !important; }
}

/* Control cards + danger zone. */
.ctl-cardhead { margin-bottom: 6px; }
.ctl-cardsub { margin: 2px 0 0; color: var(--text-dim); font-size: 12.5px; }
.ctl-stack { padding: 12px 0; border-top: 1px solid var(--border); }
.ctl-num.wide { width: auto; min-width: 150px; text-align: left; }
.danger-zone { background: var(--danger-soft); border: 1px solid rgba(255,97,102,.28); border-radius: var(--radius, 12px);
  padding: 16px 18px; margin-top: 14px; }
.danger-zone .ctl-row { border-top-color: rgba(255,97,102,.18); }
.dz-head { display: flex; align-items: flex-start; gap: 10px; margin-bottom: 8px; }
.dz-head svg { width: 20px; height: 20px; color: var(--danger); flex: none; margin-top: 2px; }
.dz-head h2, .dz-head h4 { margin: 0; }

/* Control rows (settings form). */
.ctl-h { margin: 0 0 6px; font-size: 15px; }
.ctl-row { display: flex; align-items: center; gap: 16px; padding: 12px 0; border-top: 1px solid var(--border); }
.ctl-row:first-of-type { border-top: 0; }
.ctl-label { font-weight: 550; font-size: 14px; }
.ctl-desc { color: var(--text-faint); font-size: 12.5px; margin-top: 2px; }
.ctl-num { width: 96px; padding: 7px 9px; border-radius: 8px; background: var(--panel-2);
  border: 1px solid var(--border-strong); color: var(--text); text-align: right; }
.ctl-area { width: 100%; margin: 4px 0 4px; padding: 9px 11px; border-radius: 8px; background: var(--panel-2);
  border: 1px solid var(--border-strong); color: var(--text); font: inherit; resize: vertical; min-height: 58px; }
.ctl-save { display: flex; align-items: center; justify-content: flex-end; gap: 14px; margin-top: 16px; }

/* Clickable table rows + segmented filter. */
.clickrow { cursor: pointer; }
.clickrow:hover td { background: var(--panel-2); }
.seg { display: inline-flex; gap: 2px; background: var(--panel-2); border: 1px solid var(--border); border-radius: 8px; padding: 2px; }
.seg-btn { background: transparent; border: 0; color: var(--text-dim); padding: 5px 12px; border-radius: 6px; font-size: 13px; cursor: pointer; }
.seg-btn.on { background: var(--panel-hover); color: var(--text); }

/* Per-account management modal (tabbed sheet). */
.umodal { max-width: 500px; padding: 0; overflow: hidden; }
.umodal-head { display: flex; align-items: flex-start; gap: 13px; padding: 20px 20px 16px; border-bottom: 1px solid var(--border); }
.avatar.lg { width: 44px; height: 44px; font-size: 16px; flex: none; }
.umodal-head .sw-x { margin: -4px -4px 0 0; }
.utabs { display: flex; gap: 2px; padding: 10px 14px 0; border-bottom: 1px solid var(--border); }
.utab { background: transparent; border: 0; border-bottom: 2px solid transparent; color: var(--text-dim);
  font: inherit; font-size: 13.5px; font-weight: 500; padding: 9px 12px; cursor: pointer; margin-bottom: -1px; }
.utab:hover { color: var(--text); }
.utab.on { color: var(--text); border-bottom-color: var(--accent); }
.umodal-body { padding: 18px 20px 20px; max-height: 60vh; overflow-y: auto; }
.umodal-body .msheet-desc { margin: 0 0 14px; color: var(--text-dim); font-size: 13px; }

/* Full-width action rows (Actions + Danger tabs). */
.urows { display: flex; flex-direction: column; gap: 8px; }
.urow { display: flex; align-items: center; gap: 12px; width: 100%; text-align: left; cursor: pointer;
  background: var(--panel-2); border: 1px solid var(--border); border-radius: 10px; padding: 12px 14px; color: var(--text); }
.urow:hover { border-color: var(--border-strong); background: var(--panel-hover); }
.urow-ic { display: grid; place-items: center; width: 34px; height: 34px; border-radius: 8px; flex: none;
  background: var(--panel); color: var(--text-dim); }
.urow-ic svg { width: 17px; height: 17px; }
.urow-tx { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.urow-tx b { font-size: 13.5px; font-weight: 600; }
.urow-tx i { font-style: normal; font-size: 12px; color: var(--text-faint); line-height: 1.35; }
.urow-go { color: var(--text-faint); flex: none; }
.urow-go svg { width: 16px; height: 16px; }
.urow:hover .urow-go { color: var(--accent); }
.urow.danger { border-color: rgba(255,97,102,.28); }
.urow.danger:hover { background: var(--danger-soft); }
.urow.danger .urow-ic, .urow.danger .urow-tx b { color: var(--danger); }

/* Access & limits fields. */
.urow-field { padding: 12px 0; border-top: 1px solid var(--border); }
.urow-field:first-of-type { border-top: 0; padding-top: 0; }
.urow-field > label { display: block; font-size: 13px; font-weight: 550; margin-bottom: 7px; }
.msheet-foot { margin-top: 18px; display: flex; justify-content: flex-end; }
.msheet-desc { margin: 0 0 10px; color: var(--text-dim); font-size: 12.5px; }

/* Support / feedback floating widget. */
.support-widget { position: fixed; right: 22px; bottom: 22px; z-index: 900; display: flex; flex-direction: column; align-items: flex-end; gap: 12px; }
.sw-fab { width: 52px; height: 52px; border-radius: 999px; border: 0; cursor: pointer; align-self: flex-end;
  background: var(--accent); color: #fff; display: grid; place-items: center; box-shadow: 0 8px 24px rgba(0,0,0,.4); transition: transform .15s; }
.sw-fab:hover { transform: translateY(-2px); }
.sw-fab svg { width: 24px; height: 24px; }
.support-widget.open .sw-fab svg { opacity: .9; }
.sw-panel { width: 360px; max-width: calc(100vw - 32px); height: 520px; max-height: calc(100vh - 120px);
  background: var(--bg-elevated); border: 1px solid var(--border-strong); border-radius: 16px; overflow: hidden;
  display: flex; flex-direction: column; box-shadow: 0 20px 60px rgba(0,0,0,.55); }
/* The panel starts closed; a display rule would otherwise beat the [hidden]
   attribute's default display:none, so hide it explicitly when hidden. */
.sw-panel[hidden] { display: none; }
.sw-head { display: flex; align-items: center; gap: 10px; padding: 14px 16px; border-bottom: 1px solid var(--border); }
.sw-head .sw-title { flex: 1; font-weight: 600; }
.sw-head .sw-logo svg, .sw-back svg, .sw-x svg { width: 18px; height: 18px; }
.sw-back, .sw-x { background: transparent; border: 0; color: var(--text-dim); cursor: pointer; display: grid; place-items: center; padding: 4px; border-radius: 6px; }
.sw-back:hover, .sw-x:hover { background: var(--panel-2); color: var(--text); }
.sw-body { flex: 1; overflow-y: auto; padding: 16px; }
.sw-lead { color: var(--text-dim); margin: 0 0 14px; font-size: 14px; }
.sw-tile { display: flex; align-items: center; gap: 12px; width: 100%; text-align: left; background: var(--panel-2);
  border: 1px solid var(--border); border-radius: 12px; padding: 14px; color: var(--text); cursor: pointer; margin-bottom: 10px; }
.sw-tile:hover { border-color: var(--border-strong); background: var(--panel-hover); }
.sw-tile svg { width: 20px; height: 20px; color: var(--accent); flex: none; }
.sw-tile div { flex: 1; } .sw-tile div b { display: block; font-size: 14px; } .sw-tile div span { color: var(--text-faint); font-size: 12.5px; }
.sw-tile > svg:last-child { color: var(--text-faint); width: 16px; }
.sw-threads { margin-top: 12px; display: flex; flex-direction: column; gap: 8px; }
.sw-thread { text-align: left; background: var(--panel-2); border: 1px solid var(--border); border-radius: 10px; padding: 11px 13px; cursor: pointer; color: var(--text); }
.sw-thread:hover { border-color: var(--border-strong); }
.sw-thread-top { display: flex; justify-content: space-between; gap: 8px; align-items: center; }
.sw-thread-meta { color: var(--text-faint); font-size: 12px; margin-top: 3px; }
.sw-badge { font-size: 11px; color: var(--text-faint); text-transform: capitalize; }
.sw-badge.open { color: var(--accent); }
.sw-empty { text-align: center; padding: 24px 0; }
.sw-log { display: flex; flex-direction: column; gap: 10px; padding-bottom: 8px; }
.sw-log.admin { max-height: 420px; overflow-y: auto; }
.sw-msg { display: flex; flex-direction: column; max-width: 85%; }
.sw-msg.me { align-self: flex-end; align-items: flex-end; }
.sw-msg.them { align-self: flex-start; }
.sw-bubble { padding: 9px 12px; border-radius: 12px; font-size: 13.5px; line-height: 1.45; white-space: pre-wrap; word-break: break-word; }
.sw-msg.me .sw-bubble { background: var(--accent); color: #fff; border-bottom-right-radius: 4px; }
.sw-msg.them .sw-bubble { background: var(--panel-2); border: 1px solid var(--border); border-bottom-left-radius: 4px; }
.sw-msg-meta { font-size: 11px; color: var(--text-faint); margin-top: 3px; }
.sw-compose { display: flex; gap: 8px; align-items: flex-end; border-top: 1px solid var(--border); padding-top: 12px; }
.sw-compose textarea { flex: 1; padding: 9px 11px; border-radius: 10px; background: var(--panel-2); border: 1px solid var(--border-strong); color: var(--text); font: inherit; resize: none; }
.sw-compose .btn { padding: 9px 12px; } .sw-compose .btn svg { width: 16px; height: 16px; }
.sw-stars { display: flex; gap: 4px; }
.sw-star { background: transparent; border: 0; cursor: pointer; color: var(--border-strong); padding: 2px; }
.sw-star svg { width: 22px; height: 22px; }
.sw-star.on { color: #fbbf24; }
.sw-thanks { text-align: center; padding: 30px 10px; }
.sw-thanks svg { width: 40px; height: 40px; color: var(--success); }
.sw-thanks p { margin: 12px 0 20px; color: var(--text-dim); }

@media (max-width: 560px) { .sw-panel { width: calc(100vw - 24px); } }

/* ============================================================= */
/* Guided install flow (framework tabs + origin authorisation).  */
/* ============================================================= */

/* "Start here" banner shown above Install when a site has no pages yet. */
.ins-banner { display: flex; align-items: flex-start; gap: 11px; margin: 0 0 12px; padding: 13px 15px;
  border-radius: var(--r-md); background: var(--accent-soft); border: 1px solid rgba(242,98,34,.28); }
.ins-banner > svg { width: 18px; height: 18px; color: var(--accent); flex: none; margin-top: 1px; }
.ins-banner b { display: block; font-size: 14px; }
.ins-banner span { color: var(--text-dim); font-size: 12.5px; }

/* Origin authorisation. */
.ins-orlist { display: flex; flex-wrap: wrap; gap: 8px; margin: 6px 0 10px; }
.ins-orpill { display: inline-flex; align-items: center; gap: 7px; padding: 6px 8px 6px 10px; border-radius: 999px;
  background: var(--success-soft); border: 1px solid rgba(74,222,128,.3); font-size: 12.5px; }
.ins-orpill > svg { width: 13px; height: 13px; color: var(--success); flex: none; }
.ins-orx { display: grid; place-items: center; background: transparent; border: 0; color: var(--text-faint);
  cursor: pointer; padding: 2px; border-radius: 5px; }
.ins-orx:hover { background: var(--panel-hover); color: var(--danger); }
.ins-orx svg { width: 13px; height: 13px; }
.ins-orempty { display: flex; align-items: center; gap: 8px; margin: 6px 0 10px; padding: 9px 12px; border-radius: var(--r-md);
  background: rgba(251,191,36,.1); border: 1px solid rgba(251,191,36,.28); color: #fbbf24; font-size: 12.5px; }
.ins-orempty svg { width: 15px; height: 15px; flex: none; }
.ins-oradd { display: flex; gap: 8px; }
.ins-oradd input { flex: 1; min-width: 0; padding: 8px 11px; border-radius: 8px; background: var(--panel-2);
  border: 1px solid var(--border-strong); color: var(--text); font: inherit; font-size: 13px; }
.ins-oradd .btn { flex: none; white-space: nowrap; }

/* Framework tabs. */
/* Grouped tiles, not a wrapped chip row. Eleven equal chips gave the eye no
   entry point; the group label tells you which three or four to read. */
.fw-picker { display: flex; flex-direction: column; gap: 15px; margin: 4px 0 13px; }
.fw-group-l { font-size: 10.5px; font-weight: 600; letter-spacing: .07em; text-transform: uppercase;
  color: var(--text-faint); margin-bottom: 8px; }
.fw-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(152px, 1fr)); gap: 7px; }
.fw-tile { display: flex; align-items: center; gap: 9px; padding: 9px 11px; border-radius: 8px;
  border: 1px solid var(--border); background: var(--panel-2); cursor: pointer; font: inherit;
  text-align: left; min-width: 0; transition: border-color .14s ease, background .14s ease; }
.fw-tile:hover { border-color: var(--border-strong); background: var(--panel-hover); }
.fw-tile.on { border-color: rgba(242,98,34,.45); background: var(--accent-soft); }
.fw-txt { display: flex; flex-direction: column; min-width: 0; }
.fw-txt b { font-size: 13px; font-weight: 600; line-height: 1.25; color: var(--text);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.fw-txt i { font-style: normal; font-size: 11px; line-height: 1.3; color: var(--text-faint); margin-top: 2px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.fw-tile.on .fw-txt b { color: var(--accent); }
.fw-logo { display: inline-flex; flex: none; }
.fw-logo svg { width: 16px; height: 16px; opacity: .85; }
.fw-tile.on .fw-logo svg { opacity: 1; }
@media (prefers-reduced-motion: reduce) { .fw-tile { transition: none; } }
.fw-hint { color: var(--text-dim); font-size: 12.5px; margin: 0 0 10px; }

/* Multi-line code block (framework snippets). */
.snippet.code-block { white-space: pre; }
.snippet.code-block pre { margin: 0; font: inherit; white-space: pre; }

/* ============================================================= */
/* First-run setup wizard, full screen, one decision per step.   */
/* ============================================================= */

/* Bounded height so the content scrolls inside .wiz-main and the action bar
   stays put at the bottom on every step. */
/* Transparent: the wizard used to paint its own top-anchored orange radial on
   an opaque base, which covered the app's ambient backdrop entirely and left
   the wizard looking like a different product. It now sits on the shared one. */
.wiz { height: 100vh; height: 100dvh; overflow: hidden; display: flex; flex-direction: column;
  background: transparent; }
.wiz-boot { flex: 1; display: grid; place-items: center; }

.wiz-top { display: flex; align-items: center; gap: 12px; padding: 22px 28px 14px; }
.wiz-brand { display: flex; align-items: center; gap: 9px; }
.wiz-brand .brand-logo { height: 17px; }
.wiz-brand .product { font-size: 13px; color: var(--text-dim); font-weight: 550; }
.wiz-exit { font-size: 13px; color: var(--text-faint); }
.wiz-exit:hover { color: var(--text); }

/* Progress rail */
/* The rail is the bottom edge of the fixed header block, so it carries the
   "there is more above" shadow once the content scrolls. */
.wiz-rail { display: flex; align-items: center; justify-content: center; gap: 0; padding: 6px 24px 20px;
  position: relative; z-index: 2; border-bottom: 1px solid transparent;
  transition: box-shadow .22s ease, border-color .22s ease; }
.wiz.scroll-above .wiz-rail { border-bottom-color: var(--border); box-shadow: 0 10px 20px -10px rgba(0,0,0,.8); }
.wiz-dot { display: flex; align-items: center; gap: 8px; }
.wiz-num { width: 24px; height: 24px; border-radius: 999px; display: grid; place-items: center; flex: none;
  font-size: 12px; font-weight: 650; color: var(--text-faint);
  background: var(--panel-2); border: 1px solid var(--border-strong); transition: all .25s ease; }
.wiz-num svg { width: 13px; height: 13px; }
.wiz-lbl { font-size: 12.5px; color: var(--text-faint); font-weight: 500; transition: color .25s ease; }
.wiz-dot.on .wiz-num { background: var(--accent); border-color: var(--accent); color: #fff; box-shadow: 0 0 0 4px var(--accent-soft); }
.wiz-dot.on .wiz-lbl { color: var(--text); }
.wiz-dot.done .wiz-num { background: var(--success-soft); border-color: rgba(74,222,128,.4); color: var(--success); }
.wiz-dot.done .wiz-lbl { color: var(--text-dim); }
.wiz-line { width: 46px; height: 1px; background: var(--border-strong); margin: 0 12px; transition: background .25s ease; }
.wiz-line.done { background: rgba(74,222,128,.4); }

/* Content */
/* Bottom spacing lives on the card, not here: a flex + overflow container drops
   its own padding-bottom at the scroll end, so the last content would sit flush
   against the action bar. A margin on the flex item is honoured. */
.wiz-main { flex: 1; min-height: 0; overflow-y: auto; display: flex; justify-content: center;
  align-items: flex-start; padding: 40px 24px 0; }
.wiz-card { width: 100%; max-width: 440px; margin-bottom: 48px;
  animation: wiz-in .34s cubic-bezier(.16,1,.3,1) both; }
.wiz-card.wide { max-width: 620px; }
.wiz-card.xwide { max-width: 660px; }
.wiz-card.center { text-align: center; }
@keyframes wiz-in { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) { .wiz-card { animation: none; } }

.wiz-h1 { font-size: 27px; line-height: 1.2; letter-spacing: -.02em; margin: 0 0 8px; }
.wiz-sub { color: var(--text-dim); font-size: 14.5px; line-height: 1.55; margin: 0 0 26px; }
.wiz-sub .mono { font-family: var(--font-mono); font-size: 13px; color: var(--text); }
.wiz-foot { color: var(--text-faint); font-size: 12.5px; text-align: center; margin: 16px 0 0; line-height: 1.5; }

.wiz-input { width: 100%; height: 48px; padding: 0 15px; font-size: 15px;
  background: var(--panel-2); border: 1px solid var(--border-strong); border-radius: 11px; color: var(--text); }
.wiz-input:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }
.wiz-input::placeholder { color: var(--text-faint); }

/* Fixed action bar, the primary button keeps one position and one width across
   every step; only its label changes. */
.wiz-actions { flex: none; padding: 24px 24px calc(28px + env(safe-area-inset-bottom));
  border-top: 1px solid var(--border); background: var(--bg-elevated);
  position: relative; z-index: 2; transition: box-shadow .22s ease; }
/* "There is more below" cue, only while the content can still scroll down. */
.wiz.scroll-below .wiz-actions { box-shadow: 0 -10px 20px -10px rgba(0,0,0,.8); }
/* One height for every step: tall enough for the button plus a secondary line,
   so steps without one (or with a note instead) do not shrink the bar. */
.wiz-actions-in { max-width: 400px; margin: 0 auto; min-height: 78px;
  display: flex; flex-direction: column; justify-content: center; }
.wiz-cta { width: 100%; height: 46px; font-size: 14.5px; justify-content: center; }
.wiz-cta svg { width: 16px; height: 16px; }
.wiz-cta:disabled { opacity: .6; }
.wiz-back { display: block; width: 100%; margin: 10px auto 0; background: none; border: 0; cursor: pointer;
  color: var(--text-faint); font: inherit; font-size: 13px; text-align: center; }
.wiz-back:hover { color: var(--text); }
.wiz-actions .wiz-foot { margin: 10px 0 0; }

.wiz-err { display: flex; align-items: center; gap: 8px; margin-top: 12px; padding: 10px 12px;
  background: var(--danger-soft); border: 1px solid rgba(255,97,102,.3); border-radius: 9px;
  color: #ff9a9d; font-size: 13px; text-align: left; }
.wiz-err svg { width: 15px; height: 15px; flex: none; }

/* Framework picker, grouped shelves of logo tiles. */
.wiz-picker { display: flex; flex-direction: column; gap: 16px; margin-bottom: 30px; }
.wiz-plabel { font-size: 11px; text-transform: uppercase; letter-spacing: .07em; font-weight: 650;
  color: var(--text-faint); margin-bottom: 9px; }
.wiz-tiles { display: grid; grid-template-columns: repeat(auto-fill, minmax(104px, 1fr)); gap: 8px; }
.wiz-tile { position: relative; display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 8px; padding: 15px 8px 12px; min-height: 84px; cursor: pointer; font: inherit;
  background: var(--panel-2); border: 1px solid var(--border); border-radius: 12px; color: var(--text-dim);
  transition: border-color .15s ease, background .15s ease, transform .15s ease; }
.wiz-tile:hover { border-color: var(--border-strong); color: var(--text); transform: translateY(-1px); }
.wiz-tile-ic { display: grid; place-items: center; height: 24px; }
.wiz-tile-ic svg { width: 21px; height: 21px; }
.wiz-tile-lb { font-size: 11.5px; font-weight: 550; text-align: center; line-height: 1.25; }
.wiz-tile-ck { position: absolute; top: 7px; right: 7px; width: 16px; height: 16px; border-radius: 999px;
  display: grid; place-items: center; background: var(--accent); color: #fff; opacity: 0; transform: scale(.6);
  transition: opacity .15s ease, transform .15s ease; }
.wiz-tile-ck svg { width: 10px; height: 10px; stroke-width: 3; }
.wiz-tile.on { background: var(--accent-soft); border-color: rgba(242,98,34,.45); color: var(--accent); }
.wiz-tile.on .wiz-tile-ck { opacity: 1; transform: none; }

/* Ordered install procedure. */
.wiz-steps { list-style: none; margin: 0 0 4px; padding: 0; display: flex; flex-direction: column; gap: 20px; }
.wiz-step { display: flex; gap: 14px; position: relative; }
.wiz-step:not(:last-child)::before { content: ""; position: absolute; left: 13px; top: 30px; bottom: -20px;
  width: 1px; background: var(--border); }
.wiz-stepn { width: 27px; height: 27px; border-radius: 999px; flex: none; display: grid; place-items: center;
  font-size: 12.5px; font-weight: 650; color: var(--text-dim);
  background: var(--panel-2); border: 1px solid var(--border-strong); position: relative; z-index: 1; }
.wiz-stepc { flex: 1; min-width: 0; padding-top: 2px; }
.wiz-stept { font-size: 14.5px; font-weight: 600; }
.wiz-stepb { color: var(--text-dim); font-size: 13px; line-height: 1.55; margin-top: 3px; }

/* Code block with a file header + labelled copy button. */
.wiz-code2 { margin-top: 11px; border: 1px solid var(--border-strong); border-radius: 11px; overflow: hidden;
  background: #060606; }
.wiz-code2-h { display: flex; align-items: center; gap: 10px; padding: 8px 8px 8px 13px;
  background: var(--panel-2); border-bottom: 1px solid var(--border); }
.wiz-file { display: flex; align-items: center; gap: 7px; flex: 1; min-width: 0;
  font-family: var(--font-mono); font-size: 11.5px; color: var(--text-dim);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.wiz-file svg { width: 13px; height: 13px; flex: none; color: var(--text-faint); }
.wiz-copy { display: inline-flex; align-items: center; gap: 6px; flex: none; cursor: pointer; font: inherit;
  font-size: 12px; font-weight: 550; padding: 5px 10px; border-radius: 7px;
  background: var(--panel); border: 1px solid var(--border-strong); color: var(--text-dim); transition: all .15s ease; }
.wiz-copy:hover { color: var(--text); border-color: var(--text-faint); }
.wiz-copy svg { width: 13px; height: 13px; }
.wiz-copy.copied { color: var(--success); border-color: rgba(74,222,128,.4); background: var(--success-soft); }
.wiz-code2 pre { margin: 0; padding: 14px 16px; overflow-x: auto;
  font-family: var(--font-mono); font-size: 12.5px; line-height: 1.75; color: #cfcfcf; white-space: pre; }

/* Verify states */
.wiz-spin { display: grid; place-items: center; margin-bottom: 22px; }
.spinner.lg { width: 34px; height: 34px; border-width: 3px; }
.wiz-ok, .wiz-pending { width: 60px; height: 60px; border-radius: 999px; display: grid; place-items: center;
  margin: 0 auto 20px; animation: wiz-pop .4s cubic-bezier(.16,1.4,.5,1) both; }
.wiz-ok { background: var(--success-soft); color: var(--success); border: 1px solid rgba(74,222,128,.35); }
.wiz-pending { background: rgba(251,191,36,.12); color: #fbbf24; border: 1px solid rgba(251,191,36,.3); }
.wiz-ok svg, .wiz-pending svg { width: 28px; height: 28px; }
@keyframes wiz-pop { from { opacity: 0; transform: scale(.7); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) { .wiz-ok, .wiz-pending { animation: none; } }

@media (max-width: 560px) {
  .wiz-lbl { display: none; }
  .wiz-line { width: 28px; margin: 0 8px; }
  .wiz-h1 { font-size: 23px; }
  .wiz-main { padding: 28px 18px 60px; }
}

/* Calm site-overview onboarding card (replaces the old wall of options). */
.onb-hero { text-align: center; padding: 46px 26px; border-radius: var(--r-lg);
  border: 1px solid var(--border); background: linear-gradient(180deg, var(--panel), var(--bg-elevated)); }
.onb-ico { width: 52px; height: 52px; border-radius: 14px; display: grid; place-items: center; margin: 0 auto 16px;
  background: var(--accent-soft); color: var(--accent); }
.onb-ico svg { width: 25px; height: 25px; }
.onb-hero h2 { margin: 0 0 7px; font-size: 20px; letter-spacing: -.01em; }
.onb-hero p { margin: 0 0 22px; color: var(--text-dim); font-size: 14px; }
.onb-ok { width: 34px; height: 34px; border-radius: 999px; display: grid; place-items: center; flex: none;
  background: var(--success-soft); color: var(--success); border: 1px solid rgba(74,222,128,.35); }
.onb-ok svg { width: 17px; height: 17px; }

/* Brand colours for the framework/platform marks. The SVGs draw with
   currentColor, so tinting the wrapper is enough, and it works in both the
   wizard tiles and the Settings install tabs. Shades are picked to stay legible
   on the dark panels. */
[data-logo] svg { color: inherit; }
[data-logo="html"]        { color: #e44d26; }
[data-logo="npm"]         { color: #e0574f; }
[data-logo="next-app"],
[data-logo="next-pages"]  { color: #ffffff; }
[data-logo="react"]       { color: #61dafb; }
[data-logo="nuxt"]        { color: #00dc82; }
[data-logo="svelte"]      { color: #ff5c26; }
[data-logo="astro"]       { color: #c07cf5; }
[data-logo="wordpress"]   { color: #5b82f5; }
[data-logo="gtm"]         { color: #4285f4; }
[data-logo="nocode"]      { color: #a78bfa; }
/* Keep the mark's own colour when a tile/tab is selected or hovered. */
.wiz-tile.on [data-logo], .wiz-tile:hover [data-logo],
.fw-tile.on [data-logo], .fw-tile:hover [data-logo] { filter: saturate(1.15); }

/* Variant toggle (Next.js router, npm flavour), a sub-choice of the picked tile. */
.wiz-variant { display: flex; align-items: center; gap: 12px; margin: -14px 0 26px; }
.wiz-vlabel { font-size: 11px; text-transform: uppercase; letter-spacing: .07em; font-weight: 650; color: var(--text-faint); }

/* Chosen-stack summary on the install step, with a clear way back to the picker. */
.wiz-stackbar { display: flex; align-items: center; gap: 12px; margin-bottom: 26px; padding: 11px 12px 11px 14px;
  background: var(--panel-2); border: 1px solid var(--border); border-radius: 11px; }
.wiz-sb-ic { display: grid; place-items: center; flex: none; }
.wiz-sb-ic svg { width: 20px; height: 20px; }
.wiz-sb-tx { flex: 1; min-width: 0; display: flex; align-items: baseline; gap: 8px; }
.wiz-sb-tx b { font-size: 14px; font-weight: 600; }
.wiz-sb-tx i { font-style: normal; font-size: 12.5px; color: var(--text-faint); }
.wiz-sb-ch { display: inline-flex; align-items: center; gap: 6px; flex: none; cursor: pointer; font: inherit;
  font-size: 12.5px; font-weight: 550; padding: 6px 11px; border-radius: 8px;
  background: var(--panel); border: 1px solid var(--border-strong); color: var(--text-dim); transition: all .15s ease; }
.wiz-sb-ch:hover { color: var(--text); border-color: var(--text-faint); }
.wiz-sb-ch svg { width: 13px; height: 13px; }

/* ============================================================= */
/* Site detail: header + a working overview instead of two cards. */
/* ============================================================= */

.site-head { display: flex; align-items: flex-start; gap: 20px; margin-bottom: var(--s-6); }
.site-head-main { flex: 1; min-width: 0; }
.site-head h1 { font-size: 27px; letter-spacing: -.02em; margin: 0; }
.site-meta { display: flex; align-items: center; flex-wrap: wrap; gap: 8px 14px; margin-top: 9px; }
.site-url { display: inline-flex; align-items: center; gap: 6px; font-size: 13.5px; color: var(--text-dim); }
.site-url:hover { color: var(--accent); }
.site-url svg { width: 13px; height: 13px; }
/* Replaces the old raw site-key chip. The key on its own is an opaque string
   nobody pastes anywhere; the tag is the thing you install, and it carries the
   key inside it. */
.tag-chip { display: inline-flex; align-items: center; gap: 7px; cursor: pointer; font: inherit;
  font-size: 12px; font-weight: 500; padding: 4px 10px; border-radius: 7px;
  background: var(--panel-2); border: 1px solid var(--border); color: var(--text-faint); transition: all .15s ease; }
.tag-chip:hover { color: var(--text); border-color: var(--border-strong); background: var(--panel-hover); }
.tag-chip svg { width: 13px; height: 13px; }
.tag-chip.copied { color: var(--success); border-color: rgba(74, 222, 128, .4); }
.site-head .btn { flex: none; }

/* Headline numbers. */

/* Page list on the overview. */

/* Compact "edit another page" launcher. */
.ov-launch { display: flex; gap: 10px; }
.ov-launch input { flex: 1; min-width: 0; }
.ov-launch .btn { flex: none; }

/* Two-step verification: one method on screen, the rest under a separator. */
.mfa-lead { color: var(--text-dim); font-size: 13.5px; line-height: 1.55; margin: 0 0 16px; }
.mfa-lead b { color: var(--text); font-weight: 550; }
.mfa-resend { display: block; width: 100%; text-align: center; margin-top: 12px; }
.mfa-sep { display: flex; align-items: center; gap: 12px; margin: 22px 0 14px; }
.mfa-sep::before, .mfa-sep::after { content: ""; flex: 1; height: 1px; background: var(--border); }
.mfa-sep span { color: var(--text-faint); font-size: 11.5px; text-transform: uppercase; letter-spacing: .06em; font-weight: 600; }

/* Wizard: loading-indicator picker. */
.ldr-grid { display: flex; flex-direction: column; gap: 8px; margin-bottom: 22px; }
.ldr-card { position: relative; display: flex; align-items: center; gap: 14px; width: 100%; text-align: left;
  cursor: pointer; font: inherit; padding: 13px 15px; border-radius: 12px;
  background: var(--panel-2); border: 1px solid var(--border); color: var(--text);
  transition: border-color .15s ease, background .15s ease; }
.ldr-card:hover { border-color: var(--border-strong); background: var(--panel-hover); }
.ldr-card.on { background: var(--accent-soft); border-color: rgba(242,98,34,.45); }
.ldr-card .wiz-tile-ck { top: 50%; right: 13px; transform: translateY(-50%) scale(.6); }
.ldr-card.on .wiz-tile-ck { transform: translateY(-50%) scale(1); }
.ldr-card-b { flex: 1; min-width: 0; padding-right: 22px; }
.ldr-card-b b { display: flex; align-items: center; gap: 8px; font-size: 14px; font-weight: 600; }
.ldr-card-b b em { font-style: normal; font-size: 10.5px; font-weight: 650; text-transform: uppercase;
  letter-spacing: .05em; color: var(--success); background: var(--success-soft);
  border: 1px solid rgba(74,222,128,.3); padding: 2px 7px; border-radius: 999px; }
.ldr-card-b i { display: block; font-style: normal; font-size: 12.5px; color: var(--text-faint);
  line-height: 1.45; margin-top: 3px; }

/* Tiny visual for each option. */
.ldr-mini { position: relative; width: 46px; height: 34px; border-radius: 6px; flex: none; overflow: hidden;
  background: #e8e8ea; border: 1px solid rgba(0,0,0,.12); display: block; }
.ldr-mini i { position: absolute; background: rgba(0,0,0,.16); border-radius: 2px; display: block; }
.ldr-mini-none i:nth-child(1) { inset: 8px 8px auto 8px; height: 4px; }
.ldr-mini-none i:nth-child(2) { inset: 16px 14px auto 8px; height: 4px; }
.ldr-mini-none i:nth-child(3) { display: none; }
.ldr-mini-bar i:nth-child(1) { inset: 0 40% 0 0; height: 3px; background: var(--accent); border-radius: 0; }
.ldr-mini-bar i:nth-child(2) { inset: 11px 8px auto 8px; height: 4px; }
.ldr-mini-bar i:nth-child(3) { inset: 19px 16px auto 8px; height: 4px; }
.ldr-mini-overlay i:nth-child(1) { inset: 0; background: rgba(0,0,0,.06); border-radius: 0; }
.ldr-mini-overlay i:nth-child(2) { width: 11px; height: 11px; border-radius: 50%; left: 50%; top: 50%;
  transform: translate(-50%,-50%); background: none; border: 2px solid var(--accent); border-top-color: transparent; }
.ldr-mini-overlay i:nth-child(3) { display: none; }
.ldr-mini-skeleton i { background: linear-gradient(100deg, rgba(0,0,0,.10) 30%, rgba(0,0,0,.2) 50%, rgba(0,0,0,.10) 70%); }
.ldr-mini-skeleton i:nth-child(1) { inset: 7px 8px auto 8px; height: 5px; }
.ldr-mini-skeleton i:nth-child(2) { inset: 16px 14px auto 8px; height: 5px; }
.ldr-mini-skeleton i:nth-child(3) { inset: 25px 20px auto 8px; height: 5px; }
.ldr-mini-custom i:nth-child(1) { inset: 9px; border: 1px dashed rgba(0,0,0,.35); background: none; border-radius: 4px; }
.ldr-mini-custom i:nth-child(2), .ldr-mini-custom i:nth-child(3) { display: none; }

/* Options + live preview side by side. */
.ldr-config { display: grid; grid-template-columns: 1fr 1fr; gap: 18px; align-items: start;
  padding-top: 20px; border-top: 1px solid var(--border); }
.ldr-opt { margin-bottom: 12px; }
.ldr-opt > label { display: block; font-size: 12.5px; font-weight: 550; margin-bottom: 6px; color: var(--text-dim); }
.ldr-color { display: flex; gap: 8px; align-items: center; }
.ldr-color input[type=color] { -webkit-appearance: none; appearance: none; width: 34px; height: 34px; padding: 0;
  border: 1px solid var(--border-strong); border-radius: 8px; background: none; cursor: pointer; flex: none; }
.ldr-color input[type=color]::-webkit-color-swatch-wrapper { padding: 3px; }
.ldr-color input[type=color]::-webkit-color-swatch { border: 0; border-radius: 5px; }
.ldr-hex, .ldr-text { flex: 1; min-width: 0; width: 100%; padding: 8px 10px; border-radius: 8px;
  background: var(--panel-2); border: 1px solid var(--border-strong); color: var(--text); font: inherit; font-size: 13px; }
.ldr-hex { font-family: var(--font-mono); font-size: 12px; }
.ldr-plabel { font-size: 11px; text-transform: uppercase; letter-spacing: .06em; font-weight: 650;
  color: var(--text-faint); margin-bottom: 8px; }
.ldr-hint { display: flex; gap: 8px; align-items: flex-start; margin: 0; color: var(--text-faint);
  font-size: 12.5px; line-height: 1.5; }
.ldr-hint svg { width: 14px; height: 14px; flex: none; margin-top: 2px; }
@media (max-width: 620px) { .ldr-config { grid-template-columns: 1fr; } }

/* Address fields: inline feedback under the input. */
.url-hint { display: flex; align-items: flex-start; gap: 6px; font-size: 12.5px; line-height: 1.45;
  margin-top: 7px; min-height: 0; color: var(--text-faint); }
.url-hint:empty { margin-top: 0; }
.url-hint svg { width: 13px; height: 13px; flex: none; margin-top: 2px; }
.url-hint.ok { color: var(--success); font-family: var(--font-mono); font-size: 12px; }
.url-hint.warn { color: #fbbf24; }
.url-hint.bad { color: #ff9a9d; }
input.invalid { border-color: rgba(255,97,102,.55) !important; }
input.invalid:focus { box-shadow: 0 0 0 3px var(--danger-soft) !important; }
.wiz-input.invalid { border-color: rgba(255,97,102,.55); }

/* Address control: protocol select fused to the host input. */
.url-field { display: flex; align-items: stretch; width: 100%; min-width: 0;
  border: 1px solid var(--border-strong); border-radius: 10px; background: var(--panel-2);
  overflow: hidden; transition: border-color .15s ease, box-shadow .15s ease; }
.url-field:focus-within { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }
.url-field.invalid { border-color: rgba(255,97,102,.55); }
.url-field.invalid:focus-within { box-shadow: 0 0 0 3px var(--danger-soft); }
.url-proto { flex: none; border: 0; border-right: 1px solid var(--border); background: var(--panel);
  color: var(--text-dim); font-family: var(--font-mono); font-size: 12.5px; padding: 0 8px 0 11px;
  cursor: pointer; outline: none; appearance: none;
  background-image: linear-gradient(45deg, transparent 50%, var(--text-faint) 50%), linear-gradient(135deg, var(--text-faint) 50%, transparent 50%);
  background-position: right 12px center, right 8px center; background-size: 4px 4px, 4px 4px;
  background-repeat: no-repeat; padding-right: 24px; }
.url-proto:hover { color: var(--text); }
/* The paired input owns no chrome of its own; the wrapper draws it. */
.url-field input { flex: 1; min-width: 0; border: 0 !important; background: transparent !important;
  box-shadow: none !important; border-radius: 0; }
.url-field input:focus { outline: none; box-shadow: none !important; }
.url-field input.invalid { border: 0 !important; }
/* Wizard's larger field. */
.url-field:has(.wiz-input) { border-radius: 11px; }
.url-field .wiz-input { height: 46px; font-size: 15px; padding: 0 14px; }
.url-field:has(.wiz-input) .url-proto { font-size: 13.5px; padding-left: 14px; padding-right: 26px; }

/* The hint sits after the field. Inside a flex row it must wrap to its own line,
   otherwise its text competes for width and collapses the input. */
.url-hint { flex-basis: 100%; width: 100%; }
.ov-launch, .ins-oradd { flex-wrap: wrap; }
.ov-launch .url-field, .ins-oradd .url-field { flex: 1 1 260px; min-width: 0; }

/* Protocol toggle: a button, so one click flips it. */
.url-proto { flex: none; display: inline-flex; align-items: center; border: 0;
  border-right: 1px solid var(--border); background: var(--panel); cursor: pointer;
  color: var(--text-dim); font-family: var(--font-mono); font-size: 12.5px; font-weight: 550;
  padding: 0 12px; white-space: nowrap; transition: background .15s ease, color .15s ease;
  background-image: none; }
.url-proto:hover { background: var(--panel-hover); color: var(--accent); }
.url-proto:focus-visible { outline: 2px solid var(--ring); outline-offset: -2px; }
.url-field .wiz-input + .url-proto, .url-field:has(.wiz-input) .url-proto { font-size: 13.5px; padding: 0 14px; }

/* Page rows carry state and an action, not just a name. */

/* Folded-away launcher for pages Weblay has not seen. */
.ov-more { margin-top: var(--s-5); }
/* Inside the Pages card it reads as a footer action, not a floating link. */
#panel-pages .ov-more { margin-top: 0; padding: 14px 18px; border-top: 1px solid var(--border); }
.ov-launch-wrap { margin-top: 12px; }
.ov-launch-wrap[hidden] { display: none; }

/* The inline hint is inserted between the field and its button in DOM order, so
   reorder visually: field, button, then the hint on its own line. */
.ov-launch .btn, .ins-oradd .btn { order: 1; }
.ov-launch .url-hint, .ins-oradd .url-hint { order: 2; }

/* Fixed-origin prefix for path-only fields. */
.url-prefix { display: inline-flex; align-items: center; flex: none; padding: 0 12px;
  border-right: 1px solid var(--border); background: var(--panel);
  color: var(--text-faint); font-family: var(--font-mono); font-size: 12.5px; white-space: nowrap;
  max-width: 240px; overflow: hidden; text-overflow: ellipsis; }
.url-origin { flex: none; border: 0; border-right: 1px solid var(--border); background: var(--panel);
  color: var(--text-dim); font-family: var(--font-mono); font-size: 12.5px; cursor: pointer;
  padding: 0 30px 0 12px; max-width: 260px; }
.url-origin:hover { color: var(--text); }

/* Host prefix on page paths: present for context, muted so the path leads. */
.path-host { color: var(--text-faint); font-weight: 400; }
.path-link:hover .path-host { color: inherit; opacity: .75; }

/* Members table: the "Remove" affordance and the invite field's inline hint,
   which must break onto its own line rather than fight the row for width. */
.link-btn.danger { color: var(--danger); }
.link-btn.danger:hover { color: var(--danger-strong); }
td.tr { text-align: right; }
#member-email.bad { border-color: var(--danger); }

/* ---- Site overview hero --------------------------------------------------
   A live preview of the customer's own site in browser chrome, overlaid with
   the same dashed selection rings the editor draws. The point is that someone
   landing here understands "my site is editable" before reading a word. */
.ov-hero {
  display: grid; grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr);
  gap: 28px; align-items: center; margin-bottom: 26px;
}
.ov-frame {
  border: 1px solid var(--border); border-radius: 12px; overflow: hidden;
  background: var(--panel); box-shadow: 0 18px 40px -24px rgba(0, 0, 0, .55);
}
.ov-chrome {
  display: flex; align-items: center; gap: 10px; padding: 9px 12px;
  border-bottom: 1px solid var(--border); background: var(--panel-2);
}
.ov-dots { display: flex; gap: 6px; flex: none; }
.ov-dots i { width: 9px; height: 9px; border-radius: 50%; background: var(--border); }
.ov-url {
  display: inline-flex; align-items: center; gap: 6px; min-width: 0;
  padding: 3px 10px; border-radius: 999px; background: var(--bg);
  font-family: var(--font-mono); font-size: 11.5px; color: var(--text-faint);
}
.ov-url svg { width: 11px; height: 11px; flex: none; }
.ov-url span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* The shot itself: a desktop-width viewport scaled down, non-interactive. */
.ov-shot { position: relative; aspect-ratio: 16 / 10; overflow: hidden; background: var(--bg); }
.ov-iframe {
  position: absolute; inset: 0; width: 1440px; height: 900px; border: 0;
  /* --ov-scale is set from the card's width by fitPreview(). The fallback only
     matters for the frame between paint and that first measurement. */
  transform: scale(var(--ov-scale, .34)); transform-origin: top left;
  pointer-events: none;
}
.ov-shot-fallback {
  position: absolute; inset: 0; display: none; flex-direction: column;
  align-items: center; justify-content: center; gap: 14px;
  color: var(--text-faint); font-size: 12.5px; font-family: var(--font-mono);
}
.ov-frame.no-shot .ov-iframe { display: none; }
.ov-frame.no-shot .ov-shot-fallback { display: flex; }
.ov-shot-lines { display: flex; flex-direction: column; gap: 8px; width: 46%; }
.ov-shot-lines i { height: 9px; border-radius: 3px; background: var(--border); }
.ov-shot-lines i:nth-child(1) { width: 62%; height: 13px; }
.ov-shot-lines i:nth-child(3) { width: 84%; }
.ov-shot-lines i:nth-child(4) { width: 40%; }

/* Editable affordance drawn over the preview. */
.ov-mark { position: absolute; inset: 0; pointer-events: none; }
.ov-ring { position: absolute; fill: none; stroke: var(--accent); stroke-width: 1.5; }
.ov-ring rect { stroke-dasharray: 5 4; }
.ov-ring.r1 { left: 8%; top: 22%; width: 46%; height: 9%; opacity: 0; animation: ovRing 7s ease-in-out infinite; }
.ov-ring.r2 { left: 8%; top: 40%; width: 62%; height: 7%; opacity: 0; animation: ovRing 7s ease-in-out infinite 3.5s; }
.ov-tip {
  position: absolute; left: 8%; top: 15.5%; padding: 2px 7px; border-radius: 4px;
  background: var(--accent); color: #fff; font-size: 10px; font-weight: 600;
  letter-spacing: .02em; opacity: 0; animation: ovRing 7s ease-in-out infinite;
}
.ov-cursor {
  position: absolute; width: 20px; height: 20px; fill: #fff;
  stroke: rgba(0, 0, 0, .45); stroke-width: 1;
  filter: drop-shadow(0 2px 3px rgba(0, 0, 0, .4));
  animation: ovCursor 7s ease-in-out infinite;
}
@keyframes ovRing {
  0%, 8% { opacity: 0; }
  14%, 44% { opacity: 1; }
  52%, 100% { opacity: 0; }
}
@keyframes ovCursor {
  0% { left: 62%; top: 74%; }
  12% { left: 30%; top: 27%; }
  16% { left: 30%; top: 27%; transform: scale(.82); }
  20%, 46% { left: 30%; top: 27%; transform: scale(1); }
  60% { left: 46%; top: 44%; }
  64% { left: 46%; top: 44%; transform: scale(.82); }
  68%, 88% { left: 46%; top: 44%; transform: scale(1); }
  100% { left: 62%; top: 74%; }
}

/* The whole preview is one big "open the editor" target. */
.ov-shot-hit {
  position: absolute; inset: 0; border: 0; cursor: pointer; padding: 0;
  background: transparent; display: grid; place-items: center;
  transition: background .18s ease;
}
.ov-shot-hit:hover, .ov-shot-hit:focus-visible { background: rgba(10, 10, 12, .55); }
.ov-shot-cta {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 10px 18px; border-radius: 8px; background: var(--accent); color: #fff;
  font-size: 14px; font-weight: 600;
  opacity: 0; transform: translateY(6px); transition: opacity .18s ease, transform .18s ease;
}
.ov-shot-cta svg { width: 15px; height: 15px; }
.ov-shot-hit:hover .ov-shot-cta, .ov-shot-hit:focus-visible .ov-shot-cta { opacity: 1; transform: none; }

.ov-hero-side h2 { font-size: 25px; line-height: 1.25; margin: 10px 0 10px; }
.ov-hero-side p { color: var(--text-dim); font-size: 14px; line-height: 1.6; margin: 0 0 20px; max-width: 46ch; }
.ov-eyebrow {
  display: inline-flex; align-items: center; gap: 7px; font-size: 11.5px;
  font-weight: 600; letter-spacing: .06em; text-transform: uppercase; color: var(--text-faint);
}
.ov-live {
  width: 7px; height: 7px; border-radius: 50%; background: var(--success);
  box-shadow: 0 0 0 0 var(--success); animation: ovPulse 2.4s ease-out infinite;
}
@keyframes ovPulse {
  0% { box-shadow: 0 0 0 0 rgba(74, 222, 128, .5); }
  70%, 100% { box-shadow: 0 0 0 7px rgba(74, 222, 128, 0); }
}
.ov-cta { display: flex; flex-wrap: wrap; gap: 10px; }

@media (max-width: 900px) {
  .ov-hero { grid-template-columns: 1fr; gap: 20px; }
  .ov-hero-side { order: -1; }
}
@media (prefers-reduced-motion: reduce) {
  .ov-ring, .ov-tip, .ov-cursor, .ov-live { animation: none; }
  .ov-ring, .ov-tip { opacity: 1; }
  .ov-cursor { display: none; }
}

/* ---- Site settings: one topic at a time ---------------------------------
   Six stacked sections in a single scroll buried Install and put the danger
   zone in the path of ordinary scrolling. A rail scopes the page to one
   subject; every section stays in the DOM and is only hidden. */
.set-layout { display: grid; grid-template-columns: 232px minmax(0, 1fr); gap: 26px; align-items: start; }
.set-rail { display: flex; flex-direction: column; gap: 2px; position: sticky; top: 18px; }
.set-navitem {
  display: flex; align-items: flex-start; gap: 10px; width: 100%; text-align: left;
  padding: 9px 11px; border: 1px solid transparent; border-radius: 8px;
  background: transparent; color: var(--text-dim); cursor: pointer;
  transition: background .13s ease, color .13s ease, border-color .13s ease;
}
.set-navitem:hover { background: var(--panel); color: var(--text); }
.set-navitem.on { background: var(--panel-2); border-color: var(--border); color: var(--text); }
.set-navico { display: grid; place-items: center; flex: none; margin-top: 1px; }
.set-navico svg { width: 15px; height: 15px; }
.set-navitem.on .set-navico { color: var(--accent); }
.set-navtext { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.set-navtext b { font-size: 13.5px; font-weight: 600; line-height: 1.3; }
.set-navtext span { font-size: 11.5px; line-height: 1.35; color: var(--text-faint); }
.set-navitem.danger:hover, .set-navitem.danger.on { color: var(--danger); }
.set-navitem.danger.on .set-navico { color: var(--danger); }
.set-body { min-width: 0; }
/* The first heading in a section already labels the page, so drop its top gap. */
.set-sec > .section-title:first-child { margin-top: 0; }

@media (max-width: 860px) {
  .set-layout { grid-template-columns: 1fr; gap: 16px; }
  .set-rail { position: static; flex-direction: row; overflow-x: auto; gap: 6px; padding-bottom: 4px; }
  .set-navitem { width: auto; flex: none; padding: 7px 12px; }
  .set-navtext span { display: none; }
}

/* ---- Overview install bar ------------------------------------------------
   Overview ends with the tag itself rather than a second Pages table: it is
   what people return to copy into a new deploy. Deliberately one line, with
   "More" opening the full install section (framework tabs, loader, verify). */
.ov-installbar { margin-top: var(--s-5); }
.ov-ib-head { display: flex; align-items: center; gap: 10px; margin-bottom: 8px; }
.ov-ib-title {
  display: inline-flex; align-items: center; gap: 7px; flex: 1 1 auto;
  font-size: 12px; font-weight: 600; letter-spacing: .05em;
  text-transform: uppercase; color: var(--text-faint);
}
.ov-ib-title svg { width: 14px; height: 14px; }
.ov-ib-code pre {
  margin: 0; overflow-x: auto; white-space: pre; font-size: 12px; line-height: 1.6;
}
/* Glass, like the cards. This one sits directly on the page background rather
   than inside a card, so the blur has the backdrop to work with and does not
   compound. (The webhook snippet, the only other .snippet, is inside a card and
   stays solid for exactly that reason.) */
.ov-ib-code {
  background: rgba(12, 12, 15, .58);
  -webkit-backdrop-filter: blur(16px) saturate(140%);
          backdrop-filter: blur(16px) saturate(140%);
  border-color: rgba(255, 255, 255, .08);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .04);
}
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .ov-ib-code { background: #060606; }
}
@media (max-width: 640px) {
  .ov-ib-code {
    -webkit-backdrop-filter: none;
            backdrop-filter: none;
    background: #060606;
  }
}
.ov-ib-hint { margin: 8px 0 0; font-size: 12.5px; color: var(--text-faint); }
.ov-ib-hint code { font-size: 11.5px; }

/* ---- Site condition, in the header --------------------------------------
   Moved out of the Overview panel: it describes the site, not the tab, so it
   belongs next to the site's name and stays visible on every tab. Carries no
   action of its own, the site-alert directly below owns "Review health".

   Deliberately unboxed. A bordered card sat oddly against the plain header and
   read as a control you could click; here the tinted icon carries the state and
   the type carries the detail, which is all a passive readout needs. */
.site-stat { display: flex; align-items: center; gap: 11px; flex: none; align-self: center; }
.site-stat-ic { display: grid; place-items: center; width: 28px; height: 28px; border-radius: 999px; flex: none; }
.site-stat-ic svg { width: 14px; height: 14px; }
/* Scoped through .site-stat-txt: a bare ".site-stat span" also matches the icon
   span and outranks .site-stat-ic, which killed its grid centring. */
.site-stat-txt b { display: block; font-size: 14px; font-weight: 600; line-height: 1.3; }
.site-stat-txt span { display: block; color: var(--text-faint); font-size: 12.5px; margin-top: 3px; }
.site-stat.ok .site-stat-ic { background: var(--success-soft); color: var(--success); }
.site-stat.warn .site-stat-ic { background: rgba(251,191,36,.12); color: #fbbf24; }
.site-stat.bad .site-stat-ic { background: var(--danger-soft); color: var(--danger); }

@media (max-width: 720px) {
  .site-head { flex-direction: column; gap: 14px; }
  .site-stat { align-self: flex-start; }
}

/* ---- Settings > Install --------------------------------------------------
   Mirrors the wizard's install step, reusing .wiz-steps / .wiz-code2 outright
   so the two cannot drift apart: one numbered procedure, each step naming the
   file it touches and carrying its own copy block. */
.ins-steps { margin-top: 18px; }
.ins-note {
  display: flex; align-items: flex-start; gap: 8px; margin: 12px 0 0;
  font-size: 12.5px; line-height: 1.55; color: var(--text-faint);
}
.ins-note svg { width: 14px; height: 14px; flex: none; margin-top: 2px; }

/* The loader lives here because it configures the snippet directly above it,
   but the default is "none", so it stays folded away until wanted. */
.ins-adv { margin-top: 16px; border-top: 1px solid var(--border); padding-top: 14px; }
.ins-adv summary {
  display: flex; align-items: center; gap: 9px; cursor: pointer; list-style: none;
  color: var(--text-dim); transition: color .15s ease;
}
.ins-adv summary::-webkit-details-marker { display: none; }
.ins-adv summary:hover { color: var(--text); }
.ins-adv-t { font-size: 13.5px; font-weight: 600; }
.ins-adv-tag {
  font-size: 10.5px; font-weight: 600; letter-spacing: .04em; text-transform: uppercase;
  padding: 2px 7px; border-radius: 999px; background: var(--panel-2);
  border: 1px solid var(--border); color: var(--text-faint);
}
.ins-adv summary svg { width: 14px; height: 14px; margin-left: auto; transition: transform .18s ease; }
.ins-adv[open] summary svg { transform: rotate(180deg); }
.ins-adv-bd { padding-top: 14px; }
.ins-adv-lead { margin: 0 0 14px; font-size: 12.5px; line-height: 1.6; color: var(--text-faint); max-width: 62ch; }

@media (prefers-reduced-motion: reduce) {
  .ins-adv summary svg { transition: none; }
}

/* ---- First-run welcome ---------------------------------------------------
   The empty Projects state is the first thing a new account ever sees, and it
   was three bullet points describing the product. It now shows the product:
   a looping demo of the actual gesture, clicking a headline on a live page and
   rewriting it, which explains in-place editing faster than the copy can.
   One shared 9s timeline drives every part, so the beats stay in sync. */
.card.onboard { padding: 38px 40px 34px; }
.ob-grid { display: grid; grid-template-columns: minmax(0, 1.05fr) minmax(0, 1fr); gap: 52px; align-items: center; }

.ob-side h2 { font-size: 25px; line-height: 1.25; letter-spacing: -.01em; margin: 9px 0 11px; text-wrap: balance; }
.ob-side p { color: var(--text-dim); font-size: 14px; line-height: 1.62; margin: 0 0 20px; max-width: 46ch; }
.ob-eyebrow { font-size: 11.5px; font-weight: 600; letter-spacing: .07em; text-transform: uppercase; color: var(--accent); }

/* The demo is clickable and goes where the CTA goes, so it gets button affordances. */
.ob-demo {
  display: block; width: 100%; padding: 0; cursor: pointer; text-align: left;
  border: 1px solid var(--border); border-radius: 12px; overflow: hidden;
  background: var(--panel-2); transition: border-color .16s ease, transform .16s ease;
}
.ob-demo:hover { border-color: var(--border-strong); transform: translateY(-2px); }
.ob-demo:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

.ob-chrome { display: flex; align-items: center; gap: 9px; padding: 8px 11px; border-bottom: 1px solid var(--border); }
.ob-dots { display: flex; gap: 5px; flex: none; }
.ob-dots i { width: 8px; height: 8px; border-radius: 50%; background: var(--border-strong); }
.ob-url { font-family: var(--font-mono); font-size: 10.5px; color: var(--text-faint);
  background: var(--bg); padding: 2px 9px; border-radius: 999px; }

/* A stand-in page. Deliberately abstract: it is a diagram, not a fake website. */
.ob-page { display: block; position: relative; padding: 30px 26px 32px; min-height: 208px; background: var(--panel); }
.ob-h { display: block; position: relative; height: 26px; margin-bottom: 26px; }
.ob-t1, .ob-t2 { position: absolute; left: 0; top: 0; font-size: 17px; font-weight: 650;
  color: var(--text); line-height: 26px; white-space: nowrap; }
.ob-t1 { animation: obOut 9s ease-in-out infinite; }
/* Typewriter: the caret is this element's right border, so it always sits at
   the end of the revealed text without needing to be positioned against it. */
.ob-t2 { overflow: hidden; width: 0; border-right: 2px solid transparent;
  animation: obType 9s steps(24, end) infinite, obCaret 9s linear infinite; }
/* A CSS border, not an SVG: the old ring stretched with the box and turned its
   dashes into uneven bars. Border dashes stay small and uniform at any width. */
.ob-ring {
  position: absolute; left: -9px; top: -5px; right: auto; width: calc(100% + 18px); height: 34px;
  /* A browser's dash length scales with border-width, so 1.5px drew long bars
     that pulled the eye off the headline they were meant to frame. At 1px the
     dashes are small, and the reduced opacity keeps the ring a hint rather than
     the loudest thing in the demo. */
  border: 1px dashed var(--accent); border-radius: 5px; opacity: 0;
  animation: obRing 9s ease-in-out infinite;
}

.ob-b { display: block; height: 8px; border-radius: 4px; background: var(--border); margin-bottom: 13px; }
.ob-b.b1 { width: 84%; }
.ob-b.b2 { width: 62%; }
.ob-media { display: block; height: 48px; border-radius: 6px; margin-top: 20px;
  background: linear-gradient(110deg, var(--panel-2), var(--border) 60%, var(--panel-2)); }

.ob-pub {
  position: absolute; right: 16px; bottom: 14px; display: inline-flex; align-items: center; gap: 6px;
  padding: 4px 10px; border-radius: 999px; font-size: 11.5px; font-weight: 600;
  background: var(--success-soft); color: var(--success); border: 1px solid rgba(74,222,128,.3);
  opacity: 0; transform: translateY(4px); animation: obPub 9s ease-out infinite;
}
.ob-pub svg { width: 12px; height: 12px; }
.ob-cursor {
  position: absolute; width: 19px; height: 19px; fill: #fff; stroke: rgba(0,0,0,.45); stroke-width: 1;
  filter: drop-shadow(0 2px 3px rgba(0,0,0,.4)); animation: obCursor 9s ease-in-out infinite;
}

@keyframes obCursor {
  0%      { left: 74%; top: 76%; transform: scale(1); }
  14%     { left: 26%; top: 20%; transform: scale(1); }
  17%     { left: 26%; top: 20%; transform: scale(.8); }
  20%,84% { left: 26%; top: 20%; transform: scale(1); }
  100%    { left: 74%; top: 76%; transform: scale(1); }
}
@keyframes obRing  { 0%,15% { opacity: 0; } 20%,74% { opacity: .55; } 82%,100% { opacity: 0; } }
@keyframes obOut   { 0%,19% { opacity: 1; } 25%,88% { opacity: 0; } 96%,100% { opacity: 1; } }
@keyframes obType  { 0%,24% { width: 0; } 52%,88% { width: 100%; } 96%,100% { width: 0; } }
@keyframes obCaret {
  0%,23%    { border-right-color: transparent; }
  24%,63%   { border-right-color: var(--accent); }
  64%,100%  { border-right-color: transparent; }
}
@keyframes obPub {
  0%,66%   { opacity: 0; transform: translateY(4px); }
  72%,88%  { opacity: 1; transform: none; }
  94%,100% { opacity: 0; transform: translateY(4px); }
}

/* Steps stay, demoted to a summary strip beneath the demo. */
.ob-steps { list-style: none; display: grid; grid-template-columns: repeat(3, 1fr); gap: 26px;
  margin: 36px 0 0; padding: 28px 0 0; border-top: 1px solid var(--border); }
.ob-steps li { display: grid; grid-template-columns: 22px 1fr; grid-template-rows: auto auto;
  column-gap: 10px; row-gap: 2px; align-items: center; }
.ob-sn { grid-row: 1 / span 2; align-self: start; display: grid; place-items: center;
  width: 22px; height: 22px; border-radius: 999px; font-size: 11.5px; font-weight: 650;
  background: var(--panel-2); border: 1px solid var(--border-strong); color: var(--text-dim); }
.ob-steps b { font-size: 13px; font-weight: 600; }
.ob-steps li > span:not(.ob-sn) { color: var(--text-faint); font-size: 12px; line-height: 1.45; }
.ob-steps code { font-size: 11px; background: var(--panel-2); padding: 1px 5px; border-radius: 4px; }

@media (max-width: 900px) {
  .ob-grid { grid-template-columns: 1fr; gap: 22px; }
  .ob-side { order: -1; }
  .ob-steps { grid-template-columns: 1fr; gap: 12px; }
}
@media (prefers-reduced-motion: reduce) {
  .ob-cursor { display: none; }
  .ob-t1, .ob-t2, .ob-ring, .ob-pub { animation: none; }
  /* Rest on the finished state: edited headline, ring shown, published. */
  .ob-t1 { opacity: 0; }
  .ob-t2 { width: 100%; border-right-color: transparent; }
  .ob-ring, .ob-pub { opacity: 1; transform: none; }
  .ob-demo:hover { transform: none; }
}

/* ============================================================================
   Ambient backdrop
   ----------------------------------------------------------------------------
   Orange-to-violet blooms drifting on black, with a fine grain over the top.

   Two treatments, switched by .signed-out on <html> (set in render()):
   signed out is a moment, so the blooms are large, saturated and centred on the
   card; signed in is a work surface, so they retreat to a dim horizon behind
   the topnav and never compete with content.

   Everything animated is transform/opacity only, so it runs on the compositor
   and never triggers layout or paint of the page beneath.
   ========================================================================== */
.bg {
  position: fixed; inset: 0; z-index: 0; overflow: hidden; pointer-events: none;
  /* Isolate: nothing inside can affect layout or paint outside this box. */
  contain: strict;
}

/* When a view has a stage, the backdrop takes exactly the stage's box and clips
   to it. That is what keeps the colour inside the sheet and leaves the frame
   around it flat: one element does both jobs, so the two can never drift apart.
   Views that own the whole screen (sign-in, the setup wizard) set no .framed and
   keep it full bleed. */
.framed .bg {
  top: var(--topnav-h);
  left: var(--stage-gap);
  right: var(--stage-gap);
  bottom: var(--stage-gap);
  border-radius: var(--r-xl);
  background: var(--stage-bg);
}
#app { position: relative; z-index: 1; }

.bg-bloom {
  position: absolute; display: block; border-radius: 50%;
  will-change: transform, opacity;
}

/* --- Signed in: the light blooms up from the bottom centre ----------------
   All three are anchored to the bottom and centred, overlapping there, so the
   colour gathers in one place and climbs rather than glowing in from the
   corners. Darkness is the ground; the bloom is what grows out of it. */
.bloom-a {
  width: 96vw; height: 60vw; left: 50%; margin-left: -56vw; top: auto; bottom: -26vw;
  background: radial-gradient(closest-side, rgba(242,98,34,.32), rgba(242,98,34,.09) 50%, transparent 74%);
  opacity: .6; animation: bloomRiseA 19s ease-in-out infinite alternate;
}
.bloom-b {
  width: 92vw; height: 58vw; left: 50%; margin-left: -36vw; right: auto; top: auto; bottom: -25vw;
  background: radial-gradient(closest-side, rgba(139,92,246,.30), rgba(124,58,237,.08) 50%, transparent 74%);
  opacity: .56; animation: bloomRiseB 24s ease-in-out infinite alternate;
}
/* The seam where the two meet, which is where the colour actually happens. */
.bloom-c {
  width: 64vw; height: 36vw; left: 50%; margin-left: -32vw; top: auto; bottom: -16vw;
  background: radial-gradient(closest-side, rgba(226,88,120,.20), transparent 70%);
  opacity: .55; animation: bloomRiseC 15s ease-in-out infinite alternate;
}

/* --- Signed out: the same bloom, opened right up ------------------------- */
.signed-out .bloom-a {
  width: 110vw; height: 90vh; margin-left: -64vw; bottom: -30vh;
  background: radial-gradient(closest-side, rgba(242,98,34,.42), rgba(242,98,34,.12) 50%, transparent 74%);
  opacity: .82; animation-duration: 15s;
}
.signed-out .bloom-b {
  width: 106vw; height: 86vh; margin-left: -42vw; bottom: -28vh;
  background: radial-gradient(closest-side, rgba(139,92,246,.40), rgba(124,58,237,.11) 50%, transparent 74%);
  opacity: .78; animation-duration: 19s;
}
.signed-out .bloom-c {
  width: 76vw; height: 50vh; margin-left: -38vw; bottom: -14vh;
  background: radial-gradient(closest-side, rgba(226,88,120,.26), transparent 70%);
  opacity: .7; animation-duration: 12s;
}

/* A vignette over the top half, so however far the bloom climbs the upper
   viewport stays black and content never loses its ground. */
.bg::after {
  content: ""; position: absolute; inset: 0; pointer-events: none; z-index: 1;
  background: linear-gradient(180deg,
    rgba(0,0,0,.86) 0%, rgba(0,0,0,.68) 28%, rgba(0,0,0,.32) 54%, transparent 78%);
}

/* Blooming, not drifting: each one starts low and small, then swells as it
   climbs, so the light reads as opening upward out of the bottom edge. The
   sway is small and only there to stop the rise looking mechanical. */
@keyframes bloomRiseA {
  0%   { transform: translate3d(0, 9vh, 0) scale(.78) rotate(0deg); }
  55%  { transform: translate3d(-3vw, -1vh, 0) scale(1.14) rotate(6deg); }
  100% { transform: translate3d(2vw, -7vh, 0) scale(1.3) rotate(-4deg); }
}
@keyframes bloomRiseB {
  0%   { transform: translate3d(0, 10vh, 0) scale(.82) rotate(0deg); }
  55%  { transform: translate3d(4vw, 0vh, 0) scale(1.1) rotate(-7deg); }
  100% { transform: translate3d(-3vw, -8vh, 0) scale(1.28) rotate(5deg); }
}
@keyframes bloomRiseC {
  0%   { transform: translate3d(0, 7vh, 0) scale(.7); }
  100% { transform: translate3d(0, -9vh, 0) scale(1.36); }
}

/* Fine grain, tiled from an inline SVG so it costs no request. It sits inside
   .bg, therefore behind #app: it textures the background without ever laying
   noise over live text. */
.bg-grain {
  position: absolute; inset: -100%; display: block; opacity: .13; z-index: 2;
  background-image: var(--grain-url);
  background-repeat: repeat;
  animation: grainShift 6s steps(1, end) infinite;
}
.signed-out .bg-grain { opacity: .17; }

/* Nudging the tile between eight positions reads as film grain rather than a
   fixed dirty-screen texture. steps() keeps it snapping, never sliding. */
@keyframes grainShift {
  0%      { transform: translate3d(0, 0, 0); }
  12.5%   { transform: translate3d(-3%, -2%, 0); }
  25%     { transform: translate3d(2%, -3%, 0); }
  37.5%   { transform: translate3d(-2%, 3%, 0); }
  50%     { transform: translate3d(3%, 1%, 0); }
  62.5%   { transform: translate3d(-1%, -3%, 0); }
  75%     { transform: translate3d(2%, 2%, 0); }
  87.5%   { transform: translate3d(-3%, 1%, 0); }
  100%    { transform: translate3d(0, 0, 0); }
}

/* Small screens: the blooms would otherwise dominate a narrow viewport, and
   this is where the battery cost of a permanently animating layer lands. */
@media (max-width: 640px) {
  .bloom-c { display: none; }
  .bloom-a, .bloom-b { opacity: .34; }
  .signed-out .bloom-a, .signed-out .bloom-b { opacity: .6; }
}
@media (prefers-reduced-motion: reduce) {
  .bg-bloom, .bg-grain { animation: none; }
}

/* --- Petals: the slow bloom itself ----------------------------------------
   Inspired by the Windows 11 Bloom wallpaper, where overlapping translucent
   petals of light radiate from a centre and turn almost imperceptibly. A conic
   gradient gives the petals, a radial mask dissolves the disc's hard edge, and
   an extremely slow rotation makes the light sweep rather than pulse.

   Only transform animates, so the (expensive) gradient and blur rasterise once
   and the compositor turns the finished layer. */
.bg-petals {
  position: absolute; display: block; border-radius: 50%;
  width: 150vmax; height: 150vmax; left: 50%; top: auto; bottom: -95vmax;
  margin: 0 0 0 -75vmax;
  background: conic-gradient(from 0deg at 50% 50%,
    rgba(242,98,34,.16) 0deg,
    rgba(242,98,34,.03) 34deg,
    transparent 62deg,
    rgba(139,92,246,.18) 104deg,
    rgba(139,92,246,.04) 138deg,
    transparent 168deg,
    rgba(226,88,120,.13) 210deg,
    transparent 250deg,
    rgba(139,92,246,.15) 296deg,
    rgba(242,98,34,.05) 334deg,
    rgba(242,98,34,.16) 360deg);
  -webkit-mask-image: radial-gradient(closest-side, #000 12%, rgba(0,0,0,.5) 46%, transparent 74%);
          mask-image: radial-gradient(closest-side, #000 12%, rgba(0,0,0,.5) 46%, transparent 74%);
  filter: blur(58px);
  opacity: .45;
  will-change: transform;
  animation: petalTurn 100s linear infinite;
}
.signed-out .bg-petals { opacity: .8; animation-duration: 80s; }

@keyframes petalTurn { to { transform: rotate(360deg); } }

@media (max-width: 640px) { .bg-petals { opacity: .34; } }
@media (prefers-reduced-motion: reduce) { .bg-petals { animation: none; } }

/* --- Glass sign-in card ---------------------------------------------------
   The card sat as a solid black slab on a lit background, which read as a hole
   punched through it. Frosting it lets the bloom carry through, so the card
   belongs to the scene while the blur keeps a calm ground under the text.
   saturate() stops the blurred colour behind it going grey. */
.auth .card {
  background: rgba(16, 16, 19, .62);
  -webkit-backdrop-filter: blur(26px) saturate(150%);
          backdrop-filter: blur(26px) saturate(150%);
  border-color: rgba(255, 255, 255, .09);
  box-shadow:
    0 24px 60px -20px rgba(0, 0, 0, .75),
    inset 0 1px 0 rgba(255, 255, 255, .06);
}
/* Fields have to be translucent too, or they read as solid chips sitting on
   glass rather than part of it. */
.auth .card input[type="text"],
.auth .card input[type="email"],
.auth .card input[type="password"],
.auth .card input:not([type]) {
  background: rgba(255, 255, 255, .045);
  border-color: rgba(255, 255, 255, .12);
}
.auth .card input:hover { border-color: rgba(255, 255, 255, .2); }
.auth .card input:focus {
  background: rgba(255, 255, 255, .07);
  border-color: var(--accent);
}
/* Without backdrop-filter the translucent fill would show the bloom straight
   through the card and wreck contrast, so fall back to a near-solid panel. */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .auth .card { background: rgba(13, 13, 13, .96); }
}

/* backdrop-filter is per-element work and a dense view can carry a dozen cards.
   On small screens, where the GPU and the battery are both smaller, cards drop
   the blur and take a solid fill. The sign-in card and modals keep theirs:
   there is only ever one of each on screen. */
@media (max-width: 640px) {
  .card {
    -webkit-backdrop-filter: none;
            backdrop-filter: none;
    background: linear-gradient(180deg, var(--panel), var(--bg-elevated));
  }
}

/* ============================================================================
   Glass, applied once across the whole app
   ----------------------------------------------------------------------------
   Every container surface, whether it is in the dashboard, the setup wizard,
   the admin area or an overlay, derives from the same tokens so the entire UI
   reads as one material. Small controls (buttons, chips, segmented switches,
   inputs, table rows) deliberately stay solid: they sit ON glass, and giving
   each of them its own backdrop-filter would both look wrong and cost a
   compositor pass per element.
   ========================================================================== */

/* Tier 1: surfaces that sit in the page. */
.wiz-code2,
.wiz-stackbar,
.wiz-tile,
.ldr-card,
.ldr-preview,
.onb-hero,
.ops-card,
.hpage,
.infra-detail,
.ov-frame,
.ob-demo {
  background: var(--glass);
  -webkit-backdrop-filter: var(--glass-blur);
          backdrop-filter: var(--glass-blur);
  border: 1px solid var(--glass-line);
  box-shadow: var(--glass-hi);
}

/* Tier 2: overlays. More body, because they carry their own content over
   whatever happens to be behind them. */
.modal,
.drawer,
.menu,
.toast,
.sw-panel,
.wiz-actions {
  background: var(--glass-overlay);
  -webkit-backdrop-filter: var(--glass-blur-up);
          backdrop-filter: var(--glass-blur-up);
  border-color: var(--glass-line-up);
}

/* Tinted surfaces keep their meaning; they only gain the frost. The tint is
   what tells you this is a warning or a notice, so it must not be replaced. */
.site-alert,
.ins-banner,
.wiz-err {
  -webkit-backdrop-filter: var(--glass-blur);
          backdrop-filter: var(--glass-blur);
}

/* Selected states have to stay legible against the frost, so they keep a real
   fill rather than inheriting the translucent one. */
.wiz-tile.on, .ldr-card.on { background: var(--accent-soft); }

/* One fallback for the whole system: without backdrop-filter, a translucent
   fill would put the backdrop straight through every panel in the app. */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .wiz-code2, .wiz-stackbar, .wiz-tile, .ldr-card, .ldr-preview, .onb-hero,
  .ops-card, .hpage, .infra-detail, .ov-frame, .ob-demo,
  .modal, .drawer, .menu, .toast, .sw-panel, .wiz-actions {
    background: var(--glass-solid);
  }
}

/* Small screens drop the blur on in-page surfaces, where a long list of them
   would cost a compositor pass each. Overlays keep it: only one is ever up. */
@media (max-width: 640px) {
  .wiz-code2, .wiz-stackbar, .wiz-tile, .ldr-card, .ldr-preview, .onb-hero,
  .ops-card, .hpage, .infra-detail, .ov-frame, .ob-demo {
    -webkit-backdrop-filter: none;
            backdrop-filter: none;
    background: var(--glass-solid);
  }
}

/* ============================================================================
   Touch and small screens
   ----------------------------------------------------------------------------
   Layout already reflowed without horizontal overflow down to 390px; what was
   missing was the touch-specific behaviour, which no amount of width testing on
   a desktop browser surfaces.
   ========================================================================== */

/* iOS Safari zooms the whole page when a focused input's font-size is under
   16px, and every field here was 14px. The page then sits scrolled and scaled
   with no way back except a manual pinch, on every single form. Only applied to
   coarse pointers so the desktop type scale is untouched. */
@media (pointer: coarse) {
  input[type="text"], input[type="email"], input[type="password"],
  input[type="search"], input[type="url"], input[type="tel"], input[type="number"],
  input:not([type]), select, textarea {
    font-size: 16px;
  }

  /* Touch targets. 28-32px icon buttons are comfortable with a mouse and
     genuinely hard to hit with a thumb; 44px is the accessibility floor.
     Padding grows the hit area without changing the drawn size. */
  .icon-btn, .link-btn, .tab, .anav, .snav, .set-navitem, .fw-tile, .seg button {
    min-height: 44px;
  }
  .icon-btn { min-width: 44px; }
  .btn.sm { --h: 38px; }
}

@media (max-width: 640px) {
  /* Rails and tab strips scroll rather than wrap into stacks that push content
     off the first screen. */
  .tabs, .admin-nav, .settings-nav, .fw-tabs {
    display: flex; flex-wrap: nowrap; overflow-x: auto; scrollbar-width: none;
    -webkit-overflow-scrolling: touch;
  }
  .tabs::-webkit-scrollbar, .admin-nav::-webkit-scrollbar,
  .settings-nav::-webkit-scrollbar, .fw-tabs::-webkit-scrollbar { display: none; }
  .tabs > *, .admin-nav > *, .settings-nav > * { flex: none; }

  /* Tables keep their own horizontal scroll, but nothing said so. The fade at
     the right edge is the only cue that more columns exist. */
  .table-wrap {
    position: relative;
    -webkit-overflow-scrolling: touch;
    -webkit-mask-image: linear-gradient(90deg, #000 calc(100% - 28px), transparent);
            mask-image: linear-gradient(90deg, #000 calc(100% - 28px), transparent);
  }

  /* Modals become bottom sheets: reachable with one thumb, and they stop being
     a small box floating in the middle of a tall screen. */
  .modal {
    top: auto; bottom: 0; left: 0; right: 0;
    transform: none; width: 100%;
    max-height: 88vh; overflow-y: auto;
    border-radius: 16px 16px 0 0;
    padding: var(--s-5) var(--s-5) calc(var(--s-5) + env(safe-area-inset-bottom));
    animation: sheet-in .26s cubic-bezier(.16,1,.3,1);
  }
  @keyframes sheet-in { from { transform: translateY(100%); } to { transform: none; } }
  .modal-actions { flex-direction: column-reverse; gap: 8px; }
  .modal-actions .btn { width: 100%; justify-content: center; }

  /* Drawers take the full width; 420px on a 390px screen left a dead sliver. */
  .drawer { width: 100%; }

  /* Page headers stack so the action is not squeezed against a wrapped title. */
  .page-head { flex-direction: column; align-items: stretch; gap: 14px; }
  .page-head .btn { width: 100%; justify-content: center; }

  /* The support launcher sits above the safe area, not under the home bar. */
  .support-widget { right: 14px; bottom: calc(14px + env(safe-area-inset-bottom)); }
  .sw-panel { width: calc(100vw - 28px); height: min(70vh, 520px); }
}

@media (prefers-reduced-motion: reduce) {
  .modal { animation: none; }
}

/* ---- Narrow-screen column behaviour --------------------------------------
   Multi-column rows and grids are the thing that actually breaks on a phone:
   they stay side by side long past the point where each column can hold its
   content, so labels wrap to two lines while their neighbour stays on one, and
   inputs collapse to a few characters wide. */
@media (max-width: 640px) {
  /* Any two-up form row becomes one column. Keeping them side by side left the
     Site URL field about five characters wide. */
  .row.wrap { flex-direction: column; align-items: stretch !important; }
  .row.wrap > * { width: 100%; min-width: 0; }
  .row.wrap > .btn { justify-content: center; }

  /* Card grids go single column rather than squeezing two per row. */
  .grid { grid-template-columns: 1fr; }

  /* A row whose text and action compete for the same line: the action moves
     under the text instead of overlapping it. */
  .sess-row, .notif-row {
    flex-direction: column; align-items: stretch; gap: 10px;
  }
  .sess-row > .btn, .notif-row > .btn { align-self: flex-start; }
}

/* An IPv6 address is one unbroken token with no break opportunity, so it
   overflowed its container and ran underneath the Sign out button regardless of
   min-width. This lets it break anywhere. Applies at all widths: the same row
   is tight on a narrow desktop window too. */
.sess-row .tl-time, .notif-row .tl-time { overflow-wrap: anywhere; }

/* ---- Overlay legibility on touch devices ---------------------------------
   Overlays lean on backdrop-filter to stay readable over the page. On mobile
   that is not dependable: iOS drops the effect inside some stacking contexts
   and low-power mode disables it outright, leaving only the translucent fill,
   through which the page below stays perfectly readable. The account menu was
   showing the projects list straight through it.

   So on touch devices overlays carry enough fill to be legible on their own,
   and the blur becomes an enhancement rather than the thing holding the text
   up. Desktop keeps the lighter, glassier treatment. */
@media (pointer: coarse) {
  .menu, .modal, .drawer, .sw-panel, .tip, .toast, .wiz-actions {
    background: rgba(18, 18, 21, .97);
  }
  .auth .card { background: rgba(16, 16, 19, .92); }
  .card { background: rgba(20, 20, 23, .9); }
}

/* A menu that opens over content needs a hard edge even on desktop: it is the
   only surface here that routinely sits directly on top of body text. */
.menu { background: rgba(18, 18, 21, .94); }

/* ---- Inline field errors --------------------------------------------------
   Sits directly under the control it belongs to, so the message and the field
   it refers to are never separated by another field. */
.field-err {
  display: flex; align-items: flex-start; gap: 6px;
  margin-top: 6px; font-size: 12.5px; line-height: 1.45; color: var(--danger);
}
input.bad, select.bad, textarea.bad { border-color: var(--danger); }
input.bad:focus, select.bad:focus, textarea.bad:focus {
  border-color: var(--danger); box-shadow: 0 0 0 3px var(--danger-soft);
}
/* Composed fields (url, path) draw their own frame, so the invalid state has to
   move to the wrapper or it would highlight only the inner input. */
.url-field:has(input.bad), .path-field:has(input.bad) { border-color: var(--danger); }

/* ---- Side-by-side fields -------------------------------------------------
   Bottom alignment was used so the inputs lined up when one label wrapped to
   two lines. It breaks the moment a validation error appears: the error makes
   one column taller, and aligning bottoms pushes the neighbouring label and
   input down with it.

   Aligning to the top instead means an error grows downward into its own
   column and leaves its neighbour where it is. Labels get a uniform minimum
   height so the inputs still line up in the ordinary single-line case. */
.row.fields-top { align-items: flex-start; }
.row.fields-top > .field > label,
.row.fields-top > .field > .field-row { min-height: 20px; }
/* The error is the variable part, so give it a stable slot: the row's height no
   longer jumps as messages appear and clear. */
.row.fields-top > .field { padding-bottom: 0; }

/* ─── Wolfigs Cloud home ─────────────────────────────────────── */

.home-head { margin-bottom: var(--s-8); }
.home-eyebrow {
  display: inline-block; margin-bottom: 10px;
  font-size: 11px; font-weight: 700; letter-spacing: .14em; text-transform: uppercase;
  color: var(--accent);
}
.home-head h1 { font-size: 30px; letter-spacing: -0.025em; }
.home-head .sub { color: var(--text-dim); font-size: 14.5px; margin-top: 6px; }

.prod-grid { display: grid; gap: var(--s-4); grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); }

.prod-card {
  position: relative;
  display: grid;
  grid-template-columns: auto 1fr;
  grid-template-areas: "mark body" "meta meta";
  gap: var(--s-4);
  align-content: start;
  padding: var(--s-5);
  border: 1px solid var(--glass-line);
  border-radius: var(--r-xl);
  background: var(--glass);
  -webkit-backdrop-filter: var(--glass-blur);
  backdrop-filter: var(--glass-blur);
  box-shadow: var(--glass-hi);
  transition: border-color .18s, transform .18s, background-color .18s;
}
a.prod-card:hover { border-color: var(--border-focus); transform: translateY(-2px); }
a.prod-card:hover .prod-go { opacity: 1; transform: none; }

.prod-mk {
  grid-area: mark;
  width: 44px; height: 44px; border-radius: var(--r-lg);
  display: grid; place-items: center;
  background: rgba(255, 255, 255, .05);
  border: 1px solid var(--glass-line);
  color: var(--text-faint);
}
.prod-mk img { width: 26px; height: auto; display: block; }
.prod-mk svg { width: 20px; height: 20px; }

.prod-body { grid-area: body; display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.prod-name { display: flex; align-items: center; gap: 8px; font-size: 17px; font-weight: 620; letter-spacing: -0.02em; color: var(--text); }
.prod-go { color: var(--text-faint); opacity: 0; transform: translateX(-4px); transition: opacity .18s, transform .18s; display: inline-flex; }
.prod-go svg { width: 15px; height: 15px; }
.prod-tag { font-size: 13px; color: var(--accent); font-weight: 500; }
.prod-blurb { font-size: 13px; color: var(--text-dim); line-height: 1.55; margin-top: 2px; }

.prod-meta { grid-area: meta; display: flex; flex-wrap: wrap; gap: 6px; min-height: 22px; }
.prod-meta .skel-chip { display: block; width: 84px; height: 20px; border-radius: var(--r-full); background: rgba(255,255,255,.05); }

/* The placeholder is a promise, not a product: no border highlight, no hover,
   and removed from the accessibility tree so it is never announced as a link. */
.prod-card.soon { background: transparent; border-style: dashed; border-color: var(--border); box-shadow: none; -webkit-backdrop-filter: none; backdrop-filter: none; }
.prod-card.soon .prod-name { color: var(--text-dim); }
.prod-card.soon .prod-tag { color: var(--text-faint); }
.prod-card.soon .prod-blurb { color: var(--text-faint); }

.home-links { display: grid; gap: var(--s-3); grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); }
.hl {
  display: grid; grid-template-columns: auto 1fr; grid-template-areas: "ic name" "ic desc";
  column-gap: 12px; row-gap: 2px; align-items: start;
  padding: 14px var(--s-4);
  border: 1px solid var(--glass-line); border-radius: var(--r-lg);
  background: rgba(255, 255, 255, .02);
  transition: border-color .16s, background-color .16s;
}
.hl:hover { border-color: var(--border-focus); background: rgba(255, 255, 255, .045); }
.hl svg { grid-area: ic; width: 17px; height: 17px; color: var(--text-faint); margin-top: 2px; }
.hl b { grid-area: name; font-size: 13.5px; font-weight: 600; color: var(--text); }
.hl i { grid-area: desc; font-style: normal; font-size: 12.5px; color: var(--text-faint); line-height: 1.5; }

/* ─── Shell, narrow screens ──────────────────────────────────── */

/* Crumbs go first: the tabs are the primary navigation now, and every view
   carries its own back link, so the bar keeps brand, tabs and account. */
@media (max-width: 1080px) { .cb-crumbs { display: none; } }

@media (max-width: 720px) {
  /* The frame is a desktop idea. On a phone the viewport is the frame, so the
     page scrolls normally and the stage goes back to being a plain panel. */
  body { overflow: auto; }
  /* With no inset frame there is nothing to clip the backdrop to, so it goes
     full bleed again and the sheet's ground becomes the page's. */
  .framed .bg { top: 0; left: 0; right: 0; bottom: 0; border-radius: 0; }
  .cloudbar { position: sticky; grid-template-columns: auto 1fr auto; gap: var(--s-2); padding: 0 var(--s-4); }
  .cb-tabs { justify-content: center; overflow-x: auto; scrollbar-width: none; }
  .cb-tabs::-webkit-scrollbar { display: none; }
  .cb-tab { padding: 0 12px; font-size: 13px; }
  .userchip .email { display: none; }
  .userchip { padding: 4px; }
  main.view {
    position: static;
    inset: auto;
    overflow: visible;
    min-height: calc(100vh - var(--topnav-h));
    padding-left: var(--s-4); padding-right: var(--s-4);
    padding-top: var(--s-6);
    border-left: 0; border-right: 0;
    border-radius: var(--r-lg) var(--r-lg) 0 0;
  }
  main.view.wide { padding-left: var(--s-4); padding-right: var(--s-4); }
  .home-head h1 { font-size: 24px; }
  .prod-grid, .home-links { grid-template-columns: 1fr; }
}

@media (min-width: 721px) and (max-width: 1080px) { :root { --stage-gap: 18px; } }

/* Below this the product name would push the switcher into the account chip. */
@media (max-width: 440px) {
  .cb-tab span { display: none; }
  .cb-tab { padding: 0 14px; }
}
